summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorMichael Smith <mikesmiffy128@gmail.com>2021-11-20 03:10:50 +0000
committerMichael Smith <mikesmiffy128@gmail.com>2021-11-20 03:18:08 +0000
commitda6f343032cb01597dc7866e66f091adf3243a62 (patch)
tree870f8cb8e82bb42202ab92bea03fc6ab35ada7ca
Initial public snapshot
With code from Bill. Thanks Bill!
-rw-r--r--.editorconfig11
-rw-r--r--.gitignore8
-rw-r--r--LICENCE27
-rw-r--r--README50
-rw-r--r--TODO/autocomplete4
-rw-r--r--TODO/autojump5
-rw-r--r--TODO/compat3
-rw-r--r--TODO/featgen9
-rw-r--r--TODO/linux6
-rw-r--r--TODO/opt5
-rw-r--r--compile57
-rw-r--r--compile.bat62
-rw-r--r--gamedata/engine.kv11
-rw-r--r--gamedata/gamelib.kv14
-rw-r--r--src/3p/README24
-rw-r--r--src/3p/chibicc/LICENSE21
-rw-r--r--src/3p/chibicc/chibicc.h486
-rw-r--r--src/3p/chibicc/codegen.c1595
-rw-r--r--src/3p/chibicc/hashmap.c165
-rw-r--r--src/3p/chibicc/main.c791
-rw-r--r--src/3p/chibicc/parse.c3368
-rw-r--r--src/3p/chibicc/preprocess.c1208
-rw-r--r--src/3p/chibicc/strings.c17
-rw-r--r--src/3p/chibicc/tokenize.c799
-rw-r--r--src/3p/chibicc/type.c307
-rw-r--r--src/3p/chibicc/unicode.c189
-rw-r--r--src/3p/openbsd/asprintf.c81
-rw-r--r--src/3p/udis86/decode.c1266
-rw-r--r--src/3p/udis86/decode.h197
-rw-r--r--src/3p/udis86/extern.h113
-rw-r--r--src/3p/udis86/itab.c5945
-rw-r--r--src/3p/udis86/itab.h939
-rw-r--r--src/3p/udis86/syn-att.c228
-rw-r--r--src/3p/udis86/syn-intel.c224
-rw-r--r--src/3p/udis86/syn.c212
-rw-r--r--src/3p/udis86/syn.h53
-rw-r--r--src/3p/udis86/types.h260
-rw-r--r--src/3p/udis86/udint.h95
-rw-r--r--src/3p/udis86/udis86.c456
-rw-r--r--src/abi.h91
-rw-r--r--src/bitbuf.h99
-rw-r--r--src/build/cmeta.c238
-rw-r--r--src/build/cmeta.h44
-rw-r--r--src/build/codegen.c95
-rw-r--r--src/build/mkgamedata.c238
-rw-r--r--src/con_.c533
-rw-r--r--src/con_.h278
-rw-r--r--src/dbg.c49
-rw-r--r--src/dbg.h28
-rw-r--r--src/demodefs.h94
-rw-r--r--src/demorec.c218
-rw-r--r--src/demorec.h28
-rw-r--r--src/dll.rc33
-rw-r--r--src/extmalloc.c60
-rw-r--r--src/extmalloc.h33
-rw-r--r--src/factory.h13
-rw-r--r--src/gamedata.c31
-rw-r--r--src/gamedata.h32
-rw-r--r--src/gameinfo.c372
-rw-r--r--src/gameinfo.h37
-rw-r--r--src/gametype.h38
-rw-r--r--src/hook.c99
-rw-r--r--src/hook.h54
-rw-r--r--src/intdefs.h35
-rw-r--r--src/kv.c231
-rw-r--r--src/kv.h96
-rw-r--r--src/mem.h73
-rw-r--r--src/noreturn.h11
-rw-r--r--src/os.c56
-rw-r--r--src/os.h145
-rw-r--r--src/ppmagic.h81
-rw-r--r--src/sst.c206
-rw-r--r--src/tier0stub.c19
-rw-r--r--src/udis86.c11
-rw-r--r--src/udis86.h12
-rw-r--r--src/unreachable.h14
-rw-r--r--src/vcall.h57
-rw-r--r--src/version.h5
-rw-r--r--test/bitbuf.test.c34
-rw-r--r--test/hook.test.c45
-rw-r--r--test/kv.test.c49
-rw-r--r--test/test.h234
-rw-r--r--tools/todo5
-rw-r--r--tools/todo.sh35
-rw-r--r--tools/todo.vim41
85 files changed, 23641 insertions, 0 deletions
diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000..1953ba8
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,11 @@
+root = true
+
+[*]
+end_of_line = lf
+insert_final_newline = true
+charset = utf-8
+indent_style = tab
+indent_size = 4
+
+[*.{bat,cmd}]
+end_of_line = crlf
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6861589
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+/.build/
+/sst.dll
+/sst.pdb
+/sst.so
+/compile_commands.json
+
+# a place to plonk crap you don't wanna commit yet
+/junk
diff --git a/LICENCE b/LICENCE
new file mode 100644
index 0000000..76ade89
--- /dev/null
+++ b/LICENCE
@@ -0,0 +1,27 @@
+Except where otherwise noted, the following terms apply:
+================================================================================
+Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+Copyright © 2021 Willian Henrique <wsimanbrazil@yahoo.com.br>
+
+Permission to use, copy, modify, and/or distribute this software for any purpose
+with or without fee is hereby granted, provided that the above copyright notice
+and this permission notice appear in all copies.
+
+THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
+FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
+OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
+TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
+THIS SOFTWARE.
+================================================================================
+Parts of this software distribution are released into the public domain. Check
+the copyright notices in individual files for full details.
+
+The README file is also in the public domain.
+
+Files under src/3p/ are written and licensed by third parties. See the copyright
+notices in and alongside those files for details of authorship and relevant
+redistribution rights. Some - but not all - of this third party code is
+incorporated into binary builds (sst.dll or sst.so). Please take care when
+redistributing binaries to respect all the relevant copyright notices.
diff --git a/README b/README
new file mode 100644
index 0000000..188b0ad
--- /dev/null
+++ b/README
@@ -0,0 +1,50 @@
+Hey! This README is for those looking to work on the code. For actual plugin
+documentation, you'll want to look at the website, which doesn't exist yet,
+or ask for help in the relevant speedrunning Discord, which does exist yet.
+
+NOTE: Please read and understand LICENCE before redistributing this software!
+
+== Compiling ==
+
+Windows:
+ - Install the Windows 10 SDK via the Visual Studio Installer.
+ - Install native Clang from https://clang.llvm.org (NOT MinGW/MSYS2 Clang!).
+ - Run compile.bat (in lieu of a better build tool, to be figured out later).
+
+Linux:
+ - Install Clang (and LLD) via your system package manager. Technically, GCC
+ might be able to compile this too, but Clang is heavily preferred in the name
+ of consistency and using GCC will require a decent amount of fiddling. It's
+ also not tested and might break and I probably won't care that much.
+ - Install 32-bit C libraries and the C library headers if they're not already
+ installed.
+ - Run ./compile (in lieu of a better build tool, to be figured out later).
+
+* NOTE: Linux builds currently fail; there's a bunch of code that needs to be
+ written. See also TODO/linux.
+
+== How and where to install ==
+
+Very old Source builds load plugins from the top-level bin/ folder, while
+relatively modern builds load them from the mod-specific directory, e.g.
+left4dead2/, hl2/. Since this plugin is designed to be universal, the
+recommended practice is to put it in bin/ regardless and then use the command
+`plugin_load ../bin/sst`. The way the paths work out, that ends up always
+working no matter what, and allows the plugin to be shared between different
+mods in the same engine installation where relevant. It's also possible to just
+back out of the game installation with ../ and load from whatever directory you
+want, as long as it's not on a different Windows drive letter. In that case, the
+plugin can be shared between multiple games. That said, it's a little more
+annoying to do and a little less self contained.
+
+IMPORTANT: If your game supports multiplayer, always launch with -insecure as a
+launch option before loading this plugin! In theory, plugins shouldn't be able
+to load without this, or it should at least be impossible to connect to a VAC-
+enabled server with the plugin loaded, but -insecure is the safest way to ensure
+VAC is completely disabled, otherwise you use the plugin AT YOUR OWN RISK OF
+BEING BANNED!
+
+Note: some very old (and very new) Source builds don't have a plugin_load
+command. It may be possible (although questionably necessary) to support these
+games with an injector to forcibly load the library into the game. For the time
+being, however, these versions are unsupported.
diff --git a/TODO/autocomplete b/TODO/autocomplete
new file mode 100644
index 0000000..cc3e867
--- /dev/null
+++ b/TODO/autocomplete
@@ -0,0 +1,4 @@
+Console command autocompletion
+====
+This isn't really something we need right now, but is worth documenting in case
+we deem it useful later.
diff --git a/TODO/autojump b/TODO/autojump
new file mode 100644
index 0000000..7b9c8b4
--- /dev/null
+++ b/TODO/autojump
@@ -0,0 +1,5 @@
+Add back autojump
+====
+I already wrote (and rewrote) the code long ago, but it's a secret until we
+further raise the verification standard for L4D2. Stupid, but less stupid than
+having no idea whether anyone's cheating, I guess.
diff --git a/TODO/compat b/TODO/compat
new file mode 100644
index 0000000..7f210e8
--- /dev/null
+++ b/TODO/compat
@@ -0,0 +1,3 @@
+Support more games and engine branches
+====
+Pretty self-explanatory.
diff --git a/TODO/featgen b/TODO/featgen
new file mode 100644
index 0000000..b71f32a
--- /dev/null
+++ b/TODO/featgen
@@ -0,0 +1,9 @@
+Feature setup code generation
+====
+Once the plugin has enough features across enough C files, setting up and
+tearing down everything will get kind of annoying. That's where some more code
+generation might be nice.
+
+There's a few vague ideas of how to do this but really it's pretty open-ended
+overall. In the meantime, we're just calling functions manually. Not a huge
+deal, really.
diff --git a/TODO/linux b/TODO/linux
new file mode 100644
index 0000000..d89baca
--- /dev/null
+++ b/TODO/linux
@@ -0,0 +1,6 @@
+Support Linux (again)
+====
+Early prototype code was written with both Linux and Windows in mind, but since
+then most of the development happens to have happened on Windows, which has left
+some gaps. We want to eventually add back support for Linux once all the
+important Windows stuff is out of the way.
diff --git a/TODO/opt b/TODO/opt
new file mode 100644
index 0000000..03add29
--- /dev/null
+++ b/TODO/opt
@@ -0,0 +1,5 @@
+Improve performance
+====
+Simple C code tends to go fast, but that doesn't mean we can't make a note of
+possibly-weird stuff that should maybe go more fast if we care enough to
+improve it.
diff --git a/compile b/compile
new file mode 100644
index 0000000..fa0240e
--- /dev/null
+++ b/compile
@@ -0,0 +1,57 @@
+#!/bin/sh -e
+# This file is dedicated to the public domain.
+
+case "`uname -s`" in
+ # weird people using Windows Bash might type ./compile, help them out :)
+ *NT*)
+ echo "You're on Windows, idiot! Running compile.bat for you."
+ exec cmd /c compile.bat ;;
+esac
+
+mkdir -p .build/include
+
+warnings=-Wall -pedantic -Wno-parentheses -Wno-missing-braces
+
+objs=
+cc() {
+ objs="$objs .build/${1%%.c}.o"
+ clang -m32 -c -O2 -flto -fpic $warnings -I.build/include \
+ -D_FILE_OFFSET_BITS=64 -DFILE_BASENAME="${1%%.c}" \
+ -o ".build/${1%%.c}.o" "src/$1"
+}
+
+ld() {
+ clang -m32 -shared -O2 -flto -fpic -s -fuse-ld=lld -L.build -ldl -o sst.so$objs
+}
+
+src="\
+ con_.c \
+ demorec.c \
+ dbg.c \
+ extmalloc.c \
+ gameinfo.c \
+ hook.c \
+ kv.c \
+ os.c \
+ sst.c \
+ udis86.c"
+
+clang -O2 -fuse-ld=lld $warnings -D_FILE_OFFSET_BITS=64 -o .build/codegen \
+ src/build/codegen.c src/build/cmeta.c src/os.c
+clang -O2 -fuse-ld=lld $warnings -D_FILE_OFFSET_BITS=64 -o .build/mkgamedata \
+ src/build/mkgamedata.c src/kv.c src/os.c
+.build/codegen `for s in $src; do echo "src/$s"; done`
+.build/mkgamedata gamedata/gamelib.kv gamedata/engine.kv
+for s in $src; do cc "$s" done
+clang -m32 -shared -fpic -fuse-ld=lld -O0 -w -o .build/libtier0.so src/tier0stub.c
+ld
+
+clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/bitbuf.test test/bitbuf.test.c
+.build/bitbuf.test
+# skipping this test on linux for now, since inline hooks aren't compiled in
+#clang -m32 -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/hook.test test/hook.test.c
+#.build/hook.test
+clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/kv test/kv.test.c
+.build/kv.test
+
+# vi: sw=4 tw=4 noet tw=80 cc=80
diff --git a/compile.bat b/compile.bat
new file mode 100644
index 0000000..4fce747
--- /dev/null
+++ b/compile.bat
@@ -0,0 +1,62 @@
+:: This file is dedicated to the public domain.
+@echo off
+
+if not exist .build\ (
+ md .build
+ attrib +H .build
+)
+if not exist .build\include\ md .build\include
+
+set warnings=-Wall -pedantic -Wno-parentheses -Wno-missing-braces
+
+set objs=
+goto :main
+
+:cc
+for /F %%b in ("%1") do set basename=%%~nb
+set objs=%objs% .build/%basename%.o
+clang -m32 -c -O2 -flto %warnings% -I.build/include -D_CRT_SECURE_NO_WARNINGS ^
+-DFILE_BASENAME=%basename% -o .build/%basename%.o %1 || exit /b
+goto :eof
+
+:main
+clang -municode -O2 -fuse-ld=lld %warnings% -D_CRT_SECURE_NO_WARNINGS -ladvapi32 ^
+-o .build/codegen.exe src/build/codegen.c src/build/cmeta.c src/os.c || exit /b
+clang -municode -O2 -fuse-ld=lld %warnings% -D_CRT_SECURE_NO_WARNINGS -ladvapi32 ^
+-o .build/mkgamedata.exe src/build/mkgamedata.c src/kv.c src/os.c || exit /b
+.build\codegen.exe src/con_.c src/demorec.c src/dbg.c src/gamedata.c ^
+src/gameinfo.c src/hook.c src/kv.c src/os.c src/sst.c src/udis86.c || exit /b
+.build\mkgamedata.exe gamedata/engine.kv gamedata/gamelib.kv || exit /b
+:: llvm-rc doesn't preprocess, looks like it might later:
+:: https://reviews.llvm.org/D100755?id=339141
+:: in the meantime, manually run through clang -E
+clang -E -xc src/dll.rc>.build\dll.pp.rc || exit /b
+llvm-rc /FO .build\dll.res .build\dll.pp.rc || exit /b
+:: might as well remove the temp file afterwards
+del .build\dll.pp.rc
+clang -m32 -shared -fuse-ld=lld -O0 -w -o .build/tier0.dll src/tier0stub.c
+call :cc src/con_.c || exit /b
+call :cc src/demorec.c || exit /b
+call :cc src/dbg.c || exit /b
+call :cc src/extmalloc.c || exit /b
+call :cc src/gamedata.c || exit /b
+call :cc src/gameinfo.c || exit /b
+call :cc src/hook.c || exit /b
+call :cc src/kv.c || exit /b
+call :cc src/os.c || exit /b
+call :cc src/sst.c || exit /b
+call :cc src/udis86.c || exit /b
+clang -m32 -shared -O2 -flto -fuse-ld=lld -Wl,/implib:.build/sst.lib,/Brepro ^
+-L.build -ladvapi32 -ltier0 -lshlwapi -o sst.dll%objs% .build/dll.res || exit /b
+:: get rid of another useless file (can we just not create this???)
+del .build\sst.lib
+
+clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/bitbuf.test.exe test/bitbuf.test.c || exit /b
+.build\bitbuf.test.exe || exit /b
+:: special case: test must be 32-bit
+clang -m32 -fuse-ld=lld -O2 -g3 -ladvapi32 -include test/test.h -o .build/hook.test.exe test/hook.test.c || exit /b
+.build\hook.test.exe || exit /b
+clang -fuse-ld=lld -O2 -g3 -include test/test.h -o .build/kv.test.exe test/kv.test.c || exit /b
+.build\kv.test.exe || exit /b
+
+:: vi: sw=4 tw=4 noet tw=80 cc=80
diff --git a/gamedata/engine.kv b/gamedata/engine.kv
new file mode 100644
index 0000000..81a0545
--- /dev/null
+++ b/gamedata/engine.kv
@@ -0,0 +1,11 @@
+// = engine library =
+
+// CDemoRecorder
+vtidx_SetSignonState 3
+vtidx_StopRecording 7
+vtidx_RecordPacket 11
+
+// VEngineClient
+vtidx_GetEngineBuildNumber { L4D2 99 }
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/gamedata/gamelib.kv b/gamedata/gamelib.kv
new file mode 100644
index 0000000..388abb9
--- /dev/null
+++ b/gamedata/gamelib.kv
@@ -0,0 +1,14 @@
+// = client and server libaries =
+
+// CGameMovement
+vtidx_CheckJumpButton {
+ 2013 "28 + NVDTOR"
+ L4D "32 + NVDTOR"
+ Portal2 "35 + NVDTOR"
+}
+off_mv 8
+
+// I(Server|Client)Unknown
+vtidx_GetBaseEntity 4
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/3p/README b/src/3p/README
new file mode 100644
index 0000000..85b225c
--- /dev/null
+++ b/src/3p/README
@@ -0,0 +1,24 @@
+These are imported 3rd party library sources, wrangled for ease of plonking into
+the build (e.g. relative #includes, etc.).
+
+Used in SST itself:
+ - libmpack
+ - monocypher
+ - udis86
+
+Used at build time:
+ - chibicc (somewhat hacked up for use as a lexer)
+ - asprintf() from OpenBSD (for compatibility on Windows)
+
+Most of the C sources have wrappers in the parent directory to build proper
+objects for use in the project, and wrapper headers to get the full APIs as
+conveniently as possible. In other words, most of these files aren't built or
+used directly.
+
+It is possible that these libraries may end up lightly modified; we err on the
+side of changing things to fit our use case rather than working around problems
+in outer layers. A couple of the libraries are pretty old and don't see much
+upstream change, but are small enough to be comfortably maintained as vendored.
+
+IMPORTANT! Libraries are distributed subject to their copyright notices; please
+refer to those!
diff --git a/src/3p/chibicc/LICENSE b/src/3p/chibicc/LICENSE
new file mode 100644
index 0000000..2d1fd94
--- /dev/null
+++ b/src/3p/chibicc/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Rui Ueyama
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
diff --git a/src/3p/chibicc/chibicc.h b/src/3p/chibicc/chibicc.h
new file mode 100644
index 0000000..1719bc5
--- /dev/null
+++ b/src/3p/chibicc/chibicc.h
@@ -0,0 +1,486 @@
+// include guards: upstream doesn't have these but we add them so we can cat
+// source files together (or #include them, in particular)
+#ifndef INC_CHIBICC_H
+#define INC_CHIBICC_H
+
+// note: removing defs/headers that aren't needed in tokenize.c and/or don't
+// exist on Windows, in order to get our stuff working. total hack; oh well.
+//#define _POSIX_C_SOURCE 200809L
+#include <assert.h>
+#include <ctype.h>
+#include <errno.h>
+//#include <glob.h>
+//#include <libgen.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+// stdnoreturn means we can't use our noreturn (_Noreturn void)
+// there are no noreturns in tokenize.c anyway, and the ones in this header have
+// been changed to just _Noreturn to avoid any possible conflict
+//#include <stdnoreturn.h>
+#include <string.h>
+//#include <strings.h>
+#include <sys/stat.h>
+//#include <sys/types.h>
+//#include <sys/wait.h>
+#include <time.h>
+//#include <unistd.h>
+
+// exists on all Unixes but normally hidden _GNU_SOURCE on Linux.
+// missing entirely on Windows (implemented in 3p/openbsd/asprintf.c for compat)
+int vasprintf(char **str, const char *fmt, va_list ap);
+
+#define MAX(x, y) ((x) < (y) ? (y) : (x))
+#define MIN(x, y) ((x) < (y) ? (x) : (y))
+
+#if !defined(__GNUC__) && !defined(__clang__)
+# define __attribute__(x)
+#endif
+
+typedef struct Type Type;
+typedef struct Node Node;
+typedef struct Member Member;
+typedef struct Relocation Relocation;
+typedef struct Hideset Hideset;
+
+//
+// strings.c
+//
+
+typedef struct {
+ char **data;
+ int capacity;
+ int len;
+} StringArray;
+
+void strarray_push(StringArray *arr, char *s);
+
+//
+// tokenize.c
+//
+
+// Token
+typedef enum {
+ TK_IDENT, // Identifiers
+ TK_PUNCT, // Punctuators
+ TK_KEYWORD, // Keywords
+ TK_STR, // String literals
+ TK_NUM, // Numeric literals
+ TK_PP_NUM, // Preprocessing numbers
+ TK_EOF, // End-of-file markers
+} TokenKind;
+
+typedef struct {
+ char *name;
+ int file_no;
+ char *contents;
+
+ // For #line directive
+ char *display_name;
+ int line_delta;
+} File;
+
+// Token type
+typedef struct Token Token;
+struct Token {
+ TokenKind kind; // Token kind
+ Token *next; // Next token
+ int64_t val; // If kind is TK_NUM, its value
+ long double fval; // If kind is TK_NUM, its value
+ char *loc; // Token location
+ int len; // Token length
+ Type *ty; // Used if TK_NUM or TK_STR
+ char *str; // String literal contents including terminating '\0'
+
+ File *file; // Source location
+ char *filename; // Filename
+ int line_no; // Line number
+ int line_delta; // Line number
+ bool at_bol; // True if this token is at beginning of line
+ bool has_space; // True if this token follows a space character
+ Hideset *hideset; // For macro expansion
+ Token *origin; // If this is expanded from a macro, the original token
+};
+
+_Noreturn void error(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+_Noreturn void error_at(char *loc, char *fmt, ...) __attribute__((format(printf, 2, 3)));
+_Noreturn void error_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
+void warn_tok(Token *tok, char *fmt, ...) __attribute__((format(printf, 2, 3)));
+bool equal(Token *tok, char *op);
+Token *skip(Token *tok, char *op);
+bool consume(Token **rest, Token *tok, char *str);
+void convert_pp_tokens(Token *tok);
+File **get_input_files(void);
+File *new_file(char *name, int file_no, char *contents);
+Token *tokenize_string_literal(Token *tok, Type *basety);
+Token *tokenize(File *file);
+//Token *tokenize_file(char *filename);
+Token *tokenize_buf(const char *name, char *p);
+
+// note: replacing memstream-based format with asprintf version. moved down here
+// as error() is declared above.
+//char *format(char *fmt, ...) __attribute__((format(printf, 1, 2)));
+__attribute__((format(printf, 1, 2)))
+static inline char *format(const char *fmt, ...) {
+ char *ret;
+ va_list va;
+ va_start(va, fmt);
+ if (vasprintf(&ret, fmt, va) == -1) error("couldn't allocate memory");
+ va_end(va);
+ return ret;
+}
+
+#define unreachable() \
+ error("internal error at %s:%d", __FILE__, __LINE__)
+
+//
+// preprocess.c
+//
+
+char *search_include_paths(char *filename);
+void init_macros(void);
+void define_macro(char *name, char *buf);
+void undef_macro(char *name);
+Token *preprocess(Token *tok);
+
+//
+// parse.c
+//
+
+// Variable or function
+typedef struct Obj Obj;
+struct Obj {
+ Obj *next;
+ char *name; // Variable name
+ Type *ty; // Type
+ Token *tok; // representative token
+ bool is_local; // local or global/function
+ int align; // alignment
+
+ // Local variable
+ int offset;
+
+ // Global variable or function
+ bool is_function;
+ bool is_definition;
+ bool is_static;
+
+ // Global variable
+ bool is_tentative;
+ bool is_tls;
+ char *init_data;
+ Relocation *rel;
+
+ // Function
+ bool is_inline;
+ Obj *params;
+ Node *body;
+ Obj *locals;
+ Obj *va_area;
+ Obj *alloca_bottom;
+ int stack_size;
+
+ // Static inline function
+ bool is_live;
+ bool is_root;
+ StringArray refs;
+};
+
+// Global variable can be initialized either by a constant expression
+// or a pointer to another global variable. This struct represents the
+// latter.
+typedef struct Relocation Relocation;
+struct Relocation {
+ Relocation *next;
+ int offset;
+ char **label;
+ long addend;
+};
+
+// AST node
+typedef enum {
+ ND_NULL_EXPR, // Do nothing
+ ND_ADD, // +
+ ND_SUB, // -
+ ND_MUL, // *
+ ND_DIV, // /
+ ND_NEG, // unary -
+ ND_MOD, // %
+ ND_BITAND, // &
+ ND_BITOR, // |
+ ND_BITXOR, // ^
+ ND_SHL, // <<
+ ND_SHR, // >>
+ ND_EQ, // ==
+ ND_NE, // !=
+ ND_LT, // <
+ ND_LE, // <=
+ ND_ASSIGN, // =
+ ND_COND, // ?:
+ ND_COMMA, // ,
+ ND_MEMBER, // . (struct member access)
+ ND_ADDR, // unary &
+ ND_DEREF, // unary *
+ ND_NOT, // !
+ ND_BITNOT, // ~
+ ND_LOGAND, // &&
+ ND_LOGOR, // ||
+ ND_RETURN, // "return"
+ ND_IF, // "if"
+ ND_FOR, // "for" or "while"
+ ND_DO, // "do"
+ ND_SWITCH, // "switch"
+ ND_CASE, // "case"
+ ND_BLOCK, // { ... }
+ ND_GOTO, // "goto"
+ ND_GOTO_EXPR, // "goto" labels-as-values
+ ND_LABEL, // Labeled statement
+ ND_LABEL_VAL, // [GNU] Labels-as-values
+ ND_FUNCALL, // Function call
+ ND_EXPR_STMT, // Expression statement
+ ND_STMT_EXPR, // Statement expression
+ ND_VAR, // Variable
+ ND_VLA_PTR, // VLA designator
+ ND_NUM, // Integer
+ ND_CAST, // Type cast
+ ND_MEMZERO, // Zero-clear a stack variable
+ ND_ASM, // "asm"
+ ND_CAS, // Atomic compare-and-swap
+ ND_EXCH, // Atomic exchange
+} NodeKind;
+
+// AST node type
+struct Node {
+ NodeKind kind; // Node kind
+ Node *next; // Next node
+ Type *ty; // Type, e.g. int or pointer to int
+ Token *tok; // Representative token
+
+ Node *lhs; // Left-hand side
+ Node *rhs; // Right-hand side
+
+ // "if" or "for" statement
+ Node *cond;
+ Node *then;
+ Node *els;
+ Node *init;
+ Node *inc;
+
+ // "break" and "continue" labels
+ char *brk_label;
+ char *cont_label;
+
+ // Block or statement expression
+ Node *body;
+
+ // Struct member access
+ Member *member;
+
+ // Function call
+ Type *func_ty;
+ Node *args;
+ bool pass_by_stack;
+ Obj *ret_buffer;
+
+ // Goto or labeled statement, or labels-as-values
+ char *label;
+ char *unique_label;
+ Node *goto_next;
+
+ // Switch
+ Node *case_next;
+ Node *default_case;
+
+ // Case
+ long begin;
+ long end;
+
+ // "asm" string literal
+ char *asm_str;
+
+ // Atomic compare-and-swap
+ Node *cas_addr;
+ Node *cas_old;
+ Node *cas_new;
+
+ // Atomic op= operators
+ Obj *atomic_addr;
+ Node *atomic_expr;
+
+ // Variable
+ Obj *var;
+
+ // Numeric literal
+ int64_t val;
+ long double fval;
+};
+
+Node *new_cast(Node *expr, Type *ty);
+int64_t const_expr(Token **rest, Token *tok);
+Obj *parse(Token *tok);
+
+//
+// type.c
+//
+
+typedef enum {
+ TY_VOID,
+ TY_BOOL,
+ TY_CHAR,
+ TY_SHORT,
+ TY_INT,
+ TY_LONG,
+ TY_FLOAT,
+ TY_DOUBLE,
+ TY_LDOUBLE,
+ TY_ENUM,
+ TY_PTR,
+ TY_FUNC,
+ TY_ARRAY,
+ TY_VLA, // variable-length array
+ TY_STRUCT,
+ TY_UNION,
+} TypeKind;
+
+struct Type {
+ TypeKind kind;
+ int size; // sizeof() value
+ int align; // alignment
+ bool is_unsigned; // unsigned or signed
+ bool is_atomic; // true if _Atomic
+ Type *origin; // for type compatibility check
+
+ // Pointer-to or array-of type. We intentionally use the same member
+ // to represent pointer/array duality in C.
+ //
+ // In many contexts in which a pointer is expected, we examine this
+ // member instead of "kind" member to determine whether a type is a
+ // pointer or not. That means in many contexts "array of T" is
+ // naturally handled as if it were "pointer to T", as required by
+ // the C spec.
+ Type *base;
+
+ // Declaration
+ Token *name;
+ Token *name_pos;
+
+ // Array
+ int array_len;
+
+ // Variable-length array
+ Node *vla_len; // # of elements
+ Obj *vla_size; // sizeof() value
+
+ // Struct
+ Member *members;
+ bool is_flexible;
+ bool is_packed;
+
+ // Function type
+ Type *return_ty;
+ Type *params;
+ bool is_variadic;
+ Type *next;
+};
+
+// Struct member
+struct Member {
+ Member *next;
+ Type *ty;
+ Token *tok; // for error message
+ Token *name;
+ int idx;
+ int align;
+ int offset;
+
+ // Bitfield
+ bool is_bitfield;
+ int bit_offset;
+ int bit_width;
+};
+
+extern Type *ty_void;
+extern Type *ty_bool;
+
+extern Type *ty_char;
+extern Type *ty_short;
+extern Type *ty_int;
+extern Type *ty_long;
+
+extern Type *ty_uchar;
+extern Type *ty_ushort;
+extern Type *ty_uint;
+extern Type *ty_ulong;
+
+extern Type *ty_float;
+extern Type *ty_double;
+extern Type *ty_ldouble;
+
+bool is_integer(Type *ty);
+bool is_flonum(Type *ty);
+bool is_numeric(Type *ty);
+bool is_compatible(Type *t1, Type *t2);
+Type *copy_type(Type *ty);
+Type *pointer_to(Type *base);
+Type *func_type(Type *return_ty);
+Type *array_of(Type *base, int size);
+Type *vla_of(Type *base, Node *expr);
+Type *enum_type(void);
+Type *struct_type(void);
+void add_type(Node *node);
+
+//
+// codegen.c
+//
+
+void codegen(Obj *prog, FILE *out);
+int align_to(int n, int align);
+
+//
+// unicode.c
+//
+
+int encode_utf8(char *buf, uint32_t c);
+uint32_t decode_utf8(char **new_pos, char *p);
+bool is_ident1(uint32_t c);
+bool is_ident2(uint32_t c);
+int display_width(char *p, int len);
+
+//
+// hashmap.c
+//
+
+typedef struct {
+ char *key;
+ int keylen;
+ void *val;
+} HashEntry;
+
+typedef struct {
+ HashEntry *buckets;
+ int capacity;
+ int used;
+} HashMap;
+
+void *hashmap_get(HashMap *map, char *key);
+void *hashmap_get2(HashMap *map, char *key, int keylen);
+void hashmap_put(HashMap *map, char *key, void *val);
+void hashmap_put2(HashMap *map, char *key, int keylen, void *val);
+void hashmap_delete(HashMap *map, char *key);
+void hashmap_delete2(HashMap *map, char *key, int keylen);
+void hashmap_test(void);
+
+//
+// main.c
+//
+
+bool file_exists(char *path);
+
+extern StringArray include_paths;
+extern bool opt_fpic;
+extern bool opt_fcommon;
+extern char *base_file;
+
+#endif
diff --git a/src/3p/chibicc/codegen.c b/src/3p/chibicc/codegen.c
new file mode 100644
index 0000000..da11fd7
--- /dev/null
+++ b/src/3p/chibicc/codegen.c
@@ -0,0 +1,1595 @@
+#include "chibicc.h"
+
+#define GP_MAX 6
+#define FP_MAX 8
+
+static FILE *output_file;
+static int depth;
+static char *argreg8[] = {"%dil", "%sil", "%dl", "%cl", "%r8b", "%r9b"};
+static char *argreg16[] = {"%di", "%si", "%dx", "%cx", "%r8w", "%r9w"};
+static char *argreg32[] = {"%edi", "%esi", "%edx", "%ecx", "%r8d", "%r9d"};
+static char *argreg64[] = {"%rdi", "%rsi", "%rdx", "%rcx", "%r8", "%r9"};
+static Obj *current_fn;
+
+static void gen_expr(Node *node);
+static void gen_stmt(Node *node);
+
+__attribute__((format(printf, 1, 2)))
+static void println(char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ vfprintf(output_file, fmt, ap);
+ va_end(ap);
+ fprintf(output_file, "\n");
+}
+
+static int count(void) {
+ static int i = 1;
+ return i++;
+}
+
+static void push(void) {
+ println(" push %%rax");
+ depth++;
+}
+
+static void pop(char *arg) {
+ println(" pop %s", arg);
+ depth--;
+}
+
+static void pushf(void) {
+ println(" sub $8, %%rsp");
+ println(" movsd %%xmm0, (%%rsp)");
+ depth++;
+}
+
+static void popf(int reg) {
+ println(" movsd (%%rsp), %%xmm%d", reg);
+ println(" add $8, %%rsp");
+ depth--;
+}
+
+// Round up `n` to the nearest multiple of `align`. For instance,
+// align_to(5, 8) returns 8 and align_to(11, 8) returns 16.
+int align_to(int n, int align) {
+ return (n + align - 1) / align * align;
+}
+
+static char *reg_dx(int sz) {
+ switch (sz) {
+ case 1: return "%dl";
+ case 2: return "%dx";
+ case 4: return "%edx";
+ case 8: return "%rdx";
+ }
+ unreachable();
+}
+
+static char *reg_ax(int sz) {
+ switch (sz) {
+ case 1: return "%al";
+ case 2: return "%ax";
+ case 4: return "%eax";
+ case 8: return "%rax";
+ }
+ unreachable();
+}
+
+// Compute the absolute address of a given node.
+// It's an error if a given node does not reside in memory.
+static void gen_addr(Node *node) {
+ switch (node->kind) {
+ case ND_VAR:
+ // Variable-length array, which is always local.
+ if (node->var->ty->kind == TY_VLA) {
+ println(" mov %d(%%rbp), %%rax", node->var->offset);
+ return;
+ }
+
+ // Local variable
+ if (node->var->is_local) {
+ println(" lea %d(%%rbp), %%rax", node->var->offset);
+ return;
+ }
+
+ if (opt_fpic) {
+ // Thread-local variable
+ if (node->var->is_tls) {
+ println(" data16 lea %s@tlsgd(%%rip), %%rdi", node->var->name);
+ println(" .value 0x6666");
+ println(" rex64");
+ println(" call __tls_get_addr@PLT");
+ return;
+ }
+
+ // Function or global variable
+ println(" mov %s@GOTPCREL(%%rip), %%rax", node->var->name);
+ return;
+ }
+
+ // Thread-local variable
+ if (node->var->is_tls) {
+ println(" mov %%fs:0, %%rax");
+ println(" add $%s@tpoff, %%rax", node->var->name);
+ return;
+ }
+
+ // Here, we generate an absolute address of a function or a global
+ // variable. Even though they exist at a certain address at runtime,
+ // their addresses are not known at link-time for the following
+ // two reasons.
+ //
+ // - Address randomization: Executables are loaded to memory as a
+ // whole but it is not known what address they are loaded to.
+ // Therefore, at link-time, relative address in the same
+ // exectuable (i.e. the distance between two functions in the
+ // same executable) is known, but the absolute address is not
+ // known.
+ //
+ // - Dynamic linking: Dynamic shared objects (DSOs) or .so files
+ // are loaded to memory alongside an executable at runtime and
+ // linked by the runtime loader in memory. We know nothing
+ // about addresses of global stuff that may be defined by DSOs
+ // until the runtime relocation is complete.
+ //
+ // In order to deal with the former case, we use RIP-relative
+ // addressing, denoted by `(%rip)`. For the latter, we obtain an
+ // address of a stuff that may be in a shared object file from the
+ // Global Offset Table using `@GOTPCREL(%rip)` notation.
+
+ // Function
+ if (node->ty->kind == TY_FUNC) {
+ if (node->var->is_definition)
+ println(" lea %s(%%rip), %%rax", node->var->name);
+ else
+ println(" mov %s@GOTPCREL(%%rip), %%rax", node->var->name);
+ return;
+ }
+
+ // Global variable
+ println(" lea %s(%%rip), %%rax", node->var->name);
+ return;
+ case ND_DEREF:
+ gen_expr(node->lhs);
+ return;
+ case ND_COMMA:
+ gen_expr(node->lhs);
+ gen_addr(node->rhs);
+ return;
+ case ND_MEMBER:
+ gen_addr(node->lhs);
+ println(" add $%d, %%rax", node->member->offset);
+ return;
+ case ND_FUNCALL:
+ if (node->ret_buffer) {
+ gen_expr(node);
+ return;
+ }
+ break;
+ case ND_ASSIGN:
+ case ND_COND:
+ if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION) {
+ gen_expr(node);
+ return;
+ }
+ break;
+ case ND_VLA_PTR:
+ println(" lea %d(%%rbp), %%rax", node->var->offset);
+ return;
+ }
+
+ error_tok(node->tok, "not an lvalue");
+}
+
+// Load a value from where %rax is pointing to.
+static void load(Type *ty) {
+ switch (ty->kind) {
+ case TY_ARRAY:
+ case TY_STRUCT:
+ case TY_UNION:
+ case TY_FUNC:
+ case TY_VLA:
+ // If it is an array, do not attempt to load a value to the
+ // register because in general we can't load an entire array to a
+ // register. As a result, the result of an evaluation of an array
+ // becomes not the array itself but the address of the array.
+ // This is where "array is automatically converted to a pointer to
+ // the first element of the array in C" occurs.
+ return;
+ case TY_FLOAT:
+ println(" movss (%%rax), %%xmm0");
+ return;
+ case TY_DOUBLE:
+ println(" movsd (%%rax), %%xmm0");
+ return;
+ case TY_LDOUBLE:
+ println(" fldt (%%rax)");
+ return;
+ }
+
+ char *insn = ty->is_unsigned ? "movz" : "movs";
+
+ // When we load a char or a short value to a register, we always
+ // extend them to the size of int, so we can assume the lower half of
+ // a register always contains a valid value. The upper half of a
+ // register for char, short and int may contain garbage. When we load
+ // a long value to a register, it simply occupies the entire register.
+ if (ty->size == 1)
+ println(" %sbl (%%rax), %%eax", insn);
+ else if (ty->size == 2)
+ println(" %swl (%%rax), %%eax", insn);
+ else if (ty->size == 4)
+ println(" movsxd (%%rax), %%rax");
+ else
+ println(" mov (%%rax), %%rax");
+}
+
+// Store %rax to an address that the stack top is pointing to.
+static void store(Type *ty) {
+ pop("%rdi");
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ for (int i = 0; i < ty->size; i++) {
+ println(" mov %d(%%rax), %%r8b", i);
+ println(" mov %%r8b, %d(%%rdi)", i);
+ }
+ return;
+ case TY_FLOAT:
+ println(" movss %%xmm0, (%%rdi)");
+ return;
+ case TY_DOUBLE:
+ println(" movsd %%xmm0, (%%rdi)");
+ return;
+ case TY_LDOUBLE:
+ println(" fstpt (%%rdi)");
+ return;
+ }
+
+ if (ty->size == 1)
+ println(" mov %%al, (%%rdi)");
+ else if (ty->size == 2)
+ println(" mov %%ax, (%%rdi)");
+ else if (ty->size == 4)
+ println(" mov %%eax, (%%rdi)");
+ else
+ println(" mov %%rax, (%%rdi)");
+}
+
+static void cmp_zero(Type *ty) {
+ switch (ty->kind) {
+ case TY_FLOAT:
+ println(" xorps %%xmm1, %%xmm1");
+ println(" ucomiss %%xmm1, %%xmm0");
+ return;
+ case TY_DOUBLE:
+ println(" xorpd %%xmm1, %%xmm1");
+ println(" ucomisd %%xmm1, %%xmm0");
+ return;
+ case TY_LDOUBLE:
+ println(" fldz");
+ println(" fucomip");
+ println(" fstp %%st(0)");
+ return;
+ }
+
+ if (is_integer(ty) && ty->size <= 4)
+ println(" cmp $0, %%eax");
+ else
+ println(" cmp $0, %%rax");
+}
+
+enum { I8, I16, I32, I64, U8, U16, U32, U64, F32, F64, F80 };
+
+static int getTypeId(Type *ty) {
+ switch (ty->kind) {
+ case TY_CHAR:
+ return ty->is_unsigned ? U8 : I8;
+ case TY_SHORT:
+ return ty->is_unsigned ? U16 : I16;
+ case TY_INT:
+ return ty->is_unsigned ? U32 : I32;
+ case TY_LONG:
+ return ty->is_unsigned ? U64 : I64;
+ case TY_FLOAT:
+ return F32;
+ case TY_DOUBLE:
+ return F64;
+ case TY_LDOUBLE:
+ return F80;
+ }
+ return U64;
+}
+
+// The table for type casts
+static char i32i8[] = "movsbl %al, %eax";
+static char i32u8[] = "movzbl %al, %eax";
+static char i32i16[] = "movswl %ax, %eax";
+static char i32u16[] = "movzwl %ax, %eax";
+static char i32f32[] = "cvtsi2ssl %eax, %xmm0";
+static char i32i64[] = "movsxd %eax, %rax";
+static char i32f64[] = "cvtsi2sdl %eax, %xmm0";
+static char i32f80[] = "mov %eax, -4(%rsp); fildl -4(%rsp)";
+
+static char u32f32[] = "mov %eax, %eax; cvtsi2ssq %rax, %xmm0";
+static char u32i64[] = "mov %eax, %eax";
+static char u32f64[] = "mov %eax, %eax; cvtsi2sdq %rax, %xmm0";
+static char u32f80[] = "mov %eax, %eax; mov %rax, -8(%rsp); fildll -8(%rsp)";
+
+static char i64f32[] = "cvtsi2ssq %rax, %xmm0";
+static char i64f64[] = "cvtsi2sdq %rax, %xmm0";
+static char i64f80[] = "movq %rax, -8(%rsp); fildll -8(%rsp)";
+
+static char u64f32[] = "cvtsi2ssq %rax, %xmm0";
+static char u64f64[] =
+ "test %rax,%rax; js 1f; pxor %xmm0,%xmm0; cvtsi2sd %rax,%xmm0; jmp 2f; "
+ "1: mov %rax,%rdi; and $1,%eax; pxor %xmm0,%xmm0; shr %rdi; "
+ "or %rax,%rdi; cvtsi2sd %rdi,%xmm0; addsd %xmm0,%xmm0; 2:";
+static char u64f80[] =
+ "mov %rax, -8(%rsp); fildq -8(%rsp); test %rax, %rax; jns 1f;"
+ "mov $1602224128, %eax; mov %eax, -4(%rsp); fadds -4(%rsp); 1:";
+
+static char f32i8[] = "cvttss2sil %xmm0, %eax; movsbl %al, %eax";
+static char f32u8[] = "cvttss2sil %xmm0, %eax; movzbl %al, %eax";
+static char f32i16[] = "cvttss2sil %xmm0, %eax; movswl %ax, %eax";
+static char f32u16[] = "cvttss2sil %xmm0, %eax; movzwl %ax, %eax";
+static char f32i32[] = "cvttss2sil %xmm0, %eax";
+static char f32u32[] = "cvttss2siq %xmm0, %rax";
+static char f32i64[] = "cvttss2siq %xmm0, %rax";
+static char f32u64[] = "cvttss2siq %xmm0, %rax";
+static char f32f64[] = "cvtss2sd %xmm0, %xmm0";
+static char f32f80[] = "movss %xmm0, -4(%rsp); flds -4(%rsp)";
+
+static char f64i8[] = "cvttsd2sil %xmm0, %eax; movsbl %al, %eax";
+static char f64u8[] = "cvttsd2sil %xmm0, %eax; movzbl %al, %eax";
+static char f64i16[] = "cvttsd2sil %xmm0, %eax; movswl %ax, %eax";
+static char f64u16[] = "cvttsd2sil %xmm0, %eax; movzwl %ax, %eax";
+static char f64i32[] = "cvttsd2sil %xmm0, %eax";
+static char f64u32[] = "cvttsd2siq %xmm0, %rax";
+static char f64i64[] = "cvttsd2siq %xmm0, %rax";
+static char f64u64[] = "cvttsd2siq %xmm0, %rax";
+static char f64f32[] = "cvtsd2ss %xmm0, %xmm0";
+static char f64f80[] = "movsd %xmm0, -8(%rsp); fldl -8(%rsp)";
+
+#define FROM_F80_1 \
+ "fnstcw -10(%rsp); movzwl -10(%rsp), %eax; or $12, %ah; " \
+ "mov %ax, -12(%rsp); fldcw -12(%rsp); "
+
+#define FROM_F80_2 " -24(%rsp); fldcw -10(%rsp); "
+
+static char f80i8[] = FROM_F80_1 "fistps" FROM_F80_2 "movsbl -24(%rsp), %eax";
+static char f80u8[] = FROM_F80_1 "fistps" FROM_F80_2 "movzbl -24(%rsp), %eax";
+static char f80i16[] = FROM_F80_1 "fistps" FROM_F80_2 "movzbl -24(%rsp), %eax";
+static char f80u16[] = FROM_F80_1 "fistpl" FROM_F80_2 "movswl -24(%rsp), %eax";
+static char f80i32[] = FROM_F80_1 "fistpl" FROM_F80_2 "mov -24(%rsp), %eax";
+static char f80u32[] = FROM_F80_1 "fistpl" FROM_F80_2 "mov -24(%rsp), %eax";
+static char f80i64[] = FROM_F80_1 "fistpq" FROM_F80_2 "mov -24(%rsp), %rax";
+static char f80u64[] = FROM_F80_1 "fistpq" FROM_F80_2 "mov -24(%rsp), %rax";
+static char f80f32[] = "fstps -8(%rsp); movss -8(%rsp), %xmm0";
+static char f80f64[] = "fstpl -8(%rsp); movsd -8(%rsp), %xmm0";
+
+static char *cast_table[][11] = {
+ // i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 f80
+ {NULL, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i8
+ {i32i8, NULL, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i16
+ {i32i8, i32i16, NULL, i32i64, i32u8, i32u16, NULL, i32i64, i32f32, i32f64, i32f80}, // i32
+ {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, i64f32, i64f64, i64f80}, // i64
+
+ {i32i8, NULL, NULL, i32i64, NULL, NULL, NULL, i32i64, i32f32, i32f64, i32f80}, // u8
+ {i32i8, i32i16, NULL, i32i64, i32u8, NULL, NULL, i32i64, i32f32, i32f64, i32f80}, // u16
+ {i32i8, i32i16, NULL, u32i64, i32u8, i32u16, NULL, u32i64, u32f32, u32f64, u32f80}, // u32
+ {i32i8, i32i16, NULL, NULL, i32u8, i32u16, NULL, NULL, u64f32, u64f64, u64f80}, // u64
+
+ {f32i8, f32i16, f32i32, f32i64, f32u8, f32u16, f32u32, f32u64, NULL, f32f64, f32f80}, // f32
+ {f64i8, f64i16, f64i32, f64i64, f64u8, f64u16, f64u32, f64u64, f64f32, NULL, f64f80}, // f64
+ {f80i8, f80i16, f80i32, f80i64, f80u8, f80u16, f80u32, f80u64, f80f32, f80f64, NULL}, // f80
+};
+
+static void cast(Type *from, Type *to) {
+ if (to->kind == TY_VOID)
+ return;
+
+ if (to->kind == TY_BOOL) {
+ cmp_zero(from);
+ println(" setne %%al");
+ println(" movzx %%al, %%eax");
+ return;
+ }
+
+ int t1 = getTypeId(from);
+ int t2 = getTypeId(to);
+ if (cast_table[t1][t2])
+ println(" %s", cast_table[t1][t2]);
+}
+
+// Structs or unions equal or smaller than 16 bytes are passed
+// using up to two registers.
+//
+// If the first 8 bytes contains only floating-point type members,
+// they are passed in an XMM register. Otherwise, they are passed
+// in a general-purpose register.
+//
+// If a struct/union is larger than 8 bytes, the same rule is
+// applied to the the next 8 byte chunk.
+//
+// This function returns true if `ty` has only floating-point
+// members in its byte range [lo, hi).
+static bool has_flonum(Type *ty, int lo, int hi, int offset) {
+ if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) {
+ for (Member *mem = ty->members; mem; mem = mem->next)
+ if (!has_flonum(mem->ty, lo, hi, offset + mem->offset))
+ return false;
+ return true;
+ }
+
+ if (ty->kind == TY_ARRAY) {
+ for (int i = 0; i < ty->array_len; i++)
+ if (!has_flonum(ty->base, lo, hi, offset + ty->base->size * i))
+ return false;
+ return true;
+ }
+
+ return offset < lo || hi <= offset || ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE;
+}
+
+static bool has_flonum1(Type *ty) {
+ return has_flonum(ty, 0, 8, 0);
+}
+
+static bool has_flonum2(Type *ty) {
+ return has_flonum(ty, 8, 16, 0);
+}
+
+static void push_struct(Type *ty) {
+ int sz = align_to(ty->size, 8);
+ println(" sub $%d, %%rsp", sz);
+ depth += sz / 8;
+
+ for (int i = 0; i < ty->size; i++) {
+ println(" mov %d(%%rax), %%r10b", i);
+ println(" mov %%r10b, %d(%%rsp)", i);
+ }
+}
+
+static void push_args2(Node *args, bool first_pass) {
+ if (!args)
+ return;
+ push_args2(args->next, first_pass);
+
+ if ((first_pass && !args->pass_by_stack) || (!first_pass && args->pass_by_stack))
+ return;
+
+ gen_expr(args);
+
+ switch (args->ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ push_struct(args->ty);
+ break;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ pushf();
+ break;
+ case TY_LDOUBLE:
+ println(" sub $16, %%rsp");
+ println(" fstpt (%%rsp)");
+ depth += 2;
+ break;
+ default:
+ push();
+ }
+}
+
+// Load function call arguments. Arguments are already evaluated and
+// stored to the stack as local variables. What we need to do in this
+// function is to load them to registers or push them to the stack as
+// specified by the x86-64 psABI. Here is what the spec says:
+//
+// - Up to 6 arguments of integral type are passed using RDI, RSI,
+// RDX, RCX, R8 and R9.
+//
+// - Up to 8 arguments of floating-point type are passed using XMM0 to
+// XMM7.
+//
+// - If all registers of an appropriate type are already used, push an
+// argument to the stack in the right-to-left order.
+//
+// - Each argument passed on the stack takes 8 bytes, and the end of
+// the argument area must be aligned to a 16 byte boundary.
+//
+// - If a function is variadic, set the number of floating-point type
+// arguments to RAX.
+static int push_args(Node *node) {
+ int stack = 0, gp = 0, fp = 0;
+
+ // If the return type is a large struct/union, the caller passes
+ // a pointer to a buffer as if it were the first argument.
+ if (node->ret_buffer && node->ty->size > 16)
+ gp++;
+
+ // Load as many arguments to the registers as possible.
+ for (Node *arg = node->args; arg; arg = arg->next) {
+ Type *ty = arg->ty;
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ if (ty->size > 16) {
+ arg->pass_by_stack = true;
+ stack += align_to(ty->size, 8) / 8;
+ } else {
+ bool fp1 = has_flonum1(ty);
+ bool fp2 = has_flonum2(ty);
+
+ if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {
+ fp = fp + fp1 + fp2;
+ gp = gp + !fp1 + !fp2;
+ } else {
+ arg->pass_by_stack = true;
+ stack += align_to(ty->size, 8) / 8;
+ }
+ }
+ break;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ if (fp++ >= FP_MAX) {
+ arg->pass_by_stack = true;
+ stack++;
+ }
+ break;
+ case TY_LDOUBLE:
+ arg->pass_by_stack = true;
+ stack += 2;
+ break;
+ default:
+ if (gp++ >= GP_MAX) {
+ arg->pass_by_stack = true;
+ stack++;
+ }
+ }
+ }
+
+ if ((depth + stack) % 2 == 1) {
+ println(" sub $8, %%rsp");
+ depth++;
+ stack++;
+ }
+
+ push_args2(node->args, true);
+ push_args2(node->args, false);
+
+ // If the return type is a large struct/union, the caller passes
+ // a pointer to a buffer as if it were the first argument.
+ if (node->ret_buffer && node->ty->size > 16) {
+ println(" lea %d(%%rbp), %%rax", node->ret_buffer->offset);
+ push();
+ }
+
+ return stack;
+}
+
+static void copy_ret_buffer(Obj *var) {
+ Type *ty = var->ty;
+ int gp = 0, fp = 0;
+
+ if (has_flonum1(ty)) {
+ assert(ty->size == 4 || 8 <= ty->size);
+ if (ty->size == 4)
+ println(" movss %%xmm0, %d(%%rbp)", var->offset);
+ else
+ println(" movsd %%xmm0, %d(%%rbp)", var->offset);
+ fp++;
+ } else {
+ for (int i = 0; i < MIN(8, ty->size); i++) {
+ println(" mov %%al, %d(%%rbp)", var->offset + i);
+ println(" shr $8, %%rax");
+ }
+ gp++;
+ }
+
+ if (ty->size > 8) {
+ if (has_flonum2(ty)) {
+ assert(ty->size == 12 || ty->size == 16);
+ if (ty->size == 12)
+ println(" movss %%xmm%d, %d(%%rbp)", fp, var->offset + 8);
+ else
+ println(" movsd %%xmm%d, %d(%%rbp)", fp, var->offset + 8);
+ } else {
+ char *reg1 = (gp == 0) ? "%al" : "%dl";
+ char *reg2 = (gp == 0) ? "%rax" : "%rdx";
+ for (int i = 8; i < MIN(16, ty->size); i++) {
+ println(" mov %s, %d(%%rbp)", reg1, var->offset + i);
+ println(" shr $8, %s", reg2);
+ }
+ }
+ }
+}
+
+static void copy_struct_reg(void) {
+ Type *ty = current_fn->ty->return_ty;
+ int gp = 0, fp = 0;
+
+ println(" mov %%rax, %%rdi");
+
+ if (has_flonum(ty, 0, 8, 0)) {
+ assert(ty->size == 4 || 8 <= ty->size);
+ if (ty->size == 4)
+ println(" movss (%%rdi), %%xmm0");
+ else
+ println(" movsd (%%rdi), %%xmm0");
+ fp++;
+ } else {
+ println(" mov $0, %%rax");
+ for (int i = MIN(8, ty->size) - 1; i >= 0; i--) {
+ println(" shl $8, %%rax");
+ println(" mov %d(%%rdi), %%al", i);
+ }
+ gp++;
+ }
+
+ if (ty->size > 8) {
+ if (has_flonum(ty, 8, 16, 0)) {
+ assert(ty->size == 12 || ty->size == 16);
+ if (ty->size == 4)
+ println(" movss 8(%%rdi), %%xmm%d", fp);
+ else
+ println(" movsd 8(%%rdi), %%xmm%d", fp);
+ } else {
+ char *reg1 = (gp == 0) ? "%al" : "%dl";
+ char *reg2 = (gp == 0) ? "%rax" : "%rdx";
+ println(" mov $0, %s", reg2);
+ for (int i = MIN(16, ty->size) - 1; i >= 8; i--) {
+ println(" shl $8, %s", reg2);
+ println(" mov %d(%%rdi), %s", i, reg1);
+ }
+ }
+ }
+}
+
+static void copy_struct_mem(void) {
+ Type *ty = current_fn->ty->return_ty;
+ Obj *var = current_fn->params;
+
+ println(" mov %d(%%rbp), %%rdi", var->offset);
+
+ for (int i = 0; i < ty->size; i++) {
+ println(" mov %d(%%rax), %%dl", i);
+ println(" mov %%dl, %d(%%rdi)", i);
+ }
+}
+
+static void builtin_alloca(void) {
+ // Align size to 16 bytes.
+ println(" add $15, %%rdi");
+ println(" and $0xfffffff0, %%edi");
+
+ // Shift the temporary area by %rdi.
+ println(" mov %d(%%rbp), %%rcx", current_fn->alloca_bottom->offset);
+ println(" sub %%rsp, %%rcx");
+ println(" mov %%rsp, %%rax");
+ println(" sub %%rdi, %%rsp");
+ println(" mov %%rsp, %%rdx");
+ println("1:");
+ println(" cmp $0, %%rcx");
+ println(" je 2f");
+ println(" mov (%%rax), %%r8b");
+ println(" mov %%r8b, (%%rdx)");
+ println(" inc %%rdx");
+ println(" inc %%rax");
+ println(" dec %%rcx");
+ println(" jmp 1b");
+ println("2:");
+
+ // Move alloca_bottom pointer.
+ println(" mov %d(%%rbp), %%rax", current_fn->alloca_bottom->offset);
+ println(" sub %%rdi, %%rax");
+ println(" mov %%rax, %d(%%rbp)", current_fn->alloca_bottom->offset);
+}
+
+// Generate code for a given node.
+static void gen_expr(Node *node) {
+ println(" .loc %d %d", node->tok->file->file_no, node->tok->line_no);
+
+ switch (node->kind) {
+ case ND_NULL_EXPR:
+ return;
+ case ND_NUM: {
+ switch (node->ty->kind) {
+ case TY_FLOAT: {
+ union { float f32; uint32_t u32; } u = { node->fval };
+ println(" mov $%u, %%eax # float %Lf", u.u32, node->fval);
+ println(" movq %%rax, %%xmm0");
+ return;
+ }
+ case TY_DOUBLE: {
+ union { double f64; uint64_t u64; } u = { node->fval };
+ println(" mov $%lu, %%rax # double %Lf", u.u64, node->fval);
+ println(" movq %%rax, %%xmm0");
+ return;
+ }
+ case TY_LDOUBLE: {
+ union { long double f80; uint64_t u64[2]; } u;
+ memset(&u, 0, sizeof(u));
+ u.f80 = node->fval;
+ println(" mov $%lu, %%rax # long double %Lf", u.u64[0], node->fval);
+ println(" mov %%rax, -16(%%rsp)");
+ println(" mov $%lu, %%rax", u.u64[1]);
+ println(" mov %%rax, -8(%%rsp)");
+ println(" fldt -16(%%rsp)");
+ return;
+ }
+ }
+
+ println(" mov $%ld, %%rax", node->val);
+ return;
+ }
+ case ND_NEG:
+ gen_expr(node->lhs);
+
+ switch (node->ty->kind) {
+ case TY_FLOAT:
+ println(" mov $1, %%rax");
+ println(" shl $31, %%rax");
+ println(" movq %%rax, %%xmm1");
+ println(" xorps %%xmm1, %%xmm0");
+ return;
+ case TY_DOUBLE:
+ println(" mov $1, %%rax");
+ println(" shl $63, %%rax");
+ println(" movq %%rax, %%xmm1");
+ println(" xorpd %%xmm1, %%xmm0");
+ return;
+ case TY_LDOUBLE:
+ println(" fchs");
+ return;
+ }
+
+ println(" neg %%rax");
+ return;
+ case ND_VAR:
+ gen_addr(node);
+ load(node->ty);
+ return;
+ case ND_MEMBER: {
+ gen_addr(node);
+ load(node->ty);
+
+ Member *mem = node->member;
+ if (mem->is_bitfield) {
+ println(" shl $%d, %%rax", 64 - mem->bit_width - mem->bit_offset);
+ if (mem->ty->is_unsigned)
+ println(" shr $%d, %%rax", 64 - mem->bit_width);
+ else
+ println(" sar $%d, %%rax", 64 - mem->bit_width);
+ }
+ return;
+ }
+ case ND_DEREF:
+ gen_expr(node->lhs);
+ load(node->ty);
+ return;
+ case ND_ADDR:
+ gen_addr(node->lhs);
+ return;
+ case ND_ASSIGN:
+ gen_addr(node->lhs);
+ push();
+ gen_expr(node->rhs);
+
+ if (node->lhs->kind == ND_MEMBER && node->lhs->member->is_bitfield) {
+ println(" mov %%rax, %%r8");
+
+ // If the lhs is a bitfield, we need to read the current value
+ // from memory and merge it with a new value.
+ Member *mem = node->lhs->member;
+ println(" mov %%rax, %%rdi");
+ println(" and $%ld, %%rdi", (1L << mem->bit_width) - 1);
+ println(" shl $%d, %%rdi", mem->bit_offset);
+
+ println(" mov (%%rsp), %%rax");
+ load(mem->ty);
+
+ long mask = ((1L << mem->bit_width) - 1) << mem->bit_offset;
+ println(" mov $%ld, %%r9", ~mask);
+ println(" and %%r9, %%rax");
+ println(" or %%rdi, %%rax");
+ store(node->ty);
+ println(" mov %%r8, %%rax");
+ return;
+ }
+
+ store(node->ty);
+ return;
+ case ND_STMT_EXPR:
+ for (Node *n = node->body; n; n = n->next)
+ gen_stmt(n);
+ return;
+ case ND_COMMA:
+ gen_expr(node->lhs);
+ gen_expr(node->rhs);
+ return;
+ case ND_CAST:
+ gen_expr(node->lhs);
+ cast(node->lhs->ty, node->ty);
+ return;
+ case ND_MEMZERO:
+ // `rep stosb` is equivalent to `memset(%rdi, %al, %rcx)`.
+ println(" mov $%d, %%rcx", node->var->ty->size);
+ println(" lea %d(%%rbp), %%rdi", node->var->offset);
+ println(" mov $0, %%al");
+ println(" rep stosb");
+ return;
+ case ND_COND: {
+ int c = count();
+ gen_expr(node->cond);
+ cmp_zero(node->cond->ty);
+ println(" je .L.else.%d", c);
+ gen_expr(node->then);
+ println(" jmp .L.end.%d", c);
+ println(".L.else.%d:", c);
+ gen_expr(node->els);
+ println(".L.end.%d:", c);
+ return;
+ }
+ case ND_NOT:
+ gen_expr(node->lhs);
+ cmp_zero(node->lhs->ty);
+ println(" sete %%al");
+ println(" movzx %%al, %%rax");
+ return;
+ case ND_BITNOT:
+ gen_expr(node->lhs);
+ println(" not %%rax");
+ return;
+ case ND_LOGAND: {
+ int c = count();
+ gen_expr(node->lhs);
+ cmp_zero(node->lhs->ty);
+ println(" je .L.false.%d", c);
+ gen_expr(node->rhs);
+ cmp_zero(node->rhs->ty);
+ println(" je .L.false.%d", c);
+ println(" mov $1, %%rax");
+ println(" jmp .L.end.%d", c);
+ println(".L.false.%d:", c);
+ println(" mov $0, %%rax");
+ println(".L.end.%d:", c);
+ return;
+ }
+ case ND_LOGOR: {
+ int c = count();
+ gen_expr(node->lhs);
+ cmp_zero(node->lhs->ty);
+ println(" jne .L.true.%d", c);
+ gen_expr(node->rhs);
+ cmp_zero(node->rhs->ty);
+ println(" jne .L.true.%d", c);
+ println(" mov $0, %%rax");
+ println(" jmp .L.end.%d", c);
+ println(".L.true.%d:", c);
+ println(" mov $1, %%rax");
+ println(".L.end.%d:", c);
+ return;
+ }
+ case ND_FUNCALL: {
+ if (node->lhs->kind == ND_VAR && !strcmp(node->lhs->var->name, "alloca")) {
+ gen_expr(node->args);
+ println(" mov %%rax, %%rdi");
+ builtin_alloca();
+ return;
+ }
+
+ int stack_args = push_args(node);
+ gen_expr(node->lhs);
+
+ int gp = 0, fp = 0;
+
+ // If the return type is a large struct/union, the caller passes
+ // a pointer to a buffer as if it were the first argument.
+ if (node->ret_buffer && node->ty->size > 16)
+ pop(argreg64[gp++]);
+
+ for (Node *arg = node->args; arg; arg = arg->next) {
+ Type *ty = arg->ty;
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ if (ty->size > 16)
+ continue;
+
+ bool fp1 = has_flonum1(ty);
+ bool fp2 = has_flonum2(ty);
+
+ if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {
+ if (fp1)
+ popf(fp++);
+ else
+ pop(argreg64[gp++]);
+
+ if (ty->size > 8) {
+ if (fp2)
+ popf(fp++);
+ else
+ pop(argreg64[gp++]);
+ }
+ }
+ break;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ if (fp < FP_MAX)
+ popf(fp++);
+ break;
+ case TY_LDOUBLE:
+ break;
+ default:
+ if (gp < GP_MAX)
+ pop(argreg64[gp++]);
+ }
+ }
+
+ println(" mov %%rax, %%r10");
+ println(" mov $%d, %%rax", fp);
+ println(" call *%%r10");
+ println(" add $%d, %%rsp", stack_args * 8);
+
+ depth -= stack_args;
+
+ // It looks like the most significant 48 or 56 bits in RAX may
+ // contain garbage if a function return type is short or bool/char,
+ // respectively. We clear the upper bits here.
+ switch (node->ty->kind) {
+ case TY_BOOL:
+ println(" movzx %%al, %%eax");
+ return;
+ case TY_CHAR:
+ if (node->ty->is_unsigned)
+ println(" movzbl %%al, %%eax");
+ else
+ println(" movsbl %%al, %%eax");
+ return;
+ case TY_SHORT:
+ if (node->ty->is_unsigned)
+ println(" movzwl %%ax, %%eax");
+ else
+ println(" movswl %%ax, %%eax");
+ return;
+ }
+
+ // If the return type is a small struct, a value is returned
+ // using up to two registers.
+ if (node->ret_buffer && node->ty->size <= 16) {
+ copy_ret_buffer(node->ret_buffer);
+ println(" lea %d(%%rbp), %%rax", node->ret_buffer->offset);
+ }
+
+ return;
+ }
+ case ND_LABEL_VAL:
+ println(" lea %s(%%rip), %%rax", node->unique_label);
+ return;
+ case ND_CAS: {
+ gen_expr(node->cas_addr);
+ push();
+ gen_expr(node->cas_new);
+ push();
+ gen_expr(node->cas_old);
+ println(" mov %%rax, %%r8");
+ load(node->cas_old->ty->base);
+ pop("%rdx"); // new
+ pop("%rdi"); // addr
+
+ int sz = node->cas_addr->ty->base->size;
+ println(" lock cmpxchg %s, (%%rdi)", reg_dx(sz));
+ println(" sete %%cl");
+ println(" je 1f");
+ println(" mov %s, (%%r8)", reg_ax(sz));
+ println("1:");
+ println(" movzbl %%cl, %%eax");
+ return;
+ }
+ case ND_EXCH: {
+ gen_expr(node->lhs);
+ push();
+ gen_expr(node->rhs);
+ pop("%rdi");
+
+ int sz = node->lhs->ty->base->size;
+ println(" xchg %s, (%%rdi)", reg_ax(sz));
+ return;
+ }
+ }
+
+ switch (node->lhs->ty->kind) {
+ case TY_FLOAT:
+ case TY_DOUBLE: {
+ gen_expr(node->rhs);
+ pushf();
+ gen_expr(node->lhs);
+ popf(1);
+
+ char *sz = (node->lhs->ty->kind == TY_FLOAT) ? "ss" : "sd";
+
+ switch (node->kind) {
+ case ND_ADD:
+ println(" add%s %%xmm1, %%xmm0", sz);
+ return;
+ case ND_SUB:
+ println(" sub%s %%xmm1, %%xmm0", sz);
+ return;
+ case ND_MUL:
+ println(" mul%s %%xmm1, %%xmm0", sz);
+ return;
+ case ND_DIV:
+ println(" div%s %%xmm1, %%xmm0", sz);
+ return;
+ case ND_EQ:
+ case ND_NE:
+ case ND_LT:
+ case ND_LE:
+ println(" ucomi%s %%xmm0, %%xmm1", sz);
+
+ if (node->kind == ND_EQ) {
+ println(" sete %%al");
+ println(" setnp %%dl");
+ println(" and %%dl, %%al");
+ } else if (node->kind == ND_NE) {
+ println(" setne %%al");
+ println(" setp %%dl");
+ println(" or %%dl, %%al");
+ } else if (node->kind == ND_LT) {
+ println(" seta %%al");
+ } else {
+ println(" setae %%al");
+ }
+
+ println(" and $1, %%al");
+ println(" movzb %%al, %%rax");
+ return;
+ }
+
+ error_tok(node->tok, "invalid expression");
+ }
+ case TY_LDOUBLE: {
+ gen_expr(node->lhs);
+ gen_expr(node->rhs);
+
+ switch (node->kind) {
+ case ND_ADD:
+ println(" faddp");
+ return;
+ case ND_SUB:
+ println(" fsubrp");
+ return;
+ case ND_MUL:
+ println(" fmulp");
+ return;
+ case ND_DIV:
+ println(" fdivrp");
+ return;
+ case ND_EQ:
+ case ND_NE:
+ case ND_LT:
+ case ND_LE:
+ println(" fcomip");
+ println(" fstp %%st(0)");
+
+ if (node->kind == ND_EQ)
+ println(" sete %%al");
+ else if (node->kind == ND_NE)
+ println(" setne %%al");
+ else if (node->kind == ND_LT)
+ println(" seta %%al");
+ else
+ println(" setae %%al");
+
+ println(" movzb %%al, %%rax");
+ return;
+ }
+
+ error_tok(node->tok, "invalid expression");
+ }
+ }
+
+ gen_expr(node->rhs);
+ push();
+ gen_expr(node->lhs);
+ pop("%rdi");
+
+ char *ax, *di, *dx;
+
+ if (node->lhs->ty->kind == TY_LONG || node->lhs->ty->base) {
+ ax = "%rax";
+ di = "%rdi";
+ dx = "%rdx";
+ } else {
+ ax = "%eax";
+ di = "%edi";
+ dx = "%edx";
+ }
+
+ switch (node->kind) {
+ case ND_ADD:
+ println(" add %s, %s", di, ax);
+ return;
+ case ND_SUB:
+ println(" sub %s, %s", di, ax);
+ return;
+ case ND_MUL:
+ println(" imul %s, %s", di, ax);
+ return;
+ case ND_DIV:
+ case ND_MOD:
+ if (node->ty->is_unsigned) {
+ println(" mov $0, %s", dx);
+ println(" div %s", di);
+ } else {
+ if (node->lhs->ty->size == 8)
+ println(" cqo");
+ else
+ println(" cdq");
+ println(" idiv %s", di);
+ }
+
+ if (node->kind == ND_MOD)
+ println(" mov %%rdx, %%rax");
+ return;
+ case ND_BITAND:
+ println(" and %s, %s", di, ax);
+ return;
+ case ND_BITOR:
+ println(" or %s, %s", di, ax);
+ return;
+ case ND_BITXOR:
+ println(" xor %s, %s", di, ax);
+ return;
+ case ND_EQ:
+ case ND_NE:
+ case ND_LT:
+ case ND_LE:
+ println(" cmp %s, %s", di, ax);
+
+ if (node->kind == ND_EQ) {
+ println(" sete %%al");
+ } else if (node->kind == ND_NE) {
+ println(" setne %%al");
+ } else if (node->kind == ND_LT) {
+ if (node->lhs->ty->is_unsigned)
+ println(" setb %%al");
+ else
+ println(" setl %%al");
+ } else if (node->kind == ND_LE) {
+ if (node->lhs->ty->is_unsigned)
+ println(" setbe %%al");
+ else
+ println(" setle %%al");
+ }
+
+ println(" movzb %%al, %%rax");
+ return;
+ case ND_SHL:
+ println(" mov %%rdi, %%rcx");
+ println(" shl %%cl, %s", ax);
+ return;
+ case ND_SHR:
+ println(" mov %%rdi, %%rcx");
+ if (node->lhs->ty->is_unsigned)
+ println(" shr %%cl, %s", ax);
+ else
+ println(" sar %%cl, %s", ax);
+ return;
+ }
+
+ error_tok(node->tok, "invalid expression");
+}
+
+static void gen_stmt(Node *node) {
+ println(" .loc %d %d", node->tok->file->file_no, node->tok->line_no);
+
+ switch (node->kind) {
+ case ND_IF: {
+ int c = count();
+ gen_expr(node->cond);
+ cmp_zero(node->cond->ty);
+ println(" je .L.else.%d", c);
+ gen_stmt(node->then);
+ println(" jmp .L.end.%d", c);
+ println(".L.else.%d:", c);
+ if (node->els)
+ gen_stmt(node->els);
+ println(".L.end.%d:", c);
+ return;
+ }
+ case ND_FOR: {
+ int c = count();
+ if (node->init)
+ gen_stmt(node->init);
+ println(".L.begin.%d:", c);
+ if (node->cond) {
+ gen_expr(node->cond);
+ cmp_zero(node->cond->ty);
+ println(" je %s", node->brk_label);
+ }
+ gen_stmt(node->then);
+ println("%s:", node->cont_label);
+ if (node->inc)
+ gen_expr(node->inc);
+ println(" jmp .L.begin.%d", c);
+ println("%s:", node->brk_label);
+ return;
+ }
+ case ND_DO: {
+ int c = count();
+ println(".L.begin.%d:", c);
+ gen_stmt(node->then);
+ println("%s:", node->cont_label);
+ gen_expr(node->cond);
+ cmp_zero(node->cond->ty);
+ println(" jne .L.begin.%d", c);
+ println("%s:", node->brk_label);
+ return;
+ }
+ case ND_SWITCH:
+ gen_expr(node->cond);
+
+ for (Node *n = node->case_next; n; n = n->case_next) {
+ char *ax = (node->cond->ty->size == 8) ? "%rax" : "%eax";
+ char *di = (node->cond->ty->size == 8) ? "%rdi" : "%edi";
+
+ if (n->begin == n->end) {
+ println(" cmp $%ld, %s", n->begin, ax);
+ println(" je %s", n->label);
+ continue;
+ }
+
+ // [GNU] Case ranges
+ println(" mov %s, %s", ax, di);
+ println(" sub $%ld, %s", n->begin, di);
+ println(" cmp $%ld, %s", n->end - n->begin, di);
+ println(" jbe %s", n->label);
+ }
+
+ if (node->default_case)
+ println(" jmp %s", node->default_case->label);
+
+ println(" jmp %s", node->brk_label);
+ gen_stmt(node->then);
+ println("%s:", node->brk_label);
+ return;
+ case ND_CASE:
+ println("%s:", node->label);
+ gen_stmt(node->lhs);
+ return;
+ case ND_BLOCK:
+ for (Node *n = node->body; n; n = n->next)
+ gen_stmt(n);
+ return;
+ case ND_GOTO:
+ println(" jmp %s", node->unique_label);
+ return;
+ case ND_GOTO_EXPR:
+ gen_expr(node->lhs);
+ println(" jmp *%%rax");
+ return;
+ case ND_LABEL:
+ println("%s:", node->unique_label);
+ gen_stmt(node->lhs);
+ return;
+ case ND_RETURN:
+ if (node->lhs) {
+ gen_expr(node->lhs);
+ Type *ty = node->lhs->ty;
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ if (ty->size <= 16)
+ copy_struct_reg();
+ else
+ copy_struct_mem();
+ break;
+ }
+ }
+
+ println(" jmp .L.return.%s", current_fn->name);
+ return;
+ case ND_EXPR_STMT:
+ gen_expr(node->lhs);
+ return;
+ case ND_ASM:
+ println(" %s", node->asm_str);
+ return;
+ }
+
+ error_tok(node->tok, "invalid statement");
+}
+
+// Assign offsets to local variables.
+static void assign_lvar_offsets(Obj *prog) {
+ for (Obj *fn = prog; fn; fn = fn->next) {
+ if (!fn->is_function)
+ continue;
+
+ // If a function has many parameters, some parameters are
+ // inevitably passed by stack rather than by register.
+ // The first passed-by-stack parameter resides at RBP+16.
+ int top = 16;
+ int bottom = 0;
+
+ int gp = 0, fp = 0;
+
+ // Assign offsets to pass-by-stack parameters.
+ for (Obj *var = fn->params; var; var = var->next) {
+ Type *ty = var->ty;
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ if (ty->size <= 16) {
+ bool fp1 = has_flonum(ty, 0, 8, 0);
+ bool fp2 = has_flonum(ty, 8, 16, 8);
+ if (fp + fp1 + fp2 < FP_MAX && gp + !fp1 + !fp2 < GP_MAX) {
+ fp = fp + fp1 + fp2;
+ gp = gp + !fp1 + !fp2;
+ continue;
+ }
+ }
+ break;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ if (fp++ < FP_MAX)
+ continue;
+ break;
+ case TY_LDOUBLE:
+ break;
+ default:
+ if (gp++ < GP_MAX)
+ continue;
+ }
+
+ top = align_to(top, 8);
+ var->offset = top;
+ top += var->ty->size;
+ }
+
+ // Assign offsets to pass-by-register parameters and local variables.
+ for (Obj *var = fn->locals; var; var = var->next) {
+ if (var->offset)
+ continue;
+
+ // AMD64 System V ABI has a special alignment rule for an array of
+ // length at least 16 bytes. We need to align such array to at least
+ // 16-byte boundaries. See p.14 of
+ // https://github.com/hjl-tools/x86-psABI/wiki/x86-64-psABI-draft.pdf.
+ int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16)
+ ? MAX(16, var->align) : var->align;
+
+ bottom += var->ty->size;
+ bottom = align_to(bottom, align);
+ var->offset = -bottom;
+ }
+
+ fn->stack_size = align_to(bottom, 16);
+ }
+}
+
+static void emit_data(Obj *prog) {
+ for (Obj *var = prog; var; var = var->next) {
+ if (var->is_function || !var->is_definition)
+ continue;
+
+ if (var->is_static)
+ println(" .local %s", var->name);
+ else
+ println(" .globl %s", var->name);
+
+ int align = (var->ty->kind == TY_ARRAY && var->ty->size >= 16)
+ ? MAX(16, var->align) : var->align;
+
+ // Common symbol
+ if (opt_fcommon && var->is_tentative) {
+ println(" .comm %s, %d, %d", var->name, var->ty->size, align);
+ continue;
+ }
+
+ // .data or .tdata
+ if (var->init_data) {
+ if (var->is_tls)
+ println(" .section .tdata,\"awT\",@progbits");
+ else
+ println(" .data");
+
+ println(" .type %s, @object", var->name);
+ println(" .size %s, %d", var->name, var->ty->size);
+ println(" .align %d", align);
+ println("%s:", var->name);
+
+ Relocation *rel = var->rel;
+ int pos = 0;
+ while (pos < var->ty->size) {
+ if (rel && rel->offset == pos) {
+ println(" .quad %s%+ld", *rel->label, rel->addend);
+ rel = rel->next;
+ pos += 8;
+ } else {
+ println(" .byte %d", var->init_data[pos++]);
+ }
+ }
+ continue;
+ }
+
+ // .bss or .tbss
+ if (var->is_tls)
+ println(" .section .tbss,\"awT\",@nobits");
+ else
+ println(" .bss");
+
+ println(" .align %d", align);
+ println("%s:", var->name);
+ println(" .zero %d", var->ty->size);
+ }
+}
+
+static void store_fp(int r, int offset, int sz) {
+ switch (sz) {
+ case 4:
+ println(" movss %%xmm%d, %d(%%rbp)", r, offset);
+ return;
+ case 8:
+ println(" movsd %%xmm%d, %d(%%rbp)", r, offset);
+ return;
+ }
+ unreachable();
+}
+
+static void store_gp(int r, int offset, int sz) {
+ switch (sz) {
+ case 1:
+ println(" mov %s, %d(%%rbp)", argreg8[r], offset);
+ return;
+ case 2:
+ println(" mov %s, %d(%%rbp)", argreg16[r], offset);
+ return;
+ case 4:
+ println(" mov %s, %d(%%rbp)", argreg32[r], offset);
+ return;
+ case 8:
+ println(" mov %s, %d(%%rbp)", argreg64[r], offset);
+ return;
+ default:
+ for (int i = 0; i < sz; i++) {
+ println(" mov %s, %d(%%rbp)", argreg8[r], offset + i);
+ println(" shr $8, %s", argreg64[r]);
+ }
+ return;
+ }
+}
+
+static void emit_text(Obj *prog) {
+ for (Obj *fn = prog; fn; fn = fn->next) {
+ if (!fn->is_function || !fn->is_definition)
+ continue;
+
+ // No code is emitted for "static inline" functions
+ // if no one is referencing them.
+ if (!fn->is_live)
+ continue;
+
+ if (fn->is_static)
+ println(" .local %s", fn->name);
+ else
+ println(" .globl %s", fn->name);
+
+ println(" .text");
+ println(" .type %s, @function", fn->name);
+ println("%s:", fn->name);
+ current_fn = fn;
+
+ // Prologue
+ println(" push %%rbp");
+ println(" mov %%rsp, %%rbp");
+ println(" sub $%d, %%rsp", fn->stack_size);
+ println(" mov %%rsp, %d(%%rbp)", fn->alloca_bottom->offset);
+
+ // Save arg registers if function is variadic
+ if (fn->va_area) {
+ int gp = 0, fp = 0;
+ for (Obj *var = fn->params; var; var = var->next) {
+ if (is_flonum(var->ty))
+ fp++;
+ else
+ gp++;
+ }
+
+ int off = fn->va_area->offset;
+
+ // va_elem
+ println(" movl $%d, %d(%%rbp)", gp * 8, off); // gp_offset
+ println(" movl $%d, %d(%%rbp)", fp * 8 + 48, off + 4); // fp_offset
+ println(" movq %%rbp, %d(%%rbp)", off + 8); // overflow_arg_area
+ println(" addq $16, %d(%%rbp)", off + 8);
+ println(" movq %%rbp, %d(%%rbp)", off + 16); // reg_save_area
+ println(" addq $%d, %d(%%rbp)", off + 24, off + 16);
+
+ // __reg_save_area__
+ println(" movq %%rdi, %d(%%rbp)", off + 24);
+ println(" movq %%rsi, %d(%%rbp)", off + 32);
+ println(" movq %%rdx, %d(%%rbp)", off + 40);
+ println(" movq %%rcx, %d(%%rbp)", off + 48);
+ println(" movq %%r8, %d(%%rbp)", off + 56);
+ println(" movq %%r9, %d(%%rbp)", off + 64);
+ println(" movsd %%xmm0, %d(%%rbp)", off + 72);
+ println(" movsd %%xmm1, %d(%%rbp)", off + 80);
+ println(" movsd %%xmm2, %d(%%rbp)", off + 88);
+ println(" movsd %%xmm3, %d(%%rbp)", off + 96);
+ println(" movsd %%xmm4, %d(%%rbp)", off + 104);
+ println(" movsd %%xmm5, %d(%%rbp)", off + 112);
+ println(" movsd %%xmm6, %d(%%rbp)", off + 120);
+ println(" movsd %%xmm7, %d(%%rbp)", off + 128);
+ }
+
+ // Save passed-by-register arguments to the stack
+ int gp = 0, fp = 0;
+ for (Obj *var = fn->params; var; var = var->next) {
+ if (var->offset > 0)
+ continue;
+
+ Type *ty = var->ty;
+
+ switch (ty->kind) {
+ case TY_STRUCT:
+ case TY_UNION:
+ assert(ty->size <= 16);
+ if (has_flonum(ty, 0, 8, 0))
+ store_fp(fp++, var->offset, MIN(8, ty->size));
+ else
+ store_gp(gp++, var->offset, MIN(8, ty->size));
+
+ if (ty->size > 8) {
+ if (has_flonum(ty, 8, 16, 0))
+ store_fp(fp++, var->offset + 8, ty->size - 8);
+ else
+ store_gp(gp++, var->offset + 8, ty->size - 8);
+ }
+ break;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ store_fp(fp++, var->offset, ty->size);
+ break;
+ default:
+ store_gp(gp++, var->offset, ty->size);
+ }
+ }
+
+ // Emit code
+ gen_stmt(fn->body);
+ assert(depth == 0);
+
+ // [https://www.sigbus.info/n1570#5.1.2.2.3p1] The C spec defines
+ // a special rule for the main function. Reaching the end of the
+ // main function is equivalent to returning 0, even though the
+ // behavior is undefined for the other functions.
+ if (strcmp(fn->name, "main") == 0)
+ println(" mov $0, %%rax");
+
+ // Epilogue
+ println(".L.return.%s:", fn->name);
+ println(" mov %%rbp, %%rsp");
+ println(" pop %%rbp");
+ println(" ret");
+ }
+}
+
+void codegen(Obj *prog, FILE *out) {
+ output_file = out;
+
+ File **files = get_input_files();
+ for (int i = 0; files[i]; i++)
+ println(" .file %d \"%s\"", files[i]->file_no, files[i]->name);
+
+ assign_lvar_offsets(prog);
+ emit_data(prog);
+ emit_text(prog);
+}
diff --git a/src/3p/chibicc/hashmap.c b/src/3p/chibicc/hashmap.c
new file mode 100644
index 0000000..46539d9
--- /dev/null
+++ b/src/3p/chibicc/hashmap.c
@@ -0,0 +1,165 @@
+// This is an implementation of the open-addressing hash table.
+
+#include "chibicc.h"
+
+// Initial hash bucket size
+#define INIT_SIZE 16
+
+// Rehash if the usage exceeds 70%.
+#define HIGH_WATERMARK 70
+
+// We'll keep the usage below 50% after rehashing.
+#define LOW_WATERMARK 50
+
+// Represents a deleted hash entry
+#define TOMBSTONE ((void *)-1)
+
+static uint64_t fnv_hash(char *s, int len) {
+ uint64_t hash = 0xcbf29ce484222325;
+ for (int i = 0; i < len; i++) {
+ hash *= 0x100000001b3;
+ hash ^= (unsigned char)s[i];
+ }
+ return hash;
+}
+
+// Make room for new entires in a given hashmap by removing
+// tombstones and possibly extending the bucket size.
+static void rehash(HashMap *map) {
+ // Compute the size of the new hashmap.
+ int nkeys = 0;
+ for (int i = 0; i < map->capacity; i++)
+ if (map->buckets[i].key && map->buckets[i].key != TOMBSTONE)
+ nkeys++;
+
+ int cap = map->capacity;
+ while ((nkeys * 100) / cap >= LOW_WATERMARK)
+ cap = cap * 2;
+ assert(cap > 0);
+
+ // Create a new hashmap and copy all key-values.
+ HashMap map2 = {0};
+ map2.buckets = calloc(cap, sizeof(HashEntry));
+ map2.capacity = cap;
+
+ for (int i = 0; i < map->capacity; i++) {
+ HashEntry *ent = &map->buckets[i];
+ if (ent->key && ent->key != TOMBSTONE)
+ hashmap_put2(&map2, ent->key, ent->keylen, ent->val);
+ }
+
+ assert(map2.used == nkeys);
+ *map = map2;
+}
+
+static bool match(HashEntry *ent, char *key, int keylen) {
+ return ent->key && ent->key != TOMBSTONE &&
+ ent->keylen == keylen && memcmp(ent->key, key, keylen) == 0;
+}
+
+static HashEntry *get_entry(HashMap *map, char *key, int keylen) {
+ if (!map->buckets)
+ return NULL;
+
+ uint64_t hash = fnv_hash(key, keylen);
+
+ for (int i = 0; i < map->capacity; i++) {
+ HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
+ if (match(ent, key, keylen))
+ return ent;
+ if (ent->key == NULL)
+ return NULL;
+ }
+ unreachable();
+}
+
+static HashEntry *get_or_insert_entry(HashMap *map, char *key, int keylen) {
+ if (!map->buckets) {
+ map->buckets = calloc(INIT_SIZE, sizeof(HashEntry));
+ map->capacity = INIT_SIZE;
+ } else if ((map->used * 100) / map->capacity >= HIGH_WATERMARK) {
+ rehash(map);
+ }
+
+ uint64_t hash = fnv_hash(key, keylen);
+
+ for (int i = 0; i < map->capacity; i++) {
+ HashEntry *ent = &map->buckets[(hash + i) % map->capacity];
+
+ if (match(ent, key, keylen))
+ return ent;
+
+ if (ent->key == TOMBSTONE) {
+ ent->key = key;
+ ent->keylen = keylen;
+ return ent;
+ }
+
+ if (ent->key == NULL) {
+ ent->key = key;
+ ent->keylen = keylen;
+ map->used++;
+ return ent;
+ }
+ }
+ unreachable();
+}
+
+void *hashmap_get(HashMap *map, char *key) {
+ return hashmap_get2(map, key, strlen(key));
+}
+
+void *hashmap_get2(HashMap *map, char *key, int keylen) {
+ HashEntry *ent = get_entry(map, key, keylen);
+ return ent ? ent->val : NULL;
+}
+
+void hashmap_put(HashMap *map, char *key, void *val) {
+ hashmap_put2(map, key, strlen(key), val);
+}
+
+void hashmap_put2(HashMap *map, char *key, int keylen, void *val) {
+ HashEntry *ent = get_or_insert_entry(map, key, keylen);
+ ent->val = val;
+}
+
+void hashmap_delete(HashMap *map, char *key) {
+ hashmap_delete2(map, key, strlen(key));
+}
+
+void hashmap_delete2(HashMap *map, char *key, int keylen) {
+ HashEntry *ent = get_entry(map, key, keylen);
+ if (ent)
+ ent->key = TOMBSTONE;
+}
+
+void hashmap_test(void) {
+ HashMap *map = calloc(1, sizeof(HashMap));
+
+ for (int i = 0; i < 5000; i++)
+ hashmap_put(map, format("key %d", i), (void *)(size_t)i);
+ for (int i = 1000; i < 2000; i++)
+ hashmap_delete(map, format("key %d", i));
+ for (int i = 1500; i < 1600; i++)
+ hashmap_put(map, format("key %d", i), (void *)(size_t)i);
+ for (int i = 6000; i < 7000; i++)
+ hashmap_put(map, format("key %d", i), (void *)(size_t)i);
+
+ for (int i = 0; i < 1000; i++)
+ assert((size_t)hashmap_get(map, format("key %d", i)) == i);
+ for (int i = 1000; i < 1500; i++)
+ assert(hashmap_get(map, "no such key") == NULL);
+ for (int i = 1500; i < 1600; i++)
+ assert((size_t)hashmap_get(map, format("key %d", i)) == i);
+ for (int i = 1600; i < 2000; i++)
+ assert(hashmap_get(map, "no such key") == NULL);
+ for (int i = 2000; i < 5000; i++)
+ assert((size_t)hashmap_get(map, format("key %d", i)) == i);
+ for (int i = 5000; i < 6000; i++)
+ assert(hashmap_get(map, "no such key") == NULL);
+ for (int i = 6000; i < 7000; i++)
+ hashmap_put(map, format("key %d", i), (void *)(size_t)i);
+
+ assert(hashmap_get(map, "no such key") == NULL);
+ printf("OK\n");
+}
diff --git a/src/3p/chibicc/main.c b/src/3p/chibicc/main.c
new file mode 100644
index 0000000..ffaabf4
--- /dev/null
+++ b/src/3p/chibicc/main.c
@@ -0,0 +1,791 @@
+#include "chibicc.h"
+
+typedef enum {
+ FILE_NONE, FILE_C, FILE_ASM, FILE_OBJ, FILE_AR, FILE_DSO,
+} FileType;
+
+StringArray include_paths;
+bool opt_fcommon = true;
+bool opt_fpic;
+
+static FileType opt_x;
+static StringArray opt_include;
+static bool opt_E;
+static bool opt_M;
+static bool opt_MD;
+static bool opt_MMD;
+static bool opt_MP;
+static bool opt_S;
+static bool opt_c;
+static bool opt_cc1;
+static bool opt_hash_hash_hash;
+static bool opt_static;
+static bool opt_shared;
+static char *opt_MF;
+static char *opt_MT;
+static char *opt_o;
+
+static StringArray ld_extra_args;
+static StringArray std_include_paths;
+
+char *base_file;
+static char *output_file;
+
+static StringArray input_paths;
+static StringArray tmpfiles;
+
+static void usage(int status) {
+ fprintf(stderr, "chibicc [ -o <path> ] <file>\n");
+ exit(status);
+}
+
+static bool take_arg(char *arg) {
+ char *x[] = {
+ "-o", "-I", "-idirafter", "-include", "-x", "-MF", "-MT", "-Xlinker",
+ };
+
+ for (int i = 0; i < sizeof(x) / sizeof(*x); i++)
+ if (!strcmp(arg, x[i]))
+ return true;
+ return false;
+}
+
+static void add_default_include_paths(char *argv0) {
+ // We expect that chibicc-specific include files are installed
+ // to ./include relative to argv[0].
+ strarray_push(&include_paths, format("%s/include", dirname(strdup(argv0))));
+
+ // Add standard include paths.
+ strarray_push(&include_paths, "/usr/local/include");
+ strarray_push(&include_paths, "/usr/include/x86_64-linux-gnu");
+ strarray_push(&include_paths, "/usr/include");
+
+ // Keep a copy of the standard include paths for -MMD option.
+ for (int i = 0; i < include_paths.len; i++)
+ strarray_push(&std_include_paths, include_paths.data[i]);
+}
+
+static void define(char *str) {
+ char *eq = strchr(str, '=');
+ if (eq)
+ define_macro(strndup(str, eq - str), eq + 1);
+ else
+ define_macro(str, "1");
+}
+
+static FileType parse_opt_x(char *s) {
+ if (!strcmp(s, "c"))
+ return FILE_C;
+ if (!strcmp(s, "assembler"))
+ return FILE_ASM;
+ if (!strcmp(s, "none"))
+ return FILE_NONE;
+ error("<command line>: unknown argument for -x: %s", s);
+}
+
+static char *quote_makefile(char *s) {
+ char *buf = calloc(1, strlen(s) * 2 + 1);
+
+ for (int i = 0, j = 0; s[i]; i++) {
+ switch (s[i]) {
+ case '$':
+ buf[j++] = '$';
+ buf[j++] = '$';
+ break;
+ case '#':
+ buf[j++] = '\\';
+ buf[j++] = '#';
+ break;
+ case ' ':
+ case '\t':
+ for (int k = i - 1; k >= 0 && s[k] == '\\'; k--)
+ buf[j++] = '\\';
+ buf[j++] = '\\';
+ buf[j++] = s[i];
+ break;
+ default:
+ buf[j++] = s[i];
+ break;
+ }
+ }
+ return buf;
+}
+
+static void parse_args(int argc, char **argv) {
+ // Make sure that all command line options that take an argument
+ // have an argument.
+ for (int i = 1; i < argc; i++)
+ if (take_arg(argv[i]))
+ if (!argv[++i])
+ usage(1);
+
+ StringArray idirafter = {};
+
+ for (int i = 1; i < argc; i++) {
+ if (!strcmp(argv[i], "-###")) {
+ opt_hash_hash_hash = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-cc1")) {
+ opt_cc1 = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "--help"))
+ usage(0);
+
+ if (!strcmp(argv[i], "-o")) {
+ opt_o = argv[++i];
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-o", 2)) {
+ opt_o = argv[i] + 2;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-S")) {
+ opt_S = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-fcommon")) {
+ opt_fcommon = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-fno-common")) {
+ opt_fcommon = false;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-c")) {
+ opt_c = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-E")) {
+ opt_E = true;
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-I", 2)) {
+ strarray_push(&include_paths, argv[i] + 2);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-D")) {
+ define(argv[++i]);
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-D", 2)) {
+ define(argv[i] + 2);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-U")) {
+ undef_macro(argv[++i]);
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-U", 2)) {
+ undef_macro(argv[i] + 2);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-include")) {
+ strarray_push(&opt_include, argv[++i]);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-x")) {
+ opt_x = parse_opt_x(argv[++i]);
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-x", 2)) {
+ opt_x = parse_opt_x(argv[i] + 2);
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-l", 2) || !strncmp(argv[i], "-Wl,", 4)) {
+ strarray_push(&input_paths, argv[i]);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-Xlinker")) {
+ strarray_push(&ld_extra_args, argv[++i]);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-s")) {
+ strarray_push(&ld_extra_args, "-s");
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-M")) {
+ opt_M = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MF")) {
+ opt_MF = argv[++i];
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MP")) {
+ opt_MP = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MT")) {
+ if (opt_MT == NULL)
+ opt_MT = argv[++i];
+ else
+ opt_MT = format("%s %s", opt_MT, argv[++i]);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MD")) {
+ opt_MD = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MQ")) {
+ if (opt_MT == NULL)
+ opt_MT = quote_makefile(argv[++i]);
+ else
+ opt_MT = format("%s %s", opt_MT, quote_makefile(argv[++i]));
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-MMD")) {
+ opt_MD = opt_MMD = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-fpic") || !strcmp(argv[i], "-fPIC")) {
+ opt_fpic = true;
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-cc1-input")) {
+ base_file = argv[++i];
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-cc1-output")) {
+ output_file = argv[++i];
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-idirafter")) {
+ strarray_push(&idirafter, argv[i++]);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-static")) {
+ opt_static = true;
+ strarray_push(&ld_extra_args, "-static");
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-shared")) {
+ opt_shared = true;
+ strarray_push(&ld_extra_args, "-shared");
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-L")) {
+ strarray_push(&ld_extra_args, "-L");
+ strarray_push(&ld_extra_args, argv[++i]);
+ continue;
+ }
+
+ if (!strncmp(argv[i], "-L", 2)) {
+ strarray_push(&ld_extra_args, "-L");
+ strarray_push(&ld_extra_args, argv[i] + 2);
+ continue;
+ }
+
+ if (!strcmp(argv[i], "-hashmap-test")) {
+ hashmap_test();
+ exit(0);
+ }
+
+ // These options are ignored for now.
+ if (!strncmp(argv[i], "-O", 2) ||
+ !strncmp(argv[i], "-W", 2) ||
+ !strncmp(argv[i], "-g", 2) ||
+ !strncmp(argv[i], "-std=", 5) ||
+ !strcmp(argv[i], "-ffreestanding") ||
+ !strcmp(argv[i], "-fno-builtin") ||
+ !strcmp(argv[i], "-fno-omit-frame-pointer") ||
+ !strcmp(argv[i], "-fno-stack-protector") ||
+ !strcmp(argv[i], "-fno-strict-aliasing") ||
+ !strcmp(argv[i], "-m64") ||
+ !strcmp(argv[i], "-mno-red-zone") ||
+ !strcmp(argv[i], "-w"))
+ continue;
+
+ if (argv[i][0] == '-' && argv[i][1] != '\0')
+ error("unknown argument: %s", argv[i]);
+
+ strarray_push(&input_paths, argv[i]);
+ }
+
+ for (int i = 0; i < idirafter.len; i++)
+ strarray_push(&include_paths, idirafter.data[i]);
+
+ if (input_paths.len == 0)
+ error("no input files");
+
+ // -E implies that the input is the C macro language.
+ if (opt_E)
+ opt_x = FILE_C;
+}
+
+static FILE *open_file(char *path) {
+ if (!path || strcmp(path, "-") == 0)
+ return stdout;
+
+ FILE *out = fopen(path, "w");
+ if (!out)
+ error("cannot open output file: %s: %s", path, strerror(errno));
+ return out;
+}
+
+static bool endswith(char *p, char *q) {
+ int len1 = strlen(p);
+ int len2 = strlen(q);
+ return (len1 >= len2) && !strcmp(p + len1 - len2, q);
+}
+
+// Replace file extension
+static char *replace_extn(char *tmpl, char *extn) {
+ char *filename = basename(strdup(tmpl));
+ char *dot = strrchr(filename, '.');
+ if (dot)
+ *dot = '\0';
+ return format("%s%s", filename, extn);
+}
+
+static void cleanup(void) {
+ for (int i = 0; i < tmpfiles.len; i++)
+ unlink(tmpfiles.data[i]);
+}
+
+static char *create_tmpfile(void) {
+ char *path = strdup("/tmp/chibicc-XXXXXX");
+ int fd = mkstemp(path);
+ if (fd == -1)
+ error("mkstemp failed: %s", strerror(errno));
+ close(fd);
+
+ strarray_push(&tmpfiles, path);
+ return path;
+}
+
+static void run_subprocess(char **argv) {
+ // If -### is given, dump the subprocess's command line.
+ if (opt_hash_hash_hash) {
+ fprintf(stderr, "%s", argv[0]);
+ for (int i = 1; argv[i]; i++)
+ fprintf(stderr, " %s", argv[i]);
+ fprintf(stderr, "\n");
+ }
+
+ if (fork() == 0) {
+ // Child process. Run a new command.
+ execvp(argv[0], argv);
+ fprintf(stderr, "exec failed: %s: %s\n", argv[0], strerror(errno));
+ _exit(1);
+ }
+
+ // Wait for the child process to finish.
+ int status;
+ while (wait(&status) > 0);
+ if (status != 0)
+ exit(1);
+}
+
+static void run_cc1(int argc, char **argv, char *input, char *output) {
+ char **args = calloc(argc + 10, sizeof(char *));
+ memcpy(args, argv, argc * sizeof(char *));
+ args[argc++] = "-cc1";
+
+ if (input) {
+ args[argc++] = "-cc1-input";
+ args[argc++] = input;
+ }
+
+ if (output) {
+ args[argc++] = "-cc1-output";
+ args[argc++] = output;
+ }
+
+ run_subprocess(args);
+}
+
+// Print tokens to stdout. Used for -E.
+static void print_tokens(Token *tok) {
+ FILE *out = open_file(opt_o ? opt_o : "-");
+
+ int line = 1;
+ for (; tok->kind != TK_EOF; tok = tok->next) {
+ if (line > 1 && tok->at_bol)
+ fprintf(out, "\n");
+ if (tok->has_space && !tok->at_bol)
+ fprintf(out, " ");
+ fprintf(out, "%.*s", tok->len, tok->loc);
+ line++;
+ }
+ fprintf(out, "\n");
+}
+
+static bool in_std_include_path(char *path) {
+ for (int i = 0; i < std_include_paths.len; i++) {
+ char *dir = std_include_paths.data[i];
+ int len = strlen(dir);
+ if (strncmp(dir, path, len) == 0 && path[len] == '/')
+ return true;
+ }
+ return false;
+}
+
+// If -M options is given, the compiler write a list of input files to
+// stdout in a format that "make" command can read. This feature is
+// used to automate file dependency management.
+static void print_dependencies(void) {
+ char *path;
+ if (opt_MF)
+ path = opt_MF;
+ else if (opt_MD)
+ path = replace_extn(opt_o ? opt_o : base_file, ".d");
+ else if (opt_o)
+ path = opt_o;
+ else
+ path = "-";
+
+ FILE *out = open_file(path);
+ if (opt_MT)
+ fprintf(out, "%s:", opt_MT);
+ else
+ fprintf(out, "%s:", quote_makefile(replace_extn(base_file, ".o")));
+
+ File **files = get_input_files();
+
+ for (int i = 0; files[i]; i++) {
+ if (opt_MMD && in_std_include_path(files[i]->name))
+ continue;
+ fprintf(out, " \\\n %s", files[i]->name);
+ }
+
+ fprintf(out, "\n\n");
+
+ if (opt_MP) {
+ for (int i = 1; files[i]; i++) {
+ if (opt_MMD && in_std_include_path(files[i]->name))
+ continue;
+ fprintf(out, "%s:\n\n", quote_makefile(files[i]->name));
+ }
+ }
+}
+
+static Token *must_tokenize_file(char *path) {
+ Token *tok = tokenize_file(path);
+ if (!tok)
+ error("%s: %s", path, strerror(errno));
+ return tok;
+}
+
+static Token *append_tokens(Token *tok1, Token *tok2) {
+ if (!tok1 || tok1->kind == TK_EOF)
+ return tok2;
+
+ Token *t = tok1;
+ while (t->next->kind != TK_EOF)
+ t = t->next;
+ t->next = tok2;
+ return tok1;
+}
+
+static void cc1(void) {
+ Token *tok = NULL;
+
+ // Process -include option
+ for (int i = 0; i < opt_include.len; i++) {
+ char *incl = opt_include.data[i];
+
+ char *path;
+ if (file_exists(incl)) {
+ path = incl;
+ } else {
+ path = search_include_paths(incl);
+ if (!path)
+ error("-include: %s: %s", incl, strerror(errno));
+ }
+
+ Token *tok2 = must_tokenize_file(path);
+ tok = append_tokens(tok, tok2);
+ }
+
+ // Tokenize and parse.
+ Token *tok2 = must_tokenize_file(base_file);
+ tok = append_tokens(tok, tok2);
+ tok = preprocess(tok);
+
+ // If -M or -MD are given, print file dependencies.
+ if (opt_M || opt_MD) {
+ print_dependencies();
+ if (opt_M)
+ return;
+ }
+
+ // If -E is given, print out preprocessed C code as a result.
+ if (opt_E) {
+ print_tokens(tok);
+ return;
+ }
+
+ Obj *prog = parse(tok);
+
+ // Open a temporary output buffer.
+ char *buf;
+ size_t buflen;
+ FILE *output_buf = open_memstream(&buf, &buflen);
+
+ // Traverse the AST to emit assembly.
+ codegen(prog, output_buf);
+ fclose(output_buf);
+
+ // Write the asembly text to a file.
+ FILE *out = open_file(output_file);
+ fwrite(buf, buflen, 1, out);
+ fclose(out);
+}
+
+static void assemble(char *input, char *output) {
+ char *cmd[] = {"as", "-c", input, "-o", output, NULL};
+ run_subprocess(cmd);
+}
+
+static char *find_file(char *pattern) {
+ char *path = NULL;
+ glob_t buf = {};
+ glob(pattern, 0, NULL, &buf);
+ if (buf.gl_pathc > 0)
+ path = strdup(buf.gl_pathv[buf.gl_pathc - 1]);
+ globfree(&buf);
+ return path;
+}
+
+// Returns true if a given file exists.
+bool file_exists(char *path) {
+ struct stat st;
+ return !stat(path, &st);
+}
+
+static char *find_libpath(void) {
+ if (file_exists("/usr/lib/x86_64-linux-gnu/crti.o"))
+ return "/usr/lib/x86_64-linux-gnu";
+ if (file_exists("/usr/lib64/crti.o"))
+ return "/usr/lib64";
+ error("library path is not found");
+}
+
+static char *find_gcc_libpath(void) {
+ char *paths[] = {
+ "/usr/lib/gcc/x86_64-linux-gnu/*/crtbegin.o",
+ "/usr/lib/gcc/x86_64-pc-linux-gnu/*/crtbegin.o", // For Gentoo
+ "/usr/lib/gcc/x86_64-redhat-linux/*/crtbegin.o", // For Fedora
+ };
+
+ for (int i = 0; i < sizeof(paths) / sizeof(*paths); i++) {
+ char *path = find_file(paths[i]);
+ if (path)
+ return dirname(path);
+ }
+
+ error("gcc library path is not found");
+}
+
+static void run_linker(StringArray *inputs, char *output) {
+ StringArray arr = {};
+
+ strarray_push(&arr, "ld");
+ strarray_push(&arr, "-o");
+ strarray_push(&arr, output);
+ strarray_push(&arr, "-m");
+ strarray_push(&arr, "elf_x86_64");
+
+ char *libpath = find_libpath();
+ char *gcc_libpath = find_gcc_libpath();
+
+ if (opt_shared) {
+ strarray_push(&arr, format("%s/crti.o", libpath));
+ strarray_push(&arr, format("%s/crtbeginS.o", gcc_libpath));
+ } else {
+ strarray_push(&arr, format("%s/crt1.o", libpath));
+ strarray_push(&arr, format("%s/crti.o", libpath));
+ strarray_push(&arr, format("%s/crtbegin.o", gcc_libpath));
+ }
+
+ strarray_push(&arr, format("-L%s", gcc_libpath));
+ strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
+ strarray_push(&arr, "-L/usr/lib64");
+ strarray_push(&arr, "-L/lib64");
+ strarray_push(&arr, "-L/usr/lib/x86_64-linux-gnu");
+ strarray_push(&arr, "-L/usr/lib/x86_64-pc-linux-gnu");
+ strarray_push(&arr, "-L/usr/lib/x86_64-redhat-linux");
+ strarray_push(&arr, "-L/usr/lib");
+ strarray_push(&arr, "-L/lib");
+
+ if (!opt_static) {
+ strarray_push(&arr, "-dynamic-linker");
+ strarray_push(&arr, "/lib64/ld-linux-x86-64.so.2");
+ }
+
+ for (int i = 0; i < ld_extra_args.len; i++)
+ strarray_push(&arr, ld_extra_args.data[i]);
+
+ for (int i = 0; i < inputs->len; i++)
+ strarray_push(&arr, inputs->data[i]);
+
+ if (opt_static) {
+ strarray_push(&arr, "--start-group");
+ strarray_push(&arr, "-lgcc");
+ strarray_push(&arr, "-lgcc_eh");
+ strarray_push(&arr, "-lc");
+ strarray_push(&arr, "--end-group");
+ } else {
+ strarray_push(&arr, "-lc");
+ strarray_push(&arr, "-lgcc");
+ strarray_push(&arr, "--as-needed");
+ strarray_push(&arr, "-lgcc_s");
+ strarray_push(&arr, "--no-as-needed");
+ }
+
+ if (opt_shared)
+ strarray_push(&arr, format("%s/crtendS.o", gcc_libpath));
+ else
+ strarray_push(&arr, format("%s/crtend.o", gcc_libpath));
+
+ strarray_push(&arr, format("%s/crtn.o", libpath));
+ strarray_push(&arr, NULL);
+
+ run_subprocess(arr.data);
+}
+
+static FileType get_file_type(char *filename) {
+ if (opt_x != FILE_NONE)
+ return opt_x;
+
+ if (endswith(filename, ".a"))
+ return FILE_AR;
+ if (endswith(filename, ".so"))
+ return FILE_DSO;
+ if (endswith(filename, ".o"))
+ return FILE_OBJ;
+ if (endswith(filename, ".c"))
+ return FILE_C;
+ if (endswith(filename, ".s"))
+ return FILE_ASM;
+
+ error("<command line>: unknown file extension: %s", filename);
+}
+
+int main(int argc, char **argv) {
+ atexit(cleanup);
+ init_macros();
+ parse_args(argc, argv);
+
+ if (opt_cc1) {
+ add_default_include_paths(argv[0]);
+ cc1();
+ return 0;
+ }
+
+ if (input_paths.len > 1 && opt_o && (opt_c || opt_S | opt_E))
+ error("cannot specify '-o' with '-c,' '-S' or '-E' with multiple files");
+
+ StringArray ld_args = {};
+
+ for (int i = 0; i < input_paths.len; i++) {
+ char *input = input_paths.data[i];
+
+ if (!strncmp(input, "-l", 2)) {
+ strarray_push(&ld_args, input);
+ continue;
+ }
+
+ if (!strncmp(input, "-Wl,", 4)) {
+ char *s = strdup(input + 4);
+ char *arg = strtok(s, ",");
+ while (arg) {
+ strarray_push(&ld_args, arg);
+ arg = strtok(NULL, ",");
+ }
+ continue;
+ }
+
+ char *output;
+ if (opt_o)
+ output = opt_o;
+ else if (opt_S)
+ output = replace_extn(input, ".s");
+ else
+ output = replace_extn(input, ".o");
+
+ FileType type = get_file_type(input);
+
+ // Handle .o or .a
+ if (type == FILE_OBJ || type == FILE_AR || type == FILE_DSO) {
+ strarray_push(&ld_args, input);
+ continue;
+ }
+
+ // Handle .s
+ if (type == FILE_ASM) {
+ if (!opt_S)
+ assemble(input, output);
+ continue;
+ }
+
+ assert(type == FILE_C);
+
+ // Just preprocess
+ if (opt_E || opt_M) {
+ run_cc1(argc, argv, input, NULL);
+ continue;
+ }
+
+ // Compile
+ if (opt_S) {
+ run_cc1(argc, argv, input, output);
+ continue;
+ }
+
+ // Compile and assemble
+ if (opt_c) {
+ char *tmp = create_tmpfile();
+ run_cc1(argc, argv, input, tmp);
+ assemble(tmp, output);
+ continue;
+ }
+
+ // Compile, assemble and link
+ char *tmp1 = create_tmpfile();
+ char *tmp2 = create_tmpfile();
+ run_cc1(argc, argv, input, tmp1);
+ assemble(tmp1, tmp2);
+ strarray_push(&ld_args, tmp2);
+ continue;
+ }
+
+ if (ld_args.len > 0)
+ run_linker(&ld_args, opt_o ? opt_o : "a.out");
+ return 0;
+}
diff --git a/src/3p/chibicc/parse.c b/src/3p/chibicc/parse.c
new file mode 100644
index 0000000..6acaeb8
--- /dev/null
+++ b/src/3p/chibicc/parse.c
@@ -0,0 +1,3368 @@
+// This file contains a recursive descent parser for C.
+//
+// Most functions in this file are named after the symbols they are
+// supposed to read from an input token list. For example, stmt() is
+// responsible for reading a statement from a token list. The function
+// then construct an AST node representing a statement.
+//
+// Each function conceptually returns two values, an AST node and
+// remaining part of the input tokens. Since C doesn't support
+// multiple return values, the remaining tokens are returned to the
+// caller via a pointer argument.
+//
+// Input tokens are represented by a linked list. Unlike many recursive
+// descent parsers, we don't have the notion of the "input token stream".
+// Most parsing functions don't change the global state of the parser.
+// So it is very easy to lookahead arbitrary number of tokens in this
+// parser.
+
+#include "chibicc.h"
+
+// Scope for local variables, global variables, typedefs
+// or enum constants
+typedef struct {
+ Obj *var;
+ Type *type_def;
+ Type *enum_ty;
+ int enum_val;
+} VarScope;
+
+// Represents a block scope.
+typedef struct Scope Scope;
+struct Scope {
+ Scope *next;
+
+ // C has two block scopes; one is for variables/typedefs and
+ // the other is for struct/union/enum tags.
+ HashMap vars;
+ HashMap tags;
+};
+
+// Variable attributes such as typedef or extern.
+typedef struct {
+ bool is_typedef;
+ bool is_static;
+ bool is_extern;
+ bool is_inline;
+ bool is_tls;
+ int align;
+} VarAttr;
+
+// This struct represents a variable initializer. Since initializers
+// can be nested (e.g. `int x[2][2] = {{1, 2}, {3, 4}}`), this struct
+// is a tree data structure.
+typedef struct Initializer Initializer;
+struct Initializer {
+ Initializer *next;
+ Type *ty;
+ Token *tok;
+ bool is_flexible;
+
+ // If it's not an aggregate type and has an initializer,
+ // `expr` has an initialization expression.
+ Node *expr;
+
+ // If it's an initializer for an aggregate type (e.g. array or struct),
+ // `children` has initializers for its children.
+ Initializer **children;
+
+ // Only one member can be initialized for a union.
+ // `mem` is used to clarify which member is initialized.
+ Member *mem;
+};
+
+// For local variable initializer.
+typedef struct InitDesg InitDesg;
+struct InitDesg {
+ InitDesg *next;
+ int idx;
+ Member *member;
+ Obj *var;
+};
+
+// All local variable instances created during parsing are
+// accumulated to this list.
+static Obj *locals;
+
+// Likewise, global variables are accumulated to this list.
+static Obj *globals;
+
+static Scope *scope = &(Scope){};
+
+// Points to the function object the parser is currently parsing.
+static Obj *current_fn;
+
+// Lists of all goto statements and labels in the curent function.
+static Node *gotos;
+static Node *labels;
+
+// Current "goto" and "continue" jump targets.
+static char *brk_label;
+static char *cont_label;
+
+// Points to a node representing a switch if we are parsing
+// a switch statement. Otherwise, NULL.
+static Node *current_switch;
+
+static Obj *builtin_alloca;
+
+static bool is_typename(Token *tok);
+static Type *declspec(Token **rest, Token *tok, VarAttr *attr);
+static Type *typename(Token **rest, Token *tok);
+static Type *enum_specifier(Token **rest, Token *tok);
+static Type *typeof_specifier(Token **rest, Token *tok);
+static Type *type_suffix(Token **rest, Token *tok, Type *ty);
+static Type *declarator(Token **rest, Token *tok, Type *ty);
+static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr);
+static void array_initializer2(Token **rest, Token *tok, Initializer *init, int i);
+static void struct_initializer2(Token **rest, Token *tok, Initializer *init, Member *mem);
+static void initializer2(Token **rest, Token *tok, Initializer *init);
+static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty);
+static Node *lvar_initializer(Token **rest, Token *tok, Obj *var);
+static void gvar_initializer(Token **rest, Token *tok, Obj *var);
+static Node *compound_stmt(Token **rest, Token *tok);
+static Node *stmt(Token **rest, Token *tok);
+static Node *expr_stmt(Token **rest, Token *tok);
+static Node *expr(Token **rest, Token *tok);
+static int64_t eval(Node *node);
+static int64_t eval2(Node *node, char ***label);
+static int64_t eval_rval(Node *node, char ***label);
+static bool is_const_expr(Node *node);
+static Node *assign(Token **rest, Token *tok);
+static Node *logor(Token **rest, Token *tok);
+static double eval_double(Node *node);
+static Node *conditional(Token **rest, Token *tok);
+static Node *logand(Token **rest, Token *tok);
+static Node *bitor(Token **rest, Token *tok);
+static Node *bitxor(Token **rest, Token *tok);
+static Node *bitand(Token **rest, Token *tok);
+static Node *equality(Token **rest, Token *tok);
+static Node *relational(Token **rest, Token *tok);
+static Node *shift(Token **rest, Token *tok);
+static Node *add(Token **rest, Token *tok);
+static Node *new_add(Node *lhs, Node *rhs, Token *tok);
+static Node *new_sub(Node *lhs, Node *rhs, Token *tok);
+static Node *mul(Token **rest, Token *tok);
+static Node *cast(Token **rest, Token *tok);
+static Member *get_struct_member(Type *ty, Token *tok);
+static Type *struct_decl(Token **rest, Token *tok);
+static Type *union_decl(Token **rest, Token *tok);
+static Node *postfix(Token **rest, Token *tok);
+static Node *funcall(Token **rest, Token *tok, Node *node);
+static Node *unary(Token **rest, Token *tok);
+static Node *primary(Token **rest, Token *tok);
+static Token *parse_typedef(Token *tok, Type *basety);
+static bool is_function(Token *tok);
+static Token *function(Token *tok, Type *basety, VarAttr *attr);
+static Token *global_variable(Token *tok, Type *basety, VarAttr *attr);
+
+static int align_down(int n, int align) {
+ return align_to(n - align + 1, align);
+}
+
+static void enter_scope(void) {
+ Scope *sc = calloc(1, sizeof(Scope));
+ sc->next = scope;
+ scope = sc;
+}
+
+static void leave_scope(void) {
+ scope = scope->next;
+}
+
+// Find a variable by name.
+static VarScope *find_var(Token *tok) {
+ for (Scope *sc = scope; sc; sc = sc->next) {
+ VarScope *sc2 = hashmap_get2(&sc->vars, tok->loc, tok->len);
+ if (sc2)
+ return sc2;
+ }
+ return NULL;
+}
+
+static Type *find_tag(Token *tok) {
+ for (Scope *sc = scope; sc; sc = sc->next) {
+ Type *ty = hashmap_get2(&sc->tags, tok->loc, tok->len);
+ if (ty)
+ return ty;
+ }
+ return NULL;
+}
+
+static Node *new_node(NodeKind kind, Token *tok) {
+ Node *node = calloc(1, sizeof(Node));
+ node->kind = kind;
+ node->tok = tok;
+ return node;
+}
+
+static Node *new_binary(NodeKind kind, Node *lhs, Node *rhs, Token *tok) {
+ Node *node = new_node(kind, tok);
+ node->lhs = lhs;
+ node->rhs = rhs;
+ return node;
+}
+
+static Node *new_unary(NodeKind kind, Node *expr, Token *tok) {
+ Node *node = new_node(kind, tok);
+ node->lhs = expr;
+ return node;
+}
+
+static Node *new_num(int64_t val, Token *tok) {
+ Node *node = new_node(ND_NUM, tok);
+ node->val = val;
+ return node;
+}
+
+static Node *new_long(int64_t val, Token *tok) {
+ Node *node = new_node(ND_NUM, tok);
+ node->val = val;
+ node->ty = ty_long;
+ return node;
+}
+
+static Node *new_ulong(long val, Token *tok) {
+ Node *node = new_node(ND_NUM, tok);
+ node->val = val;
+ node->ty = ty_ulong;
+ return node;
+}
+
+static Node *new_var_node(Obj *var, Token *tok) {
+ Node *node = new_node(ND_VAR, tok);
+ node->var = var;
+ return node;
+}
+
+static Node *new_vla_ptr(Obj *var, Token *tok) {
+ Node *node = new_node(ND_VLA_PTR, tok);
+ node->var = var;
+ return node;
+}
+
+Node *new_cast(Node *expr, Type *ty) {
+ add_type(expr);
+
+ Node *node = calloc(1, sizeof(Node));
+ node->kind = ND_CAST;
+ node->tok = expr->tok;
+ node->lhs = expr;
+ node->ty = copy_type(ty);
+ return node;
+}
+
+static VarScope *push_scope(char *name) {
+ VarScope *sc = calloc(1, sizeof(VarScope));
+ hashmap_put(&scope->vars, name, sc);
+ return sc;
+}
+
+static Initializer *new_initializer(Type *ty, bool is_flexible) {
+ Initializer *init = calloc(1, sizeof(Initializer));
+ init->ty = ty;
+
+ if (ty->kind == TY_ARRAY) {
+ if (is_flexible && ty->size < 0) {
+ init->is_flexible = true;
+ return init;
+ }
+
+ init->children = calloc(ty->array_len, sizeof(Initializer *));
+ for (int i = 0; i < ty->array_len; i++)
+ init->children[i] = new_initializer(ty->base, false);
+ return init;
+ }
+
+ if (ty->kind == TY_STRUCT || ty->kind == TY_UNION) {
+ // Count the number of struct members.
+ int len = 0;
+ for (Member *mem = ty->members; mem; mem = mem->next)
+ len++;
+
+ init->children = calloc(len, sizeof(Initializer *));
+
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ if (is_flexible && ty->is_flexible && !mem->next) {
+ Initializer *child = calloc(1, sizeof(Initializer));
+ child->ty = mem->ty;
+ child->is_flexible = true;
+ init->children[mem->idx] = child;
+ } else {
+ init->children[mem->idx] = new_initializer(mem->ty, false);
+ }
+ }
+ return init;
+ }
+
+ return init;
+}
+
+static Obj *new_var(char *name, Type *ty) {
+ Obj *var = calloc(1, sizeof(Obj));
+ var->name = name;
+ var->ty = ty;
+ var->align = ty->align;
+ push_scope(name)->var = var;
+ return var;
+}
+
+static Obj *new_lvar(char *name, Type *ty) {
+ Obj *var = new_var(name, ty);
+ var->is_local = true;
+ var->next = locals;
+ locals = var;
+ return var;
+}
+
+static Obj *new_gvar(char *name, Type *ty) {
+ Obj *var = new_var(name, ty);
+ var->next = globals;
+ var->is_static = true;
+ var->is_definition = true;
+ globals = var;
+ return var;
+}
+
+static char *new_unique_name(void) {
+ static int id = 0;
+ return format(".L..%d", id++);
+}
+
+static Obj *new_anon_gvar(Type *ty) {
+ return new_gvar(new_unique_name(), ty);
+}
+
+static Obj *new_string_literal(char *p, Type *ty) {
+ Obj *var = new_anon_gvar(ty);
+ var->init_data = p;
+ return var;
+}
+
+static char *get_ident(Token *tok) {
+ if (tok->kind != TK_IDENT)
+ error_tok(tok, "expected an identifier");
+ return strndup(tok->loc, tok->len);
+}
+
+static Type *find_typedef(Token *tok) {
+ if (tok->kind == TK_IDENT) {
+ VarScope *sc = find_var(tok);
+ if (sc)
+ return sc->type_def;
+ }
+ return NULL;
+}
+
+static void push_tag_scope(Token *tok, Type *ty) {
+ hashmap_put2(&scope->tags, tok->loc, tok->len, ty);
+}
+
+// declspec = ("void" | "_Bool" | "char" | "short" | "int" | "long"
+// | "typedef" | "static" | "extern" | "inline"
+// | "_Thread_local" | "__thread"
+// | "signed" | "unsigned"
+// | struct-decl | union-decl | typedef-name
+// | enum-specifier | typeof-specifier
+// | "const" | "volatile" | "auto" | "register" | "restrict"
+// | "__restrict" | "__restrict__" | "_Noreturn")+
+//
+// The order of typenames in a type-specifier doesn't matter. For
+// example, `int long static` means the same as `static long int`.
+// That can also be written as `static long` because you can omit
+// `int` if `long` or `short` are specified. However, something like
+// `char int` is not a valid type specifier. We have to accept only a
+// limited combinations of the typenames.
+//
+// In this function, we count the number of occurrences of each typename
+// while keeping the "current" type object that the typenames up
+// until that point represent. When we reach a non-typename token,
+// we returns the current type object.
+static Type *declspec(Token **rest, Token *tok, VarAttr *attr) {
+ // We use a single integer as counters for all typenames.
+ // For example, bits 0 and 1 represents how many times we saw the
+ // keyword "void" so far. With this, we can use a switch statement
+ // as you can see below.
+ enum {
+ VOID = 1 << 0,
+ BOOL = 1 << 2,
+ CHAR = 1 << 4,
+ SHORT = 1 << 6,
+ INT = 1 << 8,
+ LONG = 1 << 10,
+ FLOAT = 1 << 12,
+ DOUBLE = 1 << 14,
+ OTHER = 1 << 16,
+ SIGNED = 1 << 17,
+ UNSIGNED = 1 << 18,
+ };
+
+ Type *ty = ty_int;
+ int counter = 0;
+ bool is_atomic = false;
+
+ while (is_typename(tok)) {
+ // Handle storage class specifiers.
+ if (equal(tok, "typedef") || equal(tok, "static") || equal(tok, "extern") ||
+ equal(tok, "inline") || equal(tok, "_Thread_local") || equal(tok, "__thread")) {
+ if (!attr)
+ error_tok(tok, "storage class specifier is not allowed in this context");
+
+ if (equal(tok, "typedef"))
+ attr->is_typedef = true;
+ else if (equal(tok, "static"))
+ attr->is_static = true;
+ else if (equal(tok, "extern"))
+ attr->is_extern = true;
+ else if (equal(tok, "inline"))
+ attr->is_inline = true;
+ else
+ attr->is_tls = true;
+
+ if (attr->is_typedef &&
+ attr->is_static + attr->is_extern + attr->is_inline + attr->is_tls > 1)
+ error_tok(tok, "typedef may not be used together with static,"
+ " extern, inline, __thread or _Thread_local");
+ tok = tok->next;
+ continue;
+ }
+
+ // These keywords are recognized but ignored.
+ if (consume(&tok, tok, "const") || consume(&tok, tok, "volatile") ||
+ consume(&tok, tok, "auto") || consume(&tok, tok, "register") ||
+ consume(&tok, tok, "restrict") || consume(&tok, tok, "__restrict") ||
+ consume(&tok, tok, "__restrict__") || consume(&tok, tok, "_Noreturn"))
+ continue;
+
+ if (equal(tok, "_Atomic")) {
+ tok = tok->next;
+ if (equal(tok , "(")) {
+ ty = typename(&tok, tok->next);
+ tok = skip(tok, ")");
+ }
+ is_atomic = true;
+ continue;
+ }
+
+ if (equal(tok, "_Alignas")) {
+ if (!attr)
+ error_tok(tok, "_Alignas is not allowed in this context");
+ tok = skip(tok->next, "(");
+
+ if (is_typename(tok))
+ attr->align = typename(&tok, tok)->align;
+ else
+ attr->align = const_expr(&tok, tok);
+ tok = skip(tok, ")");
+ continue;
+ }
+
+ // Handle user-defined types.
+ Type *ty2 = find_typedef(tok);
+ if (equal(tok, "struct") || equal(tok, "union") || equal(tok, "enum") ||
+ equal(tok, "typeof") || ty2) {
+ if (counter)
+ break;
+
+ if (equal(tok, "struct")) {
+ ty = struct_decl(&tok, tok->next);
+ } else if (equal(tok, "union")) {
+ ty = union_decl(&tok, tok->next);
+ } else if (equal(tok, "enum")) {
+ ty = enum_specifier(&tok, tok->next);
+ } else if (equal(tok, "typeof")) {
+ ty = typeof_specifier(&tok, tok->next);
+ } else {
+ ty = ty2;
+ tok = tok->next;
+ }
+
+ counter += OTHER;
+ continue;
+ }
+
+ // Handle built-in types.
+ if (equal(tok, "void"))
+ counter += VOID;
+ else if (equal(tok, "_Bool"))
+ counter += BOOL;
+ else if (equal(tok, "char"))
+ counter += CHAR;
+ else if (equal(tok, "short"))
+ counter += SHORT;
+ else if (equal(tok, "int"))
+ counter += INT;
+ else if (equal(tok, "long"))
+ counter += LONG;
+ else if (equal(tok, "float"))
+ counter += FLOAT;
+ else if (equal(tok, "double"))
+ counter += DOUBLE;
+ else if (equal(tok, "signed"))
+ counter |= SIGNED;
+ else if (equal(tok, "unsigned"))
+ counter |= UNSIGNED;
+ else
+ unreachable();
+
+ switch (counter) {
+ case VOID:
+ ty = ty_void;
+ break;
+ case BOOL:
+ ty = ty_bool;
+ break;
+ case CHAR:
+ case SIGNED + CHAR:
+ ty = ty_char;
+ break;
+ case UNSIGNED + CHAR:
+ ty = ty_uchar;
+ break;
+ case SHORT:
+ case SHORT + INT:
+ case SIGNED + SHORT:
+ case SIGNED + SHORT + INT:
+ ty = ty_short;
+ break;
+ case UNSIGNED + SHORT:
+ case UNSIGNED + SHORT + INT:
+ ty = ty_ushort;
+ break;
+ case INT:
+ case SIGNED:
+ case SIGNED + INT:
+ ty = ty_int;
+ break;
+ case UNSIGNED:
+ case UNSIGNED + INT:
+ ty = ty_uint;
+ break;
+ case LONG:
+ case LONG + INT:
+ case LONG + LONG:
+ case LONG + LONG + INT:
+ case SIGNED + LONG:
+ case SIGNED + LONG + INT:
+ case SIGNED + LONG + LONG:
+ case SIGNED + LONG + LONG + INT:
+ ty = ty_long;
+ break;
+ case UNSIGNED + LONG:
+ case UNSIGNED + LONG + INT:
+ case UNSIGNED + LONG + LONG:
+ case UNSIGNED + LONG + LONG + INT:
+ ty = ty_ulong;
+ break;
+ case FLOAT:
+ ty = ty_float;
+ break;
+ case DOUBLE:
+ ty = ty_double;
+ break;
+ case LONG + DOUBLE:
+ ty = ty_ldouble;
+ break;
+ default:
+ error_tok(tok, "invalid type");
+ }
+
+ tok = tok->next;
+ }
+
+ if (is_atomic) {
+ ty = copy_type(ty);
+ ty->is_atomic = true;
+ }
+
+ *rest = tok;
+ return ty;
+}
+
+// func-params = ("void" | param ("," param)* ("," "...")?)? ")"
+// param = declspec declarator
+static Type *func_params(Token **rest, Token *tok, Type *ty) {
+ if (equal(tok, "void") && equal(tok->next, ")")) {
+ *rest = tok->next->next;
+ return func_type(ty);
+ }
+
+ Type head = {};
+ Type *cur = &head;
+ bool is_variadic = false;
+
+ while (!equal(tok, ")")) {
+ if (cur != &head)
+ tok = skip(tok, ",");
+
+ if (equal(tok, "...")) {
+ is_variadic = true;
+ tok = tok->next;
+ skip(tok, ")");
+ break;
+ }
+
+ Type *ty2 = declspec(&tok, tok, NULL);
+ ty2 = declarator(&tok, tok, ty2);
+
+ Token *name = ty2->name;
+
+ if (ty2->kind == TY_ARRAY) {
+ // "array of T" is converted to "pointer to T" only in the parameter
+ // context. For example, *argv[] is converted to **argv by this.
+ ty2 = pointer_to(ty2->base);
+ ty2->name = name;
+ } else if (ty2->kind == TY_FUNC) {
+ // Likewise, a function is converted to a pointer to a function
+ // only in the parameter context.
+ ty2 = pointer_to(ty2);
+ ty2->name = name;
+ }
+
+ cur = cur->next = copy_type(ty2);
+ }
+
+ if (cur == &head)
+ is_variadic = true;
+
+ ty = func_type(ty);
+ ty->params = head.next;
+ ty->is_variadic = is_variadic;
+ *rest = tok->next;
+ return ty;
+}
+
+// array-dimensions = ("static" | "restrict")* const-expr? "]" type-suffix
+static Type *array_dimensions(Token **rest, Token *tok, Type *ty) {
+ while (equal(tok, "static") || equal(tok, "restrict"))
+ tok = tok->next;
+
+ if (equal(tok, "]")) {
+ ty = type_suffix(rest, tok->next, ty);
+ return array_of(ty, -1);
+ }
+
+ Node *expr = conditional(&tok, tok);
+ tok = skip(tok, "]");
+ ty = type_suffix(rest, tok, ty);
+
+ if (ty->kind == TY_VLA || !is_const_expr(expr))
+ return vla_of(ty, expr);
+ return array_of(ty, eval(expr));
+}
+
+// type-suffix = "(" func-params
+// | "[" array-dimensions
+// | ε
+static Type *type_suffix(Token **rest, Token *tok, Type *ty) {
+ if (equal(tok, "("))
+ return func_params(rest, tok->next, ty);
+
+ if (equal(tok, "["))
+ return array_dimensions(rest, tok->next, ty);
+
+ *rest = tok;
+ return ty;
+}
+
+// pointers = ("*" ("const" | "volatile" | "restrict")*)*
+static Type *pointers(Token **rest, Token *tok, Type *ty) {
+ while (consume(&tok, tok, "*")) {
+ ty = pointer_to(ty);
+ while (equal(tok, "const") || equal(tok, "volatile") || equal(tok, "restrict") ||
+ equal(tok, "__restrict") || equal(tok, "__restrict__"))
+ tok = tok->next;
+ }
+ *rest = tok;
+ return ty;
+}
+
+// declarator = pointers ("(" ident ")" | "(" declarator ")" | ident) type-suffix
+static Type *declarator(Token **rest, Token *tok, Type *ty) {
+ ty = pointers(&tok, tok, ty);
+
+ if (equal(tok, "(")) {
+ Token *start = tok;
+ Type dummy = {};
+ declarator(&tok, start->next, &dummy);
+ tok = skip(tok, ")");
+ ty = type_suffix(rest, tok, ty);
+ return declarator(&tok, start->next, ty);
+ }
+
+ Token *name = NULL;
+ Token *name_pos = tok;
+
+ if (tok->kind == TK_IDENT) {
+ name = tok;
+ tok = tok->next;
+ }
+
+ ty = type_suffix(rest, tok, ty);
+ ty->name = name;
+ ty->name_pos = name_pos;
+ return ty;
+}
+
+// abstract-declarator = pointers ("(" abstract-declarator ")")? type-suffix
+static Type *abstract_declarator(Token **rest, Token *tok, Type *ty) {
+ ty = pointers(&tok, tok, ty);
+
+ if (equal(tok, "(")) {
+ Token *start = tok;
+ Type dummy = {};
+ abstract_declarator(&tok, start->next, &dummy);
+ tok = skip(tok, ")");
+ ty = type_suffix(rest, tok, ty);
+ return abstract_declarator(&tok, start->next, ty);
+ }
+
+ return type_suffix(rest, tok, ty);
+}
+
+// type-name = declspec abstract-declarator
+static Type *typename(Token **rest, Token *tok) {
+ Type *ty = declspec(&tok, tok, NULL);
+ return abstract_declarator(rest, tok, ty);
+}
+
+static bool is_end(Token *tok) {
+ return equal(tok, "}") || (equal(tok, ",") && equal(tok->next, "}"));
+}
+
+static bool consume_end(Token **rest, Token *tok) {
+ if (equal(tok, "}")) {
+ *rest = tok->next;
+ return true;
+ }
+
+ if (equal(tok, ",") && equal(tok->next, "}")) {
+ *rest = tok->next->next;
+ return true;
+ }
+
+ return false;
+}
+
+// enum-specifier = ident? "{" enum-list? "}"
+// | ident ("{" enum-list? "}")?
+//
+// enum-list = ident ("=" num)? ("," ident ("=" num)?)* ","?
+static Type *enum_specifier(Token **rest, Token *tok) {
+ Type *ty = enum_type();
+
+ // Read a struct tag.
+ Token *tag = NULL;
+ if (tok->kind == TK_IDENT) {
+ tag = tok;
+ tok = tok->next;
+ }
+
+ if (tag && !equal(tok, "{")) {
+ Type *ty = find_tag(tag);
+ if (!ty)
+ error_tok(tag, "unknown enum type");
+ if (ty->kind != TY_ENUM)
+ error_tok(tag, "not an enum tag");
+ *rest = tok;
+ return ty;
+ }
+
+ tok = skip(tok, "{");
+
+ // Read an enum-list.
+ int i = 0;
+ int val = 0;
+ while (!consume_end(rest, tok)) {
+ if (i++ > 0)
+ tok = skip(tok, ",");
+
+ char *name = get_ident(tok);
+ tok = tok->next;
+
+ if (equal(tok, "="))
+ val = const_expr(&tok, tok->next);
+
+ VarScope *sc = push_scope(name);
+ sc->enum_ty = ty;
+ sc->enum_val = val++;
+ }
+
+ if (tag)
+ push_tag_scope(tag, ty);
+ return ty;
+}
+
+// typeof-specifier = "(" (expr | typename) ")"
+static Type *typeof_specifier(Token **rest, Token *tok) {
+ tok = skip(tok, "(");
+
+ Type *ty;
+ if (is_typename(tok)) {
+ ty = typename(&tok, tok);
+ } else {
+ Node *node = expr(&tok, tok);
+ add_type(node);
+ ty = node->ty;
+ }
+ *rest = skip(tok, ")");
+ return ty;
+}
+
+// Generate code for computing a VLA size.
+static Node *compute_vla_size(Type *ty, Token *tok) {
+ Node *node = new_node(ND_NULL_EXPR, tok);
+ if (ty->base)
+ node = new_binary(ND_COMMA, node, compute_vla_size(ty->base, tok), tok);
+
+ if (ty->kind != TY_VLA)
+ return node;
+
+ Node *base_sz;
+ if (ty->base->kind == TY_VLA)
+ base_sz = new_var_node(ty->base->vla_size, tok);
+ else
+ base_sz = new_num(ty->base->size, tok);
+
+ ty->vla_size = new_lvar("", ty_ulong);
+ Node *expr = new_binary(ND_ASSIGN, new_var_node(ty->vla_size, tok),
+ new_binary(ND_MUL, ty->vla_len, base_sz, tok),
+ tok);
+ return new_binary(ND_COMMA, node, expr, tok);
+}
+
+static Node *new_alloca(Node *sz) {
+ Node *node = new_unary(ND_FUNCALL, new_var_node(builtin_alloca, sz->tok), sz->tok);
+ node->func_ty = builtin_alloca->ty;
+ node->ty = builtin_alloca->ty->return_ty;
+ node->args = sz;
+ add_type(sz);
+ return node;
+}
+
+// declaration = declspec (declarator ("=" expr)? ("," declarator ("=" expr)?)*)? ";"
+static Node *declaration(Token **rest, Token *tok, Type *basety, VarAttr *attr) {
+ Node head = {};
+ Node *cur = &head;
+ int i = 0;
+
+ while (!equal(tok, ";")) {
+ if (i++ > 0)
+ tok = skip(tok, ",");
+
+ Type *ty = declarator(&tok, tok, basety);
+ if (ty->kind == TY_VOID)
+ error_tok(tok, "variable declared void");
+ if (!ty->name)
+ error_tok(ty->name_pos, "variable name omitted");
+
+ if (attr && attr->is_static) {
+ // static local variable
+ Obj *var = new_anon_gvar(ty);
+ push_scope(get_ident(ty->name))->var = var;
+ if (equal(tok, "="))
+ gvar_initializer(&tok, tok->next, var);
+ continue;
+ }
+
+ // Generate code for computing a VLA size. We need to do this
+ // even if ty is not VLA because ty may be a pointer to VLA
+ // (e.g. int (*foo)[n][m] where n and m are variables.)
+ cur = cur->next = new_unary(ND_EXPR_STMT, compute_vla_size(ty, tok), tok);
+
+ if (ty->kind == TY_VLA) {
+ if (equal(tok, "="))
+ error_tok(tok, "variable-sized object may not be initialized");
+
+ // Variable length arrays (VLAs) are translated to alloca() calls.
+ // For example, `int x[n+2]` is translated to `tmp = n + 2,
+ // x = alloca(tmp)`.
+ Obj *var = new_lvar(get_ident(ty->name), ty);
+ Token *tok = ty->name;
+ Node *expr = new_binary(ND_ASSIGN, new_vla_ptr(var, tok),
+ new_alloca(new_var_node(ty->vla_size, tok)),
+ tok);
+
+ cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);
+ continue;
+ }
+
+ Obj *var = new_lvar(get_ident(ty->name), ty);
+ if (attr && attr->align)
+ var->align = attr->align;
+
+ if (equal(tok, "=")) {
+ Node *expr = lvar_initializer(&tok, tok->next, var);
+ cur = cur->next = new_unary(ND_EXPR_STMT, expr, tok);
+ }
+
+ if (var->ty->size < 0)
+ error_tok(ty->name, "variable has incomplete type");
+ if (var->ty->kind == TY_VOID)
+ error_tok(ty->name, "variable declared void");
+ }
+
+ Node *node = new_node(ND_BLOCK, tok);
+ node->body = head.next;
+ *rest = tok->next;
+ return node;
+}
+
+static Token *skip_excess_element(Token *tok) {
+ if (equal(tok, "{")) {
+ tok = skip_excess_element(tok->next);
+ return skip(tok, "}");
+ }
+
+ assign(&tok, tok);
+ return tok;
+}
+
+// string-initializer = string-literal
+static void string_initializer(Token **rest, Token *tok, Initializer *init) {
+ if (init->is_flexible)
+ *init = *new_initializer(array_of(init->ty->base, tok->ty->array_len), false);
+
+ int len = MIN(init->ty->array_len, tok->ty->array_len);
+
+ switch (init->ty->base->size) {
+ case 1: {
+ char *str = tok->str;
+ for (int i = 0; i < len; i++)
+ init->children[i]->expr = new_num(str[i], tok);
+ break;
+ }
+ case 2: {
+ uint16_t *str = (uint16_t *)tok->str;
+ for (int i = 0; i < len; i++)
+ init->children[i]->expr = new_num(str[i], tok);
+ break;
+ }
+ case 4: {
+ uint32_t *str = (uint32_t *)tok->str;
+ for (int i = 0; i < len; i++)
+ init->children[i]->expr = new_num(str[i], tok);
+ break;
+ }
+ default:
+ unreachable();
+ }
+
+ *rest = tok->next;
+}
+
+// array-designator = "[" const-expr "]"
+//
+// C99 added the designated initializer to the language, which allows
+// programmers to move the "cursor" of an initializer to any element.
+// The syntax looks like this:
+//
+// int x[10] = { 1, 2, [5]=3, 4, 5, 6, 7 };
+//
+// `[5]` moves the cursor to the 5th element, so the 5th element of x
+// is set to 3. Initialization then continues forward in order, so
+// 6th, 7th, 8th and 9th elements are initialized with 4, 5, 6 and 7,
+// respectively. Unspecified elements (in this case, 3rd and 4th
+// elements) are initialized with zero.
+//
+// Nesting is allowed, so the following initializer is valid:
+//
+// int x[5][10] = { [5][8]=1, 2, 3 };
+//
+// It sets x[5][8], x[5][9] and x[6][0] to 1, 2 and 3, respectively.
+//
+// Use `.fieldname` to move the cursor for a struct initializer. E.g.
+//
+// struct { int a, b, c; } x = { .c=5 };
+//
+// The above initializer sets x.c to 5.
+static void array_designator(Token **rest, Token *tok, Type *ty, int *begin, int *end) {
+ *begin = const_expr(&tok, tok->next);
+ if (*begin >= ty->array_len)
+ error_tok(tok, "array designator index exceeds array bounds");
+
+ if (equal(tok, "...")) {
+ *end = const_expr(&tok, tok->next);
+ if (*end >= ty->array_len)
+ error_tok(tok, "array designator index exceeds array bounds");
+ if (*end < *begin)
+ error_tok(tok, "array designator range [%d, %d] is empty", *begin, *end);
+ } else {
+ *end = *begin;
+ }
+
+ *rest = skip(tok, "]");
+}
+
+// struct-designator = "." ident
+static Member *struct_designator(Token **rest, Token *tok, Type *ty) {
+ Token *start = tok;
+ tok = skip(tok, ".");
+ if (tok->kind != TK_IDENT)
+ error_tok(tok, "expected a field designator");
+
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ // Anonymous struct member
+ if (mem->ty->kind == TY_STRUCT && !mem->name) {
+ if (get_struct_member(mem->ty, tok)) {
+ *rest = start;
+ return mem;
+ }
+ continue;
+ }
+
+ // Regular struct member
+ if (mem->name->len == tok->len && !strncmp(mem->name->loc, tok->loc, tok->len)) {
+ *rest = tok->next;
+ return mem;
+ }
+ }
+
+ error_tok(tok, "struct has no such member");
+}
+
+// designation = ("[" const-expr "]" | "." ident)* "="? initializer
+static void designation(Token **rest, Token *tok, Initializer *init) {
+ if (equal(tok, "[")) {
+ if (init->ty->kind != TY_ARRAY)
+ error_tok(tok, "array index in non-array initializer");
+
+ int begin, end;
+ array_designator(&tok, tok, init->ty, &begin, &end);
+
+ Token *tok2;
+ for (int i = begin; i <= end; i++)
+ designation(&tok2, tok, init->children[i]);
+ array_initializer2(rest, tok2, init, begin + 1);
+ return;
+ }
+
+ if (equal(tok, ".") && init->ty->kind == TY_STRUCT) {
+ Member *mem = struct_designator(&tok, tok, init->ty);
+ designation(&tok, tok, init->children[mem->idx]);
+ init->expr = NULL;
+ struct_initializer2(rest, tok, init, mem->next);
+ return;
+ }
+
+ if (equal(tok, ".") && init->ty->kind == TY_UNION) {
+ Member *mem = struct_designator(&tok, tok, init->ty);
+ init->mem = mem;
+ designation(rest, tok, init->children[mem->idx]);
+ return;
+ }
+
+ if (equal(tok, "."))
+ error_tok(tok, "field name not in struct or union initializer");
+
+ if (equal(tok, "="))
+ tok = tok->next;
+ initializer2(rest, tok, init);
+}
+
+// An array length can be omitted if an array has an initializer
+// (e.g. `int x[] = {1,2,3}`). If it's omitted, count the number
+// of initializer elements.
+static int count_array_init_elements(Token *tok, Type *ty) {
+ bool first = true;
+ Initializer *dummy = new_initializer(ty->base, true);
+
+ int i = 0, max = 0;
+
+ while (!consume_end(&tok, tok)) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ if (equal(tok, "[")) {
+ i = const_expr(&tok, tok->next);
+ if (equal(tok, "..."))
+ i = const_expr(&tok, tok->next);
+ tok = skip(tok, "]");
+ designation(&tok, tok, dummy);
+ } else {
+ initializer2(&tok, tok, dummy);
+ }
+
+ i++;
+ max = MAX(max, i);
+ }
+ return max;
+}
+
+// array-initializer1 = "{" initializer ("," initializer)* ","? "}"
+static void array_initializer1(Token **rest, Token *tok, Initializer *init) {
+ tok = skip(tok, "{");
+
+ if (init->is_flexible) {
+ int len = count_array_init_elements(tok, init->ty);
+ *init = *new_initializer(array_of(init->ty->base, len), false);
+ }
+
+ bool first = true;
+
+ if (init->is_flexible) {
+ int len = count_array_init_elements(tok, init->ty);
+ *init = *new_initializer(array_of(init->ty->base, len), false);
+ }
+
+ for (int i = 0; !consume_end(rest, tok); i++) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ if (equal(tok, "[")) {
+ int begin, end;
+ array_designator(&tok, tok, init->ty, &begin, &end);
+
+ Token *tok2;
+ for (int j = begin; j <= end; j++)
+ designation(&tok2, tok, init->children[j]);
+ tok = tok2;
+ i = end;
+ continue;
+ }
+
+ if (i < init->ty->array_len)
+ initializer2(&tok, tok, init->children[i]);
+ else
+ tok = skip_excess_element(tok);
+ }
+}
+
+// array-initializer2 = initializer ("," initializer)*
+static void array_initializer2(Token **rest, Token *tok, Initializer *init, int i) {
+ if (init->is_flexible) {
+ int len = count_array_init_elements(tok, init->ty);
+ *init = *new_initializer(array_of(init->ty->base, len), false);
+ }
+
+ for (; i < init->ty->array_len && !is_end(tok); i++) {
+ Token *start = tok;
+ if (i > 0)
+ tok = skip(tok, ",");
+
+ if (equal(tok, "[") || equal(tok, ".")) {
+ *rest = start;
+ return;
+ }
+
+ initializer2(&tok, tok, init->children[i]);
+ }
+ *rest = tok;
+}
+
+// struct-initializer1 = "{" initializer ("," initializer)* ","? "}"
+static void struct_initializer1(Token **rest, Token *tok, Initializer *init) {
+ tok = skip(tok, "{");
+
+ Member *mem = init->ty->members;
+ bool first = true;
+
+ while (!consume_end(rest, tok)) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ if (equal(tok, ".")) {
+ mem = struct_designator(&tok, tok, init->ty);
+ designation(&tok, tok, init->children[mem->idx]);
+ mem = mem->next;
+ continue;
+ }
+
+ if (mem) {
+ initializer2(&tok, tok, init->children[mem->idx]);
+ mem = mem->next;
+ } else {
+ tok = skip_excess_element(tok);
+ }
+ }
+}
+
+// struct-initializer2 = initializer ("," initializer)*
+static void struct_initializer2(Token **rest, Token *tok, Initializer *init, Member *mem) {
+ bool first = true;
+
+ for (; mem && !is_end(tok); mem = mem->next) {
+ Token *start = tok;
+
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ if (equal(tok, "[") || equal(tok, ".")) {
+ *rest = start;
+ return;
+ }
+
+ initializer2(&tok, tok, init->children[mem->idx]);
+ }
+ *rest = tok;
+}
+
+static void union_initializer(Token **rest, Token *tok, Initializer *init) {
+ // Unlike structs, union initializers take only one initializer,
+ // and that initializes the first union member by default.
+ // You can initialize other member using a designated initializer.
+ if (equal(tok, "{") && equal(tok->next, ".")) {
+ Member *mem = struct_designator(&tok, tok->next, init->ty);
+ init->mem = mem;
+ designation(&tok, tok, init->children[mem->idx]);
+ *rest = skip(tok, "}");
+ return;
+ }
+
+ init->mem = init->ty->members;
+
+ if (equal(tok, "{")) {
+ initializer2(&tok, tok->next, init->children[0]);
+ consume(&tok, tok, ",");
+ *rest = skip(tok, "}");
+ } else {
+ initializer2(rest, tok, init->children[0]);
+ }
+}
+
+// initializer = string-initializer | array-initializer
+// | struct-initializer | union-initializer
+// | assign
+static void initializer2(Token **rest, Token *tok, Initializer *init) {
+ if (init->ty->kind == TY_ARRAY && tok->kind == TK_STR) {
+ string_initializer(rest, tok, init);
+ return;
+ }
+
+ if (init->ty->kind == TY_ARRAY) {
+ if (equal(tok, "{"))
+ array_initializer1(rest, tok, init);
+ else
+ array_initializer2(rest, tok, init, 0);
+ return;
+ }
+
+ if (init->ty->kind == TY_STRUCT) {
+ if (equal(tok, "{")) {
+ struct_initializer1(rest, tok, init);
+ return;
+ }
+
+ // A struct can be initialized with another struct. E.g.
+ // `struct T x = y;` where y is a variable of type `struct T`.
+ // Handle that case first.
+ Node *expr = assign(rest, tok);
+ add_type(expr);
+ if (expr->ty->kind == TY_STRUCT) {
+ init->expr = expr;
+ return;
+ }
+
+ struct_initializer2(rest, tok, init, init->ty->members);
+ return;
+ }
+
+ if (init->ty->kind == TY_UNION) {
+ union_initializer(rest, tok, init);
+ return;
+ }
+
+ if (equal(tok, "{")) {
+ // An initializer for a scalar variable can be surrounded by
+ // braces. E.g. `int x = {3};`. Handle that case.
+ initializer2(&tok, tok->next, init);
+ *rest = skip(tok, "}");
+ return;
+ }
+
+ init->expr = assign(rest, tok);
+}
+
+static Type *copy_struct_type(Type *ty) {
+ ty = copy_type(ty);
+
+ Member head = {};
+ Member *cur = &head;
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ Member *m = calloc(1, sizeof(Member));
+ *m = *mem;
+ cur = cur->next = m;
+ }
+
+ ty->members = head.next;
+ return ty;
+}
+
+static Initializer *initializer(Token **rest, Token *tok, Type *ty, Type **new_ty) {
+ Initializer *init = new_initializer(ty, true);
+ initializer2(rest, tok, init);
+
+ if ((ty->kind == TY_STRUCT || ty->kind == TY_UNION) && ty->is_flexible) {
+ ty = copy_struct_type(ty);
+
+ Member *mem = ty->members;
+ while (mem->next)
+ mem = mem->next;
+ mem->ty = init->children[mem->idx]->ty;
+ ty->size += mem->ty->size;
+
+ *new_ty = ty;
+ return init;
+ }
+
+ *new_ty = init->ty;
+ return init;
+}
+
+static Node *init_desg_expr(InitDesg *desg, Token *tok) {
+ if (desg->var)
+ return new_var_node(desg->var, tok);
+
+ if (desg->member) {
+ Node *node = new_unary(ND_MEMBER, init_desg_expr(desg->next, tok), tok);
+ node->member = desg->member;
+ return node;
+ }
+
+ Node *lhs = init_desg_expr(desg->next, tok);
+ Node *rhs = new_num(desg->idx, tok);
+ return new_unary(ND_DEREF, new_add(lhs, rhs, tok), tok);
+}
+
+static Node *create_lvar_init(Initializer *init, Type *ty, InitDesg *desg, Token *tok) {
+ if (ty->kind == TY_ARRAY) {
+ Node *node = new_node(ND_NULL_EXPR, tok);
+ for (int i = 0; i < ty->array_len; i++) {
+ InitDesg desg2 = {desg, i};
+ Node *rhs = create_lvar_init(init->children[i], ty->base, &desg2, tok);
+ node = new_binary(ND_COMMA, node, rhs, tok);
+ }
+ return node;
+ }
+
+ if (ty->kind == TY_STRUCT && !init->expr) {
+ Node *node = new_node(ND_NULL_EXPR, tok);
+
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ InitDesg desg2 = {desg, 0, mem};
+ Node *rhs = create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok);
+ node = new_binary(ND_COMMA, node, rhs, tok);
+ }
+ return node;
+ }
+
+ if (ty->kind == TY_UNION) {
+ Member *mem = init->mem ? init->mem : ty->members;
+ InitDesg desg2 = {desg, 0, mem};
+ return create_lvar_init(init->children[mem->idx], mem->ty, &desg2, tok);
+ }
+
+ if (!init->expr)
+ return new_node(ND_NULL_EXPR, tok);
+
+ Node *lhs = init_desg_expr(desg, tok);
+ return new_binary(ND_ASSIGN, lhs, init->expr, tok);
+}
+
+// A variable definition with an initializer is a shorthand notation
+// for a variable definition followed by assignments. This function
+// generates assignment expressions for an initializer. For example,
+// `int x[2][2] = {{6, 7}, {8, 9}}` is converted to the following
+// expressions:
+//
+// x[0][0] = 6;
+// x[0][1] = 7;
+// x[1][0] = 8;
+// x[1][1] = 9;
+static Node *lvar_initializer(Token **rest, Token *tok, Obj *var) {
+ Initializer *init = initializer(rest, tok, var->ty, &var->ty);
+ InitDesg desg = {NULL, 0, NULL, var};
+
+ // If a partial initializer list is given, the standard requires
+ // that unspecified elements are set to 0. Here, we simply
+ // zero-initialize the entire memory region of a variable before
+ // initializing it with user-supplied values.
+ Node *lhs = new_node(ND_MEMZERO, tok);
+ lhs->var = var;
+
+ Node *rhs = create_lvar_init(init, var->ty, &desg, tok);
+ return new_binary(ND_COMMA, lhs, rhs, tok);
+}
+
+static uint64_t read_buf(char *buf, int sz) {
+ if (sz == 1)
+ return *buf;
+ if (sz == 2)
+ return *(uint16_t *)buf;
+ if (sz == 4)
+ return *(uint32_t *)buf;
+ if (sz == 8)
+ return *(uint64_t *)buf;
+ unreachable();
+}
+
+static void write_buf(char *buf, uint64_t val, int sz) {
+ if (sz == 1)
+ *buf = val;
+ else if (sz == 2)
+ *(uint16_t *)buf = val;
+ else if (sz == 4)
+ *(uint32_t *)buf = val;
+ else if (sz == 8)
+ *(uint64_t *)buf = val;
+ else
+ unreachable();
+}
+
+static Relocation *
+write_gvar_data(Relocation *cur, Initializer *init, Type *ty, char *buf, int offset) {
+ if (ty->kind == TY_ARRAY) {
+ int sz = ty->base->size;
+ for (int i = 0; i < ty->array_len; i++)
+ cur = write_gvar_data(cur, init->children[i], ty->base, buf, offset + sz * i);
+ return cur;
+ }
+
+ if (ty->kind == TY_STRUCT) {
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ if (mem->is_bitfield) {
+ Node *expr = init->children[mem->idx]->expr;
+ if (!expr)
+ break;
+
+ char *loc = buf + offset + mem->offset;
+ uint64_t oldval = read_buf(loc, mem->ty->size);
+ uint64_t newval = eval(expr);
+ uint64_t mask = (1L << mem->bit_width) - 1;
+ uint64_t combined = oldval | ((newval & mask) << mem->bit_offset);
+ write_buf(loc, combined, mem->ty->size);
+ } else {
+ cur = write_gvar_data(cur, init->children[mem->idx], mem->ty, buf,
+ offset + mem->offset);
+ }
+ }
+ return cur;
+ }
+
+ if (ty->kind == TY_UNION) {
+ if (!init->mem)
+ return cur;
+ return write_gvar_data(cur, init->children[init->mem->idx],
+ init->mem->ty, buf, offset);
+ }
+
+ if (!init->expr)
+ return cur;
+
+ if (ty->kind == TY_FLOAT) {
+ *(float *)(buf + offset) = eval_double(init->expr);
+ return cur;
+ }
+
+ if (ty->kind == TY_DOUBLE) {
+ *(double *)(buf + offset) = eval_double(init->expr);
+ return cur;
+ }
+
+ char **label = NULL;
+ uint64_t val = eval2(init->expr, &label);
+
+ if (!label) {
+ write_buf(buf + offset, val, ty->size);
+ return cur;
+ }
+
+ Relocation *rel = calloc(1, sizeof(Relocation));
+ rel->offset = offset;
+ rel->label = label;
+ rel->addend = val;
+ cur->next = rel;
+ return cur->next;
+}
+
+// Initializers for global variables are evaluated at compile-time and
+// embedded to .data section. This function serializes Initializer
+// objects to a flat byte array. It is a compile error if an
+// initializer list contains a non-constant expression.
+static void gvar_initializer(Token **rest, Token *tok, Obj *var) {
+ Initializer *init = initializer(rest, tok, var->ty, &var->ty);
+
+ Relocation head = {};
+ char *buf = calloc(1, var->ty->size);
+ write_gvar_data(&head, init, var->ty, buf, 0);
+ var->init_data = buf;
+ var->rel = head.next;
+}
+
+// Returns true if a given token represents a type.
+static bool is_typename(Token *tok) {
+ static HashMap map;
+
+ if (map.capacity == 0) {
+ static char *kw[] = {
+ "void", "_Bool", "char", "short", "int", "long", "struct", "union",
+ "typedef", "enum", "static", "extern", "_Alignas", "signed", "unsigned",
+ "const", "volatile", "auto", "register", "restrict", "__restrict",
+ "__restrict__", "_Noreturn", "float", "double", "typeof", "inline",
+ "_Thread_local", "__thread", "_Atomic",
+ };
+
+ for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
+ hashmap_put(&map, kw[i], (void *)1);
+ }
+
+ return hashmap_get2(&map, tok->loc, tok->len) || find_typedef(tok);
+}
+
+// asm-stmt = "asm" ("volatile" | "inline")* "(" string-literal ")"
+static Node *asm_stmt(Token **rest, Token *tok) {
+ Node *node = new_node(ND_ASM, tok);
+ tok = tok->next;
+
+ while (equal(tok, "volatile") || equal(tok, "inline"))
+ tok = tok->next;
+
+ tok = skip(tok, "(");
+ if (tok->kind != TK_STR || tok->ty->base->kind != TY_CHAR)
+ error_tok(tok, "expected string literal");
+ node->asm_str = tok->str;
+ *rest = skip(tok->next, ")");
+ return node;
+}
+
+// stmt = "return" expr? ";"
+// | "if" "(" expr ")" stmt ("else" stmt)?
+// | "switch" "(" expr ")" stmt
+// | "case" const-expr ("..." const-expr)? ":" stmt
+// | "default" ":" stmt
+// | "for" "(" expr-stmt expr? ";" expr? ")" stmt
+// | "while" "(" expr ")" stmt
+// | "do" stmt "while" "(" expr ")" ";"
+// | "asm" asm-stmt
+// | "goto" (ident | "*" expr) ";"
+// | "break" ";"
+// | "continue" ";"
+// | ident ":" stmt
+// | "{" compound-stmt
+// | expr-stmt
+static Node *stmt(Token **rest, Token *tok) {
+ if (equal(tok, "return")) {
+ Node *node = new_node(ND_RETURN, tok);
+ if (consume(rest, tok->next, ";"))
+ return node;
+
+ Node *exp = expr(&tok, tok->next);
+ *rest = skip(tok, ";");
+
+ add_type(exp);
+ Type *ty = current_fn->ty->return_ty;
+ if (ty->kind != TY_STRUCT && ty->kind != TY_UNION)
+ exp = new_cast(exp, current_fn->ty->return_ty);
+
+ node->lhs = exp;
+ return node;
+ }
+
+ if (equal(tok, "if")) {
+ Node *node = new_node(ND_IF, tok);
+ tok = skip(tok->next, "(");
+ node->cond = expr(&tok, tok);
+ tok = skip(tok, ")");
+ node->then = stmt(&tok, tok);
+ if (equal(tok, "else"))
+ node->els = stmt(&tok, tok->next);
+ *rest = tok;
+ return node;
+ }
+
+ if (equal(tok, "switch")) {
+ Node *node = new_node(ND_SWITCH, tok);
+ tok = skip(tok->next, "(");
+ node->cond = expr(&tok, tok);
+ tok = skip(tok, ")");
+
+ Node *sw = current_switch;
+ current_switch = node;
+
+ char *brk = brk_label;
+ brk_label = node->brk_label = new_unique_name();
+
+ node->then = stmt(rest, tok);
+
+ current_switch = sw;
+ brk_label = brk;
+ return node;
+ }
+
+ if (equal(tok, "case")) {
+ if (!current_switch)
+ error_tok(tok, "stray case");
+
+ Node *node = new_node(ND_CASE, tok);
+ int begin = const_expr(&tok, tok->next);
+ int end;
+
+ if (equal(tok, "...")) {
+ // [GNU] Case ranges, e.g. "case 1 ... 5:"
+ end = const_expr(&tok, tok->next);
+ if (end < begin)
+ error_tok(tok, "empty case range specified");
+ } else {
+ end = begin;
+ }
+
+ tok = skip(tok, ":");
+ node->label = new_unique_name();
+ node->lhs = stmt(rest, tok);
+ node->begin = begin;
+ node->end = end;
+ node->case_next = current_switch->case_next;
+ current_switch->case_next = node;
+ return node;
+ }
+
+ if (equal(tok, "default")) {
+ if (!current_switch)
+ error_tok(tok, "stray default");
+
+ Node *node = new_node(ND_CASE, tok);
+ tok = skip(tok->next, ":");
+ node->label = new_unique_name();
+ node->lhs = stmt(rest, tok);
+ current_switch->default_case = node;
+ return node;
+ }
+
+ if (equal(tok, "for")) {
+ Node *node = new_node(ND_FOR, tok);
+ tok = skip(tok->next, "(");
+
+ enter_scope();
+
+ char *brk = brk_label;
+ char *cont = cont_label;
+ brk_label = node->brk_label = new_unique_name();
+ cont_label = node->cont_label = new_unique_name();
+
+ if (is_typename(tok)) {
+ Type *basety = declspec(&tok, tok, NULL);
+ node->init = declaration(&tok, tok, basety, NULL);
+ } else {
+ node->init = expr_stmt(&tok, tok);
+ }
+
+ if (!equal(tok, ";"))
+ node->cond = expr(&tok, tok);
+ tok = skip(tok, ";");
+
+ if (!equal(tok, ")"))
+ node->inc = expr(&tok, tok);
+ tok = skip(tok, ")");
+
+ node->then = stmt(rest, tok);
+
+ leave_scope();
+ brk_label = brk;
+ cont_label = cont;
+ return node;
+ }
+
+ if (equal(tok, "while")) {
+ Node *node = new_node(ND_FOR, tok);
+ tok = skip(tok->next, "(");
+ node->cond = expr(&tok, tok);
+ tok = skip(tok, ")");
+
+ char *brk = brk_label;
+ char *cont = cont_label;
+ brk_label = node->brk_label = new_unique_name();
+ cont_label = node->cont_label = new_unique_name();
+
+ node->then = stmt(rest, tok);
+
+ brk_label = brk;
+ cont_label = cont;
+ return node;
+ }
+
+ if (equal(tok, "do")) {
+ Node *node = new_node(ND_DO, tok);
+
+ char *brk = brk_label;
+ char *cont = cont_label;
+ brk_label = node->brk_label = new_unique_name();
+ cont_label = node->cont_label = new_unique_name();
+
+ node->then = stmt(&tok, tok->next);
+
+ brk_label = brk;
+ cont_label = cont;
+
+ tok = skip(tok, "while");
+ tok = skip(tok, "(");
+ node->cond = expr(&tok, tok);
+ tok = skip(tok, ")");
+ *rest = skip(tok, ";");
+ return node;
+ }
+
+ if (equal(tok, "asm"))
+ return asm_stmt(rest, tok);
+
+ if (equal(tok, "goto")) {
+ if (equal(tok->next, "*")) {
+ // [GNU] `goto *ptr` jumps to the address specified by `ptr`.
+ Node *node = new_node(ND_GOTO_EXPR, tok);
+ node->lhs = expr(&tok, tok->next->next);
+ *rest = skip(tok, ";");
+ return node;
+ }
+
+ Node *node = new_node(ND_GOTO, tok);
+ node->label = get_ident(tok->next);
+ node->goto_next = gotos;
+ gotos = node;
+ *rest = skip(tok->next->next, ";");
+ return node;
+ }
+
+ if (equal(tok, "break")) {
+ if (!brk_label)
+ error_tok(tok, "stray break");
+ Node *node = new_node(ND_GOTO, tok);
+ node->unique_label = brk_label;
+ *rest = skip(tok->next, ";");
+ return node;
+ }
+
+ if (equal(tok, "continue")) {
+ if (!cont_label)
+ error_tok(tok, "stray continue");
+ Node *node = new_node(ND_GOTO, tok);
+ node->unique_label = cont_label;
+ *rest = skip(tok->next, ";");
+ return node;
+ }
+
+ if (tok->kind == TK_IDENT && equal(tok->next, ":")) {
+ Node *node = new_node(ND_LABEL, tok);
+ node->label = strndup(tok->loc, tok->len);
+ node->unique_label = new_unique_name();
+ node->lhs = stmt(rest, tok->next->next);
+ node->goto_next = labels;
+ labels = node;
+ return node;
+ }
+
+ if (equal(tok, "{"))
+ return compound_stmt(rest, tok->next);
+
+ return expr_stmt(rest, tok);
+}
+
+// compound-stmt = (typedef | declaration | stmt)* "}"
+static Node *compound_stmt(Token **rest, Token *tok) {
+ Node *node = new_node(ND_BLOCK, tok);
+ Node head = {};
+ Node *cur = &head;
+
+ enter_scope();
+
+ while (!equal(tok, "}")) {
+ if (is_typename(tok) && !equal(tok->next, ":")) {
+ VarAttr attr = {};
+ Type *basety = declspec(&tok, tok, &attr);
+
+ if (attr.is_typedef) {
+ tok = parse_typedef(tok, basety);
+ continue;
+ }
+
+ if (is_function(tok)) {
+ tok = function(tok, basety, &attr);
+ continue;
+ }
+
+ if (attr.is_extern) {
+ tok = global_variable(tok, basety, &attr);
+ continue;
+ }
+
+ cur = cur->next = declaration(&tok, tok, basety, &attr);
+ } else {
+ cur = cur->next = stmt(&tok, tok);
+ }
+ add_type(cur);
+ }
+
+ leave_scope();
+
+ node->body = head.next;
+ *rest = tok->next;
+ return node;
+}
+
+// expr-stmt = expr? ";"
+static Node *expr_stmt(Token **rest, Token *tok) {
+ if (equal(tok, ";")) {
+ *rest = tok->next;
+ return new_node(ND_BLOCK, tok);
+ }
+
+ Node *node = new_node(ND_EXPR_STMT, tok);
+ node->lhs = expr(&tok, tok);
+ *rest = skip(tok, ";");
+ return node;
+}
+
+// expr = assign ("," expr)?
+static Node *expr(Token **rest, Token *tok) {
+ Node *node = assign(&tok, tok);
+
+ if (equal(tok, ","))
+ return new_binary(ND_COMMA, node, expr(rest, tok->next), tok);
+
+ *rest = tok;
+ return node;
+}
+
+static int64_t eval(Node *node) {
+ return eval2(node, NULL);
+}
+
+// Evaluate a given node as a constant expression.
+//
+// A constant expression is either just a number or ptr+n where ptr
+// is a pointer to a global variable and n is a postiive/negative
+// number. The latter form is accepted only as an initialization
+// expression for a global variable.
+static int64_t eval2(Node *node, char ***label) {
+ add_type(node);
+
+ if (is_flonum(node->ty))
+ return eval_double(node);
+
+ switch (node->kind) {
+ case ND_ADD:
+ return eval2(node->lhs, label) + eval(node->rhs);
+ case ND_SUB:
+ return eval2(node->lhs, label) - eval(node->rhs);
+ case ND_MUL:
+ return eval(node->lhs) * eval(node->rhs);
+ case ND_DIV:
+ if (node->ty->is_unsigned)
+ return (uint64_t)eval(node->lhs) / eval(node->rhs);
+ return eval(node->lhs) / eval(node->rhs);
+ case ND_NEG:
+ return -eval(node->lhs);
+ case ND_MOD:
+ if (node->ty->is_unsigned)
+ return (uint64_t)eval(node->lhs) % eval(node->rhs);
+ return eval(node->lhs) % eval(node->rhs);
+ case ND_BITAND:
+ return eval(node->lhs) & eval(node->rhs);
+ case ND_BITOR:
+ return eval(node->lhs) | eval(node->rhs);
+ case ND_BITXOR:
+ return eval(node->lhs) ^ eval(node->rhs);
+ case ND_SHL:
+ return eval(node->lhs) << eval(node->rhs);
+ case ND_SHR:
+ if (node->ty->is_unsigned && node->ty->size == 8)
+ return (uint64_t)eval(node->lhs) >> eval(node->rhs);
+ return eval(node->lhs) >> eval(node->rhs);
+ case ND_EQ:
+ return eval(node->lhs) == eval(node->rhs);
+ case ND_NE:
+ return eval(node->lhs) != eval(node->rhs);
+ case ND_LT:
+ if (node->lhs->ty->is_unsigned)
+ return (uint64_t)eval(node->lhs) < eval(node->rhs);
+ return eval(node->lhs) < eval(node->rhs);
+ case ND_LE:
+ if (node->lhs->ty->is_unsigned)
+ return (uint64_t)eval(node->lhs) <= eval(node->rhs);
+ return eval(node->lhs) <= eval(node->rhs);
+ case ND_COND:
+ return eval(node->cond) ? eval2(node->then, label) : eval2(node->els, label);
+ case ND_COMMA:
+ return eval2(node->rhs, label);
+ case ND_NOT:
+ return !eval(node->lhs);
+ case ND_BITNOT:
+ return ~eval(node->lhs);
+ case ND_LOGAND:
+ return eval(node->lhs) && eval(node->rhs);
+ case ND_LOGOR:
+ return eval(node->lhs) || eval(node->rhs);
+ case ND_CAST: {
+ int64_t val = eval2(node->lhs, label);
+ if (is_integer(node->ty)) {
+ switch (node->ty->size) {
+ case 1: return node->ty->is_unsigned ? (uint8_t)val : (int8_t)val;
+ case 2: return node->ty->is_unsigned ? (uint16_t)val : (int16_t)val;
+ case 4: return node->ty->is_unsigned ? (uint32_t)val : (int32_t)val;
+ }
+ }
+ return val;
+ }
+ case ND_ADDR:
+ return eval_rval(node->lhs, label);
+ case ND_LABEL_VAL:
+ *label = &node->unique_label;
+ return 0;
+ case ND_MEMBER:
+ if (!label)
+ error_tok(node->tok, "not a compile-time constant");
+ if (node->ty->kind != TY_ARRAY)
+ error_tok(node->tok, "invalid initializer");
+ return eval_rval(node->lhs, label) + node->member->offset;
+ case ND_VAR:
+ if (!label)
+ error_tok(node->tok, "not a compile-time constant");
+ if (node->var->ty->kind != TY_ARRAY && node->var->ty->kind != TY_FUNC)
+ error_tok(node->tok, "invalid initializer");
+ *label = &node->var->name;
+ return 0;
+ case ND_NUM:
+ return node->val;
+ }
+
+ error_tok(node->tok, "not a compile-time constant");
+}
+
+static int64_t eval_rval(Node *node, char ***label) {
+ switch (node->kind) {
+ case ND_VAR:
+ if (node->var->is_local)
+ error_tok(node->tok, "not a compile-time constant");
+ *label = &node->var->name;
+ return 0;
+ case ND_DEREF:
+ return eval2(node->lhs, label);
+ case ND_MEMBER:
+ return eval_rval(node->lhs, label) + node->member->offset;
+ }
+
+ error_tok(node->tok, "invalid initializer");
+}
+
+static bool is_const_expr(Node *node) {
+ add_type(node);
+
+ switch (node->kind) {
+ case ND_ADD:
+ case ND_SUB:
+ case ND_MUL:
+ case ND_DIV:
+ case ND_BITAND:
+ case ND_BITOR:
+ case ND_BITXOR:
+ case ND_SHL:
+ case ND_SHR:
+ case ND_EQ:
+ case ND_NE:
+ case ND_LT:
+ case ND_LE:
+ case ND_LOGAND:
+ case ND_LOGOR:
+ return is_const_expr(node->lhs) && is_const_expr(node->rhs);
+ case ND_COND:
+ if (!is_const_expr(node->cond))
+ return false;
+ return is_const_expr(eval(node->cond) ? node->then : node->els);
+ case ND_COMMA:
+ return is_const_expr(node->rhs);
+ case ND_NEG:
+ case ND_NOT:
+ case ND_BITNOT:
+ case ND_CAST:
+ return is_const_expr(node->lhs);
+ case ND_NUM:
+ return true;
+ }
+
+ return false;
+}
+
+int64_t const_expr(Token **rest, Token *tok) {
+ Node *node = conditional(rest, tok);
+ return eval(node);
+}
+
+static double eval_double(Node *node) {
+ add_type(node);
+
+ if (is_integer(node->ty)) {
+ if (node->ty->is_unsigned)
+ return (unsigned long)eval(node);
+ return eval(node);
+ }
+
+ switch (node->kind) {
+ case ND_ADD:
+ return eval_double(node->lhs) + eval_double(node->rhs);
+ case ND_SUB:
+ return eval_double(node->lhs) - eval_double(node->rhs);
+ case ND_MUL:
+ return eval_double(node->lhs) * eval_double(node->rhs);
+ case ND_DIV:
+ return eval_double(node->lhs) / eval_double(node->rhs);
+ case ND_NEG:
+ return -eval_double(node->lhs);
+ case ND_COND:
+ return eval_double(node->cond) ? eval_double(node->then) : eval_double(node->els);
+ case ND_COMMA:
+ return eval_double(node->rhs);
+ case ND_CAST:
+ if (is_flonum(node->lhs->ty))
+ return eval_double(node->lhs);
+ return eval(node->lhs);
+ case ND_NUM:
+ return node->fval;
+ }
+
+ error_tok(node->tok, "not a compile-time constant");
+}
+
+// Convert op= operators to expressions containing an assignment.
+//
+// In general, `A op= C` is converted to ``tmp = &A, *tmp = *tmp op B`.
+// However, if a given expression is of form `A.x op= C`, the input is
+// converted to `tmp = &A, (*tmp).x = (*tmp).x op C` to handle assignments
+// to bitfields.
+static Node *to_assign(Node *binary) {
+ add_type(binary->lhs);
+ add_type(binary->rhs);
+ Token *tok = binary->tok;
+
+ // Convert `A.x op= C` to `tmp = &A, (*tmp).x = (*tmp).x op C`.
+ if (binary->lhs->kind == ND_MEMBER) {
+ Obj *var = new_lvar("", pointer_to(binary->lhs->lhs->ty));
+
+ Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok),
+ new_unary(ND_ADDR, binary->lhs->lhs, tok), tok);
+
+ Node *expr2 = new_unary(ND_MEMBER,
+ new_unary(ND_DEREF, new_var_node(var, tok), tok),
+ tok);
+ expr2->member = binary->lhs->member;
+
+ Node *expr3 = new_unary(ND_MEMBER,
+ new_unary(ND_DEREF, new_var_node(var, tok), tok),
+ tok);
+ expr3->member = binary->lhs->member;
+
+ Node *expr4 = new_binary(ND_ASSIGN, expr2,
+ new_binary(binary->kind, expr3, binary->rhs, tok),
+ tok);
+
+ return new_binary(ND_COMMA, expr1, expr4, tok);
+ }
+
+ // If A is an atomic type, Convert `A op= B` to
+ //
+ // ({
+ // T1 *addr = &A; T2 val = (B); T1 old = *addr; T1 new;
+ // do {
+ // new = old op val;
+ // } while (!atomic_compare_exchange_strong(addr, &old, new));
+ // new;
+ // })
+ if (binary->lhs->ty->is_atomic) {
+ Node head = {};
+ Node *cur = &head;
+
+ Obj *addr = new_lvar("", pointer_to(binary->lhs->ty));
+ Obj *val = new_lvar("", binary->rhs->ty);
+ Obj *old = new_lvar("", binary->lhs->ty);
+ Obj *new = new_lvar("", binary->lhs->ty);
+
+ cur = cur->next =
+ new_unary(ND_EXPR_STMT,
+ new_binary(ND_ASSIGN, new_var_node(addr, tok),
+ new_unary(ND_ADDR, binary->lhs, tok), tok),
+ tok);
+
+ cur = cur->next =
+ new_unary(ND_EXPR_STMT,
+ new_binary(ND_ASSIGN, new_var_node(val, tok), binary->rhs, tok),
+ tok);
+
+ cur = cur->next =
+ new_unary(ND_EXPR_STMT,
+ new_binary(ND_ASSIGN, new_var_node(old, tok),
+ new_unary(ND_DEREF, new_var_node(addr, tok), tok), tok),
+ tok);
+
+ Node *loop = new_node(ND_DO, tok);
+ loop->brk_label = new_unique_name();
+ loop->cont_label = new_unique_name();
+
+ Node *body = new_binary(ND_ASSIGN,
+ new_var_node(new, tok),
+ new_binary(binary->kind, new_var_node(old, tok),
+ new_var_node(val, tok), tok),
+ tok);
+
+ loop->then = new_node(ND_BLOCK, tok);
+ loop->then->body = new_unary(ND_EXPR_STMT, body, tok);
+
+ Node *cas = new_node(ND_CAS, tok);
+ cas->cas_addr = new_var_node(addr, tok);
+ cas->cas_old = new_unary(ND_ADDR, new_var_node(old, tok), tok);
+ cas->cas_new = new_var_node(new, tok);
+ loop->cond = new_unary(ND_NOT, cas, tok);
+
+ cur = cur->next = loop;
+ cur = cur->next = new_unary(ND_EXPR_STMT, new_var_node(new, tok), tok);
+
+ Node *node = new_node(ND_STMT_EXPR, tok);
+ node->body = head.next;
+ return node;
+ }
+
+ // Convert `A op= B` to ``tmp = &A, *tmp = *tmp op B`.
+ Obj *var = new_lvar("", pointer_to(binary->lhs->ty));
+
+ Node *expr1 = new_binary(ND_ASSIGN, new_var_node(var, tok),
+ new_unary(ND_ADDR, binary->lhs, tok), tok);
+
+ Node *expr2 =
+ new_binary(ND_ASSIGN,
+ new_unary(ND_DEREF, new_var_node(var, tok), tok),
+ new_binary(binary->kind,
+ new_unary(ND_DEREF, new_var_node(var, tok), tok),
+ binary->rhs,
+ tok),
+ tok);
+
+ return new_binary(ND_COMMA, expr1, expr2, tok);
+}
+
+// assign = conditional (assign-op assign)?
+// assign-op = "=" | "+=" | "-=" | "*=" | "/=" | "%=" | "&=" | "|=" | "^="
+// | "<<=" | ">>="
+static Node *assign(Token **rest, Token *tok) {
+ Node *node = conditional(&tok, tok);
+
+ if (equal(tok, "="))
+ return new_binary(ND_ASSIGN, node, assign(rest, tok->next), tok);
+
+ if (equal(tok, "+="))
+ return to_assign(new_add(node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "-="))
+ return to_assign(new_sub(node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "*="))
+ return to_assign(new_binary(ND_MUL, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "/="))
+ return to_assign(new_binary(ND_DIV, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "%="))
+ return to_assign(new_binary(ND_MOD, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "&="))
+ return to_assign(new_binary(ND_BITAND, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "|="))
+ return to_assign(new_binary(ND_BITOR, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "^="))
+ return to_assign(new_binary(ND_BITXOR, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, "<<="))
+ return to_assign(new_binary(ND_SHL, node, assign(rest, tok->next), tok));
+
+ if (equal(tok, ">>="))
+ return to_assign(new_binary(ND_SHR, node, assign(rest, tok->next), tok));
+
+ *rest = tok;
+ return node;
+}
+
+// conditional = logor ("?" expr? ":" conditional)?
+static Node *conditional(Token **rest, Token *tok) {
+ Node *cond = logor(&tok, tok);
+
+ if (!equal(tok, "?")) {
+ *rest = tok;
+ return cond;
+ }
+
+ if (equal(tok->next, ":")) {
+ // [GNU] Compile `a ?: b` as `tmp = a, tmp ? tmp : b`.
+ add_type(cond);
+ Obj *var = new_lvar("", cond->ty);
+ Node *lhs = new_binary(ND_ASSIGN, new_var_node(var, tok), cond, tok);
+ Node *rhs = new_node(ND_COND, tok);
+ rhs->cond = new_var_node(var, tok);
+ rhs->then = new_var_node(var, tok);
+ rhs->els = conditional(rest, tok->next->next);
+ return new_binary(ND_COMMA, lhs, rhs, tok);
+ }
+
+ Node *node = new_node(ND_COND, tok);
+ node->cond = cond;
+ node->then = expr(&tok, tok->next);
+ tok = skip(tok, ":");
+ node->els = conditional(rest, tok);
+ return node;
+}
+
+// logor = logand ("||" logand)*
+static Node *logor(Token **rest, Token *tok) {
+ Node *node = logand(&tok, tok);
+ while (equal(tok, "||")) {
+ Token *start = tok;
+ node = new_binary(ND_LOGOR, node, logand(&tok, tok->next), start);
+ }
+ *rest = tok;
+ return node;
+}
+
+// logand = bitor ("&&" bitor)*
+static Node *logand(Token **rest, Token *tok) {
+ Node *node = bitor(&tok, tok);
+ while (equal(tok, "&&")) {
+ Token *start = tok;
+ node = new_binary(ND_LOGAND, node, bitor(&tok, tok->next), start);
+ }
+ *rest = tok;
+ return node;
+}
+
+// bitor = bitxor ("|" bitxor)*
+static Node *bitor(Token **rest, Token *tok) {
+ Node *node = bitxor(&tok, tok);
+ while (equal(tok, "|")) {
+ Token *start = tok;
+ node = new_binary(ND_BITOR, node, bitxor(&tok, tok->next), start);
+ }
+ *rest = tok;
+ return node;
+}
+
+// bitxor = bitand ("^" bitand)*
+static Node *bitxor(Token **rest, Token *tok) {
+ Node *node = bitand(&tok, tok);
+ while (equal(tok, "^")) {
+ Token *start = tok;
+ node = new_binary(ND_BITXOR, node, bitand(&tok, tok->next), start);
+ }
+ *rest = tok;
+ return node;
+}
+
+// bitand = equality ("&" equality)*
+static Node *bitand(Token **rest, Token *tok) {
+ Node *node = equality(&tok, tok);
+ while (equal(tok, "&")) {
+ Token *start = tok;
+ node = new_binary(ND_BITAND, node, equality(&tok, tok->next), start);
+ }
+ *rest = tok;
+ return node;
+}
+
+// equality = relational ("==" relational | "!=" relational)*
+static Node *equality(Token **rest, Token *tok) {
+ Node *node = relational(&tok, tok);
+
+ for (;;) {
+ Token *start = tok;
+
+ if (equal(tok, "==")) {
+ node = new_binary(ND_EQ, node, relational(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, "!=")) {
+ node = new_binary(ND_NE, node, relational(&tok, tok->next), start);
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// relational = shift ("<" shift | "<=" shift | ">" shift | ">=" shift)*
+static Node *relational(Token **rest, Token *tok) {
+ Node *node = shift(&tok, tok);
+
+ for (;;) {
+ Token *start = tok;
+
+ if (equal(tok, "<")) {
+ node = new_binary(ND_LT, node, shift(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, "<=")) {
+ node = new_binary(ND_LE, node, shift(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, ">")) {
+ node = new_binary(ND_LT, shift(&tok, tok->next), node, start);
+ continue;
+ }
+
+ if (equal(tok, ">=")) {
+ node = new_binary(ND_LE, shift(&tok, tok->next), node, start);
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// shift = add ("<<" add | ">>" add)*
+static Node *shift(Token **rest, Token *tok) {
+ Node *node = add(&tok, tok);
+
+ for (;;) {
+ Token *start = tok;
+
+ if (equal(tok, "<<")) {
+ node = new_binary(ND_SHL, node, add(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, ">>")) {
+ node = new_binary(ND_SHR, node, add(&tok, tok->next), start);
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// In C, `+` operator is overloaded to perform the pointer arithmetic.
+// If p is a pointer, p+n adds not n but sizeof(*p)*n to the value of p,
+// so that p+n points to the location n elements (not bytes) ahead of p.
+// In other words, we need to scale an integer value before adding to a
+// pointer value. This function takes care of the scaling.
+static Node *new_add(Node *lhs, Node *rhs, Token *tok) {
+ add_type(lhs);
+ add_type(rhs);
+
+ // num + num
+ if (is_numeric(lhs->ty) && is_numeric(rhs->ty))
+ return new_binary(ND_ADD, lhs, rhs, tok);
+
+ if (lhs->ty->base && rhs->ty->base)
+ error_tok(tok, "invalid operands");
+
+ // Canonicalize `num + ptr` to `ptr + num`.
+ if (!lhs->ty->base && rhs->ty->base) {
+ Node *tmp = lhs;
+ lhs = rhs;
+ rhs = tmp;
+ }
+
+ // VLA + num
+ if (lhs->ty->base->kind == TY_VLA) {
+ rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok);
+ return new_binary(ND_ADD, lhs, rhs, tok);
+ }
+
+ // ptr + num
+ rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok);
+ return new_binary(ND_ADD, lhs, rhs, tok);
+}
+
+// Like `+`, `-` is overloaded for the pointer type.
+static Node *new_sub(Node *lhs, Node *rhs, Token *tok) {
+ add_type(lhs);
+ add_type(rhs);
+
+ // num - num
+ if (is_numeric(lhs->ty) && is_numeric(rhs->ty))
+ return new_binary(ND_SUB, lhs, rhs, tok);
+
+ // VLA + num
+ if (lhs->ty->base->kind == TY_VLA) {
+ rhs = new_binary(ND_MUL, rhs, new_var_node(lhs->ty->base->vla_size, tok), tok);
+ add_type(rhs);
+ Node *node = new_binary(ND_SUB, lhs, rhs, tok);
+ node->ty = lhs->ty;
+ return node;
+ }
+
+ // ptr - num
+ if (lhs->ty->base && is_integer(rhs->ty)) {
+ rhs = new_binary(ND_MUL, rhs, new_long(lhs->ty->base->size, tok), tok);
+ add_type(rhs);
+ Node *node = new_binary(ND_SUB, lhs, rhs, tok);
+ node->ty = lhs->ty;
+ return node;
+ }
+
+ // ptr - ptr, which returns how many elements are between the two.
+ if (lhs->ty->base && rhs->ty->base) {
+ Node *node = new_binary(ND_SUB, lhs, rhs, tok);
+ node->ty = ty_long;
+ return new_binary(ND_DIV, node, new_num(lhs->ty->base->size, tok), tok);
+ }
+
+ error_tok(tok, "invalid operands");
+}
+
+// add = mul ("+" mul | "-" mul)*
+static Node *add(Token **rest, Token *tok) {
+ Node *node = mul(&tok, tok);
+
+ for (;;) {
+ Token *start = tok;
+
+ if (equal(tok, "+")) {
+ node = new_add(node, mul(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, "-")) {
+ node = new_sub(node, mul(&tok, tok->next), start);
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// mul = cast ("*" cast | "/" cast | "%" cast)*
+static Node *mul(Token **rest, Token *tok) {
+ Node *node = cast(&tok, tok);
+
+ for (;;) {
+ Token *start = tok;
+
+ if (equal(tok, "*")) {
+ node = new_binary(ND_MUL, node, cast(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, "/")) {
+ node = new_binary(ND_DIV, node, cast(&tok, tok->next), start);
+ continue;
+ }
+
+ if (equal(tok, "%")) {
+ node = new_binary(ND_MOD, node, cast(&tok, tok->next), start);
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// cast = "(" type-name ")" cast | unary
+static Node *cast(Token **rest, Token *tok) {
+ if (equal(tok, "(") && is_typename(tok->next)) {
+ Token *start = tok;
+ Type *ty = typename(&tok, tok->next);
+ tok = skip(tok, ")");
+
+ // compound literal
+ if (equal(tok, "{"))
+ return unary(rest, start);
+
+ // type cast
+ Node *node = new_cast(cast(rest, tok), ty);
+ node->tok = start;
+ return node;
+ }
+
+ return unary(rest, tok);
+}
+
+// unary = ("+" | "-" | "*" | "&" | "!" | "~") cast
+// | ("++" | "--") unary
+// | "&&" ident
+// | postfix
+static Node *unary(Token **rest, Token *tok) {
+ if (equal(tok, "+"))
+ return cast(rest, tok->next);
+
+ if (equal(tok, "-"))
+ return new_unary(ND_NEG, cast(rest, tok->next), tok);
+
+ if (equal(tok, "&")) {
+ Node *lhs = cast(rest, tok->next);
+ add_type(lhs);
+ if (lhs->kind == ND_MEMBER && lhs->member->is_bitfield)
+ error_tok(tok, "cannot take address of bitfield");
+ return new_unary(ND_ADDR, lhs, tok);
+ }
+
+ if (equal(tok, "*")) {
+ // [https://www.sigbus.info/n1570#6.5.3.2p4] This is an oddity
+ // in the C spec, but dereferencing a function shouldn't do
+ // anything. If foo is a function, `*foo`, `**foo` or `*****foo`
+ // are all equivalent to just `foo`.
+ Node *node = cast(rest, tok->next);
+ add_type(node);
+ if (node->ty->kind == TY_FUNC)
+ return node;
+ return new_unary(ND_DEREF, node, tok);
+ }
+
+ if (equal(tok, "!"))
+ return new_unary(ND_NOT, cast(rest, tok->next), tok);
+
+ if (equal(tok, "~"))
+ return new_unary(ND_BITNOT, cast(rest, tok->next), tok);
+
+ // Read ++i as i+=1
+ if (equal(tok, "++"))
+ return to_assign(new_add(unary(rest, tok->next), new_num(1, tok), tok));
+
+ // Read --i as i-=1
+ if (equal(tok, "--"))
+ return to_assign(new_sub(unary(rest, tok->next), new_num(1, tok), tok));
+
+ // [GNU] labels-as-values
+ if (equal(tok, "&&")) {
+ Node *node = new_node(ND_LABEL_VAL, tok);
+ node->label = get_ident(tok->next);
+ node->goto_next = gotos;
+ gotos = node;
+ *rest = tok->next->next;
+ return node;
+ }
+
+ return postfix(rest, tok);
+}
+
+// struct-members = (declspec declarator ("," declarator)* ";")*
+static void struct_members(Token **rest, Token *tok, Type *ty) {
+ Member head = {};
+ Member *cur = &head;
+ int idx = 0;
+
+ while (!equal(tok, "}")) {
+ VarAttr attr = {};
+ Type *basety = declspec(&tok, tok, &attr);
+ bool first = true;
+
+ // Anonymous struct member
+ if ((basety->kind == TY_STRUCT || basety->kind == TY_UNION) &&
+ consume(&tok, tok, ";")) {
+ Member *mem = calloc(1, sizeof(Member));
+ mem->ty = basety;
+ mem->idx = idx++;
+ mem->align = attr.align ? attr.align : mem->ty->align;
+ cur = cur->next = mem;
+ continue;
+ }
+
+ // Regular struct members
+ while (!consume(&tok, tok, ";")) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ Member *mem = calloc(1, sizeof(Member));
+ mem->ty = declarator(&tok, tok, basety);
+ mem->name = mem->ty->name;
+ mem->idx = idx++;
+ mem->align = attr.align ? attr.align : mem->ty->align;
+
+ if (consume(&tok, tok, ":")) {
+ mem->is_bitfield = true;
+ mem->bit_width = const_expr(&tok, tok);
+ }
+
+ cur = cur->next = mem;
+ }
+ }
+
+ // If the last element is an array of incomplete type, it's
+ // called a "flexible array member". It should behave as if
+ // if were a zero-sized array.
+ if (cur != &head && cur->ty->kind == TY_ARRAY && cur->ty->array_len < 0) {
+ cur->ty = array_of(cur->ty->base, 0);
+ ty->is_flexible = true;
+ }
+
+ *rest = tok->next;
+ ty->members = head.next;
+}
+
+// attribute = ("__attribute__" "(" "(" "packed" ")" ")")*
+static Token *attribute_list(Token *tok, Type *ty) {
+ while (consume(&tok, tok, "__attribute__")) {
+ tok = skip(tok, "(");
+ tok = skip(tok, "(");
+
+ bool first = true;
+
+ while (!consume(&tok, tok, ")")) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ if (consume(&tok, tok, "packed")) {
+ ty->is_packed = true;
+ continue;
+ }
+
+ if (consume(&tok, tok, "aligned")) {
+ tok = skip(tok, "(");
+ ty->align = const_expr(&tok, tok);
+ tok = skip(tok, ")");
+ continue;
+ }
+
+ error_tok(tok, "unknown attribute");
+ }
+
+ tok = skip(tok, ")");
+ }
+
+ return tok;
+}
+
+// struct-union-decl = attribute? ident? ("{" struct-members)?
+static Type *struct_union_decl(Token **rest, Token *tok) {
+ Type *ty = struct_type();
+ tok = attribute_list(tok, ty);
+
+ // Read a tag.
+ Token *tag = NULL;
+ if (tok->kind == TK_IDENT) {
+ tag = tok;
+ tok = tok->next;
+ }
+
+ if (tag && !equal(tok, "{")) {
+ *rest = tok;
+
+ Type *ty2 = find_tag(tag);
+ if (ty2)
+ return ty2;
+
+ ty->size = -1;
+ push_tag_scope(tag, ty);
+ return ty;
+ }
+
+ tok = skip(tok, "{");
+
+ // Construct a struct object.
+ struct_members(&tok, tok, ty);
+ *rest = attribute_list(tok, ty);
+
+ if (tag) {
+ // If this is a redefinition, overwrite a previous type.
+ // Otherwise, register the struct type.
+ Type *ty2 = hashmap_get2(&scope->tags, tag->loc, tag->len);
+ if (ty2) {
+ *ty2 = *ty;
+ return ty2;
+ }
+
+ push_tag_scope(tag, ty);
+ }
+
+ return ty;
+}
+
+// struct-decl = struct-union-decl
+static Type *struct_decl(Token **rest, Token *tok) {
+ Type *ty = struct_union_decl(rest, tok);
+ ty->kind = TY_STRUCT;
+
+ if (ty->size < 0)
+ return ty;
+
+ // Assign offsets within the struct to members.
+ int bits = 0;
+
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ if (mem->is_bitfield && mem->bit_width == 0) {
+ // Zero-width anonymous bitfield has a special meaning.
+ // It affects only alignment.
+ bits = align_to(bits, mem->ty->size * 8);
+ } else if (mem->is_bitfield) {
+ int sz = mem->ty->size;
+ if (bits / (sz * 8) != (bits + mem->bit_width - 1) / (sz * 8))
+ bits = align_to(bits, sz * 8);
+
+ mem->offset = align_down(bits / 8, sz);
+ mem->bit_offset = bits % (sz * 8);
+ bits += mem->bit_width;
+ } else {
+ if (!ty->is_packed)
+ bits = align_to(bits, mem->align * 8);
+ mem->offset = bits / 8;
+ bits += mem->ty->size * 8;
+ }
+
+ if (!ty->is_packed && ty->align < mem->align)
+ ty->align = mem->align;
+ }
+
+ ty->size = align_to(bits, ty->align * 8) / 8;
+ return ty;
+}
+
+// union-decl = struct-union-decl
+static Type *union_decl(Token **rest, Token *tok) {
+ Type *ty = struct_union_decl(rest, tok);
+ ty->kind = TY_UNION;
+
+ if (ty->size < 0)
+ return ty;
+
+ // If union, we don't have to assign offsets because they
+ // are already initialized to zero. We need to compute the
+ // alignment and the size though.
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ if (ty->align < mem->align)
+ ty->align = mem->align;
+ if (ty->size < mem->ty->size)
+ ty->size = mem->ty->size;
+ }
+ ty->size = align_to(ty->size, ty->align);
+ return ty;
+}
+
+// Find a struct member by name.
+static Member *get_struct_member(Type *ty, Token *tok) {
+ for (Member *mem = ty->members; mem; mem = mem->next) {
+ // Anonymous struct member
+ if ((mem->ty->kind == TY_STRUCT || mem->ty->kind == TY_UNION) &&
+ !mem->name) {
+ if (get_struct_member(mem->ty, tok))
+ return mem;
+ continue;
+ }
+
+ // Regular struct member
+ if (mem->name->len == tok->len &&
+ !strncmp(mem->name->loc, tok->loc, tok->len))
+ return mem;
+ }
+ return NULL;
+}
+
+// Create a node representing a struct member access, such as foo.bar
+// where foo is a struct and bar is a member name.
+//
+// C has a feature called "anonymous struct" which allows a struct to
+// have another unnamed struct as a member like this:
+//
+// struct { struct { int a; }; int b; } x;
+//
+// The members of an anonymous struct belong to the outer struct's
+// member namespace. Therefore, in the above example, you can access
+// member "a" of the anonymous struct as "x.a".
+//
+// This function takes care of anonymous structs.
+static Node *struct_ref(Node *node, Token *tok) {
+ add_type(node);
+ if (node->ty->kind != TY_STRUCT && node->ty->kind != TY_UNION)
+ error_tok(node->tok, "not a struct nor a union");
+
+ Type *ty = node->ty;
+
+ for (;;) {
+ Member *mem = get_struct_member(ty, tok);
+ if (!mem)
+ error_tok(tok, "no such member");
+ node = new_unary(ND_MEMBER, node, tok);
+ node->member = mem;
+ if (mem->name)
+ break;
+ ty = mem->ty;
+ }
+ return node;
+}
+
+// Convert A++ to `(typeof A)((A += 1) - 1)`
+static Node *new_inc_dec(Node *node, Token *tok, int addend) {
+ add_type(node);
+ return new_cast(new_add(to_assign(new_add(node, new_num(addend, tok), tok)),
+ new_num(-addend, tok), tok),
+ node->ty);
+}
+
+// postfix = "(" type-name ")" "{" initializer-list "}"
+// = ident "(" func-args ")" postfix-tail*
+// | primary postfix-tail*
+//
+// postfix-tail = "[" expr "]"
+// | "(" func-args ")"
+// | "." ident
+// | "->" ident
+// | "++"
+// | "--"
+static Node *postfix(Token **rest, Token *tok) {
+ if (equal(tok, "(") && is_typename(tok->next)) {
+ // Compound literal
+ Token *start = tok;
+ Type *ty = typename(&tok, tok->next);
+ tok = skip(tok, ")");
+
+ if (scope->next == NULL) {
+ Obj *var = new_anon_gvar(ty);
+ gvar_initializer(rest, tok, var);
+ return new_var_node(var, start);
+ }
+
+ Obj *var = new_lvar("", ty);
+ Node *lhs = lvar_initializer(rest, tok, var);
+ Node *rhs = new_var_node(var, tok);
+ return new_binary(ND_COMMA, lhs, rhs, start);
+ }
+
+ Node *node = primary(&tok, tok);
+
+ for (;;) {
+ if (equal(tok, "(")) {
+ node = funcall(&tok, tok->next, node);
+ continue;
+ }
+
+ if (equal(tok, "[")) {
+ // x[y] is short for *(x+y)
+ Token *start = tok;
+ Node *idx = expr(&tok, tok->next);
+ tok = skip(tok, "]");
+ node = new_unary(ND_DEREF, new_add(node, idx, start), start);
+ continue;
+ }
+
+ if (equal(tok, ".")) {
+ node = struct_ref(node, tok->next);
+ tok = tok->next->next;
+ continue;
+ }
+
+ if (equal(tok, "->")) {
+ // x->y is short for (*x).y
+ node = new_unary(ND_DEREF, node, tok);
+ node = struct_ref(node, tok->next);
+ tok = tok->next->next;
+ continue;
+ }
+
+ if (equal(tok, "++")) {
+ node = new_inc_dec(node, tok, 1);
+ tok = tok->next;
+ continue;
+ }
+
+ if (equal(tok, "--")) {
+ node = new_inc_dec(node, tok, -1);
+ tok = tok->next;
+ continue;
+ }
+
+ *rest = tok;
+ return node;
+ }
+}
+
+// funcall = (assign ("," assign)*)? ")"
+static Node *funcall(Token **rest, Token *tok, Node *fn) {
+ add_type(fn);
+
+ if (fn->ty->kind != TY_FUNC &&
+ (fn->ty->kind != TY_PTR || fn->ty->base->kind != TY_FUNC))
+ error_tok(fn->tok, "not a function");
+
+ Type *ty = (fn->ty->kind == TY_FUNC) ? fn->ty : fn->ty->base;
+ Type *param_ty = ty->params;
+
+ Node head = {};
+ Node *cur = &head;
+
+ while (!equal(tok, ")")) {
+ if (cur != &head)
+ tok = skip(tok, ",");
+
+ Node *arg = assign(&tok, tok);
+ add_type(arg);
+
+ if (!param_ty && !ty->is_variadic)
+ error_tok(tok, "too many arguments");
+
+ if (param_ty) {
+ if (param_ty->kind != TY_STRUCT && param_ty->kind != TY_UNION)
+ arg = new_cast(arg, param_ty);
+ param_ty = param_ty->next;
+ } else if (arg->ty->kind == TY_FLOAT) {
+ // If parameter type is omitted (e.g. in "..."), float
+ // arguments are promoted to double.
+ arg = new_cast(arg, ty_double);
+ }
+
+ cur = cur->next = arg;
+ }
+
+ if (param_ty)
+ error_tok(tok, "too few arguments");
+
+ *rest = skip(tok, ")");
+
+ Node *node = new_unary(ND_FUNCALL, fn, tok);
+ node->func_ty = ty;
+ node->ty = ty->return_ty;
+ node->args = head.next;
+
+ // If a function returns a struct, it is caller's responsibility
+ // to allocate a space for the return value.
+ if (node->ty->kind == TY_STRUCT || node->ty->kind == TY_UNION)
+ node->ret_buffer = new_lvar("", node->ty);
+ return node;
+}
+
+// generic-selection = "(" assign "," generic-assoc ("," generic-assoc)* ")"
+//
+// generic-assoc = type-name ":" assign
+// | "default" ":" assign
+static Node *generic_selection(Token **rest, Token *tok) {
+ Token *start = tok;
+ tok = skip(tok, "(");
+
+ Node *ctrl = assign(&tok, tok);
+ add_type(ctrl);
+
+ Type *t1 = ctrl->ty;
+ if (t1->kind == TY_FUNC)
+ t1 = pointer_to(t1);
+ else if (t1->kind == TY_ARRAY)
+ t1 = pointer_to(t1->base);
+
+ Node *ret = NULL;
+
+ while (!consume(rest, tok, ")")) {
+ tok = skip(tok, ",");
+
+ if (equal(tok, "default")) {
+ tok = skip(tok->next, ":");
+ Node *node = assign(&tok, tok);
+ if (!ret)
+ ret = node;
+ continue;
+ }
+
+ Type *t2 = typename(&tok, tok);
+ tok = skip(tok, ":");
+ Node *node = assign(&tok, tok);
+ if (is_compatible(t1, t2))
+ ret = node;
+ }
+
+ if (!ret)
+ error_tok(start, "controlling expression type not compatible with"
+ " any generic association type");
+ return ret;
+}
+
+// primary = "(" "{" stmt+ "}" ")"
+// | "(" expr ")"
+// | "sizeof" "(" type-name ")"
+// | "sizeof" unary
+// | "_Alignof" "(" type-name ")"
+// | "_Alignof" unary
+// | "_Generic" generic-selection
+// | "__builtin_types_compatible_p" "(" type-name, type-name, ")"
+// | "__builtin_reg_class" "(" type-name ")"
+// | ident
+// | str
+// | num
+static Node *primary(Token **rest, Token *tok) {
+ Token *start = tok;
+
+ if (equal(tok, "(") && equal(tok->next, "{")) {
+ // This is a GNU statement expresssion.
+ Node *node = new_node(ND_STMT_EXPR, tok);
+ node->body = compound_stmt(&tok, tok->next->next)->body;
+ *rest = skip(tok, ")");
+ return node;
+ }
+
+ if (equal(tok, "(")) {
+ Node *node = expr(&tok, tok->next);
+ *rest = skip(tok, ")");
+ return node;
+ }
+
+ if (equal(tok, "sizeof") && equal(tok->next, "(") && is_typename(tok->next->next)) {
+ Type *ty = typename(&tok, tok->next->next);
+ *rest = skip(tok, ")");
+
+ if (ty->kind == TY_VLA) {
+ if (ty->vla_size)
+ return new_var_node(ty->vla_size, tok);
+
+ Node *lhs = compute_vla_size(ty, tok);
+ Node *rhs = new_var_node(ty->vla_size, tok);
+ return new_binary(ND_COMMA, lhs, rhs, tok);
+ }
+
+ return new_ulong(ty->size, start);
+ }
+
+ if (equal(tok, "sizeof")) {
+ Node *node = unary(rest, tok->next);
+ add_type(node);
+ if (node->ty->kind == TY_VLA)
+ return new_var_node(node->ty->vla_size, tok);
+ return new_ulong(node->ty->size, tok);
+ }
+
+ if (equal(tok, "_Alignof") && equal(tok->next, "(") && is_typename(tok->next->next)) {
+ Type *ty = typename(&tok, tok->next->next);
+ *rest = skip(tok, ")");
+ return new_ulong(ty->align, tok);
+ }
+
+ if (equal(tok, "_Alignof")) {
+ Node *node = unary(rest, tok->next);
+ add_type(node);
+ return new_ulong(node->ty->align, tok);
+ }
+
+ if (equal(tok, "_Generic"))
+ return generic_selection(rest, tok->next);
+
+ if (equal(tok, "__builtin_types_compatible_p")) {
+ tok = skip(tok->next, "(");
+ Type *t1 = typename(&tok, tok);
+ tok = skip(tok, ",");
+ Type *t2 = typename(&tok, tok);
+ *rest = skip(tok, ")");
+ return new_num(is_compatible(t1, t2), start);
+ }
+
+ if (equal(tok, "__builtin_reg_class")) {
+ tok = skip(tok->next, "(");
+ Type *ty = typename(&tok, tok);
+ *rest = skip(tok, ")");
+
+ if (is_integer(ty) || ty->kind == TY_PTR)
+ return new_num(0, start);
+ if (is_flonum(ty))
+ return new_num(1, start);
+ return new_num(2, start);
+ }
+
+ if (equal(tok, "__builtin_compare_and_swap")) {
+ Node *node = new_node(ND_CAS, tok);
+ tok = skip(tok->next, "(");
+ node->cas_addr = assign(&tok, tok);
+ tok = skip(tok, ",");
+ node->cas_old = assign(&tok, tok);
+ tok = skip(tok, ",");
+ node->cas_new = assign(&tok, tok);
+ *rest = skip(tok, ")");
+ return node;
+ }
+
+ if (equal(tok, "__builtin_atomic_exchange")) {
+ Node *node = new_node(ND_EXCH, tok);
+ tok = skip(tok->next, "(");
+ node->lhs = assign(&tok, tok);
+ tok = skip(tok, ",");
+ node->rhs = assign(&tok, tok);
+ *rest = skip(tok, ")");
+ return node;
+ }
+
+ if (tok->kind == TK_IDENT) {
+ // Variable or enum constant
+ VarScope *sc = find_var(tok);
+ *rest = tok->next;
+
+ // For "static inline" function
+ if (sc && sc->var && sc->var->is_function) {
+ if (current_fn)
+ strarray_push(&current_fn->refs, sc->var->name);
+ else
+ sc->var->is_root = true;
+ }
+
+ if (sc) {
+ if (sc->var)
+ return new_var_node(sc->var, tok);
+ if (sc->enum_ty)
+ return new_num(sc->enum_val, tok);
+ }
+
+ if (equal(tok->next, "("))
+ error_tok(tok, "implicit declaration of a function");
+ error_tok(tok, "undefined variable");
+ }
+
+ if (tok->kind == TK_STR) {
+ Obj *var = new_string_literal(tok->str, tok->ty);
+ *rest = tok->next;
+ return new_var_node(var, tok);
+ }
+
+ if (tok->kind == TK_NUM) {
+ Node *node;
+ if (is_flonum(tok->ty)) {
+ node = new_node(ND_NUM, tok);
+ node->fval = tok->fval;
+ } else {
+ node = new_num(tok->val, tok);
+ }
+
+ node->ty = tok->ty;
+ *rest = tok->next;
+ return node;
+ }
+
+ error_tok(tok, "expected an expression");
+}
+
+static Token *parse_typedef(Token *tok, Type *basety) {
+ bool first = true;
+
+ while (!consume(&tok, tok, ";")) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ Type *ty = declarator(&tok, tok, basety);
+ if (!ty->name)
+ error_tok(ty->name_pos, "typedef name omitted");
+ push_scope(get_ident(ty->name))->type_def = ty;
+ }
+ return tok;
+}
+
+static void create_param_lvars(Type *param) {
+ if (param) {
+ create_param_lvars(param->next);
+ if (!param->name)
+ error_tok(param->name_pos, "parameter name omitted");
+ new_lvar(get_ident(param->name), param);
+ }
+}
+
+// This function matches gotos or labels-as-values with labels.
+//
+// We cannot resolve gotos as we parse a function because gotos
+// can refer a label that appears later in the function.
+// So, we need to do this after we parse the entire function.
+static void resolve_goto_labels(void) {
+ for (Node *x = gotos; x; x = x->goto_next) {
+ for (Node *y = labels; y; y = y->goto_next) {
+ if (!strcmp(x->label, y->label)) {
+ x->unique_label = y->unique_label;
+ break;
+ }
+ }
+
+ if (x->unique_label == NULL)
+ error_tok(x->tok->next, "use of undeclared label");
+ }
+
+ gotos = labels = NULL;
+}
+
+static Obj *find_func(char *name) {
+ Scope *sc = scope;
+ while (sc->next)
+ sc = sc->next;
+
+ VarScope *sc2 = hashmap_get(&sc->vars, name);
+ if (sc2 && sc2->var && sc2->var->is_function)
+ return sc2->var;
+ return NULL;
+}
+
+static void mark_live(Obj *var) {
+ if (!var->is_function || var->is_live)
+ return;
+ var->is_live = true;
+
+ for (int i = 0; i < var->refs.len; i++) {
+ Obj *fn = find_func(var->refs.data[i]);
+ if (fn)
+ mark_live(fn);
+ }
+}
+
+static Token *function(Token *tok, Type *basety, VarAttr *attr) {
+ Type *ty = declarator(&tok, tok, basety);
+ if (!ty->name)
+ error_tok(ty->name_pos, "function name omitted");
+ char *name_str = get_ident(ty->name);
+
+ Obj *fn = find_func(name_str);
+ if (fn) {
+ // Redeclaration
+ if (!fn->is_function)
+ error_tok(tok, "redeclared as a different kind of symbol");
+ if (fn->is_definition && equal(tok, "{"))
+ error_tok(tok, "redefinition of %s", name_str);
+ if (!fn->is_static && attr->is_static)
+ error_tok(tok, "static declaration follows a non-static declaration");
+ fn->is_definition = fn->is_definition || equal(tok, "{");
+ } else {
+ fn = new_gvar(name_str, ty);
+ fn->is_function = true;
+ fn->is_definition = equal(tok, "{");
+ fn->is_static = attr->is_static || (attr->is_inline && !attr->is_extern);
+ fn->is_inline = attr->is_inline;
+ }
+
+ fn->is_root = !(fn->is_static && fn->is_inline);
+
+ if (consume(&tok, tok, ";"))
+ return tok;
+
+ current_fn = fn;
+ locals = NULL;
+ enter_scope();
+ create_param_lvars(ty->params);
+
+ // A buffer for a struct/union return value is passed
+ // as the hidden first parameter.
+ Type *rty = ty->return_ty;
+ if ((rty->kind == TY_STRUCT || rty->kind == TY_UNION) && rty->size > 16)
+ new_lvar("", pointer_to(rty));
+
+ fn->params = locals;
+
+ if (ty->is_variadic)
+ fn->va_area = new_lvar("__va_area__", array_of(ty_char, 136));
+ fn->alloca_bottom = new_lvar("__alloca_size__", pointer_to(ty_char));
+
+ tok = skip(tok, "{");
+
+ // [https://www.sigbus.info/n1570#6.4.2.2p1] "__func__" is
+ // automatically defined as a local variable containing the
+ // current function name.
+ push_scope("__func__")->var =
+ new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));
+
+ // [GNU] __FUNCTION__ is yet another name of __func__.
+ push_scope("__FUNCTION__")->var =
+ new_string_literal(fn->name, array_of(ty_char, strlen(fn->name) + 1));
+
+ fn->body = compound_stmt(&tok, tok);
+ fn->locals = locals;
+ leave_scope();
+ resolve_goto_labels();
+ return tok;
+}
+
+static Token *global_variable(Token *tok, Type *basety, VarAttr *attr) {
+ bool first = true;
+
+ while (!consume(&tok, tok, ";")) {
+ if (!first)
+ tok = skip(tok, ",");
+ first = false;
+
+ Type *ty = declarator(&tok, tok, basety);
+ if (!ty->name)
+ error_tok(ty->name_pos, "variable name omitted");
+
+ Obj *var = new_gvar(get_ident(ty->name), ty);
+ var->is_definition = !attr->is_extern;
+ var->is_static = attr->is_static;
+ var->is_tls = attr->is_tls;
+ if (attr->align)
+ var->align = attr->align;
+
+ if (equal(tok, "="))
+ gvar_initializer(&tok, tok->next, var);
+ else if (!attr->is_extern && !attr->is_tls)
+ var->is_tentative = true;
+ }
+ return tok;
+}
+
+// Lookahead tokens and returns true if a given token is a start
+// of a function definition or declaration.
+static bool is_function(Token *tok) {
+ if (equal(tok, ";"))
+ return false;
+
+ Type dummy = {};
+ Type *ty = declarator(&tok, tok, &dummy);
+ return ty->kind == TY_FUNC;
+}
+
+// Remove redundant tentative definitions.
+static void scan_globals(void) {
+ Obj head;
+ Obj *cur = &head;
+
+ for (Obj *var = globals; var; var = var->next) {
+ if (!var->is_tentative) {
+ cur = cur->next = var;
+ continue;
+ }
+
+ // Find another definition of the same identifier.
+ Obj *var2 = globals;
+ for (; var2; var2 = var2->next)
+ if (var != var2 && var2->is_definition && !strcmp(var->name, var2->name))
+ break;
+
+ // If there's another definition, the tentative definition
+ // is redundant
+ if (!var2)
+ cur = cur->next = var;
+ }
+
+ cur->next = NULL;
+ globals = head.next;
+}
+
+static void declare_builtin_functions(void) {
+ Type *ty = func_type(pointer_to(ty_void));
+ ty->params = copy_type(ty_int);
+ builtin_alloca = new_gvar("alloca", ty);
+ builtin_alloca->is_definition = false;
+}
+
+// program = (typedef | function-definition | global-variable)*
+Obj *parse(Token *tok) {
+ declare_builtin_functions();
+ globals = NULL;
+
+ while (tok->kind != TK_EOF) {
+ VarAttr attr = {};
+ Type *basety = declspec(&tok, tok, &attr);
+
+ // Typedef
+ if (attr.is_typedef) {
+ tok = parse_typedef(tok, basety);
+ continue;
+ }
+
+ // Function
+ if (is_function(tok)) {
+ tok = function(tok, basety, &attr);
+ continue;
+ }
+
+ // Global variable
+ tok = global_variable(tok, basety, &attr);
+ }
+
+ for (Obj *var = globals; var; var = var->next)
+ if (var->is_root)
+ mark_live(var);
+
+ // Remove redundant tentative definitions.
+ scan_globals();
+ return globals;
+}
diff --git a/src/3p/chibicc/preprocess.c b/src/3p/chibicc/preprocess.c
new file mode 100644
index 0000000..cd8d1d8
--- /dev/null
+++ b/src/3p/chibicc/preprocess.c
@@ -0,0 +1,1208 @@
+// This file implements the C preprocessor.
+//
+// The preprocessor takes a list of tokens as an input and returns a
+// new list of tokens as an output.
+//
+// The preprocessing language is designed in such a way that that's
+// guaranteed to stop even if there is a recursive macro.
+// Informally speaking, a macro is applied only once for each token.
+// That is, if a macro token T appears in a result of direct or
+// indirect macro expansion of T, T won't be expanded any further.
+// For example, if T is defined as U, and U is defined as T, then
+// token T is expanded to U and then to T and the macro expansion
+// stops at that point.
+//
+// To achieve the above behavior, we attach for each token a set of
+// macro names from which the token is expanded. The set is called
+// "hideset". Hideset is initially empty, and every time we expand a
+// macro, the macro name is added to the resulting tokens' hidesets.
+//
+// The above macro expansion algorithm is explained in this document
+// written by Dave Prossor, which is used as a basis for the
+// standard's wording:
+// https://github.com/rui314/chibicc/wiki/cpp.algo.pdf
+
+#include "chibicc.h"
+
+typedef struct MacroParam MacroParam;
+struct MacroParam {
+ MacroParam *next;
+ char *name;
+};
+
+typedef struct MacroArg MacroArg;
+struct MacroArg {
+ MacroArg *next;
+ char *name;
+ bool is_va_args;
+ Token *tok;
+};
+
+typedef Token *macro_handler_fn(Token *);
+
+typedef struct Macro Macro;
+struct Macro {
+ char *name;
+ bool is_objlike; // Object-like or function-like
+ MacroParam *params;
+ char *va_args_name;
+ Token *body;
+ macro_handler_fn *handler;
+};
+
+// `#if` can be nested, so we use a stack to manage nested `#if`s.
+typedef struct CondIncl CondIncl;
+struct CondIncl {
+ CondIncl *next;
+ enum { IN_THEN, IN_ELIF, IN_ELSE } ctx;
+ Token *tok;
+ bool included;
+};
+
+typedef struct Hideset Hideset;
+struct Hideset {
+ Hideset *next;
+ char *name;
+};
+
+static HashMap macros;
+static CondIncl *cond_incl;
+static HashMap pragma_once;
+static int include_next_idx;
+
+static Token *preprocess2(Token *tok);
+static Macro *find_macro(Token *tok);
+
+static bool is_hash(Token *tok) {
+ return tok->at_bol && equal(tok, "#");
+}
+
+// Some preprocessor directives such as #include allow extraneous
+// tokens before newline. This function skips such tokens.
+static Token *skip_line(Token *tok) {
+ if (tok->at_bol)
+ return tok;
+ warn_tok(tok, "extra token");
+ while (!tok->at_bol)
+ tok = tok->next;
+ return tok;
+}
+
+static Token *copy_token(Token *tok) {
+ Token *t = calloc(1, sizeof(Token));
+ *t = *tok;
+ t->next = NULL;
+ return t;
+}
+
+static Token *new_eof(Token *tok) {
+ Token *t = copy_token(tok);
+ t->kind = TK_EOF;
+ t->len = 0;
+ return t;
+}
+
+static Hideset *new_hideset(char *name) {
+ Hideset *hs = calloc(1, sizeof(Hideset));
+ hs->name = name;
+ return hs;
+}
+
+static Hideset *hideset_union(Hideset *hs1, Hideset *hs2) {
+ Hideset head = {};
+ Hideset *cur = &head;
+
+ for (; hs1; hs1 = hs1->next)
+ cur = cur->next = new_hideset(hs1->name);
+ cur->next = hs2;
+ return head.next;
+}
+
+static bool hideset_contains(Hideset *hs, char *s, int len) {
+ for (; hs; hs = hs->next)
+ if (strlen(hs->name) == len && !strncmp(hs->name, s, len))
+ return true;
+ return false;
+}
+
+static Hideset *hideset_intersection(Hideset *hs1, Hideset *hs2) {
+ Hideset head = {};
+ Hideset *cur = &head;
+
+ for (; hs1; hs1 = hs1->next)
+ if (hideset_contains(hs2, hs1->name, strlen(hs1->name)))
+ cur = cur->next = new_hideset(hs1->name);
+ return head.next;
+}
+
+static Token *add_hideset(Token *tok, Hideset *hs) {
+ Token head = {};
+ Token *cur = &head;
+
+ for (; tok; tok = tok->next) {
+ Token *t = copy_token(tok);
+ t->hideset = hideset_union(t->hideset, hs);
+ cur = cur->next = t;
+ }
+ return head.next;
+}
+
+// Append tok2 to the end of tok1.
+static Token *append(Token *tok1, Token *tok2) {
+ if (tok1->kind == TK_EOF)
+ return tok2;
+
+ Token head = {};
+ Token *cur = &head;
+
+ for (; tok1->kind != TK_EOF; tok1 = tok1->next)
+ cur = cur->next = copy_token(tok1);
+ cur->next = tok2;
+ return head.next;
+}
+
+static Token *skip_cond_incl2(Token *tok) {
+ while (tok->kind != TK_EOF) {
+ if (is_hash(tok) &&
+ (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
+ equal(tok->next, "ifndef"))) {
+ tok = skip_cond_incl2(tok->next->next);
+ continue;
+ }
+ if (is_hash(tok) && equal(tok->next, "endif"))
+ return tok->next->next;
+ tok = tok->next;
+ }
+ return tok;
+}
+
+// Skip until next `#else`, `#elif` or `#endif`.
+// Nested `#if` and `#endif` are skipped.
+static Token *skip_cond_incl(Token *tok) {
+ while (tok->kind != TK_EOF) {
+ if (is_hash(tok) &&
+ (equal(tok->next, "if") || equal(tok->next, "ifdef") ||
+ equal(tok->next, "ifndef"))) {
+ tok = skip_cond_incl2(tok->next->next);
+ continue;
+ }
+
+ if (is_hash(tok) &&
+ (equal(tok->next, "elif") || equal(tok->next, "else") ||
+ equal(tok->next, "endif")))
+ break;
+ tok = tok->next;
+ }
+ return tok;
+}
+
+// Double-quote a given string and returns it.
+static char *quote_string(char *str) {
+ int bufsize = 3;
+ for (int i = 0; str[i]; i++) {
+ if (str[i] == '\\' || str[i] == '"')
+ bufsize++;
+ bufsize++;
+ }
+
+ char *buf = calloc(1, bufsize);
+ char *p = buf;
+ *p++ = '"';
+ for (int i = 0; str[i]; i++) {
+ if (str[i] == '\\' || str[i] == '"')
+ *p++ = '\\';
+ *p++ = str[i];
+ }
+ *p++ = '"';
+ *p++ = '\0';
+ return buf;
+}
+
+static Token *new_str_token(char *str, Token *tmpl) {
+ char *buf = quote_string(str);
+ return tokenize(new_file(tmpl->file->name, tmpl->file->file_no, buf));
+}
+
+// Copy all tokens until the next newline, terminate them with
+// an EOF token and then returns them. This function is used to
+// create a new list of tokens for `#if` arguments.
+static Token *copy_line(Token **rest, Token *tok) {
+ Token head = {};
+ Token *cur = &head;
+
+ for (; !tok->at_bol; tok = tok->next)
+ cur = cur->next = copy_token(tok);
+
+ cur->next = new_eof(tok);
+ *rest = tok;
+ return head.next;
+}
+
+static Token *new_num_token(int val, Token *tmpl) {
+ char *buf = format("%d\n", val);
+ return tokenize(new_file(tmpl->file->name, tmpl->file->file_no, buf));
+}
+
+static Token *read_const_expr(Token **rest, Token *tok) {
+ tok = copy_line(rest, tok);
+
+ Token head = {};
+ Token *cur = &head;
+
+ while (tok->kind != TK_EOF) {
+ // "defined(foo)" or "defined foo" becomes "1" if macro "foo"
+ // is defined. Otherwise "0".
+ if (equal(tok, "defined")) {
+ Token *start = tok;
+ bool has_paren = consume(&tok, tok->next, "(");
+
+ if (tok->kind != TK_IDENT)
+ error_tok(start, "macro name must be an identifier");
+ Macro *m = find_macro(tok);
+ tok = tok->next;
+
+ if (has_paren)
+ tok = skip(tok, ")");
+
+ cur = cur->next = new_num_token(m ? 1 : 0, start);
+ continue;
+ }
+
+ cur = cur->next = tok;
+ tok = tok->next;
+ }
+
+ cur->next = tok;
+ return head.next;
+}
+
+// Read and evaluate a constant expression.
+static long eval_const_expr(Token **rest, Token *tok) {
+ Token *start = tok;
+ Token *expr = read_const_expr(rest, tok->next);
+ expr = preprocess2(expr);
+
+ if (expr->kind == TK_EOF)
+ error_tok(start, "no expression");
+
+ // [https://www.sigbus.info/n1570#6.10.1p4] The standard requires
+ // we replace remaining non-macro identifiers with "0" before
+ // evaluating a constant expression. For example, `#if foo` is
+ // equivalent to `#if 0` if foo is not defined.
+ for (Token *t = expr; t->kind != TK_EOF; t = t->next) {
+ if (t->kind == TK_IDENT) {
+ Token *next = t->next;
+ *t = *new_num_token(0, t);
+ t->next = next;
+ }
+ }
+
+ // Convert pp-numbers to regular numbers
+ convert_pp_tokens(expr);
+
+ Token *rest2;
+ long val = const_expr(&rest2, expr);
+ if (rest2->kind != TK_EOF)
+ error_tok(rest2, "extra token");
+ return val;
+}
+
+static CondIncl *push_cond_incl(Token *tok, bool included) {
+ CondIncl *ci = calloc(1, sizeof(CondIncl));
+ ci->next = cond_incl;
+ ci->ctx = IN_THEN;
+ ci->tok = tok;
+ ci->included = included;
+ cond_incl = ci;
+ return ci;
+}
+
+static Macro *find_macro(Token *tok) {
+ if (tok->kind != TK_IDENT)
+ return NULL;
+ return hashmap_get2(&macros, tok->loc, tok->len);
+}
+
+static Macro *add_macro(char *name, bool is_objlike, Token *body) {
+ Macro *m = calloc(1, sizeof(Macro));
+ m->name = name;
+ m->is_objlike = is_objlike;
+ m->body = body;
+ hashmap_put(&macros, name, m);
+ return m;
+}
+
+static MacroParam *read_macro_params(Token **rest, Token *tok, char **va_args_name) {
+ MacroParam head = {};
+ MacroParam *cur = &head;
+
+ while (!equal(tok, ")")) {
+ if (cur != &head)
+ tok = skip(tok, ",");
+
+ if (equal(tok, "...")) {
+ *va_args_name = "__VA_ARGS__";
+ *rest = skip(tok->next, ")");
+ return head.next;
+ }
+
+ if (tok->kind != TK_IDENT)
+ error_tok(tok, "expected an identifier");
+
+ if (equal(tok->next, "...")) {
+ *va_args_name = strndup(tok->loc, tok->len);
+ *rest = skip(tok->next->next, ")");
+ return head.next;
+ }
+
+ MacroParam *m = calloc(1, sizeof(MacroParam));
+ m->name = strndup(tok->loc, tok->len);
+ cur = cur->next = m;
+ tok = tok->next;
+ }
+
+ *rest = tok->next;
+ return head.next;
+}
+
+static void read_macro_definition(Token **rest, Token *tok) {
+ if (tok->kind != TK_IDENT)
+ error_tok(tok, "macro name must be an identifier");
+ char *name = strndup(tok->loc, tok->len);
+ tok = tok->next;
+
+ if (!tok->has_space && equal(tok, "(")) {
+ // Function-like macro
+ char *va_args_name = NULL;
+ MacroParam *params = read_macro_params(&tok, tok->next, &va_args_name);
+
+ Macro *m = add_macro(name, false, copy_line(rest, tok));
+ m->params = params;
+ m->va_args_name = va_args_name;
+ } else {
+ // Object-like macro
+ add_macro(name, true, copy_line(rest, tok));
+ }
+}
+
+static MacroArg *read_macro_arg_one(Token **rest, Token *tok, bool read_rest) {
+ Token head = {};
+ Token *cur = &head;
+ int level = 0;
+
+ for (;;) {
+ if (level == 0 && equal(tok, ")"))
+ break;
+ if (level == 0 && !read_rest && equal(tok, ","))
+ break;
+
+ if (tok->kind == TK_EOF)
+ error_tok(tok, "premature end of input");
+
+ if (equal(tok, "("))
+ level++;
+ else if (equal(tok, ")"))
+ level--;
+
+ cur = cur->next = copy_token(tok);
+ tok = tok->next;
+ }
+
+ cur->next = new_eof(tok);
+
+ MacroArg *arg = calloc(1, sizeof(MacroArg));
+ arg->tok = head.next;
+ *rest = tok;
+ return arg;
+}
+
+static MacroArg *
+read_macro_args(Token **rest, Token *tok, MacroParam *params, char *va_args_name) {
+ Token *start = tok;
+ tok = tok->next->next;
+
+ MacroArg head = {};
+ MacroArg *cur = &head;
+
+ MacroParam *pp = params;
+ for (; pp; pp = pp->next) {
+ if (cur != &head)
+ tok = skip(tok, ",");
+ cur = cur->next = read_macro_arg_one(&tok, tok, false);
+ cur->name = pp->name;
+ }
+
+ if (va_args_name) {
+ MacroArg *arg;
+ if (equal(tok, ")")) {
+ arg = calloc(1, sizeof(MacroArg));
+ arg->tok = new_eof(tok);
+ } else {
+ if (pp != params)
+ tok = skip(tok, ",");
+ arg = read_macro_arg_one(&tok, tok, true);
+ }
+ arg->name = va_args_name;;
+ arg->is_va_args = true;
+ cur = cur->next = arg;
+ } else if (pp) {
+ error_tok(start, "too many arguments");
+ }
+
+ skip(tok, ")");
+ *rest = tok;
+ return head.next;
+}
+
+static MacroArg *find_arg(MacroArg *args, Token *tok) {
+ for (MacroArg *ap = args; ap; ap = ap->next)
+ if (tok->len == strlen(ap->name) && !strncmp(tok->loc, ap->name, tok->len))
+ return ap;
+ return NULL;
+}
+
+// Concatenates all tokens in `tok` and returns a new string.
+static char *join_tokens(Token *tok, Token *end) {
+ // Compute the length of the resulting token.
+ int len = 1;
+ for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ if (t != tok && t->has_space)
+ len++;
+ len += t->len;
+ }
+
+ char *buf = calloc(1, len);
+
+ // Copy token texts.
+ int pos = 0;
+ for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ if (t != tok && t->has_space)
+ buf[pos++] = ' ';
+ strncpy(buf + pos, t->loc, t->len);
+ pos += t->len;
+ }
+ buf[pos] = '\0';
+ return buf;
+}
+
+// Concatenates all tokens in `arg` and returns a new string token.
+// This function is used for the stringizing operator (#).
+static Token *stringize(Token *hash, Token *arg) {
+ // Create a new string token. We need to set some value to its
+ // source location for error reporting function, so we use a macro
+ // name token as a template.
+ char *s = join_tokens(arg, NULL);
+ return new_str_token(s, hash);
+}
+
+// Concatenate two tokens to create a new token.
+static Token *paste(Token *lhs, Token *rhs) {
+ // Paste the two tokens.
+ char *buf = format("%.*s%.*s", lhs->len, lhs->loc, rhs->len, rhs->loc);
+
+ // Tokenize the resulting string.
+ Token *tok = tokenize(new_file(lhs->file->name, lhs->file->file_no, buf));
+ if (tok->next->kind != TK_EOF)
+ error_tok(lhs, "pasting forms '%s', an invalid token", buf);
+ return tok;
+}
+
+static bool has_varargs(MacroArg *args) {
+ for (MacroArg *ap = args; ap; ap = ap->next)
+ if (!strcmp(ap->name, "__VA_ARGS__"))
+ return ap->tok->kind != TK_EOF;
+ return false;
+}
+
+// Replace func-like macro parameters with given arguments.
+static Token *subst(Token *tok, MacroArg *args) {
+ Token head = {};
+ Token *cur = &head;
+
+ while (tok->kind != TK_EOF) {
+ // "#" followed by a parameter is replaced with stringized actuals.
+ if (equal(tok, "#")) {
+ MacroArg *arg = find_arg(args, tok->next);
+ if (!arg)
+ error_tok(tok->next, "'#' is not followed by a macro parameter");
+ cur = cur->next = stringize(tok, arg->tok);
+ tok = tok->next->next;
+ continue;
+ }
+
+ // [GNU] If __VA_ARG__ is empty, `,##__VA_ARGS__` is expanded
+ // to the empty token list. Otherwise, its expaned to `,` and
+ // __VA_ARGS__.
+ if (equal(tok, ",") && equal(tok->next, "##")) {
+ MacroArg *arg = find_arg(args, tok->next->next);
+ if (arg && arg->is_va_args) {
+ if (arg->tok->kind == TK_EOF) {
+ tok = tok->next->next->next;
+ } else {
+ cur = cur->next = copy_token(tok);
+ tok = tok->next->next;
+ }
+ continue;
+ }
+ }
+
+ if (equal(tok, "##")) {
+ if (cur == &head)
+ error_tok(tok, "'##' cannot appear at start of macro expansion");
+
+ if (tok->next->kind == TK_EOF)
+ error_tok(tok, "'##' cannot appear at end of macro expansion");
+
+ MacroArg *arg = find_arg(args, tok->next);
+ if (arg) {
+ if (arg->tok->kind != TK_EOF) {
+ *cur = *paste(cur, arg->tok);
+ for (Token *t = arg->tok->next; t->kind != TK_EOF; t = t->next)
+ cur = cur->next = copy_token(t);
+ }
+ tok = tok->next->next;
+ continue;
+ }
+
+ *cur = *paste(cur, tok->next);
+ tok = tok->next->next;
+ continue;
+ }
+
+ MacroArg *arg = find_arg(args, tok);
+
+ if (arg && equal(tok->next, "##")) {
+ Token *rhs = tok->next->next;
+
+ if (arg->tok->kind == TK_EOF) {
+ MacroArg *arg2 = find_arg(args, rhs);
+ if (arg2) {
+ for (Token *t = arg2->tok; t->kind != TK_EOF; t = t->next)
+ cur = cur->next = copy_token(t);
+ } else {
+ cur = cur->next = copy_token(rhs);
+ }
+ tok = rhs->next;
+ continue;
+ }
+
+ for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
+ cur = cur->next = copy_token(t);
+ tok = tok->next;
+ continue;
+ }
+
+ // If __VA_ARG__ is empty, __VA_OPT__(x) is expanded to the
+ // empty token list. Otherwise, __VA_OPT__(x) is expanded to x.
+ if (equal(tok, "__VA_OPT__") && equal(tok->next, "(")) {
+ MacroArg *arg = read_macro_arg_one(&tok, tok->next->next, true);
+ if (has_varargs(args))
+ for (Token *t = arg->tok; t->kind != TK_EOF; t = t->next)
+ cur = cur->next = t;
+ tok = skip(tok, ")");
+ continue;
+ }
+
+ // Handle a macro token. Macro arguments are completely macro-expanded
+ // before they are substituted into a macro body.
+ if (arg) {
+ Token *t = preprocess2(arg->tok);
+ t->at_bol = tok->at_bol;
+ t->has_space = tok->has_space;
+ for (; t->kind != TK_EOF; t = t->next)
+ cur = cur->next = copy_token(t);
+ tok = tok->next;
+ continue;
+ }
+
+ // Handle a non-macro token.
+ cur = cur->next = copy_token(tok);
+ tok = tok->next;
+ continue;
+ }
+
+ cur->next = tok;
+ return head.next;
+}
+
+// If tok is a macro, expand it and return true.
+// Otherwise, do nothing and return false.
+static bool expand_macro(Token **rest, Token *tok) {
+ if (hideset_contains(tok->hideset, tok->loc, tok->len))
+ return false;
+
+ Macro *m = find_macro(tok);
+ if (!m)
+ return false;
+
+ // Built-in dynamic macro application such as __LINE__
+ if (m->handler) {
+ *rest = m->handler(tok);
+ (*rest)->next = tok->next;
+ return true;
+ }
+
+ // Object-like macro application
+ if (m->is_objlike) {
+ Hideset *hs = hideset_union(tok->hideset, new_hideset(m->name));
+ Token *body = add_hideset(m->body, hs);
+ for (Token *t = body; t->kind != TK_EOF; t = t->next)
+ t->origin = tok;
+ *rest = append(body, tok->next);
+ (*rest)->at_bol = tok->at_bol;
+ (*rest)->has_space = tok->has_space;
+ return true;
+ }
+
+ // If a funclike macro token is not followed by an argument list,
+ // treat it as a normal identifier.
+ if (!equal(tok->next, "("))
+ return false;
+
+ // Function-like macro application
+ Token *macro_token = tok;
+ MacroArg *args = read_macro_args(&tok, tok, m->params, m->va_args_name);
+ Token *rparen = tok;
+
+ // Tokens that consist a func-like macro invocation may have different
+ // hidesets, and if that's the case, it's not clear what the hideset
+ // for the new tokens should be. We take the interesection of the
+ // macro token and the closing parenthesis and use it as a new hideset
+ // as explained in the Dave Prossor's algorithm.
+ Hideset *hs = hideset_intersection(macro_token->hideset, rparen->hideset);
+ hs = hideset_union(hs, new_hideset(m->name));
+
+ Token *body = subst(m->body, args);
+ body = add_hideset(body, hs);
+ for (Token *t = body; t->kind != TK_EOF; t = t->next)
+ t->origin = macro_token;
+ *rest = append(body, tok->next);
+ (*rest)->at_bol = macro_token->at_bol;
+ (*rest)->has_space = macro_token->has_space;
+ return true;
+}
+
+char *search_include_paths(char *filename) {
+ if (filename[0] == '/')
+ return filename;
+
+ static HashMap cache;
+ char *cached = hashmap_get(&cache, filename);
+ if (cached)
+ return cached;
+
+ // Search a file from the include paths.
+ for (int i = 0; i < include_paths.len; i++) {
+ char *path = format("%s/%s", include_paths.data[i], filename);
+ if (!file_exists(path))
+ continue;
+ hashmap_put(&cache, filename, path);
+ include_next_idx = i + 1;
+ return path;
+ }
+ return NULL;
+}
+
+static char *search_include_next(char *filename) {
+ for (; include_next_idx < include_paths.len; include_next_idx++) {
+ char *path = format("%s/%s", include_paths.data[include_next_idx], filename);
+ if (file_exists(path))
+ return path;
+ }
+ return NULL;
+}
+
+// Read an #include argument.
+static char *read_include_filename(Token **rest, Token *tok, bool *is_dquote) {
+ // Pattern 1: #include "foo.h"
+ if (tok->kind == TK_STR) {
+ // A double-quoted filename for #include is a special kind of
+ // token, and we don't want to interpret any escape sequences in it.
+ // For example, "\f" in "C:\foo" is not a formfeed character but
+ // just two non-control characters, backslash and f.
+ // So we don't want to use token->str.
+ *is_dquote = true;
+ *rest = skip_line(tok->next);
+ return strndup(tok->loc + 1, tok->len - 2);
+ }
+
+ // Pattern 2: #include <foo.h>
+ if (equal(tok, "<")) {
+ // Reconstruct a filename from a sequence of tokens between
+ // "<" and ">".
+ Token *start = tok;
+
+ // Find closing ">".
+ for (; !equal(tok, ">"); tok = tok->next)
+ if (tok->at_bol || tok->kind == TK_EOF)
+ error_tok(tok, "expected '>'");
+
+ *is_dquote = false;
+ *rest = skip_line(tok->next);
+ return join_tokens(start->next, tok);
+ }
+
+ // Pattern 3: #include FOO
+ // In this case FOO must be macro-expanded to either
+ // a single string token or a sequence of "<" ... ">".
+ if (tok->kind == TK_IDENT) {
+ Token *tok2 = preprocess2(copy_line(rest, tok));
+ return read_include_filename(&tok2, tok2, is_dquote);
+ }
+
+ error_tok(tok, "expected a filename");
+}
+
+// Detect the following "include guard" pattern.
+//
+// #ifndef FOO_H
+// #define FOO_H
+// ...
+// #endif
+static char *detect_include_guard(Token *tok) {
+ // Detect the first two lines.
+ if (!is_hash(tok) || !equal(tok->next, "ifndef"))
+ return NULL;
+ tok = tok->next->next;
+
+ if (tok->kind != TK_IDENT)
+ return NULL;
+
+ char *macro = strndup(tok->loc, tok->len);
+ tok = tok->next;
+
+ if (!is_hash(tok) || !equal(tok->next, "define") || !equal(tok->next->next, macro))
+ return NULL;
+
+ // Read until the end of the file.
+ while (tok->kind != TK_EOF) {
+ if (!is_hash(tok)) {
+ tok = tok->next;
+ continue;
+ }
+
+ if (equal(tok->next, "endif") && tok->next->next->kind == TK_EOF)
+ return macro;
+
+ if (equal(tok, "if") || equal(tok, "ifdef") || equal(tok, "ifndef"))
+ tok = skip_cond_incl(tok->next);
+ else
+ tok = tok->next;
+ }
+ return NULL;
+}
+
+static Token *include_file(Token *tok, char *path, Token *filename_tok) {
+ // Check for "#pragma once"
+ if (hashmap_get(&pragma_once, path))
+ return tok;
+
+ // If we read the same file before, and if the file was guarded
+ // by the usual #ifndef ... #endif pattern, we may be able to
+ // skip the file without opening it.
+ static HashMap include_guards;
+ char *guard_name = hashmap_get(&include_guards, path);
+ if (guard_name && hashmap_get(&macros, guard_name))
+ return tok;
+
+ Token *tok2 = tokenize_file(path);
+ if (!tok2)
+ error_tok(filename_tok, "%s: cannot open file: %s", path, strerror(errno));
+
+ guard_name = detect_include_guard(tok2);
+ if (guard_name)
+ hashmap_put(&include_guards, path, guard_name);
+
+ return append(tok2, tok);
+}
+
+// Read #line arguments
+static void read_line_marker(Token **rest, Token *tok) {
+ Token *start = tok;
+ tok = preprocess(copy_line(rest, tok));
+
+ if (tok->kind != TK_NUM || tok->ty->kind != TY_INT)
+ error_tok(tok, "invalid line marker");
+ start->file->line_delta = tok->val - start->line_no;
+
+ tok = tok->next;
+ if (tok->kind == TK_EOF)
+ return;
+
+ if (tok->kind != TK_STR)
+ error_tok(tok, "filename expected");
+ start->file->display_name = tok->str;
+}
+
+// Visit all tokens in `tok` while evaluating preprocessing
+// macros and directives.
+static Token *preprocess2(Token *tok) {
+ Token head = {};
+ Token *cur = &head;
+
+ while (tok->kind != TK_EOF) {
+ // If it is a macro, expand it.
+ if (expand_macro(&tok, tok))
+ continue;
+
+ // Pass through if it is not a "#".
+ if (!is_hash(tok)) {
+ tok->line_delta = tok->file->line_delta;
+ tok->filename = tok->file->display_name;
+ cur = cur->next = tok;
+ tok = tok->next;
+ continue;
+ }
+
+ Token *start = tok;
+ tok = tok->next;
+
+ if (equal(tok, "include")) {
+ bool is_dquote;
+ char *filename = read_include_filename(&tok, tok->next, &is_dquote);
+
+ if (filename[0] != '/' && is_dquote) {
+ char *path = format("%s/%s", dirname(strdup(start->file->name)), filename);
+ if (file_exists(path)) {
+ tok = include_file(tok, path, start->next->next);
+ continue;
+ }
+ }
+
+ char *path = search_include_paths(filename);
+ tok = include_file(tok, path ? path : filename, start->next->next);
+ continue;
+ }
+
+ if (equal(tok, "include_next")) {
+ bool ignore;
+ char *filename = read_include_filename(&tok, tok->next, &ignore);
+ char *path = search_include_next(filename);
+ tok = include_file(tok, path ? path : filename, start->next->next);
+ continue;
+ }
+
+ if (equal(tok, "define")) {
+ read_macro_definition(&tok, tok->next);
+ continue;
+ }
+
+ if (equal(tok, "undef")) {
+ tok = tok->next;
+ if (tok->kind != TK_IDENT)
+ error_tok(tok, "macro name must be an identifier");
+ undef_macro(strndup(tok->loc, tok->len));
+ tok = skip_line(tok->next);
+ continue;
+ }
+
+ if (equal(tok, "if")) {
+ long val = eval_const_expr(&tok, tok);
+ push_cond_incl(start, val);
+ if (!val)
+ tok = skip_cond_incl(tok);
+ continue;
+ }
+
+ if (equal(tok, "ifdef")) {
+ bool defined = find_macro(tok->next);
+ push_cond_incl(tok, defined);
+ tok = skip_line(tok->next->next);
+ if (!defined)
+ tok = skip_cond_incl(tok);
+ continue;
+ }
+
+ if (equal(tok, "ifndef")) {
+ bool defined = find_macro(tok->next);
+ push_cond_incl(tok, !defined);
+ tok = skip_line(tok->next->next);
+ if (defined)
+ tok = skip_cond_incl(tok);
+ continue;
+ }
+
+ if (equal(tok, "elif")) {
+ if (!cond_incl || cond_incl->ctx == IN_ELSE)
+ error_tok(start, "stray #elif");
+ cond_incl->ctx = IN_ELIF;
+
+ if (!cond_incl->included && eval_const_expr(&tok, tok))
+ cond_incl->included = true;
+ else
+ tok = skip_cond_incl(tok);
+ continue;
+ }
+
+ if (equal(tok, "else")) {
+ if (!cond_incl || cond_incl->ctx == IN_ELSE)
+ error_tok(start, "stray #else");
+ cond_incl->ctx = IN_ELSE;
+ tok = skip_line(tok->next);
+
+ if (cond_incl->included)
+ tok = skip_cond_incl(tok);
+ continue;
+ }
+
+ if (equal(tok, "endif")) {
+ if (!cond_incl)
+ error_tok(start, "stray #endif");
+ cond_incl = cond_incl->next;
+ tok = skip_line(tok->next);
+ continue;
+ }
+
+ if (equal(tok, "line")) {
+ read_line_marker(&tok, tok->next);
+ continue;
+ }
+
+ if (tok->kind == TK_PP_NUM) {
+ read_line_marker(&tok, tok);
+ continue;
+ }
+
+ if (equal(tok, "pragma") && equal(tok->next, "once")) {
+ hashmap_put(&pragma_once, tok->file->name, (void *)1);
+ tok = skip_line(tok->next->next);
+ continue;
+ }
+
+ if (equal(tok, "pragma")) {
+ do {
+ tok = tok->next;
+ } while (!tok->at_bol);
+ continue;
+ }
+
+ if (equal(tok, "error"))
+ error_tok(tok, "error");
+
+ // `#`-only line is legal. It's called a null directive.
+ if (tok->at_bol)
+ continue;
+
+ error_tok(tok, "invalid preprocessor directive");
+ }
+
+ cur->next = tok;
+ return head.next;
+}
+
+void define_macro(char *name, char *buf) {
+ Token *tok = tokenize(new_file("<built-in>", 1, buf));
+ add_macro(name, true, tok);
+}
+
+void undef_macro(char *name) {
+ hashmap_delete(&macros, name);
+}
+
+static Macro *add_builtin(char *name, macro_handler_fn *fn) {
+ Macro *m = add_macro(name, true, NULL);
+ m->handler = fn;
+ return m;
+}
+
+static Token *file_macro(Token *tmpl) {
+ while (tmpl->origin)
+ tmpl = tmpl->origin;
+ return new_str_token(tmpl->file->display_name, tmpl);
+}
+
+static Token *line_macro(Token *tmpl) {
+ while (tmpl->origin)
+ tmpl = tmpl->origin;
+ int i = tmpl->line_no + tmpl->file->line_delta;
+ return new_num_token(i, tmpl);
+}
+
+// __COUNTER__ is expanded to serial values starting from 0.
+static Token *counter_macro(Token *tmpl) {
+ static int i = 0;
+ return new_num_token(i++, tmpl);
+}
+
+// __TIMESTAMP__ is expanded to a string describing the last
+// modification time of the current file. E.g.
+// "Fri Jul 24 01:32:50 2020"
+static Token *timestamp_macro(Token *tmpl) {
+ struct stat st;
+ if (stat(tmpl->file->name, &st) != 0)
+ return new_str_token("??? ??? ?? ??:??:?? ????", tmpl);
+
+ char buf[30];
+ ctime_r(&st.st_mtime, buf);
+ buf[24] = '\0';
+ return new_str_token(buf, tmpl);
+}
+
+static Token *base_file_macro(Token *tmpl) {
+ return new_str_token(base_file, tmpl);
+}
+
+// __DATE__ is expanded to the current date, e.g. "May 17 2020".
+static char *format_date(struct tm *tm) {
+ static char mon[][4] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
+ };
+
+ return format("\"%s %2d %d\"", mon[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);
+}
+
+// __TIME__ is expanded to the current time, e.g. "13:34:03".
+static char *format_time(struct tm *tm) {
+ return format("\"%02d:%02d:%02d\"", tm->tm_hour, tm->tm_min, tm->tm_sec);
+}
+
+void init_macros(void) {
+ // Define predefined macros
+ define_macro("_LP64", "1");
+ define_macro("__C99_MACRO_WITH_VA_ARGS", "1");
+ define_macro("__ELF__", "1");
+ define_macro("__LP64__", "1");
+ define_macro("__SIZEOF_DOUBLE__", "8");
+ define_macro("__SIZEOF_FLOAT__", "4");
+ define_macro("__SIZEOF_INT__", "4");
+ define_macro("__SIZEOF_LONG_DOUBLE__", "8");
+ define_macro("__SIZEOF_LONG_LONG__", "8");
+ define_macro("__SIZEOF_LONG__", "8");
+ define_macro("__SIZEOF_POINTER__", "8");
+ define_macro("__SIZEOF_PTRDIFF_T__", "8");
+ define_macro("__SIZEOF_SHORT__", "2");
+ define_macro("__SIZEOF_SIZE_T__", "8");
+ define_macro("__SIZE_TYPE__", "unsigned long");
+ define_macro("__STDC_HOSTED__", "1");
+ define_macro("__STDC_NO_COMPLEX__", "1");
+ define_macro("__STDC_UTF_16__", "1");
+ define_macro("__STDC_UTF_32__", "1");
+ define_macro("__STDC_VERSION__", "201112L");
+ define_macro("__STDC__", "1");
+ define_macro("__USER_LABEL_PREFIX__", "");
+ define_macro("__alignof__", "_Alignof");
+ define_macro("__amd64", "1");
+ define_macro("__amd64__", "1");
+ define_macro("__chibicc__", "1");
+ define_macro("__const__", "const");
+ define_macro("__gnu_linux__", "1");
+ define_macro("__inline__", "inline");
+ define_macro("__linux", "1");
+ define_macro("__linux__", "1");
+ define_macro("__signed__", "signed");
+ define_macro("__typeof__", "typeof");
+ define_macro("__unix", "1");
+ define_macro("__unix__", "1");
+ define_macro("__volatile__", "volatile");
+ define_macro("__x86_64", "1");
+ define_macro("__x86_64__", "1");
+ define_macro("linux", "1");
+ define_macro("unix", "1");
+
+ add_builtin("__FILE__", file_macro);
+ add_builtin("__LINE__", line_macro);
+ add_builtin("__COUNTER__", counter_macro);
+ add_builtin("__TIMESTAMP__", timestamp_macro);
+ add_builtin("__BASE_FILE__", base_file_macro);
+
+ time_t now = time(NULL);
+ struct tm *tm = localtime(&now);
+ define_macro("__DATE__", format_date(tm));
+ define_macro("__TIME__", format_time(tm));
+}
+
+typedef enum {
+ STR_NONE, STR_UTF8, STR_UTF16, STR_UTF32, STR_WIDE,
+} StringKind;
+
+static StringKind getStringKind(Token *tok) {
+ if (!strcmp(tok->loc, "u8"))
+ return STR_UTF8;
+
+ switch (tok->loc[0]) {
+ case '"': return STR_NONE;
+ case 'u': return STR_UTF16;
+ case 'U': return STR_UTF32;
+ case 'L': return STR_WIDE;
+ }
+ unreachable();
+}
+
+// Concatenate adjacent string literals into a single string literal
+// as per the C spec.
+static void join_adjacent_string_literals(Token *tok) {
+ // First pass: If regular string literals are adjacent to wide
+ // string literals, regular string literals are converted to a wide
+ // type before concatenation. In this pass, we do the conversion.
+ for (Token *tok1 = tok; tok1->kind != TK_EOF;) {
+ if (tok1->kind != TK_STR || tok1->next->kind != TK_STR) {
+ tok1 = tok1->next;
+ continue;
+ }
+
+ StringKind kind = getStringKind(tok1);
+ Type *basety = tok1->ty->base;
+
+ for (Token *t = tok1->next; t->kind == TK_STR; t = t->next) {
+ StringKind k = getStringKind(t);
+ if (kind == STR_NONE) {
+ kind = k;
+ basety = t->ty->base;
+ } else if (k != STR_NONE && kind != k) {
+ error_tok(t, "unsupported non-standard concatenation of string literals");
+ }
+ }
+
+ if (basety->size > 1)
+ for (Token *t = tok1; t->kind == TK_STR; t = t->next)
+ if (t->ty->base->size == 1)
+ *t = *tokenize_string_literal(t, basety);
+
+ while (tok1->kind == TK_STR)
+ tok1 = tok1->next;
+ }
+
+ // Second pass: concatenate adjacent string literals.
+ for (Token *tok1 = tok; tok1->kind != TK_EOF;) {
+ if (tok1->kind != TK_STR || tok1->next->kind != TK_STR) {
+ tok1 = tok1->next;
+ continue;
+ }
+
+ Token *tok2 = tok1->next;
+ while (tok2->kind == TK_STR)
+ tok2 = tok2->next;
+
+ int len = tok1->ty->array_len;
+ for (Token *t = tok1->next; t != tok2; t = t->next)
+ len = len + t->ty->array_len - 1;
+
+ char *buf = calloc(tok1->ty->base->size, len);
+
+ int i = 0;
+ for (Token *t = tok1; t != tok2; t = t->next) {
+ memcpy(buf + i, t->str, t->ty->size);
+ i = i + t->ty->size - t->ty->base->size;
+ }
+
+ *tok1 = *copy_token(tok1);
+ tok1->ty = array_of(tok1->ty->base, len);
+ tok1->str = buf;
+ tok1->next = tok2;
+ tok1 = tok2;
+ }
+}
+
+// Entry point function of the preprocessor.
+Token *preprocess(Token *tok) {
+ tok = preprocess2(tok);
+ if (cond_incl)
+ error_tok(cond_incl->tok, "unterminated conditional directive");
+ convert_pp_tokens(tok);
+ join_adjacent_string_literals(tok);
+
+ for (Token *t = tok; t; t = t->next)
+ t->line_no += t->line_delta;
+ return tok;
+}
diff --git a/src/3p/chibicc/strings.c b/src/3p/chibicc/strings.c
new file mode 100644
index 0000000..0538fef
--- /dev/null
+++ b/src/3p/chibicc/strings.c
@@ -0,0 +1,17 @@
+#include "chibicc.h"
+
+void strarray_push(StringArray *arr, char *s) {
+ if (!arr->data) {
+ arr->data = calloc(8, sizeof(char *));
+ arr->capacity = 8;
+ }
+
+ if (arr->capacity == arr->len) {
+ arr->data = realloc(arr->data, sizeof(char *) * arr->capacity * 2);
+ arr->capacity *= 2;
+ for (int i = arr->len; i < arr->capacity; i++)
+ arr->data[i] = NULL;
+ }
+
+ arr->data[arr->len++] = s;
+}
diff --git a/src/3p/chibicc/tokenize.c b/src/3p/chibicc/tokenize.c
new file mode 100644
index 0000000..8ed414e
--- /dev/null
+++ b/src/3p/chibicc/tokenize.c
@@ -0,0 +1,799 @@
+#include "chibicc.h"
+
+// Input file
+static File *current_file;
+
+// A list of all input files.
+static File **input_files;
+
+// True if the current position is at the beginning of a line
+static bool at_bol;
+
+// True if the current position follows a space character
+static bool has_space;
+
+// Reports an error and exit.
+void error(char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ fprintf(stderr, "cmeta: chibicc: ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+ exit(1);
+}
+
+// Reports an error message in the following format.
+//
+// foo.c:10: x = y + 1;
+// ^ <error message here>
+static void verror_at(char *filename, char *input, int line_no,
+ char *loc, char *fmt, va_list ap) {
+ // Find a line containing `loc`.
+ char *line = loc;
+ while (input < line && line[-1] != '\n')
+ line--;
+
+ char *end = loc;
+ while (*end && *end != '\n')
+ end++;
+
+ // Print out the line.
+ int indent = fprintf(stderr, "%s:%d: ", filename, line_no);
+ fprintf(stderr, "%.*s\n", (int)(end - line), line);
+
+ // Show the error message.
+ int pos = display_width(line, loc - line) + indent;
+
+ fprintf(stderr, "%*s", pos, ""); // print pos spaces.
+ fprintf(stderr, "^ ");
+ vfprintf(stderr, fmt, ap);
+ fprintf(stderr, "\n");
+}
+
+void error_at(char *loc, char *fmt, ...) {
+ int line_no = 1;
+ for (char *p = current_file->contents; p < loc; p++)
+ if (*p == '\n')
+ line_no++;
+
+ va_list ap;
+ va_start(ap, fmt);
+ verror_at(current_file->name, current_file->contents, line_no, loc, fmt, ap);
+ exit(1);
+}
+
+void error_tok(Token *tok, char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap);
+ exit(1);
+}
+
+void warn_tok(Token *tok, char *fmt, ...) {
+ va_list ap;
+ va_start(ap, fmt);
+ verror_at(tok->file->name, tok->file->contents, tok->line_no, tok->loc, fmt, ap);
+ va_end(ap);
+}
+
+// Consumes the current token if it matches `op`.
+bool equal(Token *tok, char *op) {
+ return memcmp(tok->loc, op, tok->len) == 0 && op[tok->len] == '\0';
+}
+
+// Ensure that the current token is `op`.
+Token *skip(Token *tok, char *op) {
+ if (!equal(tok, op))
+ error_tok(tok, "expected '%s'", op);
+ return tok->next;
+}
+
+bool consume(Token **rest, Token *tok, char *str) {
+ if (equal(tok, str)) {
+ *rest = tok->next;
+ return true;
+ }
+ *rest = tok;
+ return false;
+}
+
+// Create a new token.
+static Token *new_token(TokenKind kind, char *start, char *end) {
+ Token *tok = calloc(1, sizeof(Token));
+ tok->kind = kind;
+ tok->loc = start;
+ tok->len = end - start;
+ tok->file = current_file;
+ tok->filename = current_file->display_name;
+ tok->at_bol = at_bol;
+ tok->has_space = has_space;
+
+ at_bol = has_space = false;
+ return tok;
+}
+
+static bool startswith(char *p, char *q) {
+ return strncmp(p, q, strlen(q)) == 0;
+}
+
+// Read an identifier and returns the length of it.
+// If p does not point to a valid identifier, 0 is returned.
+static int read_ident(char *start) {
+ char *p = start;
+ uint32_t c = decode_utf8(&p, p);
+ if (!is_ident1(c))
+ return 0;
+
+ for (;;) {
+ char *q;
+ c = decode_utf8(&q, p);
+ if (!is_ident2(c))
+ return p - start;
+ p = q;
+ }
+}
+
+static int from_hex(char c) {
+ if ('0' <= c && c <= '9')
+ return c - '0';
+ if ('a' <= c && c <= 'f')
+ return c - 'a' + 10;
+ return c - 'A' + 10;
+}
+
+// Read a punctuator token from p and returns its length.
+static int read_punct(char *p) {
+ static char *kw[] = {
+ "<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", "+=",
+ "-=", "*=", "/=", "++", "--", "%=", "&=", "|=", "^=", "&&",
+ "||", "<<", ">>", "##",
+ };
+
+ for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
+ if (startswith(p, kw[i]))
+ return strlen(kw[i]);
+
+ return ispunct(*p) ? 1 : 0;
+}
+
+static bool is_keyword(Token *tok) {
+ static HashMap map;
+
+ if (map.capacity == 0) {
+ static char *kw[] = {
+ "return", "if", "else", "for", "while", "int", "sizeof", "char",
+ "struct", "union", "short", "long", "void", "typedef", "_Bool",
+ "enum", "static", "goto", "break", "continue", "switch", "case",
+ "default", "extern", "_Alignof", "_Alignas", "do", "signed",
+ "unsigned", "const", "volatile", "auto", "register", "restrict",
+ "__restrict", "__restrict__", "_Noreturn", "float", "double",
+ "typeof", "asm", "_Thread_local", "__thread", "_Atomic",
+ "__attribute__",
+ };
+
+ for (int i = 0; i < sizeof(kw) / sizeof(*kw); i++)
+ hashmap_put(&map, kw[i], (void *)1);
+ }
+
+ return hashmap_get2(&map, tok->loc, tok->len);
+}
+
+static int read_escaped_char(char **new_pos, char *p) {
+ if ('0' <= *p && *p <= '7') {
+ // Read an octal number.
+ int c = *p++ - '0';
+ if ('0' <= *p && *p <= '7') {
+ c = (c << 3) + (*p++ - '0');
+ if ('0' <= *p && *p <= '7')
+ c = (c << 3) + (*p++ - '0');
+ }
+ *new_pos = p;
+ return c;
+ }
+
+ if (*p == 'x') {
+ // Read a hexadecimal number.
+ p++;
+ if (!isxdigit(*p))
+ error_at(p, "invalid hex escape sequence");
+
+ int c = 0;
+ for (; isxdigit(*p); p++)
+ c = (c << 4) + from_hex(*p);
+ *new_pos = p;
+ return c;
+ }
+
+ *new_pos = p + 1;
+
+ // Escape sequences are defined using themselves here. E.g.
+ // '\n' is implemented using '\n'. This tautological definition
+ // works because the compiler that compiles our compiler knows
+ // what '\n' actually is. In other words, we "inherit" the ASCII
+ // code of '\n' from the compiler that compiles our compiler,
+ // so we don't have to teach the actual code here.
+ //
+ // This fact has huge implications not only for the correctness
+ // of the compiler but also for the security of the generated code.
+ // For more info, read "Reflections on Trusting Trust" by Ken Thompson.
+ // https://github.com/rui314/chibicc/wiki/thompson1984.pdf
+ switch (*p) {
+ case 'a': return '\a';
+ case 'b': return '\b';
+ case 't': return '\t';
+ case 'n': return '\n';
+ case 'v': return '\v';
+ case 'f': return '\f';
+ case 'r': return '\r';
+ // [GNU] \e for the ASCII escape character is a GNU C extension.
+ case 'e': return 27;
+ default: return *p;
+ }
+}
+
+// Find a closing double-quote.
+static char *string_literal_end(char *p) {
+ char *start = p;
+ for (; *p != '"'; p++) {
+ if (*p == '\n' || *p == '\0')
+ error_at(start, "unclosed string literal");
+ if (*p == '\\')
+ p++;
+ }
+ return p;
+}
+
+static Token *read_string_literal(char *start, char *quote) {
+ char *end = string_literal_end(quote + 1);
+ char *buf = calloc(1, end - quote);
+ int len = 0;
+
+ for (char *p = quote + 1; p < end;) {
+ if (*p == '\\')
+ buf[len++] = read_escaped_char(&p, p + 1);
+ else
+ buf[len++] = *p++;
+ }
+
+ Token *tok = new_token(TK_STR, start, end + 1);
+ tok->ty = array_of(ty_char, len + 1);
+ tok->str = buf;
+ return tok;
+}
+
+// Read a UTF-8-encoded string literal and transcode it in UTF-16.
+//
+// UTF-16 is yet another variable-width encoding for Unicode. Code
+// points smaller than U+10000 are encoded in 2 bytes. Code points
+// equal to or larger than that are encoded in 4 bytes. Each 2 bytes
+// in the 4 byte sequence is called "surrogate", and a 4 byte sequence
+// is called a "surrogate pair".
+static Token *read_utf16_string_literal(char *start, char *quote) {
+ char *end = string_literal_end(quote + 1);
+ uint16_t *buf = calloc(2, end - start);
+ int len = 0;
+
+ for (char *p = quote + 1; p < end;) {
+ if (*p == '\\') {
+ buf[len++] = read_escaped_char(&p, p + 1);
+ continue;
+ }
+
+ uint32_t c = decode_utf8(&p, p);
+ if (c < 0x10000) {
+ // Encode a code point in 2 bytes.
+ buf[len++] = c;
+ } else {
+ // Encode a code point in 4 bytes.
+ c -= 0x10000;
+ buf[len++] = 0xd800 + ((c >> 10) & 0x3ff);
+ buf[len++] = 0xdc00 + (c & 0x3ff);
+ }
+ }
+
+ Token *tok = new_token(TK_STR, start, end + 1);
+ tok->ty = array_of(ty_ushort, len + 1);
+ tok->str = (char *)buf;
+ return tok;
+}
+
+// Read a UTF-8-encoded string literal and transcode it in UTF-32.
+//
+// UTF-32 is a fixed-width encoding for Unicode. Each code point is
+// encoded in 4 bytes.
+static Token *read_utf32_string_literal(char *start, char *quote, Type *ty) {
+ char *end = string_literal_end(quote + 1);
+ uint32_t *buf = calloc(4, end - quote);
+ int len = 0;
+
+ for (char *p = quote + 1; p < end;) {
+ if (*p == '\\')
+ buf[len++] = read_escaped_char(&p, p + 1);
+ else
+ buf[len++] = decode_utf8(&p, p);
+ }
+
+ Token *tok = new_token(TK_STR, start, end + 1);
+ tok->ty = array_of(ty, len + 1);
+ tok->str = (char *)buf;
+ return tok;
+}
+
+static Token *read_char_literal(char *start, char *quote, Type *ty) {
+ char *p = quote + 1;
+ if (*p == '\0')
+ error_at(start, "unclosed char literal");
+
+ int c;
+ if (*p == '\\')
+ c = read_escaped_char(&p, p + 1);
+ else
+ c = decode_utf8(&p, p);
+
+ char *end = strchr(p, '\'');
+ if (!end)
+ error_at(p, "unclosed char literal");
+
+ Token *tok = new_token(TK_NUM, start, end + 1);
+ tok->val = c;
+ tok->ty = ty;
+ return tok;
+}
+
+static bool convert_pp_int(Token *tok) {
+ char *p = tok->loc;
+
+ // Read a binary, octal, decimal or hexadecimal number.
+ int base = 10;
+ if (!strncasecmp(p, "0x", 2) && isxdigit(p[2])) {
+ p += 2;
+ base = 16;
+ } else if (!strncasecmp(p, "0b", 2) && (p[2] == '0' || p[2] == '1')) {
+ p += 2;
+ base = 2;
+ } else if (*p == '0') {
+ base = 8;
+ }
+
+ int64_t val = strtoul(p, &p, base);
+
+ // Read U, L or LL suffixes.
+ bool l = false;
+ bool u = false;
+
+ if (startswith(p, "LLU") || startswith(p, "LLu") ||
+ startswith(p, "llU") || startswith(p, "llu") ||
+ startswith(p, "ULL") || startswith(p, "Ull") ||
+ startswith(p, "uLL") || startswith(p, "ull")) {
+ p += 3;
+ l = u = true;
+ } else if (!strncasecmp(p, "lu", 2) || !strncasecmp(p, "ul", 2)) {
+ p += 2;
+ l = u = true;
+ } else if (startswith(p, "LL") || startswith(p, "ll")) {
+ p += 2;
+ l = true;
+ } else if (*p == 'L' || *p == 'l') {
+ p++;
+ l = true;
+ } else if (*p == 'U' || *p == 'u') {
+ p++;
+ u = true;
+ }
+
+ if (p != tok->loc + tok->len)
+ return false;
+
+ // Infer a type.
+ Type *ty;
+ if (base == 10) {
+ if (l && u)
+ ty = ty_ulong;
+ else if (l)
+ ty = ty_long;
+ else if (u)
+ ty = (val >> 32) ? ty_ulong : ty_uint;
+ else
+ ty = (val >> 31) ? ty_long : ty_int;
+ } else {
+ if (l && u)
+ ty = ty_ulong;
+ else if (l)
+ ty = (val >> 63) ? ty_ulong : ty_long;
+ else if (u)
+ ty = (val >> 32) ? ty_ulong : ty_uint;
+ else if (val >> 63)
+ ty = ty_ulong;
+ else if (val >> 32)
+ ty = ty_long;
+ else if (val >> 31)
+ ty = ty_uint;
+ else
+ ty = ty_int;
+ }
+
+ tok->kind = TK_NUM;
+ tok->val = val;
+ tok->ty = ty;
+ return true;
+}
+
+// The definition of the numeric literal at the preprocessing stage
+// is more relaxed than the definition of that at the later stages.
+// In order to handle that, a numeric literal is tokenized as a
+// "pp-number" token first and then converted to a regular number
+// token after preprocessing.
+//
+// This function converts a pp-number token to a regular number token.
+static void convert_pp_number(Token *tok) {
+ // Try to parse as an integer constant.
+ if (convert_pp_int(tok))
+ return;
+
+ // If it's not an integer, it must be a floating point constant.
+ char *end;
+ long double val = strtold(tok->loc, &end);
+
+ Type *ty;
+ if (*end == 'f' || *end == 'F') {
+ ty = ty_float;
+ end++;
+ } else if (*end == 'l' || *end == 'L') {
+ ty = ty_ldouble;
+ end++;
+ } else {
+ ty = ty_double;
+ }
+
+ if (tok->loc + tok->len != end)
+ error_tok(tok, "invalid numeric constant");
+
+ tok->kind = TK_NUM;
+ tok->fval = val;
+ tok->ty = ty;
+}
+
+void convert_pp_tokens(Token *tok) {
+ for (Token *t = tok; t->kind != TK_EOF; t = t->next) {
+ if (is_keyword(t))
+ t->kind = TK_KEYWORD;
+ else if (t->kind == TK_PP_NUM)
+ convert_pp_number(t);
+ }
+}
+
+// Initialize line info for all tokens.
+static void add_line_numbers(Token *tok) {
+ char *p = current_file->contents;
+ int n = 1;
+
+ do {
+ if (p == tok->loc) {
+ tok->line_no = n;
+ tok = tok->next;
+ }
+ if (*p == '\n')
+ n++;
+ } while (*p++);
+}
+
+Token *tokenize_string_literal(Token *tok, Type *basety) {
+ Token *t;
+ if (basety->size == 2)
+ t = read_utf16_string_literal(tok->loc, tok->loc);
+ else
+ t = read_utf32_string_literal(tok->loc, tok->loc, basety);
+ t->next = tok->next;
+ return t;
+}
+
+// Tokenize a given string and returns new tokens.
+Token *tokenize(File *file) {
+ current_file = file;
+
+ char *p = file->contents;
+ Token head = {0};
+ Token *cur = &head;
+
+ at_bol = true;
+ has_space = false;
+
+ while (*p) {
+ // Skip line comments.
+ if (startswith(p, "//")) {
+ p += 2;
+ while (*p != '\n')
+ p++;
+ has_space = true;
+ continue;
+ }
+
+ // Skip block comments.
+ if (startswith(p, "/*")) {
+ char *q = strstr(p + 2, "*/");
+ if (!q)
+ error_at(p, "unclosed block comment");
+ p = q + 2;
+ has_space = true;
+ continue;
+ }
+
+ // Skip newline.
+ if (*p == '\n') {
+ p++;
+ at_bol = true;
+ has_space = false;
+ continue;
+ }
+
+ // Skip whitespace characters.
+ if (isspace(*p)) {
+ p++;
+ has_space = true;
+ continue;
+ }
+
+ // Numeric literal
+ if (isdigit(*p) || (*p == '.' && isdigit(p[1]))) {
+ char *q = p++;
+ for (;;) {
+ if (p[0] && p[1] && strchr("eEpP", p[0]) && strchr("+-", p[1]))
+ p += 2;
+ else if (isalnum(*p) || *p == '.')
+ p++;
+ else
+ break;
+ }
+ cur = cur->next = new_token(TK_PP_NUM, q, p);
+ continue;
+ }
+
+ // String literal
+ if (*p == '"') {
+ cur = cur->next = read_string_literal(p, p);
+ p += cur->len;
+ continue;
+ }
+
+ // UTF-8 string literal
+ if (startswith(p, "u8\"")) {
+ cur = cur->next = read_string_literal(p, p + 2);
+ p += cur->len;
+ continue;
+ }
+
+ // UTF-16 string literal
+ if (startswith(p, "u\"")) {
+ cur = cur->next = read_utf16_string_literal(p, p + 1);
+ p += cur->len;
+ continue;
+ }
+
+ // Wide string literal
+ if (startswith(p, "L\"")) {
+ cur = cur->next = read_utf32_string_literal(p, p + 1, ty_int);
+ p += cur->len;
+ continue;
+ }
+
+ // UTF-32 string literal
+ if (startswith(p, "U\"")) {
+ cur = cur->next = read_utf32_string_literal(p, p + 1, ty_uint);
+ p += cur->len;
+ continue;
+ }
+
+ // Character literal
+ if (*p == '\'') {
+ cur = cur->next = read_char_literal(p, p, ty_int);
+ cur->val = (char)cur->val;
+ p += cur->len;
+ continue;
+ }
+
+ // UTF-16 character literal
+ if (startswith(p, "u'")) {
+ cur = cur->next = read_char_literal(p, p + 1, ty_ushort);
+ cur->val &= 0xffff;
+ p += cur->len;
+ continue;
+ }
+
+ // Wide character literal
+ if (startswith(p, "L'")) {
+ cur = cur->next = read_char_literal(p, p + 1, ty_int);
+ p += cur->len;
+ continue;
+ }
+
+ // UTF-32 character literal
+ if (startswith(p, "U'")) {
+ cur = cur->next = read_char_literal(p, p + 1, ty_uint);
+ p += cur->len;
+ continue;
+ }
+
+ // Identifier or keyword
+ int ident_len = read_ident(p);
+ if (ident_len) {
+ cur = cur->next = new_token(TK_IDENT, p, p + ident_len);
+ p += cur->len;
+ continue;
+ }
+
+ // Punctuators
+ int punct_len = read_punct(p);
+ if (punct_len) {
+ cur = cur->next = new_token(TK_PUNCT, p, p + punct_len);
+ p += cur->len;
+ continue;
+ }
+
+ error_at(p, "invalid token");
+ }
+
+ cur = cur->next = new_token(TK_EOF, p, p);
+ add_line_numbers(head.next);
+ return head.next;
+}
+
+// Returns the contents of a given file.
+/* this function is a bit wonkily implemented, and relies on a non-windows
+ * thing, so we have our own in src/cmeta.c.
+static char *read_file(char *path) {
+ FILE *fp;
+
+ if (strcmp(path, "-") == 0) {
+ // By convention, read from stdin if a given filename is "-".
+ fp = stdin;
+ } else {
+ fp = fopen(path, "r");
+ if (!fp)
+ return NULL;
+ }
+
+ char *buf;
+ size_t buflen;
+ FILE *out = open_memstream(&buf, &buflen);
+
+ // Read the entire file.
+ for (;;) {
+ char buf2[4096];
+ int n = fread(buf2, 1, sizeof(buf2), fp);
+ if (n == 0)
+ break;
+ fwrite(buf2, 1, n, out);
+ }
+
+ if (fp != stdin)
+ fclose(fp);
+
+ // Make sure that the last line is properly terminated with '\n'.
+ fflush(out);
+ if (buflen == 0 || buf[buflen - 1] != '\n')
+ fputc('\n', out);
+ fputc('\0', out);
+ fclose(out);
+ return buf;
+}
+*/
+
+File **get_input_files(void) {
+ return input_files;
+}
+
+File *new_file(char *name, int file_no, char *contents) {
+ File *file = calloc(1, sizeof(File));
+ file->name = name;
+ file->display_name = name;
+ file->file_no = file_no;
+ file->contents = contents;
+ return file;
+}
+
+// Replaces \r or \r\n with \n.
+static void canonicalize_newline(char *p) {
+ int i = 0, j = 0;
+
+ while (p[i]) {
+ if (p[i] == '\r' && p[i + 1] == '\n') {
+ i += 2;
+ p[j++] = '\n';
+ } else if (p[i] == '\r') {
+ i++;
+ p[j++] = '\n';
+ } else {
+ p[j++] = p[i++];
+ }
+ }
+
+ p[j] = '\0';
+}
+
+// Removes backslashes followed by a newline.
+static void remove_backslash_newline(char *p) {
+ int i = 0, j = 0;
+
+ // We want to keep the number of newline characters so that
+ // the logical line number matches the physical one.
+ // This counter maintain the number of newlines we have removed.
+ int n = 0;
+
+ while (p[i]) {
+ if (p[i] == '\\' && p[i + 1] == '\n') {
+ i += 2;
+ n++;
+ } else if (p[i] == '\n') {
+ p[j++] = p[i++];
+ for (; n > 0; n--)
+ p[j++] = '\n';
+ } else {
+ p[j++] = p[i++];
+ }
+ }
+
+ for (; n > 0; n--)
+ p[j++] = '\n';
+ p[j] = '\0';
+}
+
+static uint32_t read_universal_char(char *p, int len) {
+ uint32_t c = 0;
+ for (int i = 0; i < len; i++) {
+ if (!isxdigit(p[i]))
+ return 0;
+ c = (c << 4) | from_hex(p[i]);
+ }
+ return c;
+}
+
+// Replace \u or \U escape sequences with corresponding UTF-8 bytes.
+static void convert_universal_chars(char *p) {
+ char *q = p;
+
+ while (*p) {
+ if (startswith(p, "\\u")) {
+ uint32_t c = read_universal_char(p + 2, 4);
+ if (c) {
+ p += 6;
+ q += encode_utf8(q, c);
+ } else {
+ *q++ = *p++;
+ }
+ } else if (startswith(p, "\\U")) {
+ uint32_t c = read_universal_char(p + 2, 8);
+ if (c) {
+ p += 10;
+ q += encode_utf8(q, c);
+ } else {
+ *q++ = *p++;
+ }
+ } else if (p[0] == '\\') {
+ *q++ = *p++;
+ *q++ = *p++;
+ } else {
+ *q++ = *p++;
+ }
+ }
+
+ *q = '\0';
+}
+
+// NOTE modified API from upstream
+Token *tokenize_buf(const char *name, char *p) {
+ canonicalize_newline(p);
+ remove_backslash_newline(p);
+ convert_universal_chars(p);
+
+ // Save the filename for assembler .file directive.
+ static int file_no;
+ File *file = new_file((char *)name, file_no + 1, p);
+
+ // Save the filename for assembler .file directive.
+ input_files = realloc(input_files, sizeof(char *) * (file_no + 2));
+ input_files[file_no] = file;
+ input_files[file_no + 1] = NULL;
+ file_no++;
+
+ return tokenize(file);
+}
diff --git a/src/3p/chibicc/type.c b/src/3p/chibicc/type.c
new file mode 100644
index 0000000..02ade59
--- /dev/null
+++ b/src/3p/chibicc/type.c
@@ -0,0 +1,307 @@
+#include "chibicc.h"
+
+Type *ty_void = &(Type){TY_VOID, 1, 1};
+Type *ty_bool = &(Type){TY_BOOL, 1, 1};
+
+Type *ty_char = &(Type){TY_CHAR, 1, 1};
+Type *ty_short = &(Type){TY_SHORT, 2, 2};
+Type *ty_int = &(Type){TY_INT, 4, 4};
+Type *ty_long = &(Type){TY_LONG, 8, 8};
+
+Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
+Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
+Type *ty_uint = &(Type){TY_INT, 4, 4, true};
+Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
+
+Type *ty_float = &(Type){TY_FLOAT, 4, 4};
+Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
+Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
+
+static Type *new_type(TypeKind kind, int size, int align) {
+ Type *ty = calloc(1, sizeof(Type));
+ ty->kind = kind;
+ ty->size = size;
+ ty->align = align;
+ return ty;
+}
+
+bool is_integer(Type *ty) {
+ TypeKind k = ty->kind;
+ return k == TY_BOOL || k == TY_CHAR || k == TY_SHORT ||
+ k == TY_INT || k == TY_LONG || k == TY_ENUM;
+}
+
+bool is_flonum(Type *ty) {
+ return ty->kind == TY_FLOAT || ty->kind == TY_DOUBLE ||
+ ty->kind == TY_LDOUBLE;
+}
+
+bool is_numeric(Type *ty) {
+ return is_integer(ty) || is_flonum(ty);
+}
+
+bool is_compatible(Type *t1, Type *t2) {
+ if (t1 == t2)
+ return true;
+
+ if (t1->origin)
+ return is_compatible(t1->origin, t2);
+
+ if (t2->origin)
+ return is_compatible(t1, t2->origin);
+
+ if (t1->kind != t2->kind)
+ return false;
+
+ switch (t1->kind) {
+ case TY_CHAR:
+ case TY_SHORT:
+ case TY_INT:
+ case TY_LONG:
+ return t1->is_unsigned == t2->is_unsigned;
+ case TY_FLOAT:
+ case TY_DOUBLE:
+ case TY_LDOUBLE:
+ return true;
+ case TY_PTR:
+ return is_compatible(t1->base, t2->base);
+ case TY_FUNC: {
+ if (!is_compatible(t1->return_ty, t2->return_ty))
+ return false;
+ if (t1->is_variadic != t2->is_variadic)
+ return false;
+
+ Type *p1 = t1->params;
+ Type *p2 = t2->params;
+ for (; p1 && p2; p1 = p1->next, p2 = p2->next)
+ if (!is_compatible(p1, p2))
+ return false;
+ return p1 == NULL && p2 == NULL;
+ }
+ case TY_ARRAY:
+ if (!is_compatible(t1->base, t2->base))
+ return false;
+ return t1->array_len < 0 && t2->array_len < 0 &&
+ t1->array_len == t2->array_len;
+ }
+ return false;
+}
+
+Type *copy_type(Type *ty) {
+ Type *ret = calloc(1, sizeof(Type));
+ *ret = *ty;
+ ret->origin = ty;
+ return ret;
+}
+
+Type *pointer_to(Type *base) {
+ Type *ty = new_type(TY_PTR, 8, 8);
+ ty->base = base;
+ ty->is_unsigned = true;
+ return ty;
+}
+
+Type *func_type(Type *return_ty) {
+ // The C spec disallows sizeof(<function type>), but
+ // GCC allows that and the expression is evaluated to 1.
+ Type *ty = new_type(TY_FUNC, 1, 1);
+ ty->return_ty = return_ty;
+ return ty;
+}
+
+Type *array_of(Type *base, int len) {
+ Type *ty = new_type(TY_ARRAY, base->size * len, base->align);
+ ty->base = base;
+ ty->array_len = len;
+ return ty;
+}
+
+Type *vla_of(Type *base, Node *len) {
+ Type *ty = new_type(TY_VLA, 8, 8);
+ ty->base = base;
+ ty->vla_len = len;
+ return ty;
+}
+
+Type *enum_type(void) {
+ return new_type(TY_ENUM, 4, 4);
+}
+
+Type *struct_type(void) {
+ return new_type(TY_STRUCT, 0, 1);
+}
+
+static Type *get_common_type(Type *ty1, Type *ty2) {
+ if (ty1->base)
+ return pointer_to(ty1->base);
+
+ if (ty1->kind == TY_FUNC)
+ return pointer_to(ty1);
+ if (ty2->kind == TY_FUNC)
+ return pointer_to(ty2);
+
+ if (ty1->kind == TY_LDOUBLE || ty2->kind == TY_LDOUBLE)
+ return ty_ldouble;
+ if (ty1->kind == TY_DOUBLE || ty2->kind == TY_DOUBLE)
+ return ty_double;
+ if (ty1->kind == TY_FLOAT || ty2->kind == TY_FLOAT)
+ return ty_float;
+
+ if (ty1->size < 4)
+ ty1 = ty_int;
+ if (ty2->size < 4)
+ ty2 = ty_int;
+
+ if (ty1->size != ty2->size)
+ return (ty1->size < ty2->size) ? ty2 : ty1;
+
+ if (ty2->is_unsigned)
+ return ty2;
+ return ty1;
+}
+
+// For many binary operators, we implicitly promote operands so that
+// both operands have the same type. Any integral type smaller than
+// int is always promoted to int. If the type of one operand is larger
+// than the other's (e.g. "long" vs. "int"), the smaller operand will
+// be promoted to match with the other.
+//
+// This operation is called the "usual arithmetic conversion".
+static void usual_arith_conv(Node **lhs, Node **rhs) {
+ Type *ty = get_common_type((*lhs)->ty, (*rhs)->ty);
+ *lhs = new_cast(*lhs, ty);
+ *rhs = new_cast(*rhs, ty);
+}
+
+void add_type(Node *node) {
+ if (!node || node->ty)
+ return;
+
+ add_type(node->lhs);
+ add_type(node->rhs);
+ add_type(node->cond);
+ add_type(node->then);
+ add_type(node->els);
+ add_type(node->init);
+ add_type(node->inc);
+
+ for (Node *n = node->body; n; n = n->next)
+ add_type(n);
+ for (Node *n = node->args; n; n = n->next)
+ add_type(n);
+
+ switch (node->kind) {
+ case ND_NUM:
+ node->ty = ty_int;
+ return;
+ case ND_ADD:
+ case ND_SUB:
+ case ND_MUL:
+ case ND_DIV:
+ case ND_MOD:
+ case ND_BITAND:
+ case ND_BITOR:
+ case ND_BITXOR:
+ usual_arith_conv(&node->lhs, &node->rhs);
+ node->ty = node->lhs->ty;
+ return;
+ case ND_NEG: {
+ Type *ty = get_common_type(ty_int, node->lhs->ty);
+ node->lhs = new_cast(node->lhs, ty);
+ node->ty = ty;
+ return;
+ }
+ case ND_ASSIGN:
+ if (node->lhs->ty->kind == TY_ARRAY)
+ error_tok(node->lhs->tok, "not an lvalue");
+ if (node->lhs->ty->kind != TY_STRUCT)
+ node->rhs = new_cast(node->rhs, node->lhs->ty);
+ node->ty = node->lhs->ty;
+ return;
+ case ND_EQ:
+ case ND_NE:
+ case ND_LT:
+ case ND_LE:
+ usual_arith_conv(&node->lhs, &node->rhs);
+ node->ty = ty_int;
+ return;
+ case ND_FUNCALL:
+ node->ty = node->func_ty->return_ty;
+ return;
+ case ND_NOT:
+ case ND_LOGOR:
+ case ND_LOGAND:
+ node->ty = ty_int;
+ return;
+ case ND_BITNOT:
+ case ND_SHL:
+ case ND_SHR:
+ node->ty = node->lhs->ty;
+ return;
+ case ND_VAR:
+ case ND_VLA_PTR:
+ node->ty = node->var->ty;
+ return;
+ case ND_COND:
+ if (node->then->ty->kind == TY_VOID || node->els->ty->kind == TY_VOID) {
+ node->ty = ty_void;
+ } else {
+ usual_arith_conv(&node->then, &node->els);
+ node->ty = node->then->ty;
+ }
+ return;
+ case ND_COMMA:
+ node->ty = node->rhs->ty;
+ return;
+ case ND_MEMBER:
+ node->ty = node->member->ty;
+ return;
+ case ND_ADDR: {
+ Type *ty = node->lhs->ty;
+ if (ty->kind == TY_ARRAY)
+ node->ty = pointer_to(ty->base);
+ else
+ node->ty = pointer_to(ty);
+ return;
+ }
+ case ND_DEREF:
+ if (!node->lhs->ty->base)
+ error_tok(node->tok, "invalid pointer dereference");
+ if (node->lhs->ty->base->kind == TY_VOID)
+ error_tok(node->tok, "dereferencing a void pointer");
+
+ node->ty = node->lhs->ty->base;
+ return;
+ case ND_STMT_EXPR:
+ if (node->body) {
+ Node *stmt = node->body;
+ while (stmt->next)
+ stmt = stmt->next;
+ if (stmt->kind == ND_EXPR_STMT) {
+ node->ty = stmt->lhs->ty;
+ return;
+ }
+ }
+ error_tok(node->tok, "statement expression returning void is not supported");
+ return;
+ case ND_LABEL_VAL:
+ node->ty = pointer_to(ty_void);
+ return;
+ case ND_CAS:
+ add_type(node->cas_addr);
+ add_type(node->cas_old);
+ add_type(node->cas_new);
+ node->ty = ty_bool;
+
+ if (node->cas_addr->ty->kind != TY_PTR)
+ error_tok(node->cas_addr->tok, "pointer expected");
+ if (node->cas_old->ty->kind != TY_PTR)
+ error_tok(node->cas_old->tok, "pointer expected");
+ return;
+ case ND_EXCH:
+ if (node->lhs->ty->kind != TY_PTR)
+ error_tok(node->cas_addr->tok, "pointer expected");
+ node->ty = node->lhs->ty->base;
+ return;
+ }
+}
diff --git a/src/3p/chibicc/unicode.c b/src/3p/chibicc/unicode.c
new file mode 100644
index 0000000..6db1ad7
--- /dev/null
+++ b/src/3p/chibicc/unicode.c
@@ -0,0 +1,189 @@
+#include "chibicc.h"
+
+// Encode a given character in UTF-8.
+int encode_utf8(char *buf, uint32_t c) {
+ if (c <= 0x7F) {
+ buf[0] = c;
+ return 1;
+ }
+
+ if (c <= 0x7FF) {
+ buf[0] = 0xC0 | (c >> 6);
+ buf[1] = 0x80 | ((c >> 6) & 0x3F);
+ return 2;
+ }
+
+ if (c <= 0xFFFF) {
+ buf[0] = 0xE0 | (c >> 12);
+ buf[1] = 0x80 | ((c >> 6) & 0x3F);
+ buf[2] = 0x80 | (c & 0x3F);
+ return 3;
+ }
+
+ buf[0] = 0xF0 | (c >> 18);
+ buf[1] = 0x80 | ((c >> 12) & 0x3F);
+ buf[2] = 0x80 | ((c >> 6) & 0x3F);
+ buf[3] = 0x80 | (c & 0x3F);
+ return 4;
+}
+
+// Read a UTF-8-encoded Unicode code point from a source file.
+// We assume that source files are always in UTF-8.
+//
+// UTF-8 is a variable-width encoding in which one code point is
+// encoded in one to four bytes. One byte UTF-8 code points are
+// identical to ASCII. Non-ASCII characters are encoded using more
+// than one byte.
+uint32_t decode_utf8(char **new_pos, char *p) {
+ if ((unsigned char)*p < 128) {
+ *new_pos = p + 1;
+ return *p;
+ }
+
+ char *start = p;
+ int len;
+ uint32_t c;
+
+ if ((unsigned char)*p >= 0xF0) {
+ len = 4;
+ c = *p & 7;
+ } else if ((unsigned char)*p >= 0xE0) {
+ len = 3;
+ c = *p & 15;
+ } else if ((unsigned char)*p >= 0xC0) {
+ len = 2;
+ c = *p & 31;
+ } else {
+ error_at(start, "invalid UTF-8 sequence");
+ }
+
+ for (int i = 1; i < len; i++) {
+ if ((unsigned char)p[i] >> 6 != 2)
+ error_at(start, "invalid UTF-8 sequence");
+ c = (c << 6) | (p[i] & 63);
+ }
+
+ *new_pos = p + len;
+ return c;
+}
+
+static bool in_range(uint32_t *range, uint32_t c) {
+ for (int i = 0; range[i] != -1; i += 2)
+ if (range[i] <= c && c <= range[i + 1])
+ return true;
+ return false;
+}
+
+// [https://www.sigbus.info/n1570#D] C11 allows not only ASCII but
+// some multibyte characters in certan Unicode ranges to be used in an
+// identifier.
+//
+// This function returns true if a given character is acceptable as
+// the first character of an identifier.
+//
+// For example, ¾ (U+00BE) is a valid identifier because characters in
+// 0x00BE-0x00C0 are allowed, while neither ⟘ (U+27D8) nor ' '
+// (U+3000, full-width space) are allowed because they are out of range.
+bool is_ident1(uint32_t c) {
+ static uint32_t range[] = {
+ '_', '_', 'a', 'z', 'A', 'Z', '$', '$',
+ 0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF,
+ 0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6,
+ 0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F,
+ 0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D,
+ 0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F,
+ 0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793,
+ 0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F,
+ 0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF,
+ 0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD,
+ 0x10000, 0x1FFFD, 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD,
+ 0x50000, 0x5FFFD, 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD,
+ 0x90000, 0x9FFFD, 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD,
+ 0xD0000, 0xDFFFD, 0xE0000, 0xEFFFD, -1,
+ };
+
+ return in_range(range, c);
+}
+
+// Returns true if a given character is acceptable as a non-first
+// character of an identifier.
+bool is_ident2(uint32_t c) {
+ static uint32_t range[] = {
+ '0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 0x1DFF, 0x20D0, 0x20FF,
+ 0xFE20, 0xFE2F, -1,
+ };
+
+ return is_ident1(c) || in_range(range, c);
+}
+
+// Returns the number of columns needed to display a given
+// character in a fixed-width font.
+//
+// Based on https://www.cl.cam.ac.uk/~mgk25/ucs/wcwidth.c
+static int char_width(uint32_t c) {
+ static uint32_t range1[] = {
+ 0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486,
+ 0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2,
+ 0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615,
+ 0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8,
+ 0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A,
+ 0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C,
+ 0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963,
+ 0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD,
+ 0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42,
+ 0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82,
+ 0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD,
+ 0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F,
+ 0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82,
+ 0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48,
+ 0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF,
+ 0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43,
+ 0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6,
+ 0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1,
+ 0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19,
+ 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E,
+ 0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC,
+ 0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037,
+ 0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F,
+ 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773,
+ 0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3,
+ 0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922,
+ 0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18,
+ 0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C,
+ 0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF,
+ 0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F,
+ 0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806,
+ 0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F,
+ 0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03,
+ 0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F,
+ 0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD,
+ 0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF,
+ -1,
+ };
+
+ if (in_range(range1, c))
+ return 0;
+
+ static uint32_t range2[] = {
+ 0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E,
+ 0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19,
+ 0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644,
+ 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1,
+ };
+
+ if (in_range(range2, c))
+ return 2;
+ return 1;
+}
+
+// Returns the number of columns needed to display a given
+// string in a fixed-width font.
+int display_width(char *p, int len) {
+ char *start = p;
+ int w = 0;
+ while (p - start < len) {
+ uint32_t c = decode_utf8(&p, p);
+ w += char_width(c);
+ }
+ return w;
+}
diff --git a/src/3p/openbsd/asprintf.c b/src/3p/openbsd/asprintf.c
new file mode 100644
index 0000000..195efce
--- /dev/null
+++ b/src/3p/openbsd/asprintf.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2004 Darren Tucker.
+ *
+ * Based originally on asprintf.c from OpenBSD:
+ * Copyright (c) 1997 Todd C. Miller <Todd.Miller@courtesan.com>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <errno.h>
+#include <limits.h> /* for INT_MAX */
+#include <stdarg.h>
+#include <stdio.h> /* for vsnprintf */
+#include <stdlib.h>
+
+#define INIT_SZ 128
+
+int
+vasprintf(char **str, const char *fmt, va_list ap)
+{
+ int ret;
+ va_list ap2;
+ char *string, *newstr;
+ size_t len;
+
+ if ((string = malloc(INIT_SZ)) == NULL)
+ goto fail;
+
+ va_copy(ap2, ap);
+ ret = vsnprintf(string, INIT_SZ, fmt, ap2);
+ va_end(ap2);
+ if (ret >= 0 && ret < INIT_SZ) { /* succeeded with initial alloc */
+ *str = string;
+ } else if (ret == INT_MAX || ret < 0) { /* Bad length */
+ free(string);
+ goto fail;
+ } else { /* bigger than initial, realloc allowing for nul */
+ len = (size_t)ret + 1;
+ if ((newstr = realloc(string, len)) == NULL) {
+ free(string);
+ goto fail;
+ }
+ va_copy(ap2, ap);
+ ret = vsnprintf(newstr, len, fmt, ap2);
+ va_end(ap2);
+ if (ret < 0 || (size_t)ret >= len) { /* failed with realloc'ed string */
+ free(newstr);
+ goto fail;
+ }
+ *str = newstr;
+ }
+ return (ret);
+
+fail:
+ *str = NULL;
+ errno = ENOMEM;
+ return (-1);
+}
+
+int asprintf(char **str, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ *str = NULL;
+ va_start(ap, fmt);
+ ret = vasprintf(str, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
diff --git a/src/3p/udis86/decode.c b/src/3p/udis86/decode.c
new file mode 100644
index 0000000..036b9ed
--- /dev/null
+++ b/src/3p/udis86/decode.c
@@ -0,0 +1,1266 @@
+/* udis86 - libudis86/decode.c
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "udint.h"
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+
+#ifndef __UD_STANDALONE__
+# include <string.h>
+#endif /* __UD_STANDALONE__ */
+
+/* The max number of prefixes to an instruction */
+#define MAX_PREFIXES 15
+
+/* rex prefix bits */
+#define REX_W(r) ( ( 0xF & ( r ) ) >> 3 )
+#define REX_R(r) ( ( 0x7 & ( r ) ) >> 2 )
+#define REX_X(r) ( ( 0x3 & ( r ) ) >> 1 )
+#define REX_B(r) ( ( 0x1 & ( r ) ) >> 0 )
+#define REX_PFX_MASK(n) ( ( P_REXW(n) << 3 ) | \
+ ( P_REXR(n) << 2 ) | \
+ ( P_REXX(n) << 1 ) | \
+ ( P_REXB(n) << 0 ) )
+
+/* scable-index-base bits */
+#define SIB_S(b) ( ( b ) >> 6 )
+#define SIB_I(b) ( ( ( b ) >> 3 ) & 7 )
+#define SIB_B(b) ( ( b ) & 7 )
+
+/* modrm bits */
+#define MODRM_REG(b) ( ( ( b ) >> 3 ) & 7 )
+#define MODRM_NNN(b) ( ( ( b ) >> 3 ) & 7 )
+#define MODRM_MOD(b) ( ( ( b ) >> 6 ) & 3 )
+#define MODRM_RM(b) ( ( b ) & 7 )
+
+static int decode_ext(struct ud *u, uint16_t ptr);
+static int decode_opcode(struct ud *u);
+
+enum reg_class { /* register classes */
+ REGCLASS_GPR,
+ REGCLASS_MMX,
+ REGCLASS_CR,
+ REGCLASS_DB,
+ REGCLASS_SEG,
+ REGCLASS_XMM
+};
+
+ /*
+ * inp_start
+ * Should be called before each de-code operation.
+ */
+static void
+inp_start(struct ud *u)
+{
+ u->inp_ctr = 0;
+}
+
+static uint8_t
+inp_peek(struct ud *u)
+{
+ if (u->inp_end == 0) {
+ if (u->inp_buf != NULL) {
+ if (u->inp_buf_index < u->inp_buf_size) {
+ return u->inp_buf[u->inp_buf_index];
+ }
+ } else if (u->inp_peek != UD_EOI) {
+ return u->inp_peek;
+ } else {
+ int c;
+ if ((c = u->inp_hook(u)) != UD_EOI) {
+ u->inp_peek = c;
+ return u->inp_peek;
+ }
+ }
+ }
+ u->inp_end = 1;
+ UDERR(u, "byte expected, eoi received\n");
+ return 0;
+}
+
+static uint8_t
+inp_next(struct ud *u)
+{
+ if (u->inp_end == 0) {
+ if (u->inp_buf != NULL) {
+ if (u->inp_buf_index < u->inp_buf_size) {
+ u->inp_ctr++;
+ return (u->inp_curr = u->inp_buf[u->inp_buf_index++]);
+ }
+ } else {
+ int c = u->inp_peek;
+ if (c != UD_EOI || (c = u->inp_hook(u)) != UD_EOI) {
+ u->inp_peek = UD_EOI;
+ u->inp_curr = c;
+ u->inp_sess[u->inp_ctr++] = u->inp_curr;
+ return u->inp_curr;
+ }
+ }
+ }
+ u->inp_end = 1;
+ UDERR(u, "byte expected, eoi received\n");
+ return 0;
+}
+
+static uint8_t
+inp_curr(struct ud *u)
+{
+ return u->inp_curr;
+}
+
+
+/*
+ * inp_uint8
+ * int_uint16
+ * int_uint32
+ * int_uint64
+ * Load little-endian values from input
+ */
+static uint8_t
+inp_uint8(struct ud* u)
+{
+ return inp_next(u);
+}
+
+static uint16_t
+inp_uint16(struct ud* u)
+{
+ uint16_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ return ret | (r << 8);
+}
+
+static uint32_t
+inp_uint32(struct ud* u)
+{
+ uint32_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ ret = ret | (r << 8);
+ r = inp_next(u);
+ ret = ret | (r << 16);
+ r = inp_next(u);
+ return ret | (r << 24);
+}
+
+static uint64_t
+inp_uint64(struct ud* u)
+{
+ uint64_t r, ret;
+
+ ret = inp_next(u);
+ r = inp_next(u);
+ ret = ret | (r << 8);
+ r = inp_next(u);
+ ret = ret | (r << 16);
+ r = inp_next(u);
+ ret = ret | (r << 24);
+ r = inp_next(u);
+ ret = ret | (r << 32);
+ r = inp_next(u);
+ ret = ret | (r << 40);
+ r = inp_next(u);
+ ret = ret | (r << 48);
+ r = inp_next(u);
+ return ret | (r << 56);
+}
+
+
+static UD_INLINE int
+eff_opr_mode(int dis_mode, int rex_w, int pfx_opr)
+{
+ if (dis_mode == 64) {
+ return rex_w ? 64 : (pfx_opr ? 16 : 32);
+ } else if (dis_mode == 32) {
+ return pfx_opr ? 16 : 32;
+ } else {
+ UD_ASSERT(dis_mode == 16);
+ return pfx_opr ? 32 : 16;
+ }
+}
+
+
+static UD_INLINE int
+eff_adr_mode(int dis_mode, int pfx_adr)
+{
+ if (dis_mode == 64) {
+ return pfx_adr ? 32 : 64;
+ } else if (dis_mode == 32) {
+ return pfx_adr ? 16 : 32;
+ } else {
+ UD_ASSERT(dis_mode == 16);
+ return pfx_adr ? 32 : 16;
+ }
+}
+
+
+/*
+ * decode_prefixes
+ *
+ * Extracts instruction prefixes.
+ */
+static int
+decode_prefixes(struct ud *u)
+{
+ int done = 0;
+ uint8_t curr = 0, last = 0;
+ UD_RETURN_ON_ERROR(u);
+
+ do {
+ last = curr;
+ curr = inp_next(u);
+ UD_RETURN_ON_ERROR(u);
+ if (u->inp_ctr == MAX_INSN_LENGTH) {
+ UD_RETURN_WITH_ERROR(u, "max instruction length");
+ }
+
+ switch (curr)
+ {
+ case 0x2E:
+ u->pfx_seg = UD_R_CS;
+ break;
+ case 0x36:
+ u->pfx_seg = UD_R_SS;
+ break;
+ case 0x3E:
+ u->pfx_seg = UD_R_DS;
+ break;
+ case 0x26:
+ u->pfx_seg = UD_R_ES;
+ break;
+ case 0x64:
+ u->pfx_seg = UD_R_FS;
+ break;
+ case 0x65:
+ u->pfx_seg = UD_R_GS;
+ break;
+ case 0x67: /* adress-size override prefix */
+ u->pfx_adr = 0x67;
+ break;
+ case 0xF0:
+ u->pfx_lock = 0xF0;
+ break;
+ case 0x66:
+ u->pfx_opr = 0x66;
+ break;
+ case 0xF2:
+ u->pfx_str = 0xf2;
+ break;
+ case 0xF3:
+ u->pfx_str = 0xf3;
+ break;
+ default:
+ /* consume if rex */
+ done = (u->dis_mode == 64 && (curr & 0xF0) == 0x40) ? 0 : 1;
+ break;
+ }
+ } while (!done);
+ /* rex prefixes in 64bit mode, must be the last prefix */
+ if (u->dis_mode == 64 && (last & 0xF0) == 0x40) {
+ u->pfx_rex = last;
+ }
+ return 0;
+}
+
+
+/*
+ * vex_l, vex_w
+ * Return the vex.L and vex.W bits
+ */
+static UD_INLINE uint8_t
+vex_l(const struct ud *u)
+{
+ UD_ASSERT(u->vex_op != 0);
+ return ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 2) & 1;
+}
+
+static UD_INLINE uint8_t
+vex_w(const struct ud *u)
+{
+ UD_ASSERT(u->vex_op != 0);
+ return u->vex_op == 0xc4 ? ((u->vex_b2 >> 7) & 1) : 0;
+}
+
+
+static UD_INLINE uint8_t
+modrm(struct ud * u)
+{
+ if ( !u->have_modrm ) {
+ u->modrm = inp_next( u );
+ u->modrm_offset = (uint8_t) (u->inp_ctr - 1);
+ u->have_modrm = 1;
+ }
+ return u->modrm;
+}
+
+
+static unsigned int
+resolve_operand_size(const struct ud* u, ud_operand_size_t osize)
+{
+ switch (osize) {
+ case SZ_V:
+ return u->opr_mode;
+ case SZ_Z:
+ return u->opr_mode == 16 ? 16 : 32;
+ case SZ_Y:
+ return u->opr_mode == 16 ? 32 : u->opr_mode;
+ case SZ_RDQ:
+ return u->dis_mode == 64 ? 64 : 32;
+ case SZ_X:
+ UD_ASSERT(u->vex_op != 0);
+ return (P_VEXL(u->itab_entry->prefix) && vex_l(u)) ? SZ_QQ : SZ_DQ;
+ default:
+ return osize;
+ }
+}
+
+
+static int resolve_mnemonic( struct ud* u )
+{
+ /* resolve 3dnow weirdness. */
+ if ( u->mnemonic == UD_I3dnow ) {
+ u->mnemonic = ud_itab[ u->le->table[ inp_curr( u ) ] ].mnemonic;
+ }
+ /* SWAPGS is only valid in 64bits mode */
+ if ( u->mnemonic == UD_Iswapgs && u->dis_mode != 64 ) {
+ UDERR(u, "swapgs invalid in 64bits mode\n");
+ return -1;
+ }
+
+ if (u->mnemonic == UD_Ixchg) {
+ if ((u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_AX &&
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_AX) ||
+ (u->operand[0].type == UD_OP_REG && u->operand[0].base == UD_R_EAX &&
+ u->operand[1].type == UD_OP_REG && u->operand[1].base == UD_R_EAX)) {
+ u->operand[0].type = UD_NONE;
+ u->operand[1].type = UD_NONE;
+ u->mnemonic = UD_Inop;
+ }
+ }
+
+ if (u->mnemonic == UD_Inop && u->pfx_repe) {
+ u->pfx_repe = 0;
+ u->mnemonic = UD_Ipause;
+ }
+ return 0;
+}
+
+
+/* -----------------------------------------------------------------------------
+ * decode_a()- Decodes operands of the type seg:offset
+ * -----------------------------------------------------------------------------
+ */
+static void
+decode_a(struct ud* u, struct ud_operand *op)
+{
+ if (u->opr_mode == 16) {
+ /* seg16:off16 */
+ op->type = UD_OP_PTR;
+ op->size = 32;
+ op->lval.ptr.off = inp_uint16(u);
+ op->lval.ptr.seg = inp_uint16(u);
+ } else {
+ /* seg16:off32 */
+ op->type = UD_OP_PTR;
+ op->size = 48;
+ op->lval.ptr.off = inp_uint32(u);
+ op->lval.ptr.seg = inp_uint16(u);
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * decode_gpr() - Returns decoded General Purpose Register
+ * -----------------------------------------------------------------------------
+ */
+static enum ud_type
+decode_gpr(register struct ud* u, unsigned int s, unsigned char rm)
+{
+ switch (s) {
+ case 64:
+ return UD_R_RAX + rm;
+ case 32:
+ return UD_R_EAX + rm;
+ case 16:
+ return UD_R_AX + rm;
+ case 8:
+ if (u->dis_mode == 64 && u->pfx_rex) {
+ if (rm >= 4)
+ return UD_R_SPL + (rm-4);
+ return UD_R_AL + rm;
+ } else return UD_R_AL + rm;
+ case 0:
+ /* invalid size in case of a decode error */
+ UD_ASSERT(u->error);
+ return UD_NONE;
+ default:
+ UD_ASSERT(!"invalid operand size");
+ return UD_NONE;
+ }
+}
+
+static void
+decode_reg(struct ud *u,
+ struct ud_operand *opr,
+ int type,
+ int num,
+ int size)
+{
+ int reg;
+ size = resolve_operand_size(u, size);
+ switch (type) {
+ case REGCLASS_GPR : reg = decode_gpr(u, size, num); break;
+ case REGCLASS_MMX : reg = UD_R_MM0 + (num & 7); break;
+ case REGCLASS_XMM :
+ reg = num + (size == SZ_QQ ? UD_R_YMM0 : UD_R_XMM0);
+ break;
+ case REGCLASS_CR : reg = UD_R_CR0 + num; break;
+ case REGCLASS_DB : reg = UD_R_DR0 + num; break;
+ case REGCLASS_SEG : {
+ /*
+ * Only 6 segment registers, anything else is an error.
+ */
+ if ((num & 7) > 5) {
+ UDERR(u, "invalid segment register value\n");
+ return;
+ } else {
+ reg = UD_R_ES + (num & 7);
+ }
+ break;
+ }
+ default:
+ UD_ASSERT(!"invalid register type");
+ return;
+ }
+ opr->type = UD_OP_REG;
+ opr->base = reg;
+ opr->size = size;
+}
+
+
+/*
+ * decode_imm
+ *
+ * Decode Immediate values.
+ */
+static void
+decode_imm(struct ud* u, unsigned int size, struct ud_operand *op)
+{
+ op->size = resolve_operand_size(u, size);
+ op->type = UD_OP_IMM;
+
+ switch (op->size) {
+ case 8: op->lval.sbyte = inp_uint8(u); break;
+ case 16: op->lval.uword = inp_uint16(u); break;
+ case 32: op->lval.udword = inp_uint32(u); break;
+ case 64: op->lval.uqword = inp_uint64(u); break;
+ default: return;
+ }
+}
+
+
+/*
+ * decode_mem_disp
+ *
+ * Decode mem address displacement.
+ */
+static void
+decode_mem_disp(struct ud* u, unsigned int size, struct ud_operand *op)
+{
+ switch (size) {
+ case 8:
+ op->offset = 8;
+ op->lval.ubyte = inp_uint8(u);
+ break;
+ case 16:
+ op->offset = 16;
+ op->lval.uword = inp_uint16(u);
+ break;
+ case 32:
+ op->offset = 32;
+ op->lval.udword = inp_uint32(u);
+ break;
+ case 64:
+ op->offset = 64;
+ op->lval.uqword = inp_uint64(u);
+ break;
+ default:
+ return;
+ }
+}
+
+
+/*
+ * decode_modrm_reg
+ *
+ * Decodes reg field of mod/rm byte
+ *
+ */
+static UD_INLINE void
+decode_modrm_reg(struct ud *u,
+ struct ud_operand *operand,
+ unsigned int type,
+ unsigned int size)
+{
+ uint8_t reg = (REX_R(u->_rex) << 3) | MODRM_REG(modrm(u));
+ decode_reg(u, operand, type, reg, size);
+}
+
+
+/*
+ * decode_modrm_rm
+ *
+ * Decodes rm field of mod/rm byte
+ *
+ */
+static void
+decode_modrm_rm(struct ud *u,
+ struct ud_operand *op,
+ unsigned char type, /* register type */
+ unsigned int size) /* operand size */
+
+{
+ size_t offset = 0;
+ unsigned char mod, rm;
+
+ /* get mod, r/m and reg fields */
+ mod = MODRM_MOD(modrm(u));
+ rm = (REX_B(u->_rex) << 3) | MODRM_RM(modrm(u));
+
+ /*
+ * If mod is 11b, then the modrm.rm specifies a register.
+ *
+ */
+ if (mod == 3) {
+ decode_reg(u, op, type, rm, size);
+ return;
+ }
+
+ /*
+ * !11b => Memory Address
+ */
+ op->type = UD_OP_MEM;
+ op->size = resolve_operand_size(u, size);
+
+ if (u->adr_mode == 64) {
+ op->base = UD_R_RAX + rm;
+ if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 32;
+ } else if (mod == 0 && (rm & 7) == 5) {
+ op->base = UD_R_RIP;
+ offset = 32;
+ } else {
+ offset = 0;
+ }
+ /*
+ * Scale-Index-Base (SIB)
+ */
+ if ((rm & 7) == 4) {
+ inp_next(u);
+
+ op->base = UD_R_RAX + (SIB_B(inp_curr(u)) | (REX_B(u->_rex) << 3));
+ op->index = UD_R_RAX + (SIB_I(inp_curr(u)) | (REX_X(u->_rex) << 3));
+ /* special conditions for base reference */
+ if (op->index == UD_R_RSP) {
+ op->index = UD_NONE;
+ op->scale = UD_NONE;
+ } else {
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
+ }
+
+ if (op->base == UD_R_RBP || op->base == UD_R_R13) {
+ if (mod == 0) {
+ op->base = UD_NONE;
+ }
+ if (mod == 1) {
+ offset = 8;
+ } else {
+ offset = 32;
+ }
+ }
+ } else {
+ op->scale = UD_NONE;
+ op->index = UD_NONE;
+ }
+ } else if (u->adr_mode == 32) {
+ op->base = UD_R_EAX + rm;
+ if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 32;
+ } else if (mod == 0 && rm == 5) {
+ op->base = UD_NONE;
+ offset = 32;
+ } else {
+ offset = 0;
+ }
+
+ /* Scale-Index-Base (SIB) */
+ if ((rm & 7) == 4) {
+ inp_next(u);
+
+ op->scale = (1 << SIB_S(inp_curr(u))) & ~1;
+ op->index = UD_R_EAX + (SIB_I(inp_curr(u)) | (REX_X(u->pfx_rex) << 3));
+ op->base = UD_R_EAX + (SIB_B(inp_curr(u)) | (REX_B(u->pfx_rex) << 3));
+
+ if (op->index == UD_R_ESP) {
+ op->index = UD_NONE;
+ op->scale = UD_NONE;
+ }
+
+ /* special condition for base reference */
+ if (op->base == UD_R_EBP) {
+ if (mod == 0) {
+ op->base = UD_NONE;
+ }
+ if (mod == 1) {
+ offset = 8;
+ } else {
+ offset = 32;
+ }
+ }
+ } else {
+ op->scale = UD_NONE;
+ op->index = UD_NONE;
+ }
+ } else {
+ const unsigned int bases[] = { UD_R_BX, UD_R_BX, UD_R_BP, UD_R_BP,
+ UD_R_SI, UD_R_DI, UD_R_BP, UD_R_BX };
+ const unsigned int indices[] = { UD_R_SI, UD_R_DI, UD_R_SI, UD_R_DI,
+ UD_NONE, UD_NONE, UD_NONE, UD_NONE };
+ op->base = bases[rm & 7];
+ op->index = indices[rm & 7];
+ op->scale = UD_NONE;
+ if (mod == 0 && rm == 6) {
+ offset = 16;
+ op->base = UD_NONE;
+ } else if (mod == 1) {
+ offset = 8;
+ } else if (mod == 2) {
+ offset = 16;
+ }
+ }
+
+ if (offset) {
+ decode_mem_disp(u, offset, op);
+ } else {
+ op->offset = 0;
+ }
+}
+
+
+/*
+ * decode_moffset
+ * Decode offset-only memory operand
+ */
+static void
+decode_moffset(struct ud *u, unsigned int size, struct ud_operand *opr)
+{
+ opr->type = UD_OP_MEM;
+ opr->base = UD_NONE;
+ opr->index = UD_NONE;
+ opr->scale = UD_NONE;
+ opr->size = resolve_operand_size(u, size);
+ decode_mem_disp(u, u->adr_mode, opr);
+}
+
+
+static void
+decode_vex_vvvv(struct ud *u, struct ud_operand *opr, unsigned size)
+{
+ uint8_t vvvv;
+ UD_ASSERT(u->vex_op != 0);
+ vvvv = ((u->vex_op == 0xc4 ? u->vex_b2 : u->vex_b1) >> 3) & 0xf;
+ decode_reg(u, opr, REGCLASS_XMM, (0xf & ~vvvv), size);
+}
+
+
+/*
+ * decode_vex_immreg
+ * Decode source operand encoded in immediate byte [7:4]
+ */
+static int
+decode_vex_immreg(struct ud *u, struct ud_operand *opr, unsigned size)
+{
+ uint8_t imm = inp_next(u);
+ uint8_t mask = u->dis_mode == 64 ? 0xf : 0x7;
+ UD_RETURN_ON_ERROR(u);
+ UD_ASSERT(u->vex_op != 0);
+ decode_reg(u, opr, REGCLASS_XMM, mask & (imm >> 4), size);
+ return 0;
+}
+
+
+/*
+ * decode_operand
+ *
+ * Decodes a single operand.
+ * Returns the type of the operand (UD_NONE if none)
+ */
+static int
+decode_operand(struct ud *u,
+ struct ud_operand *operand,
+ enum ud_operand_code type,
+ unsigned int size)
+{
+ operand->type = UD_NONE;
+ operand->_oprcode = type;
+
+ switch (type) {
+ case OP_A :
+ decode_a(u, operand);
+ break;
+ case OP_MR:
+ decode_modrm_rm(u, operand, REGCLASS_GPR,
+ MODRM_MOD(modrm(u)) == 3 ?
+ Mx_reg_size(size) : Mx_mem_size(size));
+ break;
+ case OP_F:
+ u->br_far = 1;
+ /* intended fall through */
+ case OP_M:
+ if (MODRM_MOD(modrm(u)) == 3) {
+ UDERR(u, "expected modrm.mod != 3\n");
+ }
+ /* intended fall through */
+ case OP_E:
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_G:
+ decode_modrm_reg(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_sI:
+ case OP_I:
+ decode_imm(u, size, operand);
+ break;
+ case OP_I1:
+ operand->type = UD_OP_CONST;
+ operand->lval.udword = 1;
+ break;
+ case OP_N:
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ /* intended fall through */
+ case OP_Q:
+ decode_modrm_rm(u, operand, REGCLASS_MMX, size);
+ break;
+ case OP_P:
+ decode_modrm_reg(u, operand, REGCLASS_MMX, size);
+ break;
+ case OP_U:
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ /* intended fall through */
+ case OP_W:
+ decode_modrm_rm(u, operand, REGCLASS_XMM, size);
+ break;
+ case OP_V:
+ decode_modrm_reg(u, operand, REGCLASS_XMM, size);
+ break;
+ case OP_H:
+ decode_vex_vvvv(u, operand, size);
+ break;
+ case OP_MU:
+ decode_modrm_rm(u, operand, REGCLASS_XMM,
+ MODRM_MOD(modrm(u)) == 3 ?
+ Mx_reg_size(size) : Mx_mem_size(size));
+ break;
+ case OP_S:
+ decode_modrm_reg(u, operand, REGCLASS_SEG, size);
+ break;
+ case OP_O:
+ decode_moffset(u, size, operand);
+ break;
+ case OP_R0:
+ case OP_R1:
+ case OP_R2:
+ case OP_R3:
+ case OP_R4:
+ case OP_R5:
+ case OP_R6:
+ case OP_R7:
+ decode_reg(u, operand, REGCLASS_GPR,
+ (REX_B(u->_rex) << 3) | (type - OP_R0), size);
+ break;
+ case OP_AL:
+ case OP_AX:
+ case OP_eAX:
+ case OP_rAX:
+ decode_reg(u, operand, REGCLASS_GPR, 0, size);
+ break;
+ case OP_CL:
+ case OP_CX:
+ case OP_eCX:
+ decode_reg(u, operand, REGCLASS_GPR, 1, size);
+ break;
+ case OP_DL:
+ case OP_DX:
+ case OP_eDX:
+ decode_reg(u, operand, REGCLASS_GPR, 2, size);
+ break;
+ case OP_ES:
+ case OP_CS:
+ case OP_DS:
+ case OP_SS:
+ case OP_FS:
+ case OP_GS:
+ /* in 64bits mode, only fs and gs are allowed */
+ if (u->dis_mode == 64) {
+ if (type != OP_FS && type != OP_GS) {
+ UDERR(u, "invalid segment register in 64bits\n");
+ }
+ }
+ operand->type = UD_OP_REG;
+ operand->base = (type - OP_ES) + UD_R_ES;
+ operand->size = 16;
+ break;
+ case OP_J :
+ decode_imm(u, size, operand);
+ operand->type = UD_OP_JIMM;
+ break ;
+ case OP_R :
+ if (MODRM_MOD(modrm(u)) != 3) {
+ UDERR(u, "expected modrm.mod == 3\n");
+ }
+ decode_modrm_rm(u, operand, REGCLASS_GPR, size);
+ break;
+ case OP_C:
+ decode_modrm_reg(u, operand, REGCLASS_CR, size);
+ break;
+ case OP_D:
+ decode_modrm_reg(u, operand, REGCLASS_DB, size);
+ break;
+ case OP_I3 :
+ operand->type = UD_OP_CONST;
+ operand->lval.sbyte = 3;
+ break;
+ case OP_ST0:
+ case OP_ST1:
+ case OP_ST2:
+ case OP_ST3:
+ case OP_ST4:
+ case OP_ST5:
+ case OP_ST6:
+ case OP_ST7:
+ operand->type = UD_OP_REG;
+ operand->base = (type - OP_ST0) + UD_R_ST0;
+ operand->size = 80;
+ break;
+ case OP_L:
+ decode_vex_immreg(u, operand, size);
+ break;
+ default :
+ operand->type = UD_NONE;
+ break;
+ }
+ return operand->type;
+}
+
+
+/*
+ * decode_operands
+ *
+ * Disassemble upto 3 operands of the current instruction being
+ * disassembled. By the end of the function, the operand fields
+ * of the ud structure will have been filled.
+ */
+static int
+decode_operands(struct ud* u)
+{
+ decode_operand(u, &u->operand[0],
+ u->itab_entry->operand1.type,
+ u->itab_entry->operand1.size);
+ if (u->operand[0].type != UD_NONE) {
+ decode_operand(u, &u->operand[1],
+ u->itab_entry->operand2.type,
+ u->itab_entry->operand2.size);
+ }
+ if (u->operand[1].type != UD_NONE) {
+ decode_operand(u, &u->operand[2],
+ u->itab_entry->operand3.type,
+ u->itab_entry->operand3.size);
+ }
+ if (u->operand[2].type != UD_NONE) {
+ decode_operand(u, &u->operand[3],
+ u->itab_entry->operand4.type,
+ u->itab_entry->operand4.size);
+ }
+ return 0;
+}
+
+/* -----------------------------------------------------------------------------
+ * clear_insn() - clear instruction structure
+ * -----------------------------------------------------------------------------
+ */
+static void
+clear_insn(register struct ud* u)
+{
+ u->error = 0;
+ u->pfx_seg = 0;
+ u->pfx_opr = 0;
+ u->pfx_adr = 0;
+ u->pfx_lock = 0;
+ u->pfx_repne = 0;
+ u->pfx_rep = 0;
+ u->pfx_repe = 0;
+ u->pfx_rex = 0;
+ u->pfx_str = 0;
+ u->mnemonic = UD_Inone;
+ u->itab_entry = NULL;
+ u->have_modrm = 0;
+ u->br_far = 0;
+ u->vex_op = 0;
+ u->_rex = 0;
+ u->operand[0].type = UD_NONE;
+ u->operand[1].type = UD_NONE;
+ u->operand[2].type = UD_NONE;
+ u->operand[3].type = UD_NONE;
+}
+
+
+static UD_INLINE int
+resolve_pfx_str(struct ud* u)
+{
+ if (u->pfx_str == 0xf3) {
+ if (P_STR(u->itab_entry->prefix)) {
+ u->pfx_rep = 0xf3;
+ } else {
+ u->pfx_repe = 0xf3;
+ }
+ } else if (u->pfx_str == 0xf2) {
+ u->pfx_repne = 0xf3;
+ }
+ return 0;
+}
+
+
+static int
+resolve_mode( struct ud* u )
+{
+ int default64;
+ /* if in error state, bail out */
+ if ( u->error ) return -1;
+
+ /* propagate prefix effects */
+ if ( u->dis_mode == 64 ) { /* set 64bit-mode flags */
+
+ /* Check validity of instruction m64 */
+ if ( P_INV64( u->itab_entry->prefix ) ) {
+ UDERR(u, "instruction invalid in 64bits\n");
+ return -1;
+ }
+
+ /* compute effective rex based on,
+ * - vex prefix (if any)
+ * - rex prefix (if any, and not vex)
+ * - allowed prefixes specified by the opcode map
+ */
+ if (u->vex_op == 0xc4) {
+ /* vex has rex.rxb in 1's complement */
+ u->_rex = ((~(u->vex_b1 >> 5) & 0x7) /* rex.0rxb */ |
+ ((u->vex_b2 >> 4) & 0x8) /* rex.w000 */);
+ } else if (u->vex_op == 0xc5) {
+ /* vex has rex.r in 1's complement */
+ u->_rex = (~(u->vex_b1 >> 5)) & 4;
+ } else {
+ UD_ASSERT(u->vex_op == 0);
+ u->_rex = u->pfx_rex;
+ }
+ u->_rex &= REX_PFX_MASK(u->itab_entry->prefix);
+
+ /* whether this instruction has a default operand size of
+ * 64bit, also hardcoded into the opcode map.
+ */
+ default64 = P_DEF64( u->itab_entry->prefix );
+ /* calculate effective operand size */
+ if (REX_W(u->_rex)) {
+ u->opr_mode = 64;
+ } else if ( u->pfx_opr ) {
+ u->opr_mode = 16;
+ } else {
+ /* unless the default opr size of instruction is 64,
+ * the effective operand size in the absence of rex.w
+ * prefix is 32.
+ */
+ u->opr_mode = default64 ? 64 : 32;
+ }
+
+ /* calculate effective address size */
+ u->adr_mode = (u->pfx_adr) ? 32 : 64;
+ } else if ( u->dis_mode == 32 ) { /* set 32bit-mode flags */
+ u->opr_mode = ( u->pfx_opr ) ? 16 : 32;
+ u->adr_mode = ( u->pfx_adr ) ? 16 : 32;
+ } else if ( u->dis_mode == 16 ) { /* set 16bit-mode flags */
+ u->opr_mode = ( u->pfx_opr ) ? 32 : 16;
+ u->adr_mode = ( u->pfx_adr ) ? 32 : 16;
+ }
+
+ return 0;
+}
+
+
+static UD_INLINE int
+decode_insn(struct ud *u, uint16_t ptr)
+{
+ UD_ASSERT((ptr & 0x8000) == 0);
+ u->itab_entry = &ud_itab[ ptr ];
+ u->mnemonic = u->itab_entry->mnemonic;
+ return (resolve_pfx_str(u) == 0 &&
+ resolve_mode(u) == 0 &&
+ decode_operands(u) == 0 &&
+ resolve_mnemonic(u) == 0) ? 0 : -1;
+}
+
+
+/*
+ * decode_3dnow()
+ *
+ * Decoding 3dnow is a little tricky because of its strange opcode
+ * structure. The final opcode disambiguation depends on the last
+ * byte that comes after the operands have been decoded. Fortunately,
+ * all 3dnow instructions have the same set of operand types. So we
+ * go ahead and decode the instruction by picking an arbitrarily chosen
+ * valid entry in the table, decode the operands, and read the final
+ * byte to resolve the menmonic.
+ */
+static UD_INLINE int
+decode_3dnow(struct ud* u)
+{
+ uint16_t ptr;
+ UD_ASSERT(u->le->type == UD_TAB__OPC_3DNOW);
+ UD_ASSERT(u->le->table[0xc] != 0);
+ decode_insn(u, u->le->table[0xc]);
+ inp_next(u);
+ if (u->error) {
+ return -1;
+ }
+ ptr = u->le->table[inp_curr(u)];
+ UD_ASSERT((ptr & 0x8000) == 0);
+ u->mnemonic = ud_itab[ptr].mnemonic;
+ return 0;
+}
+
+
+static int
+decode_ssepfx(struct ud *u)
+{
+ uint8_t idx;
+ uint8_t pfx;
+
+ /*
+ * String prefixes (f2, f3) take precedence over operand
+ * size prefix (66).
+ */
+ pfx = u->pfx_str;
+ if (pfx == 0) {
+ pfx = u->pfx_opr;
+ }
+ idx = ((pfx & 0xf) + 1) / 2;
+ if (u->le->table[idx] == 0) {
+ idx = 0;
+ }
+ if (idx && u->le->table[idx] != 0) {
+ /*
+ * "Consume" the prefix as a part of the opcode, so it is no
+ * longer exported as an instruction prefix.
+ */
+ u->pfx_str = 0;
+ if (pfx == 0x66) {
+ /*
+ * consume "66" only if it was used for decoding, leaving
+ * it to be used as an operands size override for some
+ * simd instructions.
+ */
+ u->pfx_opr = 0;
+ }
+ }
+ return decode_ext(u, u->le->table[idx]);
+}
+
+
+static int
+decode_vex(struct ud *u)
+{
+ uint8_t index;
+ if (u->dis_mode != 64 && MODRM_MOD(inp_peek(u)) != 0x3) {
+ index = 0;
+ } else {
+ u->vex_op = inp_curr(u);
+ u->vex_b1 = inp_next(u);
+ if (u->vex_op == 0xc4) {
+ uint8_t pp, m;
+ /* 3-byte vex */
+ u->vex_b2 = inp_next(u);
+ UD_RETURN_ON_ERROR(u);
+ m = u->vex_b1 & 0x1f;
+ if (m == 0 || m > 3) {
+ UD_RETURN_WITH_ERROR(u, "reserved vex.m-mmmm value");
+ }
+ pp = u->vex_b2 & 0x3;
+ index = (pp << 2) | m;
+ } else {
+ /* 2-byte vex */
+ UD_ASSERT(u->vex_op == 0xc5);
+ index = 0x1 | ((u->vex_b1 & 0x3) << 2);
+ }
+ }
+ return decode_ext(u, u->le->table[index]);
+}
+
+
+/*
+ * decode_ext()
+ *
+ * Decode opcode extensions (if any)
+ */
+static int
+decode_ext(struct ud *u, uint16_t ptr)
+{
+ uint8_t idx = 0;
+ if ((ptr & 0x8000) == 0) {
+ return decode_insn(u, ptr);
+ }
+ u->le = &ud_lookup_table_list[(~0x8000 & ptr)];
+ if (u->le->type == UD_TAB__OPC_3DNOW) {
+ return decode_3dnow(u);
+ }
+
+ switch (u->le->type) {
+ case UD_TAB__OPC_MOD:
+ /* !11 = 0, 11 = 1 */
+ idx = (MODRM_MOD(modrm(u)) + 1) / 4;
+ break;
+ /* disassembly mode/operand size/address size based tables.
+ * 16 = 0,, 32 = 1, 64 = 2
+ */
+ case UD_TAB__OPC_MODE:
+ idx = u->dis_mode != 64 ? 0 : 1;
+ break;
+ case UD_TAB__OPC_OSIZE:
+ idx = eff_opr_mode(u->dis_mode, REX_W(u->pfx_rex), u->pfx_opr) / 32;
+ break;
+ case UD_TAB__OPC_ASIZE:
+ idx = eff_adr_mode(u->dis_mode, u->pfx_adr) / 32;
+ break;
+ case UD_TAB__OPC_X87:
+ idx = modrm(u) - 0xC0;
+ break;
+ case UD_TAB__OPC_VENDOR:
+ if (u->vendor == UD_VENDOR_ANY) {
+ /* choose a valid entry */
+ idx = (u->le->table[idx] != 0) ? 0 : 1;
+ } else if (u->vendor == UD_VENDOR_AMD) {
+ idx = 0;
+ } else {
+ idx = 1;
+ }
+ break;
+ case UD_TAB__OPC_RM:
+ idx = MODRM_RM(modrm(u));
+ break;
+ case UD_TAB__OPC_REG:
+ idx = MODRM_REG(modrm(u));
+ break;
+ case UD_TAB__OPC_SSE:
+ return decode_ssepfx(u);
+ case UD_TAB__OPC_VEX:
+ return decode_vex(u);
+ case UD_TAB__OPC_VEX_W:
+ idx = vex_w(u);
+ break;
+ case UD_TAB__OPC_VEX_L:
+ idx = vex_l(u);
+ break;
+ case UD_TAB__OPC_TABLE:
+ inp_next(u);
+ return decode_opcode(u);
+ default:
+ UD_ASSERT(!"not reached");
+ break;
+ }
+
+ return decode_ext(u, u->le->table[idx]);
+}
+
+
+static int
+decode_opcode(struct ud *u)
+{
+ uint16_t ptr;
+ UD_ASSERT(u->le->type == UD_TAB__OPC_TABLE);
+ UD_RETURN_ON_ERROR(u);
+ ptr = u->le->table[inp_curr(u)];
+ return decode_ext(u, ptr);
+}
+
+
+/* =============================================================================
+ * ud_decode() - Instruction decoder. Returns the number of bytes decoded.
+ * =============================================================================
+ */
+unsigned int
+ud_decode(struct ud *u)
+{
+ inp_start(u);
+ clear_insn(u);
+ u->le = &ud_lookup_table_list[0];
+ u->error = decode_prefixes(u) == -1 ||
+ decode_opcode(u) == -1 ||
+ u->error;
+ /* Handle decode error. */
+ if (u->error) {
+ /* clear out the decode data. */
+ clear_insn(u);
+ /* mark the sequence of bytes as invalid. */
+ u->itab_entry = &ud_itab[0]; /* entry 0 is invalid */
+ u->mnemonic = u->itab_entry->mnemonic;
+ }
+
+ /* maybe this stray segment override byte
+ * should be spewed out?
+ */
+ if ( !P_SEG( u->itab_entry->prefix ) &&
+ u->operand[0].type != UD_OP_MEM &&
+ u->operand[1].type != UD_OP_MEM )
+ u->pfx_seg = 0;
+
+ u->insn_offset = u->pc; /* set offset of instruction */
+ u->asm_buf_fill = 0; /* set translation buffer index to 0 */
+ u->pc += u->inp_ctr; /* move program counter by bytes decoded */
+
+ /* return number of bytes disassembled. */
+ return u->inp_ctr;
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/decode.h b/src/3p/udis86/decode.h
new file mode 100644
index 0000000..3949c4e
--- /dev/null
+++ b/src/3p/udis86/decode.h
@@ -0,0 +1,197 @@
+/* udis86 - libudis86/decode.h
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_DECODE_H
+#define UD_DECODE_H
+
+#include "types.h"
+#include "udint.h"
+#include "itab.h"
+
+#define MAX_INSN_LENGTH 15
+
+/* itab prefix bits */
+#define P_none ( 0 )
+
+#define P_inv64 ( 1 << 0 )
+#define P_INV64(n) ( ( n >> 0 ) & 1 )
+#define P_def64 ( 1 << 1 )
+#define P_DEF64(n) ( ( n >> 1 ) & 1 )
+
+#define P_oso ( 1 << 2 )
+#define P_OSO(n) ( ( n >> 2 ) & 1 )
+#define P_aso ( 1 << 3 )
+#define P_ASO(n) ( ( n >> 3 ) & 1 )
+
+#define P_rexb ( 1 << 4 )
+#define P_REXB(n) ( ( n >> 4 ) & 1 )
+#define P_rexw ( 1 << 5 )
+#define P_REXW(n) ( ( n >> 5 ) & 1 )
+#define P_rexr ( 1 << 6 )
+#define P_REXR(n) ( ( n >> 6 ) & 1 )
+#define P_rexx ( 1 << 7 )
+#define P_REXX(n) ( ( n >> 7 ) & 1 )
+
+#define P_seg ( 1 << 8 )
+#define P_SEG(n) ( ( n >> 8 ) & 1 )
+
+#define P_vexl ( 1 << 9 )
+#define P_VEXL(n) ( ( n >> 9 ) & 1 )
+#define P_vexw ( 1 << 10 )
+#define P_VEXW(n) ( ( n >> 10 ) & 1 )
+
+#define P_str ( 1 << 11 )
+#define P_STR(n) ( ( n >> 11 ) & 1 )
+#define P_strz ( 1 << 12 )
+#define P_STR_ZF(n) ( ( n >> 12 ) & 1 )
+
+/* operand type constants -- order is important! */
+
+enum ud_operand_code {
+ OP_NONE,
+
+ OP_A, OP_E, OP_M, OP_G,
+ OP_I, OP_F,
+
+ OP_R0, OP_R1, OP_R2, OP_R3,
+ OP_R4, OP_R5, OP_R6, OP_R7,
+
+ OP_AL, OP_CL, OP_DL,
+ OP_AX, OP_CX, OP_DX,
+ OP_eAX, OP_eCX, OP_eDX,
+ OP_rAX, OP_rCX, OP_rDX,
+
+ OP_ES, OP_CS, OP_SS, OP_DS,
+ OP_FS, OP_GS,
+
+ OP_ST0, OP_ST1, OP_ST2, OP_ST3,
+ OP_ST4, OP_ST5, OP_ST6, OP_ST7,
+
+ OP_J, OP_S, OP_O,
+ OP_I1, OP_I3, OP_sI,
+
+ OP_V, OP_W, OP_Q, OP_P,
+ OP_U, OP_N, OP_MU, OP_H,
+ OP_L,
+
+ OP_R, OP_C, OP_D,
+
+ OP_MR
+} UD_ATTR_PACKED;
+
+
+/*
+ * Operand size constants
+ *
+ * Symbolic constants for various operand sizes. Some of these constants
+ * are given a value equal to the width of the data (SZ_B == 8), such
+ * that they maybe used interchangeably in the internals. Modifying them
+ * will most certainly break things!
+ */
+typedef uint16_t ud_operand_size_t;
+
+#define SZ_NA 0
+#define SZ_Z 1
+#define SZ_V 2
+#define SZ_Y 3
+#define SZ_X 4
+#define SZ_RDQ 7
+#define SZ_B 8
+#define SZ_W 16
+#define SZ_D 32
+#define SZ_Q 64
+#define SZ_T 80
+#define SZ_O 12
+#define SZ_DQ 128 /* double quad */
+#define SZ_QQ 256 /* quad quad */
+
+/*
+ * Complex size types; that encode sizes for operands of type MR (memory or
+ * register); for internal use only. Id space above 256.
+ */
+#define SZ_BD ((SZ_B << 8) | SZ_D)
+#define SZ_BV ((SZ_B << 8) | SZ_V)
+#define SZ_WD ((SZ_W << 8) | SZ_D)
+#define SZ_WV ((SZ_W << 8) | SZ_V)
+#define SZ_WY ((SZ_W << 8) | SZ_Y)
+#define SZ_DY ((SZ_D << 8) | SZ_Y)
+#define SZ_WO ((SZ_W << 8) | SZ_O)
+#define SZ_DO ((SZ_D << 8) | SZ_O)
+#define SZ_QO ((SZ_Q << 8) | SZ_O)
+
+
+/* resolve complex size type.
+ */
+static UD_INLINE ud_operand_size_t
+Mx_mem_size(ud_operand_size_t size)
+{
+ return (size >> 8) & 0xff;
+}
+
+static UD_INLINE ud_operand_size_t
+Mx_reg_size(ud_operand_size_t size)
+{
+ return size & 0xff;
+}
+
+/* A single operand of an entry in the instruction table.
+ * (internal use only)
+ */
+struct ud_itab_entry_operand
+{
+ enum ud_operand_code type;
+ ud_operand_size_t size;
+};
+
+
+/* A single entry in an instruction table.
+ *(internal use only)
+ */
+struct ud_itab_entry
+{
+ enum ud_mnemonic_code mnemonic;
+ struct ud_itab_entry_operand operand1;
+ struct ud_itab_entry_operand operand2;
+ struct ud_itab_entry_operand operand3;
+ struct ud_itab_entry_operand operand4;
+ uint32_t prefix;
+};
+
+struct ud_lookup_table_list_entry {
+ const uint16_t *table;
+ enum ud_table_type type;
+ const char *meta;
+};
+
+extern struct ud_itab_entry ud_itab[];
+extern struct ud_lookup_table_list_entry ud_lookup_table_list[];
+
+#endif /* UD_DECODE_H */
+
+/* vim:cindent
+ * vim:expandtab
+ * vim:ts=4
+ * vim:sw=4
+ */
diff --git a/src/3p/udis86/extern.h b/src/3p/udis86/extern.h
new file mode 100644
index 0000000..71a01fd
--- /dev/null
+++ b/src/3p/udis86/extern.h
@@ -0,0 +1,113 @@
+/* udis86 - libudis86/extern.h
+ *
+ * Copyright (c) 2002-2009, 2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_EXTERN_H
+#define UD_EXTERN_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "types.h"
+
+#if defined(_MSC_VER) && defined(_USRDLL)
+# ifdef LIBUDIS86_EXPORTS
+# define LIBUDIS86_DLLEXTERN __declspec(dllexport)
+# else
+# define LIBUDIS86_DLLEXTERN __declspec(dllimport)
+# endif
+#else
+# define LIBUDIS86_DLLEXTERN
+#endif
+
+/* ============================= PUBLIC API ================================= */
+
+extern LIBUDIS86_DLLEXTERN void ud_init(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_mode(struct ud*, uint8_t);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_pc(struct ud*, uint64_t);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_input_hook(struct ud*, int (*)(struct ud*));
+
+extern LIBUDIS86_DLLEXTERN void ud_set_input_buffer(struct ud*, const uint8_t*, size_t);
+
+#ifndef __UD_STANDALONE__
+extern LIBUDIS86_DLLEXTERN void ud_set_input_file(struct ud*, FILE*);
+#endif /* __UD_STANDALONE__ */
+
+extern LIBUDIS86_DLLEXTERN void ud_set_vendor(struct ud*, unsigned);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_syntax(struct ud*, void (*)(struct ud*));
+
+extern LIBUDIS86_DLLEXTERN void ud_input_skip(struct ud*, size_t);
+
+extern LIBUDIS86_DLLEXTERN int ud_input_end(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_decode(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_disassemble(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_translate_intel(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_translate_att(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_insn_asm(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN const uint8_t* ud_insn_ptr(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN uint64_t ud_insn_off(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_insn_hex(struct ud*);
+
+extern LIBUDIS86_DLLEXTERN unsigned int ud_insn_len(const struct ud* u);
+
+extern LIBUDIS86_DLLEXTERN const struct ud_operand* ud_insn_opr(const struct ud *u, unsigned int n);
+
+extern LIBUDIS86_DLLEXTERN int ud_opr_is_sreg(const struct ud_operand *opr);
+
+extern LIBUDIS86_DLLEXTERN int ud_opr_is_gpr(const struct ud_operand *opr);
+
+extern LIBUDIS86_DLLEXTERN enum ud_mnemonic_code ud_insn_mnemonic(const struct ud *u);
+
+extern LIBUDIS86_DLLEXTERN const char* ud_lookup_mnemonic(enum ud_mnemonic_code c);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_user_opaque_data(struct ud*, void*);
+
+extern LIBUDIS86_DLLEXTERN void* ud_get_user_opaque_data(const struct ud*);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_asm_buffer(struct ud *u, char *buf, size_t size);
+
+extern LIBUDIS86_DLLEXTERN void ud_set_sym_resolver(struct ud *u,
+ const char* (*resolver)(struct ud*,
+ uint64_t addr,
+ int64_t *offset));
+
+/* ========================================================================== */
+
+#ifdef __cplusplus
+}
+#endif
+#endif /* UD_EXTERN_H */
diff --git a/src/3p/udis86/itab.c b/src/3p/udis86/itab.c
new file mode 100644
index 0000000..c774223
--- /dev/null
+++ b/src/3p/udis86/itab.c
@@ -0,0 +1,5945 @@
+/* itab.c -- generated by udis86:scripts/ud_itab.py, do no edit */
+#include "decode.h"
+
+#define GROUP(n) (0x8000 | (n))
+#define INVALID 0
+
+const uint16_t ud_itab__0[] = {
+ /* 0 */ 15, 16, 17, 18,
+ /* 4 */ 19, 20, GROUP(1), GROUP(2),
+ /* 8 */ 964, 965, 966, 967,
+ /* c */ 968, 969, GROUP(3), GROUP(4),
+ /* 10 */ 5, 6, 7, 8,
+ /* 14 */ 9, 10, GROUP(284), GROUP(285),
+ /* 18 */ 1336, 1337, 1338, 1339,
+ /* 1c */ 1340, 1341, GROUP(286), GROUP(287),
+ /* 20 */ 49, 50, 51, 52,
+ /* 24 */ 53, 54, INVALID, GROUP(288),
+ /* 28 */ 1407, 1408, 1409, 1410,
+ /* 2c */ 1411, 1412, INVALID, GROUP(289),
+ /* 30 */ 1487, 1488, 1489, 1490,
+ /* 34 */ 1491, 1492, INVALID, GROUP(290),
+ /* 38 */ 100, 101, 102, 103,
+ /* 3c */ 104, 105, INVALID, GROUP(291),
+ /* 40 */ 699, 700, 701, 702,
+ /* 44 */ 703, 704, 705, 706,
+ /* 48 */ 175, 176, 177, 178,
+ /* 4c */ 179, 180, 181, 182,
+ /* 50 */ 1246, 1247, 1248, 1249,
+ /* 54 */ 1250, 1251, 1252, 1253,
+ /* 58 */ 1101, 1102, 1103, 1104,
+ /* 5c */ 1105, 1106, 1107, 1108,
+ /* 60 */ GROUP(292), GROUP(295), GROUP(298), GROUP(299),
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ 1254, 697, 1256, 698,
+ /* 6c */ 709, GROUP(300), 982, GROUP(301),
+ /* 70 */ 726, 728, 730, 732,
+ /* 74 */ 734, 736, 738, 740,
+ /* 78 */ 742, 744, 746, 748,
+ /* 7c */ 750, 752, 754, 756,
+ /* 80 */ GROUP(302), GROUP(303), GROUP(304), GROUP(313),
+ /* 84 */ 1433, 1434, 1475, 1476,
+ /* 88 */ 828, 829, 830, 831,
+ /* 8c */ 832, 770, 833, GROUP(314),
+ /* 90 */ 1477, 1478, 1479, 1480,
+ /* 94 */ 1481, 1482, 1483, 1484,
+ /* 98 */ GROUP(315), GROUP(316), GROUP(317), 1470,
+ /* 9c */ GROUP(318), GROUP(322), 1310, 766,
+ /* a0 */ 834, 835, 836, 837,
+ /* a4 */ 922, GROUP(326), 114, GROUP(327),
+ /* a8 */ 1435, 1436, 1402, GROUP(328),
+ /* ac */ 790, GROUP(329), 1346, GROUP(330),
+ /* b0 */ 838, 839, 840, 841,
+ /* b4 */ 842, 843, 844, 845,
+ /* b8 */ 846, 847, 848, 849,
+ /* bc */ 850, 851, 852, 853,
+ /* c0 */ GROUP(331), GROUP(332), 1301, 1302,
+ /* c4 */ GROUP(333), GROUP(403), GROUP(405), GROUP(406),
+ /* c8 */ 200, 776, 1303, 1304,
+ /* cc */ 713, 714, GROUP(407), GROUP(408),
+ /* d0 */ GROUP(409), GROUP(410), GROUP(411), GROUP(412),
+ /* d4 */ GROUP(413), GROUP(414), GROUP(415), 1486,
+ /* d8 */ GROUP(416), GROUP(419), GROUP(422), GROUP(425),
+ /* dc */ GROUP(428), GROUP(431), GROUP(434), GROUP(437),
+ /* e0 */ 794, 795, 796, GROUP(440),
+ /* e4 */ 690, 691, 978, 979,
+ /* e8 */ 72, 763, GROUP(441), 765,
+ /* ec */ 692, 693, 980, 981,
+ /* f0 */ 789, 712, 1299, 1300,
+ /* f4 */ 687, 83, GROUP(442), GROUP(443),
+ /* f8 */ 77, 1395, 81, 1398,
+ /* fc */ 78, 1396, GROUP(444), GROUP(445),
+};
+
+static const uint16_t ud_itab__1[] = {
+ /* 0 */ 1240, INVALID,
+};
+
+static const uint16_t ud_itab__2[] = {
+ /* 0 */ 1096, INVALID,
+};
+
+static const uint16_t ud_itab__3[] = {
+ /* 0 */ 1241, INVALID,
+};
+
+static const uint16_t ud_itab__4[] = {
+ /* 0 */ GROUP(5), GROUP(6), 767, 797,
+ /* 4 */ INVALID, 1426, 82, 1431,
+ /* 8 */ 716, 1471, INVALID, 1444,
+ /* c */ INVALID, GROUP(27), 430, GROUP(28),
+ /* 10 */ GROUP(29), GROUP(30), GROUP(31), GROUP(34),
+ /* 14 */ GROUP(35), GROUP(36), GROUP(37), GROUP(40),
+ /* 18 */ GROUP(41), 955, 956, 957,
+ /* 1c */ 958, 959, 960, 961,
+ /* 20 */ 854, 855, 856, 857,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ GROUP(42), GROUP(43), GROUP(44), GROUP(45),
+ /* 2c */ GROUP(46), GROUP(47), GROUP(48), GROUP(49),
+ /* 30 */ 1472, 1297, 1295, 1296,
+ /* 34 */ GROUP(50), GROUP(52), INVALID, 1514,
+ /* 38 */ GROUP(54), INVALID, GROUP(116), INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ 84, 85, 86, 87,
+ /* 44 */ 88, 89, 90, 91,
+ /* 48 */ 92, 93, 94, 95,
+ /* 4c */ 96, 97, 98, 99,
+ /* 50 */ GROUP(143), GROUP(144), GROUP(145), GROUP(146),
+ /* 54 */ GROUP(147), GROUP(148), GROUP(149), GROUP(150),
+ /* 58 */ GROUP(151), GROUP(152), GROUP(153), GROUP(154),
+ /* 5c */ GROUP(155), GROUP(156), GROUP(157), GROUP(158),
+ /* 60 */ GROUP(159), GROUP(160), GROUP(161), GROUP(162),
+ /* 64 */ GROUP(163), GROUP(164), GROUP(165), GROUP(166),
+ /* 68 */ GROUP(167), GROUP(168), GROUP(169), GROUP(170),
+ /* 6c */ GROUP(171), GROUP(172), GROUP(173), GROUP(176),
+ /* 70 */ GROUP(177), GROUP(178), GROUP(182), GROUP(186),
+ /* 74 */ GROUP(191), GROUP(192), GROUP(193), 199,
+ /* 78 */ GROUP(194), GROUP(195), INVALID, INVALID,
+ /* 7c */ GROUP(196), GROUP(197), GROUP(198), GROUP(201),
+ /* 80 */ 727, 729, 731, 733,
+ /* 84 */ 735, 737, 739, 741,
+ /* 88 */ 743, 745, 747, 749,
+ /* 8c */ 751, 753, 755, 757,
+ /* 90 */ 1350, 1351, 1352, 1353,
+ /* 94 */ 1354, 1355, 1356, 1357,
+ /* 98 */ 1358, 1359, 1360, 1361,
+ /* 9c */ 1362, 1363, 1364, 1365,
+ /* a0 */ 1245, 1100, 131, 1670,
+ /* a4 */ 1375, 1376, GROUP(202), GROUP(207),
+ /* a8 */ 1244, 1099, 1305, 1675,
+ /* ac */ 1377, 1378, GROUP(215), 694,
+ /* b0 */ 122, 123, 775, 1673,
+ /* b4 */ 772, 773, 940, 941,
+ /* b8 */ GROUP(221), INVALID, GROUP(222), 1671,
+ /* bc */ 1659, 1660, 930, 931,
+ /* c0 */ 1473, 1474, GROUP(223), 904,
+ /* c4 */ GROUP(224), GROUP(225), GROUP(226), GROUP(227),
+ /* c8 */ 1661, 1662, 1663, 1664,
+ /* cc */ 1665, 1666, 1667, 1668,
+ /* d0 */ GROUP(236), GROUP(237), GROUP(238), GROUP(239),
+ /* d4 */ GROUP(240), GROUP(241), GROUP(242), GROUP(243),
+ /* d8 */ GROUP(244), GROUP(245), GROUP(246), GROUP(247),
+ /* dc */ GROUP(248), GROUP(249), GROUP(250), GROUP(251),
+ /* e0 */ GROUP(252), GROUP(253), GROUP(254), GROUP(255),
+ /* e4 */ GROUP(256), GROUP(257), GROUP(258), GROUP(259),
+ /* e8 */ GROUP(260), GROUP(261), GROUP(262), GROUP(263),
+ /* ec */ GROUP(264), GROUP(265), GROUP(266), GROUP(267),
+ /* f0 */ GROUP(268), GROUP(269), GROUP(270), GROUP(271),
+ /* f4 */ GROUP(272), GROUP(273), GROUP(274), GROUP(275),
+ /* f8 */ GROUP(277), GROUP(278), GROUP(279), GROUP(280),
+ /* fc */ GROUP(281), GROUP(282), GROUP(283), INVALID,
+};
+
+static const uint16_t ud_itab__5[] = {
+ /* 0 */ 1384, 1406, 786, 798,
+ /* 4 */ 1453, 1454, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__6[] = {
+ /* 0 */ GROUP(7), GROUP(8),
+};
+
+static const uint16_t ud_itab__7[] = {
+ /* 0 */ 1374, 1383, 785, 774,
+ /* 4 */ 1385, INVALID, 787, 719,
+};
+
+static const uint16_t ud_itab__8[] = {
+ /* 0 */ GROUP(9), GROUP(14), GROUP(15), GROUP(16),
+ /* 4 */ 1386, INVALID, 788, GROUP(25),
+};
+
+static const uint16_t ud_itab__9[] = {
+ /* 0 */ INVALID, GROUP(10), GROUP(11), GROUP(12),
+ /* 4 */ GROUP(13), INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__10[] = {
+ /* 0 */ INVALID, 1455, INVALID,
+};
+
+static const uint16_t ud_itab__11[] = {
+ /* 0 */ INVALID, 1461, INVALID,
+};
+
+static const uint16_t ud_itab__12[] = {
+ /* 0 */ INVALID, 1462, INVALID,
+};
+
+static const uint16_t ud_itab__13[] = {
+ /* 0 */ INVALID, 1463, INVALID,
+};
+
+static const uint16_t ud_itab__14[] = {
+ /* 0 */ 824, 952, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__15[] = {
+ /* 0 */ 1485, 1508, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__16[] = {
+ /* 0 */ GROUP(17), GROUP(18), GROUP(19), GROUP(20),
+ /* 4 */ GROUP(21), GROUP(22), GROUP(23), GROUP(24),
+};
+
+static const uint16_t ud_itab__17[] = {
+ /* 0 */ 1466, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__18[] = {
+ /* 0 */ 1467, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__19[] = {
+ /* 0 */ 1468, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__20[] = {
+ /* 0 */ 1469, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__21[] = {
+ /* 0 */ 1397, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__22[] = {
+ /* 0 */ 80, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__23[] = {
+ /* 0 */ 1399, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__24[] = {
+ /* 0 */ 720, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__25[] = {
+ /* 0 */ 1425, GROUP(26), INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__26[] = {
+ /* 0 */ 1298, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__27[] = {
+ /* 0 */ 1119, 1120, 1121, 1122,
+ /* 4 */ 1123, 1124, 1125, 1126,
+};
+
+static const uint16_t ud_itab__28[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ 1216, 1217, INVALID, INVALID,
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ 1218, 1219, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, 1220, INVALID,
+ /* 8c */ INVALID, INVALID, 1221, INVALID,
+ /* 90 */ 1222, INVALID, INVALID, INVALID,
+ /* 94 */ 1223, INVALID, 1224, 1225,
+ /* 98 */ INVALID, INVALID, 1226, INVALID,
+ /* 9c */ INVALID, INVALID, 1227, INVALID,
+ /* a0 */ 1228, INVALID, INVALID, INVALID,
+ /* a4 */ 1229, INVALID, 1230, 1231,
+ /* a8 */ INVALID, INVALID, 1232, INVALID,
+ /* ac */ INVALID, INVALID, 1233, INVALID,
+ /* b0 */ 1234, INVALID, INVALID, INVALID,
+ /* b4 */ 1235, INVALID, 1236, 1237,
+ /* b8 */ INVALID, INVALID, INVALID, 1238,
+ /* bc */ INVALID, INVALID, INVALID, 1239,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__29[] = {
+ /* 0 */ 936, 925, 928, 932,
+};
+
+static const uint16_t ud_itab__30[] = {
+ /* 0 */ 938, 926, 929, 934,
+};
+
+static const uint16_t ud_itab__31[] = {
+ /* 0 */ GROUP(32), GROUP(33),
+};
+
+static const uint16_t ud_itab__32[] = {
+ /* 0 */ 892, 1563, 1571, 888,
+};
+
+static const uint16_t ud_itab__33[] = {
+ /* 0 */ 896, 1561, 1569, INVALID,
+};
+
+static const uint16_t ud_itab__34[] = {
+ /* 0 */ 894, INVALID, INVALID, 890,
+};
+
+static const uint16_t ud_itab__35[] = {
+ /* 0 */ 1449, INVALID, INVALID, 1451,
+};
+
+static const uint16_t ud_itab__36[] = {
+ /* 0 */ 1447, INVALID, INVALID, 1445,
+};
+
+static const uint16_t ud_itab__37[] = {
+ /* 0 */ GROUP(38), GROUP(39),
+};
+
+static const uint16_t ud_itab__38[] = {
+ /* 0 */ 882, INVALID, 1567, 878,
+};
+
+static const uint16_t ud_itab__39[] = {
+ /* 0 */ 886, INVALID, 1565, INVALID,
+};
+
+static const uint16_t ud_itab__40[] = {
+ /* 0 */ 884, INVALID, INVALID, 880,
+};
+
+static const uint16_t ud_itab__41[] = {
+ /* 0 */ 1127, 1128, 1129, 1130,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__42[] = {
+ /* 0 */ 862, INVALID, INVALID, 858,
+};
+
+static const uint16_t ud_itab__43[] = {
+ /* 0 */ 864, INVALID, INVALID, 860,
+};
+
+static const uint16_t ud_itab__44[] = {
+ /* 0 */ 141, 152, 154, 142,
+};
+
+static const uint16_t ud_itab__45[] = {
+ /* 0 */ 907, INVALID, INVALID, 905,
+};
+
+static const uint16_t ud_itab__46[] = {
+ /* 0 */ 165, 166, 168, 162,
+};
+
+static const uint16_t ud_itab__47[] = {
+ /* 0 */ 147, 148, 158, 138,
+};
+
+static const uint16_t ud_itab__48[] = {
+ /* 0 */ 1442, INVALID, INVALID, 1440,
+};
+
+static const uint16_t ud_itab__49[] = {
+ /* 0 */ 129, INVALID, INVALID, 127,
+};
+
+static const uint16_t ud_itab__50[] = {
+ /* 0 */ 1427, GROUP(51),
+};
+
+static const uint16_t ud_itab__51[] = {
+ /* 0 */ INVALID, 1428, INVALID,
+};
+
+static const uint16_t ud_itab__52[] = {
+ /* 0 */ 1429, GROUP(53),
+};
+
+static const uint16_t ud_itab__53[] = {
+ /* 0 */ INVALID, 1430, INVALID,
+};
+
+static const uint16_t ud_itab__54[] = {
+ /* 0 */ GROUP(67), GROUP(68), GROUP(63), GROUP(64),
+ /* 4 */ GROUP(65), GROUP(66), GROUP(86), GROUP(90),
+ /* 8 */ GROUP(69), GROUP(70), GROUP(71), GROUP(72),
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(73), INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(75), GROUP(76), INVALID, GROUP(77),
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ GROUP(78), GROUP(79), GROUP(80), INVALID,
+ /* 20 */ GROUP(81), GROUP(82), GROUP(83), GROUP(84),
+ /* 24 */ GROUP(85), GROUP(108), INVALID, INVALID,
+ /* 28 */ GROUP(87), GROUP(88), GROUP(89), GROUP(74),
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ GROUP(91), GROUP(92), GROUP(93), GROUP(94),
+ /* 34 */ GROUP(95), GROUP(96), INVALID, GROUP(97),
+ /* 38 */ GROUP(98), GROUP(99), GROUP(100), GROUP(101),
+ /* 3c */ GROUP(102), GROUP(103), GROUP(104), GROUP(105),
+ /* 40 */ GROUP(106), GROUP(107), INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ GROUP(55), GROUP(59), INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, GROUP(109),
+ /* dc */ GROUP(110), GROUP(111), GROUP(112), GROUP(113),
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ GROUP(114), GROUP(115), INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__55[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(56),
+};
+
+static const uint16_t ud_itab__56[] = {
+ /* 0 */ GROUP(57), GROUP(58),
+};
+
+static const uint16_t ud_itab__57[] = {
+ /* 0 */ INVALID, 717, INVALID,
+};
+
+static const uint16_t ud_itab__58[] = {
+ /* 0 */ INVALID, 718, INVALID,
+};
+
+static const uint16_t ud_itab__59[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(60),
+};
+
+static const uint16_t ud_itab__60[] = {
+ /* 0 */ GROUP(61), GROUP(62),
+};
+
+static const uint16_t ud_itab__61[] = {
+ /* 0 */ INVALID, 721, INVALID,
+};
+
+static const uint16_t ud_itab__62[] = {
+ /* 0 */ INVALID, 722, INVALID,
+};
+
+static const uint16_t ud_itab__63[] = {
+ /* 0 */ 1588, INVALID, INVALID, 1589,
+};
+
+static const uint16_t ud_itab__64[] = {
+ /* 0 */ 1591, INVALID, INVALID, 1592,
+};
+
+static const uint16_t ud_itab__65[] = {
+ /* 0 */ 1594, INVALID, INVALID, 1595,
+};
+
+static const uint16_t ud_itab__66[] = {
+ /* 0 */ 1597, INVALID, INVALID, 1598,
+};
+
+static const uint16_t ud_itab__67[] = {
+ /* 0 */ 1582, INVALID, INVALID, 1583,
+};
+
+static const uint16_t ud_itab__68[] = {
+ /* 0 */ 1585, INVALID, INVALID, 1586,
+};
+
+static const uint16_t ud_itab__69[] = {
+ /* 0 */ 1606, INVALID, INVALID, 1607,
+};
+
+static const uint16_t ud_itab__70[] = {
+ /* 0 */ 1612, INVALID, INVALID, 1613,
+};
+
+static const uint16_t ud_itab__71[] = {
+ /* 0 */ 1609, INVALID, INVALID, 1610,
+};
+
+static const uint16_t ud_itab__72[] = {
+ /* 0 */ 1615, INVALID, INVALID, 1616,
+};
+
+static const uint16_t ud_itab__73[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1621,
+};
+
+static const uint16_t ud_itab__74[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1683,
+};
+
+static const uint16_t ud_itab__75[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1657,
+};
+
+static const uint16_t ud_itab__76[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1656,
+};
+
+static const uint16_t ud_itab__77[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1711,
+};
+
+static const uint16_t ud_itab__78[] = {
+ /* 0 */ 1573, INVALID, INVALID, 1574,
+};
+
+static const uint16_t ud_itab__79[] = {
+ /* 0 */ 1576, INVALID, INVALID, 1577,
+};
+
+static const uint16_t ud_itab__80[] = {
+ /* 0 */ 1579, INVALID, INVALID, 1580,
+};
+
+static const uint16_t ud_itab__81[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1685,
+};
+
+static const uint16_t ud_itab__82[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1687,
+};
+
+static const uint16_t ud_itab__83[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1689,
+};
+
+static const uint16_t ud_itab__84[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1691,
+};
+
+static const uint16_t ud_itab__85[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1693,
+};
+
+static const uint16_t ud_itab__86[] = {
+ /* 0 */ 1600, INVALID, INVALID, 1601,
+};
+
+static const uint16_t ud_itab__87[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1622,
+};
+
+static const uint16_t ud_itab__88[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1708,
+};
+
+static const uint16_t ud_itab__89[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1681,
+};
+
+static const uint16_t ud_itab__90[] = {
+ /* 0 */ 1603, INVALID, INVALID, 1604,
+};
+
+static const uint16_t ud_itab__91[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1696,
+};
+
+static const uint16_t ud_itab__92[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1698,
+};
+
+static const uint16_t ud_itab__93[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1700,
+};
+
+static const uint16_t ud_itab__94[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1702,
+};
+
+static const uint16_t ud_itab__95[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1704,
+};
+
+static const uint16_t ud_itab__96[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1706,
+};
+
+static const uint16_t ud_itab__97[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1717,
+};
+
+static const uint16_t ud_itab__98[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1624,
+};
+
+static const uint16_t ud_itab__99[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1626,
+};
+
+static const uint16_t ud_itab__100[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1628,
+};
+
+static const uint16_t ud_itab__101[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1630,
+};
+
+static const uint16_t ud_itab__102[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1632,
+};
+
+static const uint16_t ud_itab__103[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1634,
+};
+
+static const uint16_t ud_itab__104[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1638,
+};
+
+static const uint16_t ud_itab__105[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1636,
+};
+
+static const uint16_t ud_itab__106[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1640,
+};
+
+static const uint16_t ud_itab__107[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1642,
+};
+
+static const uint16_t ud_itab__108[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1695,
+};
+
+static const uint16_t ud_itab__109[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 45,
+};
+
+static const uint16_t ud_itab__110[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 41,
+};
+
+static const uint16_t ud_itab__111[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 43,
+};
+
+static const uint16_t ud_itab__112[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 37,
+};
+
+static const uint16_t ud_itab__113[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 39,
+};
+
+static const uint16_t ud_itab__114[] = {
+ /* 0 */ 1723, 1725, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__115[] = {
+ /* 0 */ 1724, 1726, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__116[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ GROUP(117), GROUP(118), GROUP(119), GROUP(120),
+ /* c */ GROUP(121), GROUP(122), GROUP(123), GROUP(124),
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(125), GROUP(126), GROUP(127), GROUP(129),
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ GROUP(130), GROUP(131), GROUP(132), INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ GROUP(134), GROUP(135), GROUP(136), INVALID,
+ /* 44 */ GROUP(137), INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ GROUP(139), GROUP(140), GROUP(141), GROUP(142),
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, GROUP(138),
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__117[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1644,
+};
+
+static const uint16_t ud_itab__118[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1646,
+};
+
+static const uint16_t ud_itab__119[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1648,
+};
+
+static const uint16_t ud_itab__120[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1650,
+};
+
+static const uint16_t ud_itab__121[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1654,
+};
+
+static const uint16_t ud_itab__122[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1652,
+};
+
+static const uint16_t ud_itab__123[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1677,
+};
+
+static const uint16_t ud_itab__124[] = {
+ /* 0 */ 1618, INVALID, INVALID, 1619,
+};
+
+static const uint16_t ud_itab__125[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1045,
+};
+
+static const uint16_t ud_itab__126[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1056,
+};
+
+static const uint16_t ud_itab__127[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(128),
+};
+
+static const uint16_t ud_itab__128[] = {
+ /* 0 */ 1047, 1049, 1051,
+};
+
+static const uint16_t ud_itab__129[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 201,
+};
+
+static const uint16_t ud_itab__130[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1058,
+};
+
+static const uint16_t ud_itab__131[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1557,
+};
+
+static const uint16_t ud_itab__132[] = {
+ /* 0 */ INVALID, INVALID, INVALID, GROUP(133),
+};
+
+static const uint16_t ud_itab__133[] = {
+ /* 0 */ 1062, 1063, 1064,
+};
+
+static const uint16_t ud_itab__134[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 197,
+};
+
+static const uint16_t ud_itab__135[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 195,
+};
+
+static const uint16_t ud_itab__136[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1679,
+};
+
+static const uint16_t ud_itab__137[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1512,
+};
+
+static const uint16_t ud_itab__138[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 47,
+};
+
+static const uint16_t ud_itab__139[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1715,
+};
+
+static const uint16_t ud_itab__140[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1713,
+};
+
+static const uint16_t ud_itab__141[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1721,
+};
+
+static const uint16_t ud_itab__142[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1719,
+};
+
+static const uint16_t ud_itab__143[] = {
+ /* 0 */ 900, INVALID, INVALID, 898,
+};
+
+static const uint16_t ud_itab__144[] = {
+ /* 0 */ 1387, 1391, 1393, 1389,
+};
+
+static const uint16_t ud_itab__145[] = {
+ /* 0 */ 1306, INVALID, 1308, INVALID,
+};
+
+static const uint16_t ud_itab__146[] = {
+ /* 0 */ 1291, INVALID, 1293, INVALID,
+};
+
+static const uint16_t ud_itab__147[] = {
+ /* 0 */ 61, INVALID, INVALID, 59,
+};
+
+static const uint16_t ud_itab__148[] = {
+ /* 0 */ 65, INVALID, INVALID, 63,
+};
+
+static const uint16_t ud_itab__149[] = {
+ /* 0 */ 976, INVALID, INVALID, 974,
+};
+
+static const uint16_t ud_itab__150[] = {
+ /* 0 */ 1499, INVALID, INVALID, 1497,
+};
+
+static const uint16_t ud_itab__151[] = {
+ /* 0 */ 27, 29, 31, 25,
+};
+
+static const uint16_t ud_itab__152[] = {
+ /* 0 */ 946, 948, 950, 944,
+};
+
+static const uint16_t ud_itab__153[] = {
+ /* 0 */ 145, 150, 156, 139,
+};
+
+static const uint16_t ud_itab__154[] = {
+ /* 0 */ 134, INVALID, 163, 143,
+};
+
+static const uint16_t ud_itab__155[] = {
+ /* 0 */ 1419, 1421, 1423, 1417,
+};
+
+static const uint16_t ud_itab__156[] = {
+ /* 0 */ 818, 820, 822, 816,
+};
+
+static const uint16_t ud_itab__157[] = {
+ /* 0 */ 189, 191, 193, 187,
+};
+
+static const uint16_t ud_itab__158[] = {
+ /* 0 */ 802, 804, 806, 800,
+};
+
+static const uint16_t ud_itab__159[] = {
+ /* 0 */ 1209, INVALID, INVALID, 1207,
+};
+
+static const uint16_t ud_itab__160[] = {
+ /* 0 */ 1212, INVALID, INVALID, 1210,
+};
+
+static const uint16_t ud_itab__161[] = {
+ /* 0 */ 1215, INVALID, INVALID, 1213,
+};
+
+static const uint16_t ud_itab__162[] = {
+ /* 0 */ 987, INVALID, INVALID, 985,
+};
+
+static const uint16_t ud_itab__163[] = {
+ /* 0 */ 1038, INVALID, INVALID, 1036,
+};
+
+static const uint16_t ud_itab__164[] = {
+ /* 0 */ 1041, INVALID, INVALID, 1039,
+};
+
+static const uint16_t ud_itab__165[] = {
+ /* 0 */ 1044, INVALID, INVALID, 1042,
+};
+
+static const uint16_t ud_itab__166[] = {
+ /* 0 */ 993, INVALID, INVALID, 991,
+};
+
+static const uint16_t ud_itab__167[] = {
+ /* 0 */ 1200, INVALID, INVALID, 1198,
+};
+
+static const uint16_t ud_itab__168[] = {
+ /* 0 */ 1203, INVALID, INVALID, 1201,
+};
+
+static const uint16_t ud_itab__169[] = {
+ /* 0 */ 1206, INVALID, INVALID, 1204,
+};
+
+static const uint16_t ud_itab__170[] = {
+ /* 0 */ 990, INVALID, INVALID, 988,
+};
+
+static const uint16_t ud_itab__171[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1547,
+};
+
+static const uint16_t ud_itab__172[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1545,
+};
+
+static const uint16_t ud_itab__173[] = {
+ /* 0 */ GROUP(174), INVALID, INVALID, GROUP(175),
+};
+
+static const uint16_t ud_itab__174[] = {
+ /* 0 */ 866, 867, 910,
+};
+
+static const uint16_t ud_itab__175[] = {
+ /* 0 */ 868, 870, 911,
+};
+
+static const uint16_t ud_itab__176[] = {
+ /* 0 */ 920, INVALID, 1522, 1517,
+};
+
+static const uint16_t ud_itab__177[] = {
+ /* 0 */ 1134, 1537, 1535, 1539,
+};
+
+static const uint16_t ud_itab__178[] = {
+ /* 0 */ INVALID, INVALID, GROUP(179), INVALID,
+ /* 4 */ GROUP(180), INVALID, GROUP(181), INVALID,
+};
+
+static const uint16_t ud_itab__179[] = {
+ /* 0 */ 1159, INVALID, INVALID, 1163,
+};
+
+static const uint16_t ud_itab__180[] = {
+ /* 0 */ 1152, INVALID, INVALID, 1150,
+};
+
+static const uint16_t ud_itab__181[] = {
+ /* 0 */ 1138, INVALID, INVALID, 1137,
+};
+
+static const uint16_t ud_itab__182[] = {
+ /* 0 */ INVALID, INVALID, GROUP(183), INVALID,
+ /* 4 */ GROUP(184), INVALID, GROUP(185), INVALID,
+};
+
+static const uint16_t ud_itab__183[] = {
+ /* 0 */ 1165, INVALID, INVALID, 1169,
+};
+
+static const uint16_t ud_itab__184[] = {
+ /* 0 */ 1153, INVALID, INVALID, 1157,
+};
+
+static const uint16_t ud_itab__185[] = {
+ /* 0 */ 1142, INVALID, INVALID, 1141,
+};
+
+static const uint16_t ud_itab__186[] = {
+ /* 0 */ INVALID, INVALID, GROUP(187), GROUP(188),
+ /* 4 */ INVALID, INVALID, GROUP(189), GROUP(190),
+};
+
+static const uint16_t ud_itab__187[] = {
+ /* 0 */ 1171, INVALID, INVALID, 1175,
+};
+
+static const uint16_t ud_itab__188[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1543,
+};
+
+static const uint16_t ud_itab__189[] = {
+ /* 0 */ 1146, INVALID, INVALID, 1145,
+};
+
+static const uint16_t ud_itab__190[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1541,
+};
+
+static const uint16_t ud_itab__191[] = {
+ /* 0 */ 1027, INVALID, INVALID, 1028,
+};
+
+static const uint16_t ud_itab__192[] = {
+ /* 0 */ 1030, INVALID, INVALID, 1031,
+};
+
+static const uint16_t ud_itab__193[] = {
+ /* 0 */ 1033, INVALID, INVALID, 1034,
+};
+
+static const uint16_t ud_itab__194[] = {
+ /* 0 */ INVALID, 1464, INVALID,
+};
+
+static const uint16_t ud_itab__195[] = {
+ /* 0 */ INVALID, 1465, INVALID,
+};
+
+static const uint16_t ud_itab__196[] = {
+ /* 0 */ INVALID, 1551, INVALID, 1549,
+};
+
+static const uint16_t ud_itab__197[] = {
+ /* 0 */ INVALID, 1555, INVALID, 1553,
+};
+
+static const uint16_t ud_itab__198[] = {
+ /* 0 */ GROUP(199), INVALID, 916, GROUP(200),
+};
+
+static const uint16_t ud_itab__199[] = {
+ /* 0 */ 872, 873, 913,
+};
+
+static const uint16_t ud_itab__200[] = {
+ /* 0 */ 874, 876, 914,
+};
+
+static const uint16_t ud_itab__201[] = {
+ /* 0 */ 921, INVALID, 1524, 1515,
+};
+
+static const uint16_t ud_itab__202[] = {
+ /* 0 */ INVALID, GROUP(203),
+};
+
+static const uint16_t ud_itab__203[] = {
+ /* 0 */ GROUP(204), GROUP(205), GROUP(206), INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__204[] = {
+ /* 0 */ 825, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__205[] = {
+ /* 0 */ 1509, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__206[] = {
+ /* 0 */ 1510, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__207[] = {
+ /* 0 */ INVALID, GROUP(208),
+};
+
+static const uint16_t ud_itab__208[] = {
+ /* 0 */ GROUP(209), GROUP(210), GROUP(211), GROUP(212),
+ /* 4 */ GROUP(213), GROUP(214), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__209[] = {
+ /* 0 */ 1511, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__210[] = {
+ /* 0 */ 1501, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__211[] = {
+ /* 0 */ 1502, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__212[] = {
+ /* 0 */ 1503, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__213[] = {
+ /* 0 */ 1504, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__214[] = {
+ /* 0 */ 1505, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__215[] = {
+ /* 0 */ GROUP(216), GROUP(217),
+};
+
+static const uint16_t ud_itab__216[] = {
+ /* 0 */ 683, 682, 768, 1400,
+ /* 4 */ 1507, 1506, INVALID, 79,
+};
+
+static const uint16_t ud_itab__217[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(218), GROUP(219), GROUP(220),
+};
+
+static const uint16_t ud_itab__218[] = {
+ /* 0 */ 777, 778, 779, 780,
+ /* 4 */ 781, 782, 783, 784,
+};
+
+static const uint16_t ud_itab__219[] = {
+ /* 0 */ 808, 809, 810, 811,
+ /* 4 */ 812, 813, 814, 815,
+};
+
+static const uint16_t ud_itab__220[] = {
+ /* 0 */ 1366, 1367, 1368, 1369,
+ /* 4 */ 1370, 1371, 1372, 1373,
+};
+
+static const uint16_t ud_itab__221[] = {
+ /* 0 */ INVALID, INVALID, 1710, INVALID,
+};
+
+static const uint16_t ud_itab__222[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ 1669, 1676, 1674, 1672,
+};
+
+static const uint16_t ud_itab__223[] = {
+ /* 0 */ 112, 117, 120, 110,
+};
+
+static const uint16_t ud_itab__224[] = {
+ /* 0 */ 1059, INVALID, INVALID, 1060,
+};
+
+static const uint16_t ud_itab__225[] = {
+ /* 0 */ 1055, INVALID, INVALID, 1053,
+};
+
+static const uint16_t ud_itab__226[] = {
+ /* 0 */ 1381, INVALID, INVALID, 1379,
+};
+
+static const uint16_t ud_itab__227[] = {
+ /* 0 */ GROUP(228), GROUP(235),
+};
+
+static const uint16_t ud_itab__228[] = {
+ /* 0 */ INVALID, GROUP(229), INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, GROUP(230), GROUP(234),
+};
+
+static const uint16_t ud_itab__229[] = {
+ /* 0 */ 124, 125, 126,
+};
+
+static const uint16_t ud_itab__230[] = {
+ /* 0 */ GROUP(231), INVALID, GROUP(232), GROUP(233),
+};
+
+static const uint16_t ud_itab__231[] = {
+ /* 0 */ INVALID, 1459, INVALID,
+};
+
+static const uint16_t ud_itab__232[] = {
+ /* 0 */ INVALID, 1458, INVALID,
+};
+
+static const uint16_t ud_itab__233[] = {
+ /* 0 */ INVALID, 1457, INVALID,
+};
+
+static const uint16_t ud_itab__234[] = {
+ /* 0 */ INVALID, 1460, INVALID,
+};
+
+static const uint16_t ud_itab__235[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, 1456, INVALID,
+};
+
+static const uint16_t ud_itab__236[] = {
+ /* 0 */ INVALID, 35, INVALID, 33,
+};
+
+static const uint16_t ud_itab__237[] = {
+ /* 0 */ 1160, INVALID, INVALID, 1161,
+};
+
+static const uint16_t ud_itab__238[] = {
+ /* 0 */ 1166, INVALID, INVALID, 1167,
+};
+
+static const uint16_t ud_itab__239[] = {
+ /* 0 */ 1172, INVALID, INVALID, 1173,
+};
+
+static const uint16_t ud_itab__240[] = {
+ /* 0 */ 1527, INVALID, INVALID, 1528,
+};
+
+static const uint16_t ud_itab__241[] = {
+ /* 0 */ 1093, INVALID, INVALID, 1094,
+};
+
+static const uint16_t ud_itab__242[] = {
+ /* 0 */ INVALID, 1521, 1526, 918,
+};
+
+static const uint16_t ud_itab__243[] = {
+ /* 0 */ 1086, INVALID, INVALID, 1084,
+};
+
+static const uint16_t ud_itab__244[] = {
+ /* 0 */ 1192, INVALID, INVALID, 1193,
+};
+
+static const uint16_t ud_itab__245[] = {
+ /* 0 */ 1195, INVALID, INVALID, 1196,
+};
+
+static const uint16_t ud_itab__246[] = {
+ /* 0 */ 1083, INVALID, INVALID, 1081,
+};
+
+static const uint16_t ud_itab__247[] = {
+ /* 0 */ 1017, INVALID, INVALID, 1015,
+};
+
+static const uint16_t ud_itab__248[] = {
+ /* 0 */ 1009, INVALID, INVALID, 1010,
+};
+
+static const uint16_t ud_itab__249[] = {
+ /* 0 */ 1012, INVALID, INVALID, 1013,
+};
+
+static const uint16_t ud_itab__250[] = {
+ /* 0 */ 1075, INVALID, INVALID, 1076,
+};
+
+static const uint16_t ud_itab__251[] = {
+ /* 0 */ 1020, INVALID, INVALID, 1018,
+};
+
+static const uint16_t ud_itab__252[] = {
+ /* 0 */ 1023, INVALID, INVALID, 1021,
+};
+
+static const uint16_t ud_itab__253[] = {
+ /* 0 */ 1147, INVALID, INVALID, 1148,
+};
+
+static const uint16_t ud_itab__254[] = {
+ /* 0 */ 1156, INVALID, INVALID, 1154,
+};
+
+static const uint16_t ud_itab__255[] = {
+ /* 0 */ 1026, INVALID, INVALID, 1024,
+};
+
+static const uint16_t ud_itab__256[] = {
+ /* 0 */ 1087, INVALID, INVALID, 1088,
+};
+
+static const uint16_t ud_itab__257[] = {
+ /* 0 */ 1092, INVALID, INVALID, 1090,
+};
+
+static const uint16_t ud_itab__258[] = {
+ /* 0 */ INVALID, 136, 132, 160,
+};
+
+static const uint16_t ud_itab__259[] = {
+ /* 0 */ 909, INVALID, INVALID, 902,
+};
+
+static const uint16_t ud_itab__260[] = {
+ /* 0 */ 1186, INVALID, INVALID, 1187,
+};
+
+static const uint16_t ud_itab__261[] = {
+ /* 0 */ 1189, INVALID, INVALID, 1190,
+};
+
+static const uint16_t ud_itab__262[] = {
+ /* 0 */ 1080, INVALID, INVALID, 1078,
+};
+
+static const uint16_t ud_itab__263[] = {
+ /* 0 */ 1118, INVALID, INVALID, 1116,
+};
+
+static const uint16_t ud_itab__264[] = {
+ /* 0 */ 1003, INVALID, INVALID, 1004,
+};
+
+static const uint16_t ud_itab__265[] = {
+ /* 0 */ 1006, INVALID, INVALID, 1007,
+};
+
+static const uint16_t ud_itab__266[] = {
+ /* 0 */ 1074, INVALID, INVALID, 1072,
+};
+
+static const uint16_t ud_itab__267[] = {
+ /* 0 */ 1266, INVALID, INVALID, 1264,
+};
+
+static const uint16_t ud_itab__268[] = {
+ /* 0 */ INVALID, 1559, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__269[] = {
+ /* 0 */ 1136, INVALID, INVALID, 1135,
+};
+
+static const uint16_t ud_itab__270[] = {
+ /* 0 */ 1140, INVALID, INVALID, 1139,
+};
+
+static const uint16_t ud_itab__271[] = {
+ /* 0 */ 1144, INVALID, INVALID, 1143,
+};
+
+static const uint16_t ud_itab__272[] = {
+ /* 0 */ 1533, INVALID, INVALID, 1534,
+};
+
+static const uint16_t ud_itab__273[] = {
+ /* 0 */ 1069, INVALID, INVALID, 1070,
+};
+
+static const uint16_t ud_itab__274[] = {
+ /* 0 */ 1133, INVALID, INVALID, 1131,
+};
+
+static const uint16_t ud_itab__275[] = {
+ /* 0 */ INVALID, GROUP(276),
+};
+
+static const uint16_t ud_itab__276[] = {
+ /* 0 */ 799, INVALID, INVALID, 1519,
+};
+
+static const uint16_t ud_itab__277[] = {
+ /* 0 */ 1179, INVALID, INVALID, 1177,
+};
+
+static const uint16_t ud_itab__278[] = {
+ /* 0 */ 1182, INVALID, INVALID, 1180,
+};
+
+static const uint16_t ud_itab__279[] = {
+ /* 0 */ 1183, INVALID, INVALID, 1184,
+};
+
+static const uint16_t ud_itab__280[] = {
+ /* 0 */ 1532, INVALID, INVALID, 1530,
+};
+
+static const uint16_t ud_itab__281[] = {
+ /* 0 */ 996, INVALID, INVALID, 994,
+};
+
+static const uint16_t ud_itab__282[] = {
+ /* 0 */ 997, INVALID, INVALID, 998,
+};
+
+static const uint16_t ud_itab__283[] = {
+ /* 0 */ 1000, INVALID, INVALID, 1001,
+};
+
+static const uint16_t ud_itab__284[] = {
+ /* 0 */ 1242, INVALID,
+};
+
+static const uint16_t ud_itab__285[] = {
+ /* 0 */ 1097, INVALID,
+};
+
+static const uint16_t ud_itab__286[] = {
+ /* 0 */ 1243, INVALID,
+};
+
+static const uint16_t ud_itab__287[] = {
+ /* 0 */ 1098, INVALID,
+};
+
+static const uint16_t ud_itab__288[] = {
+ /* 0 */ 173, INVALID,
+};
+
+static const uint16_t ud_itab__289[] = {
+ /* 0 */ 174, INVALID,
+};
+
+static const uint16_t ud_itab__290[] = {
+ /* 0 */ 1, INVALID,
+};
+
+static const uint16_t ud_itab__291[] = {
+ /* 0 */ 4, INVALID,
+};
+
+static const uint16_t ud_itab__292[] = {
+ /* 0 */ GROUP(293), GROUP(294), INVALID,
+};
+
+static const uint16_t ud_itab__293[] = {
+ /* 0 */ 1257, INVALID,
+};
+
+static const uint16_t ud_itab__294[] = {
+ /* 0 */ 1258, INVALID,
+};
+
+static const uint16_t ud_itab__295[] = {
+ /* 0 */ GROUP(296), GROUP(297), INVALID,
+};
+
+static const uint16_t ud_itab__296[] = {
+ /* 0 */ 1110, INVALID,
+};
+
+static const uint16_t ud_itab__297[] = {
+ /* 0 */ 1111, INVALID,
+};
+
+static const uint16_t ud_itab__298[] = {
+ /* 0 */ 1658, INVALID,
+};
+
+static const uint16_t ud_itab__299[] = {
+ /* 0 */ 67, 68,
+};
+
+static const uint16_t ud_itab__300[] = {
+ /* 0 */ 710, 711, INVALID,
+};
+
+static const uint16_t ud_itab__301[] = {
+ /* 0 */ 983, 984, INVALID,
+};
+
+static const uint16_t ud_itab__302[] = {
+ /* 0 */ 21, 970, 11, 1342,
+ /* 4 */ 55, 1413, 1493, 106,
+};
+
+static const uint16_t ud_itab__303[] = {
+ /* 0 */ 23, 971, 13, 1343,
+ /* 4 */ 57, 1414, 1494, 108,
+};
+
+static const uint16_t ud_itab__304[] = {
+ /* 0 */ GROUP(305), GROUP(306), GROUP(307), GROUP(308),
+ /* 4 */ GROUP(309), GROUP(310), GROUP(311), GROUP(312),
+};
+
+static const uint16_t ud_itab__305[] = {
+ /* 0 */ 22, INVALID,
+};
+
+static const uint16_t ud_itab__306[] = {
+ /* 0 */ 972, INVALID,
+};
+
+static const uint16_t ud_itab__307[] = {
+ /* 0 */ 12, INVALID,
+};
+
+static const uint16_t ud_itab__308[] = {
+ /* 0 */ 1344, INVALID,
+};
+
+static const uint16_t ud_itab__309[] = {
+ /* 0 */ 56, INVALID,
+};
+
+static const uint16_t ud_itab__310[] = {
+ /* 0 */ 1415, INVALID,
+};
+
+static const uint16_t ud_itab__311[] = {
+ /* 0 */ 1495, INVALID,
+};
+
+static const uint16_t ud_itab__312[] = {
+ /* 0 */ 107, INVALID,
+};
+
+static const uint16_t ud_itab__313[] = {
+ /* 0 */ 24, 973, 14, 1345,
+ /* 4 */ 58, 1416, 1496, 109,
+};
+
+static const uint16_t ud_itab__314[] = {
+ /* 0 */ 1109, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__315[] = {
+ /* 0 */ 74, 75, 76,
+};
+
+static const uint16_t ud_itab__316[] = {
+ /* 0 */ 170, 171, 172,
+};
+
+static const uint16_t ud_itab__317[] = {
+ /* 0 */ 73, INVALID,
+};
+
+static const uint16_t ud_itab__318[] = {
+ /* 0 */ GROUP(319), GROUP(320), GROUP(321),
+};
+
+static const uint16_t ud_itab__319[] = {
+ /* 0 */ 1259, 1260,
+};
+
+static const uint16_t ud_itab__320[] = {
+ /* 0 */ 1261, 1262,
+};
+
+static const uint16_t ud_itab__321[] = {
+ /* 0 */ INVALID, 1263,
+};
+
+static const uint16_t ud_itab__322[] = {
+ /* 0 */ GROUP(323), GROUP(324), GROUP(325),
+};
+
+static const uint16_t ud_itab__323[] = {
+ /* 0 */ 1112, INVALID,
+};
+
+static const uint16_t ud_itab__324[] = {
+ /* 0 */ 1113, 1114,
+};
+
+static const uint16_t ud_itab__325[] = {
+ /* 0 */ INVALID, 1115,
+};
+
+static const uint16_t ud_itab__326[] = {
+ /* 0 */ 923, 924, 927,
+};
+
+static const uint16_t ud_itab__327[] = {
+ /* 0 */ 115, 116, 119,
+};
+
+static const uint16_t ud_itab__328[] = {
+ /* 0 */ 1403, 1404, 1405,
+};
+
+static const uint16_t ud_itab__329[] = {
+ /* 0 */ 791, 792, 793,
+};
+
+static const uint16_t ud_itab__330[] = {
+ /* 0 */ 1347, 1348, 1349,
+};
+
+static const uint16_t ud_itab__331[] = {
+ /* 0 */ 1279, 1286, 1267, 1275,
+ /* 4 */ 1327, 1334, 1318, 1313,
+};
+
+static const uint16_t ud_itab__332[] = {
+ /* 0 */ 1284, 1287, 1268, 1274,
+ /* 4 */ 1323, 1330, 1319, 1315,
+};
+
+static const uint16_t ud_itab__333[] = {
+ /* 0 */ GROUP(334), GROUP(335), INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369),
+ /* 8 */ INVALID, GROUP(394), INVALID, INVALID,
+ /* c */ INVALID, GROUP(399), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__334[] = {
+ /* 0 */ 771, INVALID,
+};
+
+static const uint16_t ud_itab__335[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ 937, 939, GROUP(336), 895,
+ /* 14 */ 1450, 1448, GROUP(337), 885,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 863, 865, INVALID, 908,
+ /* 2c */ INVALID, INVALID, 1443, 130,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ 901, 1388, 1307, 1292,
+ /* 54 */ 62, 66, 977, 1500,
+ /* 58 */ 28, 947, 146, 135,
+ /* 5c */ 1420, 819, 190, 803,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, GROUP(340),
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, GROUP(338), INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 113, INVALID,
+ /* c4 */ INVALID, INVALID, 1382, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__336[] = {
+ /* 0 */ 893, 897,
+};
+
+static const uint16_t ud_itab__337[] = {
+ /* 0 */ 883, 887,
+};
+
+static const uint16_t ud_itab__338[] = {
+ /* 0 */ GROUP(339), INVALID,
+};
+
+static const uint16_t ud_itab__339[] = {
+ /* 0 */ INVALID, INVALID, INVALID, 1401,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__340[] = {
+ /* 0 */ 1742, 1743,
+};
+
+static const uint16_t ud_itab__341[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ 933, 935, GROUP(342), 891,
+ /* 14 */ 1452, 1446, GROUP(343), 881,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 859, 861, INVALID, 906,
+ /* 2c */ INVALID, INVALID, 1441, 128,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ 899, 1390, INVALID, INVALID,
+ /* 54 */ 60, 64, 975, 1498,
+ /* 58 */ 26, 945, 140, 144,
+ /* 5c */ 1418, 817, 188, 801,
+ /* 60 */ 1208, 1211, 1214, 986,
+ /* 64 */ 1037, 1040, 1043, 992,
+ /* 68 */ 1199, 1202, 1205, 989,
+ /* 6c */ 1548, 1546, GROUP(344), 1518,
+ /* 70 */ 1540, GROUP(345), GROUP(347), GROUP(349),
+ /* 74 */ 1029, 1032, 1035, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ 1550, 1554, GROUP(351), 1516,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 111, INVALID,
+ /* c4 */ 1061, 1054, 1380, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ 34, 1162, 1168, 1174,
+ /* d4 */ 1529, 1095, 919, GROUP(352),
+ /* d8 */ 1194, 1197, 1082, 1016,
+ /* dc */ 1011, 1014, 1077, 1019,
+ /* e0 */ 1022, 1149, 1155, 1025,
+ /* e4 */ 1089, 1091, 161, 903,
+ /* e8 */ 1188, 1191, 1079, 1117,
+ /* ec */ 1005, 1008, 1073, 1265,
+ /* f0 */ INVALID, GROUP(353), GROUP(354), GROUP(355),
+ /* f4 */ INVALID, 1071, 1132, GROUP(356),
+ /* f8 */ 1178, 1181, 1185, 1531,
+ /* fc */ 995, 999, 1002, INVALID,
+};
+
+static const uint16_t ud_itab__342[] = {
+ /* 0 */ 889, INVALID,
+};
+
+static const uint16_t ud_itab__343[] = {
+ /* 0 */ 879, INVALID,
+};
+
+static const uint16_t ud_itab__344[] = {
+ /* 0 */ 869, 871, 912,
+};
+
+static const uint16_t ud_itab__345[] = {
+ /* 0 */ INVALID, INVALID, 1164, INVALID,
+ /* 4 */ 1151, INVALID, GROUP(346), INVALID,
+};
+
+static const uint16_t ud_itab__346[] = {
+ /* 0 */ 1756, INVALID,
+};
+
+static const uint16_t ud_itab__347[] = {
+ /* 0 */ INVALID, INVALID, 1170, INVALID,
+ /* 4 */ 1158, INVALID, GROUP(348), INVALID,
+};
+
+static const uint16_t ud_itab__348[] = {
+ /* 0 */ 1758, INVALID,
+};
+
+static const uint16_t ud_itab__349[] = {
+ /* 0 */ INVALID, INVALID, 1176, 1544,
+ /* 4 */ INVALID, INVALID, GROUP(350), 1542,
+};
+
+static const uint16_t ud_itab__350[] = {
+ /* 0 */ 1760, INVALID,
+};
+
+static const uint16_t ud_itab__351[] = {
+ /* 0 */ 875, 877, 915,
+};
+
+static const uint16_t ud_itab__352[] = {
+ /* 0 */ 1085, INVALID,
+};
+
+static const uint16_t ud_itab__353[] = {
+ /* 0 */ 1755, INVALID,
+};
+
+static const uint16_t ud_itab__354[] = {
+ /* 0 */ 1757, INVALID,
+};
+
+static const uint16_t ud_itab__355[] = {
+ /* 0 */ 1759, INVALID,
+};
+
+static const uint16_t ud_itab__356[] = {
+ /* 0 */ INVALID, 1520,
+};
+
+static const uint16_t ud_itab__357[] = {
+ /* 0 */ 1584, 1587, 1590, 1593,
+ /* 4 */ 1596, 1599, 1602, 1605,
+ /* 8 */ 1608, 1614, 1611, 1617,
+ /* c */ GROUP(358), GROUP(359), GROUP(360), GROUP(361),
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, 1712,
+ /* 18 */ GROUP(362), GROUP(363), INVALID, INVALID,
+ /* 1c */ 1575, 1578, 1581, INVALID,
+ /* 20 */ 1686, 1688, 1690, 1692,
+ /* 24 */ 1694, INVALID, INVALID, INVALID,
+ /* 28 */ 1623, 1709, 1682, 1684,
+ /* 2c */ GROUP(365), GROUP(366), GROUP(367), GROUP(368),
+ /* 30 */ 1697, 1699, 1701, 1703,
+ /* 34 */ 1705, 1707, INVALID, 1718,
+ /* 38 */ 1625, 1627, 1629, 1631,
+ /* 3c */ 1633, 1635, 1639, 1637,
+ /* 40 */ 1641, 1643, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, 46,
+ /* dc */ 42, 44, 38, 40,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__358[] = {
+ /* 0 */ 1737, INVALID,
+};
+
+static const uint16_t ud_itab__359[] = {
+ /* 0 */ 1735, INVALID,
+};
+
+static const uint16_t ud_itab__360[] = {
+ /* 0 */ 1740, INVALID,
+};
+
+static const uint16_t ud_itab__361[] = {
+ /* 0 */ 1741, INVALID,
+};
+
+static const uint16_t ud_itab__362[] = {
+ /* 0 */ 1727, INVALID,
+};
+
+static const uint16_t ud_itab__363[] = {
+ /* 0 */ GROUP(364), INVALID,
+};
+
+static const uint16_t ud_itab__364[] = {
+ /* 0 */ INVALID, 1728,
+};
+
+static const uint16_t ud_itab__365[] = {
+ /* 0 */ 1731, INVALID,
+};
+
+static const uint16_t ud_itab__366[] = {
+ /* 0 */ 1733, INVALID,
+};
+
+static const uint16_t ud_itab__367[] = {
+ /* 0 */ 1732, INVALID,
+};
+
+static const uint16_t ud_itab__368[] = {
+ /* 0 */ 1734, INVALID,
+};
+
+static const uint16_t ud_itab__369[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ GROUP(370), GROUP(371), GROUP(372), INVALID,
+ /* 8 */ 1645, 1647, 1649, 1651,
+ /* c */ 1655, 1653, 1678, 1620,
+ /* 10 */ INVALID, INVALID, INVALID, INVALID,
+ /* 14 */ GROUP(374), 1057, GROUP(375), 202,
+ /* 18 */ GROUP(379), GROUP(381), INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ GROUP(383), 1558, GROUP(385), INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ 198, 196, 1680, INVALID,
+ /* 44 */ 1513, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, GROUP(391), GROUP(392),
+ /* 4c */ GROUP(393), INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, INVALID, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ INVALID, INVALID, INVALID, INVALID,
+ /* 5c */ INVALID, INVALID, INVALID, INVALID,
+ /* 60 */ 1716, 1714, 1722, 1720,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ INVALID, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, INVALID, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, 48,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, INVALID, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__370[] = {
+ /* 0 */ 1738, INVALID,
+};
+
+static const uint16_t ud_itab__371[] = {
+ /* 0 */ 1736, INVALID,
+};
+
+static const uint16_t ud_itab__372[] = {
+ /* 0 */ GROUP(373), INVALID,
+};
+
+static const uint16_t ud_itab__373[] = {
+ /* 0 */ INVALID, 1739,
+};
+
+static const uint16_t ud_itab__374[] = {
+ /* 0 */ 1046, INVALID,
+};
+
+static const uint16_t ud_itab__375[] = {
+ /* 0 */ GROUP(376), GROUP(377), GROUP(378),
+};
+
+static const uint16_t ud_itab__376[] = {
+ /* 0 */ 1048, INVALID,
+};
+
+static const uint16_t ud_itab__377[] = {
+ /* 0 */ 1050, INVALID,
+};
+
+static const uint16_t ud_itab__378[] = {
+ /* 0 */ INVALID, 1052,
+};
+
+static const uint16_t ud_itab__379[] = {
+ /* 0 */ GROUP(380), INVALID,
+};
+
+static const uint16_t ud_itab__380[] = {
+ /* 0 */ INVALID, 1730,
+};
+
+static const uint16_t ud_itab__381[] = {
+ /* 0 */ GROUP(382), INVALID,
+};
+
+static const uint16_t ud_itab__382[] = {
+ /* 0 */ INVALID, 1729,
+};
+
+static const uint16_t ud_itab__383[] = {
+ /* 0 */ GROUP(384), INVALID,
+};
+
+static const uint16_t ud_itab__384[] = {
+ /* 0 */ 1065, INVALID,
+};
+
+static const uint16_t ud_itab__385[] = {
+ /* 0 */ GROUP(386), GROUP(388),
+};
+
+static const uint16_t ud_itab__386[] = {
+ /* 0 */ GROUP(387), INVALID,
+};
+
+static const uint16_t ud_itab__387[] = {
+ /* 0 */ 1066, INVALID,
+};
+
+static const uint16_t ud_itab__388[] = {
+ /* 0 */ GROUP(389), GROUP(390),
+};
+
+static const uint16_t ud_itab__389[] = {
+ /* 0 */ 1067, INVALID,
+};
+
+static const uint16_t ud_itab__390[] = {
+ /* 0 */ 1068, INVALID,
+};
+
+static const uint16_t ud_itab__391[] = {
+ /* 0 */ 1745, INVALID,
+};
+
+static const uint16_t ud_itab__392[] = {
+ /* 0 */ 1744, INVALID,
+};
+
+static const uint16_t ud_itab__393[] = {
+ /* 0 */ 1754, INVALID,
+};
+
+static const uint16_t ud_itab__394[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(395), GROUP(396), GROUP(397), INVALID,
+ /* 14 */ INVALID, INVALID, GROUP(398), INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, 155, INVALID,
+ /* 2c */ 169, 159, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, 1394, 1309, 1294,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ 32, 951, 157, 164,
+ /* 5c */ 1424, 823, 194, 807,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, 1523,
+ /* 70 */ 1536, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ INVALID, INVALID, 917, 1525,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 121, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ INVALID, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, 133, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ INVALID, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__395[] = {
+ /* 0 */ 1751, 1750,
+};
+
+static const uint16_t ud_itab__396[] = {
+ /* 0 */ 1753, 1752,
+};
+
+static const uint16_t ud_itab__397[] = {
+ /* 0 */ 1572, 1570,
+};
+
+static const uint16_t ud_itab__398[] = {
+ /* 0 */ 1568, 1566,
+};
+
+static const uint16_t ud_itab__399[] = {
+ /* 0 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8 */ INVALID, INVALID, INVALID, INVALID,
+ /* c */ INVALID, INVALID, INVALID, INVALID,
+ /* 10 */ GROUP(402), GROUP(400), GROUP(401), INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ INVALID, INVALID, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, INVALID, 153, INVALID,
+ /* 2c */ 167, 149, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+ /* 40 */ INVALID, INVALID, INVALID, INVALID,
+ /* 44 */ INVALID, INVALID, INVALID, INVALID,
+ /* 48 */ INVALID, INVALID, INVALID, INVALID,
+ /* 4c */ INVALID, INVALID, INVALID, INVALID,
+ /* 50 */ INVALID, 1392, INVALID, INVALID,
+ /* 54 */ INVALID, INVALID, INVALID, INVALID,
+ /* 58 */ 30, 949, 151, INVALID,
+ /* 5c */ 1422, 821, 192, 805,
+ /* 60 */ INVALID, INVALID, INVALID, INVALID,
+ /* 64 */ INVALID, INVALID, INVALID, INVALID,
+ /* 68 */ INVALID, INVALID, INVALID, INVALID,
+ /* 6c */ INVALID, INVALID, INVALID, INVALID,
+ /* 70 */ 1538, INVALID, INVALID, INVALID,
+ /* 74 */ INVALID, INVALID, INVALID, INVALID,
+ /* 78 */ INVALID, INVALID, INVALID, INVALID,
+ /* 7c */ 1552, 1556, INVALID, INVALID,
+ /* 80 */ INVALID, INVALID, INVALID, INVALID,
+ /* 84 */ INVALID, INVALID, INVALID, INVALID,
+ /* 88 */ INVALID, INVALID, INVALID, INVALID,
+ /* 8c */ INVALID, INVALID, INVALID, INVALID,
+ /* 90 */ INVALID, INVALID, INVALID, INVALID,
+ /* 94 */ INVALID, INVALID, INVALID, INVALID,
+ /* 98 */ INVALID, INVALID, INVALID, INVALID,
+ /* 9c */ INVALID, INVALID, INVALID, INVALID,
+ /* a0 */ INVALID, INVALID, INVALID, INVALID,
+ /* a4 */ INVALID, INVALID, INVALID, INVALID,
+ /* a8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ac */ INVALID, INVALID, INVALID, INVALID,
+ /* b0 */ INVALID, INVALID, INVALID, INVALID,
+ /* b4 */ INVALID, INVALID, INVALID, INVALID,
+ /* b8 */ INVALID, INVALID, INVALID, INVALID,
+ /* bc */ INVALID, INVALID, INVALID, INVALID,
+ /* c0 */ INVALID, INVALID, 118, INVALID,
+ /* c4 */ INVALID, INVALID, INVALID, INVALID,
+ /* c8 */ INVALID, INVALID, INVALID, INVALID,
+ /* cc */ INVALID, INVALID, INVALID, INVALID,
+ /* d0 */ 36, INVALID, INVALID, INVALID,
+ /* d4 */ INVALID, INVALID, INVALID, INVALID,
+ /* d8 */ INVALID, INVALID, INVALID, INVALID,
+ /* dc */ INVALID, INVALID, INVALID, INVALID,
+ /* e0 */ INVALID, INVALID, INVALID, INVALID,
+ /* e4 */ INVALID, INVALID, 137, INVALID,
+ /* e8 */ INVALID, INVALID, INVALID, INVALID,
+ /* ec */ INVALID, INVALID, INVALID, INVALID,
+ /* f0 */ 1560, INVALID, INVALID, INVALID,
+ /* f4 */ INVALID, INVALID, INVALID, INVALID,
+ /* f8 */ INVALID, INVALID, INVALID, INVALID,
+ /* fc */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__400[] = {
+ /* 0 */ 1749, 1748,
+};
+
+static const uint16_t ud_itab__401[] = {
+ /* 0 */ 1564, 1562,
+};
+
+static const uint16_t ud_itab__402[] = {
+ /* 0 */ 1747, 1746,
+};
+
+static const uint16_t ud_itab__403[] = {
+ /* 0 */ GROUP(404), GROUP(335), INVALID, INVALID,
+ /* 4 */ INVALID, GROUP(341), GROUP(357), GROUP(369),
+ /* 8 */ INVALID, GROUP(394), INVALID, INVALID,
+ /* c */ INVALID, GROUP(399), INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__404[] = {
+ /* 0 */ 769, INVALID,
+};
+
+static const uint16_t ud_itab__405[] = {
+ /* 0 */ 826, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__406[] = {
+ /* 0 */ 827, INVALID, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__407[] = {
+ /* 0 */ 715, INVALID,
+};
+
+static const uint16_t ud_itab__408[] = {
+ /* 0 */ 723, 724, 725,
+};
+
+static const uint16_t ud_itab__409[] = {
+ /* 0 */ 1280, 1285, 1269, 1273,
+ /* 4 */ 1326, 1333, 1320, 1314,
+};
+
+static const uint16_t ud_itab__410[] = {
+ /* 0 */ 1281, 1288, 1272, 1276,
+ /* 4 */ 1325, 1332, 1329, 1312,
+};
+
+static const uint16_t ud_itab__411[] = {
+ /* 0 */ 1282, 1289, 1270, 1277,
+ /* 4 */ 1324, 1331, 1321, 1316,
+};
+
+static const uint16_t ud_itab__412[] = {
+ /* 0 */ 1283, 1290, 1271, 1278,
+ /* 4 */ 1328, 1335, 1322, 1317,
+};
+
+static const uint16_t ud_itab__413[] = {
+ /* 0 */ 3, INVALID,
+};
+
+static const uint16_t ud_itab__414[] = {
+ /* 0 */ 2, INVALID,
+};
+
+static const uint16_t ud_itab__415[] = {
+ /* 0 */ 1311, INVALID,
+};
+
+static const uint16_t ud_itab__416[] = {
+ /* 0 */ GROUP(417), GROUP(418),
+};
+
+static const uint16_t ud_itab__417[] = {
+ /* 0 */ 206, 503, 307, 357,
+ /* 4 */ 587, 630, 387, 413,
+};
+
+static const uint16_t ud_itab__418[] = {
+ /* 0 */ 215, 216, 217, 218,
+ /* 4 */ 219, 220, 221, 222,
+ /* 8 */ 504, 505, 506, 507,
+ /* c */ 508, 509, 510, 511,
+ /* 10 */ 309, 310, 311, 312,
+ /* 14 */ 313, 314, 315, 316,
+ /* 18 */ 359, 360, 361, 362,
+ /* 1c */ 363, 364, 365, 366,
+ /* 20 */ 589, 590, 591, 592,
+ /* 24 */ 593, 594, 595, 596,
+ /* 28 */ 614, 615, 616, 617,
+ /* 2c */ 618, 619, 620, 621,
+ /* 30 */ 388, 389, 390, 391,
+ /* 34 */ 392, 393, 394, 395,
+ /* 38 */ 414, 415, 416, 417,
+ /* 3c */ 418, 419, 420, 421,
+};
+
+static const uint16_t ud_itab__419[] = {
+ /* 0 */ GROUP(420), GROUP(421),
+};
+
+static const uint16_t ud_itab__420[] = {
+ /* 0 */ 476, INVALID, 573, 540,
+ /* 4 */ 493, 492, 584, 583,
+};
+
+static const uint16_t ud_itab__421[] = {
+ /* 0 */ 477, 478, 479, 480,
+ /* 4 */ 481, 482, 483, 484,
+ /* 8 */ 658, 659, 660, 661,
+ /* c */ 662, 663, 664, 665,
+ /* 10 */ 522, INVALID, INVALID, INVALID,
+ /* 14 */ INVALID, INVALID, INVALID, INVALID,
+ /* 18 */ 549, 550, 551, 552,
+ /* 1c */ 553, 554, 555, 556,
+ /* 20 */ 233, 204, INVALID, INVALID,
+ /* 24 */ 639, 657, INVALID, INVALID,
+ /* 28 */ 485, 486, 487, 488,
+ /* 2c */ 489, 490, 491, INVALID,
+ /* 30 */ 203, 685, 529, 526,
+ /* 34 */ 684, 528, 377, 454,
+ /* 38 */ 527, 686, 537, 536,
+ /* 3c */ 530, 534, 535, 376,
+};
+
+static const uint16_t ud_itab__422[] = {
+ /* 0 */ GROUP(423), GROUP(424),
+};
+
+static const uint16_t ud_itab__423[] = {
+ /* 0 */ 456, 520, 448, 450,
+ /* 4 */ 462, 464, 460, 458,
+};
+
+static const uint16_t ud_itab__424[] = {
+ /* 0 */ 235, 236, 237, 238,
+ /* 4 */ 239, 240, 241, 242,
+ /* 8 */ 243, 244, 245, 246,
+ /* c */ 247, 248, 249, 250,
+ /* 10 */ 251, 252, 253, 254,
+ /* 14 */ 255, 256, 257, 258,
+ /* 18 */ 259, 260, 261, 262,
+ /* 1c */ 263, 264, 265, 266,
+ /* 20 */ INVALID, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ INVALID, 656, INVALID, INVALID,
+ /* 2c */ INVALID, INVALID, INVALID, INVALID,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__425[] = {
+ /* 0 */ GROUP(426), GROUP(427),
+};
+
+static const uint16_t ud_itab__426[] = {
+ /* 0 */ 453, 471, 467, 470,
+ /* 4 */ INVALID, 474, INVALID, 538,
+};
+
+static const uint16_t ud_itab__427[] = {
+ /* 0 */ 267, 268, 269, 270,
+ /* 4 */ 271, 272, 273, 274,
+ /* 8 */ 275, 276, 277, 278,
+ /* c */ 279, 280, 281, 282,
+ /* 10 */ 283, 284, 285, 286,
+ /* 14 */ 287, 288, 289, 290,
+ /* 18 */ 291, 292, 293, 294,
+ /* 1c */ 295, 296, 297, 298,
+ /* 20 */ 524, 523, 234, 455,
+ /* 24 */ 525, 532, INVALID, INVALID,
+ /* 28 */ 299, 300, 301, 302,
+ /* 2c */ 303, 304, 305, 306,
+ /* 30 */ 333, 334, 335, 336,
+ /* 34 */ 337, 338, 339, 340,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__428[] = {
+ /* 0 */ GROUP(429), GROUP(430),
+};
+
+static const uint16_t ud_itab__429[] = {
+ /* 0 */ 205, 494, 308, 358,
+ /* 4 */ 588, 613, 378, 404,
+};
+
+static const uint16_t ud_itab__430[] = {
+ /* 0 */ 207, 208, 209, 210,
+ /* 4 */ 211, 212, 213, 214,
+ /* 8 */ 495, 496, 497, 498,
+ /* c */ 499, 500, 501, 502,
+ /* 10 */ 317, 318, 319, 320,
+ /* 14 */ 321, 322, 323, 324,
+ /* 18 */ 325, 326, 327, 328,
+ /* 1c */ 329, 330, 331, 332,
+ /* 20 */ 622, 623, 624, 625,
+ /* 24 */ 626, 627, 628, 629,
+ /* 28 */ 597, 598, 599, 600,
+ /* 2c */ 601, 602, 603, 604,
+ /* 30 */ 405, 406, 407, 408,
+ /* 34 */ 409, 410, 411, 412,
+ /* 38 */ 379, 380, 381, 382,
+ /* 3c */ 383, 384, 385, 386,
+};
+
+static const uint16_t ud_itab__431[] = {
+ /* 0 */ GROUP(432), GROUP(433),
+};
+
+static const uint16_t ud_itab__432[] = {
+ /* 0 */ 475, 472, 574, 539,
+ /* 4 */ 531, INVALID, 533, 585,
+};
+
+static const uint16_t ud_itab__433[] = {
+ /* 0 */ 431, 432, 433, 434,
+ /* 4 */ 435, 436, 437, 438,
+ /* 8 */ 666, 667, 668, 669,
+ /* c */ 670, 671, 672, 673,
+ /* 10 */ 575, 576, 577, 578,
+ /* 14 */ 579, 580, 581, 582,
+ /* 18 */ 541, 542, 543, 544,
+ /* 1c */ 545, 546, 547, 548,
+ /* 20 */ 640, 641, 642, 643,
+ /* 24 */ 644, 645, 646, 647,
+ /* 28 */ 648, 649, 650, 651,
+ /* 2c */ 652, 653, 654, 655,
+ /* 30 */ INVALID, INVALID, INVALID, INVALID,
+ /* 34 */ INVALID, INVALID, INVALID, INVALID,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__434[] = {
+ /* 0 */ GROUP(435), GROUP(436),
+};
+
+static const uint16_t ud_itab__435[] = {
+ /* 0 */ 457, 521, 447, 449,
+ /* 4 */ 463, 465, 461, 459,
+};
+
+static const uint16_t ud_itab__436[] = {
+ /* 0 */ 223, 224, 225, 226,
+ /* 4 */ 227, 228, 229, 230,
+ /* 8 */ 512, 513, 514, 515,
+ /* c */ 516, 517, 518, 519,
+ /* 10 */ 367, 368, 369, 370,
+ /* 14 */ 371, 372, 373, 374,
+ /* 18 */ INVALID, 375, INVALID, INVALID,
+ /* 1c */ INVALID, INVALID, INVALID, INVALID,
+ /* 20 */ 631, 632, 633, 634,
+ /* 24 */ 635, 636, 637, 638,
+ /* 28 */ 605, 606, 607, 608,
+ /* 2c */ 609, 610, 611, 612,
+ /* 30 */ 422, 423, 424, 425,
+ /* 34 */ 426, 427, 428, 429,
+ /* 38 */ 396, 397, 398, 399,
+ /* 3c */ 400, 401, 402, 403,
+};
+
+static const uint16_t ud_itab__437[] = {
+ /* 0 */ GROUP(438), GROUP(439),
+};
+
+static const uint16_t ud_itab__438[] = {
+ /* 0 */ 451, 473, 466, 468,
+ /* 4 */ 231, 452, 232, 469,
+};
+
+static const uint16_t ud_itab__439[] = {
+ /* 0 */ 439, 440, 441, 442,
+ /* 4 */ 443, 444, 445, 446,
+ /* 8 */ 674, 675, 676, 677,
+ /* c */ 678, 679, 680, 681,
+ /* 10 */ 557, 558, 559, 560,
+ /* 14 */ 561, 562, 563, 564,
+ /* 18 */ 565, 566, 567, 568,
+ /* 1c */ 569, 570, 571, 572,
+ /* 20 */ 586, INVALID, INVALID, INVALID,
+ /* 24 */ INVALID, INVALID, INVALID, INVALID,
+ /* 28 */ 341, 342, 343, 344,
+ /* 2c */ 345, 346, 347, 348,
+ /* 30 */ 349, 350, 351, 352,
+ /* 34 */ 353, 354, 355, 356,
+ /* 38 */ INVALID, INVALID, INVALID, INVALID,
+ /* 3c */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__440[] = {
+ /* 0 */ 758, 759, 760,
+};
+
+static const uint16_t ud_itab__441[] = {
+ /* 0 */ 764, INVALID,
+};
+
+static const uint16_t ud_itab__442[] = {
+ /* 0 */ 1432, 1437, 962, 953,
+ /* 4 */ 942, 695, 186, 689,
+};
+
+static const uint16_t ud_itab__443[] = {
+ /* 0 */ 1438, 1439, 963, 954,
+ /* 4 */ 943, 696, 185, 688,
+};
+
+static const uint16_t ud_itab__444[] = {
+ /* 0 */ 708, 183, INVALID, INVALID,
+ /* 4 */ INVALID, INVALID, INVALID, INVALID,
+};
+
+static const uint16_t ud_itab__445[] = {
+ /* 0 */ 707, 184, GROUP(446), 71,
+ /* 4 */ 761, 762, 1255, INVALID,
+};
+
+static const uint16_t ud_itab__446[] = {
+ /* 0 */ 69, 70,
+};
+
+
+struct ud_lookup_table_list_entry ud_lookup_table_list[] = {
+ /* 000 */ { ud_itab__0, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 001 */ { ud_itab__1, UD_TAB__OPC_MODE, "/m" },
+ /* 002 */ { ud_itab__2, UD_TAB__OPC_MODE, "/m" },
+ /* 003 */ { ud_itab__3, UD_TAB__OPC_MODE, "/m" },
+ /* 004 */ { ud_itab__4, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 005 */ { ud_itab__5, UD_TAB__OPC_REG, "/reg" },
+ /* 006 */ { ud_itab__6, UD_TAB__OPC_MOD, "/mod" },
+ /* 007 */ { ud_itab__7, UD_TAB__OPC_REG, "/reg" },
+ /* 008 */ { ud_itab__8, UD_TAB__OPC_REG, "/reg" },
+ /* 009 */ { ud_itab__9, UD_TAB__OPC_RM, "/rm" },
+ /* 010 */ { ud_itab__10, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 011 */ { ud_itab__11, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 012 */ { ud_itab__12, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 013 */ { ud_itab__13, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 014 */ { ud_itab__14, UD_TAB__OPC_RM, "/rm" },
+ /* 015 */ { ud_itab__15, UD_TAB__OPC_RM, "/rm" },
+ /* 016 */ { ud_itab__16, UD_TAB__OPC_RM, "/rm" },
+ /* 017 */ { ud_itab__17, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 018 */ { ud_itab__18, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 019 */ { ud_itab__19, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 020 */ { ud_itab__20, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 021 */ { ud_itab__21, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 022 */ { ud_itab__22, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 023 */ { ud_itab__23, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 024 */ { ud_itab__24, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 025 */ { ud_itab__25, UD_TAB__OPC_RM, "/rm" },
+ /* 026 */ { ud_itab__26, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 027 */ { ud_itab__27, UD_TAB__OPC_REG, "/reg" },
+ /* 028 */ { ud_itab__28, UD_TAB__OPC_3DNOW, "/3dnow" },
+ /* 029 */ { ud_itab__29, UD_TAB__OPC_SSE, "/sse" },
+ /* 030 */ { ud_itab__30, UD_TAB__OPC_SSE, "/sse" },
+ /* 031 */ { ud_itab__31, UD_TAB__OPC_MOD, "/mod" },
+ /* 032 */ { ud_itab__32, UD_TAB__OPC_SSE, "/sse" },
+ /* 033 */ { ud_itab__33, UD_TAB__OPC_SSE, "/sse" },
+ /* 034 */ { ud_itab__34, UD_TAB__OPC_SSE, "/sse" },
+ /* 035 */ { ud_itab__35, UD_TAB__OPC_SSE, "/sse" },
+ /* 036 */ { ud_itab__36, UD_TAB__OPC_SSE, "/sse" },
+ /* 037 */ { ud_itab__37, UD_TAB__OPC_MOD, "/mod" },
+ /* 038 */ { ud_itab__38, UD_TAB__OPC_SSE, "/sse" },
+ /* 039 */ { ud_itab__39, UD_TAB__OPC_SSE, "/sse" },
+ /* 040 */ { ud_itab__40, UD_TAB__OPC_SSE, "/sse" },
+ /* 041 */ { ud_itab__41, UD_TAB__OPC_REG, "/reg" },
+ /* 042 */ { ud_itab__42, UD_TAB__OPC_SSE, "/sse" },
+ /* 043 */ { ud_itab__43, UD_TAB__OPC_SSE, "/sse" },
+ /* 044 */ { ud_itab__44, UD_TAB__OPC_SSE, "/sse" },
+ /* 045 */ { ud_itab__45, UD_TAB__OPC_SSE, "/sse" },
+ /* 046 */ { ud_itab__46, UD_TAB__OPC_SSE, "/sse" },
+ /* 047 */ { ud_itab__47, UD_TAB__OPC_SSE, "/sse" },
+ /* 048 */ { ud_itab__48, UD_TAB__OPC_SSE, "/sse" },
+ /* 049 */ { ud_itab__49, UD_TAB__OPC_SSE, "/sse" },
+ /* 050 */ { ud_itab__50, UD_TAB__OPC_MODE, "/m" },
+ /* 051 */ { ud_itab__51, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 052 */ { ud_itab__52, UD_TAB__OPC_MODE, "/m" },
+ /* 053 */ { ud_itab__53, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 054 */ { ud_itab__54, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 055 */ { ud_itab__55, UD_TAB__OPC_SSE, "/sse" },
+ /* 056 */ { ud_itab__56, UD_TAB__OPC_MODE, "/m" },
+ /* 057 */ { ud_itab__57, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 058 */ { ud_itab__58, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 059 */ { ud_itab__59, UD_TAB__OPC_SSE, "/sse" },
+ /* 060 */ { ud_itab__60, UD_TAB__OPC_MODE, "/m" },
+ /* 061 */ { ud_itab__61, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 062 */ { ud_itab__62, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 063 */ { ud_itab__63, UD_TAB__OPC_SSE, "/sse" },
+ /* 064 */ { ud_itab__64, UD_TAB__OPC_SSE, "/sse" },
+ /* 065 */ { ud_itab__65, UD_TAB__OPC_SSE, "/sse" },
+ /* 066 */ { ud_itab__66, UD_TAB__OPC_SSE, "/sse" },
+ /* 067 */ { ud_itab__67, UD_TAB__OPC_SSE, "/sse" },
+ /* 068 */ { ud_itab__68, UD_TAB__OPC_SSE, "/sse" },
+ /* 069 */ { ud_itab__69, UD_TAB__OPC_SSE, "/sse" },
+ /* 070 */ { ud_itab__70, UD_TAB__OPC_SSE, "/sse" },
+ /* 071 */ { ud_itab__71, UD_TAB__OPC_SSE, "/sse" },
+ /* 072 */ { ud_itab__72, UD_TAB__OPC_SSE, "/sse" },
+ /* 073 */ { ud_itab__73, UD_TAB__OPC_SSE, "/sse" },
+ /* 074 */ { ud_itab__74, UD_TAB__OPC_SSE, "/sse" },
+ /* 075 */ { ud_itab__75, UD_TAB__OPC_SSE, "/sse" },
+ /* 076 */ { ud_itab__76, UD_TAB__OPC_SSE, "/sse" },
+ /* 077 */ { ud_itab__77, UD_TAB__OPC_SSE, "/sse" },
+ /* 078 */ { ud_itab__78, UD_TAB__OPC_SSE, "/sse" },
+ /* 079 */ { ud_itab__79, UD_TAB__OPC_SSE, "/sse" },
+ /* 080 */ { ud_itab__80, UD_TAB__OPC_SSE, "/sse" },
+ /* 081 */ { ud_itab__81, UD_TAB__OPC_SSE, "/sse" },
+ /* 082 */ { ud_itab__82, UD_TAB__OPC_SSE, "/sse" },
+ /* 083 */ { ud_itab__83, UD_TAB__OPC_SSE, "/sse" },
+ /* 084 */ { ud_itab__84, UD_TAB__OPC_SSE, "/sse" },
+ /* 085 */ { ud_itab__85, UD_TAB__OPC_SSE, "/sse" },
+ /* 086 */ { ud_itab__86, UD_TAB__OPC_SSE, "/sse" },
+ /* 087 */ { ud_itab__87, UD_TAB__OPC_SSE, "/sse" },
+ /* 088 */ { ud_itab__88, UD_TAB__OPC_SSE, "/sse" },
+ /* 089 */ { ud_itab__89, UD_TAB__OPC_SSE, "/sse" },
+ /* 090 */ { ud_itab__90, UD_TAB__OPC_SSE, "/sse" },
+ /* 091 */ { ud_itab__91, UD_TAB__OPC_SSE, "/sse" },
+ /* 092 */ { ud_itab__92, UD_TAB__OPC_SSE, "/sse" },
+ /* 093 */ { ud_itab__93, UD_TAB__OPC_SSE, "/sse" },
+ /* 094 */ { ud_itab__94, UD_TAB__OPC_SSE, "/sse" },
+ /* 095 */ { ud_itab__95, UD_TAB__OPC_SSE, "/sse" },
+ /* 096 */ { ud_itab__96, UD_TAB__OPC_SSE, "/sse" },
+ /* 097 */ { ud_itab__97, UD_TAB__OPC_SSE, "/sse" },
+ /* 098 */ { ud_itab__98, UD_TAB__OPC_SSE, "/sse" },
+ /* 099 */ { ud_itab__99, UD_TAB__OPC_SSE, "/sse" },
+ /* 100 */ { ud_itab__100, UD_TAB__OPC_SSE, "/sse" },
+ /* 101 */ { ud_itab__101, UD_TAB__OPC_SSE, "/sse" },
+ /* 102 */ { ud_itab__102, UD_TAB__OPC_SSE, "/sse" },
+ /* 103 */ { ud_itab__103, UD_TAB__OPC_SSE, "/sse" },
+ /* 104 */ { ud_itab__104, UD_TAB__OPC_SSE, "/sse" },
+ /* 105 */ { ud_itab__105, UD_TAB__OPC_SSE, "/sse" },
+ /* 106 */ { ud_itab__106, UD_TAB__OPC_SSE, "/sse" },
+ /* 107 */ { ud_itab__107, UD_TAB__OPC_SSE, "/sse" },
+ /* 108 */ { ud_itab__108, UD_TAB__OPC_SSE, "/sse" },
+ /* 109 */ { ud_itab__109, UD_TAB__OPC_SSE, "/sse" },
+ /* 110 */ { ud_itab__110, UD_TAB__OPC_SSE, "/sse" },
+ /* 111 */ { ud_itab__111, UD_TAB__OPC_SSE, "/sse" },
+ /* 112 */ { ud_itab__112, UD_TAB__OPC_SSE, "/sse" },
+ /* 113 */ { ud_itab__113, UD_TAB__OPC_SSE, "/sse" },
+ /* 114 */ { ud_itab__114, UD_TAB__OPC_SSE, "/sse" },
+ /* 115 */ { ud_itab__115, UD_TAB__OPC_SSE, "/sse" },
+ /* 116 */ { ud_itab__116, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 117 */ { ud_itab__117, UD_TAB__OPC_SSE, "/sse" },
+ /* 118 */ { ud_itab__118, UD_TAB__OPC_SSE, "/sse" },
+ /* 119 */ { ud_itab__119, UD_TAB__OPC_SSE, "/sse" },
+ /* 120 */ { ud_itab__120, UD_TAB__OPC_SSE, "/sse" },
+ /* 121 */ { ud_itab__121, UD_TAB__OPC_SSE, "/sse" },
+ /* 122 */ { ud_itab__122, UD_TAB__OPC_SSE, "/sse" },
+ /* 123 */ { ud_itab__123, UD_TAB__OPC_SSE, "/sse" },
+ /* 124 */ { ud_itab__124, UD_TAB__OPC_SSE, "/sse" },
+ /* 125 */ { ud_itab__125, UD_TAB__OPC_SSE, "/sse" },
+ /* 126 */ { ud_itab__126, UD_TAB__OPC_SSE, "/sse" },
+ /* 127 */ { ud_itab__127, UD_TAB__OPC_SSE, "/sse" },
+ /* 128 */ { ud_itab__128, UD_TAB__OPC_OSIZE, "/o" },
+ /* 129 */ { ud_itab__129, UD_TAB__OPC_SSE, "/sse" },
+ /* 130 */ { ud_itab__130, UD_TAB__OPC_SSE, "/sse" },
+ /* 131 */ { ud_itab__131, UD_TAB__OPC_SSE, "/sse" },
+ /* 132 */ { ud_itab__132, UD_TAB__OPC_SSE, "/sse" },
+ /* 133 */ { ud_itab__133, UD_TAB__OPC_OSIZE, "/o" },
+ /* 134 */ { ud_itab__134, UD_TAB__OPC_SSE, "/sse" },
+ /* 135 */ { ud_itab__135, UD_TAB__OPC_SSE, "/sse" },
+ /* 136 */ { ud_itab__136, UD_TAB__OPC_SSE, "/sse" },
+ /* 137 */ { ud_itab__137, UD_TAB__OPC_SSE, "/sse" },
+ /* 138 */ { ud_itab__138, UD_TAB__OPC_SSE, "/sse" },
+ /* 139 */ { ud_itab__139, UD_TAB__OPC_SSE, "/sse" },
+ /* 140 */ { ud_itab__140, UD_TAB__OPC_SSE, "/sse" },
+ /* 141 */ { ud_itab__141, UD_TAB__OPC_SSE, "/sse" },
+ /* 142 */ { ud_itab__142, UD_TAB__OPC_SSE, "/sse" },
+ /* 143 */ { ud_itab__143, UD_TAB__OPC_SSE, "/sse" },
+ /* 144 */ { ud_itab__144, UD_TAB__OPC_SSE, "/sse" },
+ /* 145 */ { ud_itab__145, UD_TAB__OPC_SSE, "/sse" },
+ /* 146 */ { ud_itab__146, UD_TAB__OPC_SSE, "/sse" },
+ /* 147 */ { ud_itab__147, UD_TAB__OPC_SSE, "/sse" },
+ /* 148 */ { ud_itab__148, UD_TAB__OPC_SSE, "/sse" },
+ /* 149 */ { ud_itab__149, UD_TAB__OPC_SSE, "/sse" },
+ /* 150 */ { ud_itab__150, UD_TAB__OPC_SSE, "/sse" },
+ /* 151 */ { ud_itab__151, UD_TAB__OPC_SSE, "/sse" },
+ /* 152 */ { ud_itab__152, UD_TAB__OPC_SSE, "/sse" },
+ /* 153 */ { ud_itab__153, UD_TAB__OPC_SSE, "/sse" },
+ /* 154 */ { ud_itab__154, UD_TAB__OPC_SSE, "/sse" },
+ /* 155 */ { ud_itab__155, UD_TAB__OPC_SSE, "/sse" },
+ /* 156 */ { ud_itab__156, UD_TAB__OPC_SSE, "/sse" },
+ /* 157 */ { ud_itab__157, UD_TAB__OPC_SSE, "/sse" },
+ /* 158 */ { ud_itab__158, UD_TAB__OPC_SSE, "/sse" },
+ /* 159 */ { ud_itab__159, UD_TAB__OPC_SSE, "/sse" },
+ /* 160 */ { ud_itab__160, UD_TAB__OPC_SSE, "/sse" },
+ /* 161 */ { ud_itab__161, UD_TAB__OPC_SSE, "/sse" },
+ /* 162 */ { ud_itab__162, UD_TAB__OPC_SSE, "/sse" },
+ /* 163 */ { ud_itab__163, UD_TAB__OPC_SSE, "/sse" },
+ /* 164 */ { ud_itab__164, UD_TAB__OPC_SSE, "/sse" },
+ /* 165 */ { ud_itab__165, UD_TAB__OPC_SSE, "/sse" },
+ /* 166 */ { ud_itab__166, UD_TAB__OPC_SSE, "/sse" },
+ /* 167 */ { ud_itab__167, UD_TAB__OPC_SSE, "/sse" },
+ /* 168 */ { ud_itab__168, UD_TAB__OPC_SSE, "/sse" },
+ /* 169 */ { ud_itab__169, UD_TAB__OPC_SSE, "/sse" },
+ /* 170 */ { ud_itab__170, UD_TAB__OPC_SSE, "/sse" },
+ /* 171 */ { ud_itab__171, UD_TAB__OPC_SSE, "/sse" },
+ /* 172 */ { ud_itab__172, UD_TAB__OPC_SSE, "/sse" },
+ /* 173 */ { ud_itab__173, UD_TAB__OPC_SSE, "/sse" },
+ /* 174 */ { ud_itab__174, UD_TAB__OPC_OSIZE, "/o" },
+ /* 175 */ { ud_itab__175, UD_TAB__OPC_OSIZE, "/o" },
+ /* 176 */ { ud_itab__176, UD_TAB__OPC_SSE, "/sse" },
+ /* 177 */ { ud_itab__177, UD_TAB__OPC_SSE, "/sse" },
+ /* 178 */ { ud_itab__178, UD_TAB__OPC_REG, "/reg" },
+ /* 179 */ { ud_itab__179, UD_TAB__OPC_SSE, "/sse" },
+ /* 180 */ { ud_itab__180, UD_TAB__OPC_SSE, "/sse" },
+ /* 181 */ { ud_itab__181, UD_TAB__OPC_SSE, "/sse" },
+ /* 182 */ { ud_itab__182, UD_TAB__OPC_REG, "/reg" },
+ /* 183 */ { ud_itab__183, UD_TAB__OPC_SSE, "/sse" },
+ /* 184 */ { ud_itab__184, UD_TAB__OPC_SSE, "/sse" },
+ /* 185 */ { ud_itab__185, UD_TAB__OPC_SSE, "/sse" },
+ /* 186 */ { ud_itab__186, UD_TAB__OPC_REG, "/reg" },
+ /* 187 */ { ud_itab__187, UD_TAB__OPC_SSE, "/sse" },
+ /* 188 */ { ud_itab__188, UD_TAB__OPC_SSE, "/sse" },
+ /* 189 */ { ud_itab__189, UD_TAB__OPC_SSE, "/sse" },
+ /* 190 */ { ud_itab__190, UD_TAB__OPC_SSE, "/sse" },
+ /* 191 */ { ud_itab__191, UD_TAB__OPC_SSE, "/sse" },
+ /* 192 */ { ud_itab__192, UD_TAB__OPC_SSE, "/sse" },
+ /* 193 */ { ud_itab__193, UD_TAB__OPC_SSE, "/sse" },
+ /* 194 */ { ud_itab__194, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 195 */ { ud_itab__195, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 196 */ { ud_itab__196, UD_TAB__OPC_SSE, "/sse" },
+ /* 197 */ { ud_itab__197, UD_TAB__OPC_SSE, "/sse" },
+ /* 198 */ { ud_itab__198, UD_TAB__OPC_SSE, "/sse" },
+ /* 199 */ { ud_itab__199, UD_TAB__OPC_OSIZE, "/o" },
+ /* 200 */ { ud_itab__200, UD_TAB__OPC_OSIZE, "/o" },
+ /* 201 */ { ud_itab__201, UD_TAB__OPC_SSE, "/sse" },
+ /* 202 */ { ud_itab__202, UD_TAB__OPC_MOD, "/mod" },
+ /* 203 */ { ud_itab__203, UD_TAB__OPC_REG, "/reg" },
+ /* 204 */ { ud_itab__204, UD_TAB__OPC_RM, "/rm" },
+ /* 205 */ { ud_itab__205, UD_TAB__OPC_RM, "/rm" },
+ /* 206 */ { ud_itab__206, UD_TAB__OPC_RM, "/rm" },
+ /* 207 */ { ud_itab__207, UD_TAB__OPC_MOD, "/mod" },
+ /* 208 */ { ud_itab__208, UD_TAB__OPC_REG, "/reg" },
+ /* 209 */ { ud_itab__209, UD_TAB__OPC_RM, "/rm" },
+ /* 210 */ { ud_itab__210, UD_TAB__OPC_RM, "/rm" },
+ /* 211 */ { ud_itab__211, UD_TAB__OPC_RM, "/rm" },
+ /* 212 */ { ud_itab__212, UD_TAB__OPC_RM, "/rm" },
+ /* 213 */ { ud_itab__213, UD_TAB__OPC_RM, "/rm" },
+ /* 214 */ { ud_itab__214, UD_TAB__OPC_RM, "/rm" },
+ /* 215 */ { ud_itab__215, UD_TAB__OPC_MOD, "/mod" },
+ /* 216 */ { ud_itab__216, UD_TAB__OPC_REG, "/reg" },
+ /* 217 */ { ud_itab__217, UD_TAB__OPC_REG, "/reg" },
+ /* 218 */ { ud_itab__218, UD_TAB__OPC_RM, "/rm" },
+ /* 219 */ { ud_itab__219, UD_TAB__OPC_RM, "/rm" },
+ /* 220 */ { ud_itab__220, UD_TAB__OPC_RM, "/rm" },
+ /* 221 */ { ud_itab__221, UD_TAB__OPC_SSE, "/sse" },
+ /* 222 */ { ud_itab__222, UD_TAB__OPC_REG, "/reg" },
+ /* 223 */ { ud_itab__223, UD_TAB__OPC_SSE, "/sse" },
+ /* 224 */ { ud_itab__224, UD_TAB__OPC_SSE, "/sse" },
+ /* 225 */ { ud_itab__225, UD_TAB__OPC_SSE, "/sse" },
+ /* 226 */ { ud_itab__226, UD_TAB__OPC_SSE, "/sse" },
+ /* 227 */ { ud_itab__227, UD_TAB__OPC_MOD, "/mod" },
+ /* 228 */ { ud_itab__228, UD_TAB__OPC_REG, "/reg" },
+ /* 229 */ { ud_itab__229, UD_TAB__OPC_OSIZE, "/o" },
+ /* 230 */ { ud_itab__230, UD_TAB__OPC_SSE, "/sse" },
+ /* 231 */ { ud_itab__231, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 232 */ { ud_itab__232, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 233 */ { ud_itab__233, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 234 */ { ud_itab__234, UD_TAB__OPC_VENDOR, "/vendor" },
+ /* 235 */ { ud_itab__235, UD_TAB__OPC_REG, "/reg" },
+ /* 236 */ { ud_itab__236, UD_TAB__OPC_SSE, "/sse" },
+ /* 237 */ { ud_itab__237, UD_TAB__OPC_SSE, "/sse" },
+ /* 238 */ { ud_itab__238, UD_TAB__OPC_SSE, "/sse" },
+ /* 239 */ { ud_itab__239, UD_TAB__OPC_SSE, "/sse" },
+ /* 240 */ { ud_itab__240, UD_TAB__OPC_SSE, "/sse" },
+ /* 241 */ { ud_itab__241, UD_TAB__OPC_SSE, "/sse" },
+ /* 242 */ { ud_itab__242, UD_TAB__OPC_SSE, "/sse" },
+ /* 243 */ { ud_itab__243, UD_TAB__OPC_SSE, "/sse" },
+ /* 244 */ { ud_itab__244, UD_TAB__OPC_SSE, "/sse" },
+ /* 245 */ { ud_itab__245, UD_TAB__OPC_SSE, "/sse" },
+ /* 246 */ { ud_itab__246, UD_TAB__OPC_SSE, "/sse" },
+ /* 247 */ { ud_itab__247, UD_TAB__OPC_SSE, "/sse" },
+ /* 248 */ { ud_itab__248, UD_TAB__OPC_SSE, "/sse" },
+ /* 249 */ { ud_itab__249, UD_TAB__OPC_SSE, "/sse" },
+ /* 250 */ { ud_itab__250, UD_TAB__OPC_SSE, "/sse" },
+ /* 251 */ { ud_itab__251, UD_TAB__OPC_SSE, "/sse" },
+ /* 252 */ { ud_itab__252, UD_TAB__OPC_SSE, "/sse" },
+ /* 253 */ { ud_itab__253, UD_TAB__OPC_SSE, "/sse" },
+ /* 254 */ { ud_itab__254, UD_TAB__OPC_SSE, "/sse" },
+ /* 255 */ { ud_itab__255, UD_TAB__OPC_SSE, "/sse" },
+ /* 256 */ { ud_itab__256, UD_TAB__OPC_SSE, "/sse" },
+ /* 257 */ { ud_itab__257, UD_TAB__OPC_SSE, "/sse" },
+ /* 258 */ { ud_itab__258, UD_TAB__OPC_SSE, "/sse" },
+ /* 259 */ { ud_itab__259, UD_TAB__OPC_SSE, "/sse" },
+ /* 260 */ { ud_itab__260, UD_TAB__OPC_SSE, "/sse" },
+ /* 261 */ { ud_itab__261, UD_TAB__OPC_SSE, "/sse" },
+ /* 262 */ { ud_itab__262, UD_TAB__OPC_SSE, "/sse" },
+ /* 263 */ { ud_itab__263, UD_TAB__OPC_SSE, "/sse" },
+ /* 264 */ { ud_itab__264, UD_TAB__OPC_SSE, "/sse" },
+ /* 265 */ { ud_itab__265, UD_TAB__OPC_SSE, "/sse" },
+ /* 266 */ { ud_itab__266, UD_TAB__OPC_SSE, "/sse" },
+ /* 267 */ { ud_itab__267, UD_TAB__OPC_SSE, "/sse" },
+ /* 268 */ { ud_itab__268, UD_TAB__OPC_SSE, "/sse" },
+ /* 269 */ { ud_itab__269, UD_TAB__OPC_SSE, "/sse" },
+ /* 270 */ { ud_itab__270, UD_TAB__OPC_SSE, "/sse" },
+ /* 271 */ { ud_itab__271, UD_TAB__OPC_SSE, "/sse" },
+ /* 272 */ { ud_itab__272, UD_TAB__OPC_SSE, "/sse" },
+ /* 273 */ { ud_itab__273, UD_TAB__OPC_SSE, "/sse" },
+ /* 274 */ { ud_itab__274, UD_TAB__OPC_SSE, "/sse" },
+ /* 275 */ { ud_itab__275, UD_TAB__OPC_MOD, "/mod" },
+ /* 276 */ { ud_itab__276, UD_TAB__OPC_SSE, "/sse" },
+ /* 277 */ { ud_itab__277, UD_TAB__OPC_SSE, "/sse" },
+ /* 278 */ { ud_itab__278, UD_TAB__OPC_SSE, "/sse" },
+ /* 279 */ { ud_itab__279, UD_TAB__OPC_SSE, "/sse" },
+ /* 280 */ { ud_itab__280, UD_TAB__OPC_SSE, "/sse" },
+ /* 281 */ { ud_itab__281, UD_TAB__OPC_SSE, "/sse" },
+ /* 282 */ { ud_itab__282, UD_TAB__OPC_SSE, "/sse" },
+ /* 283 */ { ud_itab__283, UD_TAB__OPC_SSE, "/sse" },
+ /* 284 */ { ud_itab__284, UD_TAB__OPC_MODE, "/m" },
+ /* 285 */ { ud_itab__285, UD_TAB__OPC_MODE, "/m" },
+ /* 286 */ { ud_itab__286, UD_TAB__OPC_MODE, "/m" },
+ /* 287 */ { ud_itab__287, UD_TAB__OPC_MODE, "/m" },
+ /* 288 */ { ud_itab__288, UD_TAB__OPC_MODE, "/m" },
+ /* 289 */ { ud_itab__289, UD_TAB__OPC_MODE, "/m" },
+ /* 290 */ { ud_itab__290, UD_TAB__OPC_MODE, "/m" },
+ /* 291 */ { ud_itab__291, UD_TAB__OPC_MODE, "/m" },
+ /* 292 */ { ud_itab__292, UD_TAB__OPC_OSIZE, "/o" },
+ /* 293 */ { ud_itab__293, UD_TAB__OPC_MODE, "/m" },
+ /* 294 */ { ud_itab__294, UD_TAB__OPC_MODE, "/m" },
+ /* 295 */ { ud_itab__295, UD_TAB__OPC_OSIZE, "/o" },
+ /* 296 */ { ud_itab__296, UD_TAB__OPC_MODE, "/m" },
+ /* 297 */ { ud_itab__297, UD_TAB__OPC_MODE, "/m" },
+ /* 298 */ { ud_itab__298, UD_TAB__OPC_MODE, "/m" },
+ /* 299 */ { ud_itab__299, UD_TAB__OPC_MODE, "/m" },
+ /* 300 */ { ud_itab__300, UD_TAB__OPC_OSIZE, "/o" },
+ /* 301 */ { ud_itab__301, UD_TAB__OPC_OSIZE, "/o" },
+ /* 302 */ { ud_itab__302, UD_TAB__OPC_REG, "/reg" },
+ /* 303 */ { ud_itab__303, UD_TAB__OPC_REG, "/reg" },
+ /* 304 */ { ud_itab__304, UD_TAB__OPC_REG, "/reg" },
+ /* 305 */ { ud_itab__305, UD_TAB__OPC_MODE, "/m" },
+ /* 306 */ { ud_itab__306, UD_TAB__OPC_MODE, "/m" },
+ /* 307 */ { ud_itab__307, UD_TAB__OPC_MODE, "/m" },
+ /* 308 */ { ud_itab__308, UD_TAB__OPC_MODE, "/m" },
+ /* 309 */ { ud_itab__309, UD_TAB__OPC_MODE, "/m" },
+ /* 310 */ { ud_itab__310, UD_TAB__OPC_MODE, "/m" },
+ /* 311 */ { ud_itab__311, UD_TAB__OPC_MODE, "/m" },
+ /* 312 */ { ud_itab__312, UD_TAB__OPC_MODE, "/m" },
+ /* 313 */ { ud_itab__313, UD_TAB__OPC_REG, "/reg" },
+ /* 314 */ { ud_itab__314, UD_TAB__OPC_REG, "/reg" },
+ /* 315 */ { ud_itab__315, UD_TAB__OPC_OSIZE, "/o" },
+ /* 316 */ { ud_itab__316, UD_TAB__OPC_OSIZE, "/o" },
+ /* 317 */ { ud_itab__317, UD_TAB__OPC_MODE, "/m" },
+ /* 318 */ { ud_itab__318, UD_TAB__OPC_OSIZE, "/o" },
+ /* 319 */ { ud_itab__319, UD_TAB__OPC_MODE, "/m" },
+ /* 320 */ { ud_itab__320, UD_TAB__OPC_MODE, "/m" },
+ /* 321 */ { ud_itab__321, UD_TAB__OPC_MODE, "/m" },
+ /* 322 */ { ud_itab__322, UD_TAB__OPC_OSIZE, "/o" },
+ /* 323 */ { ud_itab__323, UD_TAB__OPC_MODE, "/m" },
+ /* 324 */ { ud_itab__324, UD_TAB__OPC_MODE, "/m" },
+ /* 325 */ { ud_itab__325, UD_TAB__OPC_MODE, "/m" },
+ /* 326 */ { ud_itab__326, UD_TAB__OPC_OSIZE, "/o" },
+ /* 327 */ { ud_itab__327, UD_TAB__OPC_OSIZE, "/o" },
+ /* 328 */ { ud_itab__328, UD_TAB__OPC_OSIZE, "/o" },
+ /* 329 */ { ud_itab__329, UD_TAB__OPC_OSIZE, "/o" },
+ /* 330 */ { ud_itab__330, UD_TAB__OPC_OSIZE, "/o" },
+ /* 331 */ { ud_itab__331, UD_TAB__OPC_REG, "/reg" },
+ /* 332 */ { ud_itab__332, UD_TAB__OPC_REG, "/reg" },
+ /* 333 */ { ud_itab__333, UD_TAB__OPC_VEX, "/vex" },
+ /* 334 */ { ud_itab__334, UD_TAB__OPC_MODE, "/m" },
+ /* 335 */ { ud_itab__335, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 336 */ { ud_itab__336, UD_TAB__OPC_MOD, "/mod" },
+ /* 337 */ { ud_itab__337, UD_TAB__OPC_MOD, "/mod" },
+ /* 338 */ { ud_itab__338, UD_TAB__OPC_MOD, "/mod" },
+ /* 339 */ { ud_itab__339, UD_TAB__OPC_REG, "/reg" },
+ /* 340 */ { ud_itab__340, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 341 */ { ud_itab__341, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 342 */ { ud_itab__342, UD_TAB__OPC_MOD, "/mod" },
+ /* 343 */ { ud_itab__343, UD_TAB__OPC_MOD, "/mod" },
+ /* 344 */ { ud_itab__344, UD_TAB__OPC_OSIZE, "/o" },
+ /* 345 */ { ud_itab__345, UD_TAB__OPC_REG, "/reg" },
+ /* 346 */ { ud_itab__346, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 347 */ { ud_itab__347, UD_TAB__OPC_REG, "/reg" },
+ /* 348 */ { ud_itab__348, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 349 */ { ud_itab__349, UD_TAB__OPC_REG, "/reg" },
+ /* 350 */ { ud_itab__350, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 351 */ { ud_itab__351, UD_TAB__OPC_OSIZE, "/o" },
+ /* 352 */ { ud_itab__352, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 353 */ { ud_itab__353, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 354 */ { ud_itab__354, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 355 */ { ud_itab__355, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 356 */ { ud_itab__356, UD_TAB__OPC_MOD, "/mod" },
+ /* 357 */ { ud_itab__357, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 358 */ { ud_itab__358, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 359 */ { ud_itab__359, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 360 */ { ud_itab__360, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 361 */ { ud_itab__361, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 362 */ { ud_itab__362, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 363 */ { ud_itab__363, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 364 */ { ud_itab__364, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 365 */ { ud_itab__365, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 366 */ { ud_itab__366, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 367 */ { ud_itab__367, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 368 */ { ud_itab__368, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 369 */ { ud_itab__369, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 370 */ { ud_itab__370, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 371 */ { ud_itab__371, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 372 */ { ud_itab__372, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 373 */ { ud_itab__373, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 374 */ { ud_itab__374, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 375 */ { ud_itab__375, UD_TAB__OPC_OSIZE, "/o" },
+ /* 376 */ { ud_itab__376, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 377 */ { ud_itab__377, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 378 */ { ud_itab__378, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 379 */ { ud_itab__379, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 380 */ { ud_itab__380, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 381 */ { ud_itab__381, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 382 */ { ud_itab__382, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 383 */ { ud_itab__383, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 384 */ { ud_itab__384, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 385 */ { ud_itab__385, UD_TAB__OPC_MODE, "/m" },
+ /* 386 */ { ud_itab__386, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 387 */ { ud_itab__387, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 388 */ { ud_itab__388, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 389 */ { ud_itab__389, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 390 */ { ud_itab__390, UD_TAB__OPC_VEX_L, "/vexl" },
+ /* 391 */ { ud_itab__391, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 392 */ { ud_itab__392, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 393 */ { ud_itab__393, UD_TAB__OPC_VEX_W, "/vexw" },
+ /* 394 */ { ud_itab__394, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 395 */ { ud_itab__395, UD_TAB__OPC_MOD, "/mod" },
+ /* 396 */ { ud_itab__396, UD_TAB__OPC_MOD, "/mod" },
+ /* 397 */ { ud_itab__397, UD_TAB__OPC_MOD, "/mod" },
+ /* 398 */ { ud_itab__398, UD_TAB__OPC_MOD, "/mod" },
+ /* 399 */ { ud_itab__399, UD_TAB__OPC_TABLE, "opctbl" },
+ /* 400 */ { ud_itab__400, UD_TAB__OPC_MOD, "/mod" },
+ /* 401 */ { ud_itab__401, UD_TAB__OPC_MOD, "/mod" },
+ /* 402 */ { ud_itab__402, UD_TAB__OPC_MOD, "/mod" },
+ /* 403 */ { ud_itab__403, UD_TAB__OPC_VEX, "/vex" },
+ /* 404 */ { ud_itab__404, UD_TAB__OPC_MODE, "/m" },
+ /* 405 */ { ud_itab__405, UD_TAB__OPC_REG, "/reg" },
+ /* 406 */ { ud_itab__406, UD_TAB__OPC_REG, "/reg" },
+ /* 407 */ { ud_itab__407, UD_TAB__OPC_MODE, "/m" },
+ /* 408 */ { ud_itab__408, UD_TAB__OPC_OSIZE, "/o" },
+ /* 409 */ { ud_itab__409, UD_TAB__OPC_REG, "/reg" },
+ /* 410 */ { ud_itab__410, UD_TAB__OPC_REG, "/reg" },
+ /* 411 */ { ud_itab__411, UD_TAB__OPC_REG, "/reg" },
+ /* 412 */ { ud_itab__412, UD_TAB__OPC_REG, "/reg" },
+ /* 413 */ { ud_itab__413, UD_TAB__OPC_MODE, "/m" },
+ /* 414 */ { ud_itab__414, UD_TAB__OPC_MODE, "/m" },
+ /* 415 */ { ud_itab__415, UD_TAB__OPC_MODE, "/m" },
+ /* 416 */ { ud_itab__416, UD_TAB__OPC_MOD, "/mod" },
+ /* 417 */ { ud_itab__417, UD_TAB__OPC_REG, "/reg" },
+ /* 418 */ { ud_itab__418, UD_TAB__OPC_X87, "/x87" },
+ /* 419 */ { ud_itab__419, UD_TAB__OPC_MOD, "/mod" },
+ /* 420 */ { ud_itab__420, UD_TAB__OPC_REG, "/reg" },
+ /* 421 */ { ud_itab__421, UD_TAB__OPC_X87, "/x87" },
+ /* 422 */ { ud_itab__422, UD_TAB__OPC_MOD, "/mod" },
+ /* 423 */ { ud_itab__423, UD_TAB__OPC_REG, "/reg" },
+ /* 424 */ { ud_itab__424, UD_TAB__OPC_X87, "/x87" },
+ /* 425 */ { ud_itab__425, UD_TAB__OPC_MOD, "/mod" },
+ /* 426 */ { ud_itab__426, UD_TAB__OPC_REG, "/reg" },
+ /* 427 */ { ud_itab__427, UD_TAB__OPC_X87, "/x87" },
+ /* 428 */ { ud_itab__428, UD_TAB__OPC_MOD, "/mod" },
+ /* 429 */ { ud_itab__429, UD_TAB__OPC_REG, "/reg" },
+ /* 430 */ { ud_itab__430, UD_TAB__OPC_X87, "/x87" },
+ /* 431 */ { ud_itab__431, UD_TAB__OPC_MOD, "/mod" },
+ /* 432 */ { ud_itab__432, UD_TAB__OPC_REG, "/reg" },
+ /* 433 */ { ud_itab__433, UD_TAB__OPC_X87, "/x87" },
+ /* 434 */ { ud_itab__434, UD_TAB__OPC_MOD, "/mod" },
+ /* 435 */ { ud_itab__435, UD_TAB__OPC_REG, "/reg" },
+ /* 436 */ { ud_itab__436, UD_TAB__OPC_X87, "/x87" },
+ /* 437 */ { ud_itab__437, UD_TAB__OPC_MOD, "/mod" },
+ /* 438 */ { ud_itab__438, UD_TAB__OPC_REG, "/reg" },
+ /* 439 */ { ud_itab__439, UD_TAB__OPC_X87, "/x87" },
+ /* 440 */ { ud_itab__440, UD_TAB__OPC_ASIZE, "/a" },
+ /* 441 */ { ud_itab__441, UD_TAB__OPC_MODE, "/m" },
+ /* 442 */ { ud_itab__442, UD_TAB__OPC_REG, "/reg" },
+ /* 443 */ { ud_itab__443, UD_TAB__OPC_REG, "/reg" },
+ /* 444 */ { ud_itab__444, UD_TAB__OPC_REG, "/reg" },
+ /* 445 */ { ud_itab__445, UD_TAB__OPC_REG, "/reg" },
+ /* 446 */ { ud_itab__446, UD_TAB__OPC_MODE, "/m" },
+};
+
+/* itab entry operand definitions (for readability) */
+#define O_AL { OP_AL, SZ_B }
+#define O_AX { OP_AX, SZ_W }
+#define O_Av { OP_A, SZ_V }
+#define O_C { OP_C, SZ_NA }
+#define O_CL { OP_CL, SZ_B }
+#define O_CS { OP_CS, SZ_NA }
+#define O_CX { OP_CX, SZ_W }
+#define O_D { OP_D, SZ_NA }
+#define O_DL { OP_DL, SZ_B }
+#define O_DS { OP_DS, SZ_NA }
+#define O_DX { OP_DX, SZ_W }
+#define O_E { OP_E, SZ_NA }
+#define O_ES { OP_ES, SZ_NA }
+#define O_Eb { OP_E, SZ_B }
+#define O_Ed { OP_E, SZ_D }
+#define O_Eq { OP_E, SZ_Q }
+#define O_Ev { OP_E, SZ_V }
+#define O_Ew { OP_E, SZ_W }
+#define O_Ey { OP_E, SZ_Y }
+#define O_Ez { OP_E, SZ_Z }
+#define O_FS { OP_FS, SZ_NA }
+#define O_Fv { OP_F, SZ_V }
+#define O_G { OP_G, SZ_NA }
+#define O_GS { OP_GS, SZ_NA }
+#define O_Gb { OP_G, SZ_B }
+#define O_Gd { OP_G, SZ_D }
+#define O_Gq { OP_G, SZ_Q }
+#define O_Gv { OP_G, SZ_V }
+#define O_Gw { OP_G, SZ_W }
+#define O_Gy { OP_G, SZ_Y }
+#define O_Gz { OP_G, SZ_Z }
+#define O_H { OP_H, SZ_X }
+#define O_Hqq { OP_H, SZ_QQ }
+#define O_Hx { OP_H, SZ_X }
+#define O_I1 { OP_I1, SZ_NA }
+#define O_I3 { OP_I3, SZ_NA }
+#define O_Ib { OP_I, SZ_B }
+#define O_Iv { OP_I, SZ_V }
+#define O_Iw { OP_I, SZ_W }
+#define O_Iz { OP_I, SZ_Z }
+#define O_Jb { OP_J, SZ_B }
+#define O_Jv { OP_J, SZ_V }
+#define O_Jz { OP_J, SZ_Z }
+#define O_L { OP_L, SZ_O }
+#define O_Lx { OP_L, SZ_X }
+#define O_M { OP_M, SZ_NA }
+#define O_Mb { OP_M, SZ_B }
+#define O_MbRd { OP_MR, SZ_BD }
+#define O_MbRv { OP_MR, SZ_BV }
+#define O_Md { OP_M, SZ_D }
+#define O_MdRy { OP_MR, SZ_DY }
+#define O_MdU { OP_MU, SZ_DO }
+#define O_Mdq { OP_M, SZ_DQ }
+#define O_Mo { OP_M, SZ_O }
+#define O_Mq { OP_M, SZ_Q }
+#define O_MqU { OP_MU, SZ_QO }
+#define O_Ms { OP_M, SZ_W }
+#define O_Mt { OP_M, SZ_T }
+#define O_Mv { OP_M, SZ_V }
+#define O_Mw { OP_M, SZ_W }
+#define O_MwRd { OP_MR, SZ_WD }
+#define O_MwRv { OP_MR, SZ_WV }
+#define O_MwRy { OP_MR, SZ_WY }
+#define O_MwU { OP_MU, SZ_WO }
+#define O_N { OP_N, SZ_Q }
+#define O_NONE { OP_NONE, SZ_NA }
+#define O_Ob { OP_O, SZ_B }
+#define O_Ov { OP_O, SZ_V }
+#define O_Ow { OP_O, SZ_W }
+#define O_P { OP_P, SZ_Q }
+#define O_Q { OP_Q, SZ_Q }
+#define O_R { OP_R, SZ_RDQ }
+#define O_R0b { OP_R0, SZ_B }
+#define O_R0v { OP_R0, SZ_V }
+#define O_R0w { OP_R0, SZ_W }
+#define O_R0y { OP_R0, SZ_Y }
+#define O_R0z { OP_R0, SZ_Z }
+#define O_R1b { OP_R1, SZ_B }
+#define O_R1v { OP_R1, SZ_V }
+#define O_R1w { OP_R1, SZ_W }
+#define O_R1y { OP_R1, SZ_Y }
+#define O_R1z { OP_R1, SZ_Z }
+#define O_R2b { OP_R2, SZ_B }
+#define O_R2v { OP_R2, SZ_V }
+#define O_R2w { OP_R2, SZ_W }
+#define O_R2y { OP_R2, SZ_Y }
+#define O_R2z { OP_R2, SZ_Z }
+#define O_R3b { OP_R3, SZ_B }
+#define O_R3v { OP_R3, SZ_V }
+#define O_R3w { OP_R3, SZ_W }
+#define O_R3y { OP_R3, SZ_Y }
+#define O_R3z { OP_R3, SZ_Z }
+#define O_R4b { OP_R4, SZ_B }
+#define O_R4v { OP_R4, SZ_V }
+#define O_R4w { OP_R4, SZ_W }
+#define O_R4y { OP_R4, SZ_Y }
+#define O_R4z { OP_R4, SZ_Z }
+#define O_R5b { OP_R5, SZ_B }
+#define O_R5v { OP_R5, SZ_V }
+#define O_R5w { OP_R5, SZ_W }
+#define O_R5y { OP_R5, SZ_Y }
+#define O_R5z { OP_R5, SZ_Z }
+#define O_R6b { OP_R6, SZ_B }
+#define O_R6v { OP_R6, SZ_V }
+#define O_R6w { OP_R6, SZ_W }
+#define O_R6y { OP_R6, SZ_Y }
+#define O_R6z { OP_R6, SZ_Z }
+#define O_R7b { OP_R7, SZ_B }
+#define O_R7v { OP_R7, SZ_V }
+#define O_R7w { OP_R7, SZ_W }
+#define O_R7y { OP_R7, SZ_Y }
+#define O_R7z { OP_R7, SZ_Z }
+#define O_S { OP_S, SZ_W }
+#define O_SS { OP_SS, SZ_NA }
+#define O_ST0 { OP_ST0, SZ_NA }
+#define O_ST1 { OP_ST1, SZ_NA }
+#define O_ST2 { OP_ST2, SZ_NA }
+#define O_ST3 { OP_ST3, SZ_NA }
+#define O_ST4 { OP_ST4, SZ_NA }
+#define O_ST5 { OP_ST5, SZ_NA }
+#define O_ST6 { OP_ST6, SZ_NA }
+#define O_ST7 { OP_ST7, SZ_NA }
+#define O_U { OP_U, SZ_O }
+#define O_Ux { OP_U, SZ_X }
+#define O_V { OP_V, SZ_DQ }
+#define O_Vdq { OP_V, SZ_DQ }
+#define O_Vqq { OP_V, SZ_QQ }
+#define O_Vsd { OP_V, SZ_Q }
+#define O_Vx { OP_V, SZ_X }
+#define O_W { OP_W, SZ_DQ }
+#define O_Wdq { OP_W, SZ_DQ }
+#define O_Wqq { OP_W, SZ_QQ }
+#define O_Wsd { OP_W, SZ_Q }
+#define O_Wx { OP_W, SZ_X }
+#define O_eAX { OP_eAX, SZ_Z }
+#define O_eCX { OP_eCX, SZ_Z }
+#define O_eDX { OP_eDX, SZ_Z }
+#define O_rAX { OP_rAX, SZ_V }
+#define O_rCX { OP_rCX, SZ_V }
+#define O_rDX { OP_rDX, SZ_V }
+#define O_sIb { OP_sI, SZ_B }
+#define O_sIv { OP_sI, SZ_V }
+#define O_sIz { OP_sI, SZ_Z }
+
+struct ud_itab_entry ud_itab[] = {
+ /* 0000 */ { UD_Iinvalid, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0001 */ { UD_Iaaa, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0002 */ { UD_Iaad, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0003 */ { UD_Iaam, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0004 */ { UD_Iaas, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0005 */ { UD_Iadc, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0006 */ { UD_Iadc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0007 */ { UD_Iadc, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0008 */ { UD_Iadc, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0009 */ { UD_Iadc, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0010 */ { UD_Iadc, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0011 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0012 */ { UD_Iadc, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0013 */ { UD_Iadc, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0014 */ { UD_Iadc, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0015 */ { UD_Iadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0016 */ { UD_Iadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0017 */ { UD_Iadd, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0018 */ { UD_Iadd, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0019 */ { UD_Iadd, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0020 */ { UD_Iadd, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0021 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0022 */ { UD_Iadd, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0023 */ { UD_Iadd, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0024 */ { UD_Iadd, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0025 */ { UD_Iaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0026 */ { UD_Ivaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0027 */ { UD_Iaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0028 */ { UD_Ivaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0029 */ { UD_Iaddsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0030 */ { UD_Ivaddsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0031 */ { UD_Iaddss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0032 */ { UD_Ivaddss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0033 */ { UD_Iaddsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0034 */ { UD_Ivaddsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0035 */ { UD_Iaddsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0036 */ { UD_Ivaddsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0037 */ { UD_Iaesdec, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0038 */ { UD_Ivaesdec, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0039 */ { UD_Iaesdeclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0040 */ { UD_Ivaesdeclast, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0041 */ { UD_Iaesenc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0042 */ { UD_Ivaesenc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0043 */ { UD_Iaesenclast, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0044 */ { UD_Ivaesenclast, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0045 */ { UD_Iaesimc, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0046 */ { UD_Ivaesimc, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0047 */ { UD_Iaeskeygenassist, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0048 */ { UD_Ivaeskeygenassist, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0049 */ { UD_Iand, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0050 */ { UD_Iand, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0051 */ { UD_Iand, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0052 */ { UD_Iand, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0053 */ { UD_Iand, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0054 */ { UD_Iand, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0055 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0056 */ { UD_Iand, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0057 */ { UD_Iand, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0058 */ { UD_Iand, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0059 */ { UD_Iandpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0060 */ { UD_Ivandpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0061 */ { UD_Iandps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0062 */ { UD_Ivandps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0063 */ { UD_Iandnpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0064 */ { UD_Ivandnpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0065 */ { UD_Iandnps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0066 */ { UD_Ivandnps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0067 */ { UD_Iarpl, O_Ew, O_Gw, O_NONE, O_NONE, P_aso },
+ /* 0068 */ { UD_Imovsxd, O_Gq, O_Ed, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 0069 */ { UD_Icall, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0070 */ { UD_Icall, O_Eq, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 0071 */ { UD_Icall, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0072 */ { UD_Icall, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0073 */ { UD_Icall, O_Av, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0074 */ { UD_Icbw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0075 */ { UD_Icwde, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0076 */ { UD_Icdqe, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0077 */ { UD_Iclc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0078 */ { UD_Icld, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0079 */ { UD_Iclflush, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0080 */ { UD_Iclgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0081 */ { UD_Icli, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0082 */ { UD_Iclts, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0083 */ { UD_Icmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0084 */ { UD_Icmovo, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0085 */ { UD_Icmovno, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0086 */ { UD_Icmovb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0087 */ { UD_Icmovae, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0088 */ { UD_Icmovz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0089 */ { UD_Icmovnz, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0090 */ { UD_Icmovbe, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0091 */ { UD_Icmova, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0092 */ { UD_Icmovs, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0093 */ { UD_Icmovns, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0094 */ { UD_Icmovp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0095 */ { UD_Icmovnp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0096 */ { UD_Icmovl, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0097 */ { UD_Icmovge, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0098 */ { UD_Icmovle, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0099 */ { UD_Icmovg, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0100 */ { UD_Icmp, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0101 */ { UD_Icmp, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0102 */ { UD_Icmp, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0103 */ { UD_Icmp, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0104 */ { UD_Icmp, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0105 */ { UD_Icmp, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0106 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0107 */ { UD_Icmp, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 0108 */ { UD_Icmp, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0109 */ { UD_Icmp, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0110 */ { UD_Icmppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0111 */ { UD_Ivcmppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0112 */ { UD_Icmpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0113 */ { UD_Ivcmpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0114 */ { UD_Icmpsb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_seg },
+ /* 0115 */ { UD_Icmpsw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0116 */ { UD_Icmpsd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0117 */ { UD_Icmpsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0118 */ { UD_Ivcmpsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0119 */ { UD_Icmpsq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw|P_seg },
+ /* 0120 */ { UD_Icmpss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0121 */ { UD_Ivcmpss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0122 */ { UD_Icmpxchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0123 */ { UD_Icmpxchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0124 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0125 */ { UD_Icmpxchg8b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0126 */ { UD_Icmpxchg16b, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0127 */ { UD_Icomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0128 */ { UD_Ivcomisd, O_Vsd, O_Wsd, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0129 */ { UD_Icomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0130 */ { UD_Ivcomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0131 */ { UD_Icpuid, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0132 */ { UD_Icvtdq2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0133 */ { UD_Ivcvtdq2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0134 */ { UD_Icvtdq2ps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0135 */ { UD_Ivcvtdq2ps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0136 */ { UD_Icvtpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0137 */ { UD_Ivcvtpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0138 */ { UD_Icvtpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0139 */ { UD_Icvtpd2ps, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0140 */ { UD_Ivcvtpd2ps, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0141 */ { UD_Icvtpi2ps, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0142 */ { UD_Icvtpi2pd, O_V, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0143 */ { UD_Icvtps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0144 */ { UD_Ivcvtps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0145 */ { UD_Icvtps2pd, O_V, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0146 */ { UD_Ivcvtps2pd, O_Vx, O_Wdq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0147 */ { UD_Icvtps2pi, O_P, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0148 */ { UD_Icvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0149 */ { UD_Ivcvtsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0150 */ { UD_Icvtsd2ss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0151 */ { UD_Ivcvtsd2ss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0152 */ { UD_Icvtsi2sd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0153 */ { UD_Ivcvtsi2sd, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0154 */ { UD_Icvtsi2ss, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0155 */ { UD_Ivcvtsi2ss, O_Vx, O_Hx, O_Ey, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0156 */ { UD_Icvtss2sd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0157 */ { UD_Ivcvtss2sd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0158 */ { UD_Icvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0159 */ { UD_Ivcvtss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0160 */ { UD_Icvttpd2dq, O_Vdq, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0161 */ { UD_Ivcvttpd2dq, O_Vdq, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0162 */ { UD_Icvttpd2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0163 */ { UD_Icvttps2dq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0164 */ { UD_Ivcvttps2dq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0165 */ { UD_Icvttps2pi, O_P, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0166 */ { UD_Icvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0167 */ { UD_Ivcvttsd2si, O_Gy, O_MqU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0168 */ { UD_Icvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0169 */ { UD_Ivcvttss2si, O_Gy, O_MdU, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0170 */ { UD_Icwd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0171 */ { UD_Icdq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0172 */ { UD_Icqo, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0173 */ { UD_Idaa, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0174 */ { UD_Idas, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0175 */ { UD_Idec, O_R0z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0176 */ { UD_Idec, O_R1z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0177 */ { UD_Idec, O_R2z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0178 */ { UD_Idec, O_R3z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0179 */ { UD_Idec, O_R4z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0180 */ { UD_Idec, O_R5z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0181 */ { UD_Idec, O_R6z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0182 */ { UD_Idec, O_R7z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0183 */ { UD_Idec, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0184 */ { UD_Idec, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0185 */ { UD_Idiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0186 */ { UD_Idiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0187 */ { UD_Idivpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0188 */ { UD_Ivdivpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0189 */ { UD_Idivps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0190 */ { UD_Ivdivps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0191 */ { UD_Idivsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0192 */ { UD_Ivdivsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0193 */ { UD_Idivss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0194 */ { UD_Ivdivss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0195 */ { UD_Idppd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0196 */ { UD_Ivdppd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0197 */ { UD_Idpps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0198 */ { UD_Ivdpps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0199 */ { UD_Iemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0200 */ { UD_Ienter, O_Iw, O_Ib, O_NONE, O_NONE, P_def64 },
+ /* 0201 */ { UD_Iextractps, O_MdRy, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 0202 */ { UD_Ivextractps, O_MdRy, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 0203 */ { UD_If2xm1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0204 */ { UD_Ifabs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0205 */ { UD_Ifadd, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0206 */ { UD_Ifadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0207 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0208 */ { UD_Ifadd, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0209 */ { UD_Ifadd, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0210 */ { UD_Ifadd, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0211 */ { UD_Ifadd, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0212 */ { UD_Ifadd, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0213 */ { UD_Ifadd, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0214 */ { UD_Ifadd, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0215 */ { UD_Ifadd, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0216 */ { UD_Ifadd, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0217 */ { UD_Ifadd, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0218 */ { UD_Ifadd, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0219 */ { UD_Ifadd, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0220 */ { UD_Ifadd, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0221 */ { UD_Ifadd, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0222 */ { UD_Ifadd, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0223 */ { UD_Ifaddp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0224 */ { UD_Ifaddp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0225 */ { UD_Ifaddp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0226 */ { UD_Ifaddp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0227 */ { UD_Ifaddp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0228 */ { UD_Ifaddp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0229 */ { UD_Ifaddp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0230 */ { UD_Ifaddp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0231 */ { UD_Ifbld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0232 */ { UD_Ifbstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0233 */ { UD_Ifchs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0234 */ { UD_Ifclex, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0235 */ { UD_Ifcmovb, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0236 */ { UD_Ifcmovb, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0237 */ { UD_Ifcmovb, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0238 */ { UD_Ifcmovb, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0239 */ { UD_Ifcmovb, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0240 */ { UD_Ifcmovb, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0241 */ { UD_Ifcmovb, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0242 */ { UD_Ifcmovb, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0243 */ { UD_Ifcmove, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0244 */ { UD_Ifcmove, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0245 */ { UD_Ifcmove, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0246 */ { UD_Ifcmove, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0247 */ { UD_Ifcmove, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0248 */ { UD_Ifcmove, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0249 */ { UD_Ifcmove, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0250 */ { UD_Ifcmove, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0251 */ { UD_Ifcmovbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0252 */ { UD_Ifcmovbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0253 */ { UD_Ifcmovbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0254 */ { UD_Ifcmovbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0255 */ { UD_Ifcmovbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0256 */ { UD_Ifcmovbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0257 */ { UD_Ifcmovbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0258 */ { UD_Ifcmovbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0259 */ { UD_Ifcmovu, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0260 */ { UD_Ifcmovu, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0261 */ { UD_Ifcmovu, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0262 */ { UD_Ifcmovu, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0263 */ { UD_Ifcmovu, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0264 */ { UD_Ifcmovu, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0265 */ { UD_Ifcmovu, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0266 */ { UD_Ifcmovu, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0267 */ { UD_Ifcmovnb, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0268 */ { UD_Ifcmovnb, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0269 */ { UD_Ifcmovnb, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0270 */ { UD_Ifcmovnb, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0271 */ { UD_Ifcmovnb, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0272 */ { UD_Ifcmovnb, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0273 */ { UD_Ifcmovnb, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0274 */ { UD_Ifcmovnb, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0275 */ { UD_Ifcmovne, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0276 */ { UD_Ifcmovne, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0277 */ { UD_Ifcmovne, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0278 */ { UD_Ifcmovne, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0279 */ { UD_Ifcmovne, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0280 */ { UD_Ifcmovne, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0281 */ { UD_Ifcmovne, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0282 */ { UD_Ifcmovne, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0283 */ { UD_Ifcmovnbe, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0284 */ { UD_Ifcmovnbe, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0285 */ { UD_Ifcmovnbe, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0286 */ { UD_Ifcmovnbe, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0287 */ { UD_Ifcmovnbe, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0288 */ { UD_Ifcmovnbe, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0289 */ { UD_Ifcmovnbe, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0290 */ { UD_Ifcmovnbe, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0291 */ { UD_Ifcmovnu, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0292 */ { UD_Ifcmovnu, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0293 */ { UD_Ifcmovnu, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0294 */ { UD_Ifcmovnu, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0295 */ { UD_Ifcmovnu, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0296 */ { UD_Ifcmovnu, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0297 */ { UD_Ifcmovnu, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0298 */ { UD_Ifcmovnu, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0299 */ { UD_Ifucomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0300 */ { UD_Ifucomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0301 */ { UD_Ifucomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0302 */ { UD_Ifucomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0303 */ { UD_Ifucomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0304 */ { UD_Ifucomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0305 */ { UD_Ifucomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0306 */ { UD_Ifucomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0307 */ { UD_Ifcom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0308 */ { UD_Ifcom, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0309 */ { UD_Ifcom, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0310 */ { UD_Ifcom, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0311 */ { UD_Ifcom, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0312 */ { UD_Ifcom, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0313 */ { UD_Ifcom, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0314 */ { UD_Ifcom, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0315 */ { UD_Ifcom, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0316 */ { UD_Ifcom, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0317 */ { UD_Ifcom2, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0318 */ { UD_Ifcom2, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0319 */ { UD_Ifcom2, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0320 */ { UD_Ifcom2, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0321 */ { UD_Ifcom2, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0322 */ { UD_Ifcom2, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0323 */ { UD_Ifcom2, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0324 */ { UD_Ifcom2, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0325 */ { UD_Ifcomp3, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0326 */ { UD_Ifcomp3, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0327 */ { UD_Ifcomp3, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0328 */ { UD_Ifcomp3, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0329 */ { UD_Ifcomp3, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0330 */ { UD_Ifcomp3, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0331 */ { UD_Ifcomp3, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0332 */ { UD_Ifcomp3, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0333 */ { UD_Ifcomi, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0334 */ { UD_Ifcomi, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0335 */ { UD_Ifcomi, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0336 */ { UD_Ifcomi, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0337 */ { UD_Ifcomi, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0338 */ { UD_Ifcomi, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0339 */ { UD_Ifcomi, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0340 */ { UD_Ifcomi, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0341 */ { UD_Ifucomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0342 */ { UD_Ifucomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0343 */ { UD_Ifucomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0344 */ { UD_Ifucomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0345 */ { UD_Ifucomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0346 */ { UD_Ifucomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0347 */ { UD_Ifucomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0348 */ { UD_Ifucomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0349 */ { UD_Ifcomip, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0350 */ { UD_Ifcomip, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0351 */ { UD_Ifcomip, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0352 */ { UD_Ifcomip, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0353 */ { UD_Ifcomip, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0354 */ { UD_Ifcomip, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0355 */ { UD_Ifcomip, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0356 */ { UD_Ifcomip, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0357 */ { UD_Ifcomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0358 */ { UD_Ifcomp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0359 */ { UD_Ifcomp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0360 */ { UD_Ifcomp, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0361 */ { UD_Ifcomp, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0362 */ { UD_Ifcomp, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0363 */ { UD_Ifcomp, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0364 */ { UD_Ifcomp, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0365 */ { UD_Ifcomp, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0366 */ { UD_Ifcomp, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0367 */ { UD_Ifcomp5, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0368 */ { UD_Ifcomp5, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0369 */ { UD_Ifcomp5, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0370 */ { UD_Ifcomp5, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0371 */ { UD_Ifcomp5, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0372 */ { UD_Ifcomp5, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0373 */ { UD_Ifcomp5, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0374 */ { UD_Ifcomp5, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0375 */ { UD_Ifcompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0376 */ { UD_Ifcos, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0377 */ { UD_Ifdecstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0378 */ { UD_Ifdiv, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0379 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0380 */ { UD_Ifdiv, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0381 */ { UD_Ifdiv, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0382 */ { UD_Ifdiv, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0383 */ { UD_Ifdiv, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0384 */ { UD_Ifdiv, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0385 */ { UD_Ifdiv, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0386 */ { UD_Ifdiv, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0387 */ { UD_Ifdiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0388 */ { UD_Ifdiv, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0389 */ { UD_Ifdiv, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0390 */ { UD_Ifdiv, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0391 */ { UD_Ifdiv, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0392 */ { UD_Ifdiv, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0393 */ { UD_Ifdiv, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0394 */ { UD_Ifdiv, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0395 */ { UD_Ifdiv, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0396 */ { UD_Ifdivp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0397 */ { UD_Ifdivp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0398 */ { UD_Ifdivp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0399 */ { UD_Ifdivp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0400 */ { UD_Ifdivp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0401 */ { UD_Ifdivp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0402 */ { UD_Ifdivp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0403 */ { UD_Ifdivp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0404 */ { UD_Ifdivr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0405 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0406 */ { UD_Ifdivr, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0407 */ { UD_Ifdivr, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0408 */ { UD_Ifdivr, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0409 */ { UD_Ifdivr, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0410 */ { UD_Ifdivr, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0411 */ { UD_Ifdivr, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0412 */ { UD_Ifdivr, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0413 */ { UD_Ifdivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0414 */ { UD_Ifdivr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0415 */ { UD_Ifdivr, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0416 */ { UD_Ifdivr, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0417 */ { UD_Ifdivr, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0418 */ { UD_Ifdivr, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0419 */ { UD_Ifdivr, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0420 */ { UD_Ifdivr, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0421 */ { UD_Ifdivr, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0422 */ { UD_Ifdivrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0423 */ { UD_Ifdivrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0424 */ { UD_Ifdivrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0425 */ { UD_Ifdivrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0426 */ { UD_Ifdivrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0427 */ { UD_Ifdivrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0428 */ { UD_Ifdivrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0429 */ { UD_Ifdivrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0430 */ { UD_Ifemms, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0431 */ { UD_Iffree, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0432 */ { UD_Iffree, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0433 */ { UD_Iffree, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0434 */ { UD_Iffree, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0435 */ { UD_Iffree, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0436 */ { UD_Iffree, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0437 */ { UD_Iffree, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0438 */ { UD_Iffree, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0439 */ { UD_Iffreep, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0440 */ { UD_Iffreep, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0441 */ { UD_Iffreep, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0442 */ { UD_Iffreep, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0443 */ { UD_Iffreep, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0444 */ { UD_Iffreep, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0445 */ { UD_Iffreep, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0446 */ { UD_Iffreep, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0447 */ { UD_Ificom, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0448 */ { UD_Ificom, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0449 */ { UD_Ificomp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0450 */ { UD_Ificomp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0451 */ { UD_Ifild, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0452 */ { UD_Ifild, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0453 */ { UD_Ifild, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0454 */ { UD_Ifincstp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0455 */ { UD_Ifninit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0456 */ { UD_Ifiadd, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0457 */ { UD_Ifiadd, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0458 */ { UD_Ifidivr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0459 */ { UD_Ifidivr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0460 */ { UD_Ifidiv, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0461 */ { UD_Ifidiv, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0462 */ { UD_Ifisub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0463 */ { UD_Ifisub, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0464 */ { UD_Ifisubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0465 */ { UD_Ifisubr, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0466 */ { UD_Ifist, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0467 */ { UD_Ifist, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0468 */ { UD_Ifistp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0469 */ { UD_Ifistp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0470 */ { UD_Ifistp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0471 */ { UD_Ifisttp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0472 */ { UD_Ifisttp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0473 */ { UD_Ifisttp, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0474 */ { UD_Ifld, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0475 */ { UD_Ifld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0476 */ { UD_Ifld, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0477 */ { UD_Ifld, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0478 */ { UD_Ifld, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0479 */ { UD_Ifld, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0480 */ { UD_Ifld, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0481 */ { UD_Ifld, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0482 */ { UD_Ifld, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0483 */ { UD_Ifld, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0484 */ { UD_Ifld, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0485 */ { UD_Ifld1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0486 */ { UD_Ifldl2t, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0487 */ { UD_Ifldl2e, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0488 */ { UD_Ifldpi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0489 */ { UD_Ifldlg2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0490 */ { UD_Ifldln2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0491 */ { UD_Ifldz, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0492 */ { UD_Ifldcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0493 */ { UD_Ifldenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0494 */ { UD_Ifmul, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0495 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0496 */ { UD_Ifmul, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0497 */ { UD_Ifmul, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0498 */ { UD_Ifmul, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0499 */ { UD_Ifmul, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0500 */ { UD_Ifmul, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0501 */ { UD_Ifmul, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0502 */ { UD_Ifmul, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0503 */ { UD_Ifmul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0504 */ { UD_Ifmul, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0505 */ { UD_Ifmul, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0506 */ { UD_Ifmul, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0507 */ { UD_Ifmul, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0508 */ { UD_Ifmul, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0509 */ { UD_Ifmul, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0510 */ { UD_Ifmul, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0511 */ { UD_Ifmul, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0512 */ { UD_Ifmulp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0513 */ { UD_Ifmulp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0514 */ { UD_Ifmulp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0515 */ { UD_Ifmulp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0516 */ { UD_Ifmulp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0517 */ { UD_Ifmulp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0518 */ { UD_Ifmulp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0519 */ { UD_Ifmulp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0520 */ { UD_Ifimul, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0521 */ { UD_Ifimul, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0522 */ { UD_Ifnop, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0523 */ { UD_Ifndisi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0524 */ { UD_Ifneni, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0525 */ { UD_Ifnsetpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0526 */ { UD_Ifpatan, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0527 */ { UD_Ifprem, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0528 */ { UD_Ifprem1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0529 */ { UD_Ifptan, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0530 */ { UD_Ifrndint, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0531 */ { UD_Ifrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0532 */ { UD_Ifrstpm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0533 */ { UD_Ifnsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0534 */ { UD_Ifscale, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0535 */ { UD_Ifsin, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0536 */ { UD_Ifsincos, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0537 */ { UD_Ifsqrt, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0538 */ { UD_Ifstp, O_Mt, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0539 */ { UD_Ifstp, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0540 */ { UD_Ifstp, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0541 */ { UD_Ifstp, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0542 */ { UD_Ifstp, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0543 */ { UD_Ifstp, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0544 */ { UD_Ifstp, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0545 */ { UD_Ifstp, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0546 */ { UD_Ifstp, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0547 */ { UD_Ifstp, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0548 */ { UD_Ifstp, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0549 */ { UD_Ifstp1, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0550 */ { UD_Ifstp1, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0551 */ { UD_Ifstp1, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0552 */ { UD_Ifstp1, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0553 */ { UD_Ifstp1, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0554 */ { UD_Ifstp1, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0555 */ { UD_Ifstp1, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0556 */ { UD_Ifstp1, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0557 */ { UD_Ifstp8, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0558 */ { UD_Ifstp8, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0559 */ { UD_Ifstp8, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0560 */ { UD_Ifstp8, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0561 */ { UD_Ifstp8, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0562 */ { UD_Ifstp8, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0563 */ { UD_Ifstp8, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0564 */ { UD_Ifstp8, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0565 */ { UD_Ifstp9, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0566 */ { UD_Ifstp9, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0567 */ { UD_Ifstp9, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0568 */ { UD_Ifstp9, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0569 */ { UD_Ifstp9, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0570 */ { UD_Ifstp9, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0571 */ { UD_Ifstp9, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0572 */ { UD_Ifstp9, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0573 */ { UD_Ifst, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0574 */ { UD_Ifst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0575 */ { UD_Ifst, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0576 */ { UD_Ifst, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0577 */ { UD_Ifst, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0578 */ { UD_Ifst, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0579 */ { UD_Ifst, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0580 */ { UD_Ifst, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0581 */ { UD_Ifst, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0582 */ { UD_Ifst, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0583 */ { UD_Ifnstcw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0584 */ { UD_Ifnstenv, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0585 */ { UD_Ifnstsw, O_Mw, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0586 */ { UD_Ifnstsw, O_AX, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0587 */ { UD_Ifsub, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0588 */ { UD_Ifsub, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0589 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0590 */ { UD_Ifsub, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0591 */ { UD_Ifsub, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0592 */ { UD_Ifsub, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0593 */ { UD_Ifsub, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0594 */ { UD_Ifsub, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0595 */ { UD_Ifsub, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0596 */ { UD_Ifsub, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0597 */ { UD_Ifsub, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0598 */ { UD_Ifsub, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0599 */ { UD_Ifsub, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0600 */ { UD_Ifsub, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0601 */ { UD_Ifsub, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0602 */ { UD_Ifsub, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0603 */ { UD_Ifsub, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0604 */ { UD_Ifsub, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0605 */ { UD_Ifsubp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0606 */ { UD_Ifsubp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0607 */ { UD_Ifsubp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0608 */ { UD_Ifsubp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0609 */ { UD_Ifsubp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0610 */ { UD_Ifsubp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0611 */ { UD_Ifsubp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0612 */ { UD_Ifsubp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0613 */ { UD_Ifsubr, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0614 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0615 */ { UD_Ifsubr, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0616 */ { UD_Ifsubr, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0617 */ { UD_Ifsubr, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0618 */ { UD_Ifsubr, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0619 */ { UD_Ifsubr, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0620 */ { UD_Ifsubr, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0621 */ { UD_Ifsubr, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0622 */ { UD_Ifsubr, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0623 */ { UD_Ifsubr, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0624 */ { UD_Ifsubr, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0625 */ { UD_Ifsubr, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0626 */ { UD_Ifsubr, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0627 */ { UD_Ifsubr, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0628 */ { UD_Ifsubr, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0629 */ { UD_Ifsubr, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0630 */ { UD_Ifsubr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0631 */ { UD_Ifsubrp, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0632 */ { UD_Ifsubrp, O_ST1, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0633 */ { UD_Ifsubrp, O_ST2, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0634 */ { UD_Ifsubrp, O_ST3, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0635 */ { UD_Ifsubrp, O_ST4, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0636 */ { UD_Ifsubrp, O_ST5, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0637 */ { UD_Ifsubrp, O_ST6, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0638 */ { UD_Ifsubrp, O_ST7, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0639 */ { UD_Iftst, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0640 */ { UD_Ifucom, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0641 */ { UD_Ifucom, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0642 */ { UD_Ifucom, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0643 */ { UD_Ifucom, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0644 */ { UD_Ifucom, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0645 */ { UD_Ifucom, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0646 */ { UD_Ifucom, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0647 */ { UD_Ifucom, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0648 */ { UD_Ifucomp, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0649 */ { UD_Ifucomp, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0650 */ { UD_Ifucomp, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0651 */ { UD_Ifucomp, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0652 */ { UD_Ifucomp, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0653 */ { UD_Ifucomp, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0654 */ { UD_Ifucomp, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0655 */ { UD_Ifucomp, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0656 */ { UD_Ifucompp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0657 */ { UD_Ifxam, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0658 */ { UD_Ifxch, O_ST0, O_ST0, O_NONE, O_NONE, P_none },
+ /* 0659 */ { UD_Ifxch, O_ST0, O_ST1, O_NONE, O_NONE, P_none },
+ /* 0660 */ { UD_Ifxch, O_ST0, O_ST2, O_NONE, O_NONE, P_none },
+ /* 0661 */ { UD_Ifxch, O_ST0, O_ST3, O_NONE, O_NONE, P_none },
+ /* 0662 */ { UD_Ifxch, O_ST0, O_ST4, O_NONE, O_NONE, P_none },
+ /* 0663 */ { UD_Ifxch, O_ST0, O_ST5, O_NONE, O_NONE, P_none },
+ /* 0664 */ { UD_Ifxch, O_ST0, O_ST6, O_NONE, O_NONE, P_none },
+ /* 0665 */ { UD_Ifxch, O_ST0, O_ST7, O_NONE, O_NONE, P_none },
+ /* 0666 */ { UD_Ifxch4, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0667 */ { UD_Ifxch4, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0668 */ { UD_Ifxch4, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0669 */ { UD_Ifxch4, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0670 */ { UD_Ifxch4, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0671 */ { UD_Ifxch4, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0672 */ { UD_Ifxch4, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0673 */ { UD_Ifxch4, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0674 */ { UD_Ifxch7, O_ST0, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0675 */ { UD_Ifxch7, O_ST1, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0676 */ { UD_Ifxch7, O_ST2, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0677 */ { UD_Ifxch7, O_ST3, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0678 */ { UD_Ifxch7, O_ST4, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0679 */ { UD_Ifxch7, O_ST5, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0680 */ { UD_Ifxch7, O_ST6, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0681 */ { UD_Ifxch7, O_ST7, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0682 */ { UD_Ifxrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0683 */ { UD_Ifxsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0684 */ { UD_Ifxtract, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0685 */ { UD_Ifyl2x, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0686 */ { UD_Ifyl2xp1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0687 */ { UD_Ihlt, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0688 */ { UD_Iidiv, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0689 */ { UD_Iidiv, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0690 */ { UD_Iin, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0691 */ { UD_Iin, O_eAX, O_Ib, O_NONE, O_NONE, P_oso },
+ /* 0692 */ { UD_Iin, O_AL, O_DX, O_NONE, O_NONE, P_none },
+ /* 0693 */ { UD_Iin, O_eAX, O_DX, O_NONE, O_NONE, P_oso },
+ /* 0694 */ { UD_Iimul, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0695 */ { UD_Iimul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0696 */ { UD_Iimul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0697 */ { UD_Iimul, O_Gv, O_Ev, O_Iz, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0698 */ { UD_Iimul, O_Gv, O_Ev, O_sIb, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0699 */ { UD_Iinc, O_R0z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0700 */ { UD_Iinc, O_R1z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0701 */ { UD_Iinc, O_R2z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0702 */ { UD_Iinc, O_R3z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0703 */ { UD_Iinc, O_R4z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0704 */ { UD_Iinc, O_R5z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0705 */ { UD_Iinc, O_R6z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0706 */ { UD_Iinc, O_R7z, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0707 */ { UD_Iinc, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0708 */ { UD_Iinc, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0709 */ { UD_Iinsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0710 */ { UD_Iinsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0711 */ { UD_Iinsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0712 */ { UD_Iint1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0713 */ { UD_Iint3, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0714 */ { UD_Iint, O_Ib, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0715 */ { UD_Iinto, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 0716 */ { UD_Iinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0717 */ { UD_Iinvept, O_Gd, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0718 */ { UD_Iinvept, O_Gq, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0719 */ { UD_Iinvlpg, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0720 */ { UD_Iinvlpga, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0721 */ { UD_Iinvvpid, O_Gd, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0722 */ { UD_Iinvvpid, O_Gq, O_Mo, O_NONE, O_NONE, P_none },
+ /* 0723 */ { UD_Iiretw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0724 */ { UD_Iiretd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0725 */ { UD_Iiretq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0726 */ { UD_Ijo, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0727 */ { UD_Ijo, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0728 */ { UD_Ijno, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0729 */ { UD_Ijno, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0730 */ { UD_Ijb, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0731 */ { UD_Ijb, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0732 */ { UD_Ijae, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0733 */ { UD_Ijae, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0734 */ { UD_Ijz, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0735 */ { UD_Ijz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0736 */ { UD_Ijnz, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0737 */ { UD_Ijnz, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0738 */ { UD_Ijbe, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0739 */ { UD_Ijbe, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0740 */ { UD_Ija, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0741 */ { UD_Ija, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0742 */ { UD_Ijs, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0743 */ { UD_Ijs, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0744 */ { UD_Ijns, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0745 */ { UD_Ijns, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0746 */ { UD_Ijp, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0747 */ { UD_Ijp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0748 */ { UD_Ijnp, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0749 */ { UD_Ijnp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0750 */ { UD_Ijl, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0751 */ { UD_Ijl, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0752 */ { UD_Ijge, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0753 */ { UD_Ijge, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0754 */ { UD_Ijle, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0755 */ { UD_Ijle, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0756 */ { UD_Ijg, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0757 */ { UD_Ijg, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0758 */ { UD_Ijcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0759 */ { UD_Ijecxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0760 */ { UD_Ijrcxz, O_Jb, O_NONE, O_NONE, O_NONE, P_aso },
+ /* 0761 */ { UD_Ijmp, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 0762 */ { UD_Ijmp, O_Fv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0763 */ { UD_Ijmp, O_Jz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 0764 */ { UD_Ijmp, O_Av, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 0765 */ { UD_Ijmp, O_Jb, O_NONE, O_NONE, O_NONE, P_def64 },
+ /* 0766 */ { UD_Ilahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0767 */ { UD_Ilar, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0768 */ { UD_Ildmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0769 */ { UD_Ilds, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 0770 */ { UD_Ilea, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0771 */ { UD_Iles, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 0772 */ { UD_Ilfs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0773 */ { UD_Ilgs, O_Gz, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0774 */ { UD_Ilidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0775 */ { UD_Ilss, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0776 */ { UD_Ileave, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0777 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0778 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0779 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0780 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0781 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0782 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0783 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0784 */ { UD_Ilfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0785 */ { UD_Ilgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0786 */ { UD_Illdt, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0787 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0788 */ { UD_Ilmsw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0789 */ { UD_Ilock, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0790 */ { UD_Ilodsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0791 */ { UD_Ilodsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0792 */ { UD_Ilodsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0793 */ { UD_Ilodsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0794 */ { UD_Iloopne, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0795 */ { UD_Iloope, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0796 */ { UD_Iloop, O_Jb, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0797 */ { UD_Ilsl, O_Gv, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0798 */ { UD_Iltr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0799 */ { UD_Imaskmovq, O_P, O_N, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0800 */ { UD_Imaxpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0801 */ { UD_Ivmaxpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0802 */ { UD_Imaxps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0803 */ { UD_Ivmaxps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0804 */ { UD_Imaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0805 */ { UD_Ivmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0806 */ { UD_Imaxss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0807 */ { UD_Ivmaxss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0808 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0809 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0810 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0811 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0812 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0813 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0814 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0815 */ { UD_Imfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0816 */ { UD_Iminpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0817 */ { UD_Ivminpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0818 */ { UD_Iminps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0819 */ { UD_Ivminps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0820 */ { UD_Iminsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0821 */ { UD_Ivminsd, O_Vx, O_Hx, O_MqU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0822 */ { UD_Iminss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0823 */ { UD_Ivminss, O_Vx, O_Hx, O_MdU, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0824 */ { UD_Imonitor, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0825 */ { UD_Imontmul, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0826 */ { UD_Imov, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0827 */ { UD_Imov, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0828 */ { UD_Imov, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0829 */ { UD_Imov, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0830 */ { UD_Imov, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0831 */ { UD_Imov, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0832 */ { UD_Imov, O_MwRv, O_S, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0833 */ { UD_Imov, O_S, O_MwRv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0834 */ { UD_Imov, O_AL, O_Ob, O_NONE, O_NONE, P_none },
+ /* 0835 */ { UD_Imov, O_rAX, O_Ov, O_NONE, O_NONE, P_aso|P_oso|P_rexw },
+ /* 0836 */ { UD_Imov, O_Ob, O_AL, O_NONE, O_NONE, P_none },
+ /* 0837 */ { UD_Imov, O_Ov, O_rAX, O_NONE, O_NONE, P_aso|P_oso|P_rexw },
+ /* 0838 */ { UD_Imov, O_R0b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0839 */ { UD_Imov, O_R1b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0840 */ { UD_Imov, O_R2b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0841 */ { UD_Imov, O_R3b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0842 */ { UD_Imov, O_R4b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0843 */ { UD_Imov, O_R5b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0844 */ { UD_Imov, O_R6b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0845 */ { UD_Imov, O_R7b, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 0846 */ { UD_Imov, O_R0v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0847 */ { UD_Imov, O_R1v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0848 */ { UD_Imov, O_R2v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0849 */ { UD_Imov, O_R3v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0850 */ { UD_Imov, O_R4v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0851 */ { UD_Imov, O_R5v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0852 */ { UD_Imov, O_R6v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0853 */ { UD_Imov, O_R7v, O_Iv, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 0854 */ { UD_Imov, O_R, O_C, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0855 */ { UD_Imov, O_R, O_D, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0856 */ { UD_Imov, O_C, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0857 */ { UD_Imov, O_D, O_R, O_NONE, O_NONE, P_rexr|P_rexw|P_rexb },
+ /* 0858 */ { UD_Imovapd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0859 */ { UD_Ivmovapd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0860 */ { UD_Imovapd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0861 */ { UD_Ivmovapd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0862 */ { UD_Imovaps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0863 */ { UD_Ivmovaps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0864 */ { UD_Imovaps, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0865 */ { UD_Ivmovaps, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0866 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0867 */ { UD_Imovd, O_P, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0868 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0869 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0870 */ { UD_Imovd, O_V, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0871 */ { UD_Ivmovd, O_Vx, O_Ey, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0872 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0873 */ { UD_Imovd, O_Ey, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0874 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0875 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0876 */ { UD_Imovd, O_Ey, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0877 */ { UD_Ivmovd, O_Ey, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0878 */ { UD_Imovhpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0879 */ { UD_Ivmovhpd, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0880 */ { UD_Imovhpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0881 */ { UD_Ivmovhpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0882 */ { UD_Imovhps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0883 */ { UD_Ivmovhps, O_Vx, O_Hx, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0884 */ { UD_Imovhps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0885 */ { UD_Ivmovhps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0886 */ { UD_Imovlhps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0887 */ { UD_Ivmovlhps, O_Vx, O_Hx, O_Ux, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0888 */ { UD_Imovlpd, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0889 */ { UD_Ivmovlpd, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0890 */ { UD_Imovlpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0891 */ { UD_Ivmovlpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0892 */ { UD_Imovlps, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0893 */ { UD_Ivmovlps, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0894 */ { UD_Imovlps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0895 */ { UD_Ivmovlps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0896 */ { UD_Imovhlps, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0897 */ { UD_Ivmovhlps, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0898 */ { UD_Imovmskpd, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0899 */ { UD_Ivmovmskpd, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb|P_vexl },
+ /* 0900 */ { UD_Imovmskps, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0901 */ { UD_Ivmovmskps, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexb },
+ /* 0902 */ { UD_Imovntdq, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0903 */ { UD_Ivmovntdq, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0904 */ { UD_Imovnti, O_M, O_Gy, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0905 */ { UD_Imovntpd, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0906 */ { UD_Ivmovntpd, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0907 */ { UD_Imovntps, O_M, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0908 */ { UD_Ivmovntps, O_M, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0909 */ { UD_Imovntq, O_M, O_P, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0910 */ { UD_Imovq, O_P, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0911 */ { UD_Imovq, O_V, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0912 */ { UD_Ivmovq, O_Vx, O_Eq, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0913 */ { UD_Imovq, O_Eq, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0914 */ { UD_Imovq, O_Eq, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0915 */ { UD_Ivmovq, O_Eq, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0916 */ { UD_Imovq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0917 */ { UD_Ivmovq, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0918 */ { UD_Imovq, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0919 */ { UD_Ivmovq, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0920 */ { UD_Imovq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0921 */ { UD_Imovq, O_Q, O_P, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0922 */ { UD_Imovsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0923 */ { UD_Imovsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0924 */ { UD_Imovsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0925 */ { UD_Imovsd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0926 */ { UD_Imovsd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0927 */ { UD_Imovsq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 0928 */ { UD_Imovss, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0929 */ { UD_Imovss, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0930 */ { UD_Imovsx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0931 */ { UD_Imovsx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0932 */ { UD_Imovupd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0933 */ { UD_Ivmovupd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0934 */ { UD_Imovupd, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0935 */ { UD_Ivmovupd, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0936 */ { UD_Imovups, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0937 */ { UD_Ivmovups, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0938 */ { UD_Imovups, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0939 */ { UD_Ivmovups, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0940 */ { UD_Imovzx, O_Gv, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0941 */ { UD_Imovzx, O_Gy, O_Ew, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0942 */ { UD_Imul, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0943 */ { UD_Imul, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0944 */ { UD_Imulpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0945 */ { UD_Ivmulpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0946 */ { UD_Imulps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0947 */ { UD_Ivmulps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0948 */ { UD_Imulsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0949 */ { UD_Ivmulsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0950 */ { UD_Imulss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0951 */ { UD_Ivmulss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0952 */ { UD_Imwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 0953 */ { UD_Ineg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0954 */ { UD_Ineg, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0955 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0956 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0957 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0958 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0959 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0960 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0961 */ { UD_Inop, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0962 */ { UD_Inot, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0963 */ { UD_Inot, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0964 */ { UD_Ior, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0965 */ { UD_Ior, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0966 */ { UD_Ior, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0967 */ { UD_Ior, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0968 */ { UD_Ior, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 0969 */ { UD_Ior, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 0970 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0971 */ { UD_Ior, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0972 */ { UD_Ior, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0973 */ { UD_Ior, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 0974 */ { UD_Iorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0975 */ { UD_Ivorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0976 */ { UD_Iorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0977 */ { UD_Ivorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0978 */ { UD_Iout, O_Ib, O_AL, O_NONE, O_NONE, P_none },
+ /* 0979 */ { UD_Iout, O_Ib, O_eAX, O_NONE, O_NONE, P_oso },
+ /* 0980 */ { UD_Iout, O_DX, O_AL, O_NONE, O_NONE, P_none },
+ /* 0981 */ { UD_Iout, O_DX, O_eAX, O_NONE, O_NONE, P_oso },
+ /* 0982 */ { UD_Ioutsb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 0983 */ { UD_Ioutsw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0984 */ { UD_Ioutsd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_oso|P_seg },
+ /* 0985 */ { UD_Ipacksswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0986 */ { UD_Ivpacksswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0987 */ { UD_Ipacksswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0988 */ { UD_Ipackssdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0989 */ { UD_Ivpackssdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0990 */ { UD_Ipackssdw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0991 */ { UD_Ipackuswb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0992 */ { UD_Ivpackuswb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0993 */ { UD_Ipackuswb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0994 */ { UD_Ipaddb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0995 */ { UD_Ivpaddb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 0996 */ { UD_Ipaddb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0997 */ { UD_Ipaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0998 */ { UD_Ipaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 0999 */ { UD_Ivpaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1000 */ { UD_Ipaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1001 */ { UD_Ipaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1002 */ { UD_Ivpaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1003 */ { UD_Ipaddsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1004 */ { UD_Ipaddsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1005 */ { UD_Ivpaddsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1006 */ { UD_Ipaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1007 */ { UD_Ipaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1008 */ { UD_Ivpaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1009 */ { UD_Ipaddusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1010 */ { UD_Ipaddusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1011 */ { UD_Ivpaddusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1012 */ { UD_Ipaddusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1013 */ { UD_Ipaddusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1014 */ { UD_Ivpaddusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1015 */ { UD_Ipand, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1016 */ { UD_Ivpand, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1017 */ { UD_Ipand, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1018 */ { UD_Ipandn, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1019 */ { UD_Ivpandn, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1020 */ { UD_Ipandn, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1021 */ { UD_Ipavgb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1022 */ { UD_Ivpavgb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1023 */ { UD_Ipavgb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1024 */ { UD_Ipavgw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1025 */ { UD_Ivpavgw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1026 */ { UD_Ipavgw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1027 */ { UD_Ipcmpeqb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1028 */ { UD_Ipcmpeqb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1029 */ { UD_Ivpcmpeqb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1030 */ { UD_Ipcmpeqw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1031 */ { UD_Ipcmpeqw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1032 */ { UD_Ivpcmpeqw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1033 */ { UD_Ipcmpeqd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1034 */ { UD_Ipcmpeqd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1035 */ { UD_Ivpcmpeqd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1036 */ { UD_Ipcmpgtb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1037 */ { UD_Ivpcmpgtb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1038 */ { UD_Ipcmpgtb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1039 */ { UD_Ipcmpgtw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1040 */ { UD_Ivpcmpgtw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1041 */ { UD_Ipcmpgtw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1042 */ { UD_Ipcmpgtd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1043 */ { UD_Ivpcmpgtd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1044 */ { UD_Ipcmpgtd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1045 */ { UD_Ipextrb, O_MbRv, O_V, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 },
+ /* 1046 */ { UD_Ivpextrb, O_MbRv, O_Vx, O_Ib, O_NONE, P_aso|P_rexx|P_rexr|P_rexb|P_def64 },
+ /* 1047 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1048 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1049 */ { UD_Ipextrd, O_Ed, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1050 */ { UD_Ivpextrd, O_Ed, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexw|P_rexb },
+ /* 1051 */ { UD_Ipextrq, O_Eq, O_V, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 },
+ /* 1052 */ { UD_Ivpextrq, O_Eq, O_Vx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexb|P_def64 },
+ /* 1053 */ { UD_Ipextrw, O_Gd, O_U, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb },
+ /* 1054 */ { UD_Ivpextrw, O_Gd, O_Ux, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexb },
+ /* 1055 */ { UD_Ipextrw, O_Gd, O_N, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1056 */ { UD_Ipextrw, O_MwRd, O_V, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 1057 */ { UD_Ivpextrw, O_MwRd, O_Vx, O_Ib, O_NONE, P_aso|P_rexw|P_rexx|P_rexr|P_rexb },
+ /* 1058 */ { UD_Ipinsrb, O_V, O_MbRd, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1059 */ { UD_Ipinsrw, O_P, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1060 */ { UD_Ipinsrw, O_V, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1061 */ { UD_Ivpinsrw, O_Vx, O_MwRy, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1062 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1063 */ { UD_Ipinsrd, O_V, O_Ed, O_Ib, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1064 */ { UD_Ipinsrq, O_V, O_Eq, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1065 */ { UD_Ivpinsrb, O_V, O_H, O_MbRd, O_Ib, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1066 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1067 */ { UD_Ivpinsrd, O_V, O_H, O_Ed, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1068 */ { UD_Ivpinsrq, O_V, O_H, O_Eq, O_Ib, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1069 */ { UD_Ipmaddwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1070 */ { UD_Ipmaddwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1071 */ { UD_Ivpmaddwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1072 */ { UD_Ipmaxsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1073 */ { UD_Ivpmaxsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1074 */ { UD_Ipmaxsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1075 */ { UD_Ipmaxub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1076 */ { UD_Ipmaxub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1077 */ { UD_Ivpmaxub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1078 */ { UD_Ipminsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1079 */ { UD_Ivpminsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1080 */ { UD_Ipminsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1081 */ { UD_Ipminub, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1082 */ { UD_Ivpminub, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1083 */ { UD_Ipminub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1084 */ { UD_Ipmovmskb, O_Gd, O_U, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1085 */ { UD_Ivpmovmskb, O_Gd, O_Ux, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1086 */ { UD_Ipmovmskb, O_Gd, O_N, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexb },
+ /* 1087 */ { UD_Ipmulhuw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1088 */ { UD_Ipmulhuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1089 */ { UD_Ivpmulhuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1090 */ { UD_Ipmulhw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1091 */ { UD_Ivpmulhw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1092 */ { UD_Ipmulhw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1093 */ { UD_Ipmullw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1094 */ { UD_Ipmullw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1095 */ { UD_Ivpmullw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1096 */ { UD_Ipop, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1097 */ { UD_Ipop, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1098 */ { UD_Ipop, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1099 */ { UD_Ipop, O_GS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1100 */ { UD_Ipop, O_FS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1101 */ { UD_Ipop, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1102 */ { UD_Ipop, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1103 */ { UD_Ipop, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1104 */ { UD_Ipop, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1105 */ { UD_Ipop, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1106 */ { UD_Ipop, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1107 */ { UD_Ipop, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1108 */ { UD_Ipop, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1109 */ { UD_Ipop, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1110 */ { UD_Ipopa, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1111 */ { UD_Ipopad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1112 */ { UD_Ipopfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1113 */ { UD_Ipopfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1114 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1115 */ { UD_Ipopfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1116 */ { UD_Ipor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1117 */ { UD_Ivpor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1118 */ { UD_Ipor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1119 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1120 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1121 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1122 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1123 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1124 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1125 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1126 */ { UD_Iprefetch, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1127 */ { UD_Iprefetchnta, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1128 */ { UD_Iprefetcht0, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1129 */ { UD_Iprefetcht1, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1130 */ { UD_Iprefetcht2, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1131 */ { UD_Ipsadbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1132 */ { UD_Ivpsadbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1133 */ { UD_Ipsadbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1134 */ { UD_Ipshufw, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1135 */ { UD_Ipsllw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1136 */ { UD_Ipsllw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1137 */ { UD_Ipsllw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1138 */ { UD_Ipsllw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1139 */ { UD_Ipslld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1140 */ { UD_Ipslld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1141 */ { UD_Ipslld, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1142 */ { UD_Ipslld, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1143 */ { UD_Ipsllq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1144 */ { UD_Ipsllq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1145 */ { UD_Ipsllq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1146 */ { UD_Ipsllq, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1147 */ { UD_Ipsraw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1148 */ { UD_Ipsraw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1149 */ { UD_Ivpsraw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1150 */ { UD_Ipsraw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1151 */ { UD_Ivpsraw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1152 */ { UD_Ipsraw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1153 */ { UD_Ipsrad, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1154 */ { UD_Ipsrad, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1155 */ { UD_Ivpsrad, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1156 */ { UD_Ipsrad, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1157 */ { UD_Ipsrad, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1158 */ { UD_Ivpsrad, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1159 */ { UD_Ipsrlw, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1160 */ { UD_Ipsrlw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1161 */ { UD_Ipsrlw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1162 */ { UD_Ivpsrlw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1163 */ { UD_Ipsrlw, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1164 */ { UD_Ivpsrlw, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1165 */ { UD_Ipsrld, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1166 */ { UD_Ipsrld, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1167 */ { UD_Ipsrld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1168 */ { UD_Ivpsrld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1169 */ { UD_Ipsrld, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1170 */ { UD_Ivpsrld, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1171 */ { UD_Ipsrlq, O_N, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1172 */ { UD_Ipsrlq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1173 */ { UD_Ipsrlq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1174 */ { UD_Ivpsrlq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1175 */ { UD_Ipsrlq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1176 */ { UD_Ivpsrlq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1177 */ { UD_Ipsubb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1178 */ { UD_Ivpsubb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1179 */ { UD_Ipsubb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1180 */ { UD_Ipsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1181 */ { UD_Ivpsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1182 */ { UD_Ipsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1183 */ { UD_Ipsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1184 */ { UD_Ipsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1185 */ { UD_Ivpsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1186 */ { UD_Ipsubsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1187 */ { UD_Ipsubsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1188 */ { UD_Ivpsubsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1189 */ { UD_Ipsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1190 */ { UD_Ipsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1191 */ { UD_Ivpsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1192 */ { UD_Ipsubusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1193 */ { UD_Ipsubusb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1194 */ { UD_Ivpsubusb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1195 */ { UD_Ipsubusw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1196 */ { UD_Ipsubusw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1197 */ { UD_Ivpsubusw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1198 */ { UD_Ipunpckhbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1199 */ { UD_Ivpunpckhbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1200 */ { UD_Ipunpckhbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1201 */ { UD_Ipunpckhwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1202 */ { UD_Ivpunpckhwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1203 */ { UD_Ipunpckhwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1204 */ { UD_Ipunpckhdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1205 */ { UD_Ivpunpckhdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1206 */ { UD_Ipunpckhdq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1207 */ { UD_Ipunpcklbw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1208 */ { UD_Ivpunpcklbw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1209 */ { UD_Ipunpcklbw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1210 */ { UD_Ipunpcklwd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1211 */ { UD_Ivpunpcklwd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1212 */ { UD_Ipunpcklwd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1213 */ { UD_Ipunpckldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1214 */ { UD_Ivpunpckldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1215 */ { UD_Ipunpckldq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1216 */ { UD_Ipi2fw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1217 */ { UD_Ipi2fd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1218 */ { UD_Ipf2iw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1219 */ { UD_Ipf2id, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1220 */ { UD_Ipfnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1221 */ { UD_Ipfpnacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1222 */ { UD_Ipfcmpge, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1223 */ { UD_Ipfmin, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1224 */ { UD_Ipfrcp, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1225 */ { UD_Ipfrsqrt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1226 */ { UD_Ipfsub, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1227 */ { UD_Ipfadd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1228 */ { UD_Ipfcmpgt, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1229 */ { UD_Ipfmax, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1230 */ { UD_Ipfrcpit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1231 */ { UD_Ipfrsqit1, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1232 */ { UD_Ipfsubr, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1233 */ { UD_Ipfacc, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1234 */ { UD_Ipfcmpeq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1235 */ { UD_Ipfmul, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1236 */ { UD_Ipfrcpit2, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1237 */ { UD_Ipmulhrw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1238 */ { UD_Ipswapd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1239 */ { UD_Ipavgusb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1240 */ { UD_Ipush, O_ES, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1241 */ { UD_Ipush, O_CS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1242 */ { UD_Ipush, O_SS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1243 */ { UD_Ipush, O_DS, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1244 */ { UD_Ipush, O_GS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1245 */ { UD_Ipush, O_FS, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1246 */ { UD_Ipush, O_R0v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1247 */ { UD_Ipush, O_R1v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1248 */ { UD_Ipush, O_R2v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1249 */ { UD_Ipush, O_R3v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1250 */ { UD_Ipush, O_R4v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1251 */ { UD_Ipush, O_R5v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1252 */ { UD_Ipush, O_R6v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1253 */ { UD_Ipush, O_R7v, O_NONE, O_NONE, O_NONE, P_oso|P_rexb|P_def64 },
+ /* 1254 */ { UD_Ipush, O_sIz, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1255 */ { UD_Ipush, O_Ev, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1256 */ { UD_Ipush, O_sIb, O_NONE, O_NONE, O_NONE, P_oso|P_def64 },
+ /* 1257 */ { UD_Ipusha, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1258 */ { UD_Ipushad, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_inv64 },
+ /* 1259 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1260 */ { UD_Ipushfw, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1261 */ { UD_Ipushfd, O_NONE, O_NONE, O_NONE, O_NONE, P_oso },
+ /* 1262 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1263 */ { UD_Ipushfq, O_NONE, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_def64 },
+ /* 1264 */ { UD_Ipxor, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1265 */ { UD_Ivpxor, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1266 */ { UD_Ipxor, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1267 */ { UD_Ircl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1268 */ { UD_Ircl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1269 */ { UD_Ircl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1270 */ { UD_Ircl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1271 */ { UD_Ircl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1272 */ { UD_Ircl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1273 */ { UD_Ircr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1274 */ { UD_Ircr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1275 */ { UD_Ircr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1276 */ { UD_Ircr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1277 */ { UD_Ircr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1278 */ { UD_Ircr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1279 */ { UD_Irol, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1280 */ { UD_Irol, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1281 */ { UD_Irol, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1282 */ { UD_Irol, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1283 */ { UD_Irol, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1284 */ { UD_Irol, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1285 */ { UD_Iror, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1286 */ { UD_Iror, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1287 */ { UD_Iror, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1288 */ { UD_Iror, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1289 */ { UD_Iror, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1290 */ { UD_Iror, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1291 */ { UD_Ircpps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1292 */ { UD_Ivrcpps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1293 */ { UD_Ircpss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1294 */ { UD_Ivrcpss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1295 */ { UD_Irdmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1296 */ { UD_Irdpmc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1297 */ { UD_Irdtsc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1298 */ { UD_Irdtscp, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1299 */ { UD_Irepne, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1300 */ { UD_Irep, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1301 */ { UD_Iret, O_Iw, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1302 */ { UD_Iret, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1303 */ { UD_Iretf, O_Iw, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1304 */ { UD_Iretf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1305 */ { UD_Irsm, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1306 */ { UD_Irsqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1307 */ { UD_Ivrsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1308 */ { UD_Irsqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1309 */ { UD_Ivrsqrtss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1310 */ { UD_Isahf, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1311 */ { UD_Isalc, O_NONE, O_NONE, O_NONE, O_NONE, P_inv64 },
+ /* 1312 */ { UD_Isar, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1313 */ { UD_Isar, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1314 */ { UD_Isar, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1315 */ { UD_Isar, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1316 */ { UD_Isar, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1317 */ { UD_Isar, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1318 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1319 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1320 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1321 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1322 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1323 */ { UD_Ishl, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1324 */ { UD_Ishl, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1325 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1326 */ { UD_Ishl, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1327 */ { UD_Ishl, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1328 */ { UD_Ishl, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1329 */ { UD_Ishl, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1330 */ { UD_Ishr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1331 */ { UD_Ishr, O_Eb, O_CL, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1332 */ { UD_Ishr, O_Ev, O_I1, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1333 */ { UD_Ishr, O_Eb, O_I1, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1334 */ { UD_Ishr, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1335 */ { UD_Ishr, O_Ev, O_CL, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1336 */ { UD_Isbb, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1337 */ { UD_Isbb, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1338 */ { UD_Isbb, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1339 */ { UD_Isbb, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1340 */ { UD_Isbb, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1341 */ { UD_Isbb, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1342 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1343 */ { UD_Isbb, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1344 */ { UD_Isbb, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1345 */ { UD_Isbb, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1346 */ { UD_Iscasb, O_NONE, O_NONE, O_NONE, O_NONE, P_strz },
+ /* 1347 */ { UD_Iscasw, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1348 */ { UD_Iscasd, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1349 */ { UD_Iscasq, O_NONE, O_NONE, O_NONE, O_NONE, P_strz|P_oso|P_rexw },
+ /* 1350 */ { UD_Iseto, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1351 */ { UD_Isetno, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1352 */ { UD_Isetb, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1353 */ { UD_Isetae, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1354 */ { UD_Isetz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1355 */ { UD_Isetnz, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1356 */ { UD_Isetbe, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1357 */ { UD_Iseta, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1358 */ { UD_Isets, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1359 */ { UD_Isetns, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1360 */ { UD_Isetp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1361 */ { UD_Isetnp, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1362 */ { UD_Isetl, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1363 */ { UD_Isetge, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1364 */ { UD_Isetle, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1365 */ { UD_Isetg, O_Eb, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1366 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1367 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1368 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1369 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1370 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1371 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1372 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1373 */ { UD_Isfence, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1374 */ { UD_Isgdt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1375 */ { UD_Ishld, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1376 */ { UD_Ishld, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1377 */ { UD_Ishrd, O_Ev, O_Gv, O_Ib, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1378 */ { UD_Ishrd, O_Ev, O_Gv, O_CL, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1379 */ { UD_Ishufpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1380 */ { UD_Ivshufpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1381 */ { UD_Ishufps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1382 */ { UD_Ivshufps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1383 */ { UD_Isidt, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1384 */ { UD_Isldt, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1385 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1386 */ { UD_Ismsw, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1387 */ { UD_Isqrtps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1388 */ { UD_Ivsqrtps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1389 */ { UD_Isqrtpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1390 */ { UD_Ivsqrtpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1391 */ { UD_Isqrtsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1392 */ { UD_Ivsqrtsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1393 */ { UD_Isqrtss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1394 */ { UD_Ivsqrtss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1395 */ { UD_Istc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1396 */ { UD_Istd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1397 */ { UD_Istgi, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1398 */ { UD_Isti, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1399 */ { UD_Iskinit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1400 */ { UD_Istmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1401 */ { UD_Ivstmxcsr, O_Md, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1402 */ { UD_Istosb, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg },
+ /* 1403 */ { UD_Istosw, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1404 */ { UD_Istosd, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1405 */ { UD_Istosq, O_NONE, O_NONE, O_NONE, O_NONE, P_str|P_seg|P_oso|P_rexw },
+ /* 1406 */ { UD_Istr, O_MwRv, O_NONE, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1407 */ { UD_Isub, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1408 */ { UD_Isub, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1409 */ { UD_Isub, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1410 */ { UD_Isub, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1411 */ { UD_Isub, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1412 */ { UD_Isub, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1413 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1414 */ { UD_Isub, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1415 */ { UD_Isub, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1416 */ { UD_Isub, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1417 */ { UD_Isubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1418 */ { UD_Ivsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1419 */ { UD_Isubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1420 */ { UD_Ivsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1421 */ { UD_Isubsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1422 */ { UD_Ivsubsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1423 */ { UD_Isubss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1424 */ { UD_Ivsubss, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1425 */ { UD_Iswapgs, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1426 */ { UD_Isyscall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1427 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1428 */ { UD_Isysenter, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1429 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1430 */ { UD_Isysexit, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1431 */ { UD_Isysret, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1432 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1433 */ { UD_Itest, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1434 */ { UD_Itest, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1435 */ { UD_Itest, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1436 */ { UD_Itest, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1437 */ { UD_Itest, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1438 */ { UD_Itest, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1439 */ { UD_Itest, O_Ev, O_Iz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1440 */ { UD_Iucomisd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1441 */ { UD_Ivucomisd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1442 */ { UD_Iucomiss, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1443 */ { UD_Ivucomiss, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1444 */ { UD_Iud2, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1445 */ { UD_Iunpckhpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1446 */ { UD_Ivunpckhpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1447 */ { UD_Iunpckhps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1448 */ { UD_Ivunpckhps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1449 */ { UD_Iunpcklps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1450 */ { UD_Ivunpcklps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1451 */ { UD_Iunpcklpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1452 */ { UD_Ivunpcklpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1453 */ { UD_Iverr, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1454 */ { UD_Iverw, O_Ew, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1455 */ { UD_Ivmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1456 */ { UD_Irdrand, O_R, O_NONE, O_NONE, O_NONE, P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1457 */ { UD_Ivmclear, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1458 */ { UD_Ivmxon, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1459 */ { UD_Ivmptrld, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1460 */ { UD_Ivmptrst, O_Mq, O_NONE, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1461 */ { UD_Ivmlaunch, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1462 */ { UD_Ivmresume, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1463 */ { UD_Ivmxoff, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1464 */ { UD_Ivmread, O_Ey, O_Gy, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1465 */ { UD_Ivmwrite, O_Gy, O_Ey, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_def64 },
+ /* 1466 */ { UD_Ivmrun, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1467 */ { UD_Ivmmcall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1468 */ { UD_Ivmload, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1469 */ { UD_Ivmsave, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1470 */ { UD_Iwait, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1471 */ { UD_Iwbinvd, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1472 */ { UD_Iwrmsr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1473 */ { UD_Ixadd, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexx|P_rexb },
+ /* 1474 */ { UD_Ixadd, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1475 */ { UD_Ixchg, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1476 */ { UD_Ixchg, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1477 */ { UD_Ixchg, O_R0v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1478 */ { UD_Ixchg, O_R1v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1479 */ { UD_Ixchg, O_R2v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1480 */ { UD_Ixchg, O_R3v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1481 */ { UD_Ixchg, O_R4v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1482 */ { UD_Ixchg, O_R5v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1483 */ { UD_Ixchg, O_R6v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1484 */ { UD_Ixchg, O_R7v, O_rAX, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1485 */ { UD_Ixgetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1486 */ { UD_Ixlatb, O_NONE, O_NONE, O_NONE, O_NONE, P_rexw|P_seg },
+ /* 1487 */ { UD_Ixor, O_Eb, O_Gb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1488 */ { UD_Ixor, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1489 */ { UD_Ixor, O_Gb, O_Eb, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1490 */ { UD_Ixor, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1491 */ { UD_Ixor, O_AL, O_Ib, O_NONE, O_NONE, P_none },
+ /* 1492 */ { UD_Ixor, O_rAX, O_sIz, O_NONE, O_NONE, P_oso|P_rexw },
+ /* 1493 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1494 */ { UD_Ixor, O_Ev, O_sIz, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1495 */ { UD_Ixor, O_Eb, O_Ib, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_inv64 },
+ /* 1496 */ { UD_Ixor, O_Ev, O_sIb, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1497 */ { UD_Ixorpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1498 */ { UD_Ivxorpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1499 */ { UD_Ixorps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1500 */ { UD_Ivxorps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1501 */ { UD_Ixcryptecb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1502 */ { UD_Ixcryptcbc, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1503 */ { UD_Ixcryptctr, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1504 */ { UD_Ixcryptcfb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1505 */ { UD_Ixcryptofb, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1506 */ { UD_Ixrstor, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1507 */ { UD_Ixsave, O_M, O_NONE, O_NONE, O_NONE, P_aso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1508 */ { UD_Ixsetbv, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1509 */ { UD_Ixsha1, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1510 */ { UD_Ixsha256, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1511 */ { UD_Ixstore, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1512 */ { UD_Ipclmulqdq, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1513 */ { UD_Ivpclmulqdq, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1514 */ { UD_Igetsec, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1515 */ { UD_Imovdqa, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1516 */ { UD_Ivmovdqa, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1517 */ { UD_Imovdqa, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1518 */ { UD_Ivmovdqa, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1519 */ { UD_Imaskmovdqu, O_V, O_U, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1520 */ { UD_Ivmaskmovdqu, O_Vx, O_Ux, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1521 */ { UD_Imovdq2q, O_P, O_U, O_NONE, O_NONE, P_aso|P_rexb },
+ /* 1522 */ { UD_Imovdqu, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1523 */ { UD_Ivmovdqu, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1524 */ { UD_Imovdqu, O_W, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1525 */ { UD_Ivmovdqu, O_Wx, O_Vx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1526 */ { UD_Imovq2dq, O_V, O_N, O_NONE, O_NONE, P_aso|P_rexr },
+ /* 1527 */ { UD_Ipaddq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1528 */ { UD_Ipaddq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1529 */ { UD_Ivpaddq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1530 */ { UD_Ipsubq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1531 */ { UD_Ivpsubq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1532 */ { UD_Ipsubq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1533 */ { UD_Ipmuludq, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1534 */ { UD_Ipmuludq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1535 */ { UD_Ipshufhw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1536 */ { UD_Ivpshufhw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1537 */ { UD_Ipshuflw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1538 */ { UD_Ivpshuflw, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1539 */ { UD_Ipshufd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1540 */ { UD_Ivpshufd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1541 */ { UD_Ipslldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1542 */ { UD_Ivpslldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1543 */ { UD_Ipsrldq, O_U, O_Ib, O_NONE, O_NONE, P_rexb },
+ /* 1544 */ { UD_Ivpsrldq, O_Hx, O_Ux, O_Ib, O_NONE, P_rexb },
+ /* 1545 */ { UD_Ipunpckhqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1546 */ { UD_Ivpunpckhqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1547 */ { UD_Ipunpcklqdq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1548 */ { UD_Ivpunpcklqdq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1549 */ { UD_Ihaddpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1550 */ { UD_Ivhaddpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1551 */ { UD_Ihaddps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1552 */ { UD_Ivhaddps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1553 */ { UD_Ihsubpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1554 */ { UD_Ivhsubpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1555 */ { UD_Ihsubps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1556 */ { UD_Ivhsubps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1557 */ { UD_Iinsertps, O_V, O_Md, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1558 */ { UD_Ivinsertps, O_Vx, O_Hx, O_Md, O_Ib, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1559 */ { UD_Ilddqu, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1560 */ { UD_Ivlddqu, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1561 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1562 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1563 */ { UD_Imovddup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1564 */ { UD_Ivmovddup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1565 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1566 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1567 */ { UD_Imovshdup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1568 */ { UD_Ivmovshdup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1569 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1570 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1571 */ { UD_Imovsldup, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1572 */ { UD_Ivmovsldup, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1573 */ { UD_Ipabsb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1574 */ { UD_Ipabsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1575 */ { UD_Ivpabsb, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1576 */ { UD_Ipabsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1577 */ { UD_Ipabsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1578 */ { UD_Ivpabsw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1579 */ { UD_Ipabsd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1580 */ { UD_Ipabsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1581 */ { UD_Ivpabsd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1582 */ { UD_Ipshufb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1583 */ { UD_Ipshufb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1584 */ { UD_Ivpshufb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1585 */ { UD_Iphaddw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1586 */ { UD_Iphaddw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1587 */ { UD_Ivphaddw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1588 */ { UD_Iphaddd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1589 */ { UD_Iphaddd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1590 */ { UD_Ivphaddd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1591 */ { UD_Iphaddsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1592 */ { UD_Iphaddsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1593 */ { UD_Ivphaddsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1594 */ { UD_Ipmaddubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1595 */ { UD_Ipmaddubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1596 */ { UD_Ivpmaddubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1597 */ { UD_Iphsubw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1598 */ { UD_Iphsubw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1599 */ { UD_Ivphsubw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1600 */ { UD_Iphsubd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1601 */ { UD_Iphsubd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1602 */ { UD_Ivphsubd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1603 */ { UD_Iphsubsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1604 */ { UD_Iphsubsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1605 */ { UD_Ivphsubsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1606 */ { UD_Ipsignb, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1607 */ { UD_Ipsignb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1608 */ { UD_Ivpsignb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1609 */ { UD_Ipsignd, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1610 */ { UD_Ipsignd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1611 */ { UD_Ivpsignd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1612 */ { UD_Ipsignw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1613 */ { UD_Ipsignw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1614 */ { UD_Ivpsignw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1615 */ { UD_Ipmulhrsw, O_P, O_Q, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1616 */ { UD_Ipmulhrsw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1617 */ { UD_Ivpmulhrsw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1618 */ { UD_Ipalignr, O_P, O_Q, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1619 */ { UD_Ipalignr, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1620 */ { UD_Ivpalignr, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1621 */ { UD_Ipblendvb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1622 */ { UD_Ipmuldq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1623 */ { UD_Ivpmuldq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1624 */ { UD_Ipminsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1625 */ { UD_Ivpminsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1626 */ { UD_Ipminsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1627 */ { UD_Ivpminsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1628 */ { UD_Ipminuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1629 */ { UD_Ivpminuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1630 */ { UD_Ipminud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1631 */ { UD_Ivpminud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1632 */ { UD_Ipmaxsb, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1633 */ { UD_Ivpmaxsb, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1634 */ { UD_Ipmaxsd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1635 */ { UD_Ivpmaxsd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1636 */ { UD_Ipmaxud, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1637 */ { UD_Ivpmaxud, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1638 */ { UD_Ipmaxuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1639 */ { UD_Ivpmaxuw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1640 */ { UD_Ipmulld, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1641 */ { UD_Ivpmulld, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1642 */ { UD_Iphminposuw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1643 */ { UD_Ivphminposuw, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1644 */ { UD_Iroundps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1645 */ { UD_Ivroundps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1646 */ { UD_Iroundpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1647 */ { UD_Ivroundpd, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1648 */ { UD_Iroundss, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1649 */ { UD_Ivroundss, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1650 */ { UD_Iroundsd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1651 */ { UD_Ivroundsd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1652 */ { UD_Iblendpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1653 */ { UD_Ivblendpd, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1654 */ { UD_Iblendps, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1655 */ { UD_Ivblendps, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1656 */ { UD_Iblendvpd, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1657 */ { UD_Iblendvps, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1658 */ { UD_Ibound, O_Gv, O_M, O_NONE, O_NONE, P_aso|P_oso },
+ /* 1659 */ { UD_Ibsf, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1660 */ { UD_Ibsr, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1661 */ { UD_Ibswap, O_R0y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1662 */ { UD_Ibswap, O_R1y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1663 */ { UD_Ibswap, O_R2y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1664 */ { UD_Ibswap, O_R3y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1665 */ { UD_Ibswap, O_R4y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1666 */ { UD_Ibswap, O_R5y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1667 */ { UD_Ibswap, O_R6y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1668 */ { UD_Ibswap, O_R7y, O_NONE, O_NONE, O_NONE, P_oso|P_rexw|P_rexb },
+ /* 1669 */ { UD_Ibt, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1670 */ { UD_Ibt, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1671 */ { UD_Ibtc, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1672 */ { UD_Ibtc, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1673 */ { UD_Ibtr, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1674 */ { UD_Ibtr, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1675 */ { UD_Ibts, O_Ev, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1676 */ { UD_Ibts, O_Ev, O_Ib, O_NONE, O_NONE, P_aso|P_oso|P_rexw|P_rexr|P_rexx|P_rexb },
+ /* 1677 */ { UD_Ipblendw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1678 */ { UD_Ivpblendw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1679 */ { UD_Impsadbw, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1680 */ { UD_Ivmpsadbw, O_Vx, O_Hx, O_Wx, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1681 */ { UD_Imovntdqa, O_V, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1682 */ { UD_Ivmovntdqa, O_Vx, O_M, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1683 */ { UD_Ipackusdw, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1684 */ { UD_Ivpackusdw, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1685 */ { UD_Ipmovsxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1686 */ { UD_Ivpmovsxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1687 */ { UD_Ipmovsxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1688 */ { UD_Ivpmovsxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1689 */ { UD_Ipmovsxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1690 */ { UD_Ivpmovsxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1691 */ { UD_Ipmovsxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1692 */ { UD_Ivpmovsxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1693 */ { UD_Ipmovsxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1694 */ { UD_Ivpmovsxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1695 */ { UD_Ipmovsxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1696 */ { UD_Ipmovzxbw, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1697 */ { UD_Ivpmovzxbw, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1698 */ { UD_Ipmovzxbd, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1699 */ { UD_Ivpmovzxbd, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1700 */ { UD_Ipmovzxbq, O_V, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1701 */ { UD_Ivpmovzxbq, O_Vx, O_MwU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1702 */ { UD_Ipmovzxwd, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1703 */ { UD_Ivpmovzxwd, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1704 */ { UD_Ipmovzxwq, O_V, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1705 */ { UD_Ivpmovzxwq, O_Vx, O_MdU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1706 */ { UD_Ipmovzxdq, O_V, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1707 */ { UD_Ivpmovzxdq, O_Vx, O_MqU, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1708 */ { UD_Ipcmpeqq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1709 */ { UD_Ivpcmpeqq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1710 */ { UD_Ipopcnt, O_Gv, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1711 */ { UD_Iptest, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1712 */ { UD_Ivptest, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb|P_vexl },
+ /* 1713 */ { UD_Ipcmpestri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1714 */ { UD_Ivpcmpestri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1715 */ { UD_Ipcmpestrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1716 */ { UD_Ivpcmpestrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1717 */ { UD_Ipcmpgtq, O_V, O_W, O_NONE, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1718 */ { UD_Ivpcmpgtq, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1719 */ { UD_Ipcmpistri, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1720 */ { UD_Ivpcmpistri, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1721 */ { UD_Ipcmpistrm, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1722 */ { UD_Ivpcmpistrm, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1723 */ { UD_Imovbe, O_Gv, O_Mv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1724 */ { UD_Imovbe, O_Mv, O_Gv, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1725 */ { UD_Icrc32, O_Gy, O_Eb, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1726 */ { UD_Icrc32, O_Gy, O_Ev, O_NONE, O_NONE, P_aso|P_oso|P_rexr|P_rexw|P_rexx|P_rexb },
+ /* 1727 */ { UD_Ivbroadcastss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1728 */ { UD_Ivbroadcastsd, O_Vqq, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1729 */ { UD_Ivextractf128, O_Wdq, O_Vqq, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1730 */ { UD_Ivinsertf128, O_Vqq, O_Hqq, O_Wdq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1731 */ { UD_Ivmaskmovps, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1732 */ { UD_Ivmaskmovps, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1733 */ { UD_Ivmaskmovpd, O_V, O_H, O_M, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1734 */ { UD_Ivmaskmovpd, O_M, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1735 */ { UD_Ivpermilpd, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1736 */ { UD_Ivpermilpd, O_V, O_W, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1737 */ { UD_Ivpermilps, O_Vx, O_Hx, O_Wx, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1738 */ { UD_Ivpermilps, O_Vx, O_Wx, O_Ib, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1739 */ { UD_Ivperm2f128, O_Vqq, O_Hqq, O_Wqq, O_Ib, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1740 */ { UD_Ivtestps, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1741 */ { UD_Ivtestpd, O_Vx, O_Wx, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1742 */ { UD_Ivzeroupper, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1743 */ { UD_Ivzeroall, O_NONE, O_NONE, O_NONE, O_NONE, P_none },
+ /* 1744 */ { UD_Ivblendvpd, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1745 */ { UD_Ivblendvps, O_Vx, O_Hx, O_Wx, O_Lx, P_aso|P_rexr|P_rexx|P_rexb|P_vexl },
+ /* 1746 */ { UD_Ivmovsd, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1747 */ { UD_Ivmovsd, O_V, O_Mq, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1748 */ { UD_Ivmovsd, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1749 */ { UD_Ivmovsd, O_Mq, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1750 */ { UD_Ivmovss, O_V, O_H, O_U, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1751 */ { UD_Ivmovss, O_V, O_Md, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1752 */ { UD_Ivmovss, O_U, O_H, O_V, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1753 */ { UD_Ivmovss, O_Md, O_V, O_NONE, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1754 */ { UD_Ivpblendvb, O_V, O_H, O_W, O_L, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1755 */ { UD_Ivpsllw, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1756 */ { UD_Ivpsllw, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1757 */ { UD_Ivpslld, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1758 */ { UD_Ivpslld, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1759 */ { UD_Ivpsllq, O_V, O_H, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+ /* 1760 */ { UD_Ivpsllq, O_H, O_V, O_W, O_NONE, P_aso|P_rexr|P_rexx|P_rexb },
+};
+
+
+const char* ud_mnemonics_str[] = {
+ "aaa",
+ "aad",
+ "aam",
+ "aas",
+ "adc",
+ "add",
+ "addpd",
+ "addps",
+ "addsd",
+ "addss",
+ "addsubpd",
+ "addsubps",
+ "aesdec",
+ "aesdeclast",
+ "aesenc",
+ "aesenclast",
+ "aesimc",
+ "aeskeygenassist",
+ "and",
+ "andnpd",
+ "andnps",
+ "andpd",
+ "andps",
+ "arpl",
+ "blendpd",
+ "blendps",
+ "blendvpd",
+ "blendvps",
+ "bound",
+ "bsf",
+ "bsr",
+ "bswap",
+ "bt",
+ "btc",
+ "btr",
+ "bts",
+ "call",
+ "cbw",
+ "cdq",
+ "cdqe",
+ "clc",
+ "cld",
+ "clflush",
+ "clgi",
+ "cli",
+ "clts",
+ "cmc",
+ "cmova",
+ "cmovae",
+ "cmovb",
+ "cmovbe",
+ "cmovg",
+ "cmovge",
+ "cmovl",
+ "cmovle",
+ "cmovno",
+ "cmovnp",
+ "cmovns",
+ "cmovnz",
+ "cmovo",
+ "cmovp",
+ "cmovs",
+ "cmovz",
+ "cmp",
+ "cmppd",
+ "cmpps",
+ "cmpsb",
+ "cmpsd",
+ "cmpsq",
+ "cmpss",
+ "cmpsw",
+ "cmpxchg",
+ "cmpxchg16b",
+ "cmpxchg8b",
+ "comisd",
+ "comiss",
+ "cpuid",
+ "cqo",
+ "crc32",
+ "cvtdq2pd",
+ "cvtdq2ps",
+ "cvtpd2dq",
+ "cvtpd2pi",
+ "cvtpd2ps",
+ "cvtpi2pd",
+ "cvtpi2ps",
+ "cvtps2dq",
+ "cvtps2pd",
+ "cvtps2pi",
+ "cvtsd2si",
+ "cvtsd2ss",
+ "cvtsi2sd",
+ "cvtsi2ss",
+ "cvtss2sd",
+ "cvtss2si",
+ "cvttpd2dq",
+ "cvttpd2pi",
+ "cvttps2dq",
+ "cvttps2pi",
+ "cvttsd2si",
+ "cvttss2si",
+ "cwd",
+ "cwde",
+ "daa",
+ "das",
+ "dec",
+ "div",
+ "divpd",
+ "divps",
+ "divsd",
+ "divss",
+ "dppd",
+ "dpps",
+ "emms",
+ "enter",
+ "extractps",
+ "f2xm1",
+ "fabs",
+ "fadd",
+ "faddp",
+ "fbld",
+ "fbstp",
+ "fchs",
+ "fclex",
+ "fcmovb",
+ "fcmovbe",
+ "fcmove",
+ "fcmovnb",
+ "fcmovnbe",
+ "fcmovne",
+ "fcmovnu",
+ "fcmovu",
+ "fcom",
+ "fcom2",
+ "fcomi",
+ "fcomip",
+ "fcomp",
+ "fcomp3",
+ "fcomp5",
+ "fcompp",
+ "fcos",
+ "fdecstp",
+ "fdiv",
+ "fdivp",
+ "fdivr",
+ "fdivrp",
+ "femms",
+ "ffree",
+ "ffreep",
+ "fiadd",
+ "ficom",
+ "ficomp",
+ "fidiv",
+ "fidivr",
+ "fild",
+ "fimul",
+ "fincstp",
+ "fist",
+ "fistp",
+ "fisttp",
+ "fisub",
+ "fisubr",
+ "fld",
+ "fld1",
+ "fldcw",
+ "fldenv",
+ "fldl2e",
+ "fldl2t",
+ "fldlg2",
+ "fldln2",
+ "fldpi",
+ "fldz",
+ "fmul",
+ "fmulp",
+ "fndisi",
+ "fneni",
+ "fninit",
+ "fnop",
+ "fnsave",
+ "fnsetpm",
+ "fnstcw",
+ "fnstenv",
+ "fnstsw",
+ "fpatan",
+ "fprem",
+ "fprem1",
+ "fptan",
+ "frndint",
+ "frstor",
+ "frstpm",
+ "fscale",
+ "fsin",
+ "fsincos",
+ "fsqrt",
+ "fst",
+ "fstp",
+ "fstp1",
+ "fstp8",
+ "fstp9",
+ "fsub",
+ "fsubp",
+ "fsubr",
+ "fsubrp",
+ "ftst",
+ "fucom",
+ "fucomi",
+ "fucomip",
+ "fucomp",
+ "fucompp",
+ "fxam",
+ "fxch",
+ "fxch4",
+ "fxch7",
+ "fxrstor",
+ "fxsave",
+ "fxtract",
+ "fyl2x",
+ "fyl2xp1",
+ "getsec",
+ "haddpd",
+ "haddps",
+ "hlt",
+ "hsubpd",
+ "hsubps",
+ "idiv",
+ "imul",
+ "in",
+ "inc",
+ "insb",
+ "insd",
+ "insertps",
+ "insw",
+ "int",
+ "int1",
+ "int3",
+ "into",
+ "invd",
+ "invept",
+ "invlpg",
+ "invlpga",
+ "invvpid",
+ "iretd",
+ "iretq",
+ "iretw",
+ "ja",
+ "jae",
+ "jb",
+ "jbe",
+ "jcxz",
+ "jecxz",
+ "jg",
+ "jge",
+ "jl",
+ "jle",
+ "jmp",
+ "jno",
+ "jnp",
+ "jns",
+ "jnz",
+ "jo",
+ "jp",
+ "jrcxz",
+ "js",
+ "jz",
+ "lahf",
+ "lar",
+ "lddqu",
+ "ldmxcsr",
+ "lds",
+ "lea",
+ "leave",
+ "les",
+ "lfence",
+ "lfs",
+ "lgdt",
+ "lgs",
+ "lidt",
+ "lldt",
+ "lmsw",
+ "lock",
+ "lodsb",
+ "lodsd",
+ "lodsq",
+ "lodsw",
+ "loop",
+ "loope",
+ "loopne",
+ "lsl",
+ "lss",
+ "ltr",
+ "maskmovdqu",
+ "maskmovq",
+ "maxpd",
+ "maxps",
+ "maxsd",
+ "maxss",
+ "mfence",
+ "minpd",
+ "minps",
+ "minsd",
+ "minss",
+ "monitor",
+ "montmul",
+ "mov",
+ "movapd",
+ "movaps",
+ "movbe",
+ "movd",
+ "movddup",
+ "movdq2q",
+ "movdqa",
+ "movdqu",
+ "movhlps",
+ "movhpd",
+ "movhps",
+ "movlhps",
+ "movlpd",
+ "movlps",
+ "movmskpd",
+ "movmskps",
+ "movntdq",
+ "movntdqa",
+ "movnti",
+ "movntpd",
+ "movntps",
+ "movntq",
+ "movq",
+ "movq2dq",
+ "movsb",
+ "movsd",
+ "movshdup",
+ "movsldup",
+ "movsq",
+ "movss",
+ "movsw",
+ "movsx",
+ "movsxd",
+ "movupd",
+ "movups",
+ "movzx",
+ "mpsadbw",
+ "mul",
+ "mulpd",
+ "mulps",
+ "mulsd",
+ "mulss",
+ "mwait",
+ "neg",
+ "nop",
+ "not",
+ "or",
+ "orpd",
+ "orps",
+ "out",
+ "outsb",
+ "outsd",
+ "outsw",
+ "pabsb",
+ "pabsd",
+ "pabsw",
+ "packssdw",
+ "packsswb",
+ "packusdw",
+ "packuswb",
+ "paddb",
+ "paddd",
+ "paddq",
+ "paddsb",
+ "paddsw",
+ "paddusb",
+ "paddusw",
+ "paddw",
+ "palignr",
+ "pand",
+ "pandn",
+ "pavgb",
+ "pavgusb",
+ "pavgw",
+ "pblendvb",
+ "pblendw",
+ "pclmulqdq",
+ "pcmpeqb",
+ "pcmpeqd",
+ "pcmpeqq",
+ "pcmpeqw",
+ "pcmpestri",
+ "pcmpestrm",
+ "pcmpgtb",
+ "pcmpgtd",
+ "pcmpgtq",
+ "pcmpgtw",
+ "pcmpistri",
+ "pcmpistrm",
+ "pextrb",
+ "pextrd",
+ "pextrq",
+ "pextrw",
+ "pf2id",
+ "pf2iw",
+ "pfacc",
+ "pfadd",
+ "pfcmpeq",
+ "pfcmpge",
+ "pfcmpgt",
+ "pfmax",
+ "pfmin",
+ "pfmul",
+ "pfnacc",
+ "pfpnacc",
+ "pfrcp",
+ "pfrcpit1",
+ "pfrcpit2",
+ "pfrsqit1",
+ "pfrsqrt",
+ "pfsub",
+ "pfsubr",
+ "phaddd",
+ "phaddsw",
+ "phaddw",
+ "phminposuw",
+ "phsubd",
+ "phsubsw",
+ "phsubw",
+ "pi2fd",
+ "pi2fw",
+ "pinsrb",
+ "pinsrd",
+ "pinsrq",
+ "pinsrw",
+ "pmaddubsw",
+ "pmaddwd",
+ "pmaxsb",
+ "pmaxsd",
+ "pmaxsw",
+ "pmaxub",
+ "pmaxud",
+ "pmaxuw",
+ "pminsb",
+ "pminsd",
+ "pminsw",
+ "pminub",
+ "pminud",
+ "pminuw",
+ "pmovmskb",
+ "pmovsxbd",
+ "pmovsxbq",
+ "pmovsxbw",
+ "pmovsxdq",
+ "pmovsxwd",
+ "pmovsxwq",
+ "pmovzxbd",
+ "pmovzxbq",
+ "pmovzxbw",
+ "pmovzxdq",
+ "pmovzxwd",
+ "pmovzxwq",
+ "pmuldq",
+ "pmulhrsw",
+ "pmulhrw",
+ "pmulhuw",
+ "pmulhw",
+ "pmulld",
+ "pmullw",
+ "pmuludq",
+ "pop",
+ "popa",
+ "popad",
+ "popcnt",
+ "popfd",
+ "popfq",
+ "popfw",
+ "por",
+ "prefetch",
+ "prefetchnta",
+ "prefetcht0",
+ "prefetcht1",
+ "prefetcht2",
+ "psadbw",
+ "pshufb",
+ "pshufd",
+ "pshufhw",
+ "pshuflw",
+ "pshufw",
+ "psignb",
+ "psignd",
+ "psignw",
+ "pslld",
+ "pslldq",
+ "psllq",
+ "psllw",
+ "psrad",
+ "psraw",
+ "psrld",
+ "psrldq",
+ "psrlq",
+ "psrlw",
+ "psubb",
+ "psubd",
+ "psubq",
+ "psubsb",
+ "psubsw",
+ "psubusb",
+ "psubusw",
+ "psubw",
+ "pswapd",
+ "ptest",
+ "punpckhbw",
+ "punpckhdq",
+ "punpckhqdq",
+ "punpckhwd",
+ "punpcklbw",
+ "punpckldq",
+ "punpcklqdq",
+ "punpcklwd",
+ "push",
+ "pusha",
+ "pushad",
+ "pushfd",
+ "pushfq",
+ "pushfw",
+ "pxor",
+ "rcl",
+ "rcpps",
+ "rcpss",
+ "rcr",
+ "rdmsr",
+ "rdpmc",
+ "rdrand",
+ "rdtsc",
+ "rdtscp",
+ "rep",
+ "repne",
+ "ret",
+ "retf",
+ "rol",
+ "ror",
+ "roundpd",
+ "roundps",
+ "roundsd",
+ "roundss",
+ "rsm",
+ "rsqrtps",
+ "rsqrtss",
+ "sahf",
+ "salc",
+ "sar",
+ "sbb",
+ "scasb",
+ "scasd",
+ "scasq",
+ "scasw",
+ "seta",
+ "setae",
+ "setb",
+ "setbe",
+ "setg",
+ "setge",
+ "setl",
+ "setle",
+ "setno",
+ "setnp",
+ "setns",
+ "setnz",
+ "seto",
+ "setp",
+ "sets",
+ "setz",
+ "sfence",
+ "sgdt",
+ "shl",
+ "shld",
+ "shr",
+ "shrd",
+ "shufpd",
+ "shufps",
+ "sidt",
+ "skinit",
+ "sldt",
+ "smsw",
+ "sqrtpd",
+ "sqrtps",
+ "sqrtsd",
+ "sqrtss",
+ "stc",
+ "std",
+ "stgi",
+ "sti",
+ "stmxcsr",
+ "stosb",
+ "stosd",
+ "stosq",
+ "stosw",
+ "str",
+ "sub",
+ "subpd",
+ "subps",
+ "subsd",
+ "subss",
+ "swapgs",
+ "syscall",
+ "sysenter",
+ "sysexit",
+ "sysret",
+ "test",
+ "ucomisd",
+ "ucomiss",
+ "ud2",
+ "unpckhpd",
+ "unpckhps",
+ "unpcklpd",
+ "unpcklps",
+ "vaddpd",
+ "vaddps",
+ "vaddsd",
+ "vaddss",
+ "vaddsubpd",
+ "vaddsubps",
+ "vaesdec",
+ "vaesdeclast",
+ "vaesenc",
+ "vaesenclast",
+ "vaesimc",
+ "vaeskeygenassist",
+ "vandnpd",
+ "vandnps",
+ "vandpd",
+ "vandps",
+ "vblendpd",
+ "vblendps",
+ "vblendvpd",
+ "vblendvps",
+ "vbroadcastsd",
+ "vbroadcastss",
+ "vcmppd",
+ "vcmpps",
+ "vcmpsd",
+ "vcmpss",
+ "vcomisd",
+ "vcomiss",
+ "vcvtdq2pd",
+ "vcvtdq2ps",
+ "vcvtpd2dq",
+ "vcvtpd2ps",
+ "vcvtps2dq",
+ "vcvtps2pd",
+ "vcvtsd2si",
+ "vcvtsd2ss",
+ "vcvtsi2sd",
+ "vcvtsi2ss",
+ "vcvtss2sd",
+ "vcvtss2si",
+ "vcvttpd2dq",
+ "vcvttps2dq",
+ "vcvttsd2si",
+ "vcvttss2si",
+ "vdivpd",
+ "vdivps",
+ "vdivsd",
+ "vdivss",
+ "vdppd",
+ "vdpps",
+ "verr",
+ "verw",
+ "vextractf128",
+ "vextractps",
+ "vhaddpd",
+ "vhaddps",
+ "vhsubpd",
+ "vhsubps",
+ "vinsertf128",
+ "vinsertps",
+ "vlddqu",
+ "vmaskmovdqu",
+ "vmaskmovpd",
+ "vmaskmovps",
+ "vmaxpd",
+ "vmaxps",
+ "vmaxsd",
+ "vmaxss",
+ "vmcall",
+ "vmclear",
+ "vminpd",
+ "vminps",
+ "vminsd",
+ "vminss",
+ "vmlaunch",
+ "vmload",
+ "vmmcall",
+ "vmovapd",
+ "vmovaps",
+ "vmovd",
+ "vmovddup",
+ "vmovdqa",
+ "vmovdqu",
+ "vmovhlps",
+ "vmovhpd",
+ "vmovhps",
+ "vmovlhps",
+ "vmovlpd",
+ "vmovlps",
+ "vmovmskpd",
+ "vmovmskps",
+ "vmovntdq",
+ "vmovntdqa",
+ "vmovntpd",
+ "vmovntps",
+ "vmovq",
+ "vmovsd",
+ "vmovshdup",
+ "vmovsldup",
+ "vmovss",
+ "vmovupd",
+ "vmovups",
+ "vmpsadbw",
+ "vmptrld",
+ "vmptrst",
+ "vmread",
+ "vmresume",
+ "vmrun",
+ "vmsave",
+ "vmulpd",
+ "vmulps",
+ "vmulsd",
+ "vmulss",
+ "vmwrite",
+ "vmxoff",
+ "vmxon",
+ "vorpd",
+ "vorps",
+ "vpabsb",
+ "vpabsd",
+ "vpabsw",
+ "vpackssdw",
+ "vpacksswb",
+ "vpackusdw",
+ "vpackuswb",
+ "vpaddb",
+ "vpaddd",
+ "vpaddq",
+ "vpaddsb",
+ "vpaddsw",
+ "vpaddusb",
+ "vpaddusw",
+ "vpaddw",
+ "vpalignr",
+ "vpand",
+ "vpandn",
+ "vpavgb",
+ "vpavgw",
+ "vpblendvb",
+ "vpblendw",
+ "vpclmulqdq",
+ "vpcmpeqb",
+ "vpcmpeqd",
+ "vpcmpeqq",
+ "vpcmpeqw",
+ "vpcmpestri",
+ "vpcmpestrm",
+ "vpcmpgtb",
+ "vpcmpgtd",
+ "vpcmpgtq",
+ "vpcmpgtw",
+ "vpcmpistri",
+ "vpcmpistrm",
+ "vperm2f128",
+ "vpermilpd",
+ "vpermilps",
+ "vpextrb",
+ "vpextrd",
+ "vpextrq",
+ "vpextrw",
+ "vphaddd",
+ "vphaddsw",
+ "vphaddw",
+ "vphminposuw",
+ "vphsubd",
+ "vphsubsw",
+ "vphsubw",
+ "vpinsrb",
+ "vpinsrd",
+ "vpinsrq",
+ "vpinsrw",
+ "vpmaddubsw",
+ "vpmaddwd",
+ "vpmaxsb",
+ "vpmaxsd",
+ "vpmaxsw",
+ "vpmaxub",
+ "vpmaxud",
+ "vpmaxuw",
+ "vpminsb",
+ "vpminsd",
+ "vpminsw",
+ "vpminub",
+ "vpminud",
+ "vpminuw",
+ "vpmovmskb",
+ "vpmovsxbd",
+ "vpmovsxbq",
+ "vpmovsxbw",
+ "vpmovsxwd",
+ "vpmovsxwq",
+ "vpmovzxbd",
+ "vpmovzxbq",
+ "vpmovzxbw",
+ "vpmovzxdq",
+ "vpmovzxwd",
+ "vpmovzxwq",
+ "vpmuldq",
+ "vpmulhrsw",
+ "vpmulhuw",
+ "vpmulhw",
+ "vpmulld",
+ "vpmullw",
+ "vpor",
+ "vpsadbw",
+ "vpshufb",
+ "vpshufd",
+ "vpshufhw",
+ "vpshuflw",
+ "vpsignb",
+ "vpsignd",
+ "vpsignw",
+ "vpslld",
+ "vpslldq",
+ "vpsllq",
+ "vpsllw",
+ "vpsrad",
+ "vpsraw",
+ "vpsrld",
+ "vpsrldq",
+ "vpsrlq",
+ "vpsrlw",
+ "vpsubb",
+ "vpsubd",
+ "vpsubq",
+ "vpsubsb",
+ "vpsubsw",
+ "vpsubusb",
+ "vpsubusw",
+ "vpsubw",
+ "vptest",
+ "vpunpckhbw",
+ "vpunpckhdq",
+ "vpunpckhqdq",
+ "vpunpckhwd",
+ "vpunpcklbw",
+ "vpunpckldq",
+ "vpunpcklqdq",
+ "vpunpcklwd",
+ "vpxor",
+ "vrcpps",
+ "vrcpss",
+ "vroundpd",
+ "vroundps",
+ "vroundsd",
+ "vroundss",
+ "vrsqrtps",
+ "vrsqrtss",
+ "vshufpd",
+ "vshufps",
+ "vsqrtpd",
+ "vsqrtps",
+ "vsqrtsd",
+ "vsqrtss",
+ "vstmxcsr",
+ "vsubpd",
+ "vsubps",
+ "vsubsd",
+ "vsubss",
+ "vtestpd",
+ "vtestps",
+ "vucomisd",
+ "vucomiss",
+ "vunpckhpd",
+ "vunpckhps",
+ "vunpcklpd",
+ "vunpcklps",
+ "vxorpd",
+ "vxorps",
+ "vzeroall",
+ "vzeroupper",
+ "wait",
+ "wbinvd",
+ "wrmsr",
+ "xadd",
+ "xchg",
+ "xcryptcbc",
+ "xcryptcfb",
+ "xcryptctr",
+ "xcryptecb",
+ "xcryptofb",
+ "xgetbv",
+ "xlatb",
+ "xor",
+ "xorpd",
+ "xorps",
+ "xrstor",
+ "xsave",
+ "xsetbv",
+ "xsha1",
+ "xsha256",
+ "xstore",
+ "invalid",
+ "3dnow",
+ "none",
+ "db",
+ "pause"
+};
diff --git a/src/3p/udis86/itab.h b/src/3p/udis86/itab.h
new file mode 100644
index 0000000..3d54c43
--- /dev/null
+++ b/src/3p/udis86/itab.h
@@ -0,0 +1,939 @@
+#ifndef UD_ITAB_H
+#define UD_ITAB_H
+
+/* itab.h -- generated by udis86:scripts/ud_itab.py, do no edit */
+
+/* ud_table_type -- lookup table types (see decode.c) */
+enum ud_table_type {
+ UD_TAB__OPC_VEX,
+ UD_TAB__OPC_TABLE,
+ UD_TAB__OPC_X87,
+ UD_TAB__OPC_MOD,
+ UD_TAB__OPC_RM,
+ UD_TAB__OPC_OSIZE,
+ UD_TAB__OPC_MODE,
+ UD_TAB__OPC_VEX_L,
+ UD_TAB__OPC_3DNOW,
+ UD_TAB__OPC_REG,
+ UD_TAB__OPC_ASIZE,
+ UD_TAB__OPC_VEX_W,
+ UD_TAB__OPC_SSE,
+ UD_TAB__OPC_VENDOR
+};
+
+/* ud_mnemonic -- mnemonic constants */
+enum ud_mnemonic_code {
+ UD_Iaaa,
+ UD_Iaad,
+ UD_Iaam,
+ UD_Iaas,
+ UD_Iadc,
+ UD_Iadd,
+ UD_Iaddpd,
+ UD_Iaddps,
+ UD_Iaddsd,
+ UD_Iaddss,
+ UD_Iaddsubpd,
+ UD_Iaddsubps,
+ UD_Iaesdec,
+ UD_Iaesdeclast,
+ UD_Iaesenc,
+ UD_Iaesenclast,
+ UD_Iaesimc,
+ UD_Iaeskeygenassist,
+ UD_Iand,
+ UD_Iandnpd,
+ UD_Iandnps,
+ UD_Iandpd,
+ UD_Iandps,
+ UD_Iarpl,
+ UD_Iblendpd,
+ UD_Iblendps,
+ UD_Iblendvpd,
+ UD_Iblendvps,
+ UD_Ibound,
+ UD_Ibsf,
+ UD_Ibsr,
+ UD_Ibswap,
+ UD_Ibt,
+ UD_Ibtc,
+ UD_Ibtr,
+ UD_Ibts,
+ UD_Icall,
+ UD_Icbw,
+ UD_Icdq,
+ UD_Icdqe,
+ UD_Iclc,
+ UD_Icld,
+ UD_Iclflush,
+ UD_Iclgi,
+ UD_Icli,
+ UD_Iclts,
+ UD_Icmc,
+ UD_Icmova,
+ UD_Icmovae,
+ UD_Icmovb,
+ UD_Icmovbe,
+ UD_Icmovg,
+ UD_Icmovge,
+ UD_Icmovl,
+ UD_Icmovle,
+ UD_Icmovno,
+ UD_Icmovnp,
+ UD_Icmovns,
+ UD_Icmovnz,
+ UD_Icmovo,
+ UD_Icmovp,
+ UD_Icmovs,
+ UD_Icmovz,
+ UD_Icmp,
+ UD_Icmppd,
+ UD_Icmpps,
+ UD_Icmpsb,
+ UD_Icmpsd,
+ UD_Icmpsq,
+ UD_Icmpss,
+ UD_Icmpsw,
+ UD_Icmpxchg,
+ UD_Icmpxchg16b,
+ UD_Icmpxchg8b,
+ UD_Icomisd,
+ UD_Icomiss,
+ UD_Icpuid,
+ UD_Icqo,
+ UD_Icrc32,
+ UD_Icvtdq2pd,
+ UD_Icvtdq2ps,
+ UD_Icvtpd2dq,
+ UD_Icvtpd2pi,
+ UD_Icvtpd2ps,
+ UD_Icvtpi2pd,
+ UD_Icvtpi2ps,
+ UD_Icvtps2dq,
+ UD_Icvtps2pd,
+ UD_Icvtps2pi,
+ UD_Icvtsd2si,
+ UD_Icvtsd2ss,
+ UD_Icvtsi2sd,
+ UD_Icvtsi2ss,
+ UD_Icvtss2sd,
+ UD_Icvtss2si,
+ UD_Icvttpd2dq,
+ UD_Icvttpd2pi,
+ UD_Icvttps2dq,
+ UD_Icvttps2pi,
+ UD_Icvttsd2si,
+ UD_Icvttss2si,
+ UD_Icwd,
+ UD_Icwde,
+ UD_Idaa,
+ UD_Idas,
+ UD_Idec,
+ UD_Idiv,
+ UD_Idivpd,
+ UD_Idivps,
+ UD_Idivsd,
+ UD_Idivss,
+ UD_Idppd,
+ UD_Idpps,
+ UD_Iemms,
+ UD_Ienter,
+ UD_Iextractps,
+ UD_If2xm1,
+ UD_Ifabs,
+ UD_Ifadd,
+ UD_Ifaddp,
+ UD_Ifbld,
+ UD_Ifbstp,
+ UD_Ifchs,
+ UD_Ifclex,
+ UD_Ifcmovb,
+ UD_Ifcmovbe,
+ UD_Ifcmove,
+ UD_Ifcmovnb,
+ UD_Ifcmovnbe,
+ UD_Ifcmovne,
+ UD_Ifcmovnu,
+ UD_Ifcmovu,
+ UD_Ifcom,
+ UD_Ifcom2,
+ UD_Ifcomi,
+ UD_Ifcomip,
+ UD_Ifcomp,
+ UD_Ifcomp3,
+ UD_Ifcomp5,
+ UD_Ifcompp,
+ UD_Ifcos,
+ UD_Ifdecstp,
+ UD_Ifdiv,
+ UD_Ifdivp,
+ UD_Ifdivr,
+ UD_Ifdivrp,
+ UD_Ifemms,
+ UD_Iffree,
+ UD_Iffreep,
+ UD_Ifiadd,
+ UD_Ificom,
+ UD_Ificomp,
+ UD_Ifidiv,
+ UD_Ifidivr,
+ UD_Ifild,
+ UD_Ifimul,
+ UD_Ifincstp,
+ UD_Ifist,
+ UD_Ifistp,
+ UD_Ifisttp,
+ UD_Ifisub,
+ UD_Ifisubr,
+ UD_Ifld,
+ UD_Ifld1,
+ UD_Ifldcw,
+ UD_Ifldenv,
+ UD_Ifldl2e,
+ UD_Ifldl2t,
+ UD_Ifldlg2,
+ UD_Ifldln2,
+ UD_Ifldpi,
+ UD_Ifldz,
+ UD_Ifmul,
+ UD_Ifmulp,
+ UD_Ifndisi,
+ UD_Ifneni,
+ UD_Ifninit,
+ UD_Ifnop,
+ UD_Ifnsave,
+ UD_Ifnsetpm,
+ UD_Ifnstcw,
+ UD_Ifnstenv,
+ UD_Ifnstsw,
+ UD_Ifpatan,
+ UD_Ifprem,
+ UD_Ifprem1,
+ UD_Ifptan,
+ UD_Ifrndint,
+ UD_Ifrstor,
+ UD_Ifrstpm,
+ UD_Ifscale,
+ UD_Ifsin,
+ UD_Ifsincos,
+ UD_Ifsqrt,
+ UD_Ifst,
+ UD_Ifstp,
+ UD_Ifstp1,
+ UD_Ifstp8,
+ UD_Ifstp9,
+ UD_Ifsub,
+ UD_Ifsubp,
+ UD_Ifsubr,
+ UD_Ifsubrp,
+ UD_Iftst,
+ UD_Ifucom,
+ UD_Ifucomi,
+ UD_Ifucomip,
+ UD_Ifucomp,
+ UD_Ifucompp,
+ UD_Ifxam,
+ UD_Ifxch,
+ UD_Ifxch4,
+ UD_Ifxch7,
+ UD_Ifxrstor,
+ UD_Ifxsave,
+ UD_Ifxtract,
+ UD_Ifyl2x,
+ UD_Ifyl2xp1,
+ UD_Igetsec,
+ UD_Ihaddpd,
+ UD_Ihaddps,
+ UD_Ihlt,
+ UD_Ihsubpd,
+ UD_Ihsubps,
+ UD_Iidiv,
+ UD_Iimul,
+ UD_Iin,
+ UD_Iinc,
+ UD_Iinsb,
+ UD_Iinsd,
+ UD_Iinsertps,
+ UD_Iinsw,
+ UD_Iint,
+ UD_Iint1,
+ UD_Iint3,
+ UD_Iinto,
+ UD_Iinvd,
+ UD_Iinvept,
+ UD_Iinvlpg,
+ UD_Iinvlpga,
+ UD_Iinvvpid,
+ UD_Iiretd,
+ UD_Iiretq,
+ UD_Iiretw,
+ UD_Ija,
+ UD_Ijae,
+ UD_Ijb,
+ UD_Ijbe,
+ UD_Ijcxz,
+ UD_Ijecxz,
+ UD_Ijg,
+ UD_Ijge,
+ UD_Ijl,
+ UD_Ijle,
+ UD_Ijmp,
+ UD_Ijno,
+ UD_Ijnp,
+ UD_Ijns,
+ UD_Ijnz,
+ UD_Ijo,
+ UD_Ijp,
+ UD_Ijrcxz,
+ UD_Ijs,
+ UD_Ijz,
+ UD_Ilahf,
+ UD_Ilar,
+ UD_Ilddqu,
+ UD_Ildmxcsr,
+ UD_Ilds,
+ UD_Ilea,
+ UD_Ileave,
+ UD_Iles,
+ UD_Ilfence,
+ UD_Ilfs,
+ UD_Ilgdt,
+ UD_Ilgs,
+ UD_Ilidt,
+ UD_Illdt,
+ UD_Ilmsw,
+ UD_Ilock,
+ UD_Ilodsb,
+ UD_Ilodsd,
+ UD_Ilodsq,
+ UD_Ilodsw,
+ UD_Iloop,
+ UD_Iloope,
+ UD_Iloopne,
+ UD_Ilsl,
+ UD_Ilss,
+ UD_Iltr,
+ UD_Imaskmovdqu,
+ UD_Imaskmovq,
+ UD_Imaxpd,
+ UD_Imaxps,
+ UD_Imaxsd,
+ UD_Imaxss,
+ UD_Imfence,
+ UD_Iminpd,
+ UD_Iminps,
+ UD_Iminsd,
+ UD_Iminss,
+ UD_Imonitor,
+ UD_Imontmul,
+ UD_Imov,
+ UD_Imovapd,
+ UD_Imovaps,
+ UD_Imovbe,
+ UD_Imovd,
+ UD_Imovddup,
+ UD_Imovdq2q,
+ UD_Imovdqa,
+ UD_Imovdqu,
+ UD_Imovhlps,
+ UD_Imovhpd,
+ UD_Imovhps,
+ UD_Imovlhps,
+ UD_Imovlpd,
+ UD_Imovlps,
+ UD_Imovmskpd,
+ UD_Imovmskps,
+ UD_Imovntdq,
+ UD_Imovntdqa,
+ UD_Imovnti,
+ UD_Imovntpd,
+ UD_Imovntps,
+ UD_Imovntq,
+ UD_Imovq,
+ UD_Imovq2dq,
+ UD_Imovsb,
+ UD_Imovsd,
+ UD_Imovshdup,
+ UD_Imovsldup,
+ UD_Imovsq,
+ UD_Imovss,
+ UD_Imovsw,
+ UD_Imovsx,
+ UD_Imovsxd,
+ UD_Imovupd,
+ UD_Imovups,
+ UD_Imovzx,
+ UD_Impsadbw,
+ UD_Imul,
+ UD_Imulpd,
+ UD_Imulps,
+ UD_Imulsd,
+ UD_Imulss,
+ UD_Imwait,
+ UD_Ineg,
+ UD_Inop,
+ UD_Inot,
+ UD_Ior,
+ UD_Iorpd,
+ UD_Iorps,
+ UD_Iout,
+ UD_Ioutsb,
+ UD_Ioutsd,
+ UD_Ioutsw,
+ UD_Ipabsb,
+ UD_Ipabsd,
+ UD_Ipabsw,
+ UD_Ipackssdw,
+ UD_Ipacksswb,
+ UD_Ipackusdw,
+ UD_Ipackuswb,
+ UD_Ipaddb,
+ UD_Ipaddd,
+ UD_Ipaddq,
+ UD_Ipaddsb,
+ UD_Ipaddsw,
+ UD_Ipaddusb,
+ UD_Ipaddusw,
+ UD_Ipaddw,
+ UD_Ipalignr,
+ UD_Ipand,
+ UD_Ipandn,
+ UD_Ipavgb,
+ UD_Ipavgusb,
+ UD_Ipavgw,
+ UD_Ipblendvb,
+ UD_Ipblendw,
+ UD_Ipclmulqdq,
+ UD_Ipcmpeqb,
+ UD_Ipcmpeqd,
+ UD_Ipcmpeqq,
+ UD_Ipcmpeqw,
+ UD_Ipcmpestri,
+ UD_Ipcmpestrm,
+ UD_Ipcmpgtb,
+ UD_Ipcmpgtd,
+ UD_Ipcmpgtq,
+ UD_Ipcmpgtw,
+ UD_Ipcmpistri,
+ UD_Ipcmpistrm,
+ UD_Ipextrb,
+ UD_Ipextrd,
+ UD_Ipextrq,
+ UD_Ipextrw,
+ UD_Ipf2id,
+ UD_Ipf2iw,
+ UD_Ipfacc,
+ UD_Ipfadd,
+ UD_Ipfcmpeq,
+ UD_Ipfcmpge,
+ UD_Ipfcmpgt,
+ UD_Ipfmax,
+ UD_Ipfmin,
+ UD_Ipfmul,
+ UD_Ipfnacc,
+ UD_Ipfpnacc,
+ UD_Ipfrcp,
+ UD_Ipfrcpit1,
+ UD_Ipfrcpit2,
+ UD_Ipfrsqit1,
+ UD_Ipfrsqrt,
+ UD_Ipfsub,
+ UD_Ipfsubr,
+ UD_Iphaddd,
+ UD_Iphaddsw,
+ UD_Iphaddw,
+ UD_Iphminposuw,
+ UD_Iphsubd,
+ UD_Iphsubsw,
+ UD_Iphsubw,
+ UD_Ipi2fd,
+ UD_Ipi2fw,
+ UD_Ipinsrb,
+ UD_Ipinsrd,
+ UD_Ipinsrq,
+ UD_Ipinsrw,
+ UD_Ipmaddubsw,
+ UD_Ipmaddwd,
+ UD_Ipmaxsb,
+ UD_Ipmaxsd,
+ UD_Ipmaxsw,
+ UD_Ipmaxub,
+ UD_Ipmaxud,
+ UD_Ipmaxuw,
+ UD_Ipminsb,
+ UD_Ipminsd,
+ UD_Ipminsw,
+ UD_Ipminub,
+ UD_Ipminud,
+ UD_Ipminuw,
+ UD_Ipmovmskb,
+ UD_Ipmovsxbd,
+ UD_Ipmovsxbq,
+ UD_Ipmovsxbw,
+ UD_Ipmovsxdq,
+ UD_Ipmovsxwd,
+ UD_Ipmovsxwq,
+ UD_Ipmovzxbd,
+ UD_Ipmovzxbq,
+ UD_Ipmovzxbw,
+ UD_Ipmovzxdq,
+ UD_Ipmovzxwd,
+ UD_Ipmovzxwq,
+ UD_Ipmuldq,
+ UD_Ipmulhrsw,
+ UD_Ipmulhrw,
+ UD_Ipmulhuw,
+ UD_Ipmulhw,
+ UD_Ipmulld,
+ UD_Ipmullw,
+ UD_Ipmuludq,
+ UD_Ipop,
+ UD_Ipopa,
+ UD_Ipopad,
+ UD_Ipopcnt,
+ UD_Ipopfd,
+ UD_Ipopfq,
+ UD_Ipopfw,
+ UD_Ipor,
+ UD_Iprefetch,
+ UD_Iprefetchnta,
+ UD_Iprefetcht0,
+ UD_Iprefetcht1,
+ UD_Iprefetcht2,
+ UD_Ipsadbw,
+ UD_Ipshufb,
+ UD_Ipshufd,
+ UD_Ipshufhw,
+ UD_Ipshuflw,
+ UD_Ipshufw,
+ UD_Ipsignb,
+ UD_Ipsignd,
+ UD_Ipsignw,
+ UD_Ipslld,
+ UD_Ipslldq,
+ UD_Ipsllq,
+ UD_Ipsllw,
+ UD_Ipsrad,
+ UD_Ipsraw,
+ UD_Ipsrld,
+ UD_Ipsrldq,
+ UD_Ipsrlq,
+ UD_Ipsrlw,
+ UD_Ipsubb,
+ UD_Ipsubd,
+ UD_Ipsubq,
+ UD_Ipsubsb,
+ UD_Ipsubsw,
+ UD_Ipsubusb,
+ UD_Ipsubusw,
+ UD_Ipsubw,
+ UD_Ipswapd,
+ UD_Iptest,
+ UD_Ipunpckhbw,
+ UD_Ipunpckhdq,
+ UD_Ipunpckhqdq,
+ UD_Ipunpckhwd,
+ UD_Ipunpcklbw,
+ UD_Ipunpckldq,
+ UD_Ipunpcklqdq,
+ UD_Ipunpcklwd,
+ UD_Ipush,
+ UD_Ipusha,
+ UD_Ipushad,
+ UD_Ipushfd,
+ UD_Ipushfq,
+ UD_Ipushfw,
+ UD_Ipxor,
+ UD_Ircl,
+ UD_Ircpps,
+ UD_Ircpss,
+ UD_Ircr,
+ UD_Irdmsr,
+ UD_Irdpmc,
+ UD_Irdrand,
+ UD_Irdtsc,
+ UD_Irdtscp,
+ UD_Irep,
+ UD_Irepne,
+ UD_Iret,
+ UD_Iretf,
+ UD_Irol,
+ UD_Iror,
+ UD_Iroundpd,
+ UD_Iroundps,
+ UD_Iroundsd,
+ UD_Iroundss,
+ UD_Irsm,
+ UD_Irsqrtps,
+ UD_Irsqrtss,
+ UD_Isahf,
+ UD_Isalc,
+ UD_Isar,
+ UD_Isbb,
+ UD_Iscasb,
+ UD_Iscasd,
+ UD_Iscasq,
+ UD_Iscasw,
+ UD_Iseta,
+ UD_Isetae,
+ UD_Isetb,
+ UD_Isetbe,
+ UD_Isetg,
+ UD_Isetge,
+ UD_Isetl,
+ UD_Isetle,
+ UD_Isetno,
+ UD_Isetnp,
+ UD_Isetns,
+ UD_Isetnz,
+ UD_Iseto,
+ UD_Isetp,
+ UD_Isets,
+ UD_Isetz,
+ UD_Isfence,
+ UD_Isgdt,
+ UD_Ishl,
+ UD_Ishld,
+ UD_Ishr,
+ UD_Ishrd,
+ UD_Ishufpd,
+ UD_Ishufps,
+ UD_Isidt,
+ UD_Iskinit,
+ UD_Isldt,
+ UD_Ismsw,
+ UD_Isqrtpd,
+ UD_Isqrtps,
+ UD_Isqrtsd,
+ UD_Isqrtss,
+ UD_Istc,
+ UD_Istd,
+ UD_Istgi,
+ UD_Isti,
+ UD_Istmxcsr,
+ UD_Istosb,
+ UD_Istosd,
+ UD_Istosq,
+ UD_Istosw,
+ UD_Istr,
+ UD_Isub,
+ UD_Isubpd,
+ UD_Isubps,
+ UD_Isubsd,
+ UD_Isubss,
+ UD_Iswapgs,
+ UD_Isyscall,
+ UD_Isysenter,
+ UD_Isysexit,
+ UD_Isysret,
+ UD_Itest,
+ UD_Iucomisd,
+ UD_Iucomiss,
+ UD_Iud2,
+ UD_Iunpckhpd,
+ UD_Iunpckhps,
+ UD_Iunpcklpd,
+ UD_Iunpcklps,
+ UD_Ivaddpd,
+ UD_Ivaddps,
+ UD_Ivaddsd,
+ UD_Ivaddss,
+ UD_Ivaddsubpd,
+ UD_Ivaddsubps,
+ UD_Ivaesdec,
+ UD_Ivaesdeclast,
+ UD_Ivaesenc,
+ UD_Ivaesenclast,
+ UD_Ivaesimc,
+ UD_Ivaeskeygenassist,
+ UD_Ivandnpd,
+ UD_Ivandnps,
+ UD_Ivandpd,
+ UD_Ivandps,
+ UD_Ivblendpd,
+ UD_Ivblendps,
+ UD_Ivblendvpd,
+ UD_Ivblendvps,
+ UD_Ivbroadcastsd,
+ UD_Ivbroadcastss,
+ UD_Ivcmppd,
+ UD_Ivcmpps,
+ UD_Ivcmpsd,
+ UD_Ivcmpss,
+ UD_Ivcomisd,
+ UD_Ivcomiss,
+ UD_Ivcvtdq2pd,
+ UD_Ivcvtdq2ps,
+ UD_Ivcvtpd2dq,
+ UD_Ivcvtpd2ps,
+ UD_Ivcvtps2dq,
+ UD_Ivcvtps2pd,
+ UD_Ivcvtsd2si,
+ UD_Ivcvtsd2ss,
+ UD_Ivcvtsi2sd,
+ UD_Ivcvtsi2ss,
+ UD_Ivcvtss2sd,
+ UD_Ivcvtss2si,
+ UD_Ivcvttpd2dq,
+ UD_Ivcvttps2dq,
+ UD_Ivcvttsd2si,
+ UD_Ivcvttss2si,
+ UD_Ivdivpd,
+ UD_Ivdivps,
+ UD_Ivdivsd,
+ UD_Ivdivss,
+ UD_Ivdppd,
+ UD_Ivdpps,
+ UD_Iverr,
+ UD_Iverw,
+ UD_Ivextractf128,
+ UD_Ivextractps,
+ UD_Ivhaddpd,
+ UD_Ivhaddps,
+ UD_Ivhsubpd,
+ UD_Ivhsubps,
+ UD_Ivinsertf128,
+ UD_Ivinsertps,
+ UD_Ivlddqu,
+ UD_Ivmaskmovdqu,
+ UD_Ivmaskmovpd,
+ UD_Ivmaskmovps,
+ UD_Ivmaxpd,
+ UD_Ivmaxps,
+ UD_Ivmaxsd,
+ UD_Ivmaxss,
+ UD_Ivmcall,
+ UD_Ivmclear,
+ UD_Ivminpd,
+ UD_Ivminps,
+ UD_Ivminsd,
+ UD_Ivminss,
+ UD_Ivmlaunch,
+ UD_Ivmload,
+ UD_Ivmmcall,
+ UD_Ivmovapd,
+ UD_Ivmovaps,
+ UD_Ivmovd,
+ UD_Ivmovddup,
+ UD_Ivmovdqa,
+ UD_Ivmovdqu,
+ UD_Ivmovhlps,
+ UD_Ivmovhpd,
+ UD_Ivmovhps,
+ UD_Ivmovlhps,
+ UD_Ivmovlpd,
+ UD_Ivmovlps,
+ UD_Ivmovmskpd,
+ UD_Ivmovmskps,
+ UD_Ivmovntdq,
+ UD_Ivmovntdqa,
+ UD_Ivmovntpd,
+ UD_Ivmovntps,
+ UD_Ivmovq,
+ UD_Ivmovsd,
+ UD_Ivmovshdup,
+ UD_Ivmovsldup,
+ UD_Ivmovss,
+ UD_Ivmovupd,
+ UD_Ivmovups,
+ UD_Ivmpsadbw,
+ UD_Ivmptrld,
+ UD_Ivmptrst,
+ UD_Ivmread,
+ UD_Ivmresume,
+ UD_Ivmrun,
+ UD_Ivmsave,
+ UD_Ivmulpd,
+ UD_Ivmulps,
+ UD_Ivmulsd,
+ UD_Ivmulss,
+ UD_Ivmwrite,
+ UD_Ivmxoff,
+ UD_Ivmxon,
+ UD_Ivorpd,
+ UD_Ivorps,
+ UD_Ivpabsb,
+ UD_Ivpabsd,
+ UD_Ivpabsw,
+ UD_Ivpackssdw,
+ UD_Ivpacksswb,
+ UD_Ivpackusdw,
+ UD_Ivpackuswb,
+ UD_Ivpaddb,
+ UD_Ivpaddd,
+ UD_Ivpaddq,
+ UD_Ivpaddsb,
+ UD_Ivpaddsw,
+ UD_Ivpaddusb,
+ UD_Ivpaddusw,
+ UD_Ivpaddw,
+ UD_Ivpalignr,
+ UD_Ivpand,
+ UD_Ivpandn,
+ UD_Ivpavgb,
+ UD_Ivpavgw,
+ UD_Ivpblendvb,
+ UD_Ivpblendw,
+ UD_Ivpclmulqdq,
+ UD_Ivpcmpeqb,
+ UD_Ivpcmpeqd,
+ UD_Ivpcmpeqq,
+ UD_Ivpcmpeqw,
+ UD_Ivpcmpestri,
+ UD_Ivpcmpestrm,
+ UD_Ivpcmpgtb,
+ UD_Ivpcmpgtd,
+ UD_Ivpcmpgtq,
+ UD_Ivpcmpgtw,
+ UD_Ivpcmpistri,
+ UD_Ivpcmpistrm,
+ UD_Ivperm2f128,
+ UD_Ivpermilpd,
+ UD_Ivpermilps,
+ UD_Ivpextrb,
+ UD_Ivpextrd,
+ UD_Ivpextrq,
+ UD_Ivpextrw,
+ UD_Ivphaddd,
+ UD_Ivphaddsw,
+ UD_Ivphaddw,
+ UD_Ivphminposuw,
+ UD_Ivphsubd,
+ UD_Ivphsubsw,
+ UD_Ivphsubw,
+ UD_Ivpinsrb,
+ UD_Ivpinsrd,
+ UD_Ivpinsrq,
+ UD_Ivpinsrw,
+ UD_Ivpmaddubsw,
+ UD_Ivpmaddwd,
+ UD_Ivpmaxsb,
+ UD_Ivpmaxsd,
+ UD_Ivpmaxsw,
+ UD_Ivpmaxub,
+ UD_Ivpmaxud,
+ UD_Ivpmaxuw,
+ UD_Ivpminsb,
+ UD_Ivpminsd,
+ UD_Ivpminsw,
+ UD_Ivpminub,
+ UD_Ivpminud,
+ UD_Ivpminuw,
+ UD_Ivpmovmskb,
+ UD_Ivpmovsxbd,
+ UD_Ivpmovsxbq,
+ UD_Ivpmovsxbw,
+ UD_Ivpmovsxwd,
+ UD_Ivpmovsxwq,
+ UD_Ivpmovzxbd,
+ UD_Ivpmovzxbq,
+ UD_Ivpmovzxbw,
+ UD_Ivpmovzxdq,
+ UD_Ivpmovzxwd,
+ UD_Ivpmovzxwq,
+ UD_Ivpmuldq,
+ UD_Ivpmulhrsw,
+ UD_Ivpmulhuw,
+ UD_Ivpmulhw,
+ UD_Ivpmulld,
+ UD_Ivpmullw,
+ UD_Ivpor,
+ UD_Ivpsadbw,
+ UD_Ivpshufb,
+ UD_Ivpshufd,
+ UD_Ivpshufhw,
+ UD_Ivpshuflw,
+ UD_Ivpsignb,
+ UD_Ivpsignd,
+ UD_Ivpsignw,
+ UD_Ivpslld,
+ UD_Ivpslldq,
+ UD_Ivpsllq,
+ UD_Ivpsllw,
+ UD_Ivpsrad,
+ UD_Ivpsraw,
+ UD_Ivpsrld,
+ UD_Ivpsrldq,
+ UD_Ivpsrlq,
+ UD_Ivpsrlw,
+ UD_Ivpsubb,
+ UD_Ivpsubd,
+ UD_Ivpsubq,
+ UD_Ivpsubsb,
+ UD_Ivpsubsw,
+ UD_Ivpsubusb,
+ UD_Ivpsubusw,
+ UD_Ivpsubw,
+ UD_Ivptest,
+ UD_Ivpunpckhbw,
+ UD_Ivpunpckhdq,
+ UD_Ivpunpckhqdq,
+ UD_Ivpunpckhwd,
+ UD_Ivpunpcklbw,
+ UD_Ivpunpckldq,
+ UD_Ivpunpcklqdq,
+ UD_Ivpunpcklwd,
+ UD_Ivpxor,
+ UD_Ivrcpps,
+ UD_Ivrcpss,
+ UD_Ivroundpd,
+ UD_Ivroundps,
+ UD_Ivroundsd,
+ UD_Ivroundss,
+ UD_Ivrsqrtps,
+ UD_Ivrsqrtss,
+ UD_Ivshufpd,
+ UD_Ivshufps,
+ UD_Ivsqrtpd,
+ UD_Ivsqrtps,
+ UD_Ivsqrtsd,
+ UD_Ivsqrtss,
+ UD_Ivstmxcsr,
+ UD_Ivsubpd,
+ UD_Ivsubps,
+ UD_Ivsubsd,
+ UD_Ivsubss,
+ UD_Ivtestpd,
+ UD_Ivtestps,
+ UD_Ivucomisd,
+ UD_Ivucomiss,
+ UD_Ivunpckhpd,
+ UD_Ivunpckhps,
+ UD_Ivunpcklpd,
+ UD_Ivunpcklps,
+ UD_Ivxorpd,
+ UD_Ivxorps,
+ UD_Ivzeroall,
+ UD_Ivzeroupper,
+ UD_Iwait,
+ UD_Iwbinvd,
+ UD_Iwrmsr,
+ UD_Ixadd,
+ UD_Ixchg,
+ UD_Ixcryptcbc,
+ UD_Ixcryptcfb,
+ UD_Ixcryptctr,
+ UD_Ixcryptecb,
+ UD_Ixcryptofb,
+ UD_Ixgetbv,
+ UD_Ixlatb,
+ UD_Ixor,
+ UD_Ixorpd,
+ UD_Ixorps,
+ UD_Ixrstor,
+ UD_Ixsave,
+ UD_Ixsetbv,
+ UD_Ixsha1,
+ UD_Ixsha256,
+ UD_Ixstore,
+ UD_Iinvalid,
+ UD_I3dnow,
+ UD_Inone,
+ UD_Idb,
+ UD_Ipause,
+ UD_MAX_MNEMONIC_CODE
+};
+
+extern const char * ud_mnemonics_str[];
+
+#endif /* UD_ITAB_H */
diff --git a/src/3p/udis86/syn-att.c b/src/3p/udis86/syn-att.c
new file mode 100644
index 0000000..d1ba89b
--- /dev/null
+++ b/src/3p/udis86/syn-att.c
@@ -0,0 +1,228 @@
+/* udis86 - libudis86/syn-att.c
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+#include "itab.h"
+#include "syn.h"
+#include "udint.h"
+
+/* -----------------------------------------------------------------------------
+ * opr_cast() - Prints an operand cast.
+ * -----------------------------------------------------------------------------
+ */
+static void
+opr_cast(struct ud* u, struct ud_operand* op)
+{
+ switch(op->size) {
+ case 16 : case 32 :
+ ud_asmprintf(u, "*"); break;
+ default: break;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * gen_operand() - Generates assembly output for each operand.
+ * -----------------------------------------------------------------------------
+ */
+static void
+gen_operand(struct ud* u, struct ud_operand* op)
+{
+ switch(op->type) {
+ case UD_OP_CONST:
+ ud_asmprintf(u, "$0x%x", op->lval.udword);
+ break;
+
+ case UD_OP_REG:
+ ud_asmprintf(u, "%%%s", ud_reg_tab[op->base - UD_R_AL]);
+ break;
+
+ case UD_OP_MEM:
+ if (u->br_far) {
+ opr_cast(u, op);
+ }
+ if (u->pfx_seg) {
+ ud_asmprintf(u, "%%%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+ if (op->offset != 0) {
+ ud_syn_print_mem_disp(u, op, 0);
+ }
+ if (op->base) {
+ ud_asmprintf(u, "(%%%s", ud_reg_tab[op->base - UD_R_AL]);
+ }
+ if (op->index) {
+ if (op->base) {
+ ud_asmprintf(u, ",");
+ } else {
+ ud_asmprintf(u, "(");
+ }
+ ud_asmprintf(u, "%%%s", ud_reg_tab[op->index - UD_R_AL]);
+ }
+ if (op->scale) {
+ ud_asmprintf(u, ",%d", op->scale);
+ }
+ if (op->base || op->index) {
+ ud_asmprintf(u, ")");
+ }
+ break;
+
+ case UD_OP_IMM:
+ ud_asmprintf(u, "$");
+ ud_syn_print_imm(u, op);
+ break;
+
+ case UD_OP_JIMM:
+ ud_syn_print_addr(u, ud_syn_rel_target(u, op));
+ break;
+
+ case UD_OP_PTR:
+ switch (op->size) {
+ case 32:
+ ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off & 0xFFFF);
+ break;
+ case 48:
+ ud_asmprintf(u, "$0x%x, $0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off);
+ break;
+ }
+ break;
+
+ default: return;
+ }
+}
+
+/* =============================================================================
+ * translates to AT&T syntax
+ * =============================================================================
+ */
+extern void
+ud_translate_att(struct ud *u)
+{
+ int size = 0;
+ int star = 0;
+
+ /* check if P_OSO prefix is used */
+ if (! P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
+ switch (u->dis_mode) {
+ case 16:
+ ud_asmprintf(u, "o32 ");
+ break;
+ case 32:
+ case 64:
+ ud_asmprintf(u, "o16 ");
+ break;
+ }
+ }
+
+ /* check if P_ASO prefix was used */
+ if (! P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
+ switch (u->dis_mode) {
+ case 16:
+ ud_asmprintf(u, "a32 ");
+ break;
+ case 32:
+ ud_asmprintf(u, "a16 ");
+ break;
+ case 64:
+ ud_asmprintf(u, "a32 ");
+ break;
+ }
+ }
+
+ if (u->pfx_lock)
+ ud_asmprintf(u, "lock ");
+ if (u->pfx_rep) {
+ ud_asmprintf(u, "rep ");
+ } else if (u->pfx_repe) {
+ ud_asmprintf(u, "repe ");
+ } else if (u->pfx_repne) {
+ ud_asmprintf(u, "repne ");
+ }
+
+ /* special instructions */
+ switch (u->mnemonic) {
+ case UD_Iretf:
+ ud_asmprintf(u, "lret ");
+ break;
+ case UD_Idb:
+ ud_asmprintf(u, ".byte 0x%x", u->operand[0].lval.ubyte);
+ return;
+ case UD_Ijmp:
+ case UD_Icall:
+ if (u->br_far) ud_asmprintf(u, "l");
+ if (u->operand[0].type == UD_OP_REG) {
+ star = 1;
+ }
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+ break;
+ case UD_Ibound:
+ case UD_Ienter:
+ if (u->operand[0].type != UD_NONE)
+ gen_operand(u, &u->operand[0]);
+ if (u->operand[1].type != UD_NONE) {
+ ud_asmprintf(u, ",");
+ gen_operand(u, &u->operand[1]);
+ }
+ return;
+ default:
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+ }
+
+ if (size == 8) {
+ ud_asmprintf(u, "b");
+ } else if (size == 16) {
+ ud_asmprintf(u, "w");
+ } else if (size == 64) {
+ ud_asmprintf(u, "q");
+ }
+
+ if (star) {
+ ud_asmprintf(u, " *");
+ } else {
+ ud_asmprintf(u, " ");
+ }
+
+ if (u->operand[3].type != UD_NONE) {
+ gen_operand(u, &u->operand[3]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[2].type != UD_NONE) {
+ gen_operand(u, &u->operand[2]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[1].type != UD_NONE) {
+ gen_operand(u, &u->operand[1]);
+ ud_asmprintf(u, ", ");
+ }
+ if (u->operand[0].type != UD_NONE) {
+ gen_operand(u, &u->operand[0]);
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/syn-intel.c b/src/3p/udis86/syn-intel.c
new file mode 100644
index 0000000..0664fea
--- /dev/null
+++ b/src/3p/udis86/syn-intel.c
@@ -0,0 +1,224 @@
+/* udis86 - libudis86/syn-intel.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "extern.h"
+#include "decode.h"
+#include "itab.h"
+#include "syn.h"
+#include "udint.h"
+
+/* -----------------------------------------------------------------------------
+ * opr_cast() - Prints an operand cast.
+ * -----------------------------------------------------------------------------
+ */
+static void
+opr_cast(struct ud* u, struct ud_operand* op)
+{
+ if (u->br_far) {
+ ud_asmprintf(u, "far ");
+ }
+ switch(op->size) {
+ case 8: ud_asmprintf(u, "byte " ); break;
+ case 16: ud_asmprintf(u, "word " ); break;
+ case 32: ud_asmprintf(u, "dword "); break;
+ case 64: ud_asmprintf(u, "qword "); break;
+ case 80: ud_asmprintf(u, "tword "); break;
+ case 128: ud_asmprintf(u, "oword "); break;
+ case 256: ud_asmprintf(u, "yword "); break;
+ default: break;
+ }
+}
+
+/* -----------------------------------------------------------------------------
+ * gen_operand() - Generates assembly output for each operand.
+ * -----------------------------------------------------------------------------
+ */
+static void gen_operand(struct ud* u, struct ud_operand* op, int syn_cast)
+{
+ switch(op->type) {
+ case UD_OP_REG:
+ ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
+ break;
+
+ case UD_OP_MEM:
+ if (syn_cast) {
+ opr_cast(u, op);
+ }
+ ud_asmprintf(u, "[");
+ if (u->pfx_seg) {
+ ud_asmprintf(u, "%s:", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+ if (op->base) {
+ ud_asmprintf(u, "%s", ud_reg_tab[op->base - UD_R_AL]);
+ }
+ if (op->index) {
+ ud_asmprintf(u, "%s%s", op->base != UD_NONE? "+" : "",
+ ud_reg_tab[op->index - UD_R_AL]);
+ if (op->scale) {
+ ud_asmprintf(u, "*%d", op->scale);
+ }
+ }
+ if (op->offset != 0) {
+ ud_syn_print_mem_disp(u, op, (op->base != UD_NONE ||
+ op->index != UD_NONE) ? 1 : 0);
+ }
+ ud_asmprintf(u, "]");
+ break;
+
+ case UD_OP_IMM:
+ ud_syn_print_imm(u, op);
+ break;
+
+
+ case UD_OP_JIMM:
+ ud_syn_print_addr(u, ud_syn_rel_target(u, op));
+ break;
+
+ case UD_OP_PTR:
+ switch (op->size) {
+ case 32:
+ ud_asmprintf(u, "word 0x%x:0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off & 0xFFFF);
+ break;
+ case 48:
+ ud_asmprintf(u, "dword 0x%x:0x%x", op->lval.ptr.seg,
+ op->lval.ptr.off);
+ break;
+ }
+ break;
+
+ case UD_OP_CONST:
+ if (syn_cast) opr_cast(u, op);
+ ud_asmprintf(u, "%d", op->lval.udword);
+ break;
+
+ default: return;
+ }
+}
+
+/* =============================================================================
+ * translates to intel syntax
+ * =============================================================================
+ */
+extern void
+ud_translate_intel(struct ud* u)
+{
+ /* check if P_OSO prefix is used */
+ if (!P_OSO(u->itab_entry->prefix) && u->pfx_opr) {
+ switch (u->dis_mode) {
+ case 16: ud_asmprintf(u, "o32 "); break;
+ case 32:
+ case 64: ud_asmprintf(u, "o16 "); break;
+ }
+ }
+
+ /* check if P_ASO prefix was used */
+ if (!P_ASO(u->itab_entry->prefix) && u->pfx_adr) {
+ switch (u->dis_mode) {
+ case 16: ud_asmprintf(u, "a32 "); break;
+ case 32: ud_asmprintf(u, "a16 "); break;
+ case 64: ud_asmprintf(u, "a32 "); break;
+ }
+ }
+
+ if (u->pfx_seg &&
+ u->operand[0].type != UD_OP_MEM &&
+ u->operand[1].type != UD_OP_MEM ) {
+ ud_asmprintf(u, "%s ", ud_reg_tab[u->pfx_seg - UD_R_AL]);
+ }
+
+ if (u->pfx_lock) {
+ ud_asmprintf(u, "lock ");
+ }
+ if (u->pfx_rep) {
+ ud_asmprintf(u, "rep ");
+ } else if (u->pfx_repe) {
+ ud_asmprintf(u, "repe ");
+ } else if (u->pfx_repne) {
+ ud_asmprintf(u, "repne ");
+ }
+
+ /* print the instruction mnemonic */
+ ud_asmprintf(u, "%s", ud_lookup_mnemonic(u->mnemonic));
+
+ if (u->operand[0].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, " ");
+ if (u->operand[0].type == UD_OP_MEM) {
+ if (u->operand[1].type == UD_OP_IMM ||
+ u->operand[1].type == UD_OP_CONST ||
+ u->operand[1].type == UD_NONE ||
+ (u->operand[0].size != u->operand[1].size)) {
+ cast = 1;
+ } else if (u->operand[1].type == UD_OP_REG &&
+ u->operand[1].base == UD_R_CL) {
+ switch (u->mnemonic) {
+ case UD_Ircl:
+ case UD_Irol:
+ case UD_Iror:
+ case UD_Ircr:
+ case UD_Ishl:
+ case UD_Ishr:
+ case UD_Isar:
+ cast = 1;
+ break;
+ default: break;
+ }
+ }
+ }
+ gen_operand(u, &u->operand[0], cast);
+ }
+
+ if (u->operand[1].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, ", ");
+ if (u->operand[1].type == UD_OP_MEM &&
+ u->operand[0].size != u->operand[1].size &&
+ !ud_opr_is_sreg(&u->operand[0])) {
+ cast = 1;
+ }
+ gen_operand(u, &u->operand[1], cast);
+ }
+
+ if (u->operand[2].type != UD_NONE) {
+ int cast = 0;
+ ud_asmprintf(u, ", ");
+ if (u->operand[2].type == UD_OP_MEM &&
+ u->operand[2].size != u->operand[1].size) {
+ cast = 1;
+ }
+ gen_operand(u, &u->operand[2], cast);
+ }
+
+ if (u->operand[3].type != UD_NONE) {
+ ud_asmprintf(u, ", ");
+ gen_operand(u, &u->operand[3], 0);
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/syn.c b/src/3p/udis86/syn.c
new file mode 100644
index 0000000..1b9e1d4
--- /dev/null
+++ b/src/3p/udis86/syn.c
@@ -0,0 +1,212 @@
+/* udis86 - libudis86/syn.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include "types.h"
+#include "decode.h"
+#include "syn.h"
+#include "udint.h"
+
+/*
+ * Register Table - Order Matters (types.h)!
+ *
+ */
+const char* ud_reg_tab[] =
+{
+ "al", "cl", "dl", "bl",
+ "ah", "ch", "dh", "bh",
+ "spl", "bpl", "sil", "dil",
+ "r8b", "r9b", "r10b", "r11b",
+ "r12b", "r13b", "r14b", "r15b",
+
+ "ax", "cx", "dx", "bx",
+ "sp", "bp", "si", "di",
+ "r8w", "r9w", "r10w", "r11w",
+ "r12w", "r13w", "r14w", "r15w",
+
+ "eax", "ecx", "edx", "ebx",
+ "esp", "ebp", "esi", "edi",
+ "r8d", "r9d", "r10d", "r11d",
+ "r12d", "r13d", "r14d", "r15d",
+
+ "rax", "rcx", "rdx", "rbx",
+ "rsp", "rbp", "rsi", "rdi",
+ "r8", "r9", "r10", "r11",
+ "r12", "r13", "r14", "r15",
+
+ "es", "cs", "ss", "ds",
+ "fs", "gs",
+
+ "cr0", "cr1", "cr2", "cr3",
+ "cr4", "cr5", "cr6", "cr7",
+ "cr8", "cr9", "cr10", "cr11",
+ "cr12", "cr13", "cr14", "cr15",
+
+ "dr0", "dr1", "dr2", "dr3",
+ "dr4", "dr5", "dr6", "dr7",
+ "dr8", "dr9", "dr10", "dr11",
+ "dr12", "dr13", "dr14", "dr15",
+
+ "mm0", "mm1", "mm2", "mm3",
+ "mm4", "mm5", "mm6", "mm7",
+
+ "st0", "st1", "st2", "st3",
+ "st4", "st5", "st6", "st7",
+
+ "xmm0", "xmm1", "xmm2", "xmm3",
+ "xmm4", "xmm5", "xmm6", "xmm7",
+ "xmm8", "xmm9", "xmm10", "xmm11",
+ "xmm12", "xmm13", "xmm14", "xmm15",
+
+ "ymm0", "ymm1", "ymm2", "ymm3",
+ "ymm4", "ymm5", "ymm6", "ymm7",
+ "ymm8", "ymm9", "ymm10", "ymm11",
+ "ymm12", "ymm13", "ymm14", "ymm15",
+
+ "rip"
+};
+
+
+uint64_t
+ud_syn_rel_target(struct ud *u, struct ud_operand *opr)
+{
+ const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode);
+ switch (opr->size) {
+ case 8 : return (u->pc + opr->lval.sbyte) & trunc_mask;
+ case 16: return (u->pc + opr->lval.sword) & trunc_mask;
+ case 32: return (u->pc + opr->lval.sdword) & trunc_mask;
+ default: UD_ASSERT(!"invalid relative offset size.");
+ return 0ull;
+ }
+}
+
+
+/*
+ * asmprintf
+ * Printf style function for printing translated assembly
+ * output. Returns the number of characters written and
+ * moves the buffer pointer forward. On an overflow,
+ * returns a negative number and truncates the output.
+ */
+int
+ud_asmprintf(struct ud *u, const char *fmt, ...)
+{
+ int ret;
+ int avail;
+ va_list ap;
+ va_start(ap, fmt);
+ avail = u->asm_buf_size - u->asm_buf_fill - 1 /* nullchar */;
+ ret = vsnprintf((char*) u->asm_buf + u->asm_buf_fill, avail, fmt, ap);
+ if (ret < 0 || ret > avail) {
+ u->asm_buf_fill = u->asm_buf_size - 1;
+ } else {
+ u->asm_buf_fill += ret;
+ }
+ va_end(ap);
+ return ret;
+}
+
+
+void
+ud_syn_print_addr(struct ud *u, uint64_t addr)
+{
+ const char *name = NULL;
+ if (u->sym_resolver) {
+ int64_t offset = 0;
+ name = u->sym_resolver(u, addr, &offset);
+ if (name) {
+ if (offset) {
+ ud_asmprintf(u, "%s%+" FMT64 "d", name, offset);
+ } else {
+ ud_asmprintf(u, "%s", name);
+ }
+ return;
+ }
+ }
+ ud_asmprintf(u, "0x%" FMT64 "x", addr);
+}
+
+
+void
+ud_syn_print_imm(struct ud* u, const struct ud_operand *op)
+{
+ uint64_t v;
+ if (op->_oprcode == OP_sI && op->size != u->opr_mode) {
+ if (op->size == 8) {
+ v = (int64_t)op->lval.sbyte;
+ } else {
+ UD_ASSERT(op->size == 32);
+ v = (int64_t)op->lval.sdword;
+ }
+ if (u->opr_mode < 64) {
+ v = v & ((1ull << u->opr_mode) - 1ull);
+ }
+ } else {
+ switch (op->size) {
+ case 8 : v = op->lval.ubyte; break;
+ case 16: v = op->lval.uword; break;
+ case 32: v = op->lval.udword; break;
+ case 64: v = op->lval.uqword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+ }
+ ud_asmprintf(u, "0x%" FMT64 "x", v);
+}
+
+
+void
+ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *op, int sign)
+{
+ UD_ASSERT(op->offset != 0);
+ if (op->base == UD_NONE && op->index == UD_NONE) {
+ uint64_t v;
+ UD_ASSERT(op->scale == UD_NONE && op->offset != 8);
+ /* unsigned mem-offset */
+ switch (op->offset) {
+ case 16: v = op->lval.uword; break;
+ case 32: v = op->lval.udword; break;
+ case 64: v = op->lval.uqword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+ ud_asmprintf(u, "0x%" FMT64 "x", v);
+ } else {
+ int64_t v;
+ UD_ASSERT(op->offset != 64);
+ switch (op->offset) {
+ case 8 : v = op->lval.sbyte; break;
+ case 16: v = op->lval.sword; break;
+ case 32: v = op->lval.sdword; break;
+ default: UD_ASSERT(!"invalid offset"); v = 0; /* keep cc happy */
+ }
+ if (v < 0) {
+ ud_asmprintf(u, "-0x%" FMT64 "x", -v);
+ } else if (v > 0) {
+ ud_asmprintf(u, "%s0x%" FMT64 "x", sign? "+" : "", v);
+ }
+ }
+}
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/syn.h b/src/3p/udis86/syn.h
new file mode 100644
index 0000000..d3b1e3f
--- /dev/null
+++ b/src/3p/udis86/syn.h
@@ -0,0 +1,53 @@
+/* udis86 - libudis86/syn.h
+ *
+ * Copyright (c) 2002-2009
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_SYN_H
+#define UD_SYN_H
+
+#include "types.h"
+#ifndef __UD_STANDALONE__
+# include <stdarg.h>
+#endif /* __UD_STANDALONE__ */
+
+extern const char* ud_reg_tab[];
+
+uint64_t ud_syn_rel_target(struct ud*, struct ud_operand*);
+
+#ifdef __GNUC__
+int ud_asmprintf(struct ud *u, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
+#else
+int ud_asmprintf(struct ud *u, const char *fmt, ...);
+#endif
+
+void ud_syn_print_addr(struct ud *u, uint64_t addr);
+void ud_syn_print_imm(struct ud* u, const struct ud_operand *op);
+void ud_syn_print_mem_disp(struct ud* u, const struct ud_operand *, int sign);
+
+#endif /* UD_SYN_H */
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/types.h b/src/3p/udis86/types.h
new file mode 100644
index 0000000..69072ca
--- /dev/null
+++ b/src/3p/udis86/types.h
@@ -0,0 +1,260 @@
+/* udis86 - libudis86/types.h
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef UD_TYPES_H
+#define UD_TYPES_H
+
+#ifdef __KERNEL__
+ /*
+ * -D__KERNEL__ is automatically passed on the command line when
+ * building something as part of the Linux kernel. Assume standalone
+ * mode.
+ */
+# include <linux/kernel.h>
+# include <linux/string.h>
+# ifndef __UD_STANDALONE__
+# define __UD_STANDALONE__ 1
+# endif
+#endif /* __KERNEL__ */
+
+#if !defined(__UD_STANDALONE__)
+# include <stdint.h>
+# include <stdio.h>
+#endif
+
+/* gcc specific extensions */
+#ifdef __GNUC__
+# define UD_ATTR_PACKED __attribute__((packed))
+#else
+# define UD_ATTR_PACKED
+#endif /* UD_ATTR_PACKED */
+
+
+/* -----------------------------------------------------------------------------
+ * All possible "types" of objects in udis86. Order is Important!
+ * -----------------------------------------------------------------------------
+ */
+enum ud_type
+{
+ UD_NONE,
+
+ /* 8 bit GPRs */
+ UD_R_AL, UD_R_CL, UD_R_DL, UD_R_BL,
+ UD_R_AH, UD_R_CH, UD_R_DH, UD_R_BH,
+ UD_R_SPL, UD_R_BPL, UD_R_SIL, UD_R_DIL,
+ UD_R_R8B, UD_R_R9B, UD_R_R10B, UD_R_R11B,
+ UD_R_R12B, UD_R_R13B, UD_R_R14B, UD_R_R15B,
+
+ /* 16 bit GPRs */
+ UD_R_AX, UD_R_CX, UD_R_DX, UD_R_BX,
+ UD_R_SP, UD_R_BP, UD_R_SI, UD_R_DI,
+ UD_R_R8W, UD_R_R9W, UD_R_R10W, UD_R_R11W,
+ UD_R_R12W, UD_R_R13W, UD_R_R14W, UD_R_R15W,
+
+ /* 32 bit GPRs */
+ UD_R_EAX, UD_R_ECX, UD_R_EDX, UD_R_EBX,
+ UD_R_ESP, UD_R_EBP, UD_R_ESI, UD_R_EDI,
+ UD_R_R8D, UD_R_R9D, UD_R_R10D, UD_R_R11D,
+ UD_R_R12D, UD_R_R13D, UD_R_R14D, UD_R_R15D,
+
+ /* 64 bit GPRs */
+ UD_R_RAX, UD_R_RCX, UD_R_RDX, UD_R_RBX,
+ UD_R_RSP, UD_R_RBP, UD_R_RSI, UD_R_RDI,
+ UD_R_R8, UD_R_R9, UD_R_R10, UD_R_R11,
+ UD_R_R12, UD_R_R13, UD_R_R14, UD_R_R15,
+
+ /* segment registers */
+ UD_R_ES, UD_R_CS, UD_R_SS, UD_R_DS,
+ UD_R_FS, UD_R_GS,
+
+ /* control registers*/
+ UD_R_CR0, UD_R_CR1, UD_R_CR2, UD_R_CR3,
+ UD_R_CR4, UD_R_CR5, UD_R_CR6, UD_R_CR7,
+ UD_R_CR8, UD_R_CR9, UD_R_CR10, UD_R_CR11,
+ UD_R_CR12, UD_R_CR13, UD_R_CR14, UD_R_CR15,
+
+ /* debug registers */
+ UD_R_DR0, UD_R_DR1, UD_R_DR2, UD_R_DR3,
+ UD_R_DR4, UD_R_DR5, UD_R_DR6, UD_R_DR7,
+ UD_R_DR8, UD_R_DR9, UD_R_DR10, UD_R_DR11,
+ UD_R_DR12, UD_R_DR13, UD_R_DR14, UD_R_DR15,
+
+ /* mmx registers */
+ UD_R_MM0, UD_R_MM1, UD_R_MM2, UD_R_MM3,
+ UD_R_MM4, UD_R_MM5, UD_R_MM6, UD_R_MM7,
+
+ /* x87 registers */
+ UD_R_ST0, UD_R_ST1, UD_R_ST2, UD_R_ST3,
+ UD_R_ST4, UD_R_ST5, UD_R_ST6, UD_R_ST7,
+
+ /* extended multimedia registers */
+ UD_R_XMM0, UD_R_XMM1, UD_R_XMM2, UD_R_XMM3,
+ UD_R_XMM4, UD_R_XMM5, UD_R_XMM6, UD_R_XMM7,
+ UD_R_XMM8, UD_R_XMM9, UD_R_XMM10, UD_R_XMM11,
+ UD_R_XMM12, UD_R_XMM13, UD_R_XMM14, UD_R_XMM15,
+
+ /* 256B multimedia registers */
+ UD_R_YMM0, UD_R_YMM1, UD_R_YMM2, UD_R_YMM3,
+ UD_R_YMM4, UD_R_YMM5, UD_R_YMM6, UD_R_YMM7,
+ UD_R_YMM8, UD_R_YMM9, UD_R_YMM10, UD_R_YMM11,
+ UD_R_YMM12, UD_R_YMM13, UD_R_YMM14, UD_R_YMM15,
+
+ UD_R_RIP,
+
+ /* Operand Types */
+ UD_OP_REG, UD_OP_MEM, UD_OP_PTR, UD_OP_IMM,
+ UD_OP_JIMM, UD_OP_CONST
+};
+
+#include "itab.h"
+
+union ud_lval {
+ int8_t sbyte;
+ uint8_t ubyte;
+ int16_t sword;
+ uint16_t uword;
+ int32_t sdword;
+ uint32_t udword;
+ int64_t sqword;
+ uint64_t uqword;
+ struct {
+ uint16_t seg;
+ uint32_t off;
+ } ptr;
+};
+
+/* -----------------------------------------------------------------------------
+ * struct ud_operand - Disassembled instruction Operand.
+ * -----------------------------------------------------------------------------
+ */
+struct ud_operand {
+ enum ud_type type;
+ uint16_t size;
+ enum ud_type base;
+ enum ud_type index;
+ uint8_t scale;
+ uint8_t offset;
+ union ud_lval lval;
+ /*
+ * internal use only
+ */
+ uint64_t _legacy; /* this will be removed in 1.8 */
+ uint8_t _oprcode;
+};
+
+/* -----------------------------------------------------------------------------
+ * struct ud - The udis86 object.
+ * -----------------------------------------------------------------------------
+ */
+struct ud
+{
+ /*
+ * input buffering
+ */
+ int (*inp_hook) (struct ud*);
+#ifndef __UD_STANDALONE__
+ FILE* inp_file;
+#endif
+ const uint8_t* inp_buf;
+ size_t inp_buf_size;
+ size_t inp_buf_index;
+ uint8_t inp_curr;
+ size_t inp_ctr;
+ uint8_t inp_sess[64];
+ int inp_end;
+ int inp_peek;
+
+ void (*translator)(struct ud*);
+ uint64_t insn_offset;
+ char insn_hexcode[64];
+
+ /*
+ * Assembly output buffer
+ */
+ char *asm_buf;
+ size_t asm_buf_size;
+ size_t asm_buf_fill;
+ char asm_buf_int[128];
+
+ /*
+ * Symbol resolver for use in the translation phase.
+ */
+ const char* (*sym_resolver)(struct ud*, uint64_t addr, int64_t *offset);
+
+ uint8_t dis_mode;
+ uint64_t pc;
+ uint8_t vendor;
+ enum ud_mnemonic_code mnemonic;
+ struct ud_operand operand[4];
+ uint8_t error;
+ uint8_t _rex;
+ uint8_t pfx_rex;
+ uint8_t pfx_seg;
+ uint8_t pfx_opr;
+ uint8_t pfx_adr;
+ uint8_t pfx_lock;
+ uint8_t pfx_str;
+ uint8_t pfx_rep;
+ uint8_t pfx_repe;
+ uint8_t pfx_repne;
+ uint8_t opr_mode;
+ uint8_t adr_mode;
+ uint8_t br_far;
+ uint8_t br_near;
+ uint8_t have_modrm;
+ uint8_t modrm;
+ uint8_t modrm_offset;
+ uint8_t vex_op;
+ uint8_t vex_b1;
+ uint8_t vex_b2;
+ uint8_t primary_opcode;
+ void * user_opaque_data;
+ struct ud_itab_entry * itab_entry;
+ struct ud_lookup_table_list_entry *le;
+};
+
+/* -----------------------------------------------------------------------------
+ * Type-definitions
+ * -----------------------------------------------------------------------------
+ */
+typedef enum ud_type ud_type_t;
+typedef enum ud_mnemonic_code ud_mnemonic_code_t;
+
+typedef struct ud ud_t;
+typedef struct ud_operand ud_operand_t;
+
+#define UD_SYN_INTEL ud_translate_intel
+#define UD_SYN_ATT ud_translate_att
+#define UD_EOI (-1)
+#define UD_INP_CACHE_SZ 32
+#define UD_VENDOR_AMD 0
+#define UD_VENDOR_INTEL 1
+#define UD_VENDOR_ANY 2
+
+#endif
+
+/*
+vim: set ts=2 sw=2 expandtab
+*/
diff --git a/src/3p/udis86/udint.h b/src/3p/udis86/udint.h
new file mode 100644
index 0000000..2d6d3cb
--- /dev/null
+++ b/src/3p/udis86/udint.h
@@ -0,0 +1,95 @@
+/* udis86 - libudis86/udint.h -- definitions for internal use only
+ *
+ * Copyright (c) 2002-2009 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _UDINT_H_
+#define _UDINT_H_
+
+#include "types.h"
+
+#if defined(UD_DEBUG)
+# include <assert.h>
+# define UD_ASSERT(_x) assert(_x)
+#else
+# define UD_ASSERT(_x)
+#endif
+
+#if defined(UD_DEBUG)
+ #define UDERR(u, msg) \
+ do { \
+ (u)->error = 1; \
+ fprintf(stderr, "decode-error: %s:%d: %s", \
+ __FILE__, __LINE__, (msg)); \
+ } while (0)
+#else
+ #define UDERR(u, m) \
+ do { \
+ (u)->error = 1; \
+ } while (0)
+#endif /* !LOGERR */
+
+#define UD_RETURN_ON_ERROR(u) \
+ do { \
+ if ((u)->error != 0) { \
+ return (u)->error; \
+ } \
+ } while (0)
+
+#define UD_RETURN_WITH_ERROR(u, m) \
+ do { \
+ UDERR(u, m); \
+ return (u)->error; \
+ } while (0)
+
+#ifndef __UD_STANDALONE__
+# define UD_NON_STANDALONE(x) x
+#else
+# define UD_NON_STANDALONE(x)
+#endif
+
+/* printf formatting int64 specifier */
+#ifdef FMT64
+# undef FMT64
+#endif
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define FMT64 "I64"
+#else
+# if defined(__APPLE__)
+# define FMT64 "ll"
+# elif defined(__amd64__) || defined(__x86_64__)
+# define FMT64 "l"
+# else
+# define FMT64 "ll"
+# endif /* !x64 */
+#endif
+
+/* define an inline macro */
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+# define UD_INLINE __inline /* MS Visual Studio requires __inline
+ instead of inline for C code */
+#else
+# define UD_INLINE inline
+#endif
+
+#endif /* _UDINT_H_ */
diff --git a/src/3p/udis86/udis86.c b/src/3p/udis86/udis86.c
new file mode 100644
index 0000000..ee37a49
--- /dev/null
+++ b/src/3p/udis86/udis86.c
@@ -0,0 +1,456 @@
+/* udis86 - libudis86/udis86.c
+ *
+ * Copyright (c) 2002-2013 Vivek Thampi
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification,
+ * are permitted provided that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
+ * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "udint.h"
+#include "extern.h"
+#include "decode.h"
+
+#if !defined(__UD_STANDALONE__)
+# include <string.h>
+#endif /* !__UD_STANDALONE__ */
+
+static void ud_inp_init(struct ud *u);
+
+/* =============================================================================
+ * ud_init
+ * Initializes ud_t object.
+ * =============================================================================
+ */
+extern void
+ud_init(struct ud* u)
+{
+ memset((void*)u, 0, sizeof(struct ud));
+ ud_set_mode(u, 16);
+ u->mnemonic = UD_Iinvalid;
+ ud_set_pc(u, 0);
+#ifndef __UD_STANDALONE__
+ ud_set_input_file(u, stdin);
+#endif /* __UD_STANDALONE__ */
+
+ ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
+}
+
+
+/* =============================================================================
+ * ud_disassemble
+ * Disassembles one instruction and returns the number of
+ * bytes disassembled. A zero means end of disassembly.
+ * =============================================================================
+ */
+extern unsigned int
+ud_disassemble(struct ud* u)
+{
+ int len;
+ if (u->inp_end) {
+ return 0;
+ }
+ if ((len = ud_decode(u)) > 0) {
+ if (u->translator != NULL) {
+ u->asm_buf[0] = '\0';
+ u->translator(u);
+ }
+ }
+ return len;
+}
+
+
+/* =============================================================================
+ * ud_set_mode() - Set Disassemly Mode.
+ * =============================================================================
+ */
+extern void
+ud_set_mode(struct ud* u, uint8_t m)
+{
+ switch(m) {
+ case 16:
+ case 32:
+ case 64: u->dis_mode = m ; return;
+ default: u->dis_mode = 16; return;
+ }
+}
+
+/* =============================================================================
+ * ud_set_vendor() - Set vendor.
+ * =============================================================================
+ */
+extern void
+ud_set_vendor(struct ud* u, unsigned v)
+{
+ switch(v) {
+ case UD_VENDOR_INTEL:
+ u->vendor = v;
+ break;
+ case UD_VENDOR_ANY:
+ u->vendor = v;
+ break;
+ default:
+ u->vendor = UD_VENDOR_AMD;
+ }
+}
+
+/* =============================================================================
+ * ud_set_pc() - Sets code origin.
+ * =============================================================================
+ */
+extern void
+ud_set_pc(struct ud* u, uint64_t o)
+{
+ u->pc = o;
+}
+
+/* =============================================================================
+ * ud_set_syntax() - Sets the output syntax.
+ * =============================================================================
+ */
+extern void
+ud_set_syntax(struct ud* u, void (*t)(struct ud*))
+{
+ u->translator = t;
+}
+
+/* =============================================================================
+ * ud_insn() - returns the disassembled instruction
+ * =============================================================================
+ */
+const char*
+ud_insn_asm(const struct ud* u)
+{
+ return u->asm_buf;
+}
+
+/* =============================================================================
+ * ud_insn_offset() - Returns the offset.
+ * =============================================================================
+ */
+uint64_t
+ud_insn_off(const struct ud* u)
+{
+ return u->insn_offset;
+}
+
+
+/* =============================================================================
+ * ud_insn_hex() - Returns hex form of disassembled instruction.
+ * =============================================================================
+ */
+const char*
+ud_insn_hex(struct ud* u)
+{
+ u->insn_hexcode[0] = 0;
+ if (!u->error) {
+ unsigned int i;
+ const unsigned char *src_ptr = ud_insn_ptr(u);
+ char* src_hex;
+ src_hex = (char*) u->insn_hexcode;
+ /* for each byte used to decode instruction */
+ for (i = 0; i < ud_insn_len(u) && i < sizeof(u->insn_hexcode) / 2;
+ ++i, ++src_ptr) {
+ sprintf(src_hex, "%02x", *src_ptr & 0xFF);
+ src_hex += 2;
+ }
+ }
+ return u->insn_hexcode;
+}
+
+
+/* =============================================================================
+ * ud_insn_ptr
+ * Returns a pointer to buffer containing the bytes that were
+ * disassembled.
+ * =============================================================================
+ */
+extern const uint8_t*
+ud_insn_ptr(const struct ud* u)
+{
+ return (u->inp_buf == NULL) ?
+ u->inp_sess : u->inp_buf + (u->inp_buf_index - u->inp_ctr);
+}
+
+
+/* =============================================================================
+ * ud_insn_len
+ * Returns the count of bytes disassembled.
+ * =============================================================================
+ */
+extern unsigned int
+ud_insn_len(const struct ud* u)
+{
+ return u->inp_ctr;
+}
+
+
+/* =============================================================================
+ * ud_insn_get_opr
+ * Return the operand struct representing the nth operand of
+ * the currently disassembled instruction. Returns NULL if
+ * there's no such operand.
+ * =============================================================================
+ */
+const struct ud_operand*
+ud_insn_opr(const struct ud *u, unsigned int n)
+{
+ if (n > 3 || u->operand[n].type == UD_NONE) {
+ return NULL;
+ } else {
+ return &u->operand[n];
+ }
+}
+
+
+/* =============================================================================
+ * ud_opr_is_sreg
+ * Returns non-zero if the given operand is of a segment register type.
+ * =============================================================================
+ */
+int
+ud_opr_is_sreg(const struct ud_operand *opr)
+{
+ return opr->type == UD_OP_REG &&
+ opr->base >= UD_R_ES &&
+ opr->base <= UD_R_GS;
+}
+
+
+/* =============================================================================
+ * ud_opr_is_sreg
+ * Returns non-zero if the given operand is of a general purpose
+ * register type.
+ * =============================================================================
+ */
+int
+ud_opr_is_gpr(const struct ud_operand *opr)
+{
+ return opr->type == UD_OP_REG &&
+ opr->base >= UD_R_AL &&
+ opr->base <= UD_R_R15;
+}
+
+
+/* =============================================================================
+ * ud_set_user_opaque_data
+ * ud_get_user_opaque_data
+ * Get/set user opaqute data pointer
+ * =============================================================================
+ */
+void
+ud_set_user_opaque_data(struct ud * u, void* opaque)
+{
+ u->user_opaque_data = opaque;
+}
+
+void*
+ud_get_user_opaque_data(const struct ud *u)
+{
+ return u->user_opaque_data;
+}
+
+
+/* =============================================================================
+ * ud_set_asm_buffer
+ * Allow the user to set an assembler output buffer. If `buf` is NULL,
+ * we switch back to the internal buffer.
+ * =============================================================================
+ */
+void
+ud_set_asm_buffer(struct ud *u, char *buf, size_t size)
+{
+ if (buf == NULL) {
+ ud_set_asm_buffer(u, u->asm_buf_int, sizeof(u->asm_buf_int));
+ } else {
+ u->asm_buf = buf;
+ u->asm_buf_size = size;
+ }
+}
+
+
+/* =============================================================================
+ * ud_set_sym_resolver
+ * Set symbol resolver for relative targets used in the translation
+ * phase.
+ *
+ * The resolver is a function that takes a uint64_t address and returns a
+ * symbolic name for the that address. The function also takes a second
+ * argument pointing to an integer that the client can optionally set to a
+ * non-zero value for offsetted targets. (symbol+offset) The function may
+ * also return NULL, in which case the translator only prints the target
+ * address.
+ *
+ * The function pointer maybe NULL which resets symbol resolution.
+ * =============================================================================
+ */
+void
+ud_set_sym_resolver(struct ud *u, const char* (*resolver)(struct ud*,
+ uint64_t addr,
+ int64_t *offset))
+{
+ u->sym_resolver = resolver;
+}
+
+
+/* =============================================================================
+ * ud_insn_mnemonic
+ * Return the current instruction mnemonic.
+ * =============================================================================
+ */
+enum ud_mnemonic_code
+ud_insn_mnemonic(const struct ud *u)
+{
+ return u->mnemonic;
+}
+
+
+/* =============================================================================
+ * ud_lookup_mnemonic
+ * Looks up mnemonic code in the mnemonic string table.
+ * Returns NULL if the mnemonic code is invalid.
+ * =============================================================================
+ */
+const char*
+ud_lookup_mnemonic(enum ud_mnemonic_code c)
+{
+ if (c < UD_MAX_MNEMONIC_CODE) {
+ return ud_mnemonics_str[c];
+ } else {
+ return NULL;
+ }
+}
+
+
+/*
+ * ud_inp_init
+ * Initializes the input system.
+ */
+static void
+ud_inp_init(struct ud *u)
+{
+ u->inp_hook = NULL;
+ u->inp_buf = NULL;
+ u->inp_buf_size = 0;
+ u->inp_buf_index = 0;
+ u->inp_curr = 0;
+ u->inp_ctr = 0;
+ u->inp_end = 0;
+ u->inp_peek = UD_EOI;
+ UD_NON_STANDALONE(u->inp_file = NULL);
+}
+
+
+/* =============================================================================
+ * ud_inp_set_hook
+ * Sets input hook.
+ * =============================================================================
+ */
+void
+ud_set_input_hook(register struct ud* u, int (*hook)(struct ud*))
+{
+ ud_inp_init(u);
+ u->inp_hook = hook;
+}
+
+/* =============================================================================
+ * ud_inp_set_buffer
+ * Set buffer as input.
+ * =============================================================================
+ */
+void
+ud_set_input_buffer(register struct ud* u, const uint8_t* buf, size_t len)
+{
+ ud_inp_init(u);
+ u->inp_buf = buf;
+ u->inp_buf_size = len;
+ u->inp_buf_index = 0;
+}
+
+
+#ifndef __UD_STANDALONE__
+/* =============================================================================
+ * ud_input_set_file
+ * Set FILE as input.
+ * =============================================================================
+ */
+static int
+inp_file_hook(struct ud* u)
+{
+ return fgetc(u->inp_file);
+}
+
+void
+ud_set_input_file(register struct ud* u, FILE* f)
+{
+ ud_inp_init(u);
+ u->inp_hook = inp_file_hook;
+ u->inp_file = f;
+}
+#endif /* __UD_STANDALONE__ */
+
+
+/* =============================================================================
+ * ud_input_skip
+ * Skip n input bytes.
+ * ============================================================================
+ */
+void
+ud_input_skip(struct ud* u, size_t n)
+{
+ if (u->inp_end) {
+ return;
+ }
+ if (u->inp_buf == NULL) {
+ while (n--) {
+ int c = u->inp_hook(u);
+ if (c == UD_EOI) {
+ goto eoi;
+ }
+ }
+ return;
+ } else {
+ if (n > u->inp_buf_size ||
+ u->inp_buf_index > u->inp_buf_size - n) {
+ u->inp_buf_index = u->inp_buf_size;
+ goto eoi;
+ }
+ u->inp_buf_index += n;
+ return;
+ }
+eoi:
+ u->inp_end = 1;
+ UDERR(u, "cannot skip, eoi received\b");
+ return;
+}
+
+
+/* =============================================================================
+ * ud_input_end
+ * Returns non-zero on end-of-input.
+ * =============================================================================
+ */
+int
+ud_input_end(const struct ud *u)
+{
+ return u->inp_end;
+}
+
+/* vim:set ts=2 sw=2 expandtab */
diff --git a/src/abi.h b/src/abi.h
new file mode 100644
index 0000000..54c504a
--- /dev/null
+++ b/src/abi.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_ABI_H
+#define INC_ABI_H
+
+#include "intdefs.h"
+
+/*
+ * This file defines miscellaneous C++ ABI stuff. Looking at it may cause
+ * brain damage and/or emotional trauma.
+ */
+
+#ifdef _WIN32 // Windows RTTI stuff, obviously only used on Windows.
+
+// MSVC RTTI is quite a black box, but thankfully there's some useful sources:
+// - https://doxygen.reactos.org/d0/dcf/cxx_8h_source.html
+// - https://blog.quarkslab.com/visual-c-rtti-inspection.html
+// - https://www.geoffchappell.com/studies/msvc/language/predefined/
+// - https://docs.rs/pelite/0.5.0/src/pelite/pe32/msvc.rs.html
+
+// By the way, while I'm here I'd just like to point out how ridiculous this
+// layout is. Whoever decided to put this many levels of indirection over what
+// should be a small lookup table is an absolute nutcase. I hope that individual
+// has gotten some help by now, mostly for the sake of others.
+
+struct msvc_rtti_descriptor {
+ void *vtab;
+ void *unknown; // ???
+ // XXX: pretty sure this is supposed to be flexible, but too lazy to write
+ // the stupid union init macros to make that fully portable
+ char classname[80];
+};
+
+// "pointer to member displacement"
+struct msvc_pmd { int mdisp, pdisp, vdisp; };
+
+struct msvc_basedesc {
+ struct msvc_rtti_descriptor *desc;
+ uint nbases;
+ struct msvc_pmd where;
+ uint attr;
+};
+
+struct msvc_rtti_hierarchy {
+ uint sig;
+ uint attrs;
+ uint nbaseclasses;
+ struct msvc_basedesc **baseclasses;
+};
+
+struct msvc_rtti_locator {
+ uint sig;
+ int baseoff;
+ // ctor offset, or some flags; reactos and rust pelite say different things?
+ int unknown;
+ struct msvc_rtti_descriptor *desc;
+ struct msvc_rtti_hierarchy *hier;
+};
+
+// I mean seriously look at this crap!
+#define DEF_MSVC_BASIC_RTTI(mod, name, vtab, typestr) \
+mod struct msvc_rtti_locator name; \
+static struct msvc_rtti_descriptor _desc_##name = {(vtab) + 1, 0, typestr}; \
+static struct msvc_basedesc _basedesc_##name = {&_desc_##name, 0, {0, 0, 0}, 0}; \
+mod struct msvc_rtti_locator name = { \
+ 0, 0, 0, \
+ &_desc_##name, \
+ &(struct msvc_rtti_hierarchy){ \
+ 0, 1 /* per engine */, 1, (struct msvc_basedesc *[]){&_basedesc_##name} \
+ } \
+};
+
+#endif
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/bitbuf.h b/src/bitbuf.h
new file mode 100644
index 0000000..8ce5535
--- /dev/null
+++ b/src/bitbuf.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_BITBUF_H
+#define INC_BITBUF_H
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+
+// NOTE: This code assumes it's running on a little endian machine, because,
+// well, the game runs on a little endian machine.
+// *technically* this could break unit tests in a contrived cross-compile
+// scenario? right now none of the tests care about actual bit values, and we
+// don't cross compile, so this won't matter till later. :)
+
+// handle 8 bytes at a time (COULD do 16 with SSE, but who cares this is fine)
+typedef uvlong bitbuf_cell;
+static const int bitbuf_cell_bits = sizeof(bitbuf_cell) * 8;
+static const int bitbuf_align = _Alignof(bitbuf_cell);
+
+/* A bit buffer, ABI-compatible with bf_write defined in tier1/bitbuf.h */
+struct bitbuf {
+ union {
+ char *buf; /* NOTE: the buffer MUST be aligned as bitbuf_cell! */
+ bitbuf_cell *buf_as_cells;
+ };
+ int sz, nbits, curbit;
+ bool overflow, assert_on_overflow;
+ const char *debugname;
+};
+
+/* Append a value to the bitbuffer, with a specfied length in bits. */
+static inline void bitbuf_appendbits(struct bitbuf *bb, bitbuf_cell x,
+ int nbits) {
+ int idx = bb->curbit / bitbuf_cell_bits;
+ int shift = bb->curbit % bitbuf_cell_bits;
+ // OR into the existing cell (lower bits were already set!)
+ bb->buf_as_cells[idx] |= x << shift;
+ // assign the next cell (that also clears the upper bits for the next OR)
+ // note: if nbits fits in the first cell, this just 0s the next cell, which
+ // is absolutely fine
+ bb->buf_as_cells[idx + 1] = x >> (bitbuf_cell_bits - shift);
+ bb->curbit += nbits;
+}
+
+/* Append a byte to the bitbuffer - same as appendbits(8) but more convenient */
+static inline void bitbuf_appendbyte(struct bitbuf *bb, uchar x) {
+ bitbuf_appendbits(bb, x, 8);
+}
+
+/* Append a sequence of bytes to the bitbuffer, with length given in bytes */
+static inline void bitbuf_appendbuf(struct bitbuf *bb, const char *buf,
+ uint len) {
+ // NOTE! This function takes advantage of the fact that nothing unaligned
+ // is page aligned, so accessing slightly outside the bounds of buf can't
+ // segfault. This is absolutely definitely technically UB, but it's unit
+ // tested and apparently works in practice. If something weird happens
+ // further down the line, sorry!
+ usize unalign = (usize)buf % bitbuf_align;
+ if (unalign) {
+ // round down the pointer
+ bitbuf_cell *p = (bitbuf_cell *)((usize)buf & ~(bitbuf_align - 1));
+ // shift the stored value (if it were big endian, the shift would have
+ // to be the other way, or something)
+ bitbuf_appendbits(bb, *p >> (unalign * 8), (bitbuf_align - unalign) * 8);
+ buf += sizeof(bitbuf_cell) - unalign;
+ len -= unalign;
+ }
+ bitbuf_cell *aligned = (bitbuf_cell *)buf;
+ for (; len > sizeof(bitbuf_cell); len -= sizeof(bitbuf_cell), ++aligned) {
+ bitbuf_appendbits(bb, *aligned, bitbuf_cell_bits);
+ }
+ // unaligned end bytes
+ bitbuf_appendbits(bb, *aligned, len * 8);
+}
+
+/* Clear the bitbuffer to make it ready to append new data */
+static inline void bitbuf_reset(struct bitbuf *bb) {
+ bb->buf[0] = 0; // we have to zero out the lowest cell since it gets ORed
+ bb->curbit = 0;
+}
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/build/cmeta.c b/src/build/cmeta.c
new file mode 100644
index 0000000..b895253
--- /dev/null
+++ b/src/build/cmeta.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../intdefs.h"
+#include "../os.h"
+
+/*
+ * This file does C metadata parsing/scraping for the build system. This
+ * facilitates tasks ranging from determining header dependencies to searching
+ * for certain magic macros (for example cvar/command declarations) to generate
+ * other code.
+ *
+ * It's a bit of a mess since it's kind of just hacked together for use at build
+ * time. Don't worry about it too much.
+ */
+
+// too lazy to write a C tokenizer at the moment, so let's just yoink some code
+// from a hacked-up copy of chibicc, a nice minimal C compiler with code that's
+// pretty easy to work with. it does leak memory by design, but build stuff is
+// all one-shot so that's fine.
+#include "../3p/chibicc/unicode.c"
+// type sentinels from type.c (don't bring in the rest of type.c because it
+// circularly depends on other stuff and we really only want tokenize here)
+Type *ty_void = &(Type){TY_VOID, 1, 1};
+Type *ty_bool = &(Type){TY_BOOL, 1, 1};
+Type *ty_char = &(Type){TY_CHAR, 1, 1};
+Type *ty_short = &(Type){TY_SHORT, 2, 2};
+Type *ty_int = &(Type){TY_INT, 4, 4};
+Type *ty_long = &(Type){TY_LONG, 8, 8};
+Type *ty_uchar = &(Type){TY_CHAR, 1, 1, true};
+Type *ty_ushort = &(Type){TY_SHORT, 2, 2, true};
+Type *ty_uint = &(Type){TY_INT, 4, 4, true};
+Type *ty_ulong = &(Type){TY_LONG, 8, 8, true};
+Type *ty_float = &(Type){TY_FLOAT, 4, 4};
+Type *ty_double = &(Type){TY_DOUBLE, 8, 8};
+Type *ty_ldouble = &(Type){TY_LDOUBLE, 16, 16};
+// inline just a couple more things, super lazy, but whatever
+static Type *new_type(TypeKind kind, int size, int align) {
+ Type *ty = calloc(1, sizeof(Type));
+ ty->kind = kind;
+ ty->size = size;
+ ty->align = align;
+ return ty;
+}
+Type *array_of(Type *base, int len) {
+ Type *ty = new_type(TY_ARRAY, base->size * len, base->align);
+ ty->base = base;
+ ty->array_len = len;
+ return ty;
+}
+#include "../3p/chibicc/hashmap.c"
+#include "../3p/chibicc/strings.c"
+#include "../3p/chibicc/tokenize.c"
+// one more copypaste from preprocess.c for #include <filename> and then I'm
+// done I promise
+static char *join_tokens(Token *tok, Token *end) {
+ int len = 1;
+ for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ if (t != tok && t->has_space)
+ len++;
+ len += t->len;
+ }
+ char *buf = calloc(1, len);
+ int pos = 0;
+ for (Token *t = tok; t != end && t->kind != TK_EOF; t = t->next) {
+ if (t != tok && t->has_space)
+ buf[pos++] = ' ';
+ strncpy(buf + pos, t->loc, t->len);
+ pos += t->len;
+ }
+ buf[pos] = '\0';
+ return buf;
+}
+
+#ifdef _WIN32
+#include "../3p/openbsd/asprintf.c" // missing from libc; plonked here for now
+#endif
+
+static void die1(const char *s) {
+ fprintf(stderr, "cmeta: fatal: %s\n", s);
+ exit(100);
+}
+
+static char *readsource(const os_char *f) {
+ int fd = os_open(f, O_RDONLY);
+#ifndef _WIN32
+ if (fd == -1) die2("couldn't open ", f);
+#else
+ // TODO/FIXME/TEMP this is dumb and bad
+ if (fd == -1) { fprintf(stderr, "couldn't open %S", f); exit(100); }
+#endif
+ uint bufsz = 8192;
+ char *buf = malloc(bufsz);
+ if (!buf) die1("couldn't allocate memory");
+ int nread;
+ int off = 0;
+ while ((nread = read(fd, buf + off, bufsz - off)) > 0) {
+ off += nread;
+ if (off == bufsz) {
+ bufsz *= 2;
+ // somewhat arbitrary cutoff
+ if (bufsz == 1 << 30) die1("input file is too large");
+ buf = realloc(buf, bufsz);
+ if (!buf) die1("couldn't reallocate memory");
+ }
+ }
+ if (nread == -1) die1("couldn't read file");
+ buf[off] = 0;
+ close(fd);
+ return buf;
+}
+
+// as per cmeta.h this is totally opaque; it's actually just a Token in disguise
+struct cmeta;
+
+const struct cmeta *cmeta_loadfile(const os_char *f) {
+ char *buf = readsource(f);
+#ifdef _WIN32
+ char *realname = malloc(wcslen(f) + 1);
+ if (!realname) die1("couldn't allocate memory");
+ // XXX: being lazy about Unicode right now; a general purpose tool should
+ // implement WTF8 or something. SST itself doesn't have any unicode paths
+ // though, so don't really care as much.
+ *realname = *f;
+ for (const ushort *p = f + 1; p[-1]; ++p) realname[p - f] = *p;
+#else
+ const char *realname = f;
+#endif
+ return (const struct cmeta *)tokenize_buf(realname, buf);
+}
+
+// NOTE: we don't care about conditional includes, nor do we expand macros. We
+// just parse the minimum info to get what we need for SST. Also, there's not
+// too much in the way of syntax checking; if an error gets ignored the compiler
+// picks it anyway, and gives far better diagnostics.
+void cmeta_includes(const struct cmeta *cm,
+ void (*cb)(const char *f, bool issys, void *ctxt), void *ctxt) {
+ Token *tp = (Token *)cm;
+ if (!tp || !tp->next || !tp->next->next) return; // #, include, "string"
+ while (tp) {
+ if (!tp->at_bol || !equal(tp, "#")) { tp = tp->next; continue; }
+ if (!equal(tp->next, "include")) { tp = tp->next->next; continue; }
+ tp = tp->next->next;
+ if (!tp) break;
+ if (tp->at_bol) tp = tp->next;
+ if (!tp) break;
+ if (tp->kind == TK_STR) {
+ // include strings are a special case; they don't have \escapes.
+ char *copy = malloc(tp->len - 1);
+ if (!copy) die1("couldn't allocate memory");
+ memcpy(copy, tp->loc + 1, tp->len - 2);
+ copy[tp->len - 2] = '\0';
+ cb(copy, false, ctxt);
+ //free(copy); // ??????
+ }
+ else if (equal(tp, "<")) {
+ tp = tp->next;
+ if (!tp) break;
+ Token *end = tp;
+ while (!equal(end, ">")) {
+ end = end->next;
+ if (!end) return; // shouldn't happen in valid source obviously
+ if (end->at_bol) break; // ??????
+ }
+ char *joined = join_tokens(tp, end); // just use func from chibicc
+ cb(joined, true, ctxt);
+ //free(joined); // ??????
+ }
+ // get to the next line (standard allows extra tokens because)
+ while (!tp->at_bol) {
+ tp = tp->next;
+ if (!tp) return;
+ }
+ }
+}
+
+// AGAIN, NOTE: this doesn't *perfectly* match top level decls only in the event
+// that someone writes something weird, but we just don't really care because
+// we're not writing something weird. Don't write something weird!
+void cmeta_conmacros(const struct cmeta *cm, void (*cb)(const char *, bool)) {
+ Token *tp = (Token *)cm;
+ if (!tp || !tp->next || !tp->next->next) return; // DEF_xyz, (, name
+ while (tp) {
+ bool isplusminus = false, isvar = false;
+ if (equal(tp, "DEF_CCMD_PLUSMINUS")) isplusminus = true;
+ else if (equal(tp, "DEF_CVAR") || equal(tp, "DEF_CVAR_MIN") ||
+ equal(tp, "DEF_CVAR_MINMAX")) {
+ isvar = true;
+ }
+ else if (!equal(tp, "DEF_CCMD") && !equal(tp, "DEF_CCMD_HERE")) {
+ tp = tp->next; continue;
+ }
+ if (!equal(tp->next, "(")) { tp = tp->next->next; continue; }
+ tp = tp->next->next;
+ if (isplusminus) {
+ // XXX: this is stupid but whatever
+ char *plusname = malloc(sizeof("PLUS_") + tp->len);
+ if (!plusname) die1("couldn't allocate memory");
+ memcpy(plusname, "PLUS_", 5);
+ memcpy(plusname + sizeof("PLUS_") - 1, tp->loc, tp->len);
+ plusname[sizeof("PLUS_") - 1 + tp->len] = '\0';
+ cb(plusname, false);
+ char *minusname = malloc(sizeof("MINUS_") + tp->len);
+ if (!minusname) die1("couldn't allocate memory");
+ memcpy(minusname, "MINUS_", 5);
+ memcpy(minusname + sizeof("MINUS_") - 1, tp->loc, tp->len);
+ minusname[sizeof("MINUS_") - 1 + tp->len] = '\0';
+ cb(minusname, false);
+ }
+ else {
+ char *name = malloc(tp->len + 1);
+ if (!name) die1("couldn't allocate memory");
+ memcpy(name, tp->loc, tp->len);
+ name[tp->len] = '\0';
+ cb(name, isvar);
+ }
+ tp = tp->next;
+ }
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/build/cmeta.h b/src/build/cmeta.h
new file mode 100644
index 0000000..3319e3a
--- /dev/null
+++ b/src/build/cmeta.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_CMETA_H
+#define INC_CMETA_H
+
+#include <stdbool.h>
+
+#include "../os.h"
+
+struct cmeta;
+
+const struct cmeta *cmeta_loadfile(const os_char *f);
+
+/*
+ * Iterates through all the #include directives in a file, passing each one in
+ * turn to the callback cb.
+ */
+void cmeta_includes(const struct cmeta *cm,
+ void (*cb)(const char *f, bool issys, void *ctxt), void *ctxt);
+
+/*
+ * Iterates through all commands and variables declared using the macros in
+ * con_.h, passing each one in turn to the callback cb.
+ */
+void cmeta_conmacros(const struct cmeta *cm,
+ void (*cb)(const char *name, bool isvar));
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/build/codegen.c b/src/build/codegen.c
new file mode 100644
index 0000000..c9be0ef
--- /dev/null
+++ b/src/build/codegen.c
@@ -0,0 +1,95 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../os.h"
+#include "cmeta.h"
+
+static const char *cmdnames[4096]; // arbitrary limit!
+static int ncmdnames = 0;
+static const char *varnames[4096]; // arbitrary limit!
+static int nvarnames = 0;
+
+static void die(const char *s) {
+ fprintf(stderr, "codegen: %s\n", s);
+ exit(100);
+}
+
+#define PUT(array, ent) do { \
+ if (n##array == sizeof(array) / sizeof(*array)) { \
+ fprintf(stderr, "codegen: out of space; make " #array " bigger!\n"); \
+ exit(1); \
+ } \
+ array[n##array++] = ent; \
+} while (0)
+
+static void oncondef(const char *name, bool isvar) {
+ if (isvar) PUT(varnames, name); else PUT(cmdnames, name);
+}
+
+#define _(x) \
+ if (fprintf(out, "%s\n", x) < 0) die("couldn't write to file");
+#define F(f, ...) \
+ if (fprintf(out, f "\n", __VA_ARGS__) < 0) die("couldn't write to file");
+#define H() \
+_( "/* This file is autogenerated by src/build/codegen.c. DO NOT EDIT! */") \
+_( "")
+
+int OS_MAIN(int argc, os_char *argv[]) {
+ for (++argv; *argv; ++argv) {
+ const struct cmeta *cm = cmeta_loadfile(*argv);
+ cmeta_conmacros(cm, &oncondef);
+ }
+
+ FILE *out = fopen(".build/include/cmdinit.gen.h", "wb");
+ if (!out) die("couldn't open cmdinit.gen.h");
+ H();
+ for (const char *const *pp = cmdnames;
+ pp - cmdnames < ncmdnames; ++pp) {
+F( "extern struct con_cmd *%s;", *pp)
+ }
+ for (const char *const *pp = varnames;
+ pp - varnames < nvarnames; ++pp) {
+F( "extern struct con_var *%s;", *pp)
+ }
+_( "")
+_( "static void regcmds(void (*VCALLCONV f)(void *, void *)) {")
+ for (const char *const *pp = cmdnames;
+ pp - cmdnames < ncmdnames; ++pp) {
+F( " f(_con_iface, %s);", *pp)
+ }
+ for (const char *const *pp = varnames;
+ pp - varnames < nvarnames; ++pp) {
+F( " initval(%s);", *pp)
+F( " f(_con_iface, %s);", *pp)
+ }
+_( "}")
+_( "")
+_( "static void freevars(void) {")
+ for (const char *const *pp = varnames;
+ pp - varnames < nvarnames; ++pp) {
+F( " extfree(%s->strval);", *pp)
+ }
+_( "}")
+ if (fflush(out) == EOF) die("couldn't fully write cmdinit.gen.h");
+
+ return 0;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/build/mkgamedata.c b/src/build/mkgamedata.c
new file mode 100644
index 0000000..87de07d
--- /dev/null
+++ b/src/build/mkgamedata.c
@@ -0,0 +1,238 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../intdefs.h"
+#include "../kv.h"
+#include "../os.h"
+#include "../noreturn.h" // must come after os.h due to __declspec(noreturn)
+
+#ifdef _WIN32
+#define fS "S"
+#else
+#define fS "s"
+#endif
+
+static noreturn die(const char *s) {
+ fprintf(stderr, "mkgamedata: %s\n", s);
+ exit(100);
+}
+
+/*
+ * We keep the gamedata KV format as simple and flat as possible:
+ *
+ * <varname> <expr>
+ * <varname> { <gametype> <expr> <gametype> <expr> ... [default <expr>] }
+ * [however many entries...]
+ *
+ * If that doesn't make sense, just look at one of the existing data files and
+ * then it should be obvious. :^)
+ *
+ * Note: if `default` isn't given in a conditional block, that piece of gamedata
+ * is considered unavailable and modules that use it won't get initialised/used.
+ */
+struct ent {
+ const char *name;
+ // normally I'd be inclined to do some pointer bitpacking meme but that's
+ // annoying and doesn't matter here so here's an bool and 7 bytes of padding
+ bool iscond;
+ union {
+ struct {
+ struct ent_cond {
+ const char *name;
+ // note: can be any old C expression; just plopped in
+ const char *expr;
+ struct ent_cond *next;
+ } *cond;
+ // store user-specified defaults in a special place to make the
+ // actual codegen logic easier
+ const char *defval;
+ };
+ const char *expr;
+ };
+ struct ent *next;
+} *ents_head, **ents_tail = &ents_head;
+
+struct parsestate {
+ const os_char *filename;
+ struct kv_parser *parser;
+ const char *lastkey;
+ struct ent_cond **nextcond;
+ bool incond;
+};
+
+static noreturn badparse(struct parsestate *state, const char *e) {
+ fprintf(stderr, "mkgamedata: %" fS ":%d:%d: parse error: %s",
+ state->filename, state->parser->line, state->parser->col, e);
+ exit(1);
+}
+
+static void kv_cb(enum kv_token type, const char *p, uint len, void *ctxt) {
+ struct parsestate *state = ctxt;
+ switch (type) {
+ case KV_IDENT: case KV_IDENT_QUOTED:
+ char *k = malloc(len + 1);
+ if (!k) die("couldn't allocate key string");
+ memcpy(k, p, len);
+ k[len] = '\0';
+ state->lastkey = k;
+ break;
+ case KV_NEST_START:
+ if (state->incond) badparse(state, "unexpected nested object");
+ state->incond = true;
+ struct ent *e = malloc(sizeof(*e));
+ if (!e) die("couldn't allocate memory");
+ e->name = state->lastkey;
+ e->iscond = true;
+ e->cond = 0;
+ e->defval = 0;
+ state->nextcond = &e->cond;
+ e->next = 0;
+ *ents_tail = e;
+ ents_tail = &e->next;
+ break;
+ case KV_NEST_END:
+ state->incond = false;
+ break;
+ case KV_VAL: case KV_VAL_QUOTED:
+ if (state->incond) {
+ // dumb special case mentioned above
+ if (!strcmp(state->lastkey, "default")) {
+ (*ents_tail)->defval = state->lastkey;
+ break;
+ }
+ struct ent_cond *c = malloc(sizeof(*c));
+ if (!c) die("couldn't allocate memory");
+ c->name = state->lastkey;
+ char *expr = malloc(len + 1);
+ if (!expr) die("couldn't allocate value/expression string");
+ memcpy(expr, p, len);
+ expr[len] = '\0';
+ c->expr = expr;
+ c->next = 0;
+ *(state->nextcond) = c;
+ state->nextcond = &c->next;
+ }
+ else {
+ // also kind of dumb but whatever
+ struct ent *e = malloc(sizeof(*e));
+ if (!e) die("couldn't allocate memory");
+ e->name = state->lastkey;
+ e->iscond = false;
+ char *expr = malloc(len + 1);
+ if (!expr) die("couldn't allocate value/expression string");
+ memcpy(expr, p, len);
+ expr[len] = '\0';
+ e->expr = expr;
+ e->next = 0;
+ *ents_tail = e;
+ ents_tail = &e->next;
+ }
+ }
+}
+
+#define _(x) \
+ if (fprintf(out, "%s\n", x) < 0) die("couldn't write to file");
+#define F(f, ...) \
+ if (fprintf(out, f "\n", __VA_ARGS__) < 0) die("couldn't write to file");
+#define H() \
+_( "/* This file is autogenerated by src/build/mkgamedata.c. DO NOT EDIT! */") \
+_( "")
+
+int OS_MAIN(int argc, os_char *argv[]) {
+ for (++argv; *argv; ++argv) {
+ int fd = os_open(*argv, O_RDONLY);
+ if (fd == -1) die("couldn't open file");
+ struct kv_parser kv = {0};
+ struct parsestate state = {*argv, &kv};
+ char buf[1024];
+ int nread;
+ while (nread = read(fd, buf, sizeof(buf))) {
+ if (nread == -1) die("couldn't read file");
+ kv_parser_feed(&kv, buf, nread, &kv_cb, &state);
+ if (kv.state == KV_PARSER_ERROR) goto ep;
+ }
+ kv_parser_done(&kv);
+ if (kv.state == KV_PARSER_ERROR) {
+ep: fprintf(stderr, "mkgamedata: %" fS ":%d:%d: bad syntax: %s\n",
+ *argv, kv.line, kv.col, kv.errmsg);
+ exit(1);
+ }
+ close(fd);
+ }
+
+ FILE *out = fopen(".build/include/gamedata.gen.h", "wb");
+ if (!out) die("couldn't open gamedata.gen.h");
+ H();
+ for (struct ent *e = ents_head; e; e = e->next) {
+ if (e->iscond) {
+F( "extern int gamedata_%s;", e->name)
+ if (e->defval) {
+F( "#define gamedata_has_%s true", e->name)
+ }
+ else {
+F( "extern bool gamedata_has_%s;", e->name)
+ }
+ }
+ else {
+F( "enum { gamedata_%s = %s };", e->name, e->expr)
+F( "#define gamedata_has_%s true", e->name)
+ }
+ }
+
+ out = fopen(".build/include/gamedatainit.gen.h", "wb");
+ if (!out) die("couldn't open gamedatainit.gen.h");
+ H();
+ for (struct ent *e = ents_head; e; e = e->next) {
+ if (e->iscond) {
+ if (e->defval) {
+F( "int gamedata_%s = %s", e->name, e->defval);
+ }
+ else {
+F( "int gamedata_%s;", e->name);
+F( "bool gamedata_has_%s = false;", e->name);
+ }
+ }
+ }
+_( "")
+_( "void gamedata_init(void) {")
+ for (struct ent *e = ents_head; e; e = e->next) {
+ if (e->iscond) {
+ for (struct ent_cond *c = e->cond; c; c = c->next) {
+ if (!e->defval) {
+ // XXX: not bothering to generate `else`s. technically this
+ // has different semantics; we hope that the compiler can
+ // just do the right thing either way.
+F( " if (GAMETYPE_MATCHES(%s)) {", c->name)
+F( " gamedata_%s = %s;", e->name, c->expr)
+F( " gamedata_has_%s = true;", e->name)
+_( " }")
+ }
+ else {
+F( " if (GAMETYPE_MATCHES(%s)) %s = %s;", c->name, e->name, c->expr)
+ }
+ }
+ }
+ }
+_( "}")
+
+ return 0;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/con_.c b/src/con_.c
new file mode 100644
index 0000000..54a8e9a
--- /dev/null
+++ b/src/con_.c
@@ -0,0 +1,533 @@
+/* XXX: THIS FILE SHOULD BE CALLED `con.c` BUT WINDOWS IS STUPID */
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+#include "abi.h"
+#include "con_.h"
+#include "extmalloc.h"
+#include "gameinfo.h"
+#include "gametype.h"
+#include "mem.h"
+#include "os.h"
+#include "vcall.h"
+#include "version.h"
+
+/******************************************************************************\
+ * Have you ever noticed that when someone comments "here be dragons" there's *
+ * no actual dragons? Turns out, that's because the dragons all migrated over *
+ * here, so that they could build multiple inheritance vtables in C, by hand. *
+ * *
+ * Don't get set on fire. *
+\******************************************************************************/
+
+// given to us by the engine to unregister cvars in bulk on plugin unload
+static int dllid;
+
+// external spaghetti variable, exists only because valve are bad
+int con_cmdclient;
+
+// these have to be extern because of varargs nonsense - they get wrapped in a
+// macro for the actual api (con_colourmsg)
+void *_con_iface;
+void (*_con_colourmsgf)(void *this, const struct con_colour *c, const char *fmt,
+ ...) _CON_PRINTF(3, 4);
+
+// XXX: the const and non-const entries might actually be flipped on windows,
+// not 100% sure, but dunno if it's worth essentially duping most of these when
+// the actual executed machine code is probably identical anyway.
+DECL_VFUNC0(int, AllocateDLLIdentifier, 5)
+DECL_VFUNC0(int, AllocateDLLIdentifier_p2, 8)
+DECL_VFUNC(void, RegisterConCommand, 6, /*ConCommandBase*/ void *)
+DECL_VFUNC(void, RegisterConCommand_p2, 9, /*ConCommandBase*/ void *)
+DECL_VFUNC(void, UnregisterConCommands, 8, int)
+DECL_VFUNC(void, UnregisterConCommands_p2, 11, int)
+// DECL_VFUNC(void *, FindCommandBase, 10, const char *)
+DECL_VFUNC(void *, FindCommandBase_p2, 13, const char *)
+DECL_VFUNC(struct con_var *, FindVar, 12, const char *)
+// DECL_VFUNC0(const struct con_var *, FindVar_const, 13, const char *)
+DECL_VFUNC(struct con_var *, FindVar_p2, 15, const char *)
+DECL_VFUNC(struct con_cmd *, FindCommand, 14, const char *)
+DECL_VFUNC(struct con_cmd *, FindCommand_p2, 17, const char *)
+DECL_VFUNC(void, CallGlobalChangeCallbacks, 20, struct con_var *, const char *,
+ float)
+DECL_VFUNC(void, CallGlobalChangeCallbacks_l4d, 18, struct con_var *,
+ const char *, float)
+DECL_VFUNC(void, CallGlobalChangeCallbacks_p2, 21, struct con_var *,
+ const char *, float)
+DECL_VFUNC_CDECL(void, ConsoleColorPrintf_004, 23, const struct con_colour *,
+ const char *, ...)
+DECL_VFUNC_CDECL(void, ConsoleColorPrintf_l4d, 21, const struct con_colour *,
+ const char *, ...)
+DECL_VFUNC_CDECL(void, ConsoleColorPrintf_p2, 24, const struct con_colour *,
+ const char *, ...)
+
+static void initval(struct con_var *v) {
+ // v->strlen is set to defaultval len in _DEF_CVAR so we don't need to call
+ // strlen() on each string :)
+ v->strval = extmalloc(v->strlen);
+ memcpy(v->strval, v->defaultval, v->strlen);
+ // FIXME: technically this can be compile time too, using _Generic. Do that!
+ v->fval = atof(v->strval); v->ival = v->fval;
+}
+
+// generated by build/codegen.c, defines regcmds() and freevars()
+#include <cmdinit.gen.h>
+
+// to try and be like the engine even though it's probably not actually
+// required, we call the Internal* virtual functions by actual virtual lookup.
+// since the vtables are filled dynamically (below), we store this index; other
+// indexes are just offset from this one since the 3-or-4 functions are all
+// right next to each other.
+static int vtidx_InternalSetValue;
+
+// implementatiosn of virtual functions for our vars and commands below...
+
+static void VCALLCONV dtor(void *_) {} // we don't use constructors/destructors
+
+static bool VCALLCONV IsCommand_cmd(void *this) { return true; }
+static bool VCALLCONV IsCommand_var(void *this) { return false; }
+
+// flag stuff
+static bool VCALLCONV IsFlagSet_cmd(struct con_cmd *this, int flags) {
+ return !!(this->base.flags & flags);
+}
+static bool VCALLCONV IsFlagSet_var(struct con_var *this, int flags) {
+ return !!(this->parent->base.flags & flags);
+}
+static void VCALLCONV AddFlags_cmd(struct con_cmd *this, int flags) {
+ this->base.flags |= flags;
+}
+static void VCALLCONV AddFlags_var(struct con_var *this, int flags) {
+ this->parent->base.flags |= flags;
+}
+static void VCALLCONV RemoveFlags_cmd(struct con_cmd *this, int flags) {
+ this->base.flags &= ~flags;
+}
+static void VCALLCONV RemoveFlags_var(struct con_var *this, int flags) {
+ this->parent->base.flags &= ~flags;
+}
+static int VCALLCONV GetFlags_cmd(struct con_cmd *this) {
+ return this->base.flags;
+}
+static int VCALLCONV GetFlags_var(struct con_var *this) {
+ return this->parent->base.flags;
+}
+
+// basic registration stuff
+static const char *VCALLCONV GetName_cmd(struct con_cmd *this) {
+ return this->base.name;
+}
+static const char *VCALLCONV GetName_var(struct con_var *this) {
+ return this->parent->base.name;
+}
+static const char *VCALLCONV GetHelpText_cmd(struct con_cmd *this) {
+ return this->base.help;
+}
+static const char *VCALLCONV GetHelpText_var(struct con_var *this) {
+ return this->parent->base.help;
+}
+static bool VCALLCONV IsRegistered(struct con_cmdbase *this) {
+ return this->registered;
+}
+static int VCALLCONV GetDLLIdentifier(struct con_cmdbase *this) {
+ return dllid;
+}
+static void VCALLCONV Create_base(struct con_cmdbase *this, const char *name,
+ const char *help, int flags) {} // nop, we static init already
+static void VCALLCONV Init(struct con_cmdbase *this) {} // ""
+
+static bool VCALLCONV ClampValue(struct con_var *this, float *f) {
+ if (this->hasmin && this->minval > *f) { *f = this->minval; return true; }
+ if (this->hasmax && this->maxval < *f) { *f = this->maxval; return true; }
+ return false;
+}
+
+// command-specific stuff
+int VCALLCONV AutoCompleteSuggest(void *this, const char *partial,
+ /* CUtlVector */ void *commands) {
+ // TODO(autocomplete): implement this if needed later
+ return 0;
+}
+bool VCALLCONV CanAutoComplete(void *this) {
+ return false;
+}
+void VCALLCONV Dispatch(struct con_cmd *this, const struct con_cmdargs *args) {
+ // only try cb, cbv1 and iface should never get used by us
+ if (this->use_newcb && this->cb) this->cb(args);
+}
+
+// var-specific stuff
+static void VCALLCONV ChangeStringValue(struct con_var *this, const char *s,
+ float oldf) {
+ char *old = alloca(this->strlen);
+ memcpy(old, this->strval, this->strlen);
+ int len = strlen(s) + 1;
+ if (len > this->strlen) {
+ this->strval = extrealloc(this->strval, len);
+ this->strlen = len;
+ }
+ memcpy(this->strval, s, len);
+ //if (cb) {...} // not bothering
+ // also note: portal2 has a *list* of callbacks, although that part of ABI
+ // doesn't matter as far as plugin compat goes, so still not bothering
+ // we do however bother to call global callbacks, as is polite.
+ if (GAMETYPE_MATCHES(Portal2)) {
+ VCALL(_con_iface, CallGlobalChangeCallbacks_p2, this, old, oldf);
+ }
+ else if (GAMETYPE_MATCHES(L4D)) {
+ VCALL(_con_iface, CallGlobalChangeCallbacks_l4d, this, old, oldf);
+ }
+ else {
+ VCALL(_con_iface, CallGlobalChangeCallbacks, this, old, oldf);
+ }
+}
+
+static void VCALLCONV InternalSetValue(struct con_var *this, const char *v) {
+ float oldf = this->fval;
+ float newf = atof(v);
+ char tmp[32];
+ // NOTE: calling our own ClampValue and ChangeString, not bothering with
+ // vtable (it's internal anyway, so we're never calling into engine code)
+ if (ClampValue(this, &newf)) {
+ snprintf(tmp, sizeof(tmp), "%f", newf);
+ v = tmp;
+ }
+ this->fval = newf;
+ this->ival = (int)newf;
+ if (!(this->base.flags & CON_NOPRINT)) ChangeStringValue(this, v, oldf);
+}
+
+static void VCALLCONV InternalSetFloatValue(struct con_var *this, float v) {
+ if (v == this->fval) return;
+ ClampValue(this, &v);
+ float old = this->fval;
+ this->fval = v; this->ival = (int)this->fval;
+ if (!(this->base.flags & CON_NOPRINT)) {
+ char tmp[32];
+ snprintf(tmp, sizeof(tmp), "%f", this->fval);
+ ChangeStringValue(this, tmp, old);
+ }
+}
+
+static void VCALLCONV InternalSetIntValue(struct con_var *this, int v) {
+ if (v == this->ival) return;
+ float f = (float)v;
+ if (ClampValue(this, &f)) v = (int)f;
+ float old = this->fval;
+ this->fval = f; this->ival = v;
+ if (!(this->base.flags & CON_NOPRINT)) {
+ char tmp[32];
+ snprintf(tmp, sizeof(tmp), "%f", this->fval);
+ ChangeStringValue(this, tmp, old);
+ }
+}
+
+// Hack: IConVar things get this-adjusted pointers, we just reverse the offset
+// to get the top pointer.
+static void VCALLCONV SetValue_str_thunk(void *thisoff, const char *v) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ ((void (*VCALLCONV)(void *, const char *))(this->parent->base.vtable[
+ vtidx_InternalSetValue]))(this, v);
+}
+static void VCALLCONV SetValue_f_thunk(void *thisoff, float v) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ ((void (*VCALLCONV)(void *, float))(this->parent->base.vtable[
+ vtidx_InternalSetValue + 1]))(this, v);
+}
+static void VCALLCONV SetValue_i_thunk(void *thisoff, int v) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ ((void (*VCALLCONV)(void *, int))(this->parent->base.vtable[
+ vtidx_InternalSetValue + 2]))(this, v);
+}
+static void VCALLCONV SetValue_colour_thunk(void *thisoff, struct con_colour v) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ ((void (*VCALLCONV)(void *, struct con_colour))(this->parent->base.vtable[
+ vtidx_InternalSetValue + 3]))(this, v);
+}
+
+// more misc thunks, hopefully these just compile to a sub and a jmp
+static const char *VCALLCONV GetName_thunk(void *thisoff) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ return GetName_var(this);
+}
+static bool VCALLCONV IsFlagSet_thunk(void *thisoff, int flags) {
+ struct con_var *this = mem_offset(thisoff,
+ -offsetof(struct con_var, vtable_iconvar));
+ return IsFlagSet_var(this, flags);
+}
+
+// dunno what this is actually for...
+static int VCALLCONV GetSplitScreenPlayerSlot(void *thisoff) { return 0; }
+
+// aand yet another Create nop
+static void VCALLCONV Create_var(void *thisoff, const char *name,
+ const char *defaultval, int flags, const char *helpstr, bool hasmin,
+ float min, bool hasmax, float max, void *cb) {}
+
+#ifdef _WIN32
+#define NVDTOR 1
+#else
+#define NVDTOR 2 // Itanium ABI has 2 because I said so
+#endif
+
+// the first few members of ConCommandBase are the same between versions
+void *_con_vtab_cmd[14 + NVDTOR] = {
+ (void *)&dtor,
+#ifndef _WIN32
+ (void *)&dtor2,
+#endif
+ (void *)&IsCommand_cmd,
+ (void *)&IsFlagSet_cmd,
+ (void *)&AddFlags_cmd
+};
+
+// the engine does dynamic_casts on ConVar at some points so we have to fill out
+// bare minimum rtti to prevent crashes. oh goody.
+#ifdef _WIN32
+DEF_MSVC_BASIC_RTTI(static, varrtti, _con_realvtab_var, "sst_ConVar")
+#endif
+
+void *_con_realvtab_var[20] = {
+#ifdef _WIN32
+ &varrtti,
+#else
+ // this, among many other things, will be totally different on linux
+#endif
+ (void *)&dtor,
+#ifndef _WIN32
+ (void *)&dtor2,
+#endif
+ (void *)&IsCommand_var,
+ (void *)&IsFlagSet_var,
+ (void *)&AddFlags_var
+};
+
+void *_con_vtab_iconvar[7] = {
+#ifdef _WIN32
+ 0 // because of crazy overload vtable order we can't prefill *anything*
+#else
+ // colour is the last of the 4 on linux so we can at least prefill these 3
+ (void *)&SetValue_str_thunk,
+ (void *)&SetValue_f_thunk,
+ (void *)&SetValue_i_thunk
+#endif
+};
+
+static void fillvts(void) {
+ void **pc = _con_vtab_cmd + 3 + NVDTOR, **pv = _con_vtab_var + 3 + NVDTOR,
+ **pi = _con_vtab_iconvar
+#ifndef _WIN32
+ + 3
+#endif
+ ;
+ if (GAMETYPE_MATCHES(L4Dbased)) { // 007 base
+ *pc++ = (void *)&RemoveFlags_cmd;
+ *pc++ = (void *)&GetFlags_cmd;
+ *pv++ = (void *)&RemoveFlags_var;
+ *pv++ = (void *)&GetFlags_var;
+ }
+ // base stuff in cmd
+ *pc++ = (void *)&GetName_cmd;
+ *pc++ = (void *)&GetHelpText_cmd;
+ *pc++ = (void *)&IsRegistered;
+ *pc++ = (void *)&GetDLLIdentifier;
+ *pc++ = (void *)&Create_base;
+ *pc++ = (void *)&Init;
+ // cmd-specific
+ *pc++ = (void *)&AutoCompleteSuggest;
+ *pc++ = (void *)&CanAutoComplete;
+ *pc++ = (void *)&Dispatch;
+ // base stuff in var
+ *pv++ = (void *)&GetName_var;
+ *pv++ = (void *)&GetHelpText_var;
+ *pv++ = (void *)&IsRegistered;
+ *pv++ = (void *)&GetDLLIdentifier;
+ *pv++ = (void *)&Create_base;
+ *pv++ = (void *)&Init;
+ // var-specific
+ vtidx_InternalSetValue = pv - _con_vtab_var;
+ *pv++ = (void *)&InternalSetValue;
+ *pv++ = (void *)&InternalSetFloatValue;
+ *pv++ = (void *)&InternalSetIntValue;
+ if (GAMETYPE_MATCHES(L4D2) || GAMETYPE_MATCHES(Portal2)) { // ugh, annoying
+ // This is InternalSetColorValue, but that's basically the same thing,
+ // when you think about it.
+ *pv++ = (void *)&InternalSetIntValue;
+ }
+ *pv++ = (void *)&ClampValue;;
+ *pv++ = (void *)&ChangeStringValue;
+ *pv++ = (void *)&Create_var;
+ if (GAMETYPE_MATCHES(L4D2) || GAMETYPE_MATCHES(Portal2)) {
+ *pi++ = (void *)&SetValue_colour_thunk;
+ }
+#ifdef _WIN32
+ // see above: these aren't prefilled due the the reverse order
+ *pi++ = (void *)&SetValue_i_thunk;
+ *pi++ = (void *)&SetValue_f_thunk;
+ *pi++ = (void *)&SetValue_str_thunk;
+#endif
+ *pi++ = (void *)&GetName_thunk;
+ // GetBaseName (we just return actual name in all cases)
+ if (GAMETYPE_MATCHES(L4Dbased)) *pi++ = (void *)&GetName_thunk;
+ *pi++ = (void *)&IsFlagSet_thunk;
+ // last one: not in 004, but doesn't matter. one less branch!
+ *pi++ = (void *)&GetSplitScreenPlayerSlot;
+}
+
+bool con_init(void *(*f)(const char *, int *), int plugin_ver) {
+ int ifacever; // for error messages
+ if (_con_iface = f("VEngineCvar007", 0)) {
+ // GENIUS HACK (BUT STILL BAD): Portal 2 has everything in ICvar shifted
+ // down 3 places due to the extra stuff in IAppSystem. This means that
+ // if we look up the Portal 2-specific cvar using FindCommandBase, it
+ // *actually* calls the const-overloaded FindVar on other branches,
+ // which just happens to still work fine. From there, we can figure out
+ // the actual ABI to use to avoid spectacular crashes.
+ if (VCALL(_con_iface, FindCommandBase_p2, "portal2_square_portals")) {
+ _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_p2);
+ dllid = VCALL0(_con_iface, AllocateDLLIdentifier_p2);
+ _gametype_tag |= _gametype_tag_Portal2;
+ fillvts();
+ regcmds(VFUNC(_con_iface, RegisterConCommand_p2));
+ return true;
+ }
+ if (VCALL(_con_iface, FindCommand, "l4d2_snd_adrenaline")) {
+ _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d);
+ dllid = VCALL0(_con_iface, AllocateDLLIdentifier);
+ _gametype_tag |= _gametype_tag_L4D2;
+ fillvts();
+ regcmds(VFUNC(_con_iface, RegisterConCommand));
+ return true;
+ }
+ if (VCALL(_con_iface, FindVar, "z_difficulty")) {
+ _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_l4d);
+ dllid = VCALL0(_con_iface, AllocateDLLIdentifier);
+ _gametype_tag |= _gametype_tag_L4D1;
+ fillvts(); // XXX: is this all kinda dupey? maybe rearrange one day.
+ regcmds(VFUNC(_con_iface, RegisterConCommand));
+ return true;
+ }
+ con_warn("sst: error: game \"%s\" is unsupported (using "
+ "VEngineCvar007)\n", gameinfo_title);
+ ifacever = 7;
+ goto e;
+ }
+ if (_con_iface = f("VEngineCvar004", 0)) {
+ // TODO(compat): are there any cases where 004 is incompatible? could
+ // this crash? find out!
+ _con_colourmsgf = VFUNC(_con_iface, ConsoleColorPrintf_004);
+ dllid = VCALL0(_con_iface, AllocateDLLIdentifier);
+ // even more spaghetti! we need the plugin interface version to
+ // accurately distinguish 2007/2013 branches
+ if (plugin_ver == 3) _gametype_tag |= _gametype_tag_2013;
+ else _gametype_tag |= _gametype_tag_OrangeBox;
+ fillvts();
+ regcmds(VFUNC(_con_iface, RegisterConCommand));
+ return true;
+ }
+ if (f("VEngineCvar003", 0)) {
+ ifacever = 3;
+ goto warnoe;
+ }
+ if (f("VEngineCvar002", 0)) {
+ // I don't suppose there's anything below 002 worth caring about? Shrug.
+ ifacever = 2;
+warnoe: con_warn("sst: error: old engine console support is not implemented\n");
+ goto e;
+ }
+ con_warn("sst: error: couldn't find a supported console interface\n");
+ ifacever = -1; // meh
+e: con_msg("\n\n");
+ con_msg("-- Please include ALL of the following if asking for help:\n");
+ con_msg("-- plugin: " LONGNAME " v" VERSION "\n");
+ con_msg("-- game: %s\n", gameinfo_title);
+ con_msg("-- interfaces: %d/%d\n", plugin_ver, ifacever);
+ con_msg("\n\n");
+ return false;
+}
+
+void con_disconnect(void) {
+ if (GAMETYPE_MATCHES(Portal2)) {
+ VCALL(_con_iface, UnregisterConCommands_p2, dllid);
+ }
+ else {
+ VCALL(_con_iface, UnregisterConCommands, dllid);
+ }
+ freevars();
+}
+
+struct con_var *con_findvar(const char *name) {
+ if (GAMETYPE_MATCHES(Portal2)) {
+ return VCALL(_con_iface, FindVar_p2, name);
+ }
+ else {
+ return VCALL(_con_iface, FindVar, name);
+ }
+}
+
+struct con_cmd *con_findcmd(const char *name) {
+ if (GAMETYPE_MATCHES(Portal2)) {
+ return VCALL(_con_iface, FindCommand_p2, name);
+ }
+ else {
+ return VCALL(_con_iface, FindCommand, name);
+ }
+}
+
+#define GETTER(T, N, M) \
+ T N(const struct con_var *v) { return v->parent->M; }
+GETTER(const char *, con_getvarstr, strval)
+GETTER(float, con_getvarf, fval)
+GETTER(int, con_getvari, ival)
+#undef GETTER
+
+#define SETTER(T, I, N) \
+ void N(struct con_var *v, T x) { \
+ ((void (*VCALLCONV)(struct con_var *, T))(v->vtable_iconvar[I]))(v, x); \
+ }
+// vtable indexes for str/int/float are consistently at the start, hooray.
+// unfortunately the windows overload ordering meme still applies...
+#ifdef _WIN32
+SETTER(const char *, 2, con_setvarstr)
+SETTER(float, 1, con_setvarf)
+SETTER(int, 0, con_setvari)
+#else
+SETTER(const char *, 0, con_setvarstr)
+SETTER(float, 1, con_setvarf)
+SETTER(int, 2, con_setvari)
+#endif
+#undef SETTER
+
+con_cmdcb con_getcmdcb(const struct con_cmd *cmd) {
+ if (cmd->use_newcmdiface || !cmd->use_newcb) return 0;
+ return cmd->cb;
+}
+
+con_cmdcbv1 con_getcmdcbv1(const struct con_cmd *cmd) {
+ if (cmd->use_newcmdiface || cmd->use_newcb) return 0;
+ return cmd->cb_v1;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/con_.h b/src/con_.h
new file mode 100644
index 0000000..4c662fe
--- /dev/null
+++ b/src/con_.h
@@ -0,0 +1,278 @@
+/* XXX: THIS FILE SHOULD BE CALLED `con.h` BUT WINDOWS IS STUPID */
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_CON_H
+#define INC_CON_H
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+
+#if defined(__GNUC__) || defined(__clang__)
+#define _CON_PRINTF(x, y) __attribute__((format(printf, (x), (y))))
+#else
+#define _CON_PRINTF(x, y)
+#endif
+
+#define CON_CMD_MAX_ARGC 64
+#define CON_CMD_MAX_LENGTH 512
+
+/* arguments to a console command, parsed by the engine (SDK name: CCommand) */
+struct con_cmdargs {
+ int argc;
+ int argv0size;
+ char argsbuf[CON_CMD_MAX_LENGTH];
+ char argvbuf[CON_CMD_MAX_LENGTH];
+ const char *argv[CON_CMD_MAX_ARGC];
+};
+
+/* an ARGB colour, passed to con_colourmsg */
+struct con_colour {
+ union {
+ struct { u8 r, g, b, a; };
+ u32 val;
+ uchar bytes[4];
+ };
+};
+
+#define CON_CMD_MAXCOMPLETE 64
+#define CON_CMD_MAXCOMPLLEN 64
+
+/* ConVar/ConCommand flag bits - undocumented ones are probably not useful... */
+enum {
+ CON_UNREG = 1,
+ CON_DEVONLY = 1 << 1, /* hide unless developer 1 is set */
+ CON_SERVERSIDE = 1 << 2, /* set con_cmdclient and run on server side */
+ CON_CLIENTDLL = 1 << 3,
+ CON_HIDDEN = 1 << 4, /* hide completely, often useful to remove! */
+ CON_PROTECTED = 1 << 5, /* don't send to clients (example: password) */
+ CON_SPONLY = 1 << 6,
+ CON_ARCHIVE = 1 << 7, /* save in config - plugin would need a VDF! */
+ CON_NOTIFY = 1 << 8, /* announce changes in game chat */
+ CON_USERINFO = 1 << 9,
+ CON_PRINTABLE = 1 << 10, /* do not allow non-printable values */
+ CON_UNLOGGED = 1 << 11,
+ CON_NOPRINT = 1 << 12, /* do not attempt to print, contains junk! */
+ CON_REPLICATE = 1 << 13, /* client will use server's value */
+ CON_CHEAT = 1 << 14, /* require sv_cheats 1 to change from default */
+ CON_DEMO = 1 << 16, /* record value at the start of a demo */
+ CON_NORECORD = 1 << 17, /* don't record the command to a demo, ever */
+ CON_NOTCONN = 1 << 22, /* cannot be changed while in-game */
+ CON_SRVEXEC = 1 << 28, /* server can make clients run the command */
+ CON_NOSRVQUERY = 1 << 29, /* server cannot query the clientside value */
+ CON_CCMDEXEC = 1 << 30 /* ClientCmd() function may run the command */
+};
+
+/* A callback function invoked to execute a command. */
+typedef void (*con_cmdcb)(const struct con_cmdargs *cmd);
+
+/* Obsolete callback; not used by SST, but might still exist in the engine. */
+typedef void (*con_cmdcbv1)(void);
+
+/*
+ * This is an autocompletion callback for suggesting arguments to a command.
+ * XXX: Autocompletion isn't really totally figured out or implemented yet.
+ */
+typedef int (*con_complcb)(const char *part,
+ char cmds[CON_CMD_MAXCOMPLETE][CON_CMD_MAXCOMPLLEN]);
+
+/*
+ * These are called by the plugin load/unload functions; they have no use
+ * elsewhere.
+ */
+bool con_init(void *(*f)(const char *, int *), int plugin_ver);
+void con_disconnect(void);
+
+/*
+ * These types *pretty much* match those in the engine. Their fields can be
+ * accessed and played with if you know what you're doing!
+ */
+
+struct con_cmdbase { // ConCommandBase in engine
+ void **vtable;
+ struct con_cmdbase *next;
+ bool registered;
+ const char *name;
+ const char *help;
+ uint flags;
+};
+
+struct con_cmd { // ConCommand in engine
+ struct con_cmdbase base;
+ union {
+ con_cmdcbv1 cb_v1;
+ con_cmdcb cb;
+ /*ICommandCallback*/ void *cb_iface; // does source even use this?
+ };
+ union {
+ con_complcb complcb;
+ /*ICommandCompletionCallback*/ void *complcb_iface; // ...or this?
+ };
+ bool has_complcb : 1, use_newcb : 1, use_newcmdiface : 1;
+};
+
+// con_var will be a bit different on linux; see offset_to_top etc.
+#ifdef __linux__
+#error FIXME: redo multi-vtable crap for itanium ABI!
+#endif
+
+struct con_var { // ConVar in engine
+ struct con_cmdbase base;
+ void **vtable_iconvar; // IConVar in engine (pure virtual)
+ struct con_var *parent;
+ const char *defaultval;
+ char *strval;
+ uint strlen;
+ float fval;
+ int ival;
+ bool hasmin;
+ // bool hasmax; // better packing here, might break engine ABI
+ int minval;
+ bool hasmax; // just sticking to sdk position for now
+ int maxval;
+ //void *cb; we don't currently bother with callback support. add if needed!
+};
+
+
+/*
+ * These functions get and set the values of console variables in a
+ * neatly-abstracted manner. Note: cvar values are always strings internally -
+ * numerical values are just interpretations of the underlying value.
+ */
+struct con_var *con_findvar(const char *name);
+struct con_cmd *con_findcmd(const char *name);
+const char *con_getvarstr(const struct con_var *v);
+float con_getvarf(const struct con_var *v);
+int con_getvari(const struct con_var *v);
+void con_setvarstr(struct con_var *v, const char *s);
+void con_setvarf(struct con_var *v, float f);
+void con_setvari(struct con_var *v, int i);
+
+/*
+ * These functions grab the callback function from an existing command, allowing
+ * it to be called directly or further dug into for convenient research.
+ *
+ * They perform sanity checks to ensure that the command implements the type of
+ * callback being requested. If this is already known, consider just grabbing
+ * the member directly to avoid the small amount of unnecessary work.
+ */
+con_cmdcb con_getcmdcb(const struct con_cmd *cmd);
+con_cmdcbv1 con_getcmdcbv1(const struct con_cmd *cmd);
+
+/*
+ * These functions provide basic console output, in white and red colours
+ * respectively. They are aliases to direct tier0 calls, so they work early on
+ * even before anything else is initialised.
+ */
+#if defined(__GNUC__) || defined(__clang__)
+#ifdef _WIN32
+#define __asm__(x) __asm__("_" x) // stupid mangling meme (not on linux, right?)
+#endif
+void con_msg(const char *fmt, ...) _CON_PRINTF(1, 2) __asm__("Msg");
+void con_warn(const char *fmt, ...) _CON_PRINTF(1, 2) __asm__("Warning");
+#undef __asm__
+#else
+#error Need an equivalent of asm names for your compiler!
+#endif
+
+extern void *_con_iface;
+extern void (*_con_colourmsgf)(void *this, const struct con_colour *c,
+ const char *fmt, ...) _CON_PRINTF(3, 4);
+/*
+ * This provides the same functionality as ConColorMsg which was removed from
+ * tier0 in the L4D engine branch - specifically, it allows printing a message
+ * with an arbitrary RGBA colour. It must only be used after a successful
+ * con_init() call.
+ */
+#define con_colourmsg(c, ...) _con_colourmsgf(_con_iface, c, __VA_ARGS__)
+
+/*
+ * The index of the client responsible for the currently executing command,
+ * or -1 if serverside. This is a global variable because of Source spaghetti,
+ * rather than unforced plugin spaghetti.
+ */
+extern int con_cmdclient;
+
+// internal detail, used by DEF_* macros below
+extern void *_con_vtab_cmd[];
+// msvc rtti tables are offset negatively from the vtable pointer. to make this
+// a constant expression we have to use a macro
+#define _con_vtab_var (_con_realvtab_var + 1)
+extern void *_con_realvtab_var[];
+extern void *_con_vtab_iconvar[];
+
+#define _DEF_CVAR(name_, desc, value, hasmin_, min, hasmax_, max, flags_) \
+ static struct con_var _cvar_##name_ = { \
+ .base = { \
+ .vtable = _con_vtab_var, \
+ .name = "" #name_, .help = "" desc, .flags = (flags_) \
+ }, \
+ .vtable_iconvar = _con_vtab_iconvar, \
+ .parent = &_cvar_##name_, /* bizarre, but how the engine does it */ \
+ .defaultval = value, .strlen = sizeof("" value), \
+ .hasmin = hasmin_, .minval = (min), .hasmax = hasmax_, .maxval = (max) \
+ }; \
+ struct con_var *name_ = (struct con_var *)&_cvar_##name_;
+
+/* Defines a console variable with no min/max values. */
+#define DEF_CVAR(name, desc, value, flags) \
+ _DEF_CVAR(name, desc, value, false, 0, false, 0, flags)
+
+/* Defines a console variable with a given mininum numeric value. */
+#define DEF_CVAR_MIN(name_, desc, value, min, flags_) \
+ _DEF_CVAR(name, desc, value, true, min, false, 0, flags)
+
+/* Defines a console variable in the given numeric value range. */
+#define DEF_CVAR_MINMAX(name_, desc, value, min, max, flags_) \
+ _DEF_CVAR(name, desc, value, true, min, true, max, flags)
+
+#define _DEF_CCMD(varname, name_, desc, func, flags_) \
+ static struct con_cmd _ccmd_##varname = { \
+ .base = { \
+ .vtable = _con_vtab_cmd, \
+ .name = "" #name_, .help = "" desc, .flags = (flags_) \
+ }, \
+ .cb = &func, \
+ .use_newcb = true \
+ }; \
+ struct con_cmd *varname = (struct con_cmd *)&_ccmd_##varname;
+
+/* Defines a command with a given function as its handler. */
+#define DEF_CCMD(name, desc, func, flags) \
+ _DEF_CCMD(name, name, desc, func, flags)
+
+/*
+ * Defines two complementary +- commands, with PLUS_ and MINUS_ prefixes on
+ * their C names.
+ */
+#define DEF_CCMD_PLUSMINUS(name, descplus, fplus, descminus, fminus, flags) \
+ _DEF_CCMD(PLUS_##name, "+" name, descplus, fplus, flags) \
+ _DEF_CCMD(MINUS_##name, "-" name, descminus, fminus, flags)
+
+/*
+ * Defines a console command with the handler function body immediately
+ * following the macro (like in Source itself).
+ */
+#define DEF_CCMD_HERE(name, desc, flags) \
+ static void _cmdf_##name(const struct con_cmdargs *cmd); \
+ _DEF_CCMD(name, name, desc, _cmdf_##name, flags) \
+ static void _cmdf_##name(const struct con_cmdargs *cmd) \
+ /* { body here } */
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/dbg.c b/src/dbg.c
new file mode 100644
index 0000000..ca4e08e
--- /dev/null
+++ b/src/dbg.c
@@ -0,0 +1,49 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "con_.h"
+#include "intdefs.h"
+#include "ppmagic.h"
+#include "udis86.h"
+
+void dbg_hexdump(char *name, const void *p, int len) {
+ struct con_colour nice_colour = {160, 64, 200, 255}; // a nice purple colour
+ con_colourmsg(&nice_colour, "Hex dump \"%s\" (%p):", name, p);
+ for (const uchar *cp = p; cp - (uchar *)p < len; ++cp) {
+ // group into words and wrap every 8 words
+ switch ((cp - (uchar *)p) & 31) {
+ case 0: con_msg("\n"); break;
+ CASES(4, 8, 12, 16, 20, 24, 28): con_msg(" ");
+ }
+ con_colourmsg(&nice_colour, "%02X ", *cp);
+ }
+ con_msg("\n");
+}
+
+void dbg_asmdump(char *name, const void *p, int len) {
+ struct con_colour nice_colour = {40, 160, 140, 255}; // a nice teal colour
+ struct ud udis;
+ ud_init(&udis);
+ ud_set_mode(&udis, 32);
+ ud_set_input_buffer(&udis, p, len);
+ ud_set_syntax(&udis, UD_SYN_INTEL);
+ con_colourmsg(&nice_colour, "Disassembly \"%s\" (%p)\n", name, p);
+ while (ud_disassemble(&udis)) {
+ con_colourmsg(&nice_colour, " %s\n", ud_insn_asm(&udis));
+ }
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/dbg.h b/src/dbg.h
new file mode 100644
index 0000000..983e65f
--- /dev/null
+++ b/src/dbg.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_DBG_H
+#define INC_DBG_H
+
+/* prints out a basic hexadecimal listing of a byte range */
+void dbg_hexdump(char *name, const void *p, int len);
+
+/* prints out a disassembly of some instructions in memory */
+void dbg_asmdump(char *name, const void *p, int len);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/demodefs.h b/src/demodefs.h
new file mode 100644
index 0000000..8aab77b
--- /dev/null
+++ b/src/demodefs.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_DEMODEFS_H
+#define INC_DEMODEFS_H
+
+#include "intdefs.h"
+
+/*
+ * This file has demo format-related constants, mostly derived from Uncrafted's
+ * C# demo parser.
+ */
+
+/* Windows' MAX_PATH is also used for player/map/etc. names in the demo... */
+#define DEMO_HDR_STRLEN 260
+
+struct demo_hdr {
+ char sig[8]; /* HL2DEMO\0 */
+ s32 demover;
+ s32 netver;
+ char servername[DEMO_HDR_STRLEN];
+ char playername[DEMO_HDR_STRLEN];
+ char mapname[DEMO_HDR_STRLEN];
+ char gamedir[DEMO_HDR_STRLEN];
+ float realtime;
+ s32 nticks;
+ s32 nframes;
+ s32 signonlen;
+};
+
+enum demo_cmd {
+ // all protocols:
+ DEMO_CMD_SIGNON = 1,
+ DEMO_CMD_PACKET,
+ DEMO_CMD_SYNC,
+ DEMO_CMD_CONCMD,
+ DEMO_CMD_USERCMD,
+ DEMO_CMD_DATATABLES,
+ DEMO_CMD_STOP,
+ DEMO_CMD_STRINGTABLES14 = 8, // protocols 14 and 15
+ DEMO_CMD_CUSTOMDATA = 8, // protocol 36+
+ DEMO_CMD_STRINGTABLES36 // "
+};
+
+/* these are seemingly consistent across games/branches */
+#define DEMO_MAXEDICTBITS 11
+#define DEMO_MAXEDICTS (1 << DEMO_MAXEDICTS)
+#define DEMO_NETHANDLESERIALBITS 10
+#define DEMO_NETHANDLEBITS (DEMO_MAXEDICTBITS + DEMO_NETHANDLEBITS)
+#define DEMO_NULLHANDLE ((1u << DEMO_NETHANDLEBITS) - 1)
+#define DEMO_SUBSTRINGBITS 5
+#define DEMO_MAXUSERDATABITS 14
+#define DEMO_HANDLESERIALBITS 10
+// TODO: clarify what these ones do, and/or remove
+#define DEMO_MAXNETMSG 6
+#define DEMO_AREABITSNUMBITS 8
+#define DEMO_MAXSNDIDXBITS 13
+#define DEMO_SNDSEQBITS 10
+#define DEMO_MAXSNDLVLBITS 9
+#define DEMO_MAXSNDDELAYBITS 13
+#define DEMO_SNDSEQMASK ((1 << DEMO_SNDSEQBITS) - 1)
+// end of todo :^)
+#define DEMO_PLAYERNAMELEN 32
+#define DEMO_GUIDLEN 32
+
+/* protocol versions (seem somewhat arbitrary but just copying Uncrafted) */
+// (note: these aren't version numbers, they're just our own identifiers)
+enum {
+ DEMO_PROTO_HL2OE,
+ DEMO_PROTO_PORTAL_5135,
+ DEMO_PROTO_PORTAL_3420,
+ DEMO_PROTO_PORTAL_STEAM,
+ DEMO_PROTO_PORTAL2,
+ DEMO_PROTO_L4D2000,
+ DEMO_PROTO_L4D2042,
+ DEMO_PROTO_UNKNOWN
+};
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/demorec.c b/src/demorec.c
new file mode 100644
index 0000000..8e4c2c2
--- /dev/null
+++ b/src/demorec.c
@@ -0,0 +1,218 @@
+/*
+ * Copyright © 2021 Willian Henrique <wsimanbrazil@yahoo.com.br>
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "con_.h"
+#include "hook.h"
+#include "gamedata.h"
+#include "intdefs.h"
+#include "mem.h"
+#include "os.h"
+#include "udis86.h"
+#include "vcall.h"
+
+#define SIGNONSTATE_SPAWN 5 // ready to receive entity packets
+#define SIGNONSTATE_FULL 6 // fully connected, first non-delta packet receieved
+
+typedef void (*VCALLCONV f_StopRecording)(void *);
+typedef void (*VCALLCONV f_SetSignonState)(void *, int);
+
+static void *demorecorder;
+static struct con_cmd *cmd_stop;
+static bool *recording;
+static int *demonum;
+static f_SetSignonState orig_SetSignonState;
+static f_StopRecording orig_StopRecording;
+static con_cmdcb orig_stop_callback;
+
+static int auto_demonum = 1;
+static bool auto_recording = false;
+
+DEF_CVAR(sst_autorecord, "Continue recording demos through map changes",
+ "0", CON_ARCHIVE | CON_HIDDEN)
+
+static void VCALLCONV hook_StopRecording(void *this) {
+ // This hook will get called twice per loaded save (in most games/versions,
+ // at least, according to SAR people): first with m_bLoadgame set to false
+ // and then with it set to true. This will set m_nDemoNumber to 0 and
+ // m_bRecording to false
+ orig_StopRecording(this);
+
+ if (auto_recording && con_getvari(sst_autorecord)) {
+ *demonum = auto_demonum;
+ *recording = true;
+ }
+ else {
+ auto_demonum = 1;
+ auto_recording = false;
+ }
+}
+
+static void VCALLCONV hook_SetSignonState(void *this, int state) {
+ // SIGNONSTATE_FULL *may* happen twice per load, depending on the game, so
+ // use SIGNONSTATE_SPAWN for demo number increase
+ if (state == SIGNONSTATE_SPAWN && auto_recording) auto_demonum++;
+ // Starting a demo recording will call this function with SIGNONSTATE_FULL
+ // After a load, the engine's demo recorder will only start recording when
+ // it reaches this state, so this is a good time to set the flag if needed
+ else if (state == SIGNONSTATE_FULL) {
+ // Changing sessions may unset the recording flag (or so says NeKzor),
+ // so if we want to be recording, we want to tell the engine to record.
+ // But also, if the engine is already recording, we want our state to
+ // reflect *that*. IOW, if either thing is set, also set the other one.
+ auto_recording |= *recording; *recording = auto_recording;
+
+ // FIXME: this will override demonum incorrectly if the plugin is
+ // loaded while demos are already being recorded
+ if (auto_recording) *demonum = auto_demonum;
+ }
+ orig_SetSignonState(this, state);
+}
+
+static void hook_stop_callback(const struct con_cmdargs *args) {
+ auto_recording = false;
+ orig_stop_callback(args);
+}
+
+// This finds the "demorecorder" global variable (the engine-wide CDemoRecorder
+// instance).
+static inline void *find_demorecorder(struct con_cmd *cmd_stop) {
+ // The "stop" command calls the virtual function demorecorder.IsRecording(),
+ // so just look for the load of the "this" pointer
+ struct ud udis;
+ ud_init(&udis);
+ ud_set_mode(&udis, 32);
+ ud_set_input_buffer(&udis, (uchar *)con_getcmdcb(cmd_stop), 32);
+ while (ud_disassemble(&udis)) {
+#ifdef _WIN32
+ if (ud_insn_mnemonic(&udis) == UD_Imov) {
+ const struct ud_operand *dest = ud_insn_opr(&udis, 0);
+ const struct ud_operand *src = ud_insn_opr(&udis, 1);
+ // looking for a mov from an address into ECX, as per thiscall
+ if (dest->type == UD_OP_REG && dest->base == UD_R_ECX &&
+ src->type == UD_OP_MEM) {
+ return *(void **)src->lval.udword;
+ }
+ }
+#else
+#error TODO(linux): implement linux equivalent (cdecl!)
+#endif
+ }
+ return 0;
+}
+
+// This finds "m_bRecording" and "m_nDemoNumber" using the pointer to the
+// original "StopRecording" demorecorder function
+static inline bool find_recmembers(void *stop_recording_func, void *demorec) {
+ struct ud udis;
+ ud_init(&udis);
+ ud_set_mode(&udis, 32);
+ // TODO(opt): consider the below: is it really needed? does it matter?
+ // way overshooting the size of the function in bytes to make sure it
+ // accomodates for possible differences in different games. we make sure
+ // to stop early if we find a RET so should be fine
+ ud_set_input_buffer(&udis, (uchar *)stop_recording_func, 200);
+ while (ud_disassemble(&udis)) {
+#ifdef _WIN32
+ enum ud_mnemonic_code code = ud_insn_mnemonic(&udis);
+ if (code == UD_Imov) {
+ const struct ud_operand *dest = ud_insn_opr(&udis, 0);
+ const struct ud_operand *src = ud_insn_opr(&udis, 1);
+ // m_nDemoNumber and m_bRecording are both set to 0
+ // looking for movs with immediates equal to 0
+ // the byte immediate refers to m_bRecording
+ if (src->type == UD_OP_IMM && src->lval.ubyte == 0) {
+ if (src->size == 8) {
+ recording = (bool *)mem_offset(demorec, dest->lval.udword);
+ }
+ else {
+ demonum = (int *)mem_offset(demorec, dest->lval.udword);
+ }
+ if (recording && demonum) return true; // blegh
+ }
+ }
+ else if (code == UD_Iret) {
+ return false;
+ }
+#else // linux is probably different here idk
+#error TODO(linux): implement linux equivalent
+#endif
+ }
+ return false;
+}
+
+bool demorec_init(void) {
+ if (!gamedata_has_vtidx_SetSignonState ||
+ !gamedata_has_vtidx_StopRecording) {
+ con_warn("demorec: missing gamedata entries for this engine\n");
+ return false;
+ }
+
+ cmd_stop = con_findcmd("stop");
+ if (!cmd_stop) { // can *this* even happen? I hope not!
+ con_warn("demorec: couldn't find \"stop\" command\n");
+ return false;
+ }
+
+ demorecorder = find_demorecorder(cmd_stop);
+ if (!demorecorder) {
+ con_warn("demorec: couldn't find demo recorder instance\n");
+ return false;
+ }
+
+ void **vtable = *(void ***)demorecorder;
+
+ // XXX: 16 is totally arbitrary here! figure out proper bounds later
+ if (!os_mprot(vtable, 16 * sizeof(void *), PAGE_EXECUTE_READWRITE)) {
+#ifdef _WIN32
+ char err[128];
+ OS_WINDOWS_ERROR(err);
+#else
+ const char *err = strerror(errno);
+#endif
+ con_warn("demorec: couldn't unprotect CDemoRecorder vtable: %s\n", err);
+ return false;
+ }
+
+ if (!find_recmembers(vtable[7], demorecorder)) {
+ con_warn("demorec: couldn't find m_bRecording and m_nDemoNumber\n");
+ return false;
+ }
+
+ orig_SetSignonState = (f_SetSignonState)hook_vtable(vtable,
+ gamedata_vtidx_SetSignonState, (void *)&hook_SetSignonState);
+ orig_StopRecording = (f_StopRecording)hook_vtable(vtable,
+ gamedata_vtidx_StopRecording, (void *)&hook_StopRecording);
+
+ orig_stop_callback = cmd_stop->cb;
+ cmd_stop->cb = &hook_stop_callback;
+
+ sst_autorecord->base.flags &= ~CON_HIDDEN;
+ return true;
+}
+
+void demorec_end(void) {
+ void **vtable = *(void ***)demorecorder;
+ unhook_vtable(vtable, gamedata_vtidx_SetSignonState,
+ (void *)orig_SetSignonState);
+ unhook_vtable(vtable, gamedata_vtidx_StopRecording,
+ (void *)orig_StopRecording);
+ cmd_stop->cb = orig_stop_callback;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/demorec.h b/src/demorec.h
new file mode 100644
index 0000000..9d8e73e
--- /dev/null
+++ b/src/demorec.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright © 2021 Willian Henrique <wsimanbrazil@yahoo.com.br>
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_DEMOREC_H
+#define INC_DEMOREC_H
+
+#include <stdbool.h>
+
+bool demorec_init(void);
+void demorec_end(void);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/dll.rc b/src/dll.rc
new file mode 100644
index 0000000..59f5354
--- /dev/null
+++ b/src/dll.rc
@@ -0,0 +1,33 @@
+/* This file is dedicated to the public domain. */
+
+#include "version.h"
+
+#define EN_GB 0x809
+
+1 VERSIONINFO
+FILEVERSION VERSION_MAJOR,VERSION_MINOR,0,0
+PRODUCTVERSION VERSION_MAJOR,VERSION_MINOR,0,0
+FILEFLAGSMASK 0x17L
+FILEFLAGS 0
+FILEOS 4
+
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "080904b0"
+ BEGIN
+ VALUE "FileDescription", LONGNAME
+ VALUE "FileVersion", VERSION
+ VALUE "InternalName", NAME
+ VALUE "LegalCopyright", "Copyright (C) 2021 Michael Smith and others. All rights reserved."
+ VALUE "ProductName", LONGNAME
+ VALUE "ProductVersion", VERSION
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", EN_GB, 1200
+ END
+END
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/extmalloc.c b/src/extmalloc.c
new file mode 100644
index 0000000..9814d1b
--- /dev/null
+++ b/src/extmalloc.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "intdefs.h"
+#include "vcall.h"
+
+// FIXME: this is duped from os.h because I don't want to pull in Windows.h,
+// consider splitting out the IMPORT/EXPORT defs to some other thing?
+#ifdef _WIN32
+#define IMPORT __declspec(dllimport) // only needed for variables
+#else
+#define IMPORT
+#endif
+
+// XXX: not sure if "ext" is the best naming convention? use brain later
+
+IMPORT void *g_pMemAlloc;
+
+// this interface has changed a bit between versions but thankfully the basic
+// functions we care about have always been at the start - nice and easy.
+// unfortunately though, because the debug and non-debug versions are overloads
+// and Microsoft are a bunch of crazies who decided vtable order should be
+// affected by naming (overloads are grouped, and *reversed* inside of a
+// group!?), we get this amusing ABI difference between platforms:
+#ifdef _WIN32
+DECL_VFUNC(void *, Alloc, 1, usize sz)
+DECL_VFUNC(void *, Realloc, 3, void *mem, usize sz)
+DECL_VFUNC(void, Free, 5, void *mem)
+#else
+DECL_VFUNC(void *, Alloc, 0, usize sz)
+DECL_VFUNC(void *, Realloc, 1, void *mem, usize sz)
+DECL_VFUNC(void, Free, 2, void *mem)
+#endif
+
+void *extmalloc(usize sz) {
+ return VCALL(g_pMemAlloc, Alloc, sz);
+}
+
+void *extrealloc(void *mem, usize sz) {
+ return VCALL(g_pMemAlloc, Realloc, mem, sz);
+}
+
+void extfree(void *mem) {
+ VCALL(g_pMemAlloc, Free, mem);
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/extmalloc.h b/src/extmalloc.h
new file mode 100644
index 0000000..90c4f83
--- /dev/null
+++ b/src/extmalloc.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_EXTMALLOC_H
+#define INC_EXTMALLOC_H
+
+#include "intdefs.h"
+
+/*
+ * These functions are just like malloc/realloc/free, but they call into
+ * Valve's memory allocator wrapper, which ensures that allocations crossing
+ * plugin/engine boundaries won't cause any weird issues.
+ */
+void *extmalloc(usize sz);
+void *extrealloc(void *mem, usize sz);
+void extfree(void *mem);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/factory.h b/src/factory.h
new file mode 100644
index 0000000..a72afef
--- /dev/null
+++ b/src/factory.h
@@ -0,0 +1,13 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_FACTORY_H
+#define INC_FACTORY_H
+
+/* Access to game and engine factories obtained on plugin load */
+
+typedef void *(*ifacefactory)(const char *name, int *ret);
+extern ifacefactory factory_client, factory_server, factory_engine;
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gamedata.c b/src/gamedata.c
new file mode 100644
index 0000000..7ebbb22
--- /dev/null
+++ b/src/gamedata.c
@@ -0,0 +1,31 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "gametype.h"
+
+// same as gamedata.h, not worth putting in its own thing
+// (it's also in con_.c. whatever)
+#ifdef _WIN32
+#define NVDTOR 1
+#else
+#define NVDTOR 2
+#endif
+
+#include <gamedatainit.gen.h>
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gamedata.h b/src/gamedata.h
new file mode 100644
index 0000000..808bae0
--- /dev/null
+++ b/src/gamedata.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_GAMEDATA_H
+#define INC_GAMEDATA_H
+
+#ifdef _WIN32
+#define NVDTOR 1
+#else
+#define NVDTOR 2
+#endif
+#include <gamedata.gen.h>
+#undef NVDTOR
+
+void gamedata_init(void);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gameinfo.c b/src/gameinfo.c
new file mode 100644
index 0000000..32f5051
--- /dev/null
+++ b/src/gameinfo.c
@@ -0,0 +1,372 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdbool.h>
+#ifdef _WIN32
+#include <shlwapi.h>
+#endif
+
+#include "con_.h"
+#include "intdefs.h"
+#include "kv.h"
+#include "os.h"
+
+// Formatting for os_char * -> char * (or vice versa) - needed for con_warn()s
+// with file paths, etc
+#ifdef _WIN32
+#define fS "S" // os string (wide string) to regular string
+#define Fs L"S" // regular string to os string (wide string)
+#else
+// everything is just a regular string already
+#define fS "s"
+#define Fs "s"
+#endif
+
+static os_char exedir[PATH_MAX];
+static os_char gamedir[PATH_MAX];
+static char _gameinfo_title[64] = {0};
+const char *gameinfo_title = _gameinfo_title;
+static os_char _gameinfo_clientlib[PATH_MAX] = {0};
+const os_char *gameinfo_clientlib = _gameinfo_clientlib;
+static os_char _gameinfo_serverlib[PATH_MAX] = {0};
+const os_char *gameinfo_serverlib = _gameinfo_serverlib;
+
+// magical argc/argv grabber so we don't have to go through procfs
+#ifdef __linux__
+static const char *prog_argv;
+static int storeargs(int argc, char *argv[]) {
+ prog_argv = argv;
+ return 0;
+}
+__attribute__((used, section(".init_array")))
+static void *pstoreargs = &storeargs;
+#endif
+
+// case insensitive substring match, expects s2 to be lowercase already!
+// note: in theory this shouldn't need to be case sensitive, but I've seen mods
+// use both lowercase and TitleCase so this is just to be as lenient as possible
+static bool matchtok(const char *s1, const char *s2, usize sz) {
+ for (; sz; --sz, ++s1, ++s2) if (tolower(*s1) != *s2) return false;
+ return true;
+}
+
+static void try_gamelib(const os_char *path, os_char *outpath) {
+ // _technically_ this is toctou, but I don't think that matters here
+ if (os_access(path, F_OK) != -1) {
+ os_strcpy(outpath, path);
+ }
+ else if (errno != ENOENT) {
+ con_warn("gameinfo: failed to access %" fS ": %s\n", path,
+ strerror(errno));
+ }
+}
+
+// note: p and len are a non-null-terminated string
+static inline void do_gamelib_search(const char *p, uint len, bool isgamebin) {
+ // sanity check: don't do a bunch of work for no reason
+ if (len >= PATH_MAX - 1 - (sizeof("client" OS_DLSUFFIX) - 1)) goto toobig;
+ os_char bindir[PATH_MAX];
+ os_char *outp = bindir;
+ // this should really be an snprintf, meh whatever
+ os_strcpy(bindir, exedir);
+ outp = bindir + os_strlen(bindir);
+ // quick note about windows encoding conversion: this MIGHT clobber the
+ // encoding of non-ascii mod names, but it's unclear if/how source handles
+ // that anyway, so we just have to assume there *are no* non-ascii mod
+ // names, since they'd also be clobbered, probably. if I'm wrong this can
+ // just change later to an explicit charset conversion, so... it's kinda
+ // whatever, I guess
+ const os_char *fmt = isgamebin ?
+ OS_LIT("/%.*") Fs OS_LIT("/") :
+ OS_LIT("/%.*") Fs OS_LIT("/bin/");
+ int spaceleft = PATH_MAX;
+ if (len >= 25 && matchtok(p, "|all_source_engine_paths|", 25)) {
+ // this special path doesn't seem any different to normal,
+ // why is this a thing?
+ p += 25; len -= 25;
+ }
+ else if (len >= 15 && matchtok(p, "|gameinfo_path|", 15)) {
+ // search in the actual mod/game directory
+ p += 15; len -= 15;
+ int ret = os_snprintf(bindir, PATH_MAX, OS_LIT("%s"), gamedir);
+ outp = bindir + ret;
+ spaceleft -= ret;
+ }
+ else {
+#ifdef _WIN32
+ // sigh
+ char api_needs_null_term[PATH_MAX];
+ memcpy(api_needs_null_term, p, len * sizeof(*p));
+ api_needs_null_term[len] = L'\0';
+ if (!PathIsRelativeA(api_needs_null_term))
+#else
+ if (*p == "/") // so much easier :')
+#endif
+ {
+ // the mod path is absolute, so we're not sticking anything else in
+ // front of it, so skip the leading slash in fmt and point the pointer
+ // at the start of the buffer
+ ++fmt;
+ outp = bindir;
+ }}
+
+ // leave room for server/client.dll/so (note: server and client happen to
+ // conveniently have the same number of letters)
+ int fmtspace = spaceleft - (sizeof("client" OS_DLSUFFIX) - 1);
+ int ret = os_snprintf(outp, fmtspace, fmt, len, p);
+ if (ret >= fmtspace) {
+toobig: con_warn("gameinfo: skipping an overly long search path\n");
+ return;
+ }
+ outp += ret;
+ if (!*gameinfo_clientlib) {
+ os_strcpy(outp, OS_LIT("client" OS_DLSUFFIX));
+ try_gamelib(bindir, _gameinfo_clientlib);
+ }
+ if (!*gameinfo_serverlib) {
+ os_strcpy(outp, OS_LIT("server" OS_DLSUFFIX));
+ try_gamelib(bindir, _gameinfo_serverlib);
+ }
+}
+
+// state for the callback below to keep it somewhat reentrant-ish (except where
+// it isn't because I got lazy and wrote some spaghetti)
+struct kv_parsestate {
+ // after parsing a key we *don't* care about, how many nested subkeys have
+ // we come across?
+ short dontcarelvl;
+ // after parsing a key we *do* care about, which key in the matchkeys[]
+ // array below are we looking for next?
+ schar nestlvl;
+ // what kind of key did we just match?
+ schar matchtype;
+};
+
+// this is a sprawling mess. Too Bad!
+static void kv_cb(enum kv_token type, const char *p, uint len, void *_ctxt) {
+ struct kv_parsestate *ctxt = _ctxt;
+
+ static const struct {
+ const char *s;
+ uint len;
+ } matchkeys[] = {
+ {"gameinfo", 8},
+ {"filesystem", 10},
+ {"searchpaths", 11}
+ };
+
+ // values for ctxt->matchtype
+ enum {
+ mt_none,
+ mt_title,
+ mt_nest,
+ mt_game,
+ mt_gamebin
+ };
+
+ #define MATCH(s) (len == sizeof(s) - 1 && matchtok(p, s, sizeof(s) - 1))
+ switch (type) {
+ case KV_IDENT: case KV_IDENT_QUOTED:
+ if (ctxt->nestlvl == 1 && MATCH("game")) {
+ ctxt->matchtype = mt_title;
+ }
+ else if (ctxt->nestlvl == 3) {
+ // for some reason there's a million different ways of
+ // specifying the same type of path
+ if (MATCH("mod+game") || MATCH("game+mod") || MATCH("game") ||
+ MATCH("mod")) {
+ ctxt->matchtype = mt_game;
+ }
+ else if (MATCH("gamebin")) {
+ ctxt->matchtype = mt_gamebin;
+ }
+ }
+ else if (len == matchkeys[ctxt->nestlvl].len &&
+ matchtok(p, matchkeys[ctxt->nestlvl].s, len)) {
+ ctxt->matchtype = mt_nest;
+ }
+ break;
+ case KV_NEST_START:
+ if (ctxt->matchtype == mt_nest) ++ctxt->nestlvl;
+ else ++ctxt->dontcarelvl;
+ ctxt->matchtype = mt_none;
+ break;
+ case KV_VAL: case KV_VAL_QUOTED:
+ if (ctxt->dontcarelvl) break;
+ if (ctxt->matchtype == mt_title) {
+ // title really shouldn't get this long, but truncate just to
+ // avoid any trouble...
+ // also note: leaving 1 byte of space for null termination (the
+ // buffer is already zeroed initially)
+ if (len > sizeof(_gameinfo_title) - 1) {
+ len = sizeof(_gameinfo_title) - 1;
+ }
+ memcpy(_gameinfo_title, p, len);
+ }
+ else if (ctxt->matchtype == mt_game ||
+ ctxt->matchtype == mt_gamebin) {
+ // if we already have everything, we can just stop!
+ if (*gameinfo_clientlib && *gameinfo_serverlib) break;
+ do_gamelib_search(p, len, ctxt->matchtype == mt_gamebin);
+ }
+ ctxt->matchtype = mt_none;
+ break;
+ case KV_NEST_END:
+ if (ctxt->dontcarelvl) --ctxt->dontcarelvl; else --ctxt->nestlvl;
+ }
+ #undef MATCH
+}
+
+bool gameinfo_init(void) {
+ const os_char *modname = OS_LIT("hl2");
+#ifdef _WIN32
+ int len = GetModuleFileNameW(0, exedir, PATH_MAX);
+ if (!len) {
+ char err[128];
+ OS_WINDOWS_ERROR(err);
+ con_warn("gameinfo: couldn't get EXE path: %s\n", err);
+ return false;
+ }
+ // if the buffer is full and has no null, it's truncated
+ if (len == PATH_MAX && exedir[len - 1] != L'\0') {
+ con_warn("gameinfo: EXE path is too long!\n");
+ return false;
+ }
+#else
+ int len = readlink("/proc/self/exe", exedir, PATH_MAX);
+ if (len == -1) {
+ con_warn("gameinfo: couldn't get program path: %s\n", strerror(errno));
+ return false;
+ }
+ // if the buffer is full at all, it's truncated (readlink never writes \0)
+ if (len == PATH_MAX) {
+ con_warn("gameinfo: program path is too long!\n");
+ return false;
+ }
+ else {
+ exedir[len] = '\0';
+ }
+#endif
+ // find the last slash
+ os_char *p;
+ for (p = exedir + len - 1; *p != OS_LIT('/')
+#ifdef _WIN32
+ && *p != L'\\'
+#endif
+ ; --p);
+ // ... and split on it
+ *p = 0;
+ const os_char *exename = p + 1;
+#ifdef _WIN32
+ // try and infer the default mod name (when -game isn't given) from the exe
+ // name for a few known games
+ if (!_wcsicmp(exename, L"left4dead2.exe")) modname = L"left4dead2";
+ else if (!_wcsicmp(exename, L"left4dead.exe")) modname = L"left4dead";
+ else if (!_wcsicmp(exename, L"portal2.exe")) modname = L"portal2";
+
+ const ushort *args = GetCommandLineW();
+ const ushort *argp = args;
+ ushort modbuf[PATH_MAX];
+ // have to take the _last_ occurence of -game because sourcemods get the
+ // flag twice, for some reason
+ while (argp = wcsstr(argp, L" -game ")) {
+ argp += 7;
+ while (*argp == L' ') ++argp;
+ ushort sep = L' ';
+ // WARNING: not handling escaped quotes and such nonsense, since you
+ // can't have quotes in filepaths anyway outside of UNC and I'm just
+ // assuming there's no way Source could even be started with such an
+ // insanely named mod. We'll see how this assumption holds up!
+ if (*argp == L'"') {
+ ++argp;
+ sep = L'"';
+ }
+ ushort *bufp = modbuf;
+ for (; *argp != L'\0' && *argp != sep; ++argp, ++bufp) {
+ if (bufp - modbuf == PATH_MAX - 1) {
+ con_warn("gameinfo: mod name parameter is too long\n");
+ return false;
+ }
+ *bufp = *argp;
+ }
+ *bufp = L'\0';
+ modname = modbuf;
+ }
+ bool isrelative = PathIsRelativeW(modname);
+#else
+ // also do the executable name check just for portal2_linux
+ if (!strcmp(exename, "portal2_linux")) modname = "portal2";
+ // ah, the sane, straightforward world of unix command line arguments :)
+ for (char **pp = prog_argv + 1; *pp; ++pp) {
+ if (!strcmp(*pp, "-game")) {
+ if (!*++pp) break;
+ modname = *pp;
+ }
+ }
+ // ah, the sane, straightforward world of unix paths :)
+ bool isrelative = modname[0] != '/';
+#endif
+
+ int ret = isrelative ?
+ os_snprintf(gamedir, PATH_MAX, OS_LIT("%s/%s"), exedir, modname) :
+ // mod name might actually be an absolute (if installed in steam
+ // sourcemods for example)
+ os_snprintf(gamedir, PATH_MAX, OS_LIT("%s"), modname);
+ if (ret >= PATH_MAX) {
+ con_warn("gameinfo: game directory path is too long!\n");
+ return false;
+ }
+ os_char gameinfopath[PATH_MAX];
+ if (os_snprintf(gameinfopath, PATH_MAX, OS_LIT("%s/gameinfo.txt"),
+ gamedir, modname) >= PATH_MAX) {
+ con_warn("gameinfo: gameinfo.text path is too long!\n");
+ return false;
+ }
+
+ int fd = os_open(gameinfopath, O_RDONLY);
+ if (fd == -1) {
+ con_warn("gameinfo: couldn't open gameinfo.txt: %s\n", strerror(errno));
+ return false;
+ }
+ char buf[1024];
+ struct kv_parser kvp = {0};
+ struct kv_parsestate ctxt = {0};
+ int nread;
+ while (nread = read(fd, buf, sizeof(buf))) {
+ if (nread == -1) {
+ con_warn("gameinfo: couldn't read gameinfo.txt: %s\n",
+ strerror(errno));
+ goto e;
+ }
+ kv_parser_feed(&kvp, buf, nread, &kv_cb, &ctxt);
+ if (kvp.state == KV_PARSER_ERROR) goto ep;
+ }
+ kv_parser_done(&kvp);
+ if (kvp.state == KV_PARSER_ERROR) goto ep;
+
+ close(fd);
+ return true;
+
+ep: con_warn("gameinfo: couldn't parse gameinfo.txt (%d:%d): %s\n",
+ kvp.line, kvp.col, kvp.errmsg);
+e: close(fd);
+ return false;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gameinfo.h b/src/gameinfo.h
new file mode 100644
index 0000000..845c9c2
--- /dev/null
+++ b/src/gameinfo.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_GAMEINFO_H
+#define INC_GAMEINFO_H
+
+#include "intdefs.h"
+#include "os.h"
+
+/* These variables are only set after calling gameinfo_init(). */
+extern const char *gameinfo_title; /* Name of the game (window title) */
+extern const os_char *gameinfo_clientlib; /* Path to the client library */
+extern const os_char *gameinfo_serverlib; /* Path to the server library */
+
+/*
+ * This function is called early in the plugin load and does a whole bunch of
+ * spaghetti magic to figure out which game/engine we're in and where its
+ * libraries (which we want to hook) are located.
+ */
+bool gameinfo_init(void);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/gametype.h b/src/gametype.h
new file mode 100644
index 0000000..8a823f8
--- /dev/null
+++ b/src/gametype.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_GAMETYPE_H
+#define INC_GAMETYPE_H
+
+#include "intdefs.h"
+
+extern u32 _gametype_tag;
+
+#define _gametype_tag_OE 1
+#define _gametype_tag_OrangeBox 2
+#define _gametype_tag_L4D1 4
+#define _gametype_tag_L4D2 8
+#define _gametype_tag_Portal2 16
+#define _gametype_tag_2013 32
+
+#define _gametype_tag_L4D (_gametype_tag_L4D1 | _gametype_tag_L4D2)
+#define _gametype_tag_L4Dbased (_gametype_tag_L4D | _gametype_tag_Portal2)
+
+#define GAMETYPE_MATCHES(x) !!(_gametype_tag & (_gametype_tag_##x))
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/hook.c b/src/hook.c
new file mode 100644
index 0000000..410e23e
--- /dev/null
+++ b/src/hook.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <string.h>
+
+#include "con_.h"
+#include "intdefs.h"
+#include "mem.h"
+#include "os.h"
+#include "udis86.h"
+
+// Warning: half-arsed hacky implementation (because that's all we really need)
+// Almost certainly breaks in some weird cases. Oh well! Most of the time,
+// vtable hooking is more reliable, this is only for, uh, emergencies.
+
+#if defined(_WIN32) && !defined(_WIN64)
+
+__attribute__((aligned(4096)))
+static uchar trampolines[4096];
+static uchar *nexttrampoline = trampolines;
+__attribute__((constructor))
+static void setrwx(void) {
+ // PE doesn't support rwx sections, not sure about ELF. Eh, just hack it in
+ // a constructor instead. If this fails and we segfault later, too bad!
+ os_mprot(trampolines, sizeof(trampolines), PAGE_EXECUTE_READWRITE);
+}
+
+#define RELJMP 0xE9 // the first byte of a 5-byte jmp
+
+void *hook_inline(void *func_, void *target) {
+ uchar *func = func_;
+ if (!os_mprot(func, 5, PAGE_EXECUTE_READWRITE)) return false;
+ struct ud udis;
+ ud_init(&udis);
+ ud_set_mode(&udis, 32);
+ // max insn length is 15, we overwrite 5, so max to copy is 4 + 15 = 19
+ ud_set_input_buffer(&udis, func, 19);
+ int len = 0;
+ while (ud_disassemble(&udis) && len < 5) {
+ if (ud_insn_mnemonic(&udis) == UD_Ijmp ||
+ ud_insn_mnemonic(&udis) == UD_Icall) {
+ con_warn("hook_inline: jmp adjustment NYI\n");
+ return 0;
+ }
+ len += ud_insn_len(&udis);
+ }
+ // for simplicity, just bump alloc the trampoline. no need to free anyway
+ if (nexttrampoline - trampolines > len + 6) goto nospc;
+ uchar *trampoline = (uchar *)InterlockedExchangeAdd(
+ (volatile long *)&nexttrampoline, len + 6);
+ if (trampoline - trampolines > len + 6) { // avoid TOCTOU
+nospc: con_warn("hook_inline: out of trampoline space\n");
+ return 0;
+ }
+ *trampoline++ = len; // stick length in front for quicker unhooking
+ memcpy(trampoline, func, len);
+ trampoline[len] = RELJMP;
+ uint diff = func - (trampoline + 5); // goto the continuation
+ memcpy(trampoline + len + 1, &diff, 4);
+ uchar jmp[8];
+ jmp[0] = RELJMP;
+ diff = (uchar *)target - (func + 5); // goto the hook target
+ memcpy(jmp + 1, &diff, 4);
+ // pad with original bytes so we can do an 8-byte atomic write
+ memcpy(jmp + 5, func + 5, 3);
+ *(volatile uvlong *)func = *(uvlong *)jmp; // (assuming function is aligned)
+ FlushInstructionCache(GetCurrentProcess(), func, len);
+ return trampoline;
+}
+
+void unhook_inline(void *orig) {
+ uchar *p = (uchar *)orig;
+ int len = p[-1];
+ uint off = mem_load32(p + len + 1);
+ uchar *q = p + off + 5;
+ memcpy(q, p, 5); // XXX not atomic atm! (does any of it even need to be?)
+ FlushInstructionCache(GetCurrentProcess(), q, 5);
+}
+
+#else
+
+// TODO(linux): Implement for Linux and/or x86_64 when needed...
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/hook.h b/src/hook.h
new file mode 100644
index 0000000..02c41dc
--- /dev/null
+++ b/src/hook.h
@@ -0,0 +1,54 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_HOOK_H
+#define INC_HOOK_H
+
+#include "intdefs.h"
+
+/*
+ * Replaces a vtable entry with a target function and returns the original
+ * function.
+ */
+static inline void *hook_vtable(void **vtable, usize off, void *target) {
+ void *orig = vtable[off];
+ vtable[off] = target;
+ return orig;
+}
+
+/*
+ * Puts an original function back after hooking.
+ */
+static inline void unhook_vtable(void **vtable, usize off, void *orig) {
+ vtable[off] = orig;
+}
+
+/*
+ * Returns a trampoline pointer, or null if hooking failed. Unlike hook_vtable,
+ * handles memory protection for you.
+ */
+void *hook_inline(void *func, void *target);
+
+/*
+ * Reverts the function to its original unhooked state. Takes the pointer to the
+ * callable "original" function, i.e. the trampoline, NOT the initial function
+ * pointer from before hooking.
+ */
+void unhook_inline(void *orig);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/intdefs.h b/src/intdefs.h
new file mode 100644
index 0000000..a3370d7
--- /dev/null
+++ b/src/intdefs.h
@@ -0,0 +1,35 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_INTDEFS_H
+#define INC_INTDEFS_H
+
+typedef signed char schar;
+typedef unsigned char uchar;
+typedef unsigned short ushort;
+typedef unsigned int uint;
+typedef unsigned long ulong;
+typedef long long vlong;
+typedef unsigned long long uvlong;
+
+typedef schar s8;
+typedef uchar u8;
+typedef short s16;
+typedef ushort u16;
+typedef int s32;
+typedef uint u32;
+typedef vlong s64;
+typedef uvlong u64;
+
+// just in case there's ever a need to support 64-bit builds of Source, define a
+// size type, since Windows isn't LP64 so (u)long won't quite do
+#ifdef _WIN64
+typedef vlong ssize;
+typedef uvlong usize;
+#else
+typedef long ssize;
+typedef ulong usize;
+#endif
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/kv.c b/src/kv.c
new file mode 100644
index 0000000..8258b16
--- /dev/null
+++ b/src/kv.c
@@ -0,0 +1,231 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+#include "kv.h"
+
+#define EOF -1
+
+void kv_parser_feed(struct kv_parser *this, const char *in, uint sz,
+ kv_parser_cb cb, void *ctxt) {
+ const char *p = in;
+ short c;
+
+ // slight hack, makes init more convenient (just {0})
+ if (!this->line) this->line = 1;
+ if (!this->outp) this->outp = this->tokbuf;
+
+ // this is a big ol' blob of ugly state machine macro spaghetti - too bad!
+ #define INCCOL() (*p == '\n' ? (++this->line, this->col = 0) : ++this->col)
+ #define READ() (p == in + sz ? EOF : (INCCOL(), *p++))
+ #define ERROR(s) do { \
+ this->state = KV_PARSER_ERROR; \
+ this->errmsg = s; \
+ return; \
+ } while (0)
+ #define OUT(c) do { \
+ if (this->outp - this->tokbuf == KV_TOKEN_MAX) { \
+ ERROR("token unreasonably large!"); \
+ } \
+ *this->outp++ = (c); \
+ } while (0)
+ #define CASE_WS case ' ': case '\t': case '\n': case '\r'
+ // note: multi-eval
+ #define IS_WS(c) ((c) == ' ' || (c) == '\t' || (c) == '\n' || (c) == '\r')
+ #define STATE(s) case s: s
+ #define HANDLE_EOF() do { case EOF: return; } while (0)
+ #define SKIP_COMMENT(next) do { \
+ this->state = next; \
+ this->incomment = true; \
+ goto start; \
+ } while (0)
+ #define GOTO(s) do { this->state = s; goto s; } while (0)
+ #define CB(type) do { \
+ cb(type, this->tokbuf, this->outp - this->tokbuf, ctxt); \
+ this->outp = this->tokbuf; \
+ } while (0)
+
+ // parser states, implemented by STATE() macros below
+ enum {
+ ok,
+ ok_slash,
+ ident,
+ ident_slash,
+ identq,
+ sep,
+ sep_slash,
+ val,
+ val_slash,
+ valq
+ };
+
+start: // special spaghetti so we don't have a million different comment states
+ if (this->incomment) while ((c = READ()) != '\n') if (c == EOF) return;
+ this->incomment = false;
+
+switch (this->state) {
+
+STATE(ok):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ CASE_WS: goto ok;
+ case '#': ERROR("kv macros not supported");
+ case '{': ERROR("unexpected control character");
+ case '}':
+ if (!this->nestlvl) ERROR("too many closing braces");
+ --this->nestlvl;
+ char c_ = c;
+ cb(KV_NEST_END, &c_, 1, ctxt);
+ goto ok;
+ case '"': GOTO(identq);
+ case '/': GOTO(ok_slash);
+ default: GOTO(ident);
+ }
+
+STATE(ok_slash):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '/': SKIP_COMMENT(ok);
+ default: OUT('/'); GOTO(ident);
+ }
+
+ident:
+ OUT(c);
+case ident: // continue here
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '{':
+ CB(KV_IDENT);
+ ++this->nestlvl;
+ char c_ = c;
+ cb(KV_NEST_START, &c_, 1, ctxt);
+ GOTO(ok);
+ case '}': case '"': ERROR("unexpected control character");
+ CASE_WS:
+ CB(KV_IDENT);
+ GOTO(sep);
+ case '/': GOTO(ident_slash);
+ default: goto ident;
+ }
+
+STATE(ident_slash):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '/':
+ CB(KV_IDENT);
+ SKIP_COMMENT(sep);
+ default: OUT('/'); GOTO(ident);
+ }
+
+STATE(identq):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '"':
+ CB(KV_IDENT_QUOTED);
+ GOTO(sep);
+ default: OUT(c); goto identq;
+ }
+
+STATE(sep):
+ do c = READ(); while (IS_WS(c));
+ switch (c) {
+ HANDLE_EOF();
+ case '[': ERROR("conditionals not supported");
+ case '{':;
+ char c_ = c;
+ ++this->nestlvl;
+ cb(KV_NEST_START, &c_, 1, ctxt);
+ GOTO(ok);
+ case '"': GOTO(valq);
+ case '}': ERROR("unexpected control character");
+ case '/': GOTO(sep_slash);
+ default: GOTO(val);
+ }
+
+STATE(sep_slash):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '/': SKIP_COMMENT(sep);
+ default: OUT('/'); GOTO(val);
+ }
+
+val:
+ OUT(c);
+case val: // continue here
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '{': case '"': ERROR("unexpected control character");
+ // might get } with no whitespace
+ case '}':
+ CB(KV_VAL);
+ --this->nestlvl;
+ char c_ = c;
+ cb(KV_NEST_END, &c_, 1, ctxt);
+ GOTO(ok);
+ CASE_WS:
+ CB(KV_VAL);
+ GOTO(ok);
+ case '/': GOTO(val_slash);
+ default: goto val;
+ }
+
+STATE(val_slash):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '/':
+ CB(KV_VAL);
+ SKIP_COMMENT(ok);
+ default: OUT('/'); GOTO(val);
+ }
+
+STATE(valq):
+ switch (c = READ()) {
+ HANDLE_EOF();
+ case '"':
+ CB(KV_VAL_QUOTED);
+ GOTO(ok);
+ default: OUT(c); goto valq;
+ }
+
+}
+
+ #undef CB
+ #undef GOTO
+ #undef SKIP_COMMENT
+ #undef HANDLE_EOF
+ #undef STATE
+ #undef IS_WS
+ #undef CASE_WS
+ #undef OUT
+ #undef ERROR
+ #undef READ
+ #undef INCCOL
+}
+
+void kv_parser_done(struct kv_parser *this) {
+ if (this->state > 0) {
+ this->state = -1;
+ this->errmsg = "unexpected end of input";
+ }
+ else if (this->state == 0 && this->nestlvl != 0) {
+ this->state = -1;
+ this->errmsg = "unterminated object (unbalanced braces)";
+ }
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/kv.h b/src/kv.h
new file mode 100644
index 0000000..6de2c67
--- /dev/null
+++ b/src/kv.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_KV_H
+#define INC_KV_H
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+
+/*
+ * Maximum length of a single token. Since this code is trying to avoid dynamic
+ * memory allocations, this arbitrary limit is chosen to accomodate all known
+ * "reasonable" tokens likely to come in any real files, probably.
+ */
+#define KV_TOKEN_MAX 512
+
+/*
+ * Contains all the state associated with parsing (lexing?) a KeyValues file.
+ * Should be zeroed out prior to the first call (initialise with `= {0};`).
+ */
+struct kv_parser {
+ ushort line, col; /* the current line and column in the text */
+ schar state; /* internal, shouldn't usually be touched directly */
+ bool incomment; /* internal */
+ ushort nestlvl; /* internal */
+ const char *errmsg; /* the error message, *IF* parsing just failed */
+
+ // trying to avoid dynamic allocations - valve's own parser seems to have
+ // a similar limit as well and our use case doesn't really need to worry
+ // about stupid massive values, so it's fine
+ char *outp;
+ char tokbuf[KV_TOKEN_MAX];
+};
+
+#define KV_PARSER_ERROR -1
+
+/*
+ * These are the tokens that can be receieved by a kv_parser_cb (below).
+ * The x-macro and string descriptions are given to allow for easy debug
+ * stringification. Note that this "parser" is really just lexing out these
+ * tokens - handling the actual structure of the file should be done in the
+ * callback. This is so that data can be streamed rather than all read into
+ * memory at once.
+ */
+#define KV_TOKENS(X) \
+ X(KV_IDENT, "ident") \
+ X(KV_IDENT_QUOTED, "quoted-ident") \
+ X(KV_VAL, "value") \
+ X(KV_VAL_QUOTED, "quoted-value") \
+ X(KV_NEST_START, "object-start") \
+ X(KV_NEST_END, "object-end")
+
+#define _ENUM(s, ignore) s,
+enum kv_token { KV_TOKENS(_ENUM) };
+#undef _ENUM
+
+typedef void (*kv_parser_cb)(enum kv_token type, const char *p, uint len,
+ void *ctxt);
+
+/*
+ * Feed a block of text into the lexer. This would usually be a block of data
+ * read in from a file.
+ *
+ * The lexer is reentrant and can be fed arbitrarily sized blocks of data at a
+ * time. The function may return early in the event of an error; you must check
+ * if parser->state == KV_PARSER_ERROR between calls! Continuing to try parsing
+ * after an error is undefined.
+ */
+// FIXME: revise API usage so errors aren't passed through "state" value
+void kv_parser_feed(struct kv_parser *this, const char *in, uint sz,
+ kv_parser_cb cb, void *ctxt);
+
+/*
+ * This indicates that parsing is done; if the state is midway through a token
+ * this will be converted into an error state which can be checked in the same
+ * way as noted above.
+ */
+void kv_parser_done(struct kv_parser *this);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/mem.h b/src/mem.h
new file mode 100644
index 0000000..2a3573d
--- /dev/null
+++ b/src/mem.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_MEMUTIL_H
+#define INC_MEMUTIL_H
+
+#include "intdefs.h"
+
+/* retrieves a 32-bit integer from an unaligned pointer; avoids UB, probably */
+static inline u32 mem_load32(const void *p) {
+ const uchar *cp = p;
+ return (u32)cp[0] | (u32)cp[1] << 8 | (u32)cp[2] << 16 | (u32)cp[3] << 24;
+}
+
+/* retrieves a 64-bit integer from an unaligned pointer; avoids UB, possibly */
+static inline u64 mem_load64(const void *p) {
+ return (u64)mem_load32(p) | (u64)mem_load32((uchar *)p + 4) << 32;
+}
+
+/* retrieves a pointer from an unaligned pointer-to-pointer; avoids UB, maybe */
+static inline void *mem_loadptr(const void *p) {
+#if defined(_WIN64) || defined(__x86_64__)
+ return (void *)mem_load64(p);
+#else
+ return (void *)mem_load32(p);
+#endif
+}
+
+/* retreives a signed offset from an unaligned pointer; avoids UB, hopefully */
+static inline ssize mem_loadoffset(const void *p) {
+ return (ssize)mem_loadptr(p);
+}
+
+/* stores a 32-bit integer to an unaligned pointer; avoids UB, most likely */
+static inline void mem_store32(void *p, u32 val) {
+ uchar *cp = p;
+ cp[0] = val; cp[1] = val >> 8; cp[2] = val >> 16; cp[3] = val >> 24;
+}
+
+/* stores a 64-bit integer to an unaligned pointer; avoids UB, I'd assume */
+static inline void mem_store64(void *p, u64 val) {
+ mem_store32(p, val); mem_store32((uchar *)p + 4, val >> 32);
+}
+
+/* stores a pointer value to an unaligned pointer; avoids UB, I guess */
+static inline void mem_storeptr(void *to, const void *val) {
+#if defined(_WIN64) || defined(__x86_64__)
+ mem_store64(to, (u64)val);
+#else
+ mem_store32(to, (u32)val);
+#endif
+}
+
+/* adds a byte count to a pointer, and returns something that can be assigned
+ * to any pointer type */
+static inline void *mem_offset(void *p, int off) { return (char *)p + off; }
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/noreturn.h b/src/noreturn.h
new file mode 100644
index 0000000..81b2bae
--- /dev/null
+++ b/src/noreturn.h
@@ -0,0 +1,11 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_NORETURN_H
+#define INC_NORETURN_H
+
+#undef noreturn
+#define noreturn _Noreturn void
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/os.c b/src/os.c
new file mode 100644
index 0000000..96e3c48
--- /dev/null
+++ b/src/os.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "intdefs.h"
+#include "os.h"
+
+#ifdef _WIN32
+// SystemFunction036 is the *real* name of "RtlGenRandom," and is also
+// incorrectly defined in system headers. Yay, Windows.
+int __stdcall SystemFunction036(void *buf, ulong sz);
+#endif
+
+bool os_mprot(void *addr, int len, int fl) {
+#ifdef _WIN32
+ ulong old;
+ return !!VirtualProtect(addr, len, fl, &old);
+#else
+ // round down address and round up size
+ addr = (void *)((ulong)addr & ~(4095));
+ len = len + 4095 & ~(4095);
+ return mprotect(addr, len, fl) != -1;
+#endif
+}
+
+#ifdef _WIN32
+void *os_dlsym(void *m, const char *s) {
+ return (void *)GetProcAddress(m, s);
+}
+#endif
+
+void os_randombytes(void *buf, int sz) {
+ // if these calls ever fail, the system is fundamentally broken with no
+ // recourse, so just loop until success. hopefully nothing will go wrong.
+#ifdef _WIN32
+ while (!SystemFunction036(buf, sz));
+#else
+ while (getentropy(buf, sz) == -1);
+#endif
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/os.h b/src/os.h
new file mode 100644
index 0000000..c74d2d0
--- /dev/null
+++ b/src/os.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_OS_H
+#define INC_OS_H
+
+#include <stdbool.h>
+
+/*
+ * Here we declare an absolute ton of wrappers, macros, compatibility shims,
+ * reimplementations and so on to try in vain to sweep the inconsistencies
+ * between Windows and not-Windows under the rug.
+ *
+ * If this file gets any bigger it might need to be split up a bit...
+ */
+
+#include <fcntl.h>
+#ifdef _WIN32
+#define NOMINMAX
+#define WIN32_LEAN_AND_MEAN
+#include <io.h>
+#include <wchar.h>
+#include <Windows.h>
+#else
+#include <dlfcn.h>
+#include <limits.h>
+#include <sys/mman.h>
+#include <unistd.h>
+#endif
+
+#include "intdefs.h"
+
+#ifdef _WIN32
+
+#define IMPORT __declspec(dllimport) // only needed for variables
+#define EXPORT __declspec(dllexport)
+void *os_dlsym(void *mod, const char *sym);
+#define os_char ushort
+#define _OS_CAT(L, x) L##x
+#define OS_LIT(x) _OS_CAT(L, x)
+#define os_snprintf _snwprintf
+#define os_strchr wcschr
+#define os_strcmp wcscmp
+#define os_strcpy wcscpy
+#define os_strlen wcslen
+#define strncasecmp _strnicmp // stupid!
+#define OS_DLSUFFIX ".dll"
+#ifndef PATH_MAX
+// XXX win32/crt has this dumb 260 limit even though the actual kernel imposes
+// no limit (though apparently NTFS has a limit of 65535). Theoerically we could
+// do some memes with UNC paths to extend it to at least have parity with Unix
+// PATH_MAX (4096), but for now we just kind of accept that Windows is a
+// disaster.
+#define PATH_MAX MAX_PATH
+#endif
+#define os_fopen _wfopen
+// yuck :(
+#define _os_open3(path, flags, mode) _wopen((path), (flags) | _O_BINARY, (mode))
+#define _os_open2(path, flags) _wopen((path), (flags) | _O_BINARY)
+#define _os_open(a, b, c, x, ...) x
+#define os_open(...) _os_open(__VA_ARGS__, _os_open3, _os_open2, _)(__VA_ARGS__)
+#define os_access _waccess
+#define os_stat _stat64
+// ucrt defines __stat64 to _stat64. we want _wstat64 to be the actual function
+#define _stat64(path, buf) _wstat64(path, buf)
+// why exactly _does_ windows prefix so many things with underscores?
+#define read _read
+#define write _write
+#define close _close
+#define O_RDONLY _O_RDONLY
+#define O_RDWR _O_RDWR
+#define O_CLOEXEC _O_NOINHERIT
+#define O_CREAT _O_CREAT
+#define O_EXCL _O_EXCL
+#define F_OK 0
+#define R_OK 4
+#define W_OK 2
+#define X_OK R_OK // there's no actual X bit
+#define alloca _alloca
+#define os_getenv _wgetenv
+#define OS_MAIN wmain
+// just dump this boilerplate here as well, I spose
+#define OS_WINDOWS_ERROR(arrayname) \
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), \
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), arrayname, \
+ sizeof(arrayname), 0)
+
+#else
+
+#ifdef __GNUC__
+#define EXPORT __attribute__((visibility("default")))
+#else
+#define EXPORT int novis[-!!"visibility attribute requires Clang or GCC"];
+#endif
+#define IMPORT
+#define os_dlsym dlsym
+#define os_char char
+#define OS_LIT(x) x
+#define os_snprintf snprintf
+#define os_strchr strchr
+#define os_strcmp strcmp
+#define os_strcpy strcpy
+#define os_strlen strlen
+#define OS_DLSUFFIX ".so"
+#define os_fopen fopen
+#define os_open open
+#define os_access access
+#define os_stat stat
+// unix mprot flags are much nicer but cannot be defined in terms of the windows
+// ones, so we use the windows ones and define them in terms of the unix ones.
+// another victory for stupid!
+#define PAGE_NOACCESS 0
+#define PAGE_READONLY PROT_READ
+#define PAGE_READWRITE PROT_READ | PROT_WRITE
+#define PAGE_EXECUTE_READ PROT_READ | PROT_EXEC
+#define PAGE_EXECUTE_READWRITE PROT_READ | PROT_WRITE | PROT_EXEC
+#define os_getenv getenv
+#define OS_MAIN main
+
+#endif
+
+bool os_mprot(void *addr, int len, int fl);
+/*
+ * NOTE: this should be called with a reasonably small buffer (e.g., the size of
+ * a private key). The maximum size of the buffer on Linux is 256, on Windows
+ * it's God Knows What.
+ */
+void os_randombytes(void *buf, int len);
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/ppmagic.h b/src/ppmagic.h
new file mode 100644
index 0000000..32c1f46
--- /dev/null
+++ b/src/ppmagic.h
@@ -0,0 +1,81 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_PPMAGIC_H
+#define INC_PPMAGIC_H
+
+/* random preprocessor shenanigans */
+
+#define _PPMAGIC_DO02(m, sep, x, y) m(x) sep m(y)
+#define _PPMAGIC_DO03(m, sep, x, y, z) m(x) sep m(y) sep m(z)
+#define _PPMAGIC_DO04(m, sep, w, x, y, z) m(w) sep m(x) sep m(y) sep m(z)
+#define _PPMAGIC_DO05(m, sep, x, ...) m(x) sep _PPMAGIC_DO04(m, sep, __VA_ARGS__)
+// repetitive nonsense {{{
+#define _PPMAGIC_DO06(m, sep, x, ...) m(x) sep _PPMAGIC_DO05(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO07(m, sep, x, ...) m(x) sep _PPMAGIC_DO06(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO08(m, sep, x, ...) m(x) sep _PPMAGIC_DO07(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO09(m, sep, x, ...) m(x) sep _PPMAGIC_DO08(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO10(m, sep, x, ...) m(x) sep _PPMAGIC_DO09(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO11(m, sep, x, ...) m(x) sep _PPMAGIC_DO10(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO12(m, sep, x, ...) m(x) sep _PPMAGIC_DO11(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO13(m, sep, x, ...) m(x) sep _PPMAGIC_DO12(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO14(m, sep, x, ...) m(x) sep _PPMAGIC_DO13(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO15(m, sep, x, ...) m(x) sep _PPMAGIC_DO14(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO16(m, sep, x, ...) m(x) sep _PPMAGIC_DO15(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO17(m, sep, x, ...) m(x) sep _PPMAGIC_DO16(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO18(m, sep, x, ...) m(x) sep _PPMAGIC_DO17(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO19(m, sep, x, ...) m(x) sep _PPMAGIC_DO18(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO20(m, sep, x, ...) m(x) sep _PPMAGIC_DO19(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO21(m, sep, x, ...) m(x) sep _PPMAGIC_DO20(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO22(m, sep, x, ...) m(x) sep _PPMAGIC_DO21(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO23(m, sep, x, ...) m(x) sep _PPMAGIC_DO22(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO24(m, sep, x, ...) m(x) sep _PPMAGIC_DO23(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO25(m, sep, x, ...) m(x) sep _PPMAGIC_DO24(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO26(m, sep, x, ...) m(x) sep _PPMAGIC_DO25(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO27(m, sep, x, ...) m(x) sep _PPMAGIC_DO26(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO28(m, sep, x, ...) m(x) sep _PPMAGIC_DO27(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO29(m, sep, x, ...) m(x) sep _PPMAGIC_DO28(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO30(m, sep, x, ...) m(x) sep _PPMAGIC_DO29(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO31(m, sep, x, ...) m(x) sep _PPMAGIC_DO30(m, sep, __VA_ARGS__)
+#define _PPMAGIC_DO32(m, sep, x, ...) m(x) sep _PPMAGIC_DO31(m, sep, __VA_ARGS__)
+// }}}
+
+#define _PPMAGIC_DO_N( \
+x01, x02, x03, x04, x05, x06, x07, x08, x09, x10, x11, x12, x13, x14, x15, x16, \
+x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31, x32, \
+ N, ...) \
+ _PPMAGIC_DO##N
+
+/*
+ * applies the given single-argument macro m to each of a list of up to 32
+ * parameters, with the optional token sep inserted in between.
+ */
+#define PPMAGIC_MAP(m, sep, ...) \
+ _PPMAGIC_DO_N(__VA_ARGS__, \
+ 32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+ 16, 15, 14, 13, 12, 11, 10, 09, 08, 07, 06, 05, 04, 03, 02, 01) \
+ (m, sep, __VA_ARGS__)
+
+/* expands to up to 32 case labels at once, for matching multiple values */
+#define CASES(...) PPMAGIC_MAP(case, :, __VA_ARGS__)
+
+#define _PPMAGIC_0x(n) 0x##n,
+/* expands to a byte array with each digit prefixed with 0x */
+#define HEXBYTES(...) {PPMAGIC_MAP(_PPMAGIC_0x, , __VA_ARGS__)}
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80 fdm=marker
diff --git a/src/sst.c b/src/sst.c
new file mode 100644
index 0000000..dbee4b7
--- /dev/null
+++ b/src/sst.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <stdbool.h>
+
+#include "con_.h"
+#include "demorec.h"
+#include "factory.h"
+#include "gamedata.h"
+#include "gameinfo.h"
+#include "gametype.h"
+#include "hook.h"
+#include "os.h"
+#include "vcall.h"
+#include "version.h"
+
+#define RGBA(r, g, b, a) (&(struct con_colour){(r), (g), (b), (a)})
+
+u32 _gametype_tag = 0; // spaghetti: no point making a .c file for 1 variable
+
+static int plugin_ver;
+// this is where we start dynamically adding virtual functions, see vtable[]
+// array below
+static const void **vtable_firstdiff;
+
+// most plugin callbacks are unused - define dummy functions for each signature
+static void VCALLCONV nop_v_v(void *this) {}
+static void VCALLCONV nop_b_v(void *this, bool b) {}
+static void VCALLCONV nop_p_v(void *this, void *p) {}
+static void VCALLCONV nop_pp_v(void *this, void *p1, void *p2) {}
+static void VCALLCONV nop_pii_v(void *this, void *p, int i1, int i2) {}
+static int VCALLCONV nop_p_i(void *this, void *p) { return 0; }
+static int VCALLCONV nop_pp_i(void *this, void *p1, void *p2) { return 0; }
+static int VCALLCONV nop_5pi_i(void *this, void *p1, void *p2, void *p3,
+ void *p4, void *p5, int i) { return 0; }
+static void VCALLCONV nop_ipipp_v(void *this, int i1, void *p1, int i2,
+ void *p2, void *p3) {}
+
+#ifdef __linux__
+// we need to keep this reference to dlclose() it later - see below
+static void *clientlib = 0;
+#endif
+
+// more source spaghetti wow!
+static void VCALLCONV SetCommandClient(void *this, int i) { con_cmdclient = i; }
+
+ifacefactory factory_client = 0, factory_server = 0, factory_engine = 0;
+
+// TODO(featgen): I wanted some nice fancy automatic feature system that
+// figures out the dependencies at build time and generates all the init glue
+// but we want to actually release the plugin this decade so for now I'm just
+// plonking ~~some bools~~ one bool here and worrying about it later. :^)
+static bool has_demorec = false;
+
+static bool do_load(ifacefactory enginef, ifacefactory serverf) {
+ factory_engine = enginef; factory_server = serverf;
+#ifndef __linux__
+ void *clientlib = 0;
+#endif
+ if (!gameinfo_init() || !con_init(enginef, plugin_ver)) return false;
+ const void **p = vtable_firstdiff;
+ if (GAMETYPE_MATCHES(Portal2)) *p++ = (void *)&nop_p_v; // ClientFullyConnect
+ *p++ = (void *)&nop_p_v; // ClientDisconnect
+ *p++ = (void *)&nop_pp_v; // ClientPutInServer
+ *p++ = (void *)&SetCommandClient; // SetCommandClient
+ *p++ = (void *)&nop_p_v; // ClientSettingsChanged
+ *p++ = (void *)&nop_5pi_i; // ClientConnect
+ *p++ = plugin_ver > 1 ? (void *)&nop_pp_i : (void *)&nop_p_i; // ClientCommand
+ *p++ = (void *)&nop_pp_i; // NetworkIDValidated
+ // remaining stuff here is backwards compatible, so added unconditionally
+ *p++ = (void *)&nop_ipipp_v; // OnQueryCvarValueFinished (002+)
+ *p++ = (void *)&nop_p_v; // OnEdictAllocated
+ *p = (void *)&nop_p_v; // OnEdictFreed
+
+#ifdef _WIN32
+ //if (gameinfo_serverlib) serverlib = GetModuleHandleW(gameinfo_serverlib);
+ if (gameinfo_clientlib) clientlib = GetModuleHandleW(gameinfo_clientlib);
+#else
+ // Linux Source load order seems to be different to the point where if we
+ // +plugin_load or use a vdf then RTLD_NOLOAD won't actually find these, so
+ // we have to just dlopen them normally - and then remember to decrement the
+ // refcount again later in do_unload() so nothing gets leaked
+ //if (gameinfo_serverlib) serverlib = dlopen(gameinfo_serverlib, 0);
+ if (gameinfo_clientlib) clientlib = dlopen(gameinfo_clientlib, 0);
+#endif
+ if (!clientlib) {
+ con_warn("sst: warning: couldn't get the game's client library\n");
+ goto nc;
+ }
+ factory_client = (ifacefactory)os_dlsym(clientlib, "CreateInterface");
+ if (!factory_client) {
+ con_warn("sst: warning: couldn't get client's CreateInterface\n");
+ }
+
+nc: gamedata_init();
+ // TODO(autojump): we'd init that here
+ has_demorec = demorec_init();
+
+ con_colourmsg(RGBA(64, 255, 64, 255),
+ NAME " v" VERSION " successfully loaded");
+ con_colourmsg(RGBA(255, 255, 255, 255), " for game ");
+ con_colourmsg(RGBA(0, 255, 255, 255), "%s\n", gameinfo_title);
+ return true;
+}
+
+static void do_unload(void) {
+ // TODO(autojump): we'd end that here
+ if (has_demorec) demorec_end();
+
+#ifdef __linux__
+ //if (serverlib) dlclose(serverlib);
+ if (clientlib) dlclose(clientlib);
+#endif
+ con_disconnect();
+}
+
+// since this is static/global, it only becomes false again when the plugin SO
+// is unloaded/reloaded
+static bool already_loaded = false;
+static bool skip_unload = false;
+
+static bool VCALLCONV Load(void *this, ifacefactory enginef,
+ ifacefactory serverf) {
+ if (already_loaded) {
+ con_warn("Already loaded! Doing nothing!\n");
+ skip_unload = true;
+ return false;
+ }
+ already_loaded = do_load(enginef, serverf);
+ skip_unload = !already_loaded;
+ return already_loaded;
+}
+
+static void Unload(void *this) {
+ // the game tries to unload on a failed load, for some reason
+ if (skip_unload) {
+ skip_unload = false;
+ return;
+ }
+ do_unload();
+}
+
+static void VCALLCONV Pause(void *this) {
+ con_warn(NAME " doesn't support plugin_pause - ignoring\n");
+}
+static void VCALLCONV UnPause(void *this) {
+ con_warn(NAME " doesn't support plugin_unpause - ignoring\n");
+}
+
+static const char *VCALLCONV GetPluginDescription(void *this) {
+ return LONGNAME " v" VERSION;
+}
+
+DEF_CCMD_HERE(sst_printversion, "Display plugin version information", 0) {
+ con_msg("v" VERSION "\n");
+}
+
+#define MAX_VTABLE_FUNCS 21
+static const void *vtable[MAX_VTABLE_FUNCS] = {
+ // start off with the members which (thankfully...) are totally stable
+ // between interface versions - the *remaining* members get filled in just
+ // in time by do_load() once we've figured out what engine branch we're on
+ (void *)&Load,
+ (void *)&Unload,
+ (void *)&Pause,
+ (void *)&UnPause,
+ (void *)&GetPluginDescription,
+ (void *)&nop_p_v, // LevelInit
+ (void *)&nop_pii_v, // ServerActivate
+ (void *)&nop_b_v, // GameFrame
+ (void *)&nop_v_v, // LevelShutdown
+ (void *)&nop_p_v // ClientActive
+ // At this point, Alien Swarm and Portal 2 add ClientFullyConnect, so we
+ // can't hardcode any more of the layout!
+};
+// end MUST point AFTER the last of the above entries
+static const void **vtable_firstdiff = vtable + 10;
+// this is equivalent to a class with no members!
+static const void *const *const plugin_obj = vtable;
+
+EXPORT const void *CreateInterface(const char *name, int *ret) {
+ if (!strncmp(name, "ISERVERPLUGINCALLBACKS00", 24)) {
+ if ((name[24] >= '1' || name[24] <= '3') && name[25] == '\0') {
+ if (ret) *ret = 0;
+ plugin_ver = name[24] - '0';
+ return &plugin_obj;
+ }
+ }
+ if (ret) *ret = 1;
+ return 0;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/tier0stub.c b/src/tier0stub.c
new file mode 100644
index 0000000..a043bea
--- /dev/null
+++ b/src/tier0stub.c
@@ -0,0 +1,19 @@
+/* This file is dedicated to the public domain. */
+
+// Produce a dummy tier0.dll/libtier0.so to allow linking without dlsym faff.
+// Windows needs additional care because it's dumb.
+
+#ifdef _WIN32
+#define F(name) __declspec(dllexport) void name(void) {}
+#define V(name) __declspec(dllexport) void *name;
+#else
+#define F(name) void *name;
+#define V(name) void *name;
+#endif
+
+F(Msg);
+F(Warning);
+// F(Error); // unused in plugin
+V(g_pMemAlloc);
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/udis86.c b/src/udis86.c
new file mode 100644
index 0000000..fcb3656
--- /dev/null
+++ b/src/udis86.c
@@ -0,0 +1,11 @@
+/* This file is dedicated to the public domain. */
+
+#include "3p/udis86/udis86.c"
+#include "3p/udis86/decode.c"
+#include "3p/udis86/itab.c"
+// this stuff is optional but llvm is smart enough to remove it if it's unused,
+// so we keep it in here to be able to use it conveniently for debugging etc.
+#include "3p/udis86/syn.c"
+#include "3p/udis86/syn-intel.c"
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/udis86.h b/src/udis86.h
new file mode 100644
index 0000000..ba5af90
--- /dev/null
+++ b/src/udis86.h
@@ -0,0 +1,12 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_UDIS86_H
+#define INC_UDIS86_H
+
+#include "3p/udis86/types.h"
+#include "3p/udis86/extern.h"
+#include "3p/udis86/itab.h"
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/unreachable.h b/src/unreachable.h
new file mode 100644
index 0000000..99c82b5
--- /dev/null
+++ b/src/unreachable.h
@@ -0,0 +1,14 @@
+/* This file is dedicated to the public domain. */
+
+#ifndef INC_UNREACHABLE_H
+#define INC_UNREACHABLE_H
+
+#if defined(__GNUC__) || defined(__clang__)
+#define unreachable __builtin_unreachable()
+#else
+#define unreachable do; while (0)
+#endif
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/vcall.h b/src/vcall.h
new file mode 100644
index 0000000..c92f8db
--- /dev/null
+++ b/src/vcall.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright © 2021 Michael Smith <mikesmiffy128@gmail.com>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+ * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+ * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+ * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+ * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+ * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+ * PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef INC_VCALL_H
+#define INC_VCALL_H
+
+/*
+ * Convenient facilities for calling simple (single-table) virtual functions on
+ * possibly-opaque pointers to C++ objects.
+ */
+
+#ifdef _WIN32
+#if defined(__GNUC__) || defined(__clang__)
+#define VCALLCONV __thiscall
+#else
+// XXX: could support MSVC via __fastcall and dummy param, but is there a point?
+#error C __thiscall support requires Clang or GCC
+#endif
+#else
+#define VCALLCONV
+#endif
+
+#define DECL_VFUNC0(ret, name, idx) \
+ enum { _VTIDX_##name = (idx) }; \
+ typedef ret (*VCALLCONV _VFUNC_##name)(void *this);
+
+#define DECL_VFUNC(ret, name, idx, ...) \
+ enum { _VTIDX_##name = (idx) }; \
+ typedef ret (*VCALLCONV _VFUNC_##name)(void *this, __VA_ARGS__);
+
+// not bothering to provide a zero-argument version because the main use of
+// this is vararg functions, which error if __thiscall
+#define DECL_VFUNC_CDECL(ret, name, idx, ...) \
+ enum { _VTIDX_##name = (idx) }; \
+ typedef ret (*_VFUNC_##name)(void *this, __VA_ARGS__);
+
+#define VFUNC(x, name) ((*(_VFUNC_##name **)(x))[_VTIDX_##name])
+
+#define VCALL0(x, name) (VFUNC(x, name)(x))
+#define VCALL(x, name, ...) VFUNC(x, name)(x, __VA_ARGS__)
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/src/version.h b/src/version.h
new file mode 100644
index 0000000..b75b78f
--- /dev/null
+++ b/src/version.h
@@ -0,0 +1,5 @@
+#define NAME "SST"
+#define LONGNAME "Source Speedrun Tools"
+#define VERSION_MAJOR 0
+#define VERSION_MINOR 1
+#define VERSION "Beta 0.1"
diff --git a/test/bitbuf.test.c b/test/bitbuf.test.c
new file mode 100644
index 0000000..58d1c4d
--- /dev/null
+++ b/test/bitbuf.test.c
@@ -0,0 +1,34 @@
+/* This file is dedicated to the public domain. */
+
+{.desc = "the bit buffer implementation"};
+
+#include "../src/bitbuf.h"
+#include "../src/intdefs.h"
+
+#include <stdio.h>
+#include <string.h>
+
+static union {
+ char buf[512];
+ bitbuf_cell buf_align[512 / sizeof(bitbuf_cell)];
+} bb_buf;
+static struct bitbuf bb = {bb_buf.buf, 512, 512 * 8, 0, false, false, "test"};
+
+TEST("The possible UB in bitbuf_appendbuf shouldn't trigger horrible bugs", 0) {
+ char unalign[3] = {'X', 'X', 'X'};
+ char _buf[32 + sizeof(bitbuf_cell)];
+ char *buf = _buf;
+ if (bitbuf_align <= 1) {
+ // *shouldn't* happen
+ fputs("what's going on with the alignment???\n", stderr);
+ return false;
+ }
+ // make sure the pointer is definitely misaligned
+ while (!((usize)buf % bitbuf_align)) ++buf;
+
+ memcpy(buf, "Misaligned test buffer contents!", 32);
+ bitbuf_appendbuf(&bb, buf, 32);
+ return !memcmp(bb.buf, buf, 32);
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/test/hook.test.c b/test/hook.test.c
new file mode 100644
index 0000000..a918e22
--- /dev/null
+++ b/test/hook.test.c
@@ -0,0 +1,45 @@
+/* This file is dedicated to the public domain. */
+
+{.desc = "inline function hooking"};
+
+#ifdef _WIN32
+
+#include "../src/udis86.c"
+#include "../src/os.c"
+#include "../src/hook.c"
+
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+// stubs
+void con_warn(const char *msg, ...) {
+ va_list l;
+ va_start(l, msg);
+ vfprintf(stderr, msg, l);
+ va_end(l);
+}
+
+__attribute__((noinline))
+static int some_function(int a, int b) { return a + b; }
+static int (*orig_some_function)(int, int);
+static int some_hook(int a, int b) {
+ return orig_some_function(a, b) + 5;
+}
+
+TEST("Inline hooks should be able to wrap the original function", 0) {
+ orig_some_function = hook_inline(&some_function, &some_hook);
+ if (!orig_some_function) return false;
+ return some_function(5, 5) == 15;
+}
+
+TEST("Inline hooks should be removable again", 0) {
+ orig_some_function = hook_inline(&some_function, &some_hook);
+ if (!orig_some_function) return false;
+ unhook_inline(orig_some_function);
+ return some_function(5, 5) == 10;
+}
+
+#endif
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/test/kv.test.c b/test/kv.test.c
new file mode 100644
index 0000000..cd08d16
--- /dev/null
+++ b/test/kv.test.c
@@ -0,0 +1,49 @@
+/* This file is dedicated to the public domain. */
+
+{.desc = "the KeyValues parser"};
+
+// undef conflicting macros
+#undef ERROR // windows.h
+#undef OUT // "
+#undef EOF // stdio.h
+#include "../src/kv.c"
+
+#include "../src/intdefs.h"
+#include "../src/noreturn.h"
+
+static noreturn die(const struct kv_parser *kvp) {
+ fprintf(stderr, "parse error: %d:%d: %s\n", kvp->line, kvp->col,
+ kvp->errmsg);
+ exit(1);
+}
+
+static void tokcb(enum kv_token type, const char *p, uint len,
+ void *ctxt) {
+ // nop - we're just testing the tokeniser
+}
+
+static const char data[] =
+"KeyValues {\n\tKey/1\tVal1! \tKey2\nVal2// comment\n\"String Key\"// also comment\nVal3 Key4{ Key5 \"Value Five\" } // one more\n\t\n}"
+;
+static const int sz = sizeof(data) - 1;
+
+TEST("parsing should work with any buffer size", 0) {
+ for (int chunksz = 3; chunksz <= sz; ++chunksz) {
+ struct kv_parser kvp = {0};
+ // sending data in chunks to test reentrancy
+ for (int chunk = 0; chunk * chunksz < sz; ++chunk) {
+ int thischunk = chunksz;
+ if (chunk * chunksz + thischunk > sz) {
+ thischunk = sz - chunk * chunksz;
+ }
+ kv_parser_feed(&kvp, data + chunk * chunksz, thischunk,
+ tokcb, 0);
+ if (kvp.state == KV_PARSER_ERROR) die(&kvp);
+ }
+ kv_parser_done(&kvp);
+ if (kvp.state == KV_PARSER_ERROR) die(&kvp);
+ }
+ return true;
+}
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/test/test.h b/test/test.h
new file mode 100644
index 0000000..3893359
--- /dev/null
+++ b/test/test.h
@@ -0,0 +1,234 @@
+/*
+ * test.h - Michael Smith <mikesmiffy128@gmail.com>
+ * I hereby dedicate the contents of this file to the public domain. In
+ * jurisdictions with no public domain, go you your supreme court and get a
+ * public domain.
+ */
+
+/*
+ * NOTE: This is a hacky black magic Windows port! If you only want Unix
+ * support, the less-atrocious original resides in a Git repository:
+ * https://gitlab.com/mikesmiffy128/test.h
+ */
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <string.h>
+#ifdef _WIN32
+#include <Windows.h>
+#else
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+#include <sys/select.h>
+#endif
+
+#ifdef __clang__
+#define _TEST_SILENCE_CLANG \
+ _Pragma("clang diagnostic push") \
+ _Pragma("clang diagnostic ignored \"-Winitializer-overrides\"")
+#define _TEST_UNSILENCE_CLANG \
+ _Pragma("clang diagnostic pop")
+#else
+#define _TEST_SILENCE_CLANG
+#define _TEST_UNSILENCE_CLANG
+#endif
+
+static struct _test_desc {
+ char *desc;
+ int default_flags;
+} _test_desc;
+
+static struct _test {
+ char *desc;
+ /* Optional attributes that can be set to further customise the test case */
+ // Note: the first attribute here has to have a default value of 0 because
+ // of __VA_ARGS__ requiring at least one argument
+ int expected_exit; /* expected exit from forked child (255 is reserved!) */
+ int flags; /* see flags below */
+ int timeout; /* milisecond timeout on forked child (if forking) */
+ bool (*_f)(void);
+ struct _test *_next;
+} *_tests = 0, **_tests_tail = &_tests;
+static int _ntests = 0;
+
+/* Test flags - currently just NOFORK but you could add your own custom ones! */
+#define NOFORK 1
+
+#define _TEST_USE_DEFAULT_FLAGS -1 // indicator to use global default_flags
+#define _TEST_DEFAULT_TIMEOUT 1000 // 1s seems reasonable
+
+#define _TESTCAT1(a, b) a##b
+#define _TESTCAT(a, b) _TESTCAT1(a, b)
+#define _TESTSTR1(x) #x
+#define _TESTSTR(x) _TESTSTR1(x)
+#define TEST(desc_, ...) \
+ static bool _TESTCAT(_test_f_, __LINE__)(void); \
+ _TEST_SILENCE_CLANG \
+ static struct _test _TESTCAT(_test_, __LINE__) = { \
+ .flags = _TEST_USE_DEFAULT_FLAGS, \
+ .timeout = _TEST_DEFAULT_TIMEOUT, \
+ .desc = __FILE__":"_TESTSTR(__LINE__)": "desc_, \
+ __VA_ARGS__, \
+ ._f = &_TESTCAT(_test_f_, __LINE__) \
+ }; \
+ _TEST_UNSILENCE_CLANG \
+ /* constructor adds tests to the list tail to run them in order */ \
+ __attribute__((constructor(100 + __LINE__))) \
+ static void _TESTCAT(_test_init_, __LINE__)(void) { \
+ if (_TESTCAT(_test_, __LINE__).flags == _TEST_USE_DEFAULT_FLAGS) { \
+ _TESTCAT(_test_, __LINE__).flags = _test_desc.default_flags; \
+ } \
+ _TESTCAT(_test_, __LINE__)._next = *_tests_tail; \
+ *_tests_tail = &_TESTCAT(_test_, __LINE__); \
+ _tests_tail = &_TESTCAT(_test_, __LINE__)._next; \
+ ++_ntests; \
+ } \
+ static bool _TESTCAT(_test_f_, __LINE__)(void)
+
+#ifdef _WIN32
+// since we can't fork, we CreateProcess ourselves and use WriteProcessMemory
+// to set this function pointer to call the test we want to call
+static volatile bool (*_test_entry_f)(void) = 0;
+unsigned short _test_exepath[MAX_PATH];
+#define _test_perror_win(thing) do { \
+ char err[128]; \
+ FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, 0, GetLastError(), \
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), err, sizeof(err), 0); \
+ fprintf(stderr, thing ": %s\n", err); \
+ return false; \
+} while (0)
+#else
+static sigset_t _test_sigmask = {0};
+#endif
+
+static bool _run_test(struct _test *t) {
+ if (t->flags & NOFORK) return t->_f();
+
+#ifdef _WIN32
+ STARTUPINFOW startinfo = {0};
+ PROCESS_INFORMATION info;
+ if (!CreateProcessW(_test_exepath, L"", 0, 0, 1, CREATE_SUSPENDED, 0, 0,
+ &startinfo, &info)) {
+ _test_perror_win("CreateProcess");
+ }
+ if (!WriteProcessMemory(info.hProcess, (void *)&_test_entry_f, &t->_f,
+ sizeof(t->_f), 0)) {
+ TerminateProcess(info.hProcess, -1);
+ _test_perror_win("WriteProcessMemory");
+ }
+ ResumeThread(info.hThread);
+ bool success;
+ if (t->timeout) {
+ if (WaitForSingleObject(info.hProcess, t->timeout) == WAIT_TIMEOUT) {
+ TerminateProcess(info.hProcess, -1);
+ fprintf(stderr, "child process timed out after %d milliseconds\n",
+ t->timeout);
+ success = false;
+ goto r;
+ }
+ }
+ else {
+ WaitForSingleObject(info.hProcess, INFINITE);
+ }
+ unsigned long status;
+ GetExitCodeProcess(info.hProcess, &status);
+ success = status == t->expected_exit;
+r: CloseHandle(info.hProcess);
+ CloseHandle(info.hThread);
+ return success;
+#else
+ pid_t pid = fork();
+ if (pid == -1) {
+ perror("fork");
+ return false;
+ }
+ if (!pid) {
+ bool ret = t->_f();
+ if (!ret) exit(255);
+ exit(t->expected_exit);
+ }
+ if (t->timeout) {
+ struct timespec ts = { t->timeout / 1000, (t->timeout % 1000) * 1000000 };
+ if (!pselect(0, 0, 0, 0, &ts, &_test_sigmask)) {
+ // if pselect returned zero it must've timed out
+ fprintf(stderr, "child process timed out after %d milliseconds\n",
+ t->timeout);
+ kill(pid, SIGKILL); // XXX should this be a less harsh signal?
+ waitpid(pid, 0, 0); // still have to reap the zombie process
+ return false;
+ }
+ }
+ // either there was no timeout value or pselect errored meaning we should
+ // have something to wait() on!
+ int status;
+ wait(&status);
+ if (WIFEXITED(status)) {
+ return WEXITSTATUS(status) == t->expected_exit;
+ }
+ else /* WIFSIGNALED(status) */ {
+ fprintf(stderr, "child process killed by signal %d (%s)\n",
+ WTERMSIG(status), strsignal(WTERMSIG(status)));
+ return false;
+ }
+#endif
+}
+
+#ifndef _WIN32
+static void _test_sigchld(int sig) {}
+#endif
+
+/*
+ * Main test driver, does the important stuff
+ */
+int main(void) {
+#ifdef _WIN32
+ // if _test_entry_f points at something, we're the """forked""" child
+ if (_test_entry_f) return !_test_entry_f();
+ GetModuleFileNameW(0, _test_exepath, sizeof(_test_exepath) /
+ sizeof(*_test_exepath));
+ // make the output look correct
+ void *con = GetStdHandle(STD_OUTPUT_HANDLE);
+ unsigned long conmode;
+ GetConsoleMode(con, &conmode);
+ SetConsoleMode(con, conmode | ENABLE_VIRTUAL_TERMINAL_PROCESSING);
+#else
+ // set up no-op SIGCHLD handling so we can (ab)use pselect() to do race-free
+ // timeouts
+ struct sigaction sa;
+ sigfillset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = &_test_sigchld;
+ sigaction(SIGCHLD, &sa, 0);
+ sigaddset(&_test_sigmask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &_test_sigmask, 0);
+ sigemptyset(&_test_sigmask);
+#endif
+
+ int thistest = 1;
+ bool failed = false;
+ for (struct _test *t = _tests; t; t = t->_next, ++thistest) {
+ if (!_run_test(t)) {
+ if (!failed) {
+ fprintf(stderr, "\
+\x1b[1;31m==== TESTS FAILED ====\x1b[0m\n\
+Testing \x1b[36m%s\x1b[0m failed on the following cases:\n\
+", _test_desc.desc);
+ }
+ failed = true;
+ fprintf(stderr, "[%02d/%02d] %s\n", thistest, _ntests, t->desc);
+ }
+ }
+#ifdef _WIN32
+ SetConsoleMode(con, conmode);
+#endif
+ return !!failed;
+}
+
+// get any normal main()s out the way in the tested code
+#define main _main
+
+static struct _test_desc _test_desc = // user input follows this header
+
+// vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/tools/todo b/tools/todo
new file mode 100644
index 0000000..7903eb3
--- /dev/null
+++ b/tools/todo
@@ -0,0 +1,5 @@
+#!/bin/sh -e
+# This file is dedicated to the public domain.
+
+. "$0.sh"
+todo "$@"
diff --git a/tools/todo.sh b/tools/todo.sh
new file mode 100644
index 0000000..44c7929
--- /dev/null
+++ b/tools/todo.sh
@@ -0,0 +1,35 @@
+# This file is dedicated to the public domain.
+
+todo() {
+ if [ $# = 0 ]; then
+ printf "Active TODO list:\n\n"
+ ls TODO/ | {
+ while read _l; do
+ printf " * %s: " "$_l"
+ head -n1 "TODO/$_l"
+ done
+ }
+ return
+ fi
+ if [ $# != 1 ]; then
+ echo "expected 0 or 1 argument(s)"
+ return
+ fi
+ if [ -f "TODO/$1" ]; then
+ printf "Active TODO item: "
+ _f="TODO/$1"
+ elif [ -f "TODO/.$1" ]; then
+ printf "Inactive TODO item: "
+ _f="TODO/.$1"
+ else
+ echo "TODO item not found: $1"
+ return
+ fi
+ head -n1 "$_f"
+ printf "\n"
+ sed -n '/^====$/,$p' "$_f"
+ printf "====\n\nMentions in project:\n"
+ git grep -Fn "TODO($1)" || echo "<none>"
+}
+
+# vi: sw=4 ts=4 noet tw=80 cc=80
diff --git a/tools/todo.vim b/tools/todo.vim
new file mode 100644
index 0000000..04c704d
--- /dev/null
+++ b/tools/todo.vim
@@ -0,0 +1,41 @@
+" This file is dedicated to the public domain.
+
+function! Todo(...)
+ if exists("a:1") && a:1 != ""
+ copen
+ " cex "" | cadde to avoid insta-jumping
+ if &shell == "cmd.exe"
+ cex "" | cadde system("git grep -nF TODO(".shellescape(a:1).")")
+ else
+ cex "" | cadde system("git grep -nF \"TODO(\"".shellescape(a:1)."\\)")
+ endif
+ else
+ " just displaying like this for now...
+ if &shell == "cmd.exe"
+ " FIXME: write a Windows batch equivalent!? in the meantime, you
+ " need a Unix shell to track issues :^)
+ cex "" | cclose | !sh tools/todo
+ else
+ cex "" | cclose | !tools/todo
+ endif
+ endif
+endfunction
+
+function! TodoEdit(...)
+ if exists("a:1") && a:1 != ""
+ exec "tabe TODO/".a:1
+ if line('$') == 1 && getline(1) == ''
+ normal o====
+ 1
+ else
+ 3 " XXX should really search for ====, but this is fine for now
+ endif
+ else
+ echoerr "Specify an issue ID"
+ endif
+endfunction
+
+command! -nargs=? Todo call Todo("<args>")
+command! -nargs=? TodoEdit call TodoEdit("<args>")
+
+" vi: sw=4 ts=4 noet tw=80 cc=80