diff --git a/build/Makefile.global b/build/Makefile.global index 14d90a1f3da9d..acf45f9a15cac 100644 --- a/build/Makefile.global +++ b/build/Makefile.global @@ -119,9 +119,6 @@ clean: find . -name \*.so | xargs rm -f find . -name .libs -a -type d|xargs rm -rf rm -f libphp.la $(SAPI_CLI_PATH) $(SAPI_CGI_PATH) $(SAPI_LITESPEED_PATH) $(SAPI_FPM_PATH) $(OVERALL_TARGET) modules/* libs/* - rm -f ext/opcache/jit/zend_jit_x86.c - rm -f ext/opcache/jit/zend_jit_arm64.c - rm -f ext/opcache/minilua rm -f ext/opcache/jit/ir/gen_ir_fold_hash rm -f ext/opcache/jit/ir/minilua rm -f ext/opcache/jit/ir/ir_fold_hash.h diff --git a/ext/opcache/config.m4 b/ext/opcache/config.m4 index 4fa403337b04c..857708783efbc 100644 --- a/ext/opcache/config.m4 +++ b/ext/opcache/config.m4 @@ -24,13 +24,6 @@ PHP_ARG_WITH([capstone],, [no], [no]) -PHP_ARG_ENABLE([opcache-jit-ir], - [whether to enable JIT based on IR framework], - [AS_HELP_STRING([--disable-opcache-jit-ir], - [Disable JIT based on IR framework (use old JIT)])], - [yes], - [no]) - if test "$PHP_OPCACHE" != "no"; then dnl Always build as shared extension @@ -51,52 +44,7 @@ if test "$PHP_OPCACHE" != "no"; then esac fi - if test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "no" ; then - AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT]) - ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_gdb.c jit/zend_jit_vm_helpers.c" - - dnl Find out which ABI we are using. - case $host_alias in - x86_64-*-darwin*) - DASM_FLAGS="-D X64APPLE=1 -D X64=1" - DASM_ARCH="x86" - ;; - x86_64*) - DASM_FLAGS="-D X64=1" - DASM_ARCH="x86" - ;; - i[[34567]]86*) - DASM_ARCH="x86" - ;; - x86*) - DASM_ARCH="x86" - ;; - aarch64*) - DASM_FLAGS="-D ARM64=1" - DASM_ARCH="arm64" - ;; - esac - - if test "$PHP_THREAD_SAFETY" = "yes"; then - DASM_FLAGS="$DASM_FLAGS -D ZTS=1" - fi - - AS_IF([test x"$with_capstone" = "xyes"],[ - PKG_CHECK_MODULES([CAPSTONE],[capstone >= 3.0.0],[ - AC_DEFINE([HAVE_CAPSTONE], [1], [Capstone is available]) - PHP_EVAL_LIBLINE($CAPSTONE_LIBS, OPCACHE_SHARED_LIBADD) - PHP_EVAL_INCLINE($CAPSTONE_CFLAGS) - ],[ - AC_MSG_ERROR([capstone >= 3.0 required but not found]) - ]) - ]) - - PHP_SUBST(DASM_FLAGS) - PHP_SUBST(DASM_ARCH) - - JIT_CFLAGS= - - elif test "$PHP_OPCACHE_JIT" = "yes" -a "$PHP_OPCACHE_JIT_IR" = "yes"; then + if test "$PHP_OPCACHE_JIT" = "yes" ; then AC_DEFINE(HAVE_JIT, 1, [Define to enable JIT]) AC_DEFINE(ZEND_JIT_IR, 1, [Use JIT IR framework]) ZEND_JIT_SRC="jit/zend_jit.c jit/zend_jit_vm_helpers.c jit/ir/ir.c jit/ir/ir_strtab.c \ @@ -383,9 +331,7 @@ int main(void) { if test "$PHP_OPCACHE_JIT" = "yes"; then PHP_ADD_BUILD_DIR([$ext_builddir/jit], 1) - if test "$PHP_OPCACHE_JIT_IR" = "yes"; then - PHP_ADD_BUILD_DIR([$ext_builddir/jit/ir], 1) - fi + PHP_ADD_BUILD_DIR([$ext_builddir/jit/ir], 1) PHP_ADD_MAKEFILE_FRAGMENT($ext_srcdir/jit/Makefile.frag) fi PHP_SUBST(OPCACHE_SHARED_LIBADD) diff --git a/ext/opcache/config.w32 b/ext/opcache/config.w32 index da60492b59f7e..24b4acaabcdc0 100644 --- a/ext/opcache/config.w32 +++ b/ext/opcache/config.w32 @@ -5,8 +5,6 @@ if (PHP_OPCACHE != "no") { ARG_ENABLE("opcache-jit", "whether to enable JIT", "yes"); - ARG_ENABLE("opcache-jit-ir", "whether to enable JIT based on IR framework", "yes"); - ZEND_EXTENSION('opcache', "\ ZendAccelerator.c \ zend_accelerator_blacklist.c \ @@ -20,26 +18,7 @@ if (PHP_OPCACHE != "no") { zend_shared_alloc.c \ shared_alloc_win32.c", true, "/DZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); - if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "no") { - if (CHECK_HEADER_ADD_INCLUDE("dynasm/dasm_x86.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) { - var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1"; - if (PHP_ZTS == "yes") { - dasm_flags += " -D ZTS=1"; - } - DEFINE("DASM_FLAGS", dasm_flags); - DEFINE("DASM_ARCH", "x86"); - - AC_DEFINE('HAVE_JIT', 1, 'Define to enable JIT'); - /* XXX read this dynamically */ - /*ADD_FLAG("CFLAGS_OPCACHE", "/D DASM_VERSION=10400");*/ - - ADD_MAKEFILE_FRAGMENT(configure_module_dirname + "\\jit\\Makefile.frag.w32"); - - ADD_SOURCES(configure_module_dirname + "\\jit", "zend_jit.c zend_jit_vm_helpers.c", "opcache", "ext\\opcache\\jit"); - } else { - WARNING("JIT not enabled, headers not found"); - } - } else if (PHP_OPCACHE_JIT == "yes" && PHP_OPCACHE_JIT_IR == "yes") { + if (PHP_OPCACHE_JIT == "yes") { if (CHECK_HEADER_ADD_INCLUDE("ir/ir.h", "CFLAGS_OPCACHE", PHP_OPCACHE + ";ext\\opcache\\jit")) { var dasm_flags = (X64 ? "-D X64=1" : "") + (X64 ? " -D X64WIN=1" : "") + " -D WIN=1"; var ir_target = (X64 ? "IR_TARGET_X64" : "IR_TARGET_X86"); diff --git a/ext/opcache/jit/Makefile.frag b/ext/opcache/jit/Makefile.frag index 07a826764ed72..4aec791396771 100644 --- a/ext/opcache/jit/Makefile.frag +++ b/ext/opcache/jit/Makefile.frag @@ -1,5 +1,3 @@ -ifdef IR_TARGET -# New IR based JIT $(builddir)/jit/ir/minilua: $(srcdir)/jit/ir/dynasm/minilua.c $(BUILD_CC) $(srcdir)/jit/ir/dynasm/minilua.c -lm -o $@ @@ -22,26 +20,6 @@ $(builddir)/jit/zend_jit.lo: \ $(srcdir)/jit/zend_jit_helpers.c \ $(srcdir)/jit/zend_jit_ir.c -else -# Old DynAsm based JIT -$(builddir)/minilua: $(srcdir)/jit/dynasm/minilua.c - $(BUILD_CC) $(srcdir)/jit/dynasm/minilua.c -lm -o $@ - -$(builddir)/jit/zend_jit_$(DASM_ARCH).c: $(srcdir)/jit/zend_jit_$(DASM_ARCH).dasc $(srcdir)/jit/dynasm/*.lua $(builddir)/minilua - $(builddir)/minilua $(srcdir)/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ $(srcdir)/jit/zend_jit_$(DASM_ARCH).dasc - -$(builddir)/jit/zend_jit.lo: \ - $(builddir)/jit/zend_jit_$(DASM_ARCH).c \ - $(srcdir)/jit/zend_jit_helpers.c \ - $(srcdir)/jit/zend_jit_disasm.c \ - $(srcdir)/jit/zend_jit_gdb.c \ - $(srcdir)/jit/zend_jit_perf_dump.c \ - $(srcdir)/jit/zend_jit_vtune.c \ - $(srcdir)/jit/zend_jit_trace.c \ - $(srcdir)/jit/zend_elf.c - -endif - # For non-GNU make, jit/zend_jit.lo and ./jit/zend_jit.lo are considered distinct targets. # Use this workaround to allow building from inside ext/opcache. jit/zend_jit.lo: $(builddir)/jit/zend_jit.lo diff --git a/ext/opcache/jit/Makefile.frag.w32 b/ext/opcache/jit/Makefile.frag.w32 index f2c1995fc79ea..7caf814588705 100644 --- a/ext/opcache/jit/Makefile.frag.w32 +++ b/ext/opcache/jit/Makefile.frag.w32 @@ -1,6 +1,3 @@ -!if "$(IR_TARGET)" != "" -# New IR based JIT - $(BUILD_DIR)\\minilua.exe: ext\opcache\jit\ir\dynasm\minilua.c @if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe $(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\ir\dynasm\minilua.c @@ -39,24 +36,3 @@ $(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \ ext\opcache\jit\zend_jit_helpers.c \ ext\opcache\jit\ir\ir.h \ ext\opcache\jit\ir\ir_builder.h - -!else -# Old DynAsm based JIT - -$(BUILD_DIR)\\minilua.exe: ext\opcache\jit\dynasm\minilua.c - @if exist $(BUILD_DIR)\\minilua.exe del $(BUILD_DIR)\\minilua.exe - $(PHP_CL) /Fo$(BUILD_DIR)\ /Fd$(BUILD_DIR)\ /Fp$(BUILD_DIR)\ /FR$(BUILD_DIR) /Fe$(BUILD_DIR)\minilua.exe ext\opcache\jit\dynasm\minilua.c - -ext\opcache\jit\zend_jit_x86.c: ext\opcache\jit\zend_jit_x86.dasc $(BUILD_DIR)\\minilua.exe - @if exist ext\opcache\jit\zend_jit_x86.c del ext\opcache\jit\zend_jit_x86.c - $(BUILD_DIR)\\minilua.exe ext/opcache/jit/dynasm/dynasm.lua $(DASM_FLAGS) -o $@ ext/opcache/jit/zend_jit_x86.dasc - -$(BUILD_DIR)\ext\opcache\jit\zend_jit.obj: \ - ext/opcache/jit/zend_jit_x86.c \ - ext/opcache/jit/zend_jit_helpers.c \ - ext/opcache/jit/zend_jit_disasm.c \ - ext/opcache/jit/zend_jit_gdb.c \ - ext/opcache/jit/zend_jit_perf_dump.c \ - ext/opcache/jit/zend_jit_trace.c \ - ext/opcache/jit/zend_jit_vtune.c -!endif diff --git a/ext/opcache/jit/README-IR.md b/ext/opcache/jit/README-IR.md deleted file mode 100644 index b547792e493d8..0000000000000 --- a/ext/opcache/jit/README-IR.md +++ /dev/null @@ -1,32 +0,0 @@ -New JIT implementation -====================== - -This branch provides a new JIT implementation based on [IR - Lightweight -JIT Compilation Framework](https://github.com/dstogov/ir). - -As opposed to the PHP 8.* JIT approach that generates native code directly from -PHP byte-code, this implementation generates intermediate representation (IR) -and delegates all lower-level tasks to the IR Framework. IR for JIT is like an -AST for compiler. - -Key benefits of the new JIT implementation: -- Usage of IR opens possibilities for better optimization and register - allocation (the resulting native code is more efficient) -- PHP doesn't have to care about most low-level details (different CPUs, - calling conventions, TLS details, etc) -- it's much easier to implement support for new targets (e.g. RISCV) -- IR framework is going to be developed separately from PHP and may accept - contributions from other projects (new optimizations, improvements, bug fixes) - -Disadvantages: -- JIT compilation becomes slower (this is almost invisible for tracing - JIT, but function JIT compilation of Wordpress becomes 4 times slower) - -The necessary part of the IR Framework is embedded into php-src. So, the PR -doesn't introduce new dependencies. - -The new JIT implementation successfully passes all CI workflows, but it's still -not mature and may cause failures. To reduce risks, this patch doesn't remove -the old JIT implementation (that is the same as PHP-8.3 JIT). It's possible -to build PHP with the old JIT by configuring with **--disable-opcache-jit-ir**. -In the future the old implementation should be removed. diff --git a/ext/opcache/jit/README.md b/ext/opcache/jit/README.md index 3ba6fe2abe3af..6ec58378acc7e 100644 --- a/ext/opcache/jit/README.md +++ b/ext/opcache/jit/README.md @@ -2,33 +2,10 @@ Opcache JIT =========== This is the implementation of Opcache's JIT (Just-In-Time compiler), -This converts the PHP Virtual Machine's opcodes into x64/x86 assembly, -on POSIX platforms and Windows. - -It generates native code directly from PHP byte-code and information collected -by the SSA static analysis framework (a part of the opcache optimizer). -Code is usually generated separately for each PHP byte-code instruction. Only -a few combinations are considered together (e.g. compare + conditional jump). - -See [the JIT RFC](https://wiki.php.net/rfc/jit) for more details. - -DynAsm ------- - -This uses [DynAsm](https://luajit.org/dynasm.html) (developed for LuaJIT project) -for the generation of native code. It's a very lightweight and advanced tool, -but does assume good, and very low-level development knowledge of target -assembler languages. In the past we tried LLVM, but its code generation speed -was almost 100 times slower, making it prohibitively expensive to use. - -[The unofficial DynASM Documentation](https://corsix.github.io/dynasm-doc/tutorial.html) -has a tutorial, reference, and instruction listing. - -In x86 builds, `zend_jit_x86.dasc` gets automatically converted to `zend_jit_x86.c` by the bundled -`dynasm` during `make`. - -In arm64 builds, `zend_jit_arm64.dasc` gets automatically converted to `zend_jit_arm64.c` by the bundled -`dynasm` during `make`. +This converts the PHP Virtual Machine's opcodes into Intermediate +Representation and uses [IR - Lightweight JIT Compilation Framework](https://github.com/dstogov/ir) +to produce optimized native code. The necessary part of the IR +Framework is embedded into php-src. Running tests of the JIT ------------------------ @@ -62,17 +39,6 @@ Note that the JIT supports 3 different architectures: `X86_64`, `i386`, and `arm Miscellaneous ------------- -### Checking dasc files for in a different architecture - -The following command can be run to manually check if the modified `.dasc code` is at least transpilable -for an architecture you're not using, e.g.: - -For arm64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D ARM64=1 -o ext/opcache/jit/zend_jit_arm64.ignored.c ext/opcache/jit/zend_jit_arm64.dasc` - -For x86_64: `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -D X64=1 -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc` - -For i386 (i.e. 32-bit): `ext/opcache/minilua ext/opcache/jit/dynasm/dynasm.lua -o ext/opcache/jit/zend_jit_x86.ignored.c ext/opcache/jit/zend_jit_x86.dasc` - ### How to build 32-bit builds on x86_64 environments Refer to [../../../.github/workflows/push.yml](../../../.github/workflows/push.yml) for examples of diff --git a/ext/opcache/jit/dynasm/dasm_arm.h b/ext/opcache/jit/dynasm/dasm_arm.h deleted file mode 100644 index ebcf4ac0ec13f..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_arm.h +++ /dev/null @@ -1,461 +0,0 @@ -/* -** DynASM ARM encoding engine. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, - DASM_IMM, DASM_IMM12, DASM_IMM16, DASM_IMML8, DASM_IMML12, DASM_IMMV8, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - int i; - for (i = 0; i < 16; i++, n = (n << 2) | (n >> 30)) - if (n <= 255) return (int)(n + (i << 8)); - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - case DASM_IMM16: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMV8: - CK((n & 3) == 0, RANGE_I); - n >>= 2; - /* fallthrough */ - case DASM_IMML8: - case DASM_IMML12: - CK(n >= 0 ? ((n>>((ins>>5)&31)) == 0) : - (((-n)>>((ins>>5)&31)) == 0), RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM12: case DASM_IMM16: - case DASM_IMML8: case DASM_IMML12: case DASM_IMMV8: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - if (n < 0) { - n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp - 4); - goto patchrel; - } - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) - 4; - patchrel: - if ((ins & 0x800) == 0) { - CK((n & 3) == 0 && ((n+0x02000000) >> 26) == 0, RANGE_REL); - cp[-1] |= ((n >> 2) & 0x00ffffff); - } else if ((ins & 0x1000)) { - CK((n & 3) == 0 && -256 <= n && n <= 256, RANGE_REL); - goto patchimml8; - } else if ((ins & 0x2000) == 0) { - CK((n & 3) == 0 && -4096 <= n && n <= 4096, RANGE_REL); - goto patchimml; - } else { - CK((n & 3) == 0 && -1020 <= n && n <= 1020, RANGE_REL); - n >>= 2; - goto patchimml; - } - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= ((n>>((ins>>10)&31)) & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM12: - cp[-1] |= dasm_imm12((unsigned int)n); - break; - case DASM_IMM16: - cp[-1] |= ((n & 0xf000) << 4) | (n & 0x0fff); - break; - case DASM_IMML8: patchimml8: - cp[-1] |= n >= 0 ? (0x00800000 | (n & 0x0f) | ((n & 0xf0) << 4)) : - ((-n & 0x0f) | ((-n & 0xf0) << 4)); - break; - case DASM_IMML12: case DASM_IMMV8: patchimml: - cp[-1] |= n >= 0 ? (0x00800000 | n) : (-n); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/ext/opcache/jit/dynasm/dasm_arm.lua b/ext/opcache/jit/dynasm/dasm_arm.lua deleted file mode 100644 index 0c775ae2687db..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_arm.lua +++ /dev/null @@ -1,1125 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM ARM module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "arm", - description = "DynASM ARM module", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable, rawget = assert, setmetatable, rawget -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub -local concat, sort, insert = table.concat, table.sort, table.insert -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local ror, tohex = bit.ror, bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMM12", "IMM16", "IMML8", "IMML12", "IMMV8", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0x000fffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - if n <= 0x000fffff then - insert(actlist, pos+1, n) - n = map_action.ESC * 0x10000 - end - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. - --- Ext. register name -> int. name. -local map_archdef = { sp = "r13", lr = "r14", pc = "r15", } - --- Int. register name -> ext. name. -local map_reg_rev = { r13 = "sp", r14 = "lr", r15 = "pc", } - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - return map_reg_rev[s] or s -end - -local map_shift = { lsl = 0, lsr = 1, asr = 2, ror = 3, } - -local map_cond = { - eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, - hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, - hs = 2, lo = 3, -} - ------------------------------------------------------------------------------- - --- Template strings for ARM instructions. -local map_op = { - -- Basic data processing instructions. - and_3 = "e0000000DNPs", - eor_3 = "e0200000DNPs", - sub_3 = "e0400000DNPs", - rsb_3 = "e0600000DNPs", - add_3 = "e0800000DNPs", - adc_3 = "e0a00000DNPs", - sbc_3 = "e0c00000DNPs", - rsc_3 = "e0e00000DNPs", - tst_2 = "e1100000NP", - teq_2 = "e1300000NP", - cmp_2 = "e1500000NP", - cmn_2 = "e1700000NP", - orr_3 = "e1800000DNPs", - mov_2 = "e1a00000DPs", - bic_3 = "e1c00000DNPs", - mvn_2 = "e1e00000DPs", - - and_4 = "e0000000DNMps", - eor_4 = "e0200000DNMps", - sub_4 = "e0400000DNMps", - rsb_4 = "e0600000DNMps", - add_4 = "e0800000DNMps", - adc_4 = "e0a00000DNMps", - sbc_4 = "e0c00000DNMps", - rsc_4 = "e0e00000DNMps", - tst_3 = "e1100000NMp", - teq_3 = "e1300000NMp", - cmp_3 = "e1500000NMp", - cmn_3 = "e1700000NMp", - orr_4 = "e1800000DNMps", - mov_3 = "e1a00000DMps", - bic_4 = "e1c00000DNMps", - mvn_3 = "e1e00000DMps", - - lsl_3 = "e1a00000DMws", - lsr_3 = "e1a00020DMws", - asr_3 = "e1a00040DMws", - ror_3 = "e1a00060DMws", - rrx_2 = "e1a00060DMs", - - -- Multiply and multiply-accumulate. - mul_3 = "e0000090NMSs", - mla_4 = "e0200090NMSDs", - umaal_4 = "e0400090DNMSs", -- v6 - mls_4 = "e0600090DNMSs", -- v6T2 - umull_4 = "e0800090DNMSs", - umlal_4 = "e0a00090DNMSs", - smull_4 = "e0c00090DNMSs", - smlal_4 = "e0e00090DNMSs", - - -- Halfword multiply and multiply-accumulate. - smlabb_4 = "e1000080NMSD", -- v5TE - smlatb_4 = "e10000a0NMSD", -- v5TE - smlabt_4 = "e10000c0NMSD", -- v5TE - smlatt_4 = "e10000e0NMSD", -- v5TE - smlawb_4 = "e1200080NMSD", -- v5TE - smulwb_3 = "e12000a0NMS", -- v5TE - smlawt_4 = "e12000c0NMSD", -- v5TE - smulwt_3 = "e12000e0NMS", -- v5TE - smlalbb_4 = "e1400080NMSD", -- v5TE - smlaltb_4 = "e14000a0NMSD", -- v5TE - smlalbt_4 = "e14000c0NMSD", -- v5TE - smlaltt_4 = "e14000e0NMSD", -- v5TE - smulbb_3 = "e1600080NMS", -- v5TE - smultb_3 = "e16000a0NMS", -- v5TE - smulbt_3 = "e16000c0NMS", -- v5TE - smultt_3 = "e16000e0NMS", -- v5TE - - -- Miscellaneous data processing instructions. - clz_2 = "e16f0f10DM", -- v5T - rev_2 = "e6bf0f30DM", -- v6 - rev16_2 = "e6bf0fb0DM", -- v6 - revsh_2 = "e6ff0fb0DM", -- v6 - sel_3 = "e6800fb0DNM", -- v6 - usad8_3 = "e780f010NMS", -- v6 - usada8_4 = "e7800010NMSD", -- v6 - rbit_2 = "e6ff0f30DM", -- v6T2 - movw_2 = "e3000000DW", -- v6T2 - movt_2 = "e3400000DW", -- v6T2 - -- Note: the X encodes width-1, not width. - sbfx_4 = "e7a00050DMvX", -- v6T2 - ubfx_4 = "e7e00050DMvX", -- v6T2 - -- Note: the X encodes the msb field, not the width. - bfc_3 = "e7c0001fDvX", -- v6T2 - bfi_4 = "e7c00010DMvX", -- v6T2 - - -- Packing and unpacking instructions. - pkhbt_3 = "e6800010DNM", pkhbt_4 = "e6800010DNMv", -- v6 - pkhtb_3 = "e6800050DNM", pkhtb_4 = "e6800050DNMv", -- v6 - sxtab_3 = "e6a00070DNM", sxtab_4 = "e6a00070DNMv", -- v6 - sxtab16_3 = "e6800070DNM", sxtab16_4 = "e6800070DNMv", -- v6 - sxtah_3 = "e6b00070DNM", sxtah_4 = "e6b00070DNMv", -- v6 - sxtb_2 = "e6af0070DM", sxtb_3 = "e6af0070DMv", -- v6 - sxtb16_2 = "e68f0070DM", sxtb16_3 = "e68f0070DMv", -- v6 - sxth_2 = "e6bf0070DM", sxth_3 = "e6bf0070DMv", -- v6 - uxtab_3 = "e6e00070DNM", uxtab_4 = "e6e00070DNMv", -- v6 - uxtab16_3 = "e6c00070DNM", uxtab16_4 = "e6c00070DNMv", -- v6 - uxtah_3 = "e6f00070DNM", uxtah_4 = "e6f00070DNMv", -- v6 - uxtb_2 = "e6ef0070DM", uxtb_3 = "e6ef0070DMv", -- v6 - uxtb16_2 = "e6cf0070DM", uxtb16_3 = "e6cf0070DMv", -- v6 - uxth_2 = "e6ff0070DM", uxth_3 = "e6ff0070DMv", -- v6 - - -- Saturating instructions. - qadd_3 = "e1000050DMN", -- v5TE - qsub_3 = "e1200050DMN", -- v5TE - qdadd_3 = "e1400050DMN", -- v5TE - qdsub_3 = "e1600050DMN", -- v5TE - -- Note: the X for ssat* encodes sat_imm-1, not sat_imm. - ssat_3 = "e6a00010DXM", ssat_4 = "e6a00010DXMp", -- v6 - usat_3 = "e6e00010DXM", usat_4 = "e6e00010DXMp", -- v6 - ssat16_3 = "e6a00f30DXM", -- v6 - usat16_3 = "e6e00f30DXM", -- v6 - - -- Parallel addition and subtraction. - sadd16_3 = "e6100f10DNM", -- v6 - sasx_3 = "e6100f30DNM", -- v6 - ssax_3 = "e6100f50DNM", -- v6 - ssub16_3 = "e6100f70DNM", -- v6 - sadd8_3 = "e6100f90DNM", -- v6 - ssub8_3 = "e6100ff0DNM", -- v6 - qadd16_3 = "e6200f10DNM", -- v6 - qasx_3 = "e6200f30DNM", -- v6 - qsax_3 = "e6200f50DNM", -- v6 - qsub16_3 = "e6200f70DNM", -- v6 - qadd8_3 = "e6200f90DNM", -- v6 - qsub8_3 = "e6200ff0DNM", -- v6 - shadd16_3 = "e6300f10DNM", -- v6 - shasx_3 = "e6300f30DNM", -- v6 - shsax_3 = "e6300f50DNM", -- v6 - shsub16_3 = "e6300f70DNM", -- v6 - shadd8_3 = "e6300f90DNM", -- v6 - shsub8_3 = "e6300ff0DNM", -- v6 - uadd16_3 = "e6500f10DNM", -- v6 - uasx_3 = "e6500f30DNM", -- v6 - usax_3 = "e6500f50DNM", -- v6 - usub16_3 = "e6500f70DNM", -- v6 - uadd8_3 = "e6500f90DNM", -- v6 - usub8_3 = "e6500ff0DNM", -- v6 - uqadd16_3 = "e6600f10DNM", -- v6 - uqasx_3 = "e6600f30DNM", -- v6 - uqsax_3 = "e6600f50DNM", -- v6 - uqsub16_3 = "e6600f70DNM", -- v6 - uqadd8_3 = "e6600f90DNM", -- v6 - uqsub8_3 = "e6600ff0DNM", -- v6 - uhadd16_3 = "e6700f10DNM", -- v6 - uhasx_3 = "e6700f30DNM", -- v6 - uhsax_3 = "e6700f50DNM", -- v6 - uhsub16_3 = "e6700f70DNM", -- v6 - uhadd8_3 = "e6700f90DNM", -- v6 - uhsub8_3 = "e6700ff0DNM", -- v6 - - -- Load/store instructions. - str_2 = "e4000000DL", str_3 = "e4000000DL", str_4 = "e4000000DL", - strb_2 = "e4400000DL", strb_3 = "e4400000DL", strb_4 = "e4400000DL", - ldr_2 = "e4100000DL", ldr_3 = "e4100000DL", ldr_4 = "e4100000DL", - ldrb_2 = "e4500000DL", ldrb_3 = "e4500000DL", ldrb_4 = "e4500000DL", - strh_2 = "e00000b0DL", strh_3 = "e00000b0DL", - ldrh_2 = "e01000b0DL", ldrh_3 = "e01000b0DL", - ldrd_2 = "e00000d0DL", ldrd_3 = "e00000d0DL", -- v5TE - ldrsb_2 = "e01000d0DL", ldrsb_3 = "e01000d0DL", - strd_2 = "e00000f0DL", strd_3 = "e00000f0DL", -- v5TE - ldrsh_2 = "e01000f0DL", ldrsh_3 = "e01000f0DL", - - ldm_2 = "e8900000oR", ldmia_2 = "e8900000oR", ldmfd_2 = "e8900000oR", - ldmda_2 = "e8100000oR", ldmfa_2 = "e8100000oR", - ldmdb_2 = "e9100000oR", ldmea_2 = "e9100000oR", - ldmib_2 = "e9900000oR", ldmed_2 = "e9900000oR", - stm_2 = "e8800000oR", stmia_2 = "e8800000oR", stmfd_2 = "e8800000oR", - stmda_2 = "e8000000oR", stmfa_2 = "e8000000oR", - stmdb_2 = "e9000000oR", stmea_2 = "e9000000oR", - stmib_2 = "e9800000oR", stmed_2 = "e9800000oR", - pop_1 = "e8bd0000R", push_1 = "e92d0000R", - - -- Branch instructions. - b_1 = "ea000000B", - bl_1 = "eb000000B", - blx_1 = "e12fff30C", - bx_1 = "e12fff10M", - - -- Miscellaneous instructions. - nop_0 = "e1a00000", - mrs_1 = "e10f0000D", - bkpt_1 = "e1200070K", -- v5T - svc_1 = "ef000000T", swi_1 = "ef000000T", - ud_0 = "e7f001f0", - - -- VFP instructions. - ["vadd.f32_3"] = "ee300a00dnm", - ["vadd.f64_3"] = "ee300b00Gdnm", - ["vsub.f32_3"] = "ee300a40dnm", - ["vsub.f64_3"] = "ee300b40Gdnm", - ["vmul.f32_3"] = "ee200a00dnm", - ["vmul.f64_3"] = "ee200b00Gdnm", - ["vnmul.f32_3"] = "ee200a40dnm", - ["vnmul.f64_3"] = "ee200b40Gdnm", - ["vmla.f32_3"] = "ee000a00dnm", - ["vmla.f64_3"] = "ee000b00Gdnm", - ["vmls.f32_3"] = "ee000a40dnm", - ["vmls.f64_3"] = "ee000b40Gdnm", - ["vnmla.f32_3"] = "ee100a40dnm", - ["vnmla.f64_3"] = "ee100b40Gdnm", - ["vnmls.f32_3"] = "ee100a00dnm", - ["vnmls.f64_3"] = "ee100b00Gdnm", - ["vdiv.f32_3"] = "ee800a00dnm", - ["vdiv.f64_3"] = "ee800b00Gdnm", - - ["vabs.f32_2"] = "eeb00ac0dm", - ["vabs.f64_2"] = "eeb00bc0Gdm", - ["vneg.f32_2"] = "eeb10a40dm", - ["vneg.f64_2"] = "eeb10b40Gdm", - ["vsqrt.f32_2"] = "eeb10ac0dm", - ["vsqrt.f64_2"] = "eeb10bc0Gdm", - ["vcmp.f32_2"] = "eeb40a40dm", - ["vcmp.f64_2"] = "eeb40b40Gdm", - ["vcmpe.f32_2"] = "eeb40ac0dm", - ["vcmpe.f64_2"] = "eeb40bc0Gdm", - ["vcmpz.f32_1"] = "eeb50a40d", - ["vcmpz.f64_1"] = "eeb50b40Gd", - ["vcmpze.f32_1"] = "eeb50ac0d", - ["vcmpze.f64_1"] = "eeb50bc0Gd", - - vldr_2 = "ed100a00dl|ed100b00Gdl", - vstr_2 = "ed000a00dl|ed000b00Gdl", - vldm_2 = "ec900a00or", - vldmia_2 = "ec900a00or", - vldmdb_2 = "ed100a00or", - vpop_1 = "ecbd0a00r", - vstm_2 = "ec800a00or", - vstmia_2 = "ec800a00or", - vstmdb_2 = "ed000a00or", - vpush_1 = "ed2d0a00r", - - ["vmov.f32_2"] = "eeb00a40dm|eeb00a00dY", -- #imm is VFPv3 only - ["vmov.f64_2"] = "eeb00b40Gdm|eeb00b00GdY", -- #imm is VFPv3 only - vmov_2 = "ee100a10Dn|ee000a10nD", - vmov_3 = "ec500a10DNm|ec400a10mDN|ec500b10GDNm|ec400b10GmDN", - - vmrs_0 = "eef1fa10", - vmrs_1 = "eef10a10D", - vmsr_1 = "eee10a10D", - - ["vcvt.s32.f32_2"] = "eebd0ac0dm", - ["vcvt.s32.f64_2"] = "eebd0bc0dGm", - ["vcvt.u32.f32_2"] = "eebc0ac0dm", - ["vcvt.u32.f64_2"] = "eebc0bc0dGm", - ["vcvtr.s32.f32_2"] = "eebd0a40dm", - ["vcvtr.s32.f64_2"] = "eebd0b40dGm", - ["vcvtr.u32.f32_2"] = "eebc0a40dm", - ["vcvtr.u32.f64_2"] = "eebc0b40dGm", - ["vcvt.f32.s32_2"] = "eeb80ac0dm", - ["vcvt.f64.s32_2"] = "eeb80bc0GdFm", - ["vcvt.f32.u32_2"] = "eeb80a40dm", - ["vcvt.f64.u32_2"] = "eeb80b40GdFm", - ["vcvt.f32.f64_2"] = "eeb70bc0dGm", - ["vcvt.f64.f32_2"] = "eeb70ac0GdFm", - - -- VFPv4 only: - ["vfma.f32_3"] = "eea00a00dnm", - ["vfma.f64_3"] = "eea00b00Gdnm", - ["vfms.f32_3"] = "eea00a40dnm", - ["vfms.f64_3"] = "eea00b40Gdnm", - ["vfnma.f32_3"] = "ee900a40dnm", - ["vfnma.f64_3"] = "ee900b40Gdnm", - ["vfnms.f32_3"] = "ee900a00dnm", - ["vfnms.f64_3"] = "ee900b00Gdnm", - - -- NYI: Advanced SIMD instructions. - - -- NYI: I have no need for these instructions right now: - -- swp, swpb, strex, ldrex, strexd, ldrexd, strexb, ldrexb, strexh, ldrexh - -- msr, nopv6, yield, wfe, wfi, sev, dbg, bxj, smc, srs, rfe - -- cps, setend, pli, pld, pldw, clrex, dsb, dmb, isb - -- stc, ldc, mcr, mcr2, mrc, mrc2, mcrr, mcrr2, mrrc, mrrc2, cdp, cdp2 -} - --- Add mnemonics for "s" variants. -do - local t = {} - for k,v in pairs(map_op) do - if sub(v, -1) == "s" then - local v2 = sub(v, 1, 2)..char(byte(v, 3)+1)..sub(v, 4, -2) - t[sub(k, 1, -3).."s"..sub(k, -2)] = v2 - end - end - for k,v in pairs(t) do - map_op[k] = v - end -end - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r1?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r(1?[0-9])$") - if r then - r = tonumber(r) - if r <= 15 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_gpr_pm(expr) - local pm, expr2 = match(expr, "^([+-]?)(.*)$") - return parse_gpr(expr2), (pm == "-") -end - -local function parse_vr(expr, tp) - local t, r = match(expr, "^([sd])([0-9]+)$") - if t == tp then - r = tonumber(r) - if r <= 31 then - if t == "s" then return shr(r, 1), band(r, 1) end - return band(r, 15), shr(r, 4) - end - end - werror("bad register name `"..expr.."'") -end - -local function parse_reglist(reglist) - reglist = match(reglist, "^{%s*([^}]*)}$") - if not reglist then werror("register list expected") end - local rr = 0 - for p in gmatch(reglist..",", "%s*([^,]*),") do - local rbit = shl(1, parse_gpr(gsub(p, "%s+$", ""))) - if band(rr, rbit) ~= 0 then - werror("duplicate register `"..p.."'") - end - rr = rr + rbit - end - return rr -end - -local function parse_vrlist(reglist) - local ta, ra, tb, rb = match(reglist, - "^{%s*([sd])([0-9]+)%s*%-%s*([sd])([0-9]+)%s*}$") - ra, rb = tonumber(ra), tonumber(rb) - if ta and ta == tb and ra and rb and ra <= 31 and rb <= 31 and ra <= rb then - local nr = rb+1 - ra - if ta == "s" then - return shl(shr(ra,1),12)+shl(band(ra,1),22) + nr - else - return shl(band(ra,15),12)+shl(shr(ra,4),22) + nr*2 + 0x100 - end - end - werror("register list expected") -end - -local function parse_imm(imm, bits, shift, scale, signed) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = tonumber(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_imm12(imm) - local n = tonumber(imm) - if n then - local m = band(n) - for i=0,-15,-1 do - if shr(m, 8) == 0 then return m + shl(band(i, 15), 8) end - m = ror(m, 2) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM12", 0, imm) - return 0 - end -end - -local function parse_imm16(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = tonumber(imm) - if n then - if shr(n, 16) == 0 then return band(n, 0x0fff) + shl(band(n, 0xf000), 4) end - werror("out of range immediate `"..imm.."'") - else - waction("IMM16", 32*16, imm) - return 0 - end -end - -local function parse_imm_load(imm, ext) - local n = tonumber(imm) - if n then - if ext then - if n >= -255 and n <= 255 then - local up = 0x00800000 - if n < 0 then n = -n; up = 0 end - return shl(band(n, 0xf0), 4) + band(n, 0x0f) + up - end - else - if n >= -4095 and n <= 4095 then - if n >= 0 then return n+0x00800000 end - return -n - end - end - werror("out of range immediate `"..imm.."'") - else - waction(ext and "IMML8" or "IMML12", 32768 + shl(ext and 8 or 12, 5), imm) - return 0 - end -end - -local function parse_shift(shift, gprok) - if shift == "rrx" then - return 3 * 32 - else - local s, s2 = match(shift, "^(%S+)%s*(.*)$") - s = map_shift[s] - if not s then werror("expected shift operand") end - if sub(s2, 1, 1) == "#" then - return parse_imm(s2, 5, 7, 0, false) + shl(s, 5) - else - if not gprok then werror("expected immediate shift operand") end - return shl(parse_gpr(s2), 8) + shl(s, 5) + 16 - end - end -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - -local function parse_load(params, nparams, n, op) - local oplo = band(op, 255) - local ext, ldrd = (oplo ~= 0), (oplo == 208) - local d - if (ldrd or oplo == 240) then - d = band(shr(op, 12), 15) - if band(d, 1) ~= 0 then werror("odd destination register") end - end - local pn = params[n] - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - local p2 = params[n+1] - if not p1 then - if not p2 then - if match(pn, "^[<>=%-]") or match(pn, "^extern%s+") then - local mode, n, s = parse_label(pn, false) - waction("REL_"..mode, n + (ext and 0x1800 or 0x0800), s, 1) - return op + 15 * 65536 + 0x01000000 + (ext and 0x00400000 or 0) - end - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local d, tp = parse_gpr(reg) - if tp then - waction(ext and "IMML8" or "IMML12", 32768 + 32*(ext and 8 or 12), - format(tp.ctypefmt, tailr)) - return op + shl(d, 16) + 0x01000000 + (ext and 0x00400000 or 0) - end - end - end - werror("expected address operand") - end - if wb == "!" then op = op + 0x00200000 end - if p2 then - if wb == "!" then werror("bad use of '!'") end - local p3 = params[n+2] - op = op + shl(parse_gpr(p1), 16) - local imm = match(p2, "^#(.*)$") - if imm then - local m = parse_imm_load(imm, ext) - if p3 then werror("too many parameters") end - op = op + m + (ext and 0x00400000 or 0) - else - local m, neg = parse_gpr_pm(p2) - if ldrd and (m == d or m-1 == d) then werror("register conflict") end - op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) - if p3 then op = op + parse_shift(p3) end - end - else - local p1a, p2 = match(p1, "^([^,%s]*)%s*(.*)$") - op = op + shl(parse_gpr(p1a), 16) + 0x01000000 - if p2 ~= "" then - local imm = match(p2, "^,%s*#(.*)$") - if imm then - local m = parse_imm_load(imm, ext) - op = op + m + (ext and 0x00400000 or 0) - else - local p2a, p3 = match(p2, "^,%s*([^,%s]*)%s*,?%s*(.*)$") - local m, neg = parse_gpr_pm(p2a) - if ldrd and (m == d or m-1 == d) then werror("register conflict") end - op = op + m + (neg and 0 or 0x00800000) + (ext and 0 or 0x02000000) - if p3 ~= "" then - if ext then werror("too many parameters") end - op = op + parse_shift(p3) - end - end - else - if wb == "!" then werror("bad use of '!'") end - op = op + (ext and 0x00c00000 or 0x00800000) - end - end - return op -end - -local function parse_vload(q) - local reg, imm = match(q, "^%[%s*([^,%s]*)%s*(.*)%]$") - if reg then - local d = shl(parse_gpr(reg), 16) - if imm == "" then return d end - imm = match(imm, "^,%s*#(.*)$") - if imm then - local n = tonumber(imm) - if n then - if n >= -1020 and n <= 1020 and n%4 == 0 then - return d + (n >= 0 and n/4+0x00800000 or -n/4) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMMV8", 32768 + 32*8, imm) - return d - end - end - else - if match(q, "^[<>=%-]") or match(q, "^extern%s+") then - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n + 0x2800, s, 1) - return 15 * 65536 - end - local reg, tailr = match(q, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local d, tp = parse_gpr(reg) - if tp then - waction("IMMV8", 32768 + 32*8, format(tp.ctypefmt, tailr)) - return shl(d, 16) - end - end - end - werror("expected address operand") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -local function parse_template(params, template, nparams, pos) - local op = tonumber(sub(template, 1, 8), 16) - local n = 1 - local vr = "s" - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - local q = params[n] - if p == "D" then - op = op + shl(parse_gpr(q), 12); n = n + 1 - elseif p == "N" then - op = op + shl(parse_gpr(q), 16); n = n + 1 - elseif p == "S" then - op = op + shl(parse_gpr(q), 8); n = n + 1 - elseif p == "M" then - op = op + parse_gpr(q); n = n + 1 - elseif p == "d" then - local r,h = parse_vr(q, vr); op = op+shl(r,12)+shl(h,22); n = n + 1 - elseif p == "n" then - local r,h = parse_vr(q, vr); op = op+shl(r,16)+shl(h,7); n = n + 1 - elseif p == "m" then - local r,h = parse_vr(q, vr); op = op+r+shl(h,5); n = n + 1 - elseif p == "P" then - local imm = match(q, "^#(.*)$") - if imm then - op = op + parse_imm12(imm) + 0x02000000 - else - op = op + parse_gpr(q) - end - n = n + 1 - elseif p == "p" then - op = op + parse_shift(q, true); n = n + 1 - elseif p == "L" then - op = parse_load(params, nparams, n, op) - elseif p == "l" then - op = op + parse_vload(q) - elseif p == "B" then - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n, s, 1) - elseif p == "C" then -- blx gpr vs. blx label. - if match(q, "^([%w_]+):(r1?[0-9])$") or match(q, "^r(1?[0-9])$") then - op = op + parse_gpr(q) - else - if op < 0xe0000000 then werror("unconditional instruction") end - local mode, n, s = parse_label(q, false) - waction("REL_"..mode, n, s, 1) - op = 0xfa000000 - end - elseif p == "F" then - vr = "s" - elseif p == "G" then - vr = "d" - elseif p == "o" then - local r, wb = match(q, "^([^!]*)(!?)$") - op = op + shl(parse_gpr(r), 16) + (wb == "!" and 0x00200000 or 0) - n = n + 1 - elseif p == "R" then - op = op + parse_reglist(q); n = n + 1 - elseif p == "r" then - op = op + parse_vrlist(q); n = n + 1 - elseif p == "W" then - op = op + parse_imm16(q); n = n + 1 - elseif p == "v" then - op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 - elseif p == "w" then - local imm = match(q, "^#(.*)$") - if imm then - op = op + parse_imm(q, 5, 7, 0, false); n = n + 1 - else - op = op + shl(parse_gpr(q), 8) + 16 - end - elseif p == "X" then - op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 - elseif p == "Y" then - local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 - if not imm or shr(imm, 8) ~= 0 then - werror("bad immediate operand") - end - op = op + shl(band(imm, 0xf0), 12) + band(imm, 0x0f) - elseif p == "K" then - local imm = tonumber(match(q, "^#(.*)$")); n = n + 1 - if not imm or shr(imm, 16) ~= 0 then - werror("bad immediate operand") - end - op = op + shl(band(imm, 0xfff0), 4) + band(imm, 0x000f) - elseif p == "T" then - op = op + parse_imm(q, 24, 0, 0, false); n = n + 1 - elseif p == "s" then - -- Ignored. - else - assert(false) - end - end - wputpos(pos, op) -end - -map_op[".template__"] = function(params, template, nparams) - if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions. - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() - local lpos, apos, spos = #actlist, #actargs, secpos - - local ok, err - for t in gmatch(template, "[^|]+") do - ok, err = pcall(parse_template, params, t, nparams, pos) - if ok then return end - secpos = spos - actlist[lpos+1] = nil - actlist[lpos+2] = nil - actlist[lpos+3] = nil - actargs[apos+1] = nil - actargs[apos+2] = nil - actargs[apos+3] = nil - end - error(err, 0) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = function(t, k) - local v = map_coreop[k] - if v then return v end - local k1, cc, k2 = match(k, "^(.-)(..)([._].*)$") - local cv = map_cond[cc] - if cv then - local v = rawget(t, k1..k2) - if type(v) == "string" then - local scv = format("%x", cv) - return gsub(scv..sub(v, 2), "|e", "|"..scv) - end - end - end }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/dasm_arm64.h b/ext/opcache/jit/dynasm/dasm_arm64.h deleted file mode 100644 index 0c817f9cf5cdd..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_arm64.h +++ /dev/null @@ -1,570 +0,0 @@ -/* -** DynASM ARM64 encoding engine. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "arm64" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_REL_A, - DASM_IMM, DASM_IMM6, DASM_IMM12, DASM_IMM13W, DASM_IMM13X, DASM_IMML, - DASM_IMMV, DASM_VREG, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_RANGE_VREG 0x16000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -static int dasm_imm12(unsigned int n) -{ - if ((n >> 12) == 0) - return n; - else if ((n & 0xff000fff) == 0) - return (n >> 12) | 0x1000; - else - return -1; -} - -static int dasm_ffs(unsigned long long x) -{ - int n = -1; - while (x) { x >>= 1; n++; } - return n; -} - -static int dasm_imm13(int lo, int hi) -{ - int inv = 0, w = 64, s = 0xfff, xa, xb; - unsigned long long n = (((unsigned long long)hi) << 32) | (unsigned int)lo; - unsigned long long m = 1ULL, a, b, c; - if (n & 1) { n = ~n; inv = 1; } - a = n & -n; b = (n+a)&-(n+a); c = (n+a-b)&-(n+a-b); - xa = dasm_ffs(a); xb = dasm_ffs(b); - if (c) { - w = dasm_ffs(c) - xa; - if (w == 32) m = 0x0000000100000001UL; - else if (w == 16) m = 0x0001000100010001UL; - else if (w == 8) m = 0x0101010101010101UL; - else if (w == 4) m = 0x1111111111111111UL; - else if (w == 2) m = 0x5555555555555555UL; - else return -1; - s = (-2*w & 0x3f) - 1; - } else if (!a) { - return -1; - } else if (xb == -1) { - xb = 64; - } - if ((b-a) * m != n) return -1; - if (inv) { - return ((w - xb) << 6) | (s+w+xa-xb); - } else { - return ((w - xa) << 6) | (s+xb-xa); - } - return -1; -} - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: if ((ins & 0x8000)) ofs += 8; break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - if ((ins & 0x8000)) ofs += 8; - break; - case DASM_REL_A: - b[pos++] = n; - b[pos++] = va_arg(ap, int); - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if ((ins & 0x8000)) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMM6: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM12: - CK(dasm_imm12((unsigned int)n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13W: - CK(dasm_imm13(n, n) != -1, RANGE_I); - b[pos++] = n; - break; - case DASM_IMM13X: { - int m = va_arg(ap, int); - CK(dasm_imm13(n, m) != -1, RANGE_I); - b[pos++] = n; - b[pos++] = m; - break; - } - case DASM_IMML: { -#ifdef DASM_CHECKS - int scale = (ins & 3); - CK((!(n & ((1<>scale) < 4096) || - (unsigned int)(n+256) < 512, RANGE_I); -#endif - b[pos++] = n; - break; - } - case DASM_IMMV: - ofs += 4; - b[pos++] = n; - break; - case DASM_VREG: - CK(n < 32, RANGE_VREG); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMM6: case DASM_IMM12: case DASM_IMM13W: - case DASM_IMML: case DASM_IMMV: case DASM_VREG: pos++; break; - case DASM_IMM13X: case DASM_REL_A: pos += 2; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_ADD_VENEER -#define CK_REL(x, o) \ - do { if (!(x) && !(n = DASM_ADD_VENEER(D, buffer, ins, b, cp, o))) \ - return DASM_S_RANGE_REL|(p-D->actionlist-1); \ - } while (0) -#else -#define CK_REL(x, o) CK(x, RANGE_REL) -#endif - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins&2047), !(ins&2048)); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0xe1a00000; - break; - case DASM_REL_LG: - if (n < 0) { - ptrdiff_t na = (ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp + 4; - n = (int)na; - CK_REL((ptrdiff_t)n == na, na); - goto patchrel; - } - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base) + 4; - patchrel: - if (!(ins & 0xf800)) { /* B, BL */ - CK_REL((n & 3) == 0 && ((n+0x08000000) >> 28) == 0, n); - cp[-1] |= ((n >> 2) & 0x03ffffff); - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - CK_REL((n & 3) == 0 && ((n+0x00100000) >> 21) == 0, n); - cp[-1] |= ((n << 3) & 0x00ffffe0); - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - CK_REL(((n+0x00100000) >> 21) == 0, n); - cp[-1] |= ((n << 3) & 0x00ffffe0) | ((n & 3) << 29); - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - cp[-1] |= ((n >> 9) & 0x00ffffe0) | (((n >> 12) & 3) << 29); - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - CK_REL((n & 3) == 0 && ((n+0x00008000) >> 16) == 0, n); - cp[-1] |= ((n << 3) & 0x0007ffe0); - } else if ((ins & 0x8000)) { /* absolute */ - cp[0] = (unsigned int)((ptrdiff_t)cp - 4 + n); - cp[1] = (unsigned int)(((ptrdiff_t)cp - 4 + n) >> 32); - cp += 2; - } - break; - case DASM_REL_A: { - ptrdiff_t na = (((ptrdiff_t)(*b++) << 32) | (unsigned int)n); - if ((ins & 0x3000) == 0x3000) { /* ADRP */ - ins &= ~0x1000; - na = (na >> 12) - (((ptrdiff_t)cp - 4) >> 12); - } else { - na = na - (ptrdiff_t)cp + 4; - } - n = (int)na; - CK_REL((ptrdiff_t)n == na, na); - goto patchrel; - } - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMM6: - cp[-1] |= ((n&31) << 19) | ((n&32) << 26); - break; - case DASM_IMM12: - cp[-1] |= (dasm_imm12((unsigned int)n) << 10); - break; - case DASM_IMM13W: - cp[-1] |= (dasm_imm13(n, n) << 10); - break; - case DASM_IMM13X: - cp[-1] |= (dasm_imm13(n, *b++) << 10); - break; - case DASM_IMML: { - int scale = (ins & 3); - cp[-1] |= (!(n & ((1<>scale) < 4096) ? - ((n << (10-scale)) | 0x01000000) : ((n & 511) << 12); - break; - } - case DASM_IMMV: - *cp++ = n; - break; - case DASM_VREG: - cp[-1] |= (n & 0x1f) << (ins & 0x1f); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/ext/opcache/jit/dynasm/dasm_arm64.lua b/ext/opcache/jit/dynasm/dasm_arm64.lua deleted file mode 100644 index cb82dc4a52a34..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_arm64.lua +++ /dev/null @@ -1,1219 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM ARM64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "arm", - description = "DynASM ARM64 module", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable, rawget = assert, setmetatable, rawget -local _s = string -local format, byte, char = _s.format, _s.byte, _s.char -local match, gmatch, gsub = _s.match, _s.gmatch, _s.gsub -local concat, sort, insert = table.concat, table.sort, table.insert -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local ror, tohex, tobit = bit.ror, bit.tohex, bit.tobit - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "REL_A", - "IMM", "IMM6", "IMM12", "IMM13W", "IMM13X", "IMML", "IMMV", - "VREG", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0x000fffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - if n <= 0x000fffff then - insert(actlist, pos+1, n) - n = map_action.ESC * 0x10000 - end - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. - --- Ext. register name -> int. name. -local map_archdef = { xzr = "@x31", wzr = "@w31", lr = "x30", } - --- Int. register name -> ext. name. -local map_reg_rev = { ["@x31"] = "xzr", ["@w31"] = "wzr", x30 = "lr", } - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - return map_reg_rev[s] or s -end - -local map_shift = { lsl = 0, lsr = 1, asr = 2, } - -local map_extend = { - uxtb = 0, uxth = 1, uxtw = 2, uxtx = 3, - sxtb = 4, sxth = 5, sxtw = 6, sxtx = 7, -} - -local map_cond = { - eq = 0, ne = 1, cs = 2, cc = 3, mi = 4, pl = 5, vs = 6, vc = 7, - hi = 8, ls = 9, ge = 10, lt = 11, gt = 12, le = 13, al = 14, - hs = 2, lo = 3, -} - ------------------------------------------------------------------------------- - -local parse_reg_type - -local function parse_reg(expr, shift) - if not expr then werror("expected register name") end - local tname, ovreg = match(expr, "^([%w_]+):(@?%l%d+)$") - if not tname then - tname, ovreg = match(expr, "^([%w_]+):(R[xwqdshb]%b())$") - end - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local ok31, rt, r = match(expr, "^(@?)([xwqdshb])([123]?[0-9])$") - if r then - r = tonumber(r) - if r <= 30 or (r == 31 and ok31 ~= "" or (rt ~= "w" and rt ~= "x")) then - if not parse_reg_type then - parse_reg_type = rt - elseif parse_reg_type ~= rt then - werror("register size mismatch") - end - return shl(r, shift), tp - end - end - local vrt, vreg = match(expr, "^R([xwqdshb])(%b())$") - if vreg then - if not parse_reg_type then - parse_reg_type = vrt - elseif parse_reg_type ~= vrt then - werror("register size mismatch") - end - if shift then waction("VREG", shift, vreg) end - return 0 - end - werror("bad register name `"..expr.."'") -end - -local function parse_reg_base(expr) - if expr == "sp" then return 0x3e0 end - local base, tp = parse_reg(expr, 5) - if parse_reg_type ~= "x" then werror("bad register type") end - parse_reg_type = false - return base, tp -end - -local parse_ctx = {} - -local loadenv = setfenv and function(s) - local code = loadstring(s, "") - if code then setfenv(code, parse_ctx) end - return code -end or function(s) - return load(s, "", nil, parse_ctx) -end - --- Try to parse simple arithmetic, too, since some basic ops are aliases. -local function parse_number(n) - local x = tonumber(n) - if x then return x end - local code = loadenv("return "..n) - if code then - local ok, y = pcall(code) - if ok and type(y) == "number" then return y end - end - return nil -end - -local function parse_imm(imm, bits, shift, scale, signed) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_imm12(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - if shr(n, 12) == 0 then - return shl(n, 10) - elseif band(n, 0xff000fff) == 0 then - return shr(n, 2) + 0x00400000 - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM12", 0, imm) - return 0 - end -end - -local function parse_imm13(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - local r64 = parse_reg_type == "x" - if n and n % 1 == 0 and n >= 0 and n <= 0xffffffff then - local inv = false - if band(n, 1) == 1 then n = bit.bnot(n); inv = true end - local t = {} - for i=1,32 do t[i] = band(n, 1); n = shr(n, 1) end - local b = table.concat(t) - b = b..(r64 and (inv and "1" or "0"):rep(32) or b) - local p0, p1, p0a, p1a = b:match("^(0+)(1+)(0*)(1*)") - if p0 then - local w = p1a == "" and (r64 and 64 or 32) or #p1+#p0a - if band(w, w-1) == 0 and b == b:sub(1, w):rep(64/w) then - local s = band(-2*w, 0x3f) - 1 - if w == 64 then s = s + 0x1000 end - if inv then - return shl(w-#p1-#p0, 16) + shl(s+w-#p1, 10) - else - return shl(w-#p0, 16) + shl(s+#p1, 10) - end - end - end - werror("out of range immediate `"..imm.."'") - elseif r64 then - waction("IMM13X", 0, format("(unsigned int)(%s)", imm)) - actargs[#actargs+1] = format("(unsigned int)((unsigned long long)(%s)>>32)", imm) - return 0 - else - waction("IMM13W", 0, imm) - return 0 - end -end - -local function parse_imm6(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - if n >= 0 and n <= 63 then - return shl(band(n, 0x1f), 19) + (n >= 32 and 0x80000000 or 0) - end - werror("out of range immediate `"..imm.."'") - else - waction("IMM6", 0, imm) - return 0 - end -end - -local function parse_imm_load(imm, scale) - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n and m >= 0 and m < 0x1000 then - return shl(m, 10) + 0x01000000 -- Scaled, unsigned 12 bit offset. - elseif n >= -256 and n < 256 then - return shl(band(n, 511), 12) -- Unscaled, signed 9 bit offset. - end - werror("out of range immediate `"..imm.."'") - else - waction("IMML", scale, imm) - return 0 - end -end - -local function parse_fpimm(imm) - imm = match(imm, "^#(.*)$") - if not imm then werror("expected immediate operand") end - local n = parse_number(imm) - if n then - local m, e = math.frexp(n) - local s, e2 = 0, band(e-2, 7) - if m < 0 then m = -m; s = 0x00100000 end - m = m*32-16 - if m % 1 == 0 and m >= 0 and m <= 15 and sar(shl(e2, 29), 29)+2 == e then - return s + shl(e2, 17) + shl(m, 13) - end - werror("out of range immediate `"..imm.."'") - else - werror("NYI fpimm action") - end -end - -local function parse_shift(expr) - local s, s2 = match(expr, "^(%S+)%s*(.*)$") - s = map_shift[s] - if not s then werror("expected shift operand") end - return parse_imm(s2, 6, 10, 0, false) + shl(s, 22) -end - -local function parse_lslx16(expr) - local n = match(expr, "^lsl%s*#(%d+)$") - n = tonumber(n) - if not n then werror("expected shift operand") end - if band(n, parse_reg_type == "x" and 0xffffffcf or 0xffffffef) ~= 0 then - werror("bad shift amount") - end - return shl(n, 17) -end - -local function parse_extend(expr) - local s, s2 = match(expr, "^(%S+)%s*(.*)$") - if s == "lsl" then - s = parse_reg_type == "x" and 3 or 2 - else - s = map_extend[s] - end - if not s then werror("expected extend operand") end - return (s2 == "" and 0 or parse_imm(s2, 3, 10, 0, false)) + shl(s, 13) -end - -local function parse_cond(expr, inv) - local c = map_cond[expr] - if not c then werror("expected condition operand") end - return shl(bit.bxor(c, inv), 12) -end - -local function parse_load(params, nparams, n, op) - if params[n+2] then werror("too many operands") end - local scale = shr(op, 30) - local pn, p2 = params[n], params[n+1] - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - if not p1 then - if not p2 then - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local base, tp = parse_reg_base(reg) - if tp then - waction("IMML", scale, format(tp.ctypefmt, tailr)) - return op + base - end - end - end - werror("expected address operand") - end - if p2 then - if wb == "!" then werror("bad use of '!'") end - op = op + parse_reg_base(p1) + parse_imm(p2, 9, 12, 0, true) + 0x400 - elseif wb == "!" then - local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") - if not p1a then werror("bad use of '!'") end - op = op + parse_reg_base(p1a) + parse_imm(p2a, 9, 12, 0, true) + 0xc00 - else - local p1a, p2a = match(p1, "^([^,%s]*)%s*(.*)$") - op = op + parse_reg_base(p1a) - if p2a ~= "" then - local imm = match(p2a, "^,%s*#(.*)$") - if imm then - op = op + parse_imm_load(imm, scale) - else - local p2b, p3b, p3s = match(p2a, "^,%s*([^,%s]*)%s*,?%s*(%S*)%s*(.*)$") - op = op + parse_reg(p2b, 16) + 0x00200800 - if parse_reg_type ~= "x" and parse_reg_type ~= "w" then - werror("bad index register type") - end - if p3b == "" then - if parse_reg_type ~= "x" then werror("bad index register type") end - op = op + 0x6000 - else - if p3s == "" or p3s == "#0" then - elseif p3s == "#"..scale then - op = op + 0x1000 - else - werror("bad scale") - end - if parse_reg_type == "x" then - if p3b == "lsl" and p3s ~= "" then op = op + 0x6000 - elseif p3b == "sxtx" then op = op + 0xe000 - else - werror("bad extend/shift specifier") - end - else - if p3b == "uxtw" then op = op + 0x4000 - elseif p3b == "sxtw" then op = op + 0xc000 - else - werror("bad extend/shift specifier") - end - end - end - end - else - if wb == "!" then werror("bad use of '!'") end - op = op + 0x01000000 - end - end - return op -end - -local function parse_load_pair(params, nparams, n, op) - if params[n+2] then werror("too many operands") end - local pn, p2 = params[n], params[n+1] - local scale = shr(op, 30) == 0 and 2 or 3 - local p1, wb = match(pn, "^%[%s*(.-)%s*%](!?)$") - if not p1 then - if not p2 then - local reg, tailr = match(pn, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local base, tp = parse_reg_base(reg) - if tp then - waction("IMM", 32768+7*32+15+scale*1024, format(tp.ctypefmt, tailr)) - return op + base + 0x01000000 - end - end - end - werror("expected address operand") - end - if p2 then - if wb == "!" then werror("bad use of '!'") end - op = op + 0x00800000 - else - local p1a, p2a = match(p1, "^([^,%s]*)%s*,%s*(.*)$") - if p1a then p1, p2 = p1a, p2a else p2 = "#0" end - op = op + (wb == "!" and 0x01800000 or 0x01000000) - end - return op + parse_reg_base(p1) + parse_imm(p2, 7, 15, scale, true) -end - -local function parse_label(label, def) - local prefix = label:sub(1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, label:sub(3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[label:sub(3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - -- &expr (pointer) - if label:sub(1, 1) == "&" then - return "A", 0, format("(ptrdiff_t)(%s)", label:sub(2)) - end - end -end - -local function branch_type(op) - if band(op, 0x7c000000) == 0x14000000 then return 0 -- B, BL - elseif shr(op, 24) == 0x54 or band(op, 0x7e000000) == 0x34000000 or - band(op, 0x3b000000) == 0x18000000 then - return 0x800 -- B.cond, CBZ, CBNZ, LDR* literal - elseif band(op, 0x7e000000) == 0x36000000 then return 0x1000 -- TBZ, TBNZ - elseif band(op, 0x9f000000) == 0x10000000 then return 0x2000 -- ADR - elseif band(op, 0x9f000000) == band(0x90000000) then return 0x3000 -- ADRP - else - assert(false, "unknown branch type") - end -end - ------------------------------------------------------------------------------- - -local map_op, op_template - -local function op_alias(opname, f) - return function(params, nparams) - if not params then return "-> "..opname:sub(1, -3) end - f(params, nparams) - op_template(params, map_op[opname], nparams) - end -end - -local function alias_bfx(p) - p[4] = "#("..p[3]:sub(2)..")+("..p[4]:sub(2)..")-1" -end - -local function alias_bfiz(p) - parse_reg(p[1], 0) - if parse_reg_type == "w" then - p[3] = "#(32-("..p[3]:sub(2).."))%32" - p[4] = "#("..p[4]:sub(2)..")-1" - else - p[3] = "#(64-("..p[3]:sub(2).."))%64" - p[4] = "#("..p[4]:sub(2)..")-1" - end -end - -local alias_lslimm = op_alias("ubfm_4", function(p) - parse_reg(p[1], 0) - local sh = p[3]:sub(2) - if parse_reg_type == "w" then - p[3] = "#(32-("..sh.."))%32" - p[4] = "#31-("..sh..")" - else - p[3] = "#(64-("..sh.."))%64" - p[4] = "#63-("..sh..")" - end -end) - --- Template strings for ARM instructions. -map_op = { - -- Basic data processing instructions. - add_3 = "0b000000DNMg|11000000pDpNIg|8b206000pDpNMx", - add_4 = "0b000000DNMSg|0b200000DNMXg|8b200000pDpNMXx|8b200000pDpNxMwX", - adds_3 = "2b000000DNMg|31000000DpNIg|ab206000DpNMx", - adds_4 = "2b000000DNMSg|2b200000DNMXg|ab200000DpNMXx|ab200000DpNxMwX", - cmn_2 = "2b00001fNMg|3100001fpNIg|ab20601fpNMx", - cmn_3 = "2b00001fNMSg|2b20001fNMXg|ab20001fpNMXx|ab20001fpNxMwX", - - sub_3 = "4b000000DNMg|51000000pDpNIg|cb206000pDpNMx", - sub_4 = "4b000000DNMSg|4b200000DNMXg|cb200000pDpNMXx|cb200000pDpNxMwX", - subs_3 = "6b000000DNMg|71000000DpNIg|eb206000DpNMx", - subs_4 = "6b000000DNMSg|6b200000DNMXg|eb200000DpNMXx|eb200000DpNxMwX", - cmp_2 = "6b00001fNMg|7100001fpNIg|eb20601fpNMx", - cmp_3 = "6b00001fNMSg|6b20001fNMXg|eb20001fpNMXx|eb20001fpNxMwX", - - neg_2 = "4b0003e0DMg", - neg_3 = "4b0003e0DMSg", - negs_2 = "6b0003e0DMg", - negs_3 = "6b0003e0DMSg", - - adc_3 = "1a000000DNMg", - adcs_3 = "3a000000DNMg", - sbc_3 = "5a000000DNMg", - sbcs_3 = "7a000000DNMg", - ngc_2 = "5a0003e0DMg", - ngcs_2 = "7a0003e0DMg", - - and_3 = "0a000000DNMg|12000000pDNig", - and_4 = "0a000000DNMSg", - orr_3 = "2a000000DNMg|32000000pDNig", - orr_4 = "2a000000DNMSg", - eor_3 = "4a000000DNMg|52000000pDNig", - eor_4 = "4a000000DNMSg", - ands_3 = "6a000000DNMg|72000000DNig", - ands_4 = "6a000000DNMSg", - tst_2 = "6a00001fNMg|7200001fNig", - tst_3 = "6a00001fNMSg", - - bic_3 = "0a200000DNMg", - bic_4 = "0a200000DNMSg", - orn_3 = "2a200000DNMg", - orn_4 = "2a200000DNMSg", - eon_3 = "4a200000DNMg", - eon_4 = "4a200000DNMSg", - bics_3 = "6a200000DNMg", - bics_4 = "6a200000DNMSg", - - movn_2 = "12800000DWg", - movn_3 = "12800000DWRg", - movz_2 = "52800000DWg", - movz_3 = "52800000DWRg", - movk_2 = "72800000DWg", - movk_3 = "72800000DWRg", - - -- TODO: this doesn't cover all valid immediates for mov reg, #imm. - mov_2 = "2a0003e0DMg|52800000DW|320003e0pDig|11000000pDpNg", - mov_3 = "2a0003e0DMSg", - mvn_2 = "2a2003e0DMg", - mvn_3 = "2a2003e0DMSg", - - adr_2 = "10000000DBx", - adrp_2 = "90000000DBx", - - csel_4 = "1a800000DNMCg", - csinc_4 = "1a800400DNMCg", - csinv_4 = "5a800000DNMCg", - csneg_4 = "5a800400DNMCg", - cset_2 = "1a9f07e0Dcg", - csetm_2 = "5a9f03e0Dcg", - cinc_3 = "1a800400DNmcg", - cinv_3 = "5a800000DNmcg", - cneg_3 = "5a800400DNmcg", - - ccmn_4 = "3a400000NMVCg|3a400800N5VCg", - ccmp_4 = "7a400000NMVCg|7a400800N5VCg", - - madd_4 = "1b000000DNMAg", - msub_4 = "1b008000DNMAg", - mul_3 = "1b007c00DNMg", - mneg_3 = "1b00fc00DNMg", - - smaddl_4 = "9b200000DxNMwAx", - smsubl_4 = "9b208000DxNMwAx", - smull_3 = "9b207c00DxNMw", - smnegl_3 = "9b20fc00DxNMw", - smulh_3 = "9b407c00DNMx", - umaddl_4 = "9ba00000DxNMwAx", - umsubl_4 = "9ba08000DxNMwAx", - umull_3 = "9ba07c00DxNMw", - umnegl_3 = "9ba0fc00DxNMw", - umulh_3 = "9bc07c00DNMx", - - udiv_3 = "1ac00800DNMg", - sdiv_3 = "1ac00c00DNMg", - - -- Bit operations. - sbfm_4 = "13000000DN12w|93400000DN12x", - bfm_4 = "33000000DN12w|b3400000DN12x", - ubfm_4 = "53000000DN12w|d3400000DN12x", - extr_4 = "13800000DNM2w|93c00000DNM2x", - - sxtb_2 = "13001c00DNw|93401c00DNx", - sxth_2 = "13003c00DNw|93403c00DNx", - sxtw_2 = "93407c00DxNw", - uxtb_2 = "53001c00DNw", - uxth_2 = "53003c00DNw", - - sbfx_4 = op_alias("sbfm_4", alias_bfx), - bfxil_4 = op_alias("bfm_4", alias_bfx), - ubfx_4 = op_alias("ubfm_4", alias_bfx), - sbfiz_4 = op_alias("sbfm_4", alias_bfiz), - bfi_4 = op_alias("bfm_4", alias_bfiz), - ubfiz_4 = op_alias("ubfm_4", alias_bfiz), - - lsl_3 = function(params, nparams) - if params and params[3]:byte() == 35 then - return alias_lslimm(params, nparams) - else - return op_template(params, "1ac02000DNMg", nparams) - end - end, - lsr_3 = "1ac02400DNMg|53007c00DN1w|d340fc00DN1x", - asr_3 = "1ac02800DNMg|13007c00DN1w|9340fc00DN1x", - ror_3 = "1ac02c00DNMg|13800000DNm2w|93c00000DNm2x", - - clz_2 = "5ac01000DNg", - cls_2 = "5ac01400DNg", - rbit_2 = "5ac00000DNg", - rev_2 = "5ac00800DNw|dac00c00DNx", - rev16_2 = "5ac00400DNg", - rev32_2 = "dac00800DNx", - - -- Loads and stores. - ["strb_*"] = "38000000DwL", - ["ldrb_*"] = "38400000DwL", - ["ldrsb_*"] = "38c00000DwL|38800000DxL", - ["strh_*"] = "78000000DwL", - ["ldrh_*"] = "78400000DwL", - ["ldrsh_*"] = "78c00000DwL|78800000DxL", - ["str_*"] = "b8000000DwL|f8000000DxL|bc000000DsL|fc000000DdL", - ["ldr_*"] = "18000000DwB|58000000DxB|1c000000DsB|5c000000DdB|b8400000DwL|f8400000DxL|bc400000DsL|fc400000DdL", - ["ldrsw_*"] = "98000000DxB|b8800000DxL", - -- NOTE: ldur etc. are handled by ldr et al. - - ["stp_*"] = "28000000DAwP|a8000000DAxP|2c000000DAsP|6c000000DAdP", - ["ldp_*"] = "28400000DAwP|a8400000DAxP|2c400000DAsP|6c400000DAdP", - ["ldpsw_*"] = "68400000DAxP", - - -- Branches. - b_1 = "14000000B", - bl_1 = "94000000B", - blr_1 = "d63f0000Nx", - br_1 = "d61f0000Nx", - ret_0 = "d65f03c0", - ret_1 = "d65f0000Nx", - -- b.cond is added below. - cbz_2 = "34000000DBg", - cbnz_2 = "35000000DBg", - tbz_3 = "36000000DTBw|36000000DTBx", - tbnz_3 = "37000000DTBw|37000000DTBx", - - -- Miscellaneous instructions. - -- TODO: hlt, hvc, smc, svc, eret, dcps[123], drps, mrs, msr - -- TODO: sys, sysl, ic, dc, at, tlbi - -- TODO: hint, yield, wfe, wfi, sev, sevl - -- TODO: clrex, dsb, dmb, isb - nop_0 = "d503201f", - brk_0 = "d4200000", - brk_1 = "d4200000W", - - -- Floating point instructions. - fmov_2 = "1e204000DNf|1e260000DwNs|1e270000DsNw|9e660000DxNd|9e670000DdNx|1e201000DFf", - fabs_2 = "1e20c000DNf", - fneg_2 = "1e214000DNf", - fsqrt_2 = "1e21c000DNf", - - fcvt_2 = "1e22c000DdNs|1e624000DsNd", - - -- TODO: half-precision and fixed-point conversions. - fcvtas_2 = "1e240000DwNs|9e240000DxNs|1e640000DwNd|9e640000DxNd", - fcvtau_2 = "1e250000DwNs|9e250000DxNs|1e650000DwNd|9e650000DxNd", - fcvtms_2 = "1e300000DwNs|9e300000DxNs|1e700000DwNd|9e700000DxNd", - fcvtmu_2 = "1e310000DwNs|9e310000DxNs|1e710000DwNd|9e710000DxNd", - fcvtns_2 = "1e200000DwNs|9e200000DxNs|1e600000DwNd|9e600000DxNd", - fcvtnu_2 = "1e210000DwNs|9e210000DxNs|1e610000DwNd|9e610000DxNd", - fcvtps_2 = "1e280000DwNs|9e280000DxNs|1e680000DwNd|9e680000DxNd", - fcvtpu_2 = "1e290000DwNs|9e290000DxNs|1e690000DwNd|9e690000DxNd", - fcvtzs_2 = "1e380000DwNs|9e380000DxNs|1e780000DwNd|9e780000DxNd", - fcvtzu_2 = "1e390000DwNs|9e390000DxNs|1e790000DwNd|9e790000DxNd", - - scvtf_2 = "1e220000DsNw|9e220000DsNx|1e620000DdNw|9e620000DdNx", - ucvtf_2 = "1e230000DsNw|9e230000DsNx|1e630000DdNw|9e630000DdNx", - - frintn_2 = "1e244000DNf", - frintp_2 = "1e24c000DNf", - frintm_2 = "1e254000DNf", - frintz_2 = "1e25c000DNf", - frinta_2 = "1e264000DNf", - frintx_2 = "1e274000DNf", - frinti_2 = "1e27c000DNf", - - fadd_3 = "1e202800DNMf", - fsub_3 = "1e203800DNMf", - fmul_3 = "1e200800DNMf", - fnmul_3 = "1e208800DNMf", - fdiv_3 = "1e201800DNMf", - - fmadd_4 = "1f000000DNMAf", - fmsub_4 = "1f008000DNMAf", - fnmadd_4 = "1f200000DNMAf", - fnmsub_4 = "1f208000DNMAf", - - fmax_3 = "1e204800DNMf", - fmaxnm_3 = "1e206800DNMf", - fmin_3 = "1e205800DNMf", - fminnm_3 = "1e207800DNMf", - - fcmp_2 = "1e202000NMf|1e202008NZf", - fcmpe_2 = "1e202010NMf|1e202018NZf", - - fccmp_4 = "1e200400NMVCf", - fccmpe_4 = "1e200410NMVCf", - - fcsel_4 = "1e200c00DNMCf", - - -- TODO: crc32*, aes*, sha*, pmull - -- TODO: SIMD instructions. -} - -for cond,c in pairs(map_cond) do - map_op["b"..cond.."_1"] = tohex(0x54000000+c).."B" -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -local function parse_template(params, template, nparams, pos) - local op = tonumber(template:sub(1, 8), 16) - local n = 1 - local rtt = {} - - parse_reg_type = false - - -- Process each character. - for p in gmatch(template:sub(9), ".") do - local q = params[n] - if p == "D" then - op = op + parse_reg(q, 0); n = n + 1 - elseif p == "N" then - op = op + parse_reg(q, 5); n = n + 1 - elseif p == "M" then - op = op + parse_reg(q, 16); n = n + 1 - elseif p == "A" then - op = op + parse_reg(q, 10); n = n + 1 - elseif p == "m" then - op = op + parse_reg(params[n-1], 16) - - elseif p == "p" then - if q == "sp" then params[n] = "@x31" end - elseif p == "g" then - if parse_reg_type == "x" then - op = op + 0x80000000 - elseif parse_reg_type ~= "w" then - werror("bad register type") - end - parse_reg_type = false - elseif p == "f" then - if parse_reg_type == "d" then - op = op + 0x00400000 - elseif parse_reg_type ~= "s" then - werror("bad register type") - end - parse_reg_type = false - elseif p == "x" or p == "w" or p == "d" or p == "s" then - if parse_reg_type ~= p then - werror("register size mismatch") - end - parse_reg_type = false - - elseif p == "L" then - op = parse_load(params, nparams, n, op) - elseif p == "P" then - op = parse_load_pair(params, nparams, n, op) - - elseif p == "B" then - local mode, v, s = parse_label(q, false); n = n + 1 - if not mode then werror("bad label `"..q.."'") end - local m = branch_type(op) - if mode == "A" then - waction("REL_"..mode, v+m, format("(unsigned int)(%s)", s)) - actargs[#actargs+1] = format("(unsigned int)((%s)>>32)", s) - else - waction("REL_"..mode, v+m, s, 1) - end - - elseif p == "I" then - op = op + parse_imm12(q); n = n + 1 - elseif p == "i" then - op = op + parse_imm13(q); n = n + 1 - elseif p == "W" then - op = op + parse_imm(q, 16, 5, 0, false); n = n + 1 - elseif p == "T" then - op = op + parse_imm6(q); n = n + 1 - elseif p == "1" then - op = op + parse_imm(q, 6, 16, 0, false); n = n + 1 - elseif p == "2" then - op = op + parse_imm(q, 6, 10, 0, false); n = n + 1 - elseif p == "5" then - op = op + parse_imm(q, 5, 16, 0, false); n = n + 1 - elseif p == "V" then - op = op + parse_imm(q, 4, 0, 0, false); n = n + 1 - elseif p == "F" then - op = op + parse_fpimm(q); n = n + 1 - elseif p == "Z" then - if q ~= "#0" and q ~= "#0.0" then werror("expected zero immediate") end - n = n + 1 - - elseif p == "S" then - op = op + parse_shift(q); n = n + 1 - elseif p == "X" then - op = op + parse_extend(q); n = n + 1 - elseif p == "R" then - op = op + parse_lslx16(q); n = n + 1 - elseif p == "C" then - op = op + parse_cond(q, 0); n = n + 1 - elseif p == "c" then - op = op + parse_cond(q, 1); n = n + 1 - - else - assert(false) - end - end - wputpos(pos, op) -end - -function op_template(params, template, nparams) - if not params then return template:gsub("%x%x%x%x%x%x%x%x", "") end - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 4 positions. - if secpos+4 > maxsecpos then wflush() end - local pos = wpos() - local lpos, apos, spos = #actlist, #actargs, secpos - - local ok, err - for t in gmatch(template, "[^|]+") do - ok, err = pcall(parse_template, params, t, nparams, pos) - if ok then return end - secpos = spos - actlist[lpos+1] = nil - actlist[lpos+2] = nil - actlist[lpos+3] = nil - actlist[lpos+4] = nil - actargs[apos+1] = nil - actargs[apos+2] = nil - actargs[apos+3] = nil - actargs[apos+4] = nil - end - error(err, 0) -end - -map_op[".template__"] = op_template - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if not mode or mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -local function op_data(params) - if not params then return "imm..." end - local sz = params.op == ".long" and 4 or 8 - for _,p in ipairs(params) do - local imm = parse_number(p) - if imm then - local n = tobit(imm) - if n == imm or (n < 0 and n + 2^32 == imm) then - wputw(n < 0 and n + 2^32 or n) - if sz == 8 then - wputw(imm < 0 and 0xffffffff or 0) - end - elseif sz == 4 then - werror("bad immediate `"..p.."'") - else - imm = nil - end - end - if not imm then - local mode, v, s = parse_label(p, false) - if sz == 4 then - if mode then werror("label does not fit into .long") end - waction("IMMV", 0, p) - elseif mode and mode ~= "A" then - waction("REL_"..mode, v+0x8000, s, 1) - else - if mode == "A" then p = s end - waction("IMMV", 0, format("(unsigned int)(%s)", p)) - waction("IMMV", 0, format("(unsigned int)((unsigned long long)(%s)>>32)", p)) - end - end - if secpos+2 > maxsecpos then wflush() end - end -end -map_op[".long_*"] = op_data -map_op[".quad_*"] = op_data -map_op[".addr_*"] = op_data - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/dasm_mips.h b/ext/opcache/jit/dynasm/dasm_mips.h deleted file mode 100644 index b99b56b0e9ae6..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_mips.h +++ /dev/null @@ -1,424 +0,0 @@ -/* -** DynASM MIPS encoding engine. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "mips" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMS, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: case DASM_IMMS: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMMS: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16) - 0xff00; - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1); - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - if (n < 0) { - n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp); - goto patchrel; - } - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n); - if (ins & 2048) - n = (n + (int)(size_t)base) & 0x0fffffff; - else - n = n - (int)((char *)cp - base); - patchrel: { - unsigned int e = 16 + ((ins >> 12) & 15); - CK((n & 3) == 0 && - ((n + ((ins & 2048) ? 0 : (1<<(e+1)))) >> (e+2)) == 0, RANGE_REL); - cp[-1] |= ((n>>2) & ((1<= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMMS: - cp[-1] |= ((n>>3) & 4); n &= 0x1f; - /* fallthrough */ - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/ext/opcache/jit/dynasm/dasm_mips.lua b/ext/opcache/jit/dynasm/dasm_mips.lua deleted file mode 100644 index 591470157c4ee..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_mips.lua +++ /dev/null @@ -1,1181 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM MIPS32/MIPS64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - -local mips64 = mips64 -local mipsr6 = _map_def.MIPSR6 - --- Module information: -local _info = { - arch = mips64 and "mips64" or "mips", - description = "DynASM MIPS32/MIPS64 module", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable = assert, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch = _s.match, _s.gmatch -local concat, sort = table.concat, table.sort -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local tohex = bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMMS", -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(0xff000000 + w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n >= 0xff000000 then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = { sp="r29", ra="r31" } -- Ext. register name -> int. name. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - if s == "r29" then return "sp" - elseif s == "r31" then return "ra" end - return s -end - ------------------------------------------------------------------------------- - --- Template strings for MIPS instructions. -local map_op = { - -- First-level opcodes. - j_1 = "08000000J", - jal_1 = "0c000000J", - b_1 = "10000000B", - beqz_2 = "10000000SB", - beq_3 = "10000000STB", - bnez_2 = "14000000SB", - bne_3 = "14000000STB", - blez_2 = "18000000SB", - bgtz_2 = "1c000000SB", - li_2 = "24000000TI", - addiu_3 = "24000000TSI", - slti_3 = "28000000TSI", - sltiu_3 = "2c000000TSI", - andi_3 = "30000000TSU", - lu_2 = "34000000TU", - ori_3 = "34000000TSU", - xori_3 = "38000000TSU", - lui_2 = "3c000000TU", - daddiu_3 = mips64 and "64000000TSI", - ldl_2 = mips64 and "68000000TO", - ldr_2 = mips64 and "6c000000TO", - lb_2 = "80000000TO", - lh_2 = "84000000TO", - lw_2 = "8c000000TO", - lbu_2 = "90000000TO", - lhu_2 = "94000000TO", - lwu_2 = mips64 and "9c000000TO", - sb_2 = "a0000000TO", - sh_2 = "a4000000TO", - sw_2 = "ac000000TO", - lwc1_2 = "c4000000HO", - ldc1_2 = "d4000000HO", - ld_2 = mips64 and "dc000000TO", - swc1_2 = "e4000000HO", - sdc1_2 = "f4000000HO", - sd_2 = mips64 and "fc000000TO", - - -- Opcode SPECIAL. - nop_0 = "00000000", - sll_3 = "00000000DTA", - sextw_2 = "00000000DT", - srl_3 = "00000002DTA", - rotr_3 = "00200002DTA", - sra_3 = "00000003DTA", - sllv_3 = "00000004DTS", - srlv_3 = "00000006DTS", - rotrv_3 = "00000046DTS", - drotrv_3 = mips64 and "00000056DTS", - srav_3 = "00000007DTS", - jalr_1 = "0000f809S", - jalr_2 = "00000009DS", - syscall_0 = "0000000c", - syscall_1 = "0000000cY", - break_0 = "0000000d", - break_1 = "0000000dY", - sync_0 = "0000000f", - dsllv_3 = mips64 and "00000014DTS", - dsrlv_3 = mips64 and "00000016DTS", - dsrav_3 = mips64 and "00000017DTS", - add_3 = "00000020DST", - move_2 = mips64 and "00000025DS" or "00000021DS", - addu_3 = "00000021DST", - sub_3 = "00000022DST", - negu_2 = mips64 and "0000002fDT" or "00000023DT", - subu_3 = "00000023DST", - and_3 = "00000024DST", - or_3 = "00000025DST", - xor_3 = "00000026DST", - not_2 = "00000027DS", - nor_3 = "00000027DST", - slt_3 = "0000002aDST", - sltu_3 = "0000002bDST", - dadd_3 = mips64 and "0000002cDST", - daddu_3 = mips64 and "0000002dDST", - dsub_3 = mips64 and "0000002eDST", - dsubu_3 = mips64 and "0000002fDST", - tge_2 = "00000030ST", - tge_3 = "00000030STZ", - tgeu_2 = "00000031ST", - tgeu_3 = "00000031STZ", - tlt_2 = "00000032ST", - tlt_3 = "00000032STZ", - tltu_2 = "00000033ST", - tltu_3 = "00000033STZ", - teq_2 = "00000034ST", - teq_3 = "00000034STZ", - tne_2 = "00000036ST", - tne_3 = "00000036STZ", - dsll_3 = mips64 and "00000038DTa", - dsrl_3 = mips64 and "0000003aDTa", - drotr_3 = mips64 and "0020003aDTa", - dsra_3 = mips64 and "0000003bDTa", - dsll32_3 = mips64 and "0000003cDTA", - dsrl32_3 = mips64 and "0000003eDTA", - drotr32_3 = mips64 and "0020003eDTA", - dsra32_3 = mips64 and "0000003fDTA", - - -- Opcode REGIMM. - bltz_2 = "04000000SB", - bgez_2 = "04010000SB", - bltzl_2 = "04020000SB", - bgezl_2 = "04030000SB", - bal_1 = "04110000B", - synci_1 = "041f0000O", - - -- Opcode SPECIAL3. - ext_4 = "7c000000TSAM", -- Note: last arg is msbd = size-1 - dextm_4 = mips64 and "7c000001TSAM", -- Args: pos | size-1-32 - dextu_4 = mips64 and "7c000002TSAM", -- Args: pos-32 | size-1 - dext_4 = mips64 and "7c000003TSAM", -- Args: pos | size-1 - zextw_2 = mips64 and "7c00f803TS", - ins_4 = "7c000004TSAM", -- Note: last arg is msb = pos+size-1 - dinsm_4 = mips64 and "7c000005TSAM", -- Args: pos | pos+size-33 - dinsu_4 = mips64 and "7c000006TSAM", -- Args: pos-32 | pos+size-33 - dins_4 = mips64 and "7c000007TSAM", -- Args: pos | pos+size-1 - wsbh_2 = "7c0000a0DT", - dsbh_2 = mips64 and "7c0000a4DT", - dshd_2 = mips64 and "7c000164DT", - seb_2 = "7c000420DT", - seh_2 = "7c000620DT", - rdhwr_2 = "7c00003bTD", - - -- Opcode COP0. - mfc0_2 = "40000000TD", - mfc0_3 = "40000000TDW", - dmfc0_2 = mips64 and "40200000TD", - dmfc0_3 = mips64 and "40200000TDW", - mtc0_2 = "40800000TD", - mtc0_3 = "40800000TDW", - dmtc0_2 = mips64 and "40a00000TD", - dmtc0_3 = mips64 and "40a00000TDW", - rdpgpr_2 = "41400000DT", - di_0 = "41606000", - di_1 = "41606000T", - ei_0 = "41606020", - ei_1 = "41606020T", - wrpgpr_2 = "41c00000DT", - tlbr_0 = "42000001", - tlbwi_0 = "42000002", - tlbwr_0 = "42000006", - tlbp_0 = "42000008", - eret_0 = "42000018", - deret_0 = "4200001f", - wait_0 = "42000020", - - -- Opcode COP1. - mfc1_2 = "44000000TG", - dmfc1_2 = mips64 and "44200000TG", - cfc1_2 = "44400000TG", - mfhc1_2 = "44600000TG", - mtc1_2 = "44800000TG", - dmtc1_2 = mips64 and "44a00000TG", - ctc1_2 = "44c00000TG", - mthc1_2 = "44e00000TG", - - ["add.s_3"] = "46000000FGH", - ["sub.s_3"] = "46000001FGH", - ["mul.s_3"] = "46000002FGH", - ["div.s_3"] = "46000003FGH", - ["sqrt.s_2"] = "46000004FG", - ["abs.s_2"] = "46000005FG", - ["mov.s_2"] = "46000006FG", - ["neg.s_2"] = "46000007FG", - ["round.l.s_2"] = "46000008FG", - ["trunc.l.s_2"] = "46000009FG", - ["ceil.l.s_2"] = "4600000aFG", - ["floor.l.s_2"] = "4600000bFG", - ["round.w.s_2"] = "4600000cFG", - ["trunc.w.s_2"] = "4600000dFG", - ["ceil.w.s_2"] = "4600000eFG", - ["floor.w.s_2"] = "4600000fFG", - ["recip.s_2"] = "46000015FG", - ["rsqrt.s_2"] = "46000016FG", - ["cvt.d.s_2"] = "46000021FG", - ["cvt.w.s_2"] = "46000024FG", - ["cvt.l.s_2"] = "46000025FG", - ["add.d_3"] = "46200000FGH", - ["sub.d_3"] = "46200001FGH", - ["mul.d_3"] = "46200002FGH", - ["div.d_3"] = "46200003FGH", - ["sqrt.d_2"] = "46200004FG", - ["abs.d_2"] = "46200005FG", - ["mov.d_2"] = "46200006FG", - ["neg.d_2"] = "46200007FG", - ["round.l.d_2"] = "46200008FG", - ["trunc.l.d_2"] = "46200009FG", - ["ceil.l.d_2"] = "4620000aFG", - ["floor.l.d_2"] = "4620000bFG", - ["round.w.d_2"] = "4620000cFG", - ["trunc.w.d_2"] = "4620000dFG", - ["ceil.w.d_2"] = "4620000eFG", - ["floor.w.d_2"] = "4620000fFG", - ["recip.d_2"] = "46200015FG", - ["rsqrt.d_2"] = "46200016FG", - ["cvt.s.d_2"] = "46200020FG", - ["cvt.w.d_2"] = "46200024FG", - ["cvt.l.d_2"] = "46200025FG", - ["cvt.s.w_2"] = "46800020FG", - ["cvt.d.w_2"] = "46800021FG", - ["cvt.s.l_2"] = "46a00020FG", - ["cvt.d.l_2"] = "46a00021FG", -} - -if mipsr6 then -- Instructions added with MIPSR6. - - for k,v in pairs({ - - -- Add immediate to upper bits. - aui_3 = "3c000000TSI", - daui_3 = mips64 and "74000000TSI", - dahi_2 = mips64 and "04060000SI", - dati_2 = mips64 and "041e0000SI", - - -- TODO: addiupc, auipc, aluipc, lwpc, lwupc, ldpc. - - -- Compact branches. - blezalc_2 = "18000000TB", -- rt != 0. - bgezalc_2 = "18000000T=SB", -- rt != 0. - bgtzalc_2 = "1c000000TB", -- rt != 0. - bltzalc_2 = "1c000000T=SB", -- rt != 0. - - blezc_2 = "58000000TB", -- rt != 0. - bgezc_2 = "58000000T=SB", -- rt != 0. - bgec_3 = "58000000STB", -- rs != rt. - blec_3 = "58000000TSB", -- rt != rs. - - bgtzc_2 = "5c000000TB", -- rt != 0. - bltzc_2 = "5c000000T=SB", -- rt != 0. - bltc_3 = "5c000000STB", -- rs != rt. - bgtc_3 = "5c000000TSB", -- rt != rs. - - bgeuc_3 = "18000000STB", -- rs != rt. - bleuc_3 = "18000000TSB", -- rt != rs. - bltuc_3 = "1c000000STB", -- rs != rt. - bgtuc_3 = "1c000000TSB", -- rt != rs. - - beqzalc_2 = "20000000TB", -- rt != 0. - bnezalc_2 = "60000000TB", -- rt != 0. - beqc_3 = "20000000STB", -- rs < rt. - bnec_3 = "60000000STB", -- rs < rt. - bovc_3 = "20000000STB", -- rs >= rt. - bnvc_3 = "60000000STB", -- rs >= rt. - - beqzc_2 = "d8000000SK", -- rs != 0. - bnezc_2 = "f8000000SK", -- rs != 0. - jic_2 = "d8000000TI", - jialc_2 = "f8000000TI", - bc_1 = "c8000000L", - balc_1 = "e8000000L", - - -- Opcode SPECIAL. - jr_1 = "00000009S", - sdbbp_0 = "0000000e", - sdbbp_1 = "0000000eY", - lsa_4 = "00000005DSTA", - dlsa_4 = mips64 and "00000015DSTA", - seleqz_3 = "00000035DST", - selnez_3 = "00000037DST", - clz_2 = "00000050DS", - clo_2 = "00000051DS", - dclz_2 = mips64 and "00000052DS", - dclo_2 = mips64 and "00000053DS", - mul_3 = "00000098DST", - muh_3 = "000000d8DST", - mulu_3 = "00000099DST", - muhu_3 = "000000d9DST", - div_3 = "0000009aDST", - mod_3 = "000000daDST", - divu_3 = "0000009bDST", - modu_3 = "000000dbDST", - dmul_3 = mips64 and "0000009cDST", - dmuh_3 = mips64 and "000000dcDST", - dmulu_3 = mips64 and "0000009dDST", - dmuhu_3 = mips64 and "000000ddDST", - ddiv_3 = mips64 and "0000009eDST", - dmod_3 = mips64 and "000000deDST", - ddivu_3 = mips64 and "0000009fDST", - dmodu_3 = mips64 and "000000dfDST", - - -- Opcode SPECIAL3. - align_4 = "7c000220DSTA", - dalign_4 = mips64 and "7c000224DSTA", - bitswap_2 = "7c000020DT", - dbitswap_2 = mips64 and "7c000024DT", - - -- Opcode COP1. - bc1eqz_2 = "45200000HB", - bc1nez_2 = "45a00000HB", - - ["sel.s_3"] = "46000010FGH", - ["seleqz.s_3"] = "46000014FGH", - ["selnez.s_3"] = "46000017FGH", - ["maddf.s_3"] = "46000018FGH", - ["msubf.s_3"] = "46000019FGH", - ["rint.s_2"] = "4600001aFG", - ["class.s_2"] = "4600001bFG", - ["min.s_3"] = "4600001cFGH", - ["mina.s_3"] = "4600001dFGH", - ["max.s_3"] = "4600001eFGH", - ["maxa.s_3"] = "4600001fFGH", - ["cmp.af.s_3"] = "46800000FGH", - ["cmp.un.s_3"] = "46800001FGH", - ["cmp.or.s_3"] = "46800011FGH", - ["cmp.eq.s_3"] = "46800002FGH", - ["cmp.une.s_3"] = "46800012FGH", - ["cmp.ueq.s_3"] = "46800003FGH", - ["cmp.ne.s_3"] = "46800013FGH", - ["cmp.lt.s_3"] = "46800004FGH", - ["cmp.ult.s_3"] = "46800005FGH", - ["cmp.le.s_3"] = "46800006FGH", - ["cmp.ule.s_3"] = "46800007FGH", - ["cmp.saf.s_3"] = "46800008FGH", - ["cmp.sun.s_3"] = "46800009FGH", - ["cmp.sor.s_3"] = "46800019FGH", - ["cmp.seq.s_3"] = "4680000aFGH", - ["cmp.sune.s_3"] = "4680001aFGH", - ["cmp.sueq.s_3"] = "4680000bFGH", - ["cmp.sne.s_3"] = "4680001bFGH", - ["cmp.slt.s_3"] = "4680000cFGH", - ["cmp.sult.s_3"] = "4680000dFGH", - ["cmp.sle.s_3"] = "4680000eFGH", - ["cmp.sule.s_3"] = "4680000fFGH", - - ["sel.d_3"] = "46200010FGH", - ["seleqz.d_3"] = "46200014FGH", - ["selnez.d_3"] = "46200017FGH", - ["maddf.d_3"] = "46200018FGH", - ["msubf.d_3"] = "46200019FGH", - ["rint.d_2"] = "4620001aFG", - ["class.d_2"] = "4620001bFG", - ["min.d_3"] = "4620001cFGH", - ["mina.d_3"] = "4620001dFGH", - ["max.d_3"] = "4620001eFGH", - ["maxa.d_3"] = "4620001fFGH", - ["cmp.af.d_3"] = "46a00000FGH", - ["cmp.un.d_3"] = "46a00001FGH", - ["cmp.or.d_3"] = "46a00011FGH", - ["cmp.eq.d_3"] = "46a00002FGH", - ["cmp.une.d_3"] = "46a00012FGH", - ["cmp.ueq.d_3"] = "46a00003FGH", - ["cmp.ne.d_3"] = "46a00013FGH", - ["cmp.lt.d_3"] = "46a00004FGH", - ["cmp.ult.d_3"] = "46a00005FGH", - ["cmp.le.d_3"] = "46a00006FGH", - ["cmp.ule.d_3"] = "46a00007FGH", - ["cmp.saf.d_3"] = "46a00008FGH", - ["cmp.sun.d_3"] = "46a00009FGH", - ["cmp.sor.d_3"] = "46a00019FGH", - ["cmp.seq.d_3"] = "46a0000aFGH", - ["cmp.sune.d_3"] = "46a0001aFGH", - ["cmp.sueq.d_3"] = "46a0000bFGH", - ["cmp.sne.d_3"] = "46a0001bFGH", - ["cmp.slt.d_3"] = "46a0000cFGH", - ["cmp.sult.d_3"] = "46a0000dFGH", - ["cmp.sle.d_3"] = "46a0000eFGH", - ["cmp.sule.d_3"] = "46a0000fFGH", - - }) do map_op[k] = v end - -else -- Instructions removed by MIPSR6. - - for k,v in pairs({ - -- Traps, don't use. - addi_3 = "20000000TSI", - daddi_3 = mips64 and "60000000TSI", - - -- Branch on likely, don't use. - beqzl_2 = "50000000SB", - beql_3 = "50000000STB", - bnezl_2 = "54000000SB", - bnel_3 = "54000000STB", - blezl_2 = "58000000SB", - bgtzl_2 = "5c000000SB", - - lwl_2 = "88000000TO", - lwr_2 = "98000000TO", - swl_2 = "a8000000TO", - sdl_2 = mips64 and "b0000000TO", - sdr_2 = mips64 and "b1000000TO", - swr_2 = "b8000000TO", - cache_2 = "bc000000NO", - ll_2 = "c0000000TO", - pref_2 = "cc000000NO", - sc_2 = "e0000000TO", - scd_2 = mips64 and "f0000000TO", - - -- Opcode SPECIAL. - movf_2 = "00000001DS", - movf_3 = "00000001DSC", - movt_2 = "00010001DS", - movt_3 = "00010001DSC", - jr_1 = "00000008S", - movz_3 = "0000000aDST", - movn_3 = "0000000bDST", - mfhi_1 = "00000010D", - mthi_1 = "00000011S", - mflo_1 = "00000012D", - mtlo_1 = "00000013S", - mult_2 = "00000018ST", - multu_2 = "00000019ST", - div_3 = "0000001aST", - divu_3 = "0000001bST", - ddiv_3 = mips64 and "0000001eST", - ddivu_3 = mips64 and "0000001fST", - dmult_2 = mips64 and "0000001cST", - dmultu_2 = mips64 and "0000001dST", - - -- Opcode REGIMM. - tgei_2 = "04080000SI", - tgeiu_2 = "04090000SI", - tlti_2 = "040a0000SI", - tltiu_2 = "040b0000SI", - teqi_2 = "040c0000SI", - tnei_2 = "040e0000SI", - bltzal_2 = "04100000SB", - bgezal_2 = "04110000SB", - bltzall_2 = "04120000SB", - bgezall_2 = "04130000SB", - - -- Opcode SPECIAL2. - madd_2 = "70000000ST", - maddu_2 = "70000001ST", - mul_3 = "70000002DST", - msub_2 = "70000004ST", - msubu_2 = "70000005ST", - clz_2 = "70000020D=TS", - clo_2 = "70000021D=TS", - dclz_2 = mips64 and "70000024D=TS", - dclo_2 = mips64 and "70000025D=TS", - sdbbp_0 = "7000003f", - sdbbp_1 = "7000003fY", - - -- Opcode COP1. - bc1f_1 = "45000000B", - bc1f_2 = "45000000CB", - bc1t_1 = "45010000B", - bc1t_2 = "45010000CB", - bc1fl_1 = "45020000B", - bc1fl_2 = "45020000CB", - bc1tl_1 = "45030000B", - bc1tl_2 = "45030000CB", - - ["movf.s_2"] = "46000011FG", - ["movf.s_3"] = "46000011FGC", - ["movt.s_2"] = "46010011FG", - ["movt.s_3"] = "46010011FGC", - ["movz.s_3"] = "46000012FGT", - ["movn.s_3"] = "46000013FGT", - ["cvt.ps.s_3"] = "46000026FGH", - ["c.f.s_2"] = "46000030GH", - ["c.f.s_3"] = "46000030VGH", - ["c.un.s_2"] = "46000031GH", - ["c.un.s_3"] = "46000031VGH", - ["c.eq.s_2"] = "46000032GH", - ["c.eq.s_3"] = "46000032VGH", - ["c.ueq.s_2"] = "46000033GH", - ["c.ueq.s_3"] = "46000033VGH", - ["c.olt.s_2"] = "46000034GH", - ["c.olt.s_3"] = "46000034VGH", - ["c.ult.s_2"] = "46000035GH", - ["c.ult.s_3"] = "46000035VGH", - ["c.ole.s_2"] = "46000036GH", - ["c.ole.s_3"] = "46000036VGH", - ["c.ule.s_2"] = "46000037GH", - ["c.ule.s_3"] = "46000037VGH", - ["c.sf.s_2"] = "46000038GH", - ["c.sf.s_3"] = "46000038VGH", - ["c.ngle.s_2"] = "46000039GH", - ["c.ngle.s_3"] = "46000039VGH", - ["c.seq.s_2"] = "4600003aGH", - ["c.seq.s_3"] = "4600003aVGH", - ["c.ngl.s_2"] = "4600003bGH", - ["c.ngl.s_3"] = "4600003bVGH", - ["c.lt.s_2"] = "4600003cGH", - ["c.lt.s_3"] = "4600003cVGH", - ["c.nge.s_2"] = "4600003dGH", - ["c.nge.s_3"] = "4600003dVGH", - ["c.le.s_2"] = "4600003eGH", - ["c.le.s_3"] = "4600003eVGH", - ["c.ngt.s_2"] = "4600003fGH", - ["c.ngt.s_3"] = "4600003fVGH", - ["movf.d_2"] = "46200011FG", - ["movf.d_3"] = "46200011FGC", - ["movt.d_2"] = "46210011FG", - ["movt.d_3"] = "46210011FGC", - ["movz.d_3"] = "46200012FGT", - ["movn.d_3"] = "46200013FGT", - ["c.f.d_2"] = "46200030GH", - ["c.f.d_3"] = "46200030VGH", - ["c.un.d_2"] = "46200031GH", - ["c.un.d_3"] = "46200031VGH", - ["c.eq.d_2"] = "46200032GH", - ["c.eq.d_3"] = "46200032VGH", - ["c.ueq.d_2"] = "46200033GH", - ["c.ueq.d_3"] = "46200033VGH", - ["c.olt.d_2"] = "46200034GH", - ["c.olt.d_3"] = "46200034VGH", - ["c.ult.d_2"] = "46200035GH", - ["c.ult.d_3"] = "46200035VGH", - ["c.ole.d_2"] = "46200036GH", - ["c.ole.d_3"] = "46200036VGH", - ["c.ule.d_2"] = "46200037GH", - ["c.ule.d_3"] = "46200037VGH", - ["c.sf.d_2"] = "46200038GH", - ["c.sf.d_3"] = "46200038VGH", - ["c.ngle.d_2"] = "46200039GH", - ["c.ngle.d_3"] = "46200039VGH", - ["c.seq.d_2"] = "4620003aGH", - ["c.seq.d_3"] = "4620003aVGH", - ["c.ngl.d_2"] = "4620003bGH", - ["c.ngl.d_3"] = "4620003bVGH", - ["c.lt.d_2"] = "4620003cGH", - ["c.lt.d_3"] = "4620003cVGH", - ["c.nge.d_2"] = "4620003dGH", - ["c.nge.d_3"] = "4620003dVGH", - ["c.le.d_2"] = "4620003eGH", - ["c.le.d_3"] = "4620003eVGH", - ["c.ngt.d_2"] = "4620003fGH", - ["c.ngt.d_3"] = "4620003fVGH", - ["add.ps_3"] = "46c00000FGH", - ["sub.ps_3"] = "46c00001FGH", - ["mul.ps_3"] = "46c00002FGH", - ["abs.ps_2"] = "46c00005FG", - ["mov.ps_2"] = "46c00006FG", - ["neg.ps_2"] = "46c00007FG", - ["movf.ps_2"] = "46c00011FG", - ["movf.ps_3"] = "46c00011FGC", - ["movt.ps_2"] = "46c10011FG", - ["movt.ps_3"] = "46c10011FGC", - ["movz.ps_3"] = "46c00012FGT", - ["movn.ps_3"] = "46c00013FGT", - ["cvt.s.pu_2"] = "46c00020FG", - ["cvt.s.pl_2"] = "46c00028FG", - ["pll.ps_3"] = "46c0002cFGH", - ["plu.ps_3"] = "46c0002dFGH", - ["pul.ps_3"] = "46c0002eFGH", - ["puu.ps_3"] = "46c0002fFGH", - ["c.f.ps_2"] = "46c00030GH", - ["c.f.ps_3"] = "46c00030VGH", - ["c.un.ps_2"] = "46c00031GH", - ["c.un.ps_3"] = "46c00031VGH", - ["c.eq.ps_2"] = "46c00032GH", - ["c.eq.ps_3"] = "46c00032VGH", - ["c.ueq.ps_2"] = "46c00033GH", - ["c.ueq.ps_3"] = "46c00033VGH", - ["c.olt.ps_2"] = "46c00034GH", - ["c.olt.ps_3"] = "46c00034VGH", - ["c.ult.ps_2"] = "46c00035GH", - ["c.ult.ps_3"] = "46c00035VGH", - ["c.ole.ps_2"] = "46c00036GH", - ["c.ole.ps_3"] = "46c00036VGH", - ["c.ule.ps_2"] = "46c00037GH", - ["c.ule.ps_3"] = "46c00037VGH", - ["c.sf.ps_2"] = "46c00038GH", - ["c.sf.ps_3"] = "46c00038VGH", - ["c.ngle.ps_2"] = "46c00039GH", - ["c.ngle.ps_3"] = "46c00039VGH", - ["c.seq.ps_2"] = "46c0003aGH", - ["c.seq.ps_3"] = "46c0003aVGH", - ["c.ngl.ps_2"] = "46c0003bGH", - ["c.ngl.ps_3"] = "46c0003bVGH", - ["c.lt.ps_2"] = "46c0003cGH", - ["c.lt.ps_3"] = "46c0003cVGH", - ["c.nge.ps_2"] = "46c0003dGH", - ["c.nge.ps_3"] = "46c0003dVGH", - ["c.le.ps_2"] = "46c0003eGH", - ["c.le.ps_3"] = "46c0003eVGH", - ["c.ngt.ps_2"] = "46c0003fGH", - ["c.ngt.ps_3"] = "46c0003fVGH", - - -- Opcode COP1X. - lwxc1_2 = "4c000000FX", - ldxc1_2 = "4c000001FX", - luxc1_2 = "4c000005FX", - swxc1_2 = "4c000008FX", - sdxc1_2 = "4c000009FX", - suxc1_2 = "4c00000dFX", - prefx_2 = "4c00000fMX", - ["alnv.ps_4"] = "4c00001eFGHS", - ["madd.s_4"] = "4c000020FRGH", - ["madd.d_4"] = "4c000021FRGH", - ["madd.ps_4"] = "4c000026FRGH", - ["msub.s_4"] = "4c000028FRGH", - ["msub.d_4"] = "4c000029FRGH", - ["msub.ps_4"] = "4c00002eFRGH", - ["nmadd.s_4"] = "4c000030FRGH", - ["nmadd.d_4"] = "4c000031FRGH", - ["nmadd.ps_4"] = "4c000036FRGH", - ["nmsub.s_4"] = "4c000038FRGH", - ["nmsub.d_4"] = "4c000039FRGH", - ["nmsub.ps_4"] = "4c00003eFRGH", - - }) do map_op[k] = v end - -end - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_fpr(expr) - local r = match(expr, "^f([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_imm(imm, bits, shift, scale, signed, action) - local n = tonumber(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^[rf]([1-3]?[0-9])$") or - match(imm, "^([%w_]+):([rf][1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction(action or "IMM", - (signed and 32768 or 0)+shl(scale, 10)+shl(bits, 5)+shift, imm) - return 0 - end -end - -local function parse_disp(disp) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = shl(parse_gpr(reg), 21) - local extname = match(imm, "^extern%s+(%S+)$") - if extname then - waction("REL_EXT", map_extern[extname], nil, 1) - return r - else - return r + parse_imm(imm, 16, 0, 0, true) - end - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if tp then - waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) - return shl(r, 21) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_index(idx) - local rt, rs = match(idx, "^(.*)%(([%w_:]+)%)$") - if rt then - rt = parse_gpr(rt) - rs = parse_gpr(rs) - return shl(rt, 16) + shl(rs, 21) - end - werror("bad index `"..idx.."'") -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) - if not params then return sub(template, 9) end - local op = tonumber(sub(template, 1, 8), 16) - local n = 1 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 2 positions (ins/ext). - if secpos+2 > maxsecpos then wflush() end - local pos = wpos() - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - if p == "D" then - op = op + shl(parse_gpr(params[n]), 11); n = n + 1 - elseif p == "T" then - op = op + shl(parse_gpr(params[n]), 16); n = n + 1 - elseif p == "S" then - op = op + shl(parse_gpr(params[n]), 21); n = n + 1 - elseif p == "F" then - op = op + shl(parse_fpr(params[n]), 6); n = n + 1 - elseif p == "G" then - op = op + shl(parse_fpr(params[n]), 11); n = n + 1 - elseif p == "H" then - op = op + shl(parse_fpr(params[n]), 16); n = n + 1 - elseif p == "R" then - op = op + shl(parse_fpr(params[n]), 21); n = n + 1 - elseif p == "I" then - op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 - elseif p == "U" then - op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 - elseif p == "O" then - op = op + parse_disp(params[n]); n = n + 1 - elseif p == "X" then - op = op + parse_index(params[n]); n = n + 1 - elseif p == "B" or p == "J" or p == "K" or p == "L" then - local mode, m, s = parse_label(params[n], false) - if p == "J" then m = m + 0xa800 - elseif p == "K" then m = m + 0x5000 - elseif p == "L" then m = m + 0xa000 end - waction("REL_"..mode, m, s, 1) - n = n + 1 - elseif p == "A" then - op = op + parse_imm(params[n], 5, 6, 0, false); n = n + 1 - elseif p == "a" then - local m = parse_imm(params[n], 6, 6, 0, false, "IMMS"); n = n + 1 - op = op + band(m, 0x7c0) + band(shr(m, 9), 4) - elseif p == "M" then - op = op + parse_imm(params[n], 5, 11, 0, false); n = n + 1 - elseif p == "N" then - op = op + parse_imm(params[n], 5, 16, 0, false); n = n + 1 - elseif p == "C" then - op = op + parse_imm(params[n], 3, 18, 0, false); n = n + 1 - elseif p == "V" then - op = op + parse_imm(params[n], 3, 8, 0, false); n = n + 1 - elseif p == "W" then - op = op + parse_imm(params[n], 3, 0, 0, false); n = n + 1 - elseif p == "Y" then - op = op + parse_imm(params[n], 20, 6, 0, false); n = n + 1 - elseif p == "Z" then - op = op + parse_imm(params[n], 10, 6, 0, false); n = n + 1 - elseif p == "=" then - n = n - 1 -- Re-use previous parameter for next template char. - else - assert(false) - end - end - wputpos(pos, op) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/dasm_mips64.lua b/ext/opcache/jit/dynasm/dasm_mips64.lua deleted file mode 100644 index 8ab5d33a2084f..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_mips64.lua +++ /dev/null @@ -1,12 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM MIPS64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- --- This module just sets 64 bit mode for the combined MIPS/MIPS64 module. --- All the interesting stuff is there. ------------------------------------------------------------------------------- - -mips64 = true -- Using a global is an ugly, but effective solution. -return require("dasm_mips") diff --git a/ext/opcache/jit/dynasm/dasm_ppc.h b/ext/opcache/jit/dynasm/dasm_ppc.h deleted file mode 100644 index 35264f2eb93b9..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_ppc.h +++ /dev/null @@ -1,423 +0,0 @@ -/* -** DynASM PPC/PPC64 encoding engine. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "ppc" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. */ -enum { - DASM_STOP, DASM_SECTION, DASM_ESC, DASM_REL_EXT, - /* The following actions need a buffer position. */ - DASM_ALIGN, DASM_REL_LG, DASM_LABEL_LG, - /* The following actions also have an argument. */ - DASM_REL_PC, DASM_LABEL_PC, DASM_IMM, DASM_IMMSH, - DASM__MAX -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_REL 0x15000000 -#define DASM_S_UNDEF_LG 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned int *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = D->sections[i].buf - DASM_SEC2POS(i); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; - D->globals = gl - 10; /* Negative bias to compensate for locals. */ - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status = DASM_S_RANGE_##st|(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - if (action >= DASM__MAX) { - ofs += 4; - } else { - int *pl, n = action >= DASM_REL_PC ? va_arg(ap, int) : 0; - switch (action) { - case DASM_STOP: goto stop; - case DASM_SECTION: - n = (ins & 255); CK(n < D->maxsection, RANGE_SEC); - D->section = &D->sections[n]; goto stop; - case DASM_ESC: p++; ofs += 4; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs += (ins & 255); b[pos++] = ofs; break; - case DASM_REL_LG: - n = (ins & 2047) - 10; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n >= 0) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl += 10; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - break; - case DASM_LABEL_LG: - pl = D->lglabels + (ins & 2047) - 10; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: - pl = D->pclabels + n; CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; - } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_IMM: -#ifdef DASM_CHECKS - CK((n & ((1<<((ins>>10)&31))-1)) == 0, RANGE_I); -#endif - n >>= ((ins>>10)&31); -#ifdef DASM_CHECKS - if (ins & 0x8000) - CK(((n + (1<<(((ins>>5)&31)-1)))>>((ins>>5)&31)) == 0, RANGE_I); - else - CK((n>>((ins>>5)&31)) == 0, RANGE_I); -#endif - b[pos++] = n; - break; - case DASM_IMMSH: - CK((n >> 6) == 0, RANGE_I); - b[pos++] = n; - break; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: p++; break; - case DASM_REL_EXT: break; - case DASM_ALIGN: ofs -= (b[pos++] + ofs) & (ins & 255); break; - case DASM_REL_LG: case DASM_REL_PC: pos++; break; - case DASM_LABEL_LG: case DASM_LABEL_PC: b[pos++] += ofs; break; - case DASM_IMM: case DASM_IMMSH: pos++; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) return DASM_S_##st|(p-D->actionlist-1); } while (0) -#else -#define CK(x, st) ((void)0) -#endif - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - char *base = (char *)buffer; - unsigned int *cp = (unsigned int *)buffer; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = sec->rbuf + sec->pos; - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - while (1) { - unsigned int ins = *p++; - unsigned int action = (ins >> 16); - int n = (action >= DASM_ALIGN && action < DASM__MAX) ? *b++ : 0; - switch (action) { - case DASM_STOP: case DASM_SECTION: goto stop; - case DASM_ESC: *cp++ = *p++; break; - case DASM_REL_EXT: - n = DASM_EXTERN(Dst, (unsigned char *)cp, (ins & 2047), 1) - 4; - goto patchrel; - case DASM_ALIGN: - ins &= 255; while ((((char *)cp - base) & ins)) *cp++ = 0x60000000; - break; - case DASM_REL_LG: - if (n < 0) { - n = (int)((ptrdiff_t)D->globals[-n] - (ptrdiff_t)cp); - goto patchrel; - } - /* fallthrough */ - case DASM_REL_PC: - CK(n >= 0, UNDEF_PC); - n = *DASM_POS2PTR(D, n) - (int)((char *)cp - base); - patchrel: - CK((n & 3) == 0 && - (((n+4) + ((ins & 2048) ? 0x00008000 : 0x02000000)) >> - ((ins & 2048) ? 16 : 26)) == 0, RANGE_REL); - cp[-1] |= ((n+4) & ((ins & 2048) ? 0x0000fffc: 0x03fffffc)); - break; - case DASM_LABEL_LG: - ins &= 2047; if (ins >= 20) D->globals[ins-10] = (void *)(base + n); - break; - case DASM_LABEL_PC: break; - case DASM_IMM: - cp[-1] |= (n & ((1<<((ins>>5)&31))-1)) << (ins&31); - break; - case DASM_IMMSH: - cp[-1] |= (ins & 1) ? ((n&31)<<11)|((n&32)>>4) : ((n&31)<<6)|(n&32); - break; - default: *cp++ = ins; break; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != (char *)cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} -#undef CK - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_LG|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(D->section-D->sections); - return D->status; -} -#endif - diff --git a/ext/opcache/jit/dynasm/dasm_ppc.lua b/ext/opcache/jit/dynasm/dasm_ppc.lua deleted file mode 100644 index ee2afb2ecfadf..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_ppc.lua +++ /dev/null @@ -1,1919 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM PPC/PPC64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. --- --- Support for various extensions contributed by Caio Souza Oliveira. ------------------------------------------------------------------------------- - --- Module information: -local _info = { - arch = "ppc", - description = "DynASM PPC module", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, setmetatable = assert, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local match, gmatch = _s.match, _s.gmatch -local concat, sort = table.concat, table.sort -local bit = bit or require("bit") -local band, shl, shr, sar = bit.band, bit.lshift, bit.rshift, bit.arshift -local tohex = bit.tohex - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - "STOP", "SECTION", "ESC", "REL_EXT", - "ALIGN", "REL_LG", "LABEL_LG", - "REL_PC", "LABEL_PC", "IMM", "IMMSH" -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number. -local map_action = {} -for n,name in ipairs(action_names) do - map_action[name] = n-1 -end - --- Action list buffer. -local actlist = {} - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - ------------------------------------------------------------------------------- - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - if nn == 0 then nn = 1; actlist[0] = map_action.STOP end - out:write("static const unsigned int ", name, "[", nn, "] = {\n") - for i = 1,nn-1 do - assert(out:write("0x", tohex(actlist[i]), ",\n")) - end - assert(out:write("0x", tohex(actlist[nn]), "\n};\n\n")) -end - ------------------------------------------------------------------------------- - --- Add word to action list. -local function wputxw(n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, val, a, num) - local w = assert(map_action[action], "bad action name `"..action.."'") - wputxw(w * 0x10000 + (val or 0)) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - if #actlist == actargs[1] then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - wline(format("dasm_put(Dst, %s);", concat(actargs, ", ")), true) - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped word. -local function wputw(n) - if n <= 0xffffff then waction("ESC") end - wputxw(n) -end - --- Reserve position for word. -local function wpos() - local pos = #actlist+1 - actlist[pos] = "" - return pos -end - --- Store word to reserved position. -local function wputpos(pos, n) - assert(n >= 0 and n <= 0xffffffff and n % 1 == 0, "word out of range") - actlist[pos] = n -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 20 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_]*$") then werror("bad global label") end - local n = next_global - if n > 2047 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=20,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=20,next_global-1 do - out:write(" ", prefix, t[i], ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=20,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = 0 -local map_extern_ = {} -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n > 2047 then werror("too many extern labels") end - next_extern = n + 1 - t[name] = n - map_extern_[n] = name - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - out:write("Extern labels:\n") - for i=0,next_extern-1 do - out:write(format(" %s\n", map_extern_[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - out:write("static const char *const ", name, "[] = {\n") - for i=0,next_extern-1 do - out:write(" \"", map_extern_[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = { sp = "r1" } -- Ext. register name -> int. name. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for Dt... macros). - --- Reverse defines for registers. -function _M.revdef(s) - if s == "r1" then return "sp" end - return s -end - -local map_cond = { - lt = 0, gt = 1, eq = 2, so = 3, - ge = 4, le = 5, ne = 6, ns = 7, -} - ------------------------------------------------------------------------------- - -local map_op, op_template - -local function op_alias(opname, f) - return function(params, nparams) - if not params then return "-> "..opname:sub(1, -3) end - f(params, nparams) - op_template(params, map_op[opname], nparams) - end -end - --- Template strings for PPC instructions. -map_op = { - tdi_3 = "08000000ARI", - twi_3 = "0c000000ARI", - mulli_3 = "1c000000RRI", - subfic_3 = "20000000RRI", - cmplwi_3 = "28000000XRU", - cmplwi_2 = "28000000-RU", - cmpldi_3 = "28200000XRU", - cmpldi_2 = "28200000-RU", - cmpwi_3 = "2c000000XRI", - cmpwi_2 = "2c000000-RI", - cmpdi_3 = "2c200000XRI", - cmpdi_2 = "2c200000-RI", - addic_3 = "30000000RRI", - ["addic._3"] = "34000000RRI", - addi_3 = "38000000RR0I", - li_2 = "38000000RI", - la_2 = "38000000RD", - addis_3 = "3c000000RR0I", - lis_2 = "3c000000RI", - lus_2 = "3c000000RU", - bc_3 = "40000000AAK", - bcl_3 = "40000001AAK", - bdnz_1 = "42000000K", - bdz_1 = "42400000K", - sc_0 = "44000000", - b_1 = "48000000J", - bl_1 = "48000001J", - rlwimi_5 = "50000000RR~AAA.", - rlwinm_5 = "54000000RR~AAA.", - rlwnm_5 = "5c000000RR~RAA.", - ori_3 = "60000000RR~U", - nop_0 = "60000000", - oris_3 = "64000000RR~U", - xori_3 = "68000000RR~U", - xoris_3 = "6c000000RR~U", - ["andi._3"] = "70000000RR~U", - ["andis._3"] = "74000000RR~U", - lwz_2 = "80000000RD", - lwzu_2 = "84000000RD", - lbz_2 = "88000000RD", - lbzu_2 = "8c000000RD", - stw_2 = "90000000RD", - stwu_2 = "94000000RD", - stb_2 = "98000000RD", - stbu_2 = "9c000000RD", - lhz_2 = "a0000000RD", - lhzu_2 = "a4000000RD", - lha_2 = "a8000000RD", - lhau_2 = "ac000000RD", - sth_2 = "b0000000RD", - sthu_2 = "b4000000RD", - lmw_2 = "b8000000RD", - stmw_2 = "bc000000RD", - lfs_2 = "c0000000FD", - lfsu_2 = "c4000000FD", - lfd_2 = "c8000000FD", - lfdu_2 = "cc000000FD", - stfs_2 = "d0000000FD", - stfsu_2 = "d4000000FD", - stfd_2 = "d8000000FD", - stfdu_2 = "dc000000FD", - ld_2 = "e8000000RD", -- NYI: displacement must be divisible by 4. - ldu_2 = "e8000001RD", - lwa_2 = "e8000002RD", - std_2 = "f8000000RD", - stdu_2 = "f8000001RD", - - subi_3 = op_alias("addi_3", function(p) p[3] = "-("..p[3]..")" end), - subis_3 = op_alias("addis_3", function(p) p[3] = "-("..p[3]..")" end), - subic_3 = op_alias("addic_3", function(p) p[3] = "-("..p[3]..")" end), - ["subic._3"] = op_alias("addic._3", function(p) p[3] = "-("..p[3]..")" end), - - rotlwi_3 = op_alias("rlwinm_5", function(p) - p[4] = "0"; p[5] = "31" - end), - rotrwi_3 = op_alias("rlwinm_5", function(p) - p[3] = "32-("..p[3]..")"; p[4] = "0"; p[5] = "31" - end), - rotlw_3 = op_alias("rlwnm_5", function(p) - p[4] = "0"; p[5] = "31" - end), - slwi_3 = op_alias("rlwinm_5", function(p) - p[5] = "31-("..p[3]..")"; p[4] = "0" - end), - srwi_3 = op_alias("rlwinm_5", function(p) - p[4] = p[3]; p[3] = "32-("..p[3]..")"; p[5] = "31" - end), - clrlwi_3 = op_alias("rlwinm_5", function(p) - p[4] = p[3]; p[3] = "0"; p[5] = "31" - end), - clrrwi_3 = op_alias("rlwinm_5", function(p) - p[5] = "31-("..p[3]..")"; p[3] = "0"; p[4] = "0" - end), - - -- Primary opcode 4: - mulhhwu_3 = "10000010RRR.", - machhwu_3 = "10000018RRR.", - mulhhw_3 = "10000050RRR.", - nmachhw_3 = "1000005cRRR.", - machhwsu_3 = "10000098RRR.", - machhws_3 = "100000d8RRR.", - nmachhws_3 = "100000dcRRR.", - mulchwu_3 = "10000110RRR.", - macchwu_3 = "10000118RRR.", - mulchw_3 = "10000150RRR.", - macchw_3 = "10000158RRR.", - nmacchw_3 = "1000015cRRR.", - macchwsu_3 = "10000198RRR.", - macchws_3 = "100001d8RRR.", - nmacchws_3 = "100001dcRRR.", - mullhw_3 = "10000350RRR.", - maclhw_3 = "10000358RRR.", - nmaclhw_3 = "1000035cRRR.", - maclhwsu_3 = "10000398RRR.", - maclhws_3 = "100003d8RRR.", - nmaclhws_3 = "100003dcRRR.", - machhwuo_3 = "10000418RRR.", - nmachhwo_3 = "1000045cRRR.", - machhwsuo_3 = "10000498RRR.", - machhwso_3 = "100004d8RRR.", - nmachhwso_3 = "100004dcRRR.", - macchwuo_3 = "10000518RRR.", - macchwo_3 = "10000558RRR.", - nmacchwo_3 = "1000055cRRR.", - macchwsuo_3 = "10000598RRR.", - macchwso_3 = "100005d8RRR.", - nmacchwso_3 = "100005dcRRR.", - maclhwo_3 = "10000758RRR.", - nmaclhwo_3 = "1000075cRRR.", - maclhwsuo_3 = "10000798RRR.", - maclhwso_3 = "100007d8RRR.", - nmaclhwso_3 = "100007dcRRR.", - - vaddubm_3 = "10000000VVV", - vmaxub_3 = "10000002VVV", - vrlb_3 = "10000004VVV", - vcmpequb_3 = "10000006VVV", - vmuloub_3 = "10000008VVV", - vaddfp_3 = "1000000aVVV", - vmrghb_3 = "1000000cVVV", - vpkuhum_3 = "1000000eVVV", - vmhaddshs_4 = "10000020VVVV", - vmhraddshs_4 = "10000021VVVV", - vmladduhm_4 = "10000022VVVV", - vmsumubm_4 = "10000024VVVV", - vmsummbm_4 = "10000025VVVV", - vmsumuhm_4 = "10000026VVVV", - vmsumuhs_4 = "10000027VVVV", - vmsumshm_4 = "10000028VVVV", - vmsumshs_4 = "10000029VVVV", - vsel_4 = "1000002aVVVV", - vperm_4 = "1000002bVVVV", - vsldoi_4 = "1000002cVVVP", - vpermxor_4 = "1000002dVVVV", - vmaddfp_4 = "1000002eVVVV~", - vnmsubfp_4 = "1000002fVVVV~", - vaddeuqm_4 = "1000003cVVVV", - vaddecuq_4 = "1000003dVVVV", - vsubeuqm_4 = "1000003eVVVV", - vsubecuq_4 = "1000003fVVVV", - vadduhm_3 = "10000040VVV", - vmaxuh_3 = "10000042VVV", - vrlh_3 = "10000044VVV", - vcmpequh_3 = "10000046VVV", - vmulouh_3 = "10000048VVV", - vsubfp_3 = "1000004aVVV", - vmrghh_3 = "1000004cVVV", - vpkuwum_3 = "1000004eVVV", - vadduwm_3 = "10000080VVV", - vmaxuw_3 = "10000082VVV", - vrlw_3 = "10000084VVV", - vcmpequw_3 = "10000086VVV", - vmulouw_3 = "10000088VVV", - vmuluwm_3 = "10000089VVV", - vmrghw_3 = "1000008cVVV", - vpkuhus_3 = "1000008eVVV", - vaddudm_3 = "100000c0VVV", - vmaxud_3 = "100000c2VVV", - vrld_3 = "100000c4VVV", - vcmpeqfp_3 = "100000c6VVV", - vcmpequd_3 = "100000c7VVV", - vpkuwus_3 = "100000ceVVV", - vadduqm_3 = "10000100VVV", - vmaxsb_3 = "10000102VVV", - vslb_3 = "10000104VVV", - vmulosb_3 = "10000108VVV", - vrefp_2 = "1000010aV-V", - vmrglb_3 = "1000010cVVV", - vpkshus_3 = "1000010eVVV", - vaddcuq_3 = "10000140VVV", - vmaxsh_3 = "10000142VVV", - vslh_3 = "10000144VVV", - vmulosh_3 = "10000148VVV", - vrsqrtefp_2 = "1000014aV-V", - vmrglh_3 = "1000014cVVV", - vpkswus_3 = "1000014eVVV", - vaddcuw_3 = "10000180VVV", - vmaxsw_3 = "10000182VVV", - vslw_3 = "10000184VVV", - vmulosw_3 = "10000188VVV", - vexptefp_2 = "1000018aV-V", - vmrglw_3 = "1000018cVVV", - vpkshss_3 = "1000018eVVV", - vmaxsd_3 = "100001c2VVV", - vsl_3 = "100001c4VVV", - vcmpgefp_3 = "100001c6VVV", - vlogefp_2 = "100001caV-V", - vpkswss_3 = "100001ceVVV", - vadduhs_3 = "10000240VVV", - vminuh_3 = "10000242VVV", - vsrh_3 = "10000244VVV", - vcmpgtuh_3 = "10000246VVV", - vmuleuh_3 = "10000248VVV", - vrfiz_2 = "1000024aV-V", - vsplth_3 = "1000024cVV3", - vupkhsh_2 = "1000024eV-V", - vminuw_3 = "10000282VVV", - vminud_3 = "100002c2VVV", - vcmpgtud_3 = "100002c7VVV", - vrfim_2 = "100002caV-V", - vcmpgtsb_3 = "10000306VVV", - vcfux_3 = "1000030aVVA~", - vaddshs_3 = "10000340VVV", - vminsh_3 = "10000342VVV", - vsrah_3 = "10000344VVV", - vcmpgtsh_3 = "10000346VVV", - vmulesh_3 = "10000348VVV", - vcfsx_3 = "1000034aVVA~", - vspltish_2 = "1000034cVS", - vupkhpx_2 = "1000034eV-V", - vaddsws_3 = "10000380VVV", - vminsw_3 = "10000382VVV", - vsraw_3 = "10000384VVV", - vcmpgtsw_3 = "10000386VVV", - vmulesw_3 = "10000388VVV", - vctuxs_3 = "1000038aVVA~", - vspltisw_2 = "1000038cVS", - vminsd_3 = "100003c2VVV", - vsrad_3 = "100003c4VVV", - vcmpbfp_3 = "100003c6VVV", - vcmpgtsd_3 = "100003c7VVV", - vctsxs_3 = "100003caVVA~", - vupklpx_2 = "100003ceV-V", - vsububm_3 = "10000400VVV", - ["bcdadd._4"] = "10000401VVVy.", - vavgub_3 = "10000402VVV", - vand_3 = "10000404VVV", - ["vcmpequb._3"] = "10000406VVV", - vmaxfp_3 = "1000040aVVV", - vsubuhm_3 = "10000440VVV", - ["bcdsub._4"] = "10000441VVVy.", - vavguh_3 = "10000442VVV", - vandc_3 = "10000444VVV", - ["vcmpequh._3"] = "10000446VVV", - vminfp_3 = "1000044aVVV", - vpkudum_3 = "1000044eVVV", - vsubuwm_3 = "10000480VVV", - vavguw_3 = "10000482VVV", - vor_3 = "10000484VVV", - ["vcmpequw._3"] = "10000486VVV", - vpmsumw_3 = "10000488VVV", - ["vcmpeqfp._3"] = "100004c6VVV", - ["vcmpequd._3"] = "100004c7VVV", - vpkudus_3 = "100004ceVVV", - vavgsb_3 = "10000502VVV", - vavgsh_3 = "10000542VVV", - vorc_3 = "10000544VVV", - vbpermq_3 = "1000054cVVV", - vpksdus_3 = "1000054eVVV", - vavgsw_3 = "10000582VVV", - vsld_3 = "100005c4VVV", - ["vcmpgefp._3"] = "100005c6VVV", - vpksdss_3 = "100005ceVVV", - vsububs_3 = "10000600VVV", - mfvscr_1 = "10000604V--", - vsum4ubs_3 = "10000608VVV", - vsubuhs_3 = "10000640VVV", - mtvscr_1 = "10000644--V", - ["vcmpgtuh._3"] = "10000646VVV", - vsum4shs_3 = "10000648VVV", - vupkhsw_2 = "1000064eV-V", - vsubuws_3 = "10000680VVV", - vshasigmaw_4 = "10000682VVYp", - veqv_3 = "10000684VVV", - vsum2sws_3 = "10000688VVV", - vmrgow_3 = "1000068cVVV", - vshasigmad_4 = "100006c2VVYp", - vsrd_3 = "100006c4VVV", - ["vcmpgtud._3"] = "100006c7VVV", - vupklsw_2 = "100006ceV-V", - vupkslw_2 = "100006ceV-V", - vsubsbs_3 = "10000700VVV", - vclzb_2 = "10000702V-V", - vpopcntb_2 = "10000703V-V", - ["vcmpgtsb._3"] = "10000706VVV", - vsum4sbs_3 = "10000708VVV", - vsubshs_3 = "10000740VVV", - vclzh_2 = "10000742V-V", - vpopcnth_2 = "10000743V-V", - ["vcmpgtsh._3"] = "10000746VVV", - vsubsws_3 = "10000780VVV", - vclzw_2 = "10000782V-V", - vpopcntw_2 = "10000783V-V", - ["vcmpgtsw._3"] = "10000786VVV", - vsumsws_3 = "10000788VVV", - vmrgew_3 = "1000078cVVV", - vclzd_2 = "100007c2V-V", - vpopcntd_2 = "100007c3V-V", - ["vcmpbfp._3"] = "100007c6VVV", - ["vcmpgtsd._3"] = "100007c7VVV", - - -- Primary opcode 19: - mcrf_2 = "4c000000XX", - isync_0 = "4c00012c", - crnor_3 = "4c000042CCC", - crnot_2 = "4c000042CC=", - crandc_3 = "4c000102CCC", - crxor_3 = "4c000182CCC", - crclr_1 = "4c000182C==", - crnand_3 = "4c0001c2CCC", - crand_3 = "4c000202CCC", - creqv_3 = "4c000242CCC", - crset_1 = "4c000242C==", - crorc_3 = "4c000342CCC", - cror_3 = "4c000382CCC", - crmove_2 = "4c000382CC=", - bclr_2 = "4c000020AA", - bclrl_2 = "4c000021AA", - bcctr_2 = "4c000420AA", - bcctrl_2 = "4c000421AA", - bctar_2 = "4c000460AA", - bctarl_2 = "4c000461AA", - blr_0 = "4e800020", - blrl_0 = "4e800021", - bctr_0 = "4e800420", - bctrl_0 = "4e800421", - - -- Primary opcode 31: - cmpw_3 = "7c000000XRR", - cmpw_2 = "7c000000-RR", - cmpd_3 = "7c200000XRR", - cmpd_2 = "7c200000-RR", - tw_3 = "7c000008ARR", - lvsl_3 = "7c00000cVRR", - subfc_3 = "7c000010RRR.", - subc_3 = "7c000010RRR~.", - mulhdu_3 = "7c000012RRR.", - addc_3 = "7c000014RRR.", - mulhwu_3 = "7c000016RRR.", - isel_4 = "7c00001eRRRC", - isellt_3 = "7c00001eRRR", - iselgt_3 = "7c00005eRRR", - iseleq_3 = "7c00009eRRR", - mfcr_1 = "7c000026R", - mfocrf_2 = "7c100026RG", - mtcrf_2 = "7c000120GR", - mtocrf_2 = "7c100120GR", - lwarx_3 = "7c000028RR0R", - ldx_3 = "7c00002aRR0R", - lwzx_3 = "7c00002eRR0R", - slw_3 = "7c000030RR~R.", - cntlzw_2 = "7c000034RR~", - sld_3 = "7c000036RR~R.", - and_3 = "7c000038RR~R.", - cmplw_3 = "7c000040XRR", - cmplw_2 = "7c000040-RR", - cmpld_3 = "7c200040XRR", - cmpld_2 = "7c200040-RR", - lvsr_3 = "7c00004cVRR", - subf_3 = "7c000050RRR.", - sub_3 = "7c000050RRR~.", - lbarx_3 = "7c000068RR0R", - ldux_3 = "7c00006aRR0R", - dcbst_2 = "7c00006c-RR", - lwzux_3 = "7c00006eRR0R", - cntlzd_2 = "7c000074RR~", - andc_3 = "7c000078RR~R.", - td_3 = "7c000088ARR", - lvewx_3 = "7c00008eVRR", - mulhd_3 = "7c000092RRR.", - addg6s_3 = "7c000094RRR", - mulhw_3 = "7c000096RRR.", - dlmzb_3 = "7c00009cRR~R.", - ldarx_3 = "7c0000a8RR0R", - dcbf_2 = "7c0000ac-RR", - lbzx_3 = "7c0000aeRR0R", - lvx_3 = "7c0000ceVRR", - neg_2 = "7c0000d0RR.", - lharx_3 = "7c0000e8RR0R", - lbzux_3 = "7c0000eeRR0R", - popcntb_2 = "7c0000f4RR~", - not_2 = "7c0000f8RR~%.", - nor_3 = "7c0000f8RR~R.", - stvebx_3 = "7c00010eVRR", - subfe_3 = "7c000110RRR.", - sube_3 = "7c000110RRR~.", - adde_3 = "7c000114RRR.", - stdx_3 = "7c00012aRR0R", - ["stwcx._3"] = "7c00012dRR0R.", - stwx_3 = "7c00012eRR0R", - prtyw_2 = "7c000134RR~", - stvehx_3 = "7c00014eVRR", - stdux_3 = "7c00016aRR0R", - ["stqcx._3"] = "7c00016dR:R0R.", - stwux_3 = "7c00016eRR0R", - prtyd_2 = "7c000174RR~", - stvewx_3 = "7c00018eVRR", - subfze_2 = "7c000190RR.", - addze_2 = "7c000194RR.", - ["stdcx._3"] = "7c0001adRR0R.", - stbx_3 = "7c0001aeRR0R", - stvx_3 = "7c0001ceVRR", - subfme_2 = "7c0001d0RR.", - mulld_3 = "7c0001d2RRR.", - addme_2 = "7c0001d4RR.", - mullw_3 = "7c0001d6RRR.", - dcbtst_2 = "7c0001ec-RR", - stbux_3 = "7c0001eeRR0R", - bpermd_3 = "7c0001f8RR~R", - lvepxl_3 = "7c00020eVRR", - add_3 = "7c000214RRR.", - lqarx_3 = "7c000228R:R0R", - dcbt_2 = "7c00022c-RR", - lhzx_3 = "7c00022eRR0R", - cdtbcd_2 = "7c000234RR~", - eqv_3 = "7c000238RR~R.", - lvepx_3 = "7c00024eVRR", - eciwx_3 = "7c00026cRR0R", - lhzux_3 = "7c00026eRR0R", - cbcdtd_2 = "7c000274RR~", - xor_3 = "7c000278RR~R.", - mfspefscr_1 = "7c0082a6R", - mfxer_1 = "7c0102a6R", - mflr_1 = "7c0802a6R", - mfctr_1 = "7c0902a6R", - lwax_3 = "7c0002aaRR0R", - lhax_3 = "7c0002aeRR0R", - mftb_1 = "7c0c42e6R", - mftbu_1 = "7c0d42e6R", - lvxl_3 = "7c0002ceVRR", - lwaux_3 = "7c0002eaRR0R", - lhaux_3 = "7c0002eeRR0R", - popcntw_2 = "7c0002f4RR~", - divdeu_3 = "7c000312RRR.", - divweu_3 = "7c000316RRR.", - sthx_3 = "7c00032eRR0R", - orc_3 = "7c000338RR~R.", - ecowx_3 = "7c00036cRR0R", - sthux_3 = "7c00036eRR0R", - or_3 = "7c000378RR~R.", - mr_2 = "7c000378RR~%.", - divdu_3 = "7c000392RRR.", - divwu_3 = "7c000396RRR.", - mtspefscr_1 = "7c0083a6R", - mtxer_1 = "7c0103a6R", - mtlr_1 = "7c0803a6R", - mtctr_1 = "7c0903a6R", - dcbi_2 = "7c0003ac-RR", - nand_3 = "7c0003b8RR~R.", - dsn_2 = "7c0003c6-RR", - stvxl_3 = "7c0003ceVRR", - divd_3 = "7c0003d2RRR.", - divw_3 = "7c0003d6RRR.", - popcntd_2 = "7c0003f4RR~", - cmpb_3 = "7c0003f8RR~R.", - mcrxr_1 = "7c000400X", - lbdx_3 = "7c000406RRR", - subfco_3 = "7c000410RRR.", - subco_3 = "7c000410RRR~.", - addco_3 = "7c000414RRR.", - ldbrx_3 = "7c000428RR0R", - lswx_3 = "7c00042aRR0R", - lwbrx_3 = "7c00042cRR0R", - lfsx_3 = "7c00042eFR0R", - srw_3 = "7c000430RR~R.", - srd_3 = "7c000436RR~R.", - lhdx_3 = "7c000446RRR", - subfo_3 = "7c000450RRR.", - subo_3 = "7c000450RRR~.", - lfsux_3 = "7c00046eFR0R", - lwdx_3 = "7c000486RRR", - lswi_3 = "7c0004aaRR0A", - sync_0 = "7c0004ac", - lwsync_0 = "7c2004ac", - ptesync_0 = "7c4004ac", - lfdx_3 = "7c0004aeFR0R", - lddx_3 = "7c0004c6RRR", - nego_2 = "7c0004d0RR.", - lfdux_3 = "7c0004eeFR0R", - stbdx_3 = "7c000506RRR", - subfeo_3 = "7c000510RRR.", - subeo_3 = "7c000510RRR~.", - addeo_3 = "7c000514RRR.", - stdbrx_3 = "7c000528RR0R", - stswx_3 = "7c00052aRR0R", - stwbrx_3 = "7c00052cRR0R", - stfsx_3 = "7c00052eFR0R", - sthdx_3 = "7c000546RRR", - ["stbcx._3"] = "7c00056dRRR", - stfsux_3 = "7c00056eFR0R", - stwdx_3 = "7c000586RRR", - subfzeo_2 = "7c000590RR.", - addzeo_2 = "7c000594RR.", - stswi_3 = "7c0005aaRR0A", - ["sthcx._3"] = "7c0005adRRR", - stfdx_3 = "7c0005aeFR0R", - stddx_3 = "7c0005c6RRR", - subfmeo_2 = "7c0005d0RR.", - mulldo_3 = "7c0005d2RRR.", - addmeo_2 = "7c0005d4RR.", - mullwo_3 = "7c0005d6RRR.", - dcba_2 = "7c0005ec-RR", - stfdux_3 = "7c0005eeFR0R", - stvepxl_3 = "7c00060eVRR", - addo_3 = "7c000614RRR.", - lhbrx_3 = "7c00062cRR0R", - lfdpx_3 = "7c00062eF:RR", - sraw_3 = "7c000630RR~R.", - srad_3 = "7c000634RR~R.", - lfddx_3 = "7c000646FRR", - stvepx_3 = "7c00064eVRR", - srawi_3 = "7c000670RR~A.", - sradi_3 = "7c000674RR~H.", - eieio_0 = "7c0006ac", - lfiwax_3 = "7c0006aeFR0R", - divdeuo_3 = "7c000712RRR.", - divweuo_3 = "7c000716RRR.", - sthbrx_3 = "7c00072cRR0R", - stfdpx_3 = "7c00072eF:RR", - extsh_2 = "7c000734RR~.", - stfddx_3 = "7c000746FRR", - divdeo_3 = "7c000752RRR.", - divweo_3 = "7c000756RRR.", - extsb_2 = "7c000774RR~.", - divduo_3 = "7c000792RRR.", - divwou_3 = "7c000796RRR.", - icbi_2 = "7c0007ac-RR", - stfiwx_3 = "7c0007aeFR0R", - extsw_2 = "7c0007b4RR~.", - divdo_3 = "7c0007d2RRR.", - divwo_3 = "7c0007d6RRR.", - dcbz_2 = "7c0007ec-RR", - - ["tbegin._1"] = "7c00051d1", - ["tbegin._0"] = "7c00051d", - ["tend._1"] = "7c00055dY", - ["tend._0"] = "7c00055d", - ["tendall._0"] = "7e00055d", - tcheck_1 = "7c00059cX", - ["tsr._1"] = "7c0005dd1", - ["tsuspend._0"] = "7c0005dd", - ["tresume._0"] = "7c2005dd", - ["tabortwc._3"] = "7c00061dARR", - ["tabortdc._3"] = "7c00065dARR", - ["tabortwci._3"] = "7c00069dARS", - ["tabortdci._3"] = "7c0006ddARS", - ["tabort._1"] = "7c00071d-R-", - ["treclaim._1"] = "7c00075d-R", - ["trechkpt._0"] = "7c0007dd", - - lxsiwzx_3 = "7c000018QRR", - lxsiwax_3 = "7c000098QRR", - mfvsrd_2 = "7c000066-Rq", - mfvsrwz_2 = "7c0000e6-Rq", - stxsiwx_3 = "7c000118QRR", - mtvsrd_2 = "7c000166QR", - mtvsrwa_2 = "7c0001a6QR", - lxvdsx_3 = "7c000298QRR", - lxsspx_3 = "7c000418QRR", - lxsdx_3 = "7c000498QRR", - stxsspx_3 = "7c000518QRR", - stxsdx_3 = "7c000598QRR", - lxvw4x_3 = "7c000618QRR", - lxvd2x_3 = "7c000698QRR", - stxvw4x_3 = "7c000718QRR", - stxvd2x_3 = "7c000798QRR", - - -- Primary opcode 30: - rldicl_4 = "78000000RR~HM.", - rldicr_4 = "78000004RR~HM.", - rldic_4 = "78000008RR~HM.", - rldimi_4 = "7800000cRR~HM.", - rldcl_4 = "78000010RR~RM.", - rldcr_4 = "78000012RR~RM.", - - rotldi_3 = op_alias("rldicl_4", function(p) - p[4] = "0" - end), - rotrdi_3 = op_alias("rldicl_4", function(p) - p[3] = "64-("..p[3]..")"; p[4] = "0" - end), - rotld_3 = op_alias("rldcl_4", function(p) - p[4] = "0" - end), - sldi_3 = op_alias("rldicr_4", function(p) - p[4] = "63-("..p[3]..")" - end), - srdi_3 = op_alias("rldicl_4", function(p) - p[4] = p[3]; p[3] = "64-("..p[3]..")" - end), - clrldi_3 = op_alias("rldicl_4", function(p) - p[4] = p[3]; p[3] = "0" - end), - clrrdi_3 = op_alias("rldicr_4", function(p) - p[4] = "63-("..p[3]..")"; p[3] = "0" - end), - - -- Primary opcode 56: - lq_2 = "e0000000R:D", -- NYI: displacement must be divisible by 8. - - -- Primary opcode 57: - lfdp_2 = "e4000000F:D", -- NYI: displacement must be divisible by 4. - - -- Primary opcode 59: - fdivs_3 = "ec000024FFF.", - fsubs_3 = "ec000028FFF.", - fadds_3 = "ec00002aFFF.", - fsqrts_2 = "ec00002cF-F.", - fres_2 = "ec000030F-F.", - fmuls_3 = "ec000032FF-F.", - frsqrtes_2 = "ec000034F-F.", - fmsubs_4 = "ec000038FFFF~.", - fmadds_4 = "ec00003aFFFF~.", - fnmsubs_4 = "ec00003cFFFF~.", - fnmadds_4 = "ec00003eFFFF~.", - fcfids_2 = "ec00069cF-F.", - fcfidus_2 = "ec00079cF-F.", - - dadd_3 = "ec000004FFF.", - dqua_4 = "ec000006FFFZ.", - dmul_3 = "ec000044FFF.", - drrnd_4 = "ec000046FFFZ.", - dscli_3 = "ec000084FF6.", - dquai_4 = "ec000086SF~FZ.", - dscri_3 = "ec0000c4FF6.", - drintx_4 = "ec0000c61F~FZ.", - dcmpo_3 = "ec000104XFF", - dtstex_3 = "ec000144XFF", - dtstdc_3 = "ec000184XF6", - dtstdg_3 = "ec0001c4XF6", - drintn_4 = "ec0001c61F~FZ.", - dctdp_2 = "ec000204F-F.", - dctfix_2 = "ec000244F-F.", - ddedpd_3 = "ec000284ZF~F.", - dxex_2 = "ec0002c4F-F.", - dsub_3 = "ec000404FFF.", - ddiv_3 = "ec000444FFF.", - dcmpu_3 = "ec000504XFF", - dtstsf_3 = "ec000544XFF", - drsp_2 = "ec000604F-F.", - dcffix_2 = "ec000644F-F.", - denbcd_3 = "ec000684YF~F.", - diex_3 = "ec0006c4FFF.", - - -- Primary opcode 60: - xsaddsp_3 = "f0000000QQQ", - xsmaddasp_3 = "f0000008QQQ", - xxsldwi_4 = "f0000010QQQz", - xsrsqrtesp_2 = "f0000028Q-Q", - xssqrtsp_2 = "f000002cQ-Q", - xxsel_4 = "f0000030QQQQ", - xssubsp_3 = "f0000040QQQ", - xsmaddmsp_3 = "f0000048QQQ", - xxpermdi_4 = "f0000050QQQz", - xsresp_2 = "f0000068Q-Q", - xsmulsp_3 = "f0000080QQQ", - xsmsubasp_3 = "f0000088QQQ", - xxmrghw_3 = "f0000090QQQ", - xsdivsp_3 = "f00000c0QQQ", - xsmsubmsp_3 = "f00000c8QQQ", - xsadddp_3 = "f0000100QQQ", - xsmaddadp_3 = "f0000108QQQ", - xscmpudp_3 = "f0000118XQQ", - xscvdpuxws_2 = "f0000120Q-Q", - xsrdpi_2 = "f0000124Q-Q", - xsrsqrtedp_2 = "f0000128Q-Q", - xssqrtdp_2 = "f000012cQ-Q", - xssubdp_3 = "f0000140QQQ", - xsmaddmdp_3 = "f0000148QQQ", - xscmpodp_3 = "f0000158XQQ", - xscvdpsxws_2 = "f0000160Q-Q", - xsrdpiz_2 = "f0000164Q-Q", - xsredp_2 = "f0000168Q-Q", - xsmuldp_3 = "f0000180QQQ", - xsmsubadp_3 = "f0000188QQQ", - xxmrglw_3 = "f0000190QQQ", - xsrdpip_2 = "f00001a4Q-Q", - xstsqrtdp_2 = "f00001a8X-Q", - xsrdpic_2 = "f00001acQ-Q", - xsdivdp_3 = "f00001c0QQQ", - xsmsubmdp_3 = "f00001c8QQQ", - xsrdpim_2 = "f00001e4Q-Q", - xstdivdp_3 = "f00001e8XQQ", - xvaddsp_3 = "f0000200QQQ", - xvmaddasp_3 = "f0000208QQQ", - xvcmpeqsp_3 = "f0000218QQQ", - xvcvspuxws_2 = "f0000220Q-Q", - xvrspi_2 = "f0000224Q-Q", - xvrsqrtesp_2 = "f0000228Q-Q", - xvsqrtsp_2 = "f000022cQ-Q", - xvsubsp_3 = "f0000240QQQ", - xvmaddmsp_3 = "f0000248QQQ", - xvcmpgtsp_3 = "f0000258QQQ", - xvcvspsxws_2 = "f0000260Q-Q", - xvrspiz_2 = "f0000264Q-Q", - xvresp_2 = "f0000268Q-Q", - xvmulsp_3 = "f0000280QQQ", - xvmsubasp_3 = "f0000288QQQ", - xxspltw_3 = "f0000290QQg~", - xvcmpgesp_3 = "f0000298QQQ", - xvcvuxwsp_2 = "f00002a0Q-Q", - xvrspip_2 = "f00002a4Q-Q", - xvtsqrtsp_2 = "f00002a8X-Q", - xvrspic_2 = "f00002acQ-Q", - xvdivsp_3 = "f00002c0QQQ", - xvmsubmsp_3 = "f00002c8QQQ", - xvcvsxwsp_2 = "f00002e0Q-Q", - xvrspim_2 = "f00002e4Q-Q", - xvtdivsp_3 = "f00002e8XQQ", - xvadddp_3 = "f0000300QQQ", - xvmaddadp_3 = "f0000308QQQ", - xvcmpeqdp_3 = "f0000318QQQ", - xvcvdpuxws_2 = "f0000320Q-Q", - xvrdpi_2 = "f0000324Q-Q", - xvrsqrtedp_2 = "f0000328Q-Q", - xvsqrtdp_2 = "f000032cQ-Q", - xvsubdp_3 = "f0000340QQQ", - xvmaddmdp_3 = "f0000348QQQ", - xvcmpgtdp_3 = "f0000358QQQ", - xvcvdpsxws_2 = "f0000360Q-Q", - xvrdpiz_2 = "f0000364Q-Q", - xvredp_2 = "f0000368Q-Q", - xvmuldp_3 = "f0000380QQQ", - xvmsubadp_3 = "f0000388QQQ", - xvcmpgedp_3 = "f0000398QQQ", - xvcvuxwdp_2 = "f00003a0Q-Q", - xvrdpip_2 = "f00003a4Q-Q", - xvtsqrtdp_2 = "f00003a8X-Q", - xvrdpic_2 = "f00003acQ-Q", - xvdivdp_3 = "f00003c0QQQ", - xvmsubmdp_3 = "f00003c8QQQ", - xvcvsxwdp_2 = "f00003e0Q-Q", - xvrdpim_2 = "f00003e4Q-Q", - xvtdivdp_3 = "f00003e8XQQ", - xsnmaddasp_3 = "f0000408QQQ", - xxland_3 = "f0000410QQQ", - xscvdpsp_2 = "f0000424Q-Q", - xscvdpspn_2 = "f000042cQ-Q", - xsnmaddmsp_3 = "f0000448QQQ", - xxlandc_3 = "f0000450QQQ", - xsrsp_2 = "f0000464Q-Q", - xsnmsubasp_3 = "f0000488QQQ", - xxlor_3 = "f0000490QQQ", - xscvuxdsp_2 = "f00004a0Q-Q", - xsnmsubmsp_3 = "f00004c8QQQ", - xxlxor_3 = "f00004d0QQQ", - xscvsxdsp_2 = "f00004e0Q-Q", - xsmaxdp_3 = "f0000500QQQ", - xsnmaddadp_3 = "f0000508QQQ", - xxlnor_3 = "f0000510QQQ", - xscvdpuxds_2 = "f0000520Q-Q", - xscvspdp_2 = "f0000524Q-Q", - xscvspdpn_2 = "f000052cQ-Q", - xsmindp_3 = "f0000540QQQ", - xsnmaddmdp_3 = "f0000548QQQ", - xxlorc_3 = "f0000550QQQ", - xscvdpsxds_2 = "f0000560Q-Q", - xsabsdp_2 = "f0000564Q-Q", - xscpsgndp_3 = "f0000580QQQ", - xsnmsubadp_3 = "f0000588QQQ", - xxlnand_3 = "f0000590QQQ", - xscvuxddp_2 = "f00005a0Q-Q", - xsnabsdp_2 = "f00005a4Q-Q", - xsnmsubmdp_3 = "f00005c8QQQ", - xxleqv_3 = "f00005d0QQQ", - xscvsxddp_2 = "f00005e0Q-Q", - xsnegdp_2 = "f00005e4Q-Q", - xvmaxsp_3 = "f0000600QQQ", - xvnmaddasp_3 = "f0000608QQQ", - ["xvcmpeqsp._3"] = "f0000618QQQ", - xvcvspuxds_2 = "f0000620Q-Q", - xvcvdpsp_2 = "f0000624Q-Q", - xvminsp_3 = "f0000640QQQ", - xvnmaddmsp_3 = "f0000648QQQ", - ["xvcmpgtsp._3"] = "f0000658QQQ", - xvcvspsxds_2 = "f0000660Q-Q", - xvabssp_2 = "f0000664Q-Q", - xvcpsgnsp_3 = "f0000680QQQ", - xvnmsubasp_3 = "f0000688QQQ", - ["xvcmpgesp._3"] = "f0000698QQQ", - xvcvuxdsp_2 = "f00006a0Q-Q", - xvnabssp_2 = "f00006a4Q-Q", - xvnmsubmsp_3 = "f00006c8QQQ", - xvcvsxdsp_2 = "f00006e0Q-Q", - xvnegsp_2 = "f00006e4Q-Q", - xvmaxdp_3 = "f0000700QQQ", - xvnmaddadp_3 = "f0000708QQQ", - ["xvcmpeqdp._3"] = "f0000718QQQ", - xvcvdpuxds_2 = "f0000720Q-Q", - xvcvspdp_2 = "f0000724Q-Q", - xvmindp_3 = "f0000740QQQ", - xvnmaddmdp_3 = "f0000748QQQ", - ["xvcmpgtdp._3"] = "f0000758QQQ", - xvcvdpsxds_2 = "f0000760Q-Q", - xvabsdp_2 = "f0000764Q-Q", - xvcpsgndp_3 = "f0000780QQQ", - xvnmsubadp_3 = "f0000788QQQ", - ["xvcmpgedp._3"] = "f0000798QQQ", - xvcvuxddp_2 = "f00007a0Q-Q", - xvnabsdp_2 = "f00007a4Q-Q", - xvnmsubmdp_3 = "f00007c8QQQ", - xvcvsxddp_2 = "f00007e0Q-Q", - xvnegdp_2 = "f00007e4Q-Q", - - -- Primary opcode 61: - stfdp_2 = "f4000000F:D", -- NYI: displacement must be divisible by 4. - - -- Primary opcode 62: - stq_2 = "f8000002R:D", -- NYI: displacement must be divisible by 8. - - -- Primary opcode 63: - fdiv_3 = "fc000024FFF.", - fsub_3 = "fc000028FFF.", - fadd_3 = "fc00002aFFF.", - fsqrt_2 = "fc00002cF-F.", - fsel_4 = "fc00002eFFFF~.", - fre_2 = "fc000030F-F.", - fmul_3 = "fc000032FF-F.", - frsqrte_2 = "fc000034F-F.", - fmsub_4 = "fc000038FFFF~.", - fmadd_4 = "fc00003aFFFF~.", - fnmsub_4 = "fc00003cFFFF~.", - fnmadd_4 = "fc00003eFFFF~.", - fcmpu_3 = "fc000000XFF", - fcpsgn_3 = "fc000010FFF.", - fcmpo_3 = "fc000040XFF", - mtfsb1_1 = "fc00004cA", - fneg_2 = "fc000050F-F.", - mcrfs_2 = "fc000080XX", - mtfsb0_1 = "fc00008cA", - fmr_2 = "fc000090F-F.", - frsp_2 = "fc000018F-F.", - fctiw_2 = "fc00001cF-F.", - fctiwz_2 = "fc00001eF-F.", - ftdiv_2 = "fc000100X-F.", - fctiwu_2 = "fc00011cF-F.", - fctiwuz_2 = "fc00011eF-F.", - mtfsfi_2 = "fc00010cAA", -- NYI: upshift. - fnabs_2 = "fc000110F-F.", - ftsqrt_2 = "fc000140X-F.", - fabs_2 = "fc000210F-F.", - frin_2 = "fc000310F-F.", - friz_2 = "fc000350F-F.", - frip_2 = "fc000390F-F.", - frim_2 = "fc0003d0F-F.", - mffs_1 = "fc00048eF.", - -- NYI: mtfsf, mtfsb0, mtfsb1. - fctid_2 = "fc00065cF-F.", - fctidz_2 = "fc00065eF-F.", - fmrgow_3 = "fc00068cFFF", - fcfid_2 = "fc00069cF-F.", - fctidu_2 = "fc00075cF-F.", - fctiduz_2 = "fc00075eF-F.", - fmrgew_3 = "fc00078cFFF", - fcfidu_2 = "fc00079cF-F.", - - daddq_3 = "fc000004F:F:F:.", - dquaq_4 = "fc000006F:F:F:Z.", - dmulq_3 = "fc000044F:F:F:.", - drrndq_4 = "fc000046F:F:F:Z.", - dscliq_3 = "fc000084F:F:6.", - dquaiq_4 = "fc000086SF:~F:Z.", - dscriq_3 = "fc0000c4F:F:6.", - drintxq_4 = "fc0000c61F:~F:Z.", - dcmpoq_3 = "fc000104XF:F:", - dtstexq_3 = "fc000144XF:F:", - dtstdcq_3 = "fc000184XF:6", - dtstdgq_3 = "fc0001c4XF:6", - drintnq_4 = "fc0001c61F:~F:Z.", - dctqpq_2 = "fc000204F:-F:.", - dctfixq_2 = "fc000244F:-F:.", - ddedpdq_3 = "fc000284ZF:~F:.", - dxexq_2 = "fc0002c4F:-F:.", - dsubq_3 = "fc000404F:F:F:.", - ddivq_3 = "fc000444F:F:F:.", - dcmpuq_3 = "fc000504XF:F:", - dtstsfq_3 = "fc000544XF:F:", - drdpq_2 = "fc000604F:-F:.", - dcffixq_2 = "fc000644F:-F:.", - denbcdq_3 = "fc000684YF:~F:.", - diexq_3 = "fc0006c4F:FF:.", - - -- Primary opcode 4, SPE APU extension: - evaddw_3 = "10000200RRR", - evaddiw_3 = "10000202RAR~", - evsubw_3 = "10000204RRR~", - evsubiw_3 = "10000206RAR~", - evabs_2 = "10000208RR", - evneg_2 = "10000209RR", - evextsb_2 = "1000020aRR", - evextsh_2 = "1000020bRR", - evrndw_2 = "1000020cRR", - evcntlzw_2 = "1000020dRR", - evcntlsw_2 = "1000020eRR", - brinc_3 = "1000020fRRR", - evand_3 = "10000211RRR", - evandc_3 = "10000212RRR", - evxor_3 = "10000216RRR", - evor_3 = "10000217RRR", - evmr_2 = "10000217RR=", - evnor_3 = "10000218RRR", - evnot_2 = "10000218RR=", - eveqv_3 = "10000219RRR", - evorc_3 = "1000021bRRR", - evnand_3 = "1000021eRRR", - evsrwu_3 = "10000220RRR", - evsrws_3 = "10000221RRR", - evsrwiu_3 = "10000222RRA", - evsrwis_3 = "10000223RRA", - evslw_3 = "10000224RRR", - evslwi_3 = "10000226RRA", - evrlw_3 = "10000228RRR", - evsplati_2 = "10000229RS", - evrlwi_3 = "1000022aRRA", - evsplatfi_2 = "1000022bRS", - evmergehi_3 = "1000022cRRR", - evmergelo_3 = "1000022dRRR", - evcmpgtu_3 = "10000230XRR", - evcmpgtu_2 = "10000230-RR", - evcmpgts_3 = "10000231XRR", - evcmpgts_2 = "10000231-RR", - evcmpltu_3 = "10000232XRR", - evcmpltu_2 = "10000232-RR", - evcmplts_3 = "10000233XRR", - evcmplts_2 = "10000233-RR", - evcmpeq_3 = "10000234XRR", - evcmpeq_2 = "10000234-RR", - evsel_4 = "10000278RRRW", - evsel_3 = "10000278RRR", - evfsadd_3 = "10000280RRR", - evfssub_3 = "10000281RRR", - evfsabs_2 = "10000284RR", - evfsnabs_2 = "10000285RR", - evfsneg_2 = "10000286RR", - evfsmul_3 = "10000288RRR", - evfsdiv_3 = "10000289RRR", - evfscmpgt_3 = "1000028cXRR", - evfscmpgt_2 = "1000028c-RR", - evfscmplt_3 = "1000028dXRR", - evfscmplt_2 = "1000028d-RR", - evfscmpeq_3 = "1000028eXRR", - evfscmpeq_2 = "1000028e-RR", - evfscfui_2 = "10000290R-R", - evfscfsi_2 = "10000291R-R", - evfscfuf_2 = "10000292R-R", - evfscfsf_2 = "10000293R-R", - evfsctui_2 = "10000294R-R", - evfsctsi_2 = "10000295R-R", - evfsctuf_2 = "10000296R-R", - evfsctsf_2 = "10000297R-R", - evfsctuiz_2 = "10000298R-R", - evfsctsiz_2 = "1000029aR-R", - evfststgt_3 = "1000029cXRR", - evfststgt_2 = "1000029c-RR", - evfststlt_3 = "1000029dXRR", - evfststlt_2 = "1000029d-RR", - evfststeq_3 = "1000029eXRR", - evfststeq_2 = "1000029e-RR", - efsadd_3 = "100002c0RRR", - efssub_3 = "100002c1RRR", - efsabs_2 = "100002c4RR", - efsnabs_2 = "100002c5RR", - efsneg_2 = "100002c6RR", - efsmul_3 = "100002c8RRR", - efsdiv_3 = "100002c9RRR", - efscmpgt_3 = "100002ccXRR", - efscmpgt_2 = "100002cc-RR", - efscmplt_3 = "100002cdXRR", - efscmplt_2 = "100002cd-RR", - efscmpeq_3 = "100002ceXRR", - efscmpeq_2 = "100002ce-RR", - efscfd_2 = "100002cfR-R", - efscfui_2 = "100002d0R-R", - efscfsi_2 = "100002d1R-R", - efscfuf_2 = "100002d2R-R", - efscfsf_2 = "100002d3R-R", - efsctui_2 = "100002d4R-R", - efsctsi_2 = "100002d5R-R", - efsctuf_2 = "100002d6R-R", - efsctsf_2 = "100002d7R-R", - efsctuiz_2 = "100002d8R-R", - efsctsiz_2 = "100002daR-R", - efststgt_3 = "100002dcXRR", - efststgt_2 = "100002dc-RR", - efststlt_3 = "100002ddXRR", - efststlt_2 = "100002dd-RR", - efststeq_3 = "100002deXRR", - efststeq_2 = "100002de-RR", - efdadd_3 = "100002e0RRR", - efdsub_3 = "100002e1RRR", - efdcfuid_2 = "100002e2R-R", - efdcfsid_2 = "100002e3R-R", - efdabs_2 = "100002e4RR", - efdnabs_2 = "100002e5RR", - efdneg_2 = "100002e6RR", - efdmul_3 = "100002e8RRR", - efddiv_3 = "100002e9RRR", - efdctuidz_2 = "100002eaR-R", - efdctsidz_2 = "100002ebR-R", - efdcmpgt_3 = "100002ecXRR", - efdcmpgt_2 = "100002ec-RR", - efdcmplt_3 = "100002edXRR", - efdcmplt_2 = "100002ed-RR", - efdcmpeq_3 = "100002eeXRR", - efdcmpeq_2 = "100002ee-RR", - efdcfs_2 = "100002efR-R", - efdcfui_2 = "100002f0R-R", - efdcfsi_2 = "100002f1R-R", - efdcfuf_2 = "100002f2R-R", - efdcfsf_2 = "100002f3R-R", - efdctui_2 = "100002f4R-R", - efdctsi_2 = "100002f5R-R", - efdctuf_2 = "100002f6R-R", - efdctsf_2 = "100002f7R-R", - efdctuiz_2 = "100002f8R-R", - efdctsiz_2 = "100002faR-R", - efdtstgt_3 = "100002fcXRR", - efdtstgt_2 = "100002fc-RR", - efdtstlt_3 = "100002fdXRR", - efdtstlt_2 = "100002fd-RR", - efdtsteq_3 = "100002feXRR", - efdtsteq_2 = "100002fe-RR", - evlddx_3 = "10000300RR0R", - evldd_2 = "10000301R8", - evldwx_3 = "10000302RR0R", - evldw_2 = "10000303R8", - evldhx_3 = "10000304RR0R", - evldh_2 = "10000305R8", - evlwhex_3 = "10000310RR0R", - evlwhe_2 = "10000311R4", - evlwhoux_3 = "10000314RR0R", - evlwhou_2 = "10000315R4", - evlwhosx_3 = "10000316RR0R", - evlwhos_2 = "10000317R4", - evstddx_3 = "10000320RR0R", - evstdd_2 = "10000321R8", - evstdwx_3 = "10000322RR0R", - evstdw_2 = "10000323R8", - evstdhx_3 = "10000324RR0R", - evstdh_2 = "10000325R8", - evstwhex_3 = "10000330RR0R", - evstwhe_2 = "10000331R4", - evstwhox_3 = "10000334RR0R", - evstwho_2 = "10000335R4", - evstwwex_3 = "10000338RR0R", - evstwwe_2 = "10000339R4", - evstwwox_3 = "1000033cRR0R", - evstwwo_2 = "1000033dR4", - evmhessf_3 = "10000403RRR", - evmhossf_3 = "10000407RRR", - evmheumi_3 = "10000408RRR", - evmhesmi_3 = "10000409RRR", - evmhesmf_3 = "1000040bRRR", - evmhoumi_3 = "1000040cRRR", - evmhosmi_3 = "1000040dRRR", - evmhosmf_3 = "1000040fRRR", - evmhessfa_3 = "10000423RRR", - evmhossfa_3 = "10000427RRR", - evmheumia_3 = "10000428RRR", - evmhesmia_3 = "10000429RRR", - evmhesmfa_3 = "1000042bRRR", - evmhoumia_3 = "1000042cRRR", - evmhosmia_3 = "1000042dRRR", - evmhosmfa_3 = "1000042fRRR", - evmwhssf_3 = "10000447RRR", - evmwlumi_3 = "10000448RRR", - evmwhumi_3 = "1000044cRRR", - evmwhsmi_3 = "1000044dRRR", - evmwhsmf_3 = "1000044fRRR", - evmwssf_3 = "10000453RRR", - evmwumi_3 = "10000458RRR", - evmwsmi_3 = "10000459RRR", - evmwsmf_3 = "1000045bRRR", - evmwhssfa_3 = "10000467RRR", - evmwlumia_3 = "10000468RRR", - evmwhumia_3 = "1000046cRRR", - evmwhsmia_3 = "1000046dRRR", - evmwhsmfa_3 = "1000046fRRR", - evmwssfa_3 = "10000473RRR", - evmwumia_3 = "10000478RRR", - evmwsmia_3 = "10000479RRR", - evmwsmfa_3 = "1000047bRRR", - evmra_2 = "100004c4RR", - evdivws_3 = "100004c6RRR", - evdivwu_3 = "100004c7RRR", - evmwssfaa_3 = "10000553RRR", - evmwumiaa_3 = "10000558RRR", - evmwsmiaa_3 = "10000559RRR", - evmwsmfaa_3 = "1000055bRRR", - evmwssfan_3 = "100005d3RRR", - evmwumian_3 = "100005d8RRR", - evmwsmian_3 = "100005d9RRR", - evmwsmfan_3 = "100005dbRRR", - evmergehilo_3 = "1000022eRRR", - evmergelohi_3 = "1000022fRRR", - evlhhesplatx_3 = "10000308RR0R", - evlhhesplat_2 = "10000309R2", - evlhhousplatx_3 = "1000030cRR0R", - evlhhousplat_2 = "1000030dR2", - evlhhossplatx_3 = "1000030eRR0R", - evlhhossplat_2 = "1000030fR2", - evlwwsplatx_3 = "10000318RR0R", - evlwwsplat_2 = "10000319R4", - evlwhsplatx_3 = "1000031cRR0R", - evlwhsplat_2 = "1000031dR4", - evaddusiaaw_2 = "100004c0RR", - evaddssiaaw_2 = "100004c1RR", - evsubfusiaaw_2 = "100004c2RR", - evsubfssiaaw_2 = "100004c3RR", - evaddumiaaw_2 = "100004c8RR", - evaddsmiaaw_2 = "100004c9RR", - evsubfumiaaw_2 = "100004caRR", - evsubfsmiaaw_2 = "100004cbRR", - evmheusiaaw_3 = "10000500RRR", - evmhessiaaw_3 = "10000501RRR", - evmhessfaaw_3 = "10000503RRR", - evmhousiaaw_3 = "10000504RRR", - evmhossiaaw_3 = "10000505RRR", - evmhossfaaw_3 = "10000507RRR", - evmheumiaaw_3 = "10000508RRR", - evmhesmiaaw_3 = "10000509RRR", - evmhesmfaaw_3 = "1000050bRRR", - evmhoumiaaw_3 = "1000050cRRR", - evmhosmiaaw_3 = "1000050dRRR", - evmhosmfaaw_3 = "1000050fRRR", - evmhegumiaa_3 = "10000528RRR", - evmhegsmiaa_3 = "10000529RRR", - evmhegsmfaa_3 = "1000052bRRR", - evmhogumiaa_3 = "1000052cRRR", - evmhogsmiaa_3 = "1000052dRRR", - evmhogsmfaa_3 = "1000052fRRR", - evmwlusiaaw_3 = "10000540RRR", - evmwlssiaaw_3 = "10000541RRR", - evmwlumiaaw_3 = "10000548RRR", - evmwlsmiaaw_3 = "10000549RRR", - evmheusianw_3 = "10000580RRR", - evmhessianw_3 = "10000581RRR", - evmhessfanw_3 = "10000583RRR", - evmhousianw_3 = "10000584RRR", - evmhossianw_3 = "10000585RRR", - evmhossfanw_3 = "10000587RRR", - evmheumianw_3 = "10000588RRR", - evmhesmianw_3 = "10000589RRR", - evmhesmfanw_3 = "1000058bRRR", - evmhoumianw_3 = "1000058cRRR", - evmhosmianw_3 = "1000058dRRR", - evmhosmfanw_3 = "1000058fRRR", - evmhegumian_3 = "100005a8RRR", - evmhegsmian_3 = "100005a9RRR", - evmhegsmfan_3 = "100005abRRR", - evmhogumian_3 = "100005acRRR", - evmhogsmian_3 = "100005adRRR", - evmhogsmfan_3 = "100005afRRR", - evmwlusianw_3 = "100005c0RRR", - evmwlssianw_3 = "100005c1RRR", - evmwlumianw_3 = "100005c8RRR", - evmwlsmianw_3 = "100005c9RRR", - - -- NYI: Book E instructions. -} - --- Add mnemonics for "." variants. -do - local t = {} - for k,v in pairs(map_op) do - if type(v) == "string" and sub(v, -1) == "." then - local v2 = sub(v, 1, 7)..char(byte(v, 8)+1)..sub(v, 9, -2) - t[sub(k, 1, -3).."."..sub(k, -2)] = v2 - end - end - for k,v in pairs(t) do - map_op[k] = v - end -end - --- Add more branch mnemonics. -for cond,c in pairs(map_cond) do - local b1 = "b"..cond - local c1 = shl(band(c, 3), 16) + (c < 4 and 0x01000000 or 0) - -- bX[l] - map_op[b1.."_1"] = tohex(0x40800000 + c1).."K" - map_op[b1.."y_1"] = tohex(0x40a00000 + c1).."K" - map_op[b1.."l_1"] = tohex(0x40800001 + c1).."K" - map_op[b1.."_2"] = tohex(0x40800000 + c1).."-XK" - map_op[b1.."y_2"] = tohex(0x40a00000 + c1).."-XK" - map_op[b1.."l_2"] = tohex(0x40800001 + c1).."-XK" - -- bXlr[l] - map_op[b1.."lr_0"] = tohex(0x4c800020 + c1) - map_op[b1.."lrl_0"] = tohex(0x4c800021 + c1) - map_op[b1.."ctr_0"] = tohex(0x4c800420 + c1) - map_op[b1.."ctrl_0"] = tohex(0x4c800421 + c1) - -- bXctr[l] - map_op[b1.."lr_1"] = tohex(0x4c800020 + c1).."-X" - map_op[b1.."lrl_1"] = tohex(0x4c800021 + c1).."-X" - map_op[b1.."ctr_1"] = tohex(0x4c800420 + c1).."-X" - map_op[b1.."ctrl_1"] = tohex(0x4c800421 + c1).."-X" -end - ------------------------------------------------------------------------------- - -local function parse_gpr(expr) - local tname, ovreg = match(expr, "^([%w_]+):(r[1-3]?[0-9])$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - if not reg then - werror("type `"..(tname or expr).."' needs a register override") - end - expr = reg - end - local r = match(expr, "^r([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r, tp end - end - werror("bad register name `"..expr.."'") -end - -local function parse_fpr(expr) - local r = match(expr, "^f([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_vr(expr) - local r = match(expr, "^v([1-3]?[0-9])$") - if r then - r = tonumber(r) - if r <= 31 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_vs(expr) - local r = match(expr, "^vs([1-6]?[0-9])$") - if r then - r = tonumber(r) - if r <= 63 then return r end - end - werror("bad register name `"..expr.."'") -end - -local function parse_cr(expr) - local r = match(expr, "^cr([0-7])$") - if r then return tonumber(r) end - werror("bad condition register name `"..expr.."'") -end - -local function parse_cond(expr) - local r, cond = match(expr, "^4%*cr([0-7])%+(%w%w)$") - if r then - r = tonumber(r) - local c = map_cond[cond] - if c and c < 4 then return r*4+c end - end - werror("bad condition bit name `"..expr.."'") -end - -local parse_ctx = {} - -local loadenv = setfenv and function(s) - local code = loadstring(s, "") - if code then setfenv(code, parse_ctx) end - return code -end or function(s) - return load(s, "", nil, parse_ctx) -end - --- Try to parse simple arithmetic, too, since some basic ops are aliases. -local function parse_number(n) - local x = tonumber(n) - if x then return x end - local code = loadenv("return "..n) - if code then - local ok, y = pcall(code) - if ok then return y end - end - return nil -end - -local function parse_imm(imm, bits, shift, scale, signed) - local n = parse_number(imm) - if n then - local m = sar(n, scale) - if shl(m, scale) == n then - if signed then - local s = sar(m, bits-1) - if s == 0 then return shl(m, shift) - elseif s == -1 then return shl(m + shl(1, bits), shift) end - else - if sar(m, bits) == 0 then return shl(m, shift) end - end - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^[rfv]([1-3]?[0-9])$") or - match(imm, "^vs([1-6]?[0-9])$") or - match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction("IMM", (signed and 32768 or 0)+scale*1024+bits*32+shift, imm) - return 0 - end -end - -local function parse_shiftmask(imm, isshift) - local n = parse_number(imm) - if n then - if shr(n, 6) == 0 then - local lsb = band(n, 31) - local msb = n - lsb - return isshift and (shl(lsb, 11)+shr(msb, 4)) or (shl(lsb, 6)+msb) - end - werror("out of range immediate `"..imm.."'") - elseif match(imm, "^r([1-3]?[0-9])$") or - match(imm, "^([%w_]+):(r[1-3]?[0-9])$") then - werror("expected immediate operand, got register") - else - waction("IMMSH", isshift and 1 or 0, imm) - return 0; - end -end - -local function parse_disp(disp) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - return shl(r, 16) + parse_imm(imm, 16, 0, 0, true) - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - if tp then - waction("IMM", 32768+16*32, format(tp.ctypefmt, tailr)) - return shl(r, 16) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_u5disp(disp, scale) - local imm, reg = match(disp, "^(.*)%(([%w_:]+)%)$") - if imm then - local r = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - return shl(r, 16) + parse_imm(imm, 5, 11, scale, false) - end - local reg, tailr = match(disp, "^([%w_:]+)%s*(.*)$") - if reg and tailr ~= "" then - local r, tp = parse_gpr(reg) - if r == 0 then werror("cannot use r0 in displacement") end - if tp then - waction("IMM", scale*1024+5*32+11, format(tp.ctypefmt, tailr)) - return shl(r, 16) - end - end - werror("bad displacement `"..disp.."'") -end - -local function parse_label(label, def) - local prefix = sub(label, 1, 2) - -- =>label (pc label reference) - if prefix == "=>" then - return "PC", 0, sub(label, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "LG", map_global[sub(label, 3)] - end - if def then - -- [1-9] (local label definition) - if match(label, "^[1-9]$") then - return "LG", 10+tonumber(label) - end - else - -- [<>][1-9] (local label reference) - local dir, lnum = match(label, "^([<>])([1-9])$") - if dir then -- Fwd: 1-9, Bkwd: 11-19. - return "LG", lnum + (dir == ">" and 0 or 10) - end - -- extern label (extern label reference) - local extname = match(label, "^extern%s+(%S+)$") - if extname then - return "EXT", map_extern[extname] - end - end - werror("bad label `"..label.."'") -end - ------------------------------------------------------------------------------- - --- Handle opcodes defined with template strings. -op_template = function(params, template, nparams) - if not params then return sub(template, 9) end - local op = tonumber(sub(template, 1, 8), 16) - local n, rs = 1, 26 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 3 positions (rlwinm). - if secpos+3 > maxsecpos then wflush() end - local pos = wpos() - - -- Process each character. - for p in gmatch(sub(template, 9), ".") do - if p == "R" then - rs = rs - 5; op = op + shl(parse_gpr(params[n]), rs); n = n + 1 - elseif p == "F" then - rs = rs - 5; op = op + shl(parse_fpr(params[n]), rs); n = n + 1 - elseif p == "V" then - rs = rs - 5; op = op + shl(parse_vr(params[n]), rs); n = n + 1 - elseif p == "Q" then - local vs = parse_vs(params[n]); n = n + 1; rs = rs - 5 - local sh = rs == 6 and 2 or 3 + band(shr(rs, 1), 3) - op = op + shl(band(vs, 31), rs) + shr(band(vs, 32), sh) - elseif p == "q" then - local vs = parse_vs(params[n]); n = n + 1 - op = op + shl(band(vs, 31), 21) + shr(band(vs, 32), 5) - elseif p == "A" then - rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, false); n = n + 1 - elseif p == "S" then - rs = rs - 5; op = op + parse_imm(params[n], 5, rs, 0, true); n = n + 1 - elseif p == "I" then - op = op + parse_imm(params[n], 16, 0, 0, true); n = n + 1 - elseif p == "U" then - op = op + parse_imm(params[n], 16, 0, 0, false); n = n + 1 - elseif p == "D" then - op = op + parse_disp(params[n]); n = n + 1 - elseif p == "2" then - op = op + parse_u5disp(params[n], 1); n = n + 1 - elseif p == "4" then - op = op + parse_u5disp(params[n], 2); n = n + 1 - elseif p == "8" then - op = op + parse_u5disp(params[n], 3); n = n + 1 - elseif p == "C" then - rs = rs - 5; op = op + shl(parse_cond(params[n]), rs); n = n + 1 - elseif p == "X" then - rs = rs - 5; op = op + shl(parse_cr(params[n]), rs+2); n = n + 1 - elseif p == "1" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs, 0, false); n = n + 1 - elseif p == "g" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs, 0, false); n = n + 1 - elseif p == "3" then - rs = rs - 5; op = op + parse_imm(params[n], 3, rs, 0, false); n = n + 1 - elseif p == "P" then - rs = rs - 5; op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 - elseif p == "p" then - op = op + parse_imm(params[n], 4, rs, 0, false); n = n + 1 - elseif p == "6" then - rs = rs - 6; op = op + parse_imm(params[n], 6, rs, 0, false); n = n + 1 - elseif p == "Y" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs+4, 0, false); n = n + 1 - elseif p == "y" then - rs = rs - 5; op = op + parse_imm(params[n], 1, rs+3, 0, false); n = n + 1 - elseif p == "Z" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs+3, 0, false); n = n + 1 - elseif p == "z" then - rs = rs - 5; op = op + parse_imm(params[n], 2, rs+2, 0, false); n = n + 1 - elseif p == "W" then - op = op + parse_cr(params[n]); n = n + 1 - elseif p == "G" then - op = op + parse_imm(params[n], 8, 12, 0, false); n = n + 1 - elseif p == "H" then - op = op + parse_shiftmask(params[n], true); n = n + 1 - elseif p == "M" then - op = op + parse_shiftmask(params[n], false); n = n + 1 - elseif p == "J" or p == "K" then - local mode, m, s = parse_label(params[n], false) - if p == "K" then m = m + 2048 end - waction("REL_"..mode, m, s, 1) - n = n + 1 - elseif p == "0" then - if band(shr(op, rs), 31) == 0 then werror("cannot use r0") end - elseif p == "=" or p == "%" then - local t = band(shr(op, p == "%" and rs+5 or rs), 31) - rs = rs - 5 - op = op + shl(t, rs) - elseif p == "~" then - local mm = shl(31, rs) - local lo = band(op, mm) - local hi = band(op, shl(mm, 5)) - op = op - lo - hi + shl(lo, 5) + shr(hi, 5) - elseif p == ":" then - if band(shr(op, rs), 1) ~= 0 then werror("register pair expected") end - elseif p == "-" then - rs = rs - 5 - elseif p == "." then - -- Ignored. - else - assert(false) - end - end - wputpos(pos, op) -end - -map_op[".template__"] = op_template - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_1"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr" end - if secpos+1 > maxsecpos then wflush() end - local mode, n, s = parse_label(params[1], true) - if mode == "EXT" then werror("bad label definition") end - waction("LABEL_"..mode, n, s, 1) -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -map_op[".long_*"] = function(params) - if not params then return "imm..." end - for _,p in ipairs(params) do - local n = tonumber(p) - if not n then werror("bad immediate `"..p.."'") end - if n < 0 then n = n + 2^32 end - wputw(n) - if secpos+2 > maxsecpos then wflush() end - end -end - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", align-1, nil, 1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION", num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/dasm_proto.h b/ext/opcache/jit/dynasm/dasm_proto.h deleted file mode 100644 index 8914596adf5f4..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_proto.h +++ /dev/null @@ -1,83 +0,0 @@ -/* -** DynASM encoding engine prototypes. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#ifndef _DASM_PROTO_H -#define _DASM_PROTO_H - -#include -#include - -#define DASM_IDENT "DynASM 1.5.0" -#define DASM_VERSION 10500 /* 1.5.0 */ - -#ifndef Dst_DECL -#define Dst_DECL dasm_State **Dst -#endif - -#ifndef Dst_REF -#define Dst_REF (*Dst) -#endif - -#ifndef DASM_FDEF -#define DASM_FDEF extern -#endif - -#ifndef DASM_M_GROW -#define DASM_M_GROW(ctx, t, p, sz, need) \ - do { \ - size_t _sz = (sz), _need = (need); \ - if (_sz < _need) { \ - if (_sz < 16) _sz = 16; \ - while (_sz < _need) _sz += _sz; \ - (p) = (t *)realloc((p), _sz); \ - if ((p) == NULL) exit(1); \ - (sz) = _sz; \ - } \ - } while(0) -#endif - -#ifndef DASM_M_FREE -#define DASM_M_FREE(ctx, p, sz) free(p) -#endif - -/* Internal DynASM encoder state. */ -typedef struct dasm_State dasm_State; - - -/* Initialize and free DynASM state. */ -DASM_FDEF void dasm_init(Dst_DECL, int maxsection); -DASM_FDEF void dasm_free(Dst_DECL); - -/* Setup global array. Must be called before dasm_setup(). */ -DASM_FDEF void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl); - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -DASM_FDEF void dasm_growpc(Dst_DECL, unsigned int maxpc); - -/* Setup encoder. */ -DASM_FDEF void dasm_setup(Dst_DECL, const void *actionlist); - -/* Feed encoder with actions. Calls are generated by pre-processor. */ -DASM_FDEF void dasm_put(Dst_DECL, int start, ...); - -/* Link sections and return the resulting size. */ -DASM_FDEF int dasm_link(Dst_DECL, size_t *szp); - -/* Encode sections into buffer. */ -DASM_FDEF int dasm_encode(Dst_DECL, void *buffer); - -/* Get PC label offset. */ -DASM_FDEF int dasm_getpclabel(Dst_DECL, unsigned int pc); - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -DASM_FDEF int dasm_checkstep(Dst_DECL, int secmatch); -#else -#define dasm_checkstep(a, b) 0 -#endif - - -#endif /* _DASM_PROTO_H */ diff --git a/ext/opcache/jit/dynasm/dasm_x64.lua b/ext/opcache/jit/dynasm/dasm_x64.lua deleted file mode 100644 index 2c0a0e8681f17..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_x64.lua +++ /dev/null @@ -1,12 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM x64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- --- This module just sets 64 bit mode for the combined x86/x64 module. --- All the interesting stuff is there. ------------------------------------------------------------------------------- - -x64 = true -- Using a global is an ugly, but effective solution. -return require("dasm_x86") diff --git a/ext/opcache/jit/dynasm/dasm_x86.h b/ext/opcache/jit/dynasm/dasm_x86.h deleted file mode 100644 index 098b226b06a11..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_x86.h +++ /dev/null @@ -1,540 +0,0 @@ -/* -** DynASM x86 encoding engine. -** Copyright (C) 2005-2021 Mike Pall. All rights reserved. -** Released under the MIT license. See dynasm.lua for full copyright notice. -*/ - -#include -#include -#include -#include - -#define DASM_ARCH "x86" - -#ifndef DASM_EXTERN -#define DASM_EXTERN(a,b,c,d) 0 -#endif - -/* Action definitions. DASM_STOP must be 255. */ -enum { - DASM_DISP = 233, - DASM_IMM_S, DASM_IMM_B, DASM_IMM_W, DASM_IMM_D, DASM_IMM_WB, DASM_IMM_DB, - DASM_VREG, DASM_SPACE, DASM_SETLABEL, DASM_REL_A, DASM_REL_LG, DASM_REL_PC, - DASM_IMM_LG, DASM_IMM_PC, DASM_LABEL_LG, DASM_LABEL_PC, DASM_ALIGN, - DASM_EXTERN, DASM_ESC, DASM_MARK, DASM_SECTION, DASM_STOP -}; - -/* Maximum number of section buffer positions for a single dasm_put() call. */ -#define DASM_MAXSECPOS 25 - -/* DynASM encoder status codes. Action list offset or number are or'ed in. */ -#define DASM_S_OK 0x00000000 -#define DASM_S_NOMEM 0x01000000 -#define DASM_S_PHASE 0x02000000 -#define DASM_S_MATCH_SEC 0x03000000 -#define DASM_S_RANGE_I 0x11000000 -#define DASM_S_RANGE_SEC 0x12000000 -#define DASM_S_RANGE_LG 0x13000000 -#define DASM_S_RANGE_PC 0x14000000 -#define DASM_S_RANGE_VREG 0x15000000 -#define DASM_S_UNDEF_L 0x21000000 -#define DASM_S_UNDEF_PC 0x22000000 - -/* Macros to convert positions (8 bit section + 24 bit index). */ -#define DASM_POS2IDX(pos) ((pos)&0x00ffffff) -#define DASM_POS2BIAS(pos) ((pos)&0xff000000) -#define DASM_SEC2POS(sec) ((sec)<<24) -#define DASM_POS2SEC(pos) ((pos)>>24) -#define DASM_POS2PTR(D, pos) (D->sections[DASM_POS2SEC(pos)].rbuf + (pos)) - -/* Action list type. */ -typedef const unsigned char *dasm_ActList; - -/* Per-section structure. */ -typedef struct dasm_Section { - int *rbuf; /* Biased buffer pointer (negative section bias). */ - int *buf; /* True buffer pointer. */ - size_t bsize; /* Buffer size in bytes. */ - int pos; /* Biased buffer position. */ - int epos; /* End of biased buffer position - max single put. */ - int ofs; /* Byte offset into section. */ -} dasm_Section; - -/* Core structure holding the DynASM encoding state. */ -struct dasm_State { - size_t psize; /* Allocated size of this structure. */ - dasm_ActList actionlist; /* Current actionlist pointer. */ - int *lglabels; /* Local/global chain/pos ptrs. */ - size_t lgsize; - int *pclabels; /* PC label chains/pos ptrs. */ - size_t pcsize; - void **globals; /* Array of globals (bias -10). */ - dasm_Section *section; /* Pointer to active section. */ - size_t codesize; /* Total size of all code sections. */ - int maxsection; /* 0 <= sectionidx < maxsection. */ - int status; /* Status code. */ - dasm_Section sections[1]; /* All sections. Alloc-extended. */ -}; - -/* The size of the core structure depends on the max. number of sections. */ -#define DASM_PSZ(ms) (sizeof(dasm_State)+(ms-1)*sizeof(dasm_Section)) - -/* Perform potentially overflowing pointer operations in a way that avoids UB. */ -#define DASM_PTR_SUB(p1, off) ((void *) ((uintptr_t) (p1) - sizeof(*p1) * (uintptr_t) (off))) -#define DASM_PTR_ADD(p1, off) ((void *) ((uintptr_t) (p1) + sizeof(*p1) * (uintptr_t) (off))) - -/* Initialize DynASM state. */ -void dasm_init(Dst_DECL, int maxsection) -{ - dasm_State *D; - size_t psz = 0; - int i; - Dst_REF = NULL; - DASM_M_GROW(Dst, struct dasm_State, Dst_REF, psz, DASM_PSZ(maxsection)); - D = Dst_REF; - D->psize = psz; - D->lglabels = NULL; - D->lgsize = 0; - D->pclabels = NULL; - D->pcsize = 0; - D->globals = NULL; - D->maxsection = maxsection; - for (i = 0; i < maxsection; i++) { - D->sections[i].buf = NULL; /* Need this for pass3. */ - D->sections[i].rbuf = DASM_PTR_SUB(D->sections[i].buf, DASM_SEC2POS(i)); - D->sections[i].bsize = 0; - D->sections[i].epos = 0; /* Wrong, but is recalculated after resize. */ - } -} - -/* Free DynASM state. */ -void dasm_free(Dst_DECL) -{ - dasm_State *D = Dst_REF; - int i; - for (i = 0; i < D->maxsection; i++) - if (D->sections[i].buf) - DASM_M_FREE(Dst, D->sections[i].buf, D->sections[i].bsize); - if (D->pclabels) DASM_M_FREE(Dst, D->pclabels, D->pcsize); - if (D->lglabels) DASM_M_FREE(Dst, D->lglabels, D->lgsize); - DASM_M_FREE(Dst, D, D->psize); -} - -/* Setup global label array. Must be called before dasm_setup(). */ -void dasm_setupglobal(Dst_DECL, void **gl, unsigned int maxgl) -{ - dasm_State *D = Dst_REF; -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Warray-bounds" -#endif - D->globals = gl - 10; /* Negative bias to compensate for locals. */ -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif - DASM_M_GROW(Dst, int, D->lglabels, D->lgsize, (10+maxgl)*sizeof(int)); -} - -/* Grow PC label array. Can be called after dasm_setup(), too. */ -void dasm_growpc(Dst_DECL, unsigned int maxpc) -{ - dasm_State *D = Dst_REF; - size_t osz = D->pcsize; - DASM_M_GROW(Dst, int, D->pclabels, D->pcsize, maxpc*sizeof(int)); - memset((void *)(((unsigned char *)D->pclabels)+osz), 0, D->pcsize-osz); -} - -/* Setup encoder. */ -void dasm_setup(Dst_DECL, const void *actionlist) -{ - dasm_State *D = Dst_REF; - int i; - D->actionlist = (dasm_ActList)actionlist; - D->status = DASM_S_OK; - D->section = &D->sections[0]; - memset((void *)D->lglabels, 0, D->lgsize); - if (D->pclabels) memset((void *)D->pclabels, 0, D->pcsize); - for (i = 0; i < D->maxsection; i++) { - D->sections[i].pos = DASM_SEC2POS(i); - D->sections[i].ofs = 0; - } -} - - -#ifdef DASM_CHECKS -#define CK(x, st) \ - do { if (!(x)) { \ - D->status = DASM_S_##st|(int)(p-D->actionlist-1); return; } } while (0) -#define CKPL(kind, st) \ - do { if ((size_t)((char *)pl-(char *)D->kind##labels) >= D->kind##size) { \ - D->status=DASM_S_RANGE_##st|(int)(p-D->actionlist-1); return; } } while (0) -#else -#define CK(x, st) ((void)0) -#define CKPL(kind, st) ((void)0) -#endif - -/* Pass 1: Store actions and args, link branches/labels, estimate offsets. */ -void dasm_put(Dst_DECL, int start, ...) -{ - va_list ap; - dasm_State *D = Dst_REF; - dasm_ActList p = D->actionlist + start; - dasm_Section *sec = D->section; - int pos = sec->pos, ofs = sec->ofs, mrm = -1; - int *b; - - if (pos >= sec->epos) { - DASM_M_GROW(Dst, int, sec->buf, sec->bsize, - sec->bsize + 2*DASM_MAXSECPOS*sizeof(int)); - sec->rbuf = sec->buf - DASM_POS2BIAS(pos); - sec->epos = (int)sec->bsize/sizeof(int) - DASM_MAXSECPOS+DASM_POS2BIAS(pos); - } - - b = sec->rbuf; - b[pos++] = start; - - va_start(ap, start); - while (1) { - int action = *p++; - if (action < DASM_DISP) { - ofs++; - } else if (action <= DASM_REL_A) { - int n = va_arg(ap, int); - b[pos++] = n; - switch (action) { - case DASM_DISP: - if (n == 0) { if (mrm < 0) mrm = p[-2]; if ((mrm&7) != 5) break; } - /* fallthrough */ - case DASM_IMM_DB: if ((((unsigned)n+128)&-256) == 0) goto ob; /* fallthrough */ - case DASM_REL_A: /* Assumes ptrdiff_t is int. !x64 */ - case DASM_IMM_D: ofs += 4; break; - case DASM_IMM_S: CK(((n+128)&-256) == 0, RANGE_I); goto ob; - case DASM_IMM_B: CK((n&-256) == 0, RANGE_I); ob: ofs++; break; - case DASM_IMM_WB: if (((n+128)&-256) == 0) goto ob; /* fallthrough */ - case DASM_IMM_W: CK((n&-65536) == 0, RANGE_I); ofs += 2; break; - case DASM_SPACE: p++; ofs += n; break; - case DASM_SETLABEL: b[pos-2] = -0x40000000; break; /* Neg. label ofs. */ - case DASM_VREG: CK((n&-16) == 0 && (n != 4 || (*p>>5) != 2), RANGE_VREG); - if (*p < 0x40 && p[1] == DASM_DISP) mrm = n; - if (*p < 0x20 && (n&7) == 4) ofs++; - switch ((*p++ >> 3) & 3) { - case 3: n |= b[pos-3]; /* fallthrough */ - case 2: n |= b[pos-2]; /* fallthrough */ - case 1: if (n <= 7) { b[pos-1] |= 0x10; ofs--; } - } - continue; - } - mrm = -1; - } else { - int *pl, n; - switch (action) { - case DASM_REL_LG: - case DASM_IMM_LG: - n = *p++; pl = D->lglabels + n; - /* Bkwd rel or global. */ - if (n <= 246) { CK(n>=10||*pl<0, RANGE_LG); CKPL(lg, LG); goto putrel; } - pl -= 246; n = *pl; - if (n < 0) n = 0; /* Start new chain for fwd rel if label exists. */ - goto linkrel; - case DASM_REL_PC: - case DASM_IMM_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putrel: - n = *pl; - if (n < 0) { /* Label exists. Get label pos and store it. */ - b[pos] = -n; - } else { - linkrel: - b[pos] = n; /* Else link to rel chain, anchored at label. */ - *pl = pos; - } - pos++; - ofs += 4; /* Maximum offset needed. */ - if (action == DASM_REL_LG || action == DASM_REL_PC) { - b[pos++] = ofs; /* Store pass1 offset estimate. */ - } else if (sizeof(ptrdiff_t) == 8) { - ofs += 4; - } - break; - case DASM_LABEL_LG: pl = D->lglabels + *p++; CKPL(lg, LG); goto putlabel; - case DASM_LABEL_PC: pl = D->pclabels + va_arg(ap, int); CKPL(pc, PC); - putlabel: - n = *pl; /* n > 0: Collapse rel chain and replace with label pos. */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = pos; } - *pl = -pos; /* Label exists now. */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_ALIGN: - ofs += *p++; /* Maximum alignment needed (arg is 2**n-1). */ - b[pos++] = ofs; /* Store pass1 offset estimate. */ - break; - case DASM_EXTERN: p += 2; ofs += 4; break; - case DASM_ESC: p++; ofs++; break; - case DASM_MARK: mrm = p[-2]; break; - case DASM_SECTION: - n = *p; CK(n < D->maxsection, RANGE_SEC); D->section = &D->sections[n]; - case DASM_STOP: goto stop; - } - } - } -stop: - va_end(ap); - sec->pos = pos; - sec->ofs = ofs; -} -#undef CK - -/* Pass 2: Link sections, shrink branches/aligns, fix label offsets. */ -int dasm_link(Dst_DECL, size_t *szp) -{ - dasm_State *D = Dst_REF; - int secnum; - int ofs = 0; - -#ifdef DASM_CHECKS - *szp = 0; - if (D->status != DASM_S_OK) return D->status; - { - int pc; - for (pc = 0; pc*sizeof(int) < D->pcsize; pc++) - if (D->pclabels[pc] > 0) return DASM_S_UNDEF_PC|pc; - } -#endif - - { /* Handle globals not defined in this translation unit. */ - int idx; - for (idx = 10; idx*sizeof(int) < D->lgsize; idx++) { - int n = D->lglabels[idx]; - /* Undefined label: Collapse rel chain and replace with marker (< 0). */ - while (n > 0) { int *pb = DASM_POS2PTR(D, n); n = *pb; *pb = -idx; } - } - } - - /* Combine all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->rbuf; - int pos = DASM_SEC2POS(secnum); - int lastpos = sec->pos; - - while (pos != lastpos) { - dasm_ActList p = D->actionlist + b[pos++]; - int op = 0; - while (1) { - int action = *p++; - switch (action) { - case DASM_REL_LG: p++; - /* fallthrough */ - case DASM_REL_PC: { - int shrink = op == 0xe9 ? 3 : ((op&0xf0) == 0x80 ? 4 : 0); - if (shrink) { /* Shrinkable branch opcode? */ - int lofs, lpos = b[pos]; - if (lpos < 0) goto noshrink; /* Ext global? */ - lofs = *DASM_POS2PTR(D, lpos); - if (lpos > pos) { /* Fwd label: add cumulative section offsets. */ - int i; - for (i = secnum; i < DASM_POS2SEC(lpos); i++) - lofs += D->sections[i].ofs; - } else { - lofs -= ofs; /* Bkwd label: unfix offset. */ - } - lofs -= b[pos+1]; /* Short branch ok? */ - if (lofs >= -128-shrink && lofs <= 127) ofs -= shrink; /* Yes. */ - else { noshrink: shrink = 0; } /* No, cannot shrink op. */ - } - b[pos+1] = shrink; - pos += 2; - break; - } - /* fallthrough */ - case DASM_SPACE: case DASM_IMM_LG: case DASM_VREG: p++; - case DASM_DISP: case DASM_IMM_S: case DASM_IMM_B: case DASM_IMM_W: - case DASM_IMM_D: case DASM_IMM_WB: case DASM_IMM_DB: - case DASM_SETLABEL: case DASM_REL_A: case DASM_IMM_PC: pos++; break; - case DASM_LABEL_LG: p++; - /* fallthrough */ - case DASM_LABEL_PC: b[pos++] += ofs; break; /* Fix label offset. */ - case DASM_ALIGN: ofs -= (b[pos++]+ofs)&*p++; break; /* Adjust ofs. */ - case DASM_EXTERN: p += 2; break; - case DASM_ESC: op = *p++; break; - case DASM_MARK: break; - case DASM_SECTION: case DASM_STOP: goto stop; - default: op = action; break; - } - } - stop: (void)0; - } - ofs += sec->ofs; /* Next section starts right after current section. */ - } - - D->codesize = ofs; /* Total size of all code sections */ - *szp = ofs; - return DASM_S_OK; -} - -#define dasmb(x) *cp++ = (unsigned char)(x) -#ifndef DASM_ALIGNED_WRITES -typedef ZEND_SET_ALIGNED(1, unsigned short unaligned_short); -typedef ZEND_SET_ALIGNED(1, unsigned int unaligned_int); -typedef ZEND_SET_ALIGNED(1, unsigned long long unaligned_long_long); -#define dasmw(x) \ - do { *((unaligned_short *)cp) = (unsigned short)(x); cp+=2; } while (0) -#define dasmd(x) \ - do { *((unaligned_int *)cp) = (unsigned int)(x); cp+=4; } while (0) -#define dasmq(x) \ - do { *((unaligned_long_long *)cp) = (unsigned long long)(x); cp+=8; } while (0) -#else -#define dasmw(x) do { dasmb(x); dasmb((x)>>8); } while (0) -#define dasmd(x) do { dasmw(x); dasmw((x)>>16); } while (0) -#define dasmq(x) do { dasmd(x); dasmd((x)>>32); } while (0) -#endif -static unsigned char *dasma_(unsigned char *cp, ptrdiff_t x) -{ - if (sizeof(ptrdiff_t) == 8) - dasmq((unsigned long long)x); - else - dasmd((unsigned int)x); - return cp; -} -#define dasma(x) (cp = dasma_(cp, (x))) - -/* Pass 3: Encode sections. */ -int dasm_encode(Dst_DECL, void *buffer) -{ - dasm_State *D = Dst_REF; - unsigned char *base = (unsigned char *)buffer; - unsigned char *cp = base; - int secnum; - - /* Encode all code sections. No support for data sections (yet). */ - for (secnum = 0; secnum < D->maxsection; secnum++) { - dasm_Section *sec = D->sections + secnum; - int *b = sec->buf; - int *endb = DASM_PTR_ADD(sec->rbuf, sec->pos); - - while (b != endb) { - dasm_ActList p = D->actionlist + *b++; - unsigned char *mark = NULL; - while (1) { - int action = *p++; - int n = (action >= DASM_DISP && action <= DASM_ALIGN) ? *b++ : 0; - switch (action) { - case DASM_DISP: if (!mark) mark = cp; { - unsigned char *mm = mark; - if (*p != DASM_IMM_DB && *p != DASM_IMM_WB) mark = NULL; - if (n == 0) { int mrm = mm[-1]&7; if (mrm == 4) mrm = mm[0]&7; - if (mrm != 5) { mm[-1] -= 0x80; break; } } - if ((((unsigned)n+128) & -256) != 0) goto wd; else mm[-1] -= 0x40; - } - /* fallthrough */ - case DASM_IMM_S: case DASM_IMM_B: wb: dasmb(n); break; - case DASM_IMM_DB: if ((((unsigned)n+128)&-256) == 0) { - db: if (!mark) mark = cp; mark[-2] += 2; mark = NULL; goto wb; - } else mark = NULL; - /* fallthrough */ - case DASM_IMM_D: wd: dasmd(n); break; - case DASM_IMM_WB: if ((((unsigned)n+128)&-256) == 0) goto db; else mark = NULL; - /* fallthrough */ - case DASM_IMM_W: dasmw(n); break; - case DASM_VREG: { - int t = *p++; - unsigned char *ex = cp - (t&7); - if ((n & 8) && t < 0xa0) { - if (*ex & 0x80) ex[1] ^= 0x20 << (t>>6); else *ex ^= 1 << (t>>6); - n &= 7; - } else if (n & 0x10) { - if (*ex & 0x80) { - *ex = 0xc5; ex[1] = (ex[1] & 0x80) | ex[2]; ex += 2; - } - while (++ex < cp) ex[-1] = *ex; - if (mark) mark--; - cp--; - n &= 7; - } - if (t >= 0xc0) n <<= 4; - else if (t >= 0x40) n <<= 3; - else if (n == 4 && t < 0x20) { cp[-1] ^= n; *cp++ = 0x20; } - cp[-1] ^= n; - break; - } - case DASM_REL_LG: p++; if (n >= 0) goto rel_pc; - b++; n = (int)(ptrdiff_t)D->globals[-n]; - /* fallthrough */ - case DASM_REL_A: rel_a: - n -= (unsigned int)(ptrdiff_t)(cp+4); goto wd; /* !x64 */ - case DASM_REL_PC: rel_pc: { - int shrink = *b++; - int *pb = DASM_POS2PTR(D, n); if (*pb < 0) { n = pb[1]; goto rel_a; } - n = *pb - ((int)(cp-base) + 4-shrink); - if (shrink == 0) goto wd; - if (shrink == 4) { cp--; cp[-1] = *cp-0x10; } else cp[-1] = 0xeb; - goto wb; - } - case DASM_IMM_LG: - p++; - if (n < 0) { dasma((ptrdiff_t)D->globals[-n]); break; } - /* fallthrough */ - case DASM_IMM_PC: { - int *pb = DASM_POS2PTR(D, n); - dasma(*pb < 0 ? (ptrdiff_t)pb[1] : (*pb + (ptrdiff_t)base)); - break; - } - case DASM_LABEL_LG: { - int idx = *p++; - if (idx >= 10) - D->globals[idx] = (void *)(base + (*p == DASM_SETLABEL ? *b : n)); - break; - } - case DASM_LABEL_PC: case DASM_SETLABEL: break; - case DASM_SPACE: { int fill = *p++; while (n--) *cp++ = fill; break; } - case DASM_ALIGN: - n = *p++; - while (((cp-base) & n)) *cp++ = 0x90; /* nop */ - break; - case DASM_EXTERN: n = DASM_EXTERN(Dst, cp, p[1], *p); p += 2; goto wd; - case DASM_MARK: mark = cp; break; - case DASM_ESC: action = *p++; - /* fallthrough */ - default: *cp++ = action; break; - case DASM_SECTION: case DASM_STOP: goto stop; - } - } - stop: (void)0; - } - } - - if (base + D->codesize != cp) /* Check for phase errors. */ - return DASM_S_PHASE; - return DASM_S_OK; -} - -/* Get PC label offset. */ -int dasm_getpclabel(Dst_DECL, unsigned int pc) -{ - dasm_State *D = Dst_REF; - if (pc*sizeof(int) < D->pcsize) { - int pos = D->pclabels[pc]; - if (pos < 0) return *DASM_POS2PTR(D, -pos); - if (pos > 0) return -1; /* Undefined. */ - } - return -2; /* Unused or out of range. */ -} - -#ifdef DASM_CHECKS -/* Optional sanity checker to call between isolated encoding steps. */ -int dasm_checkstep(Dst_DECL, int secmatch) -{ - dasm_State *D = Dst_REF; - if (D->status == DASM_S_OK) { - int i; - for (i = 1; i <= 9; i++) { - if (D->lglabels[i] > 0) { D->status = DASM_S_UNDEF_L|i; break; } - D->lglabels[i] = 0; - } - } - if (D->status == DASM_S_OK && secmatch >= 0 && - D->section != &D->sections[secmatch]) - D->status = DASM_S_MATCH_SEC|(int)(D->section-D->sections); - return D->status; -} -#endif - diff --git a/ext/opcache/jit/dynasm/dasm_x86.lua b/ext/opcache/jit/dynasm/dasm_x86.lua deleted file mode 100644 index d5eea69e485a7..0000000000000 --- a/ext/opcache/jit/dynasm/dasm_x86.lua +++ /dev/null @@ -1,2390 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM x86/x64 module. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See dynasm.lua for full copyright notice. ------------------------------------------------------------------------------- - -local x64 = x64 - --- Module information: -local _info = { - arch = x64 and "x64" or "x86", - description = "DynASM x86/x64 module", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - license = "MIT", -} - --- Exported glue functions for the arch-specific module. -local _M = { _info = _info } - --- Cache library functions. -local type, tonumber, pairs, ipairs = type, tonumber, pairs, ipairs -local assert, unpack, setmetatable = assert, unpack or table.unpack, setmetatable -local _s = string -local sub, format, byte, char = _s.sub, _s.format, _s.byte, _s.char -local find, match, gmatch, gsub = _s.find, _s.match, _s.gmatch, _s.gsub -local concat, sort, remove = table.concat, table.sort, table.remove -local bit = bit or require("bit") -local band, bxor, shl, shr = bit.band, bit.bxor, bit.lshift, bit.rshift - --- Inherited tables and callbacks. -local g_opt, g_arch -local wline, werror, wfatal, wwarn - --- Action name list. --- CHECK: Keep this in sync with the C code! -local action_names = { - -- int arg, 1 buffer pos: - "DISP", "IMM_S", "IMM_B", "IMM_W", "IMM_D", "IMM_WB", "IMM_DB", - -- action arg (1 byte), int arg, 1 buffer pos (reg/num): - "VREG", "SPACE", - -- ptrdiff_t arg, 1 buffer pos (address): !x64 - "SETLABEL", "REL_A", - -- action arg (1 byte) or int arg, 2 buffer pos (link, offset): - "REL_LG", "REL_PC", - -- action arg (1 byte) or int arg, 1 buffer pos (link): - "IMM_LG", "IMM_PC", - -- action arg (1 byte) or int arg, 1 buffer pos (offset): - "LABEL_LG", "LABEL_PC", - -- action arg (1 byte), 1 buffer pos (offset): - "ALIGN", - -- action args (2 bytes), no buffer pos. - "EXTERN", - -- action arg (1 byte), no buffer pos. - "ESC", - -- no action arg, no buffer pos. - "MARK", - -- action arg (1 byte), no buffer pos, terminal action: - "SECTION", - -- no args, no buffer pos, terminal action: - "STOP" -} - --- Maximum number of section buffer positions for dasm_put(). --- CHECK: Keep this in sync with the C code! -local maxsecpos = 25 -- Keep this low, to avoid excessively long C lines. - --- Action name -> action number (dynamically generated below). -local map_action = {} --- First action number. Everything below does not need to be escaped. -local actfirst = 256-#action_names - --- Action list buffer and string (only used to remove dupes). -local actlist = {} -local actstr = "" - --- Argument list for next dasm_put(). Start with offset 0 into action list. -local actargs = { 0 } - --- Current number of section buffer positions for dasm_put(). -local secpos = 1 - --- VREG kind encodings, pre-shifted by 5 bits. -local map_vreg = { - ["modrm.rm.m"] = 0x00, - ["modrm.rm.r"] = 0x20, - ["opcode"] = 0x20, - ["sib.base"] = 0x20, - ["sib.index"] = 0x40, - ["modrm.reg"] = 0x80, - ["vex.v"] = 0xa0, - ["imm.hi"] = 0xc0, -} - --- Current number of VREG actions contributing to REX/VEX shrinkage. -local vreg_shrink_count = 0 - ------------------------------------------------------------------------------- - --- Compute action numbers for action names. -for n,name in ipairs(action_names) do - local num = actfirst + n - 1 - map_action[name] = num -end - --- Dump action names and numbers. -local function dumpactions(out) - out:write("DynASM encoding engine action codes:\n") - for n,name in ipairs(action_names) do - local num = map_action[name] - out:write(format(" %-10s %02X %d\n", name, num, num)) - end - out:write("\n") -end - --- Write action list buffer as a huge static C array. -local function writeactions(out, name) - local nn = #actlist - local last = actlist[nn] or 255 - actlist[nn] = nil -- Remove last byte. - if nn == 0 then nn = 1 end - out:write("static const unsigned char ", name, "[", nn, "] = {\n") - local s = " " - for n,b in ipairs(actlist) do - s = s..b.."," - if #s >= 75 then - assert(out:write(s, "\n")) - s = " " - end - end - out:write(s, last, "\n};\n\n") -- Add last byte back. -end - ------------------------------------------------------------------------------- - --- Add byte to action list. -local function wputxb(n) - assert(n >= 0 and n <= 255 and n % 1 == 0, "byte out of range") - actlist[#actlist+1] = n -end - --- Add action to list with optional arg. Advance buffer pos, too. -local function waction(action, a, num) - wputxb(assert(map_action[action], "bad action name `"..action.."'")) - if a then actargs[#actargs+1] = a end - if a or num then secpos = secpos + (num or 1) end -end - --- Optionally add a VREG action. -local function wvreg(kind, vreg, psz, sk, defer) - if not vreg then return end - waction("VREG", vreg) - local b = assert(map_vreg[kind], "bad vreg kind `"..vreg.."'") - if b < (sk or 0) then - vreg_shrink_count = vreg_shrink_count + 1 - end - if not defer then - b = b + vreg_shrink_count * 8 - vreg_shrink_count = 0 - end - wputxb(b + (psz or 0)) -end - --- Add call to embedded DynASM C code. -local function wcall(func, args) - wline(format("dasm_%s(Dst, %s);", func, concat(args, ", ")), true) -end - --- Delete duplicate action list chunks. A tad slow, but so what. -local function dedupechunk(offset) - local al, as = actlist, actstr - local chunk = char(unpack(al, offset+1, #al)) - local orig = find(as, chunk, 1, true) - if orig then - actargs[1] = orig-1 -- Replace with original offset. - for i=offset+1,#al do al[i] = nil end -- Kill dupe. - else - actstr = as..chunk - end -end - --- Flush action list (intervening C code or buffer pos overflow). -local function wflush(term) - local offset = actargs[1] - if #actlist == offset then return end -- Nothing to flush. - if not term then waction("STOP") end -- Terminate action list. - dedupechunk(offset) - wcall("put", actargs) -- Add call to dasm_put(). - actargs = { #actlist } -- Actionlist offset is 1st arg to next dasm_put(). - secpos = 1 -- The actionlist offset occupies a buffer position, too. -end - --- Put escaped byte. -local function wputb(n) - if n >= actfirst then waction("ESC") end -- Need to escape byte. - wputxb(n) -end - ------------------------------------------------------------------------------- - --- Global label name -> global label number. With auto assignment on 1st use. -local next_global = 10 -local map_global = setmetatable({}, { __index = function(t, name) - if not match(name, "^[%a_][%w_@]*$") then werror("bad global label") end - local n = next_global - if n > 246 then werror("too many global labels") end - next_global = n + 1 - t[name] = n - return n -end}) - --- Dump global labels. -local function dumpglobals(out, lvl) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("Global labels:\n") - for i=10,next_global-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write global label enum. -local function writeglobals(out, prefix) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("enum {\n") - for i=10,next_global-1 do - out:write(" ", prefix, gsub(t[i], "@.*", ""), ",\n") - end - out:write(" ", prefix, "_MAX\n};\n") -end - --- Write global label names. -local function writeglobalnames(out, name) - local t = {} - for name, n in pairs(map_global) do t[n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=10,next_global-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Extern label name -> extern label number. With auto assignment on 1st use. -local next_extern = -1 -local map_extern = setmetatable({}, { __index = function(t, name) - -- No restrictions on the name for now. - local n = next_extern - if n < -256 then werror("too many extern labels") end - next_extern = n - 1 - t[name] = n - return n -end}) - --- Dump extern labels. -local function dumpexterns(out, lvl) - local t = {} - for name, n in pairs(map_extern) do t[-n] = name end - out:write("Extern labels:\n") - for i=1,-next_extern-1 do - out:write(format(" %s\n", t[i])) - end - out:write("\n") -end - --- Write extern label names. -local function writeexternnames(out, name) - local t = {} - for name, n in pairs(map_extern) do t[-n] = name end - out:write("static const char *const ", name, "[] = {\n") - for i=1,-next_extern-1 do - out:write(" \"", t[i], "\",\n") - end - out:write(" (const char *)0\n};\n") -end - ------------------------------------------------------------------------------- - --- Arch-specific maps. -local map_archdef = {} -- Ext. register name -> int. name. -local map_reg_rev = {} -- Int. register name -> ext. name. -local map_reg_num = {} -- Int. register name -> register number. -local map_reg_opsize = {} -- Int. register name -> operand size. -local map_reg_valid_base = {} -- Int. register name -> valid base register? -local map_reg_valid_index = {} -- Int. register name -> valid index register? -local map_reg_needrex = {} -- Int. register name -> need rex vs. no rex. -local reg_list = {} -- Canonical list of int. register names. - -local map_type = {} -- Type name -> { ctype, reg } -local ctypenum = 0 -- Type number (for _PTx macros). - -local addrsize = x64 and "q" or "d" -- Size for address operands. - --- Helper functions to fill register maps. -local function mkrmap(sz, cl, names) - local cname = format("@%s", sz) - reg_list[#reg_list+1] = cname - map_archdef[cl] = cname - map_reg_rev[cname] = cl - map_reg_num[cname] = -1 - map_reg_opsize[cname] = sz - if sz == addrsize or sz == "d" then - map_reg_valid_base[cname] = true - map_reg_valid_index[cname] = true - end - if names then - for n,name in ipairs(names) do - local iname = format("@%s%x", sz, n-1) - reg_list[#reg_list+1] = iname - map_archdef[name] = iname - map_reg_rev[iname] = name - map_reg_num[iname] = n-1 - map_reg_opsize[iname] = sz - if sz == "b" and n > 4 then map_reg_needrex[iname] = false end - if sz == addrsize or sz == "d" then - map_reg_valid_base[iname] = true - map_reg_valid_index[iname] = true - end - end - end - for i=0,(x64 and sz ~= "f") and 15 or 7 do - local needrex = sz == "b" and i > 3 - local iname = format("@%s%x%s", sz, i, needrex and "R" or "") - if needrex then map_reg_needrex[iname] = true end - local name - if sz == "o" or sz == "y" then name = format("%s%d", cl, i) - elseif sz == "f" then name = format("st%d", i) - else name = format("r%d%s", i, sz == addrsize and "" or sz) end - map_archdef[name] = iname - if not map_reg_rev[iname] then - reg_list[#reg_list+1] = iname - map_reg_rev[iname] = name - map_reg_num[iname] = i - map_reg_opsize[iname] = sz - if sz == addrsize or sz == "d" then - map_reg_valid_base[iname] = true - map_reg_valid_index[iname] = true - end - end - end - reg_list[#reg_list+1] = "" -end - --- Integer registers (qword, dword, word and byte sized). -if x64 then - mkrmap("q", "Rq", {"rax", "rcx", "rdx", "rbx", "rsp", "rbp", "rsi", "rdi"}) -end -mkrmap("d", "Rd", {"eax", "ecx", "edx", "ebx", "esp", "ebp", "esi", "edi"}) -mkrmap("w", "Rw", {"ax", "cx", "dx", "bx", "sp", "bp", "si", "di"}) -mkrmap("b", "Rb", {"al", "cl", "dl", "bl", "ah", "ch", "dh", "bh"}) -map_reg_valid_index[map_archdef.esp] = false -if x64 then map_reg_valid_index[map_archdef.rsp] = false end -if x64 then map_reg_needrex[map_archdef.Rb] = true end -map_archdef["Ra"] = "@"..addrsize - --- FP registers (internally tword sized, but use "f" as operand size). -mkrmap("f", "Rf") - --- SSE registers (oword sized, but qword and dword accessible). -mkrmap("o", "xmm") - --- AVX registers (yword sized, but oword, qword and dword accessible). -mkrmap("y", "ymm") - --- Operand size prefixes to codes. -local map_opsize = { - byte = "b", word = "w", dword = "d", qword = "q", oword = "o", yword = "y", - tword = "t", aword = addrsize, -} - --- Operand size code to number. -local map_opsizenum = { - b = 1, w = 2, d = 4, q = 8, o = 16, y = 32, t = 10, -} - --- Operand size code to name. -local map_opsizename = { - b = "byte", w = "word", d = "dword", q = "qword", o = "oword", y = "yword", - t = "tword", f = "fpword", -} - --- Valid index register scale factors. -local map_xsc = { - ["1"] = 0, ["2"] = 1, ["4"] = 2, ["8"] = 3, -} - --- Condition codes. -local map_cc = { - o = 0, no = 1, b = 2, nb = 3, e = 4, ne = 5, be = 6, nbe = 7, - s = 8, ns = 9, p = 10, np = 11, l = 12, nl = 13, le = 14, nle = 15, - c = 2, nae = 2, nc = 3, ae = 3, z = 4, nz = 5, na = 6, a = 7, - pe = 10, po = 11, nge = 12, ge = 13, ng = 14, g = 15, -} - - --- Reverse defines for registers. -function _M.revdef(s) - return gsub(s, "@%w+", map_reg_rev) -end - --- Dump register names and numbers -local function dumpregs(out) - out:write("Register names, sizes and internal numbers:\n") - for _,reg in ipairs(reg_list) do - if reg == "" then - out:write("\n") - else - local name = map_reg_rev[reg] - local num = map_reg_num[reg] - local opsize = map_opsizename[map_reg_opsize[reg]] - out:write(format(" %-5s %-8s %s\n", name, opsize, - num < 0 and "(variable)" or num)) - end - end -end - ------------------------------------------------------------------------------- - --- Put action for label arg (IMM_LG, IMM_PC, REL_LG, REL_PC). -local function wputlabel(aprefix, imm, num) - if type(imm) == "number" then - if imm < 0 then - waction("EXTERN") - wputxb(aprefix == "IMM_" and 0 or 1) - imm = -imm-1 - else - waction(aprefix.."LG", nil, num); - end - wputxb(imm) - else - waction(aprefix.."PC", imm, num) - end -end - --- Put signed byte or arg. -local function wputsbarg(n) - if type(n) == "number" then - if n < -128 or n > 127 then - werror("signed immediate byte out of range") - end - if n < 0 then n = n + 256 end - wputb(n) - else waction("IMM_S", n) end -end - --- Put unsigned byte or arg. -local function wputbarg(n) - if type(n) == "number" then - if n < 0 or n > 255 then - werror("unsigned immediate byte out of range") - end - wputb(n) - else waction("IMM_B", n) end -end - --- Put unsigned word or arg. -local function wputwarg(n) - if type(n) == "number" then - if shr(n, 16) ~= 0 then - werror("unsigned immediate word out of range") - end - wputb(band(n, 255)); wputb(shr(n, 8)); - else waction("IMM_W", n) end -end - --- Put signed or unsigned dword or arg. -local function wputdarg(n) - local tn = type(n) - if tn == "number" then - wputb(band(n, 255)) - wputb(band(shr(n, 8), 255)) - wputb(band(shr(n, 16), 255)) - wputb(shr(n, 24)) - elseif tn == "table" then - wputlabel("IMM_", n[1], 1) - else - waction("IMM_D", n) - end -end - --- Put signed or unsigned qword or arg. -local function wputqarg(n) - local tn = type(n) - if tn == "number" then -- This is only used for numbers from -2^31..2^32-1. - wputb(band(n, 255)) - wputb(band(shr(n, 8), 255)) - wputb(band(shr(n, 16), 255)) - wputb(shr(n, 24)) - local sign = n < 0 and 255 or 0 - wputb(sign); wputb(sign); wputb(sign); wputb(sign) - else - waction("IMM_D", format("(unsigned int)(%s)", n)) - waction("IMM_D", format("(unsigned int)((unsigned long long)(%s)>>32)", n)) - end -end - --- Put operand-size dependent number or arg (defaults to dword). -local function wputszarg(sz, n) - if not sz or sz == "d" or sz == "q" then wputdarg(n) - elseif sz == "w" then wputwarg(n) - elseif sz == "b" then wputbarg(n) - elseif sz == "s" then wputsbarg(n) - else werror("bad operand size") end -end - --- Put multi-byte opcode with operand-size dependent modifications. -local function wputop(sz, op, rex, vex, vregr, vregxb) - local psz, sk = 0, nil - if vex then - local tail - if vex.m == 1 and band(rex, 11) == 0 then - if x64 and vregxb then - sk = map_vreg["modrm.reg"] - else - wputb(0xc5) - tail = shl(bxor(band(rex, 4), 4), 5) - psz = 3 - end - end - if not tail then - wputb(0xc4) - wputb(shl(bxor(band(rex, 7), 7), 5) + vex.m) - tail = shl(band(rex, 8), 4) - psz = 4 - end - local reg, vreg = 0, nil - if vex.v then - reg = vex.v.reg - if not reg then werror("bad vex operand") end - if reg < 0 then reg = 0; vreg = vex.v.vreg end - end - if sz == "y" or vex.l then tail = tail + 4 end - wputb(tail + shl(bxor(reg, 15), 3) + vex.p) - wvreg("vex.v", vreg) - rex = 0 - if op >= 256 then werror("bad vex opcode") end - else - if rex ~= 0 then - if not x64 then werror("bad operand size") end - elseif (vregr or vregxb) and x64 then - rex = 0x10 - sk = map_vreg["vex.v"] - end - end - local r - if sz == "w" then wputb(102) end - -- Needs >32 bit numbers, but only for crc32 eax, word [ebx] - if op >= 4294967296 then r = op%4294967296 wputb((op-r)/4294967296) op = r end - if op >= 16777216 then wputb(shr(op, 24)); op = band(op, 0xffffff) end - if op >= 65536 then - if rex ~= 0 then - local opc3 = band(op, 0xffff00) - if opc3 == 0x0f3a00 or opc3 == 0x0f3800 then - wputb(64 + band(rex, 15)); rex = 0; psz = 2 - end - end - wputb(shr(op, 16)); op = band(op, 0xffff); psz = psz + 1 - end - if op >= 256 then - local b = shr(op, 8) - if b == 15 and rex ~= 0 then wputb(64 + band(rex, 15)); rex = 0; psz = 2 end - wputb(b); op = band(op, 255); psz = psz + 1 - end - if rex ~= 0 then wputb(64 + band(rex, 15)); psz = 2 end - if sz == "b" then op = op - 1 end - wputb(op) - return psz, sk -end - --- Put ModRM or SIB formatted byte. -local function wputmodrm(m, s, rm, vs, vrm) - assert(m < 4 and s < 16 and rm < 16, "bad modrm operands") - wputb(shl(m, 6) + shl(band(s, 7), 3) + band(rm, 7)) -end - --- Put ModRM/SIB plus optional displacement. -local function wputmrmsib(t, imark, s, vsreg, psz, sk) - local vreg, vxreg - local reg, xreg = t.reg, t.xreg - if reg and reg < 0 then reg = 0; vreg = t.vreg end - if xreg and xreg < 0 then xreg = 0; vxreg = t.vxreg end - if s < 0 then s = 0 end - - -- Register mode. - if sub(t.mode, 1, 1) == "r" then - wputmodrm(3, s, reg) - wvreg("modrm.reg", vsreg, psz+1, sk, vreg) - wvreg("modrm.rm.r", vreg, psz+1, sk) - return - end - - local disp = t.disp - local tdisp = type(disp) - -- No base register? - if not reg then - local riprel = false - if xreg then - -- Indexed mode with index register only. - -- [xreg*xsc+disp] -> (0, s, esp) (xsc, xreg, ebp) - wputmodrm(0, s, 4) - if imark == "I" then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vxreg) - wputmodrm(t.xsc, xreg, 5) - wvreg("sib.index", vxreg, psz+2, sk) - else - -- Pure 32 bit displacement. - if x64 and tdisp ~= "table" then - wputmodrm(0, s, 4) -- [disp] -> (0, s, esp) (0, esp, ebp) - wvreg("modrm.reg", vsreg, psz+1, sk) - if imark == "I" then waction("MARK") end - wputmodrm(0, 4, 5) - else - riprel = x64 - wputmodrm(0, s, 5) -- [disp|rip-label] -> (0, s, ebp) - wvreg("modrm.reg", vsreg, psz+1, sk) - if imark == "I" then waction("MARK") end - end - end - if riprel then -- Emit rip-relative displacement. - if match("UWSiI", imark) then - werror("NYI: rip-relative displacement followed by immediate") - end - -- The previous byte in the action buffer cannot be 0xe9 or 0x80-0x8f. - wputlabel("REL_", disp[1], 2) - else - wputdarg(disp) - end - return - end - - local m - if tdisp == "number" then -- Check displacement size at assembly time. - if disp == 0 and band(reg, 7) ~= 5 then -- [ebp] -> [ebp+0] (in SIB, too) - if not vreg then m = 0 end -- Force DISP to allow [Rd(5)] -> [ebp+0] - elseif disp >= -128 and disp <= 127 then m = 1 - else m = 2 end - elseif tdisp == "table" then - m = 2 - end - - -- Index register present or esp as base register: need SIB encoding. - if xreg or band(reg, 7) == 4 then - wputmodrm(m or 2, s, 4) -- ModRM. - if m == nil or imark == "I" then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vxreg or vreg) - wputmodrm(t.xsc or 0, xreg or 4, reg) -- SIB. - wvreg("sib.index", vxreg, psz+2, sk, vreg) - wvreg("sib.base", vreg, psz+2, sk) - else - wputmodrm(m or 2, s, reg) -- ModRM. - if (imark == "I" and (m == 1 or m == 2)) or - (m == nil and (vsreg or vreg)) then waction("MARK") end - wvreg("modrm.reg", vsreg, psz+1, sk, vreg) - wvreg("modrm.rm.m", vreg, psz+1, sk) - end - - -- Put displacement. - if m == 1 then wputsbarg(disp) - elseif m == 2 then wputdarg(disp) - elseif m == nil then waction("DISP", disp) end -end - ------------------------------------------------------------------------------- - --- Return human-readable operand mode string. -local function opmodestr(op, args) - local m = {} - for i=1,#args do - local a = args[i] - m[#m+1] = sub(a.mode, 1, 1)..(a.opsize or "?") - end - return op.." "..concat(m, ",") -end - --- Convert number to valid integer or nil. -local function toint(expr, isqword) - local n = tonumber(expr) - if n then - if n % 1 ~= 0 then - werror("not an integer number `"..expr.."'") - elseif isqword then - if n < -2147483648 or n > 2147483647 then - n = nil -- Handle it as an expression to avoid precision loss. - end - elseif n < -2147483648 or n > 4294967295 then - werror("bad integer number `"..expr.."'") - end - return n - end -end - --- Parse immediate expression. -local function immexpr(expr) - -- &expr (pointer) - if sub(expr, 1, 1) == "&" then - return "iPJ", format("(ptrdiff_t)(%s)", sub(expr,2)) - end - - local prefix = sub(expr, 1, 2) - -- =>expr (pc label reference) - if prefix == "=>" then - return "iJ", sub(expr, 3) - end - -- ->name (global label reference) - if prefix == "->" then - return "iJ", map_global[sub(expr, 3)] - end - - -- [<>][1-9] (local label reference) - local dir, lnum = match(expr, "^([<>])([1-9])$") - if dir then -- Fwd: 247-255, Bkwd: 1-9. - return "iJ", lnum + (dir == ">" and 246 or 0) - end - - local extname = match(expr, "^extern%s+(%S+)$") - if extname then - return "iJ", map_extern[extname] - end - - -- expr (interpreted as immediate) - return "iI", expr -end - --- Parse displacement expression: +-num, +-expr, +-opsize*num -local function dispexpr(expr) - local disp = expr == "" and 0 or toint(expr) - if disp then return disp end - local c, dispt = match(expr, "^([+-])%s*(.+)$") - if c == "+" then - expr = dispt - elseif not c then - werror("bad displacement expression `"..expr.."'") - end - local opsize, tailops = match(dispt, "^(%w+)%s*%*%s*(.+)$") - local ops, imm = map_opsize[opsize], toint(tailops) - if ops and imm then - if c == "-" then imm = -imm end - return imm*map_opsizenum[ops] - end - local mode, iexpr = immexpr(dispt) - if mode == "iJ" then - if c == "-" then werror("cannot invert label reference") end - return { iexpr } - end - return expr -- Need to return original signed expression. -end - --- Parse register or type expression. -local function rtexpr(expr) - if not expr then return end - local tname, ovreg = match(expr, "^([%w_]+):(@[%w_]+)$") - local tp = map_type[tname or expr] - if tp then - local reg = ovreg or tp.reg - local rnum = map_reg_num[reg] - if not rnum then - werror("type `"..(tname or expr).."' needs a register override") - end - if not map_reg_valid_base[reg] then - werror("bad base register override `"..(map_reg_rev[reg] or reg).."'") - end - return reg, rnum, tp - end - return expr, map_reg_num[expr] -end - --- Parse operand and return { mode, opsize, reg, xreg, xsc, disp, imm }. -local function parseoperand(param, isqword) - local t = {} - - local expr = param - local opsize, tailops = match(param, "^(%w+)%s*(.+)$") - if opsize then - t.opsize = map_opsize[opsize] - if t.opsize then expr = tailops end - end - - local br = match(expr, "^%[%s*(.-)%s*%]$") - repeat - if br then - t.mode = "xm" - - -- [disp] - t.disp = toint(br) - if t.disp then - t.mode = x64 and "xm" or "xmO" - break - end - - -- [reg...] - local tp - local reg, tailr = match(br, "^([@%w_:]+)%s*(.*)$") - reg, t.reg, tp = rtexpr(reg) - if not t.reg then - -- [expr] - t.mode = x64 and "xm" or "xmO" - t.disp = dispexpr("+"..br) - break - end - - if t.reg == -1 then - t.vreg, tailr = match(tailr, "^(%b())(.*)$") - if not t.vreg then werror("bad variable register expression") end - end - - -- [xreg*xsc] or [xreg*xsc+-disp] or [xreg*xsc+-expr] - local xsc, tailsc = match(tailr, "^%*%s*([1248])%s*(.*)$") - if xsc then - if not map_reg_valid_index[reg] then - werror("bad index register `"..map_reg_rev[reg].."'") - end - t.xsc = map_xsc[xsc] - t.xreg = t.reg - t.vxreg = t.vreg - t.reg = nil - t.vreg = nil - t.disp = dispexpr(tailsc) - break - end - if not map_reg_valid_base[reg] then - werror("bad base register `"..map_reg_rev[reg].."'") - end - - -- [reg] or [reg+-disp] - t.disp = toint(tailr) or (tailr == "" and 0) - if t.disp then break end - - -- [reg+xreg...] - local xreg, tailx = match(tailr, "^%+%s*([@%w_:]+)%s*(.*)$") - xreg, t.xreg, tp = rtexpr(xreg) - if not t.xreg then - -- [reg+-expr] - t.disp = dispexpr(tailr) - break - end - if not map_reg_valid_index[xreg] then - werror("bad index register `"..map_reg_rev[xreg].."'") - end - - if t.xreg == -1 then - t.vxreg, tailx = match(tailx, "^(%b())(.*)$") - if not t.vxreg then werror("bad variable register expression") end - end - - -- [reg+xreg*xsc...] - local xsc, tailsc = match(tailx, "^%*%s*([1248])%s*(.*)$") - if xsc then - t.xsc = map_xsc[xsc] - tailx = tailsc - end - - -- [...] or [...+-disp] or [...+-expr] - t.disp = dispexpr(tailx) - else - -- imm or opsize*imm - local imm = toint(expr, isqword) - if not imm and sub(expr, 1, 1) == "*" and t.opsize then - imm = toint(sub(expr, 2)) - if imm then - imm = imm * map_opsizenum[t.opsize] - t.opsize = nil - end - end - if imm then - if t.opsize then werror("bad operand size override") end - local m = "i" - if imm == 1 then m = m.."1" end - if imm >= 4294967168 and imm <= 4294967295 then imm = imm-4294967296 end - if imm >= -128 and imm <= 127 then m = m.."S" end - t.imm = imm - t.mode = m - break - end - - local tp - local reg, tailr = match(expr, "^([@%w_:]+)%s*(.*)$") - reg, t.reg, tp = rtexpr(reg) - if t.reg then - if t.reg == -1 then - t.vreg, tailr = match(tailr, "^(%b())(.*)$") - if not t.vreg then werror("bad variable register expression") end - end - -- reg - if tailr == "" then - if t.opsize then werror("bad operand size override") end - t.opsize = map_reg_opsize[reg] - if t.opsize == "f" then - t.mode = t.reg == 0 and "fF" or "f" - else - if reg == "@w4" or (x64 and reg == "@d4") then - wwarn("bad idea, try again with `"..(x64 and "rsp'" or "esp'")) - end - t.mode = t.reg == 0 and "rmR" or (reg == "@b1" and "rmC" or "rm") - end - t.needrex = map_reg_needrex[reg] - break - end - - -- type[idx], type[idx].field, type->field -> [reg+offset_expr] - if not tp then werror("bad operand `"..param.."'") end - t.mode = "xm" - t.disp = format(tp.ctypefmt, tailr) - else - t.mode, t.imm = immexpr(expr) - if sub(t.mode, -1) == "J" then - if t.opsize and t.opsize ~= addrsize then - werror("bad operand size override") - end - t.opsize = addrsize - end - end - end - until true - return t -end - ------------------------------------------------------------------------------- --- x86 Template String Description --- =============================== --- --- Each template string is a list of [match:]pattern pairs, --- separated by "|". The first match wins. No match means a --- bad or unsupported combination of operand modes or sizes. --- --- The match part and the ":" is omitted if the operation has --- no operands. Otherwise the first N characters are matched --- against the mode strings of each of the N operands. --- --- The mode string for each operand type is (see parseoperand()): --- Integer register: "rm", +"R" for eax, ax, al, +"C" for cl --- FP register: "f", +"F" for st0 --- Index operand: "xm", +"O" for [disp] (pure offset) --- Immediate: "i", +"S" for signed 8 bit, +"1" for 1, --- +"I" for arg, +"P" for pointer --- Any: +"J" for valid jump targets --- --- So a match character "m" (mixed) matches both an integer register --- and an index operand (to be encoded with the ModRM/SIB scheme). --- But "r" matches only a register and "x" only an index operand --- (e.g. for FP memory access operations). --- --- The operand size match string starts right after the mode match --- characters and ends before the ":". "dwb" or "qdwb" is assumed, if empty. --- The effective data size of the operation is matched against this list. --- --- If only the regular "b", "w", "d", "q", "t" operand sizes are --- present, then all operands must be the same size. Unspecified sizes --- are ignored, but at least one operand must have a size or the pattern --- won't match (use the "byte", "word", "dword", "qword", "tword" --- operand size overrides. E.g.: mov dword [eax], 1). --- --- If the list has a "1" or "2" prefix, the operand size is taken --- from the respective operand and any other operand sizes are ignored. --- If the list contains only ".", all operand sizes are ignored. --- If the list has a "/" prefix, the concatenated (mixed) operand sizes --- are compared to the match. --- --- E.g. "rrdw" matches for either two dword registers or two word --- registers. "Fx2dq" matches an st0 operand plus an index operand --- pointing to a dword (float) or qword (double). --- --- Every character after the ":" is part of the pattern string: --- Hex chars are accumulated to form the opcode (left to right). --- "n" disables the standard opcode mods --- (otherwise: -1 for "b", o16 prefix for "w", rex.w for "q") --- "X" Force REX.W. --- "r"/"R" adds the reg. number from the 1st/2nd operand to the opcode. --- "m"/"M" generates ModRM/SIB from the 1st/2nd operand. --- The spare 3 bits are either filled with the last hex digit or --- the result from a previous "r"/"R". The opcode is restored. --- "u" Use VEX encoding, vvvv unused. --- "v"/"V" Use VEX encoding, vvvv from 1st/2nd operand (the operand is --- removed from the list used by future characters). --- "w" Use VEX encoding, vvvv from 3rd operand. --- "L" Force VEX.L --- --- All of the following characters force a flush of the opcode: --- "o"/"O" stores a pure 32 bit disp (offset) from the 1st/2nd operand. --- "s" stores a 4 bit immediate from the last register operand, --- followed by 4 zero bits. --- "S" stores a signed 8 bit immediate from the last operand. --- "U" stores an unsigned 8 bit immediate from the last operand. --- "W" stores an unsigned 16 bit immediate from the last operand. --- "i" stores an operand sized immediate from the last operand. --- "I" dito, but generates an action code to optionally modify --- the opcode (+2) for a signed 8 bit immediate. --- "J" generates one of the REL action codes from the last operand. --- ------------------------------------------------------------------------------- - --- Template strings for x86 instructions. Ordered by first opcode byte. --- Unimplemented opcodes (deliberate omissions) are marked with *. -local map_op = { - -- 00-05: add... - -- 06: *push es - -- 07: *pop es - -- 08-0D: or... - -- 0E: *push cs - -- 0F: two byte opcode prefix - -- 10-15: adc... - -- 16: *push ss - -- 17: *pop ss - -- 18-1D: sbb... - -- 1E: *push ds - -- 1F: *pop ds - -- 20-25: and... - es_0 = "26", - -- 27: *daa - -- 28-2D: sub... - cs_0 = "2E", - -- 2F: *das - -- 30-35: xor... - ss_0 = "36", - -- 37: *aaa - -- 38-3D: cmp... - ds_0 = "3E", - -- 3F: *aas - inc_1 = x64 and "m:FF0m" or "rdw:40r|m:FF0m", - dec_1 = x64 and "m:FF1m" or "rdw:48r|m:FF1m", - push_1 = (x64 and "rq:n50r|rw:50r|mq:nFF6m|mw:FF6m" or - "rdw:50r|mdw:FF6m").."|S.:6AS|ib:n6Ai|i.:68i", - pop_1 = x64 and "rq:n58r|rw:58r|mq:n8F0m|mw:8F0m" or "rdw:58r|mdw:8F0m", - -- 60: *pusha, *pushad, *pushaw - -- 61: *popa, *popad, *popaw - -- 62: *bound rdw,x - -- 63: x86: *arpl mw,rw - movsxd_2 = x64 and "rm/qd:63rM", - fs_0 = "64", - gs_0 = "65", - o16_0 = "66", - a16_0 = not x64 and "67" or nil, - a32_0 = x64 and "67", - -- 68: push idw - -- 69: imul rdw,mdw,idw - -- 6A: push ib - -- 6B: imul rdw,mdw,S - -- 6C: *insb - -- 6D: *insd, *insw - -- 6E: *outsb - -- 6F: *outsd, *outsw - -- 70-7F: jcc lb - -- 80: add... mb,i - -- 81: add... mdw,i - -- 82: *undefined - -- 83: add... mdw,S - test_2 = "mr:85Rm|rm:85rM|Ri:A9ri|mi:F70mi", - -- 86: xchg rb,mb - -- 87: xchg rdw,mdw - -- 88: mov mb,r - -- 89: mov mdw,r - -- 8A: mov r,mb - -- 8B: mov r,mdw - -- 8C: *mov mdw,seg - lea_2 = "rx1dq:8DrM", - -- 8E: *mov seg,mdw - -- 8F: pop mdw - nop_0 = "90", - xchg_2 = "Rrqdw:90R|rRqdw:90r|rm:87rM|mr:87Rm", - cbw_0 = "6698", - cwde_0 = "98", - cdqe_0 = "4898", - cwd_0 = "6699", - cdq_0 = "99", - cqo_0 = "4899", - -- 9A: *call iw:idw - wait_0 = "9B", - fwait_0 = "9B", - pushf_0 = "9C", - pushfd_0 = not x64 and "9C", - pushfq_0 = x64 and "9C", - popf_0 = "9D", - popfd_0 = not x64 and "9D", - popfq_0 = x64 and "9D", - sahf_0 = "9E", - lahf_0 = "9F", - mov_2 = "OR:A3o|RO:A1O|mr:89Rm|rm:8BrM|rib:nB0ri|ridw:B8ri|mi:C70mi", - movsb_0 = "A4", - movsw_0 = "66A5", - movsd_0 = "A5", - cmpsb_0 = "A6", - cmpsw_0 = "66A7", - cmpsd_0 = "A7", - -- A8: test Rb,i - -- A9: test Rdw,i - stosb_0 = "AA", - stosw_0 = "66AB", - stosd_0 = "AB", - lodsb_0 = "AC", - lodsw_0 = "66AD", - lodsd_0 = "AD", - scasb_0 = "AE", - scasw_0 = "66AF", - scasd_0 = "AF", - -- B0-B7: mov rb,i - -- B8-BF: mov rdw,i - -- C0: rol... mb,i - -- C1: rol... mdw,i - ret_1 = "i.:nC2W", - ret_0 = "C3", - -- C4: *les rdw,mq - -- C5: *lds rdw,mq - -- C6: mov mb,i - -- C7: mov mdw,i - -- C8: *enter iw,ib - leave_0 = "C9", - -- CA: *retf iw - -- CB: *retf - int3_0 = "CC", - int_1 = "i.:nCDU", - into_0 = "CE", - -- CF: *iret - -- D0: rol... mb,1 - -- D1: rol... mdw,1 - -- D2: rol... mb,cl - -- D3: rol... mb,cl - -- D4: *aam ib - -- D5: *aad ib - -- D6: *salc - -- D7: *xlat - -- D8-DF: floating point ops - -- E0: *loopne - -- E1: *loope - -- E2: *loop - -- E3: *jcxz, *jecxz - -- E4: *in Rb,ib - -- E5: *in Rdw,ib - -- E6: *out ib,Rb - -- E7: *out ib,Rdw - call_1 = x64 and "mq:nFF2m|J.:E8nJ" or "md:FF2m|J.:E8J", - jmp_1 = x64 and "mq:nFF4m|J.:E9nJ" or "md:FF4m|J.:E9J", -- short: EB - -- EA: *jmp iw:idw - -- EB: jmp ib - -- EC: *in Rb,dx - -- ED: *in Rdw,dx - -- EE: *out dx,Rb - -- EF: *out dx,Rdw - lock_0 = "F0", - int1_0 = "F1", - repne_0 = "F2", - repnz_0 = "F2", - rep_0 = "F3", - repe_0 = "F3", - repz_0 = "F3", - endbr32_0 = "F30F1EFB", - endbr64_0 = "F30F1EFA", - -- F4: *hlt - cmc_0 = "F5", - -- F6: test... mb,i; div... mb - -- F7: test... mdw,i; div... mdw - clc_0 = "F8", - stc_0 = "F9", - -- FA: *cli - cld_0 = "FC", - std_0 = "FD", - -- FE: inc... mb - -- FF: inc... mdw - - -- misc ops - not_1 = "m:F72m", - neg_1 = "m:F73m", - mul_1 = "m:F74m", - imul_1 = "m:F75m", - div_1 = "m:F76m", - idiv_1 = "m:F77m", - - imul_2 = "rmqdw:0FAFrM|rIqdw:69rmI|rSqdw:6BrmS|riqdw:69rmi", - imul_3 = "rmIqdw:69rMI|rmSqdw:6BrMS|rmiqdw:69rMi", - - movzx_2 = "rm/db:0FB6rM|rm/qb:|rm/wb:0FB6rM|rm/dw:0FB7rM|rm/qw:", - movsx_2 = "rm/db:0FBErM|rm/qb:|rm/wb:0FBErM|rm/dw:0FBFrM|rm/qw:", - - bswap_1 = "rqd:0FC8r", - bsf_2 = "rmqdw:0FBCrM", - bsr_2 = "rmqdw:0FBDrM", - bt_2 = "mrqdw:0FA3Rm|miqdw:0FBA4mU", - btc_2 = "mrqdw:0FBBRm|miqdw:0FBA7mU", - btr_2 = "mrqdw:0FB3Rm|miqdw:0FBA6mU", - bts_2 = "mrqdw:0FABRm|miqdw:0FBA5mU", - - shld_3 = "mriqdw:0FA4RmU|mrC/qq:0FA5Rm|mrC/dd:|mrC/ww:", - shrd_3 = "mriqdw:0FACRmU|mrC/qq:0FADRm|mrC/dd:|mrC/ww:", - - rdtsc_0 = "0F31", -- P1+ - rdpmc_0 = "0F33", -- P6+ - cpuid_0 = "0FA2", -- P1+ - - -- floating point ops - fst_1 = "ff:DDD0r|xd:D92m|xq:nDD2m", - fstp_1 = "ff:DDD8r|xd:D93m|xq:nDD3m|xt:DB7m", - fld_1 = "ff:D9C0r|xd:D90m|xq:nDD0m|xt:DB5m", - - fpop_0 = "DDD8", -- Alias for fstp st0. - - fist_1 = "xw:nDF2m|xd:DB2m", - fistp_1 = "xw:nDF3m|xd:DB3m|xq:nDF7m", - fild_1 = "xw:nDF0m|xd:DB0m|xq:nDF5m", - - fxch_0 = "D9C9", - fxch_1 = "ff:D9C8r", - fxch_2 = "fFf:D9C8r|Fff:D9C8R", - - fucom_1 = "ff:DDE0r", - fucom_2 = "Fff:DDE0R", - fucomp_1 = "ff:DDE8r", - fucomp_2 = "Fff:DDE8R", - fucomi_1 = "ff:DBE8r", -- P6+ - fucomi_2 = "Fff:DBE8R", -- P6+ - fucomip_1 = "ff:DFE8r", -- P6+ - fucomip_2 = "Fff:DFE8R", -- P6+ - fcomi_1 = "ff:DBF0r", -- P6+ - fcomi_2 = "Fff:DBF0R", -- P6+ - fcomip_1 = "ff:DFF0r", -- P6+ - fcomip_2 = "Fff:DFF0R", -- P6+ - fucompp_0 = "DAE9", - fcompp_0 = "DED9", - - fldenv_1 = "x.:D94m", - fnstenv_1 = "x.:D96m", - fstenv_1 = "x.:9BD96m", - fldcw_1 = "xw:nD95m", - fstcw_1 = "xw:n9BD97m", - fnstcw_1 = "xw:nD97m", - fstsw_1 = "Rw:n9BDFE0|xw:n9BDD7m", - fnstsw_1 = "Rw:nDFE0|xw:nDD7m", - fclex_0 = "9BDBE2", - fnclex_0 = "DBE2", - - fnop_0 = "D9D0", - -- D9D1-D9DF: unassigned - - fchs_0 = "D9E0", - fabs_0 = "D9E1", - -- D9E2: unassigned - -- D9E3: unassigned - ftst_0 = "D9E4", - fxam_0 = "D9E5", - -- D9E6: unassigned - -- D9E7: unassigned - fld1_0 = "D9E8", - fldl2t_0 = "D9E9", - fldl2e_0 = "D9EA", - fldpi_0 = "D9EB", - fldlg2_0 = "D9EC", - fldln2_0 = "D9ED", - fldz_0 = "D9EE", - -- D9EF: unassigned - - f2xm1_0 = "D9F0", - fyl2x_0 = "D9F1", - fptan_0 = "D9F2", - fpatan_0 = "D9F3", - fxtract_0 = "D9F4", - fprem1_0 = "D9F5", - fdecstp_0 = "D9F6", - fincstp_0 = "D9F7", - fprem_0 = "D9F8", - fyl2xp1_0 = "D9F9", - fsqrt_0 = "D9FA", - fsincos_0 = "D9FB", - frndint_0 = "D9FC", - fscale_0 = "D9FD", - fsin_0 = "D9FE", - fcos_0 = "D9FF", - - -- SSE, SSE2 - andnpd_2 = "rmo:660F55rM", - andnps_2 = "rmo:0F55rM", - andpd_2 = "rmo:660F54rM", - andps_2 = "rmo:0F54rM", - clflush_1 = "x.:0FAE7m", - cmppd_3 = "rmio:660FC2rMU", - cmpps_3 = "rmio:0FC2rMU", - cmpsd_3 = "rrio:F20FC2rMU|rxi/oq:", - cmpss_3 = "rrio:F30FC2rMU|rxi/od:", - comisd_2 = "rro:660F2FrM|rx/oq:", - comiss_2 = "rro:0F2FrM|rx/od:", - cvtdq2pd_2 = "rro:F30FE6rM|rx/oq:", - cvtdq2ps_2 = "rmo:0F5BrM", - cvtpd2dq_2 = "rmo:F20FE6rM", - cvtpd2ps_2 = "rmo:660F5ArM", - cvtpi2pd_2 = "rx/oq:660F2ArM", - cvtpi2ps_2 = "rx/oq:0F2ArM", - cvtps2dq_2 = "rmo:660F5BrM", - cvtps2pd_2 = "rro:0F5ArM|rx/oq:", - cvtsd2si_2 = "rr/do:F20F2DrM|rr/qo:|rx/dq:|rxq:", - cvtsd2ss_2 = "rro:F20F5ArM|rx/oq:", - cvtsi2sd_2 = "rm/od:F20F2ArM|rm/oq:F20F2ArXM", - cvtsi2ss_2 = "rm/od:F30F2ArM|rm/oq:F30F2ArXM", - cvtss2sd_2 = "rro:F30F5ArM|rx/od:", - cvtss2si_2 = "rr/do:F30F2DrM|rr/qo:|rxd:|rx/qd:", - cvttpd2dq_2 = "rmo:660FE6rM", - cvttps2dq_2 = "rmo:F30F5BrM", - cvttsd2si_2 = "rr/do:F20F2CrM|rr/qo:|rx/dq:|rxq:", - cvttss2si_2 = "rr/do:F30F2CrM|rr/qo:|rxd:|rx/qd:", - fxsave_1 = "x.:0FAE0m", - fxrstor_1 = "x.:0FAE1m", - ldmxcsr_1 = "xd:0FAE2m", - lfence_0 = "0FAEE8", - maskmovdqu_2 = "rro:660FF7rM", - mfence_0 = "0FAEF0", - movapd_2 = "rmo:660F28rM|mro:660F29Rm", - movaps_2 = "rmo:0F28rM|mro:0F29Rm", - movd_2 = "rm/od:660F6ErM|rm/oq:660F6ErXM|mr/do:660F7ERm|mr/qo:", - movdqa_2 = "rmo:660F6FrM|mro:660F7FRm", - movdqu_2 = "rmo:F30F6FrM|mro:F30F7FRm", - movhlps_2 = "rro:0F12rM", - movhpd_2 = "rx/oq:660F16rM|xr/qo:n660F17Rm", - movhps_2 = "rx/oq:0F16rM|xr/qo:n0F17Rm", - movlhps_2 = "rro:0F16rM", - movlpd_2 = "rx/oq:660F12rM|xr/qo:n660F13Rm", - movlps_2 = "rx/oq:0F12rM|xr/qo:n0F13Rm", - movmskpd_2 = "rr/do:660F50rM", - movmskps_2 = "rr/do:0F50rM", - movntdq_2 = "xro:660FE7Rm", - movnti_2 = "xrqd:0FC3Rm", - movntpd_2 = "xro:660F2BRm", - movntps_2 = "xro:0F2BRm", - movq_2 = "rro:F30F7ErM|rx/oq:|xr/qo:n660FD6Rm", - movsd_2 = "rro:F20F10rM|rx/oq:|xr/qo:nF20F11Rm", - movss_2 = "rro:F30F10rM|rx/od:|xr/do:F30F11Rm", - movupd_2 = "rmo:660F10rM|mro:660F11Rm", - movups_2 = "rmo:0F10rM|mro:0F11Rm", - orpd_2 = "rmo:660F56rM", - orps_2 = "rmo:0F56rM", - pause_0 = "F390", - pextrw_3 = "rri/do:660FC5rMU|xri/wo:660F3A15nRmU", -- Mem op: SSE4.1 only. - pinsrw_3 = "rri/od:660FC4rMU|rxi/ow:", - pmovmskb_2 = "rr/do:660FD7rM", - prefetchnta_1 = "xb:n0F180m", - prefetcht0_1 = "xb:n0F181m", - prefetcht1_1 = "xb:n0F182m", - prefetcht2_1 = "xb:n0F183m", - pshufd_3 = "rmio:660F70rMU", - pshufhw_3 = "rmio:F30F70rMU", - pshuflw_3 = "rmio:F20F70rMU", - pslld_2 = "rmo:660FF2rM|rio:660F726mU", - pslldq_2 = "rio:660F737mU", - psllq_2 = "rmo:660FF3rM|rio:660F736mU", - psllw_2 = "rmo:660FF1rM|rio:660F716mU", - psrad_2 = "rmo:660FE2rM|rio:660F724mU", - psraw_2 = "rmo:660FE1rM|rio:660F714mU", - psrld_2 = "rmo:660FD2rM|rio:660F722mU", - psrldq_2 = "rio:660F733mU", - psrlq_2 = "rmo:660FD3rM|rio:660F732mU", - psrlw_2 = "rmo:660FD1rM|rio:660F712mU", - rcpps_2 = "rmo:0F53rM", - rcpss_2 = "rro:F30F53rM|rx/od:", - rsqrtps_2 = "rmo:0F52rM", - rsqrtss_2 = "rmo:F30F52rM", - sfence_0 = "0FAEF8", - shufpd_3 = "rmio:660FC6rMU", - shufps_3 = "rmio:0FC6rMU", - stmxcsr_1 = "xd:0FAE3m", - ucomisd_2 = "rro:660F2ErM|rx/oq:", - ucomiss_2 = "rro:0F2ErM|rx/od:", - unpckhpd_2 = "rmo:660F15rM", - unpckhps_2 = "rmo:0F15rM", - unpcklpd_2 = "rmo:660F14rM", - unpcklps_2 = "rmo:0F14rM", - xorpd_2 = "rmo:660F57rM", - xorps_2 = "rmo:0F57rM", - - -- SSE3 ops - fisttp_1 = "xw:nDF1m|xd:DB1m|xq:nDD1m", - addsubpd_2 = "rmo:660FD0rM", - addsubps_2 = "rmo:F20FD0rM", - haddpd_2 = "rmo:660F7CrM", - haddps_2 = "rmo:F20F7CrM", - hsubpd_2 = "rmo:660F7DrM", - hsubps_2 = "rmo:F20F7DrM", - lddqu_2 = "rxo:F20FF0rM", - movddup_2 = "rmo:F20F12rM", - movshdup_2 = "rmo:F30F16rM", - movsldup_2 = "rmo:F30F12rM", - - -- SSSE3 ops - pabsb_2 = "rmo:660F381CrM", - pabsd_2 = "rmo:660F381ErM", - pabsw_2 = "rmo:660F381DrM", - palignr_3 = "rmio:660F3A0FrMU", - phaddd_2 = "rmo:660F3802rM", - phaddsw_2 = "rmo:660F3803rM", - phaddw_2 = "rmo:660F3801rM", - phsubd_2 = "rmo:660F3806rM", - phsubsw_2 = "rmo:660F3807rM", - phsubw_2 = "rmo:660F3805rM", - pmaddubsw_2 = "rmo:660F3804rM", - pmulhrsw_2 = "rmo:660F380BrM", - pshufb_2 = "rmo:660F3800rM", - psignb_2 = "rmo:660F3808rM", - psignd_2 = "rmo:660F380ArM", - psignw_2 = "rmo:660F3809rM", - - -- SSE4.1 ops - blendpd_3 = "rmio:660F3A0DrMU", - blendps_3 = "rmio:660F3A0CrMU", - blendvpd_3 = "rmRo:660F3815rM", - blendvps_3 = "rmRo:660F3814rM", - dppd_3 = "rmio:660F3A41rMU", - dpps_3 = "rmio:660F3A40rMU", - extractps_3 = "mri/do:660F3A17RmU|rri/qo:660F3A17RXmU", - insertps_3 = "rrio:660F3A41rMU|rxi/od:", - movntdqa_2 = "rxo:660F382ArM", - mpsadbw_3 = "rmio:660F3A42rMU", - packusdw_2 = "rmo:660F382BrM", - pblendvb_3 = "rmRo:660F3810rM", - pblendw_3 = "rmio:660F3A0ErMU", - pcmpeqq_2 = "rmo:660F3829rM", - pextrb_3 = "rri/do:660F3A14nRmU|rri/qo:|xri/bo:", - pextrd_3 = "mri/do:660F3A16RmU", - pextrq_3 = "mri/qo:660F3A16RmU", - -- pextrw is SSE2, mem operand is SSE4.1 only - phminposuw_2 = "rmo:660F3841rM", - pinsrb_3 = "rri/od:660F3A20nrMU|rxi/ob:", - pinsrd_3 = "rmi/od:660F3A22rMU", - pinsrq_3 = "rmi/oq:660F3A22rXMU", - pmaxsb_2 = "rmo:660F383CrM", - pmaxsd_2 = "rmo:660F383DrM", - pmaxud_2 = "rmo:660F383FrM", - pmaxuw_2 = "rmo:660F383ErM", - pminsb_2 = "rmo:660F3838rM", - pminsd_2 = "rmo:660F3839rM", - pminud_2 = "rmo:660F383BrM", - pminuw_2 = "rmo:660F383ArM", - pmovsxbd_2 = "rro:660F3821rM|rx/od:", - pmovsxbq_2 = "rro:660F3822rM|rx/ow:", - pmovsxbw_2 = "rro:660F3820rM|rx/oq:", - pmovsxdq_2 = "rro:660F3825rM|rx/oq:", - pmovsxwd_2 = "rro:660F3823rM|rx/oq:", - pmovsxwq_2 = "rro:660F3824rM|rx/od:", - pmovzxbd_2 = "rro:660F3831rM|rx/od:", - pmovzxbq_2 = "rro:660F3832rM|rx/ow:", - pmovzxbw_2 = "rro:660F3830rM|rx/oq:", - pmovzxdq_2 = "rro:660F3835rM|rx/oq:", - pmovzxwd_2 = "rro:660F3833rM|rx/oq:", - pmovzxwq_2 = "rro:660F3834rM|rx/od:", - pmuldq_2 = "rmo:660F3828rM", - pmulld_2 = "rmo:660F3840rM", - ptest_2 = "rmo:660F3817rM", - roundpd_3 = "rmio:660F3A09rMU", - roundps_3 = "rmio:660F3A08rMU", - roundsd_3 = "rrio:660F3A0BrMU|rxi/oq:", - roundss_3 = "rrio:660F3A0ArMU|rxi/od:", - - -- SSE4.2 ops - crc32_2 = "rmqd:F20F38F1rM|rm/dw:66F20F38F1rM|rm/db:F20F38F0rM|rm/qb:", - pcmpestri_3 = "rmio:660F3A61rMU", - pcmpestrm_3 = "rmio:660F3A60rMU", - pcmpgtq_2 = "rmo:660F3837rM", - pcmpistri_3 = "rmio:660F3A63rMU", - pcmpistrm_3 = "rmio:660F3A62rMU", - popcnt_2 = "rmqdw:F30FB8rM", - - -- SSE4a - extrq_2 = "rro:660F79rM", - extrq_3 = "riio:660F780mUU", - insertq_2 = "rro:F20F79rM", - insertq_4 = "rriio:F20F78rMUU", - lzcnt_2 = "rmqdw:F30FBDrM", - movntsd_2 = "xr/qo:nF20F2BRm", - movntss_2 = "xr/do:F30F2BRm", - -- popcnt is also in SSE4.2 - - -- AES-NI - aesdec_2 = "rmo:660F38DErM", - aesdeclast_2 = "rmo:660F38DFrM", - aesenc_2 = "rmo:660F38DCrM", - aesenclast_2 = "rmo:660F38DDrM", - aesimc_2 = "rmo:660F38DBrM", - aeskeygenassist_3 = "rmio:660F3ADFrMU", - pclmulqdq_3 = "rmio:660F3A44rMU", - - -- AVX FP ops - vaddsubpd_3 = "rrmoy:660FVD0rM", - vaddsubps_3 = "rrmoy:F20FVD0rM", - vandpd_3 = "rrmoy:660FV54rM", - vandps_3 = "rrmoy:0FV54rM", - vandnpd_3 = "rrmoy:660FV55rM", - vandnps_3 = "rrmoy:0FV55rM", - vblendpd_4 = "rrmioy:660F3AV0DrMU", - vblendps_4 = "rrmioy:660F3AV0CrMU", - vblendvpd_4 = "rrmroy:660F3AV4BrMs", - vblendvps_4 = "rrmroy:660F3AV4ArMs", - vbroadcastf128_2 = "rx/yo:660F38u1ArM", - vcmppd_4 = "rrmioy:660FVC2rMU", - vcmpps_4 = "rrmioy:0FVC2rMU", - vcmpsd_4 = "rrrio:F20FVC2rMU|rrxi/ooq:", - vcmpss_4 = "rrrio:F30FVC2rMU|rrxi/ood:", - vcomisd_2 = "rro:660Fu2FrM|rx/oq:", - vcomiss_2 = "rro:0Fu2FrM|rx/od:", - vcvtdq2pd_2 = "rro:F30FuE6rM|rx/oq:|rm/yo:", - vcvtdq2ps_2 = "rmoy:0Fu5BrM", - vcvtpd2dq_2 = "rmoy:F20FuE6rM", - vcvtpd2ps_2 = "rmoy:660Fu5ArM", - vcvtps2dq_2 = "rmoy:660Fu5BrM", - vcvtps2pd_2 = "rro:0Fu5ArM|rx/oq:|rm/yo:", - vcvtsd2si_2 = "rr/do:F20Fu2DrM|rx/dq:|rr/qo:|rxq:", - vcvtsd2ss_3 = "rrro:F20FV5ArM|rrx/ooq:", - vcvtsi2sd_3 = "rrm/ood:F20FV2ArM|rrm/ooq:F20FVX2ArM", - vcvtsi2ss_3 = "rrm/ood:F30FV2ArM|rrm/ooq:F30FVX2ArM", - vcvtss2sd_3 = "rrro:F30FV5ArM|rrx/ood:", - vcvtss2si_2 = "rr/do:F30Fu2DrM|rxd:|rr/qo:|rx/qd:", - vcvttpd2dq_2 = "rmo:660FuE6rM|rm/oy:660FuLE6rM", - vcvttps2dq_2 = "rmoy:F30Fu5BrM", - vcvttsd2si_2 = "rr/do:F20Fu2CrM|rx/dq:|rr/qo:|rxq:", - vcvttss2si_2 = "rr/do:F30Fu2CrM|rxd:|rr/qo:|rx/qd:", - vdppd_4 = "rrmio:660F3AV41rMU", - vdpps_4 = "rrmioy:660F3AV40rMU", - vextractf128_3 = "mri/oy:660F3AuL19RmU", - vextractps_3 = "mri/do:660F3Au17RmU", - vhaddpd_3 = "rrmoy:660FV7CrM", - vhaddps_3 = "rrmoy:F20FV7CrM", - vhsubpd_3 = "rrmoy:660FV7DrM", - vhsubps_3 = "rrmoy:F20FV7DrM", - vinsertf128_4 = "rrmi/yyo:660F3AV18rMU", - vinsertps_4 = "rrrio:660F3AV21rMU|rrxi/ood:", - vldmxcsr_1 = "xd:0FuAE2m", - vmaskmovps_3 = "rrxoy:660F38V2CrM|xrroy:660F38V2ERm", - vmaskmovpd_3 = "rrxoy:660F38V2DrM|xrroy:660F38V2FRm", - vmovapd_2 = "rmoy:660Fu28rM|mroy:660Fu29Rm", - vmovaps_2 = "rmoy:0Fu28rM|mroy:0Fu29Rm", - vmovd_2 = "rm/od:660Fu6ErM|rm/oq:660FuX6ErM|mr/do:660Fu7ERm|mr/qo:", - vmovq_2 = "rro:F30Fu7ErM|rx/oq:|xr/qo:660FuD6Rm", - vmovddup_2 = "rmy:F20Fu12rM|rro:|rx/oq:", - vmovhlps_3 = "rrro:0FV12rM", - vmovhpd_2 = "xr/qo:660Fu17Rm", - vmovhpd_3 = "rrx/ooq:660FV16rM", - vmovhps_2 = "xr/qo:0Fu17Rm", - vmovhps_3 = "rrx/ooq:0FV16rM", - vmovlhps_3 = "rrro:0FV16rM", - vmovlpd_2 = "xr/qo:660Fu13Rm", - vmovlpd_3 = "rrx/ooq:660FV12rM", - vmovlps_2 = "xr/qo:0Fu13Rm", - vmovlps_3 = "rrx/ooq:0FV12rM", - vmovmskpd_2 = "rr/do:660Fu50rM|rr/dy:660FuL50rM", - vmovmskps_2 = "rr/do:0Fu50rM|rr/dy:0FuL50rM", - vmovntpd_2 = "xroy:660Fu2BRm", - vmovntps_2 = "xroy:0Fu2BRm", - vmovsd_2 = "rx/oq:F20Fu10rM|xr/qo:F20Fu11Rm", - vmovsd_3 = "rrro:F20FV10rM", - vmovshdup_2 = "rmoy:F30Fu16rM", - vmovsldup_2 = "rmoy:F30Fu12rM", - vmovss_2 = "rx/od:F30Fu10rM|xr/do:F30Fu11Rm", - vmovss_3 = "rrro:F30FV10rM", - vmovupd_2 = "rmoy:660Fu10rM|mroy:660Fu11Rm", - vmovups_2 = "rmoy:0Fu10rM|mroy:0Fu11Rm", - vorpd_3 = "rrmoy:660FV56rM", - vorps_3 = "rrmoy:0FV56rM", - vpermilpd_3 = "rrmoy:660F38V0DrM|rmioy:660F3Au05rMU", - vpermilps_3 = "rrmoy:660F38V0CrM|rmioy:660F3Au04rMU", - vperm2f128_4 = "rrmiy:660F3AV06rMU", - vptestpd_2 = "rmoy:660F38u0FrM", - vptestps_2 = "rmoy:660F38u0ErM", - vrcpps_2 = "rmoy:0Fu53rM", - vrcpss_3 = "rrro:F30FV53rM|rrx/ood:", - vrsqrtps_2 = "rmoy:0Fu52rM", - vrsqrtss_3 = "rrro:F30FV52rM|rrx/ood:", - vroundpd_3 = "rmioy:660F3Au09rMU", - vroundps_3 = "rmioy:660F3Au08rMU", - vroundsd_4 = "rrrio:660F3AV0BrMU|rrxi/ooq:", - vroundss_4 = "rrrio:660F3AV0ArMU|rrxi/ood:", - vshufpd_4 = "rrmioy:660FVC6rMU", - vshufps_4 = "rrmioy:0FVC6rMU", - vsqrtps_2 = "rmoy:0Fu51rM", - vsqrtss_2 = "rro:F30Fu51rM|rx/od:", - vsqrtpd_2 = "rmoy:660Fu51rM", - vsqrtsd_2 = "rro:F20Fu51rM|rx/oq:", - vstmxcsr_1 = "xd:0FuAE3m", - vucomisd_2 = "rro:660Fu2ErM|rx/oq:", - vucomiss_2 = "rro:0Fu2ErM|rx/od:", - vunpckhpd_3 = "rrmoy:660FV15rM", - vunpckhps_3 = "rrmoy:0FV15rM", - vunpcklpd_3 = "rrmoy:660FV14rM", - vunpcklps_3 = "rrmoy:0FV14rM", - vxorpd_3 = "rrmoy:660FV57rM", - vxorps_3 = "rrmoy:0FV57rM", - vzeroall_0 = "0FuL77", - vzeroupper_0 = "0Fu77", - - -- AVX2 FP ops - vbroadcastss_2 = "rx/od:660F38u18rM|rx/yd:|rro:|rr/yo:", - vbroadcastsd_2 = "rx/yq:660F38u19rM|rr/yo:", - -- *vgather* (!vsib) - vpermpd_3 = "rmiy:660F3AuX01rMU", - vpermps_3 = "rrmy:660F38V16rM", - - -- AVX, AVX2 integer ops - -- In general, xmm requires AVX, ymm requires AVX2. - vaesdec_3 = "rrmo:660F38VDErM", - vaesdeclast_3 = "rrmo:660F38VDFrM", - vaesenc_3 = "rrmo:660F38VDCrM", - vaesenclast_3 = "rrmo:660F38VDDrM", - vaesimc_2 = "rmo:660F38uDBrM", - vaeskeygenassist_3 = "rmio:660F3AuDFrMU", - vlddqu_2 = "rxoy:F20FuF0rM", - vmaskmovdqu_2 = "rro:660FuF7rM", - vmovdqa_2 = "rmoy:660Fu6FrM|mroy:660Fu7FRm", - vmovdqu_2 = "rmoy:F30Fu6FrM|mroy:F30Fu7FRm", - vmovntdq_2 = "xroy:660FuE7Rm", - vmovntdqa_2 = "rxoy:660F38u2ArM", - vmpsadbw_4 = "rrmioy:660F3AV42rMU", - vpabsb_2 = "rmoy:660F38u1CrM", - vpabsd_2 = "rmoy:660F38u1ErM", - vpabsw_2 = "rmoy:660F38u1DrM", - vpackusdw_3 = "rrmoy:660F38V2BrM", - vpalignr_4 = "rrmioy:660F3AV0FrMU", - vpblendvb_4 = "rrmroy:660F3AV4CrMs", - vpblendw_4 = "rrmioy:660F3AV0ErMU", - vpclmulqdq_4 = "rrmio:660F3AV44rMU", - vpcmpeqq_3 = "rrmoy:660F38V29rM", - vpcmpestri_3 = "rmio:660F3Au61rMU", - vpcmpestrm_3 = "rmio:660F3Au60rMU", - vpcmpgtq_3 = "rrmoy:660F38V37rM", - vpcmpistri_3 = "rmio:660F3Au63rMU", - vpcmpistrm_3 = "rmio:660F3Au62rMU", - vpextrb_3 = "rri/do:660F3Au14nRmU|rri/qo:|xri/bo:", - vpextrw_3 = "rri/do:660FuC5rMU|xri/wo:660F3Au15nRmU", - vpextrd_3 = "mri/do:660F3Au16RmU", - vpextrq_3 = "mri/qo:660F3Au16RmU", - vphaddw_3 = "rrmoy:660F38V01rM", - vphaddd_3 = "rrmoy:660F38V02rM", - vphaddsw_3 = "rrmoy:660F38V03rM", - vphminposuw_2 = "rmo:660F38u41rM", - vphsubw_3 = "rrmoy:660F38V05rM", - vphsubd_3 = "rrmoy:660F38V06rM", - vphsubsw_3 = "rrmoy:660F38V07rM", - vpinsrb_4 = "rrri/ood:660F3AV20rMU|rrxi/oob:", - vpinsrw_4 = "rrri/ood:660FVC4rMU|rrxi/oow:", - vpinsrd_4 = "rrmi/ood:660F3AV22rMU", - vpinsrq_4 = "rrmi/ooq:660F3AVX22rMU", - vpmaddubsw_3 = "rrmoy:660F38V04rM", - vpmaxsb_3 = "rrmoy:660F38V3CrM", - vpmaxsd_3 = "rrmoy:660F38V3DrM", - vpmaxuw_3 = "rrmoy:660F38V3ErM", - vpmaxud_3 = "rrmoy:660F38V3FrM", - vpminsb_3 = "rrmoy:660F38V38rM", - vpminsd_3 = "rrmoy:660F38V39rM", - vpminuw_3 = "rrmoy:660F38V3ArM", - vpminud_3 = "rrmoy:660F38V3BrM", - vpmovmskb_2 = "rr/do:660FuD7rM|rr/dy:660FuLD7rM", - vpmovsxbw_2 = "rroy:660F38u20rM|rx/oq:|rx/yo:", - vpmovsxbd_2 = "rroy:660F38u21rM|rx/od:|rx/yq:", - vpmovsxbq_2 = "rroy:660F38u22rM|rx/ow:|rx/yd:", - vpmovsxwd_2 = "rroy:660F38u23rM|rx/oq:|rx/yo:", - vpmovsxwq_2 = "rroy:660F38u24rM|rx/od:|rx/yq:", - vpmovsxdq_2 = "rroy:660F38u25rM|rx/oq:|rx/yo:", - vpmovzxbw_2 = "rroy:660F38u30rM|rx/oq:|rx/yo:", - vpmovzxbd_2 = "rroy:660F38u31rM|rx/od:|rx/yq:", - vpmovzxbq_2 = "rroy:660F38u32rM|rx/ow:|rx/yd:", - vpmovzxwd_2 = "rroy:660F38u33rM|rx/oq:|rx/yo:", - vpmovzxwq_2 = "rroy:660F38u34rM|rx/od:|rx/yq:", - vpmovzxdq_2 = "rroy:660F38u35rM|rx/oq:|rx/yo:", - vpmuldq_3 = "rrmoy:660F38V28rM", - vpmulhrsw_3 = "rrmoy:660F38V0BrM", - vpmulld_3 = "rrmoy:660F38V40rM", - vpshufb_3 = "rrmoy:660F38V00rM", - vpshufd_3 = "rmioy:660Fu70rMU", - vpshufhw_3 = "rmioy:F30Fu70rMU", - vpshuflw_3 = "rmioy:F20Fu70rMU", - vpsignb_3 = "rrmoy:660F38V08rM", - vpsignw_3 = "rrmoy:660F38V09rM", - vpsignd_3 = "rrmoy:660F38V0ArM", - vpslldq_3 = "rrioy:660Fv737mU", - vpsllw_3 = "rrmoy:660FVF1rM|rrioy:660Fv716mU", - vpslld_3 = "rrmoy:660FVF2rM|rrioy:660Fv726mU", - vpsllq_3 = "rrmoy:660FVF3rM|rrioy:660Fv736mU", - vpsraw_3 = "rrmoy:660FVE1rM|rrioy:660Fv714mU", - vpsrad_3 = "rrmoy:660FVE2rM|rrioy:660Fv724mU", - vpsrldq_3 = "rrioy:660Fv733mU", - vpsrlw_3 = "rrmoy:660FVD1rM|rrioy:660Fv712mU", - vpsrld_3 = "rrmoy:660FVD2rM|rrioy:660Fv722mU", - vpsrlq_3 = "rrmoy:660FVD3rM|rrioy:660Fv732mU", - vptest_2 = "rmoy:660F38u17rM", - - -- AVX2 integer ops - vbroadcasti128_2 = "rx/yo:660F38u5ArM", - vinserti128_4 = "rrmi/yyo:660F3AV38rMU", - vextracti128_3 = "mri/oy:660F3AuL39RmU", - vpblendd_4 = "rrmioy:660F3AV02rMU", - vpbroadcastb_2 = "rro:660F38u78rM|rx/ob:|rr/yo:|rx/yb:", - vpbroadcastw_2 = "rro:660F38u79rM|rx/ow:|rr/yo:|rx/yw:", - vpbroadcastd_2 = "rro:660F38u58rM|rx/od:|rr/yo:|rx/yd:", - vpbroadcastq_2 = "rro:660F38u59rM|rx/oq:|rr/yo:|rx/yq:", - vpermd_3 = "rrmy:660F38V36rM", - vpermq_3 = "rmiy:660F3AuX00rMU", - -- *vpgather* (!vsib) - vperm2i128_4 = "rrmiy:660F3AV46rMU", - vpmaskmovd_3 = "rrxoy:660F38V8CrM|xrroy:660F38V8ERm", - vpmaskmovq_3 = "rrxoy:660F38VX8CrM|xrroy:660F38VX8ERm", - vpsllvd_3 = "rrmoy:660F38V47rM", - vpsllvq_3 = "rrmoy:660F38VX47rM", - vpsravd_3 = "rrmoy:660F38V46rM", - vpsrlvd_3 = "rrmoy:660F38V45rM", - vpsrlvq_3 = "rrmoy:660F38VX45rM", - - -- Intel ADX - adcx_2 = "rmqd:660F38F6rM", - adox_2 = "rmqd:F30F38F6rM", - - -- BMI1 - andn_3 = "rrmqd:0F38VF2rM", - bextr_3 = "rmrqd:0F38wF7rM", - blsi_2 = "rmqd:0F38vF33m", - blsmsk_2 = "rmqd:0F38vF32m", - blsr_2 = "rmqd:0F38vF31m", - tzcnt_2 = "rmqdw:F30FBCrM", - - -- BMI2 - bzhi_3 = "rmrqd:0F38wF5rM", - mulx_3 = "rrmqd:F20F38VF6rM", - pdep_3 = "rrmqd:F20F38VF5rM", - pext_3 = "rrmqd:F30F38VF5rM", - rorx_3 = "rmSqd:F20F3AuF0rMS", - sarx_3 = "rmrqd:F30F38wF7rM", - shrx_3 = "rmrqd:F20F38wF7rM", - shlx_3 = "rmrqd:660F38wF7rM", - - -- FMA3 - vfmaddsub132pd_3 = "rrmoy:660F38VX96rM", - vfmaddsub132ps_3 = "rrmoy:660F38V96rM", - vfmaddsub213pd_3 = "rrmoy:660F38VXA6rM", - vfmaddsub213ps_3 = "rrmoy:660F38VA6rM", - vfmaddsub231pd_3 = "rrmoy:660F38VXB6rM", - vfmaddsub231ps_3 = "rrmoy:660F38VB6rM", - - vfmsubadd132pd_3 = "rrmoy:660F38VX97rM", - vfmsubadd132ps_3 = "rrmoy:660F38V97rM", - vfmsubadd213pd_3 = "rrmoy:660F38VXA7rM", - vfmsubadd213ps_3 = "rrmoy:660F38VA7rM", - vfmsubadd231pd_3 = "rrmoy:660F38VXB7rM", - vfmsubadd231ps_3 = "rrmoy:660F38VB7rM", - - vfmadd132pd_3 = "rrmoy:660F38VX98rM", - vfmadd132ps_3 = "rrmoy:660F38V98rM", - vfmadd132sd_3 = "rrro:660F38VX99rM|rrx/ooq:", - vfmadd132ss_3 = "rrro:660F38V99rM|rrx/ood:", - vfmadd213pd_3 = "rrmoy:660F38VXA8rM", - vfmadd213ps_3 = "rrmoy:660F38VA8rM", - vfmadd213sd_3 = "rrro:660F38VXA9rM|rrx/ooq:", - vfmadd213ss_3 = "rrro:660F38VA9rM|rrx/ood:", - vfmadd231pd_3 = "rrmoy:660F38VXB8rM", - vfmadd231ps_3 = "rrmoy:660F38VB8rM", - vfmadd231sd_3 = "rrro:660F38VXB9rM|rrx/ooq:", - vfmadd231ss_3 = "rrro:660F38VB9rM|rrx/ood:", - - vfmsub132pd_3 = "rrmoy:660F38VX9ArM", - vfmsub132ps_3 = "rrmoy:660F38V9ArM", - vfmsub132sd_3 = "rrro:660F38VX9BrM|rrx/ooq:", - vfmsub132ss_3 = "rrro:660F38V9BrM|rrx/ood:", - vfmsub213pd_3 = "rrmoy:660F38VXAArM", - vfmsub213ps_3 = "rrmoy:660F38VAArM", - vfmsub213sd_3 = "rrro:660F38VXABrM|rrx/ooq:", - vfmsub213ss_3 = "rrro:660F38VABrM|rrx/ood:", - vfmsub231pd_3 = "rrmoy:660F38VXBArM", - vfmsub231ps_3 = "rrmoy:660F38VBArM", - vfmsub231sd_3 = "rrro:660F38VXBBrM|rrx/ooq:", - vfmsub231ss_3 = "rrro:660F38VBBrM|rrx/ood:", - - vfnmadd132pd_3 = "rrmoy:660F38VX9CrM", - vfnmadd132ps_3 = "rrmoy:660F38V9CrM", - vfnmadd132sd_3 = "rrro:660F38VX9DrM|rrx/ooq:", - vfnmadd132ss_3 = "rrro:660F38V9DrM|rrx/ood:", - vfnmadd213pd_3 = "rrmoy:660F38VXACrM", - vfnmadd213ps_3 = "rrmoy:660F38VACrM", - vfnmadd213sd_3 = "rrro:660F38VXADrM|rrx/ooq:", - vfnmadd213ss_3 = "rrro:660F38VADrM|rrx/ood:", - vfnmadd231pd_3 = "rrmoy:660F38VXBCrM", - vfnmadd231ps_3 = "rrmoy:660F38VBCrM", - vfnmadd231sd_3 = "rrro:660F38VXBDrM|rrx/ooq:", - vfnmadd231ss_3 = "rrro:660F38VBDrM|rrx/ood:", - - vfnmsub132pd_3 = "rrmoy:660F38VX9ErM", - vfnmsub132ps_3 = "rrmoy:660F38V9ErM", - vfnmsub132sd_3 = "rrro:660F38VX9FrM|rrx/ooq:", - vfnmsub132ss_3 = "rrro:660F38V9FrM|rrx/ood:", - vfnmsub213pd_3 = "rrmoy:660F38VXAErM", - vfnmsub213ps_3 = "rrmoy:660F38VAErM", - vfnmsub213sd_3 = "rrro:660F38VXAFrM|rrx/ooq:", - vfnmsub213ss_3 = "rrro:660F38VAFrM|rrx/ood:", - vfnmsub231pd_3 = "rrmoy:660F38VXBErM", - vfnmsub231ps_3 = "rrmoy:660F38VBErM", - vfnmsub231sd_3 = "rrro:660F38VXBFrM|rrx/ooq:", - vfnmsub231ss_3 = "rrro:660F38VBFrM|rrx/ood:", -} - ------------------------------------------------------------------------------- - --- Arithmetic ops. -for name,n in pairs{ add = 0, ["or"] = 1, adc = 2, sbb = 3, - ["and"] = 4, sub = 5, xor = 6, cmp = 7 } do - local n8 = shl(n, 3) - map_op[name.."_2"] = format( - "mr:%02XRm|rm:%02XrM|mI1qdw:81%XmI|mS1qdw:83%XmS|Ri1qdwb:%02Xri|mi1qdwb:81%Xmi", - 1+n8, 3+n8, n, n, 5+n8, n) -end - --- Shift ops. -for name,n in pairs{ rol = 0, ror = 1, rcl = 2, rcr = 3, - shl = 4, shr = 5, sar = 7, sal = 4 } do - map_op[name.."_2"] = format("m1:D1%Xm|mC1qdwb:D3%Xm|mi:C1%XmU", n, n, n) -end - --- Conditional ops. -for cc,n in pairs(map_cc) do - map_op["j"..cc.."_1"] = format("J.:n0F8%XJ", n) -- short: 7%X - map_op["set"..cc.."_1"] = format("mb:n0F9%X2m", n) - map_op["cmov"..cc.."_2"] = format("rmqdw:0F4%XrM", n) -- P6+ -end - --- FP arithmetic ops. -for name,n in pairs{ add = 0, mul = 1, com = 2, comp = 3, - sub = 4, subr = 5, div = 6, divr = 7 } do - local nc = 0xc0 + shl(n, 3) - local nr = nc + (n < 4 and 0 or (n % 2 == 0 and 8 or -8)) - local fn = "f"..name - map_op[fn.."_1"] = format("ff:D8%02Xr|xd:D8%Xm|xq:nDC%Xm", nc, n, n) - if n == 2 or n == 3 then - map_op[fn.."_2"] = format("Fff:D8%02XR|Fx2d:D8%XM|Fx2q:nDC%XM", nc, n, n) - else - map_op[fn.."_2"] = format("Fff:D8%02XR|fFf:DC%02Xr|Fx2d:D8%XM|Fx2q:nDC%XM", nc, nr, n, n) - map_op[fn.."p_1"] = format("ff:DE%02Xr", nr) - map_op[fn.."p_2"] = format("fFf:DE%02Xr", nr) - end - map_op["fi"..name.."_1"] = format("xd:DA%Xm|xw:nDE%Xm", n, n) -end - --- FP conditional moves. -for cc,n in pairs{ b=0, e=1, be=2, u=3, nb=4, ne=5, nbe=6, nu=7 } do - local nc = 0xdac0 + shl(band(n, 3), 3) + shl(band(n, 4), 6) - map_op["fcmov"..cc.."_1"] = format("ff:%04Xr", nc) -- P6+ - map_op["fcmov"..cc.."_2"] = format("Fff:%04XR", nc) -- P6+ -end - --- SSE / AVX FP arithmetic ops. -for name,n in pairs{ sqrt = 1, add = 8, mul = 9, - sub = 12, min = 13, div = 14, max = 15 } do - map_op[name.."ps_2"] = format("rmo:0F5%XrM", n) - map_op[name.."ss_2"] = format("rro:F30F5%XrM|rx/od:", n) - map_op[name.."pd_2"] = format("rmo:660F5%XrM", n) - map_op[name.."sd_2"] = format("rro:F20F5%XrM|rx/oq:", n) - if n ~= 1 then - map_op["v"..name.."ps_3"] = format("rrmoy:0FV5%XrM", n) - map_op["v"..name.."ss_3"] = format("rrro:F30FV5%XrM|rrx/ood:", n) - map_op["v"..name.."pd_3"] = format("rrmoy:660FV5%XrM", n) - map_op["v"..name.."sd_3"] = format("rrro:F20FV5%XrM|rrx/ooq:", n) - end -end - --- SSE2 / AVX / AVX2 integer arithmetic ops (66 0F leaf). -for name,n in pairs{ - paddb = 0xFC, paddw = 0xFD, paddd = 0xFE, paddq = 0xD4, - paddsb = 0xEC, paddsw = 0xED, packssdw = 0x6B, - packsswb = 0x63, packuswb = 0x67, paddusb = 0xDC, - paddusw = 0xDD, pand = 0xDB, pandn = 0xDF, pavgb = 0xE0, - pavgw = 0xE3, pcmpeqb = 0x74, pcmpeqd = 0x76, - pcmpeqw = 0x75, pcmpgtb = 0x64, pcmpgtd = 0x66, - pcmpgtw = 0x65, pmaddwd = 0xF5, pmaxsw = 0xEE, - pmaxub = 0xDE, pminsw = 0xEA, pminub = 0xDA, - pmulhuw = 0xE4, pmulhw = 0xE5, pmullw = 0xD5, - pmuludq = 0xF4, por = 0xEB, psadbw = 0xF6, psubb = 0xF8, - psubw = 0xF9, psubd = 0xFA, psubq = 0xFB, psubsb = 0xE8, - psubsw = 0xE9, psubusb = 0xD8, psubusw = 0xD9, - punpckhbw = 0x68, punpckhwd = 0x69, punpckhdq = 0x6A, - punpckhqdq = 0x6D, punpcklbw = 0x60, punpcklwd = 0x61, - punpckldq = 0x62, punpcklqdq = 0x6C, pxor = 0xEF -} do - map_op[name.."_2"] = format("rmo:660F%02XrM", n) - map_op["v"..name.."_3"] = format("rrmoy:660FV%02XrM", n) -end - ------------------------------------------------------------------------------- - -local map_vexarg = { u = false, v = 1, V = 2, w = 3 } - --- Process pattern string. -local function dopattern(pat, args, sz, op, needrex) - local digit, addin, vex - local opcode = 0 - local szov = sz - local narg = 1 - local rex = 0 - - -- Limit number of section buffer positions used by a single dasm_put(). - -- A single opcode needs a maximum of 6 positions. - if secpos+6 > maxsecpos then wflush() end - - -- Process each character. - for c in gmatch(pat.."|", ".") do - if match(c, "%x") then -- Hex digit. - digit = byte(c) - 48 - if digit > 48 then digit = digit - 39 - elseif digit > 16 then digit = digit - 7 end - opcode = opcode*16 + digit - addin = nil - elseif c == "n" then -- Disable operand size mods for opcode. - szov = nil - elseif c == "X" then -- Force REX.W. - rex = 8 - elseif c == "L" then -- Force VEX.L. - vex.l = true - elseif c == "r" then -- Merge 1st operand regno. into opcode. - addin = args[1]; opcode = opcode + (addin.reg % 8) - if narg < 2 then narg = 2 end - elseif c == "R" then -- Merge 2nd operand regno. into opcode. - addin = args[2]; opcode = opcode + (addin.reg % 8) - narg = 3 - elseif c == "m" or c == "M" then -- Encode ModRM/SIB. - local s - if addin then - s = addin.reg - opcode = opcode - band(s, 7) -- Undo regno opcode merge. - else - s = band(opcode, 15) -- Undo last digit. - opcode = shr(opcode, 4) - end - local nn = c == "m" and 1 or 2 - local t = args[nn] - if narg <= nn then narg = nn + 1 end - if szov == "q" and rex == 0 then rex = rex + 8 end - if t.reg and t.reg > 7 then rex = rex + 1 end - if t.xreg and t.xreg > 7 then rex = rex + 2 end - if s > 7 then rex = rex + 4 end - if needrex then rex = rex + 16 end - local psz, sk = wputop(szov, opcode, rex, vex, s < 0, t.vreg or t.vxreg) - opcode = nil - local imark = sub(pat, -1) -- Force a mark (ugly). - -- Put ModRM/SIB with regno/last digit as spare. - wputmrmsib(t, imark, s, addin and addin.vreg, psz, sk) - addin = nil - elseif map_vexarg[c] ~= nil then -- Encode using VEX prefix - local b = band(opcode, 255); opcode = shr(opcode, 8) - local m = 1 - if b == 0x38 then m = 2 - elseif b == 0x3a then m = 3 end - if m ~= 1 then b = band(opcode, 255); opcode = shr(opcode, 8) end - if b ~= 0x0f then - werror("expected `0F', `0F38', or `0F3A' to precede `"..c.. - "' in pattern `"..pat.."' for `"..op.."'") - end - local v = map_vexarg[c] - if v then v = remove(args, v) end - b = band(opcode, 255) - local p = 0 - if b == 0x66 then p = 1 - elseif b == 0xf3 then p = 2 - elseif b == 0xf2 then p = 3 end - if p ~= 0 then opcode = shr(opcode, 8) end - if opcode ~= 0 then wputop(nil, opcode, 0); opcode = 0 end - vex = { m = m, p = p, v = v } - else - if opcode then -- Flush opcode. - if szov == "q" and rex == 0 then rex = rex + 8 end - if needrex then rex = rex + 16 end - if addin and addin.reg == -1 then - local psz, sk = wputop(szov, opcode - 7, rex, vex, true) - wvreg("opcode", addin.vreg, psz, sk) - else - if addin and addin.reg > 7 then rex = rex + 1 end - wputop(szov, opcode, rex, vex) - end - opcode = nil - end - if c == "|" then break end - if c == "o" then -- Offset (pure 32 bit displacement). - wputdarg(args[1].disp); if narg < 2 then narg = 2 end - elseif c == "O" then - wputdarg(args[2].disp); narg = 3 - else - -- Anything else is an immediate operand. - local a = args[narg] - narg = narg + 1 - local mode, imm = a.mode, a.imm - if mode == "iJ" and not match(x64 and "J" or "iIJ", c) then - werror("bad operand size for label") - end - if c == "S" then - wputsbarg(imm) - elseif c == "U" then - wputbarg(imm) - elseif c == "W" then - wputwarg(imm) - elseif c == "i" or c == "I" then - if mode == "iJ" then - wputlabel("IMM_", imm, 1) - elseif mode == "iI" and c == "I" then - waction(sz == "w" and "IMM_WB" or "IMM_DB", imm) - else - wputszarg(sz, imm) - end - elseif c == "J" then - if mode == "iPJ" then - waction("REL_A", imm) -- !x64 (secpos) - else - wputlabel("REL_", imm, 2) - end - elseif c == "s" then - local reg = a.reg - if reg < 0 then - wputb(0) - wvreg("imm.hi", a.vreg) - else - wputb(shl(reg, 4)) - end - else - werror("bad char `"..c.."' in pattern `"..pat.."' for `"..op.."'") - end - end - end - end -end - ------------------------------------------------------------------------------- - --- Mapping of operand modes to short names. Suppress output with '#'. -local map_modename = { - r = "reg", R = "eax", C = "cl", x = "mem", m = "mrm", i = "imm", - f = "stx", F = "st0", J = "lbl", ["1"] = "1", - I = "#", S = "#", O = "#", -} - --- Return a table/string showing all possible operand modes. -local function templatehelp(template, nparams) - if nparams == 0 then return "" end - local t = {} - for tm in gmatch(template, "[^%|]+") do - local s = map_modename[sub(tm, 1, 1)] - s = s..gsub(sub(tm, 2, nparams), ".", function(c) - return ", "..map_modename[c] - end) - if not match(s, "#") then t[#t+1] = s end - end - return t -end - --- Match operand modes against mode match part of template. -local function matchtm(tm, args) - for i=1,#args do - if not match(args[i].mode, sub(tm, i, i)) then return end - end - return true -end - --- Handle opcodes defined with template strings. -map_op[".template__"] = function(params, template, nparams) - if not params then return templatehelp(template, nparams) end - local args = {} - - -- Zero-operand opcodes have no match part. - if #params == 0 then - dopattern(template, args, "d", params.op, nil) - return - end - - -- Determine common operand size (coerce undefined size) or flag as mixed. - local sz, szmix, needrex - for i,p in ipairs(params) do - args[i] = parseoperand(p) - local nsz = args[i].opsize - if nsz then - if sz and sz ~= nsz then szmix = true else sz = nsz end - end - local nrex = args[i].needrex - if nrex ~= nil then - if needrex == nil then - needrex = nrex - elseif needrex ~= nrex then - werror("bad mix of byte-addressable registers") - end - end - end - - -- Try all match:pattern pairs (separated by '|'). - local gotmatch, lastpat - for tm in gmatch(template, "[^%|]+") do - -- Split off size match (starts after mode match) and pattern string. - local szm, pat = match(tm, "^(.-):(.*)$", #args+1) - if pat == "" then pat = lastpat else lastpat = pat end - if matchtm(tm, args) then - local prefix = sub(szm, 1, 1) - if prefix == "/" then -- Exactly match leading operand sizes. - for i = #szm,1,-1 do - if i == 1 then - dopattern(pat, args, sz, params.op, needrex) -- Process pattern. - return - elseif args[i-1].opsize ~= sub(szm, i, i) then - break - end - end - else -- Match common operand size. - local szp = sz - if szm == "" then szm = x64 and "qdwb" or "dwb" end -- Default sizes. - if prefix == "1" then szp = args[1].opsize; szmix = nil - elseif prefix == "2" then szp = args[2].opsize; szmix = nil end - if not szmix and (prefix == "." or match(szm, szp or "#")) then - dopattern(pat, args, szp, params.op, needrex) -- Process pattern. - return - end - end - gotmatch = true - end - end - - local msg = "bad operand mode" - if gotmatch then - if szmix then - msg = "mixed operand size" - else - msg = sz and "bad operand size" or "missing operand size" - end - end - - werror(msg.." in `"..opmodestr(params.op, args).."'") -end - ------------------------------------------------------------------------------- - --- x64-specific opcode for 64 bit immediates and displacements. -if x64 then - function map_op.mov64_2(params) - if not params then return { "reg, imm", "reg, [disp]", "[disp], reg" } end - if secpos+2 > maxsecpos then wflush() end - local opcode, op64, sz, rex, vreg - local op64 = match(params[1], "^%[%s*(.-)%s*%]$") - if op64 then - local a = parseoperand(params[2]) - if a.mode ~= "rmR" then werror("bad operand mode") end - sz = a.opsize - rex = sz == "q" and 8 or 0 - opcode = 0xa3 - else - op64 = match(params[2], "^%[%s*(.-)%s*%]$") - local a = parseoperand(params[1]) - if op64 then - if a.mode ~= "rmR" then werror("bad operand mode") end - sz = a.opsize - rex = sz == "q" and 8 or 0 - opcode = 0xa1 - else - if sub(a.mode, 1, 1) ~= "r" or a.opsize ~= "q" then - werror("bad operand mode") - end - op64 = params[2] - if a.reg == -1 then - vreg = a.vreg - opcode = 0xb8 - else - opcode = 0xb8 + band(a.reg, 7) - end - rex = a.reg > 7 and 9 or 8 - end - end - local psz, sk = wputop(sz, opcode, rex, nil, vreg) - wvreg("opcode", vreg, psz, sk) - waction("IMM_D", format("(unsigned int)(%s)", op64)) - waction("IMM_D", format("(unsigned int)((%s)>>32)", op64)) - end -end - ------------------------------------------------------------------------------- - --- Pseudo-opcodes for data storage. -local function op_data(params) - if not params then return "imm..." end - local sz = sub(params.op, 2, 2) - if sz == "l" then sz = "d" elseif sz == "a" then sz = addrsize end - for _,p in ipairs(params) do - local a = parseoperand(p, sz == "q") - if sub(a.mode, 1, 1) ~= "i" or (a.opsize and a.opsize ~= sz) then - werror("bad mode or size in `"..p.."'") - end - if a.mode == "iJ" then - wputlabel("IMM_", a.imm, 1) - elseif sz == "q" then - wputqarg(a.imm) - else - wputszarg(sz, a.imm) - end - if secpos+2 > maxsecpos then wflush() end - end -end - -map_op[".byte_*"] = op_data -map_op[".sbyte_*"] = op_data -map_op[".word_*"] = op_data -map_op[".dword_*"] = op_data -map_op[".qword_*"] = op_data -map_op[".aword_*"] = op_data -map_op[".long_*"] = op_data -map_op[".quad_*"] = op_data -map_op[".addr_*"] = op_data - ------------------------------------------------------------------------------- - --- Pseudo-opcode to mark the position where the action list is to be emitted. -map_op[".actionlist_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeactions(out, name) end) -end - --- Pseudo-opcode to mark the position where the global enum is to be emitted. -map_op[".globals_1"] = function(params) - if not params then return "prefix" end - local prefix = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobals(out, prefix) end) -end - --- Pseudo-opcode to mark the position where the global names are to be emitted. -map_op[".globalnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeglobalnames(out, name) end) -end - --- Pseudo-opcode to mark the position where the extern names are to be emitted. -map_op[".externnames_1"] = function(params) - if not params then return "cvar" end - local name = params[1] -- No syntax check. You get to keep the pieces. - wline(function(out) writeexternnames(out, name) end) -end - ------------------------------------------------------------------------------- - --- Label pseudo-opcode (converted from trailing colon form). -map_op[".label_2"] = function(params) - if not params then return "[1-9] | ->global | =>pcexpr [, addr]" end - if secpos+2 > maxsecpos then wflush() end - local a = parseoperand(params[1]) - local mode, imm = a.mode, a.imm - if type(imm) == "number" and (mode == "iJ" or (imm >= 1 and imm <= 9)) then - -- Local label (1: ... 9:) or global label (->global:). - waction("LABEL_LG", nil, 1) - wputxb(imm) - elseif mode == "iJ" then - -- PC label (=>pcexpr:). - waction("LABEL_PC", imm) - else - werror("bad label definition") - end - -- SETLABEL must immediately follow LABEL_LG/LABEL_PC. - local addr = params[2] - if addr then - local a = parseoperand(addr) - if a.mode == "iPJ" then - waction("SETLABEL", a.imm) - else - werror("bad label assignment") - end - end -end -map_op[".label_1"] = map_op[".label_2"] - ------------------------------------------------------------------------------- - --- Alignment pseudo-opcode. -map_op[".align_1"] = function(params) - if not params then return "numpow2" end - if secpos+1 > maxsecpos then wflush() end - local align = tonumber(params[1]) or map_opsizenum[map_opsize[params[1]]] - if align then - local x = align - -- Must be a power of 2 in the range (2 ... 256). - for i=1,8 do - x = x / 2 - if x == 1 then - waction("ALIGN", nil, 1) - wputxb(align-1) -- Action byte is 2**n-1. - return - end - end - end - werror("bad alignment") -end - --- Spacing pseudo-opcode. -map_op[".space_2"] = function(params) - if not params then return "num [, filler]" end - if secpos+1 > maxsecpos then wflush() end - waction("SPACE", params[1]) - local fill = params[2] - if fill then - fill = tonumber(fill) - if not fill or fill < 0 or fill > 255 then werror("bad filler") end - end - wputxb(fill or 0) -end -map_op[".space_1"] = map_op[".space_2"] - ------------------------------------------------------------------------------- - --- Pseudo-opcode for (primitive) type definitions (map to C types). -map_op[".type_3"] = function(params, nparams) - if not params then - return nparams == 2 and "name, ctype" or "name, ctype, reg" - end - local name, ctype, reg = params[1], params[2], params[3] - if not match(name, "^[%a_][%w_]*$") then - werror("bad type name `"..name.."'") - end - local tp = map_type[name] - if tp then - werror("duplicate type `"..name.."'") - end - if reg and not map_reg_valid_base[reg] then - werror("bad base register `"..(map_reg_rev[reg] or reg).."'") - end - -- Add #type to defines. A bit unclean to put it in map_archdef. - map_archdef["#"..name] = "sizeof("..ctype..")" - -- Add new type and emit shortcut define. - local num = ctypenum + 1 - map_type[name] = { - ctype = ctype, - ctypefmt = format("Dt%X(%%s)", num), - reg = reg, - } - wline(format("#define Dt%X(_V) (int)(ptrdiff_t)&(((%s *)0)_V)", num, ctype)) - ctypenum = num -end -map_op[".type_2"] = map_op[".type_3"] - --- Dump type definitions. -local function dumptypes(out, lvl) - local t = {} - for name in pairs(map_type) do t[#t+1] = name end - sort(t) - out:write("Type definitions:\n") - for _,name in ipairs(t) do - local tp = map_type[name] - local reg = tp.reg and map_reg_rev[tp.reg] or "" - out:write(format(" %-20s %-20s %s\n", name, tp.ctype, reg)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Set the current section. -function _M.section(num) - waction("SECTION") - wputxb(num) - wflush(true) -- SECTION is a terminal action. -end - ------------------------------------------------------------------------------- - --- Dump architecture description. -function _M.dumparch(out) - out:write(format("DynASM %s version %s, released %s\n\n", - _info.arch, _info.version, _info.release)) - dumpregs(out) - dumpactions(out) -end - --- Dump all user defined elements. -function _M.dumpdef(out, lvl) - dumptypes(out, lvl) - dumpglobals(out, lvl) - dumpexterns(out, lvl) -end - ------------------------------------------------------------------------------- - --- Pass callbacks from/to the DynASM core. -function _M.passcb(wl, we, wf, ww) - wline, werror, wfatal, wwarn = wl, we, wf, ww - return wflush -end - --- Setup the arch-specific module. -function _M.setup(arch, opt) - g_arch, g_opt = arch, opt -end - --- Merge the core maps and the arch-specific maps. -function _M.mergemaps(map_coreop, map_def) - setmetatable(map_op, { __index = map_coreop }) - setmetatable(map_def, { __index = map_archdef }) - return map_op, map_def -end - -return _M - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/dynasm.lua b/ext/opcache/jit/dynasm/dynasm.lua deleted file mode 100644 index 2583295fce368..0000000000000 --- a/ext/opcache/jit/dynasm/dynasm.lua +++ /dev/null @@ -1,1095 +0,0 @@ ------------------------------------------------------------------------------- --- DynASM. A dynamic assembler for code generation engines. --- Originally designed and implemented for LuaJIT. --- --- Copyright (C) 2005-2021 Mike Pall. All rights reserved. --- See below for full copyright notice. ------------------------------------------------------------------------------- - --- Application information. -local _info = { - name = "DynASM", - description = "A dynamic assembler for code generation engines", - version = "1.5.0", - vernum = 10500, - release = "2021-05-02", - author = "Mike Pall", - url = "https://luajit.org/dynasm.html", - license = "MIT", - copyright = [[ -Copyright (C) 2005-2021 Mike Pall. All rights reserved. - -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. - -[ MIT license: https://www.opensource.org/licenses/mit-license.php ] -]], -} - --- Cache library functions. -local type, pairs, ipairs = type, pairs, ipairs -local pcall, error, assert = pcall, error, assert -local _s = string -local sub, match, gmatch, gsub = _s.sub, _s.match, _s.gmatch, _s.gsub -local format, rep, upper = _s.format, _s.rep, _s.upper -local _t = table -local insert, remove, concat, sort = _t.insert, _t.remove, _t.concat, _t.sort -local exit = os.exit -local io = io -local stdin, stdout, stderr = io.stdin, io.stdout, io.stderr - ------------------------------------------------------------------------------- - --- Program options. -local g_opt = {} - --- Global state for current file. -local g_fname, g_curline, g_indent, g_lineno, g_synclineno, g_arch -local g_errcount = 0 - --- Write buffer for output file. -local g_wbuffer, g_capbuffer - ------------------------------------------------------------------------------- - --- Write an output line (or callback function) to the buffer. -local function wline(line, needindent) - local buf = g_capbuffer or g_wbuffer - buf[#buf+1] = needindent and g_indent..line or line - g_synclineno = g_synclineno + 1 -end - --- Write assembler line as a comment, if requested. -local function wcomment(aline) - if g_opt.comment then - wline(g_opt.comment..aline..g_opt.endcomment, true) - end -end - --- Resync CPP line numbers. -local function wsync() - if g_synclineno ~= g_lineno and g_opt.cpp then - wline("#line "..g_lineno..' "'..g_fname..'"') - g_synclineno = g_lineno - end -end - --- Dummy action flush function. Replaced with arch-specific function later. -local function wflush(term) -end - --- Dump all buffered output lines. -local function wdumplines(out, buf) - for _,line in ipairs(buf) do - if type(line) == "string" then - assert(out:write(line, "\n")) - else - -- Special callback to dynamically insert lines after end of processing. - line(out) - end - end -end - ------------------------------------------------------------------------------- - --- Emit an error. Processing continues with next statement. -local function werror(msg) - error(format("%s:%s: error: %s:\n%s", g_fname, g_lineno, msg, g_curline), 0) -end - --- Emit a fatal error. Processing stops. -local function wfatal(msg) - g_errcount = "fatal" - werror(msg) -end - --- Print a warning. Processing continues. -local function wwarn(msg) - stderr:write(format("%s:%s: warning: %s:\n%s\n", - g_fname, g_lineno, msg, g_curline)) -end - --- Print caught error message. But suppress excessive errors. -local function wprinterr(...) - if type(g_errcount) == "number" then - -- Regular error. - g_errcount = g_errcount + 1 - if g_errcount < 21 then -- Seems to be a reasonable limit. - stderr:write(...) - elseif g_errcount == 21 then - stderr:write(g_fname, - ":*: warning: too many errors (suppressed further messages).\n") - end - else - -- Fatal error. - stderr:write(...) - return true -- Stop processing. - end -end - ------------------------------------------------------------------------------- - --- Map holding all option handlers. -local opt_map = {} -local opt_current - --- Print error and exit with error status. -local function opterror(...) - stderr:write("dynasm.lua: ERROR: ", ...) - stderr:write("\n") - exit(1) -end - --- Get option parameter. -local function optparam(args) - local argn = args.argn - local p = args[argn] - if not p then - opterror("missing parameter for option `", opt_current, "'.") - end - args.argn = argn + 1 - return p -end - ------------------------------------------------------------------------------- - --- Core pseudo-opcodes. -local map_coreop = {} --- Dummy opcode map. Replaced by arch-specific map. -local map_op = {} - --- Forward declarations. -local dostmt -local readfile - ------------------------------------------------------------------------------- - --- Map for defines (initially empty, chains to arch-specific map). -local map_def = {} - --- Pseudo-opcode to define a substitution. -map_coreop[".define_2"] = function(params, nparams) - if not params then return nparams == 1 and "name" or "name, subst" end - local name, def = params[1], params[2] or "1" - if not match(name, "^[%a_][%w_]*$") then werror("bad or duplicate define") end - map_def[name] = def -end -map_coreop[".define_1"] = map_coreop[".define_2"] - --- Define a substitution on the command line. -function opt_map.D(args) - local namesubst = optparam(args) - local name, subst = match(namesubst, "^([%a_][%w_]*)=(.*)$") - if name then - map_def[name] = subst - elseif match(namesubst, "^[%a_][%w_]*$") then - map_def[namesubst] = "1" - else - opterror("bad define") - end -end - --- Undefine a substitution on the command line. -function opt_map.U(args) - local name = optparam(args) - if match(name, "^[%a_][%w_]*$") then - map_def[name] = nil - else - opterror("bad define") - end -end - --- Helper for definesubst. -local gotsubst - -local function definesubst_one(word) - local subst = map_def[word] - if subst then gotsubst = word; return subst else return word end -end - --- Iteratively substitute defines. -local function definesubst(stmt) - -- Limit number of iterations. - for i=1,100 do - gotsubst = false - stmt = gsub(stmt, "#?[%w_]+", definesubst_one) - if not gotsubst then break end - end - if gotsubst then wfatal("recursive define involving `"..gotsubst.."'") end - return stmt -end - --- Dump all defines. -local function dumpdefines(out, lvl) - local t = {} - for name in pairs(map_def) do - t[#t+1] = name - end - sort(t) - out:write("Defines:\n") - for _,name in ipairs(t) do - local subst = map_def[name] - if g_arch then subst = g_arch.revdef(subst) end - out:write(format(" %-20s %s\n", name, subst)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Support variables for conditional assembly. -local condlevel = 0 -local condstack = {} - --- Evaluate condition with a Lua expression. Substitutions already performed. -local function cond_eval(cond) - local func, err - if setfenv then - func, err = loadstring("return "..cond, "=expr") - else - -- No globals. All unknown identifiers evaluate to nil. - func, err = load("return "..cond, "=expr", "t", {}) - end - if func then - if setfenv then - setfenv(func, {}) -- No globals. All unknown identifiers evaluate to nil. - end - local ok, res = pcall(func) - if ok then - if res == 0 then return false end -- Oh well. - return not not res - end - err = res - end - wfatal("bad condition: "..err) -end - --- Skip statements until next conditional pseudo-opcode at the same level. -local function stmtskip() - local dostmt_save = dostmt - local lvl = 0 - dostmt = function(stmt) - local op = match(stmt, "^%s*(%S+)") - if op == ".if" then - lvl = lvl + 1 - elseif lvl ~= 0 then - if op == ".endif" then lvl = lvl - 1 end - elseif op == ".elif" or op == ".else" or op == ".endif" then - dostmt = dostmt_save - dostmt(stmt) - end - end -end - --- Pseudo-opcodes for conditional assembly. -map_coreop[".if_1"] = function(params) - if not params then return "condition" end - local lvl = condlevel + 1 - local res = cond_eval(params[1]) - condlevel = lvl - condstack[lvl] = res - if not res then stmtskip() end -end - -map_coreop[".elif_1"] = function(params) - if not params then return "condition" end - if condlevel == 0 then wfatal(".elif without .if") end - local lvl = condlevel - local res = condstack[lvl] - if res then - if res == "else" then wfatal(".elif after .else") end - else - res = cond_eval(params[1]) - if res then - condstack[lvl] = res - return - end - end - stmtskip() -end - -map_coreop[".else_0"] = function(params) - if condlevel == 0 then wfatal(".else without .if") end - local lvl = condlevel - local res = condstack[lvl] - condstack[lvl] = "else" - if res then - if res == "else" then wfatal(".else after .else") end - stmtskip() - end -end - -map_coreop[".endif_0"] = function(params) - local lvl = condlevel - if lvl == 0 then wfatal(".endif without .if") end - condlevel = lvl - 1 -end - --- Check for unfinished conditionals. -local function checkconds() - if g_errcount ~= "fatal" and condlevel ~= 0 then - wprinterr(g_fname, ":*: error: unbalanced conditional\n") - end -end - ------------------------------------------------------------------------------- - --- Search for a file in the given path and open it for reading. -local function pathopen(path, name) - local dirsep = package and match(package.path, "\\") and "\\" or "/" - for _,p in ipairs(path) do - local fullname = p == "" and name or p..dirsep..name - local fin = io.open(fullname, "r") - if fin then - g_fname = fullname - return fin - end - end -end - --- Include a file. -map_coreop[".include_1"] = function(params) - if not params then return "filename" end - local name = params[1] - -- Save state. Ugly, I know. but upvalues are fast. - local gf, gl, gcl, gi = g_fname, g_lineno, g_curline, g_indent - -- Read the included file. - local fatal = readfile(pathopen(g_opt.include, name) or - wfatal("include file `"..name.."' not found")) - -- Restore state. - g_synclineno = -1 - g_fname, g_lineno, g_curline, g_indent = gf, gl, gcl, gi - if fatal then wfatal("in include file") end -end - --- Make .include and conditionals initially available, too. -map_op[".include_1"] = map_coreop[".include_1"] -map_op[".if_1"] = map_coreop[".if_1"] -map_op[".elif_1"] = map_coreop[".elif_1"] -map_op[".else_0"] = map_coreop[".else_0"] -map_op[".endif_0"] = map_coreop[".endif_0"] - ------------------------------------------------------------------------------- - --- Support variables for macros. -local mac_capture, mac_lineno, mac_name -local mac_active = {} -local mac_list = {} - --- Pseudo-opcode to define a macro. -map_coreop[".macro_*"] = function(mparams) - if not mparams then return "name [, params...]" end - -- Split off and validate macro name. - local name = remove(mparams, 1) - if not name then werror("missing macro name") end - if not (match(name, "^[%a_][%w_%.]*$") or match(name, "^%.[%w_%.]*$")) then - wfatal("bad macro name `"..name.."'") - end - -- Validate macro parameter names. - local mdup = {} - for _,mp in ipairs(mparams) do - if not match(mp, "^[%a_][%w_]*$") then - wfatal("bad macro parameter name `"..mp.."'") - end - if mdup[mp] then wfatal("duplicate macro parameter name `"..mp.."'") end - mdup[mp] = true - end - -- Check for duplicate or recursive macro definitions. - local opname = name.."_"..#mparams - if map_op[opname] or map_op[name.."_*"] then - wfatal("duplicate macro `"..name.."' ("..#mparams.." parameters)") - end - if mac_capture then wfatal("recursive macro definition") end - - -- Enable statement capture. - local lines = {} - mac_lineno = g_lineno - mac_name = name - mac_capture = function(stmt) -- Statement capture function. - -- Stop macro definition with .endmacro pseudo-opcode. - if not match(stmt, "^%s*.endmacro%s*$") then - lines[#lines+1] = stmt - return - end - mac_capture = nil - mac_lineno = nil - mac_name = nil - mac_list[#mac_list+1] = opname - -- Add macro-op definition. - map_op[opname] = function(params) - if not params then return mparams, lines end - -- Protect against recursive macro invocation. - if mac_active[opname] then wfatal("recursive macro invocation") end - mac_active[opname] = true - -- Setup substitution map. - local subst = {} - for i,mp in ipairs(mparams) do subst[mp] = params[i] end - local mcom - if g_opt.maccomment and g_opt.comment then - mcom = " MACRO "..name.." ("..#mparams..")" - wcomment("{"..mcom) - end - -- Loop through all captured statements - for _,stmt in ipairs(lines) do - -- Substitute macro parameters. - local st = gsub(stmt, "[%w_]+", subst) - st = definesubst(st) - st = gsub(st, "%s*%.%.%s*", "") -- Token paste a..b. - if mcom and sub(st, 1, 1) ~= "|" then wcomment(st) end - -- Emit statement. Use a protected call for better diagnostics. - local ok, err = pcall(dostmt, st) - if not ok then - -- Add the captured statement to the error. - wprinterr(err, "\n", g_indent, "| ", stmt, - "\t[MACRO ", name, " (", #mparams, ")]\n") - end - end - if mcom then wcomment("}"..mcom) end - mac_active[opname] = nil - end - end -end - --- An .endmacro pseudo-opcode outside of a macro definition is an error. -map_coreop[".endmacro_0"] = function(params) - wfatal(".endmacro without .macro") -end - --- Dump all macros and their contents (with -PP only). -local function dumpmacros(out, lvl) - sort(mac_list) - out:write("Macros:\n") - for _,opname in ipairs(mac_list) do - local name = sub(opname, 1, -3) - local params, lines = map_op[opname]() - out:write(format(" %-20s %s\n", name, concat(params, ", "))) - if lvl > 1 then - for _,line in ipairs(lines) do - out:write(" |", line, "\n") - end - out:write("\n") - end - end - out:write("\n") -end - --- Check for unfinished macro definitions. -local function checkmacros() - if mac_capture then - wprinterr(g_fname, ":", mac_lineno, - ": error: unfinished .macro `", mac_name ,"'\n") - end -end - ------------------------------------------------------------------------------- - --- Support variables for captures. -local cap_lineno, cap_name -local cap_buffers = {} -local cap_used = {} - --- Start a capture. -map_coreop[".capture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - if cap_name then - wfatal("already capturing to `"..cap_name.."' since line "..cap_lineno) - end - cap_name = name - cap_lineno = g_lineno - -- Create or continue a capture buffer and start the output line capture. - local buf = cap_buffers[name] - if not buf then buf = {}; cap_buffers[name] = buf end - g_capbuffer = buf - g_synclineno = 0 -end - --- Stop a capture. -map_coreop[".endcapture_0"] = function(params) - wflush() - if not cap_name then wfatal(".endcapture without a valid .capture") end - cap_name = nil - cap_lineno = nil - g_capbuffer = nil - g_synclineno = 0 -end - --- Dump a capture buffer. -map_coreop[".dumpcapture_1"] = function(params) - if not params then return "name" end - wflush() - local name = params[1] - if not match(name, "^[%a_][%w_]*$") then - wfatal("bad capture name `"..name.."'") - end - cap_used[name] = true - wline(function(out) - local buf = cap_buffers[name] - if buf then wdumplines(out, buf) end - end) - g_synclineno = 0 -end - --- Dump all captures and their buffers (with -PP only). -local function dumpcaptures(out, lvl) - out:write("Captures:\n") - for name,buf in pairs(cap_buffers) do - out:write(format(" %-20s %4s)\n", name, "("..#buf)) - if lvl > 1 then - local bar = rep("=", 76) - out:write(" ", bar, "\n") - for _,line in ipairs(buf) do - out:write(" ", line, "\n") - end - out:write(" ", bar, "\n\n") - end - end - out:write("\n") -end - --- Check for unfinished or unused captures. -local function checkcaptures() - if cap_name then - wprinterr(g_fname, ":", cap_lineno, - ": error: unfinished .capture `", cap_name,"'\n") - return - end - for name in pairs(cap_buffers) do - if not cap_used[name] then - wprinterr(g_fname, ":*: error: missing .dumpcapture ", name ,"\n") - end - end -end - ------------------------------------------------------------------------------- - --- Sections names. -local map_sections = {} - --- Pseudo-opcode to define code sections. --- TODO: Data sections, BSS sections. Needs extra C code and API. -map_coreop[".section_*"] = function(params) - if not params then return "name..." end - if #map_sections > 0 then werror("duplicate section definition") end - wflush() - for sn,name in ipairs(params) do - local opname = "."..name.."_0" - if not match(name, "^[%a][%w_]*$") or - map_op[opname] or map_op["."..name.."_*"] then - werror("bad section name `"..name.."'") - end - map_sections[#map_sections+1] = name - wline(format("#define DASM_SECTION_%s\t%d", upper(name), sn-1)) - map_op[opname] = function(params) g_arch.section(sn-1) end - end - wline(format("#define DASM_MAXSECTION\t\t%d", #map_sections)) -end - --- Dump all sections. -local function dumpsections(out, lvl) - out:write("Sections:\n") - for _,name in ipairs(map_sections) do - out:write(format(" %s\n", name)) - end - out:write("\n") -end - ------------------------------------------------------------------------------- - --- Replacement for customized Lua, which lacks the package library. -local prefix = "" -if not require then - function require(name) - local fp = assert(io.open(prefix..name..".lua")) - local s = fp:read("*a") - assert(fp:close()) - return assert(loadstring(s, "@"..name..".lua"))() - end -end - --- Load architecture-specific module. -local function loadarch(arch) - if not match(arch, "^[%w_]+$") then return "bad arch name" end - _G._map_def = map_def - local ok, m_arch = pcall(require, "dasm_"..arch) - if not ok then return "cannot load module: "..m_arch end - g_arch = m_arch - wflush = m_arch.passcb(wline, werror, wfatal, wwarn) - m_arch.setup(arch, g_opt) - map_op, map_def = m_arch.mergemaps(map_coreop, map_def) -end - --- Dump architecture description. -function opt_map.dumparch(args) - local name = optparam(args) - if not g_arch then - local err = loadarch(name) - if err then opterror(err) end - end - - local t = {} - for name in pairs(map_coreop) do t[#t+1] = name end - for name in pairs(map_op) do t[#t+1] = name end - sort(t) - - local out = stdout - local _arch = g_arch._info - out:write(format("%s version %s, released %s, %s\n", - _info.name, _info.version, _info.release, _info.url)) - g_arch.dumparch(out) - - local pseudo = true - out:write("Pseudo-Opcodes:\n") - for _,sname in ipairs(t) do - local name, nparam = match(sname, "^(.+)_([0-9%*])$") - if name then - if pseudo and sub(name, 1, 1) ~= "." then - out:write("\nOpcodes:\n") - pseudo = false - end - local f = map_op[sname] - local s - if nparam ~= "*" then nparam = nparam + 0 end - if nparam == 0 then - s = "" - elseif type(f) == "string" then - s = map_op[".template__"](nil, f, nparam) - else - s = f(nil, nparam) - end - if type(s) == "table" then - for _,s2 in ipairs(s) do - out:write(format(" %-12s %s\n", name, s2)) - end - else - out:write(format(" %-12s %s\n", name, s)) - end - end - end - out:write("\n") - exit(0) -end - --- Pseudo-opcode to set the architecture. --- Only initially available (map_op is replaced when called). -map_op[".arch_1"] = function(params) - if not params then return "name" end - local err = loadarch(params[1]) - if err then wfatal(err) end - wline(format("#if DASM_VERSION != %d", _info.vernum)) - wline('#error "Version mismatch between DynASM and included encoding engine"') - wline("#endif") -end - --- Dummy .arch pseudo-opcode to improve the error report. -map_coreop[".arch_1"] = function(params) - if not params then return "name" end - wfatal("duplicate .arch statement") -end - ------------------------------------------------------------------------------- - --- Dummy pseudo-opcode. Don't confuse '.nop' with 'nop'. -map_coreop[".nop_*"] = function(params) - if not params then return "[ignored...]" end -end - --- Pseudo-opcodes to raise errors. -map_coreop[".error_1"] = function(params) - if not params then return "message" end - werror(params[1]) -end - -map_coreop[".fatal_1"] = function(params) - if not params then return "message" end - wfatal(params[1]) -end - --- Dump all user defined elements. -local function dumpdef(out) - local lvl = g_opt.dumpdef - if lvl == 0 then return end - dumpsections(out, lvl) - dumpdefines(out, lvl) - if g_arch then g_arch.dumpdef(out, lvl) end - dumpmacros(out, lvl) - dumpcaptures(out, lvl) -end - ------------------------------------------------------------------------------- - --- Helper for splitstmt. -local splitlvl - -local function splitstmt_one(c) - if c == "(" then - splitlvl = ")"..splitlvl - elseif c == "[" then - splitlvl = "]"..splitlvl - elseif c == "{" then - splitlvl = "}"..splitlvl - elseif c == ")" or c == "]" or c == "}" then - if sub(splitlvl, 1, 1) ~= c then werror("unbalanced (), [] or {}") end - splitlvl = sub(splitlvl, 2) - elseif splitlvl == "" then - return " \0 " - end - return c -end - --- Split statement into (pseudo-)opcode and params. -local function splitstmt(stmt) - -- Convert label with trailing-colon into .label statement. - local label = match(stmt, "^%s*(.+):%s*$") - if label then return ".label", {label} end - - -- Split at commas and equal signs, but obey parentheses and brackets. - splitlvl = "" - stmt = gsub(stmt, "[,%(%)%[%]{}]", splitstmt_one) - if splitlvl ~= "" then werror("unbalanced () or []") end - - -- Split off opcode. - local op, other = match(stmt, "^%s*([^%s%z]+)%s*(.*)$") - if not op then werror("bad statement syntax") end - - -- Split parameters. - local params = {} - for p in gmatch(other, "%s*(%Z+)%z?") do - params[#params+1] = gsub(p, "%s+$", "") - end - if #params > 16 then werror("too many parameters") end - - params.op = op - return op, params -end - --- Process a single statement. -dostmt = function(stmt) - -- Ignore empty statements. - if match(stmt, "^%s*$") then return end - - -- Capture macro defs before substitution. - if mac_capture then return mac_capture(stmt) end - stmt = definesubst(stmt) - - -- Emit C code without parsing the line. - if sub(stmt, 1, 1) == "|" then - local tail = sub(stmt, 2) - wflush() - if sub(tail, 1, 2) == "//" then wcomment(tail) else wline(tail, true) end - return - end - - -- Split into (pseudo-)opcode and params. - local op, params = splitstmt(stmt) - - -- Get opcode handler (matching # of parameters or generic handler). - local f = map_op[op.."_"..#params] or map_op[op.."_*"] - if not f then - if not g_arch then wfatal("first statement must be .arch") end - -- Improve error report. - for i=0,9 do - if map_op[op.."_"..i] then - werror("wrong number of parameters for `"..op.."'") - end - end - werror("unknown statement `"..op.."'") - end - - -- Call opcode handler or special handler for template strings. - if type(f) == "string" then - map_op[".template__"](params, f) - else - f(params) - end -end - --- Process a single line. -local function doline(line) - if g_opt.flushline then wflush() end - - -- Assembler line? - local indent, aline = match(line, "^(%s*)%|(.*)$") - if not aline then - -- No, plain C code line, need to flush first. - wflush() - wsync() - wline(line, false) - return - end - - g_indent = indent -- Remember current line indentation. - - -- Emit C code (even from macros). Avoids echo and line parsing. - if sub(aline, 1, 1) == "|" then - if not mac_capture then - wsync() - elseif g_opt.comment then - wsync() - wcomment(aline) - end - dostmt(aline) - return - end - - -- Echo assembler line as a comment. - if g_opt.comment then - wsync() - wcomment(aline) - end - - -- Strip assembler comments. - aline = gsub(aline, "//.*$", "") - - -- Split line into statements at semicolons. - if match(aline, ";") then - for stmt in gmatch(aline, "[^;]+") do dostmt(stmt) end - else - dostmt(aline) - end -end - ------------------------------------------------------------------------------- - --- Write DynASM header. -local function dasmhead(out) - out:write(format([[ -/* -** This file has been pre-processed with DynASM. -** %s -** DynASM version %s, DynASM %s version %s -** DO NOT EDIT! The original file is in "%s". -*/ - -]], _info.url, - _info.version, g_arch._info.arch, g_arch._info.version, - g_fname)) -end - --- Read input file. -readfile = function(fin) - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Process all lines. - for line in fin:lines() do - g_lineno = g_lineno + 1 - g_curline = line - local ok, err = pcall(doline, line) - if not ok and wprinterr(err, "\n") then return true end - end - wflush() - - -- Close input file. - assert(fin == stdin or fin:close()) -end - --- Write output file. -local function writefile(outfile) - local fout - - -- Open output file. - if outfile == nil or outfile == "-" then - fout = stdout - else - fout = assert(io.open(outfile, "w")) - end - - -- Write all buffered lines - wdumplines(fout, g_wbuffer) - - -- Close output file. - assert(fout == stdout or fout:close()) - - -- Optionally dump definitions. - dumpdef(fout == stdout and stderr or stdout) -end - --- Translate an input file to an output file. -local function translate(infile, outfile) - g_wbuffer = {} - g_indent = "" - g_lineno = 0 - g_synclineno = -1 - - -- Put header. - wline(dasmhead) - - -- Read input file. - local fin - if infile == "-" then - g_fname = "(stdin)" - fin = stdin - else - g_fname = infile - fin = assert(io.open(infile, "r")) - end - readfile(fin) - - -- Check for errors. - if not g_arch then - wprinterr(g_fname, ":*: error: missing .arch directive\n") - end - checkconds() - checkmacros() - checkcaptures() - - if g_errcount ~= 0 then - stderr:write(g_fname, ":*: info: ", g_errcount, " error", - (type(g_errcount) == "number" and g_errcount > 1) and "s" or "", - " in input file -- no output file generated.\n") - dumpdef(stderr) - exit(1) - end - - -- Write output file. - writefile(outfile) -end - ------------------------------------------------------------------------------- - --- Print help text. -function opt_map.help() - stdout:write("DynASM -- ", _info.description, ".\n") - stdout:write("DynASM ", _info.version, " ", _info.release, " ", _info.url, "\n") - stdout:write[[ - -Usage: dynasm [OPTION]... INFILE.dasc|- - - -h, --help Display this help text. - -V, --version Display version and copyright information. - - -o, --outfile FILE Output file name (default is stdout). - -I, --include DIR Add directory to the include search path. - - -c, --ccomment Use /* */ comments for assembler lines. - -C, --cppcomment Use // comments for assembler lines (default). - -N, --nocomment Suppress assembler lines in output. - -M, --maccomment Show macro expansions as comments (default off). - - -L, --nolineno Suppress CPP line number information in output. - -F, --flushline Flush action list for every line. - - -D NAME[=SUBST] Define a substitution. - -U NAME Undefine a substitution. - - -P, --dumpdef Dump defines, macros, etc. Repeat for more output. - -A, --dumparch ARCH Load architecture ARCH and dump description. -]] - exit(0) -end - --- Print version information. -function opt_map.version() - stdout:write(format("%s version %s, released %s\n%s\n\n%s", - _info.name, _info.version, _info.release, _info.url, _info.copyright)) - exit(0) -end - --- Misc. options. -function opt_map.outfile(args) g_opt.outfile = optparam(args) end -function opt_map.include(args) insert(g_opt.include, 1, optparam(args)) end -function opt_map.ccomment() g_opt.comment = "/*|"; g_opt.endcomment = " */" end -function opt_map.cppcomment() g_opt.comment = "//|"; g_opt.endcomment = "" end -function opt_map.nocomment() g_opt.comment = false end -function opt_map.maccomment() g_opt.maccomment = true end -function opt_map.nolineno() g_opt.cpp = false end -function opt_map.flushline() g_opt.flushline = true end -function opt_map.dumpdef() g_opt.dumpdef = g_opt.dumpdef + 1 end - ------------------------------------------------------------------------------- - --- Short aliases for long options. -local opt_alias = { - h = "help", ["?"] = "help", V = "version", - o = "outfile", I = "include", - c = "ccomment", C = "cppcomment", N = "nocomment", M = "maccomment", - L = "nolineno", F = "flushline", - P = "dumpdef", A = "dumparch", -} - --- Parse single option. -local function parseopt(opt, args) - opt_current = #opt == 1 and "-"..opt or "--"..opt - local f = opt_map[opt] or opt_map[opt_alias[opt]] - if not f then - opterror("unrecognized option `", opt_current, "'. Try `--help'.\n") - end - f(args) -end - --- Parse arguments. -local function parseargs(args) - -- Default options. - g_opt.comment = "//|" - g_opt.endcomment = "" - g_opt.cpp = true - g_opt.dumpdef = 0 - g_opt.include = { "" } - - -- Process all option arguments. - args.argn = 1 - repeat - local a = args[args.argn] - if not a then break end - local lopt, opt = match(a, "^%-(%-?)(.+)") - if not opt then break end - args.argn = args.argn + 1 - if lopt == "" then - -- Loop through short options. - for o in gmatch(opt, ".") do parseopt(o, args) end - else - -- Long option. - parseopt(opt, args) - end - until false - - -- Check for proper number of arguments. - local nargs = #args - args.argn + 1 - if nargs ~= 1 then - if nargs == 0 then - if g_opt.dumpdef > 0 then return dumpdef(stdout) end - end - opt_map.help() - end - - -- Translate a single input file to a single output file - -- TODO: Handle multiple files? - translate(args[args.argn], g_opt.outfile) -end - ------------------------------------------------------------------------------- - --- Add the directory dynasm.lua resides in to the Lua module search path. -local arg = arg -if arg and arg[0] then - prefix = match(arg[0], "^(.*[/\\])") - if package and prefix then package.path = prefix.."?.lua;"..package.path end -end - --- Start DynASM. -parseargs{...} - ------------------------------------------------------------------------------- - diff --git a/ext/opcache/jit/dynasm/minilua.c b/ext/opcache/jit/dynasm/minilua.c deleted file mode 100644 index a8d7c305e109e..0000000000000 --- a/ext/opcache/jit/dynasm/minilua.c +++ /dev/null @@ -1,7770 +0,0 @@ -/* This is a heavily customized and minimized copy of Lua 5.1.5. */ -/* It's only used to build LuaJIT. It does NOT have all standard functions! */ -/****************************************************************************** -* Copyright (C) 1994-2012 Lua.org, PUC-Rio. All rights reserved. -* -* 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. -******************************************************************************/ -#ifdef _MSC_VER -typedef unsigned __int64 U64; -#else -typedef unsigned long long U64; -#endif -int _CRT_glob = 0; -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -typedef enum{ -TM_INDEX, -TM_NEWINDEX, -TM_GC, -TM_MODE, -TM_EQ, -TM_ADD, -TM_SUB, -TM_MUL, -TM_DIV, -TM_MOD, -TM_POW, -TM_UNM, -TM_LEN, -TM_LT, -TM_LE, -TM_CONCAT, -TM_CALL, -TM_N -}TMS; -enum OpMode{iABC,iABx,iAsBx}; -typedef enum{ -OP_MOVE, -OP_LOADK, -OP_LOADBOOL, -OP_LOADNIL, -OP_GETUPVAL, -OP_GETGLOBAL, -OP_GETTABLE, -OP_SETGLOBAL, -OP_SETUPVAL, -OP_SETTABLE, -OP_NEWTABLE, -OP_SELF, -OP_ADD, -OP_SUB, -OP_MUL, -OP_DIV, -OP_MOD, -OP_POW, -OP_UNM, -OP_NOT, -OP_LEN, -OP_CONCAT, -OP_JMP, -OP_EQ, -OP_LT, -OP_LE, -OP_TEST, -OP_TESTSET, -OP_CALL, -OP_TAILCALL, -OP_RETURN, -OP_FORLOOP, -OP_FORPREP, -OP_TFORLOOP, -OP_SETLIST, -OP_CLOSE, -OP_CLOSURE, -OP_VARARG -}OpCode; -enum OpArgMask{ -OpArgN, -OpArgU, -OpArgR, -OpArgK -}; -typedef enum{ -VVOID, -VNIL, -VTRUE, -VFALSE, -VK, -VKNUM, -VLOCAL, -VUPVAL, -VGLOBAL, -VINDEXED, -VJMP, -VRELOCABLE, -VNONRELOC, -VCALL, -VVARARG -}expkind; -enum RESERVED{ -TK_AND=257,TK_BREAK, -TK_DO,TK_ELSE,TK_ELSEIF,TK_END,TK_FALSE,TK_FOR,TK_FUNCTION, -TK_IF,TK_IN,TK_LOCAL,TK_NIL,TK_NOT,TK_OR,TK_REPEAT, -TK_RETURN,TK_THEN,TK_TRUE,TK_UNTIL,TK_WHILE, -TK_CONCAT,TK_DOTS,TK_EQ,TK_GE,TK_LE,TK_NE,TK_NUMBER, -TK_NAME,TK_STRING,TK_EOS -}; -typedef enum BinOpr{ -OPR_ADD,OPR_SUB,OPR_MUL,OPR_DIV,OPR_MOD,OPR_POW, -OPR_CONCAT, -OPR_NE,OPR_EQ, -OPR_LT,OPR_LE,OPR_GT,OPR_GE, -OPR_AND,OPR_OR, -OPR_NOBINOPR -}BinOpr; -typedef enum UnOpr{OPR_MINUS,OPR_NOT,OPR_LEN,OPR_NOUNOPR}UnOpr; -#define LUA_QL(x)"'"x"'" -#define luai_apicheck(L,o){(void)L;} -#define lua_number2str(s,n)sprintf((s),"%.14g",(n)) -#define lua_str2number(s,p)strtod((s),(p)) -#define luai_numadd(a,b)((a)+(b)) -#define luai_numsub(a,b)((a)-(b)) -#define luai_nummul(a,b)((a)*(b)) -#define luai_numdiv(a,b)((a)/(b)) -#define luai_nummod(a,b)((a)-floor((a)/(b))*(b)) -#define luai_numpow(a,b)(pow(a,b)) -#define luai_numunm(a)(-(a)) -#define luai_numeq(a,b)((a)==(b)) -#define luai_numlt(a,b)((a)<(b)) -#define luai_numle(a,b)((a)<=(b)) -#define luai_numisnan(a)(!luai_numeq((a),(a))) -#define lua_number2int(i,d)((i)=(int)(d)) -#define lua_number2integer(i,d)((i)=(lua_Integer)(d)) -#define LUAI_THROW(L,c)longjmp((c)->b,1) -#define LUAI_TRY(L,c,a)if(setjmp((c)->b)==0){a} -#define lua_pclose(L,file)((void)((void)L,file),0) -#define lua_upvalueindex(i)((-10002)-(i)) -typedef struct lua_State lua_State; -typedef int(*lua_CFunction)(lua_State*L); -typedef const char*(*lua_Reader)(lua_State*L,void*ud,size_t*sz); -typedef void*(*lua_Alloc)(void*ud,void*ptr,size_t osize,size_t nsize); -typedef double lua_Number; -typedef ptrdiff_t lua_Integer; -static void lua_settop(lua_State*L,int idx); -static int lua_type(lua_State*L,int idx); -static const char* lua_tolstring(lua_State*L,int idx,size_t*len); -static size_t lua_objlen(lua_State*L,int idx); -static void lua_pushlstring(lua_State*L,const char*s,size_t l); -static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n); -static void lua_createtable(lua_State*L,int narr,int nrec); -static void lua_setfield(lua_State*L,int idx,const char*k); -#define lua_pop(L,n)lua_settop(L,-(n)-1) -#define lua_newtable(L)lua_createtable(L,0,0) -#define lua_pushcfunction(L,f)lua_pushcclosure(L,(f),0) -#define lua_strlen(L,i)lua_objlen(L,(i)) -#define lua_isfunction(L,n)(lua_type(L,(n))==6) -#define lua_istable(L,n)(lua_type(L,(n))==5) -#define lua_isnil(L,n)(lua_type(L,(n))==0) -#define lua_isboolean(L,n)(lua_type(L,(n))==1) -#define lua_isnone(L,n)(lua_type(L,(n))==(-1)) -#define lua_isnoneornil(L,n)(lua_type(L,(n))<=0) -#define lua_pushliteral(L,s)lua_pushlstring(L,""s,(sizeof(s)/sizeof(char))-1) -#define lua_setglobal(L,s)lua_setfield(L,(-10002),(s)) -#define lua_tostring(L,i)lua_tolstring(L,(i),NULL) -typedef struct lua_Debug lua_Debug; -typedef void(*lua_Hook)(lua_State*L,lua_Debug*ar); -struct lua_Debug{ -int event; -const char*name; -const char*namewhat; -const char*what; -const char*source; -int currentline; -int nups; -int linedefined; -int lastlinedefined; -char short_src[60]; -int i_ci; -}; -typedef unsigned int lu_int32; -typedef size_t lu_mem; -typedef ptrdiff_t l_mem; -typedef unsigned char lu_byte; -#define IntPoint(p)((unsigned int)(lu_mem)(p)) -typedef union{double u;void*s;long l;}L_Umaxalign; -typedef double l_uacNumber; -#define check_exp(c,e)(e) -#define UNUSED(x)((void)(x)) -#define cast(t,exp)((t)(exp)) -#define cast_byte(i)cast(lu_byte,(i)) -#define cast_num(i)cast(lua_Number,(i)) -#define cast_int(i)cast(int,(i)) -typedef lu_int32 Instruction; -#define condhardstacktests(x)((void)0) -typedef union GCObject GCObject; -typedef struct GCheader{ -GCObject*next;lu_byte tt;lu_byte marked; -}GCheader; -typedef union{ -GCObject*gc; -void*p; -lua_Number n; -int b; -}Value; -typedef struct lua_TValue{ -Value value;int tt; -}TValue; -#define ttisnil(o)(ttype(o)==0) -#define ttisnumber(o)(ttype(o)==3) -#define ttisstring(o)(ttype(o)==4) -#define ttistable(o)(ttype(o)==5) -#define ttisfunction(o)(ttype(o)==6) -#define ttisboolean(o)(ttype(o)==1) -#define ttisuserdata(o)(ttype(o)==7) -#define ttisthread(o)(ttype(o)==8) -#define ttislightuserdata(o)(ttype(o)==2) -#define ttype(o)((o)->tt) -#define gcvalue(o)check_exp(iscollectable(o),(o)->value.gc) -#define pvalue(o)check_exp(ttislightuserdata(o),(o)->value.p) -#define nvalue(o)check_exp(ttisnumber(o),(o)->value.n) -#define rawtsvalue(o)check_exp(ttisstring(o),&(o)->value.gc->ts) -#define tsvalue(o)(&rawtsvalue(o)->tsv) -#define rawuvalue(o)check_exp(ttisuserdata(o),&(o)->value.gc->u) -#define uvalue(o)(&rawuvalue(o)->uv) -#define clvalue(o)check_exp(ttisfunction(o),&(o)->value.gc->cl) -#define hvalue(o)check_exp(ttistable(o),&(o)->value.gc->h) -#define bvalue(o)check_exp(ttisboolean(o),(o)->value.b) -#define thvalue(o)check_exp(ttisthread(o),&(o)->value.gc->th) -#define l_isfalse(o)(ttisnil(o)||(ttisboolean(o)&&bvalue(o)==0)) -#define checkconsistency(obj) -#define checkliveness(g,obj) -#define setnilvalue(obj)((obj)->tt=0) -#define setnvalue(obj,x){TValue*i_o=(obj);i_o->value.n=(x);i_o->tt=3;} -#define setbvalue(obj,x){TValue*i_o=(obj);i_o->value.b=(x);i_o->tt=1;} -#define setsvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=4;checkliveness(G(L),i_o);} -#define setuvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=7;checkliveness(G(L),i_o);} -#define setthvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=8;checkliveness(G(L),i_o);} -#define setclvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=6;checkliveness(G(L),i_o);} -#define sethvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=5;checkliveness(G(L),i_o);} -#define setptvalue(L,obj,x){TValue*i_o=(obj);i_o->value.gc=cast(GCObject*,(x));i_o->tt=(8+1);checkliveness(G(L),i_o);} -#define setobj(L,obj1,obj2){const TValue*o2=(obj2);TValue*o1=(obj1);o1->value=o2->value;o1->tt=o2->tt;checkliveness(G(L),o1);} -#define setttype(obj,tt)(ttype(obj)=(tt)) -#define iscollectable(o)(ttype(o)>=4) -typedef TValue*StkId; -typedef union TString{ -L_Umaxalign dummy; -struct{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte reserved; -unsigned int hash; -size_t len; -}tsv; -}TString; -#define getstr(ts)cast(const char*,(ts)+1) -#define svalue(o)getstr(rawtsvalue(o)) -typedef union Udata{ -L_Umaxalign dummy; -struct{ -GCObject*next;lu_byte tt;lu_byte marked; -struct Table*metatable; -struct Table*env; -size_t len; -}uv; -}Udata; -typedef struct Proto{ -GCObject*next;lu_byte tt;lu_byte marked; -TValue*k; -Instruction*code; -struct Proto**p; -int*lineinfo; -struct LocVar*locvars; -TString**upvalues; -TString*source; -int sizeupvalues; -int sizek; -int sizecode; -int sizelineinfo; -int sizep; -int sizelocvars; -int linedefined; -int lastlinedefined; -GCObject*gclist; -lu_byte nups; -lu_byte numparams; -lu_byte is_vararg; -lu_byte maxstacksize; -}Proto; -typedef struct LocVar{ -TString*varname; -int startpc; -int endpc; -}LocVar; -typedef struct UpVal{ -GCObject*next;lu_byte tt;lu_byte marked; -TValue*v; -union{ -TValue value; -struct{ -struct UpVal*prev; -struct UpVal*next; -}l; -}u; -}UpVal; -typedef struct CClosure{ -GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env; -lua_CFunction f; -TValue upvalue[1]; -}CClosure; -typedef struct LClosure{ -GCObject*next;lu_byte tt;lu_byte marked;lu_byte isC;lu_byte nupvalues;GCObject*gclist;struct Table*env; -struct Proto*p; -UpVal*upvals[1]; -}LClosure; -typedef union Closure{ -CClosure c; -LClosure l; -}Closure; -#define iscfunction(o)(ttype(o)==6&&clvalue(o)->c.isC) -typedef union TKey{ -struct{ -Value value;int tt; -struct Node*next; -}nk; -TValue tvk; -}TKey; -typedef struct Node{ -TValue i_val; -TKey i_key; -}Node; -typedef struct Table{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte flags; -lu_byte lsizenode; -struct Table*metatable; -TValue*array; -Node*node; -Node*lastfree; -GCObject*gclist; -int sizearray; -}Table; -#define lmod(s,size)(check_exp((size&(size-1))==0,(cast(int,(s)&((size)-1))))) -#define twoto(x)((size_t)1<<(x)) -#define sizenode(t)(twoto((t)->lsizenode)) -static const TValue luaO_nilobject_; -#define ceillog2(x)(luaO_log2((x)-1)+1) -static int luaO_log2(unsigned int x); -#define gfasttm(g,et,e)((et)==NULL?NULL:((et)->flags&(1u<<(e)))?NULL:luaT_gettm(et,e,(g)->tmname[e])) -#define fasttm(l,et,e)gfasttm(G(l),et,e) -static const TValue*luaT_gettm(Table*events,TMS event,TString*ename); -#define luaM_reallocv(L,b,on,n,e)((cast(size_t,(n)+1)<=((size_t)(~(size_t)0)-2)/(e))?luaM_realloc_(L,(b),(on)*(e),(n)*(e)):luaM_toobig(L)) -#define luaM_freemem(L,b,s)luaM_realloc_(L,(b),(s),0) -#define luaM_free(L,b)luaM_realloc_(L,(b),sizeof(*(b)),0) -#define luaM_freearray(L,b,n,t)luaM_reallocv(L,(b),n,0,sizeof(t)) -#define luaM_malloc(L,t)luaM_realloc_(L,NULL,0,(t)) -#define luaM_new(L,t)cast(t*,luaM_malloc(L,sizeof(t))) -#define luaM_newvector(L,n,t)cast(t*,luaM_reallocv(L,NULL,0,n,sizeof(t))) -#define luaM_growvector(L,v,nelems,size,t,limit,e)if((nelems)+1>(size))((v)=cast(t*,luaM_growaux_(L,v,&(size),sizeof(t),limit,e))) -#define luaM_reallocvector(L,v,oldn,n,t)((v)=cast(t*,luaM_reallocv(L,v,oldn,n,sizeof(t)))) -static void*luaM_realloc_(lua_State*L,void*block,size_t oldsize, -size_t size); -static void*luaM_toobig(lua_State*L); -static void*luaM_growaux_(lua_State*L,void*block,int*size, -size_t size_elem,int limit, -const char*errormsg); -typedef struct Zio ZIO; -#define char2int(c)cast(int,cast(unsigned char,(c))) -#define zgetc(z)(((z)->n--)>0?char2int(*(z)->p++):luaZ_fill(z)) -typedef struct Mbuffer{ -char*buffer; -size_t n; -size_t buffsize; -}Mbuffer; -#define luaZ_initbuffer(L,buff)((buff)->buffer=NULL,(buff)->buffsize=0) -#define luaZ_buffer(buff)((buff)->buffer) -#define luaZ_sizebuffer(buff)((buff)->buffsize) -#define luaZ_bufflen(buff)((buff)->n) -#define luaZ_resetbuffer(buff)((buff)->n=0) -#define luaZ_resizebuffer(L,buff,size)(luaM_reallocvector(L,(buff)->buffer,(buff)->buffsize,size,char),(buff)->buffsize=size) -#define luaZ_freebuffer(L,buff)luaZ_resizebuffer(L,buff,0) -struct Zio{ -size_t n; -const char*p; -lua_Reader reader; -void*data; -lua_State*L; -}; -static int luaZ_fill(ZIO*z); -struct lua_longjmp; -#define gt(L)(&L->l_gt) -#define registry(L)(&G(L)->l_registry) -typedef struct stringtable{ -GCObject**hash; -lu_int32 nuse; -int size; -}stringtable; -typedef struct CallInfo{ -StkId base; -StkId func; -StkId top; -const Instruction*savedpc; -int nresults; -int tailcalls; -}CallInfo; -#define curr_func(L)(clvalue(L->ci->func)) -#define ci_func(ci)(clvalue((ci)->func)) -#define f_isLua(ci)(!ci_func(ci)->c.isC) -#define isLua(ci)(ttisfunction((ci)->func)&&f_isLua(ci)) -typedef struct global_State{ -stringtable strt; -lua_Alloc frealloc; -void*ud; -lu_byte currentwhite; -lu_byte gcstate; -int sweepstrgc; -GCObject*rootgc; -GCObject**sweepgc; -GCObject*gray; -GCObject*grayagain; -GCObject*weak; -GCObject*tmudata; -Mbuffer buff; -lu_mem GCthreshold; -lu_mem totalbytes; -lu_mem estimate; -lu_mem gcdept; -int gcpause; -int gcstepmul; -lua_CFunction panic; -TValue l_registry; -struct lua_State*mainthread; -UpVal uvhead; -struct Table*mt[(8+1)]; -TString*tmname[TM_N]; -}global_State; -struct lua_State{ -GCObject*next;lu_byte tt;lu_byte marked; -lu_byte status; -StkId top; -StkId base; -global_State*l_G; -CallInfo*ci; -const Instruction*savedpc; -StkId stack_last; -StkId stack; -CallInfo*end_ci; -CallInfo*base_ci; -int stacksize; -int size_ci; -unsigned short nCcalls; -unsigned short baseCcalls; -lu_byte hookmask; -lu_byte allowhook; -int basehookcount; -int hookcount; -lua_Hook hook; -TValue l_gt; -TValue env; -GCObject*openupval; -GCObject*gclist; -struct lua_longjmp*errorJmp; -ptrdiff_t errfunc; -}; -#define G(L)(L->l_G) -union GCObject{ -GCheader gch; -union TString ts; -union Udata u; -union Closure cl; -struct Table h; -struct Proto p; -struct UpVal uv; -struct lua_State th; -}; -#define rawgco2ts(o)check_exp((o)->gch.tt==4,&((o)->ts)) -#define gco2ts(o)(&rawgco2ts(o)->tsv) -#define rawgco2u(o)check_exp((o)->gch.tt==7,&((o)->u)) -#define gco2u(o)(&rawgco2u(o)->uv) -#define gco2cl(o)check_exp((o)->gch.tt==6,&((o)->cl)) -#define gco2h(o)check_exp((o)->gch.tt==5,&((o)->h)) -#define gco2p(o)check_exp((o)->gch.tt==(8+1),&((o)->p)) -#define gco2uv(o)check_exp((o)->gch.tt==(8+2),&((o)->uv)) -#define ngcotouv(o)check_exp((o)==NULL||(o)->gch.tt==(8+2),&((o)->uv)) -#define gco2th(o)check_exp((o)->gch.tt==8,&((o)->th)) -#define obj2gco(v)(cast(GCObject*,(v))) -static void luaE_freethread(lua_State*L,lua_State*L1); -#define pcRel(pc,p)(cast(int,(pc)-(p)->code)-1) -#define getline_(f,pc)(((f)->lineinfo)?(f)->lineinfo[pc]:0) -#define resethookcount(L)(L->hookcount=L->basehookcount) -static void luaG_typeerror(lua_State*L,const TValue*o, -const char*opname); -static void luaG_runerror(lua_State*L,const char*fmt,...); -#define luaD_checkstack(L,n)if((char*)L->stack_last-(char*)L->top<=(n)*(int)sizeof(TValue))luaD_growstack(L,n);else condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1)); -#define incr_top(L){luaD_checkstack(L,1);L->top++;} -#define savestack(L,p)((char*)(p)-(char*)L->stack) -#define restorestack(L,n)((TValue*)((char*)L->stack+(n))) -#define saveci(L,p)((char*)(p)-(char*)L->base_ci) -#define restoreci(L,n)((CallInfo*)((char*)L->base_ci+(n))) -typedef void(*Pfunc)(lua_State*L,void*ud); -static int luaD_poscall(lua_State*L,StkId firstResult); -static void luaD_reallocCI(lua_State*L,int newsize); -static void luaD_reallocstack(lua_State*L,int newsize); -static void luaD_growstack(lua_State*L,int n); -static void luaD_throw(lua_State*L,int errcode); -static void*luaM_growaux_(lua_State*L,void*block,int*size,size_t size_elems, -int limit,const char*errormsg){ -void*newblock; -int newsize; -if(*size>=limit/2){ -if(*size>=limit) -luaG_runerror(L,errormsg); -newsize=limit; -} -else{ -newsize=(*size)*2; -if(newsize<4) -newsize=4; -} -newblock=luaM_reallocv(L,block,*size,newsize,size_elems); -*size=newsize; -return newblock; -} -static void*luaM_toobig(lua_State*L){ -luaG_runerror(L,"memory allocation error: block too big"); -return NULL; -} -static void*luaM_realloc_(lua_State*L,void*block,size_t osize,size_t nsize){ -global_State*g=G(L); -block=(*g->frealloc)(g->ud,block,osize,nsize); -if(block==NULL&&nsize>0) -luaD_throw(L,4); -g->totalbytes=(g->totalbytes-osize)+nsize; -return block; -} -#define resetbits(x,m)((x)&=cast(lu_byte,~(m))) -#define setbits(x,m)((x)|=(m)) -#define testbits(x,m)((x)&(m)) -#define bitmask(b)(1<<(b)) -#define bit2mask(b1,b2)(bitmask(b1)|bitmask(b2)) -#define l_setbit(x,b)setbits(x,bitmask(b)) -#define resetbit(x,b)resetbits(x,bitmask(b)) -#define testbit(x,b)testbits(x,bitmask(b)) -#define set2bits(x,b1,b2)setbits(x,(bit2mask(b1,b2))) -#define reset2bits(x,b1,b2)resetbits(x,(bit2mask(b1,b2))) -#define test2bits(x,b1,b2)testbits(x,(bit2mask(b1,b2))) -#define iswhite(x)test2bits((x)->gch.marked,0,1) -#define isblack(x)testbit((x)->gch.marked,2) -#define isgray(x)(!isblack(x)&&!iswhite(x)) -#define otherwhite(g)(g->currentwhite^bit2mask(0,1)) -#define isdead(g,v)((v)->gch.marked&otherwhite(g)&bit2mask(0,1)) -#define changewhite(x)((x)->gch.marked^=bit2mask(0,1)) -#define gray2black(x)l_setbit((x)->gch.marked,2) -#define valiswhite(x)(iscollectable(x)&&iswhite(gcvalue(x))) -#define luaC_white(g)cast(lu_byte,(g)->currentwhite&bit2mask(0,1)) -#define luaC_checkGC(L){condhardstacktests(luaD_reallocstack(L,L->stacksize-5-1));if(G(L)->totalbytes>=G(L)->GCthreshold)luaC_step(L);} -#define luaC_barrier(L,p,v){if(valiswhite(v)&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),gcvalue(v));} -#define luaC_barriert(L,t,v){if(valiswhite(v)&&isblack(obj2gco(t)))luaC_barrierback(L,t);} -#define luaC_objbarrier(L,p,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(p)))luaC_barrierf(L,obj2gco(p),obj2gco(o));} -#define luaC_objbarriert(L,t,o){if(iswhite(obj2gco(o))&&isblack(obj2gco(t)))luaC_barrierback(L,t);} -static void luaC_step(lua_State*L); -static void luaC_link(lua_State*L,GCObject*o,lu_byte tt); -static void luaC_linkupval(lua_State*L,UpVal*uv); -static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v); -static void luaC_barrierback(lua_State*L,Table*t); -#define sizestring(s)(sizeof(union TString)+((s)->len+1)*sizeof(char)) -#define sizeudata(u)(sizeof(union Udata)+(u)->len) -#define luaS_new(L,s)(luaS_newlstr(L,s,strlen(s))) -#define luaS_newliteral(L,s)(luaS_newlstr(L,""s,(sizeof(s)/sizeof(char))-1)) -#define luaS_fix(s)l_setbit((s)->tsv.marked,5) -static TString*luaS_newlstr(lua_State*L,const char*str,size_t l); -#define tostring(L,o)((ttype(o)==4)||(luaV_tostring(L,o))) -#define tonumber(o,n)(ttype(o)==3||(((o)=luaV_tonumber(o,n))!=NULL)) -#define equalobj(L,o1,o2)(ttype(o1)==ttype(o2)&&luaV_equalval(L,o1,o2)) -static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2); -static const TValue*luaV_tonumber(const TValue*obj,TValue*n); -static int luaV_tostring(lua_State*L,StkId obj); -static void luaV_execute(lua_State*L,int nexeccalls); -static void luaV_concat(lua_State*L,int total,int last); -static const TValue luaO_nilobject_={{NULL},0}; -static int luaO_int2fb(unsigned int x){ -int e=0; -while(x>=16){ -x=(x+1)>>1; -e++; -} -if(x<8)return x; -else return((e+1)<<3)|(cast_int(x)-8); -} -static int luaO_fb2int(int x){ -int e=(x>>3)&31; -if(e==0)return x; -else return((x&7)+8)<<(e-1); -} -static int luaO_log2(unsigned int x){ -static const lu_byte log_2[256]={ -0,1,2,2,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, -6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, -7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, -7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, -8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8 -}; -int l=-1; -while(x>=256){l+=8;x>>=8;} -return l+log_2[x]; -} -static int luaO_rawequalObj(const TValue*t1,const TValue*t2){ -if(ttype(t1)!=ttype(t2))return 0; -else switch(ttype(t1)){ -case 0: -return 1; -case 3: -return luai_numeq(nvalue(t1),nvalue(t2)); -case 1: -return bvalue(t1)==bvalue(t2); -case 2: -return pvalue(t1)==pvalue(t2); -default: -return gcvalue(t1)==gcvalue(t2); -} -} -static int luaO_str2d(const char*s,lua_Number*result){ -char*endptr; -*result=lua_str2number(s,&endptr); -if(endptr==s)return 0; -if(*endptr=='x'||*endptr=='X') -*result=cast_num(strtoul(s,&endptr,16)); -if(*endptr=='\0')return 1; -while(isspace(cast(unsigned char,*endptr)))endptr++; -if(*endptr!='\0')return 0; -return 1; -} -static void pushstr(lua_State*L,const char*str){ -setsvalue(L,L->top,luaS_new(L,str)); -incr_top(L); -} -static const char*luaO_pushvfstring(lua_State*L,const char*fmt,va_list argp){ -int n=1; -pushstr(L,""); -for(;;){ -const char*e=strchr(fmt,'%'); -if(e==NULL)break; -setsvalue(L,L->top,luaS_newlstr(L,fmt,e-fmt)); -incr_top(L); -switch(*(e+1)){ -case's':{ -const char*s=va_arg(argp,char*); -if(s==NULL)s="(null)"; -pushstr(L,s); -break; -} -case'c':{ -char buff[2]; -buff[0]=cast(char,va_arg(argp,int)); -buff[1]='\0'; -pushstr(L,buff); -break; -} -case'd':{ -setnvalue(L->top,cast_num(va_arg(argp,int))); -incr_top(L); -break; -} -case'f':{ -setnvalue(L->top,cast_num(va_arg(argp,l_uacNumber))); -incr_top(L); -break; -} -case'p':{ -char buff[4*sizeof(void*)+8]; -sprintf(buff,"%p",va_arg(argp,void*)); -pushstr(L,buff); -break; -} -case'%':{ -pushstr(L,"%"); -break; -} -default:{ -char buff[3]; -buff[0]='%'; -buff[1]=*(e+1); -buff[2]='\0'; -pushstr(L,buff); -break; -} -} -n+=2; -fmt=e+2; -} -pushstr(L,fmt); -luaV_concat(L,n+1,cast_int(L->top-L->base)-1); -L->top-=n; -return svalue(L->top-1); -} -static const char*luaO_pushfstring(lua_State*L,const char*fmt,...){ -const char*msg; -va_list argp; -va_start(argp,fmt); -msg=luaO_pushvfstring(L,fmt,argp); -va_end(argp); -return msg; -} -static void luaO_chunkid(char*out,const char*source,size_t bufflen){ -if(*source=='='){ -strncpy(out,source+1,bufflen); -out[bufflen-1]='\0'; -} -else{ -if(*source=='@'){ -size_t l; -source++; -bufflen-=sizeof(" '...' "); -l=strlen(source); -strcpy(out,""); -if(l>bufflen){ -source+=(l-bufflen); -strcat(out,"..."); -} -strcat(out,source); -} -else{ -size_t len=strcspn(source,"\n\r"); -bufflen-=sizeof(" [string \"...\"] "); -if(len>bufflen)len=bufflen; -strcpy(out,"[string \""); -if(source[len]!='\0'){ -strncat(out,source,len); -strcat(out,"..."); -} -else -strcat(out,source); -strcat(out,"\"]"); -} -} -} -#define gnode(t,i)(&(t)->node[i]) -#define gkey(n)(&(n)->i_key.nk) -#define gval(n)(&(n)->i_val) -#define gnext(n)((n)->i_key.nk.next) -#define key2tval(n)(&(n)->i_key.tvk) -static TValue*luaH_setnum(lua_State*L,Table*t,int key); -static const TValue*luaH_getstr(Table*t,TString*key); -static TValue*luaH_set(lua_State*L,Table*t,const TValue*key); -static const char*const luaT_typenames[]={ -"nil","boolean","userdata","number", -"string","table","function","userdata","thread", -"proto","upval" -}; -static void luaT_init(lua_State*L){ -static const char*const luaT_eventname[]={ -"__index","__newindex", -"__gc","__mode","__eq", -"__add","__sub","__mul","__div","__mod", -"__pow","__unm","__len","__lt","__le", -"__concat","__call" -}; -int i; -for(i=0;itmname[i]=luaS_new(L,luaT_eventname[i]); -luaS_fix(G(L)->tmname[i]); -} -} -static const TValue*luaT_gettm(Table*events,TMS event,TString*ename){ -const TValue*tm=luaH_getstr(events,ename); -if(ttisnil(tm)){ -events->flags|=cast_byte(1u<metatable; -break; -case 7: -mt=uvalue(o)->metatable; -break; -default: -mt=G(L)->mt[ttype(o)]; -} -return(mt?luaH_getstr(mt,G(L)->tmname[event]):(&luaO_nilobject_)); -} -#define sizeCclosure(n)(cast(int,sizeof(CClosure))+cast(int,sizeof(TValue)*((n)-1))) -#define sizeLclosure(n)(cast(int,sizeof(LClosure))+cast(int,sizeof(TValue*)*((n)-1))) -static Closure*luaF_newCclosure(lua_State*L,int nelems,Table*e){ -Closure*c=cast(Closure*,luaM_malloc(L,sizeCclosure(nelems))); -luaC_link(L,obj2gco(c),6); -c->c.isC=1; -c->c.env=e; -c->c.nupvalues=cast_byte(nelems); -return c; -} -static Closure*luaF_newLclosure(lua_State*L,int nelems,Table*e){ -Closure*c=cast(Closure*,luaM_malloc(L,sizeLclosure(nelems))); -luaC_link(L,obj2gco(c),6); -c->l.isC=0; -c->l.env=e; -c->l.nupvalues=cast_byte(nelems); -while(nelems--)c->l.upvals[nelems]=NULL; -return c; -} -static UpVal*luaF_newupval(lua_State*L){ -UpVal*uv=luaM_new(L,UpVal); -luaC_link(L,obj2gco(uv),(8+2)); -uv->v=&uv->u.value; -setnilvalue(uv->v); -return uv; -} -static UpVal*luaF_findupval(lua_State*L,StkId level){ -global_State*g=G(L); -GCObject**pp=&L->openupval; -UpVal*p; -UpVal*uv; -while(*pp!=NULL&&(p=ngcotouv(*pp))->v>=level){ -if(p->v==level){ -if(isdead(g,obj2gco(p))) -changewhite(obj2gco(p)); -return p; -} -pp=&p->next; -} -uv=luaM_new(L,UpVal); -uv->tt=(8+2); -uv->marked=luaC_white(g); -uv->v=level; -uv->next=*pp; -*pp=obj2gco(uv); -uv->u.l.prev=&g->uvhead; -uv->u.l.next=g->uvhead.u.l.next; -uv->u.l.next->u.l.prev=uv; -g->uvhead.u.l.next=uv; -return uv; -} -static void unlinkupval(UpVal*uv){ -uv->u.l.next->u.l.prev=uv->u.l.prev; -uv->u.l.prev->u.l.next=uv->u.l.next; -} -static void luaF_freeupval(lua_State*L,UpVal*uv){ -if(uv->v!=&uv->u.value) -unlinkupval(uv); -luaM_free(L,uv); -} -static void luaF_close(lua_State*L,StkId level){ -UpVal*uv; -global_State*g=G(L); -while(L->openupval!=NULL&&(uv=ngcotouv(L->openupval))->v>=level){ -GCObject*o=obj2gco(uv); -L->openupval=uv->next; -if(isdead(g,o)) -luaF_freeupval(L,uv); -else{ -unlinkupval(uv); -setobj(L,&uv->u.value,uv->v); -uv->v=&uv->u.value; -luaC_linkupval(L,uv); -} -} -} -static Proto*luaF_newproto(lua_State*L){ -Proto*f=luaM_new(L,Proto); -luaC_link(L,obj2gco(f),(8+1)); -f->k=NULL; -f->sizek=0; -f->p=NULL; -f->sizep=0; -f->code=NULL; -f->sizecode=0; -f->sizelineinfo=0; -f->sizeupvalues=0; -f->nups=0; -f->upvalues=NULL; -f->numparams=0; -f->is_vararg=0; -f->maxstacksize=0; -f->lineinfo=NULL; -f->sizelocvars=0; -f->locvars=NULL; -f->linedefined=0; -f->lastlinedefined=0; -f->source=NULL; -return f; -} -static void luaF_freeproto(lua_State*L,Proto*f){ -luaM_freearray(L,f->code,f->sizecode,Instruction); -luaM_freearray(L,f->p,f->sizep,Proto*); -luaM_freearray(L,f->k,f->sizek,TValue); -luaM_freearray(L,f->lineinfo,f->sizelineinfo,int); -luaM_freearray(L,f->locvars,f->sizelocvars,struct LocVar); -luaM_freearray(L,f->upvalues,f->sizeupvalues,TString*); -luaM_free(L,f); -} -static void luaF_freeclosure(lua_State*L,Closure*c){ -int size=(c->c.isC)?sizeCclosure(c->c.nupvalues): -sizeLclosure(c->l.nupvalues); -luaM_freemem(L,c,size); -} -#define MASK1(n,p)((~((~(Instruction)0)<>0)&MASK1(6,0))) -#define SET_OPCODE(i,o)((i)=(((i)&MASK0(6,0))|((cast(Instruction,o)<<0)&MASK1(6,0)))) -#define GETARG_A(i)(cast(int,((i)>>(0+6))&MASK1(8,0))) -#define SETARG_A(i,u)((i)=(((i)&MASK0(8,(0+6)))|((cast(Instruction,u)<<(0+6))&MASK1(8,(0+6))))) -#define GETARG_B(i)(cast(int,((i)>>(((0+6)+8)+9))&MASK1(9,0))) -#define SETARG_B(i,b)((i)=(((i)&MASK0(9,(((0+6)+8)+9)))|((cast(Instruction,b)<<(((0+6)+8)+9))&MASK1(9,(((0+6)+8)+9))))) -#define GETARG_C(i)(cast(int,((i)>>((0+6)+8))&MASK1(9,0))) -#define SETARG_C(i,b)((i)=(((i)&MASK0(9,((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1(9,((0+6)+8))))) -#define GETARG_Bx(i)(cast(int,((i)>>((0+6)+8))&MASK1((9+9),0))) -#define SETARG_Bx(i,b)((i)=(((i)&MASK0((9+9),((0+6)+8)))|((cast(Instruction,b)<<((0+6)+8))&MASK1((9+9),((0+6)+8))))) -#define GETARG_sBx(i)(GETARG_Bx(i)-(((1<<(9+9))-1)>>1)) -#define SETARG_sBx(i,b)SETARG_Bx((i),cast(unsigned int,(b)+(((1<<(9+9))-1)>>1))) -#define CREATE_ABC(o,a,b,c)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,b)<<(((0+6)+8)+9))|(cast(Instruction,c)<<((0+6)+8))) -#define CREATE_ABx(o,a,bc)((cast(Instruction,o)<<0)|(cast(Instruction,a)<<(0+6))|(cast(Instruction,bc)<<((0+6)+8))) -#define ISK(x)((x)&(1<<(9-1))) -#define INDEXK(r)((int)(r)&~(1<<(9-1))) -#define RKASK(x)((x)|(1<<(9-1))) -static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]; -#define getBMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>4)&3)) -#define getCMode(m)(cast(enum OpArgMask,(luaP_opmodes[m]>>2)&3)) -#define testTMode(m)(luaP_opmodes[m]&(1<<7)) -typedef struct expdesc{ -expkind k; -union{ -struct{int info,aux;}s; -lua_Number nval; -}u; -int t; -int f; -}expdesc; -typedef struct upvaldesc{ -lu_byte k; -lu_byte info; -}upvaldesc; -struct BlockCnt; -typedef struct FuncState{ -Proto*f; -Table*h; -struct FuncState*prev; -struct LexState*ls; -struct lua_State*L; -struct BlockCnt*bl; -int pc; -int lasttarget; -int jpc; -int freereg; -int nk; -int np; -short nlocvars; -lu_byte nactvar; -upvaldesc upvalues[60]; -unsigned short actvar[200]; -}FuncState; -static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff, -const char*name); -struct lua_longjmp{ -struct lua_longjmp*previous; -jmp_buf b; -volatile int status; -}; -static void luaD_seterrorobj(lua_State*L,int errcode,StkId oldtop){ -switch(errcode){ -case 4:{ -setsvalue(L,oldtop,luaS_newliteral(L,"not enough memory")); -break; -} -case 5:{ -setsvalue(L,oldtop,luaS_newliteral(L,"error in error handling")); -break; -} -case 3: -case 2:{ -setobj(L,oldtop,L->top-1); -break; -} -} -L->top=oldtop+1; -} -static void restore_stack_limit(lua_State*L){ -if(L->size_ci>20000){ -int inuse=cast_int(L->ci-L->base_ci); -if(inuse+1<20000) -luaD_reallocCI(L,20000); -} -} -static void resetstack(lua_State*L,int status){ -L->ci=L->base_ci; -L->base=L->ci->base; -luaF_close(L,L->base); -luaD_seterrorobj(L,status,L->base); -L->nCcalls=L->baseCcalls; -L->allowhook=1; -restore_stack_limit(L); -L->errfunc=0; -L->errorJmp=NULL; -} -static void luaD_throw(lua_State*L,int errcode){ -if(L->errorJmp){ -L->errorJmp->status=errcode; -LUAI_THROW(L,L->errorJmp); -} -else{ -L->status=cast_byte(errcode); -if(G(L)->panic){ -resetstack(L,errcode); -G(L)->panic(L); -} -exit(EXIT_FAILURE); -} -} -static int luaD_rawrunprotected(lua_State*L,Pfunc f,void*ud){ -struct lua_longjmp lj; -lj.status=0; -lj.previous=L->errorJmp; -L->errorJmp=&lj; -LUAI_TRY(L,&lj, -(*f)(L,ud); -); -L->errorJmp=lj.previous; -return lj.status; -} -static void correctstack(lua_State*L,TValue*oldstack){ -CallInfo*ci; -GCObject*up; -L->top=(L->top-oldstack)+L->stack; -for(up=L->openupval;up!=NULL;up=up->gch.next) -gco2uv(up)->v=(gco2uv(up)->v-oldstack)+L->stack; -for(ci=L->base_ci;ci<=L->ci;ci++){ -ci->top=(ci->top-oldstack)+L->stack; -ci->base=(ci->base-oldstack)+L->stack; -ci->func=(ci->func-oldstack)+L->stack; -} -L->base=(L->base-oldstack)+L->stack; -} -static void luaD_reallocstack(lua_State*L,int newsize){ -TValue*oldstack=L->stack; -int realsize=newsize+1+5; -luaM_reallocvector(L,L->stack,L->stacksize,realsize,TValue); -L->stacksize=realsize; -L->stack_last=L->stack+newsize; -correctstack(L,oldstack); -} -static void luaD_reallocCI(lua_State*L,int newsize){ -CallInfo*oldci=L->base_ci; -luaM_reallocvector(L,L->base_ci,L->size_ci,newsize,CallInfo); -L->size_ci=newsize; -L->ci=(L->ci-oldci)+L->base_ci; -L->end_ci=L->base_ci+L->size_ci-1; -} -static void luaD_growstack(lua_State*L,int n){ -if(n<=L->stacksize) -luaD_reallocstack(L,2*L->stacksize); -else -luaD_reallocstack(L,L->stacksize+n); -} -static CallInfo*growCI(lua_State*L){ -if(L->size_ci>20000) -luaD_throw(L,5); -else{ -luaD_reallocCI(L,2*L->size_ci); -if(L->size_ci>20000) -luaG_runerror(L,"stack overflow"); -} -return++L->ci; -} -static StkId adjust_varargs(lua_State*L,Proto*p,int actual){ -int i; -int nfixargs=p->numparams; -Table*htab=NULL; -StkId base,fixed; -for(;actualtop++); -fixed=L->top-actual; -base=L->top; -for(i=0;itop++,fixed+i); -setnilvalue(fixed+i); -} -if(htab){ -sethvalue(L,L->top++,htab); -} -return base; -} -static StkId tryfuncTM(lua_State*L,StkId func){ -const TValue*tm=luaT_gettmbyobj(L,func,TM_CALL); -StkId p; -ptrdiff_t funcr=savestack(L,func); -if(!ttisfunction(tm)) -luaG_typeerror(L,func,"call"); -for(p=L->top;p>func;p--)setobj(L,p,p-1); -incr_top(L); -func=restorestack(L,funcr); -setobj(L,func,tm); -return func; -} -#define inc_ci(L)((L->ci==L->end_ci)?growCI(L):(condhardstacktests(luaD_reallocCI(L,L->size_ci)),++L->ci)) -static int luaD_precall(lua_State*L,StkId func,int nresults){ -LClosure*cl; -ptrdiff_t funcr; -if(!ttisfunction(func)) -func=tryfuncTM(L,func); -funcr=savestack(L,func); -cl=&clvalue(func)->l; -L->ci->savedpc=L->savedpc; -if(!cl->isC){ -CallInfo*ci; -StkId st,base; -Proto*p=cl->p; -luaD_checkstack(L,p->maxstacksize); -func=restorestack(L,funcr); -if(!p->is_vararg){ -base=func+1; -if(L->top>base+p->numparams) -L->top=base+p->numparams; -} -else{ -int nargs=cast_int(L->top-func)-1; -base=adjust_varargs(L,p,nargs); -func=restorestack(L,funcr); -} -ci=inc_ci(L); -ci->func=func; -L->base=ci->base=base; -ci->top=L->base+p->maxstacksize; -L->savedpc=p->code; -ci->tailcalls=0; -ci->nresults=nresults; -for(st=L->top;sttop;st++) -setnilvalue(st); -L->top=ci->top; -return 0; -} -else{ -CallInfo*ci; -int n; -luaD_checkstack(L,20); -ci=inc_ci(L); -ci->func=restorestack(L,funcr); -L->base=ci->base=ci->func+1; -ci->top=L->top+20; -ci->nresults=nresults; -n=(*curr_func(L)->c.f)(L); -if(n<0) -return 2; -else{ -luaD_poscall(L,L->top-n); -return 1; -} -} -} -static int luaD_poscall(lua_State*L,StkId firstResult){ -StkId res; -int wanted,i; -CallInfo*ci; -ci=L->ci--; -res=ci->func; -wanted=ci->nresults; -L->base=(ci-1)->base; -L->savedpc=(ci-1)->savedpc; -for(i=wanted;i!=0&&firstResulttop;i--) -setobj(L,res++,firstResult++); -while(i-->0) -setnilvalue(res++); -L->top=res; -return(wanted-(-1)); -} -static void luaD_call(lua_State*L,StkId func,int nResults){ -if(++L->nCcalls>=200){ -if(L->nCcalls==200) -luaG_runerror(L,"C stack overflow"); -else if(L->nCcalls>=(200+(200>>3))) -luaD_throw(L,5); -} -if(luaD_precall(L,func,nResults)==0) -luaV_execute(L,1); -L->nCcalls--; -luaC_checkGC(L); -} -static int luaD_pcall(lua_State*L,Pfunc func,void*u, -ptrdiff_t old_top,ptrdiff_t ef){ -int status; -unsigned short oldnCcalls=L->nCcalls; -ptrdiff_t old_ci=saveci(L,L->ci); -lu_byte old_allowhooks=L->allowhook; -ptrdiff_t old_errfunc=L->errfunc; -L->errfunc=ef; -status=luaD_rawrunprotected(L,func,u); -if(status!=0){ -StkId oldtop=restorestack(L,old_top); -luaF_close(L,oldtop); -luaD_seterrorobj(L,status,oldtop); -L->nCcalls=oldnCcalls; -L->ci=restoreci(L,old_ci); -L->base=L->ci->base; -L->savedpc=L->ci->savedpc; -L->allowhook=old_allowhooks; -restore_stack_limit(L); -} -L->errfunc=old_errfunc; -return status; -} -struct SParser{ -ZIO*z; -Mbuffer buff; -const char*name; -}; -static void f_parser(lua_State*L,void*ud){ -int i; -Proto*tf; -Closure*cl; -struct SParser*p=cast(struct SParser*,ud); -luaC_checkGC(L); -tf=luaY_parser(L,p->z, -&p->buff,p->name); -cl=luaF_newLclosure(L,tf->nups,hvalue(gt(L))); -cl->l.p=tf; -for(i=0;inups;i++) -cl->l.upvals[i]=luaF_newupval(L); -setclvalue(L,L->top,cl); -incr_top(L); -} -static int luaD_protectedparser(lua_State*L,ZIO*z,const char*name){ -struct SParser p; -int status; -p.z=z;p.name=name; -luaZ_initbuffer(L,&p.buff); -status=luaD_pcall(L,f_parser,&p,savestack(L,L->top),L->errfunc); -luaZ_freebuffer(L,&p.buff); -return status; -} -static void luaS_resize(lua_State*L,int newsize){ -GCObject**newhash; -stringtable*tb; -int i; -if(G(L)->gcstate==2) -return; -newhash=luaM_newvector(L,newsize,GCObject*); -tb=&G(L)->strt; -for(i=0;isize;i++){ -GCObject*p=tb->hash[i]; -while(p){ -GCObject*next=p->gch.next; -unsigned int h=gco2ts(p)->hash; -int h1=lmod(h,newsize); -p->gch.next=newhash[h1]; -newhash[h1]=p; -p=next; -} -} -luaM_freearray(L,tb->hash,tb->size,TString*); -tb->size=newsize; -tb->hash=newhash; -} -static TString*newlstr(lua_State*L,const char*str,size_t l, -unsigned int h){ -TString*ts; -stringtable*tb; -if(l+1>(((size_t)(~(size_t)0)-2)-sizeof(TString))/sizeof(char)) -luaM_toobig(L); -ts=cast(TString*,luaM_malloc(L,(l+1)*sizeof(char)+sizeof(TString))); -ts->tsv.len=l; -ts->tsv.hash=h; -ts->tsv.marked=luaC_white(G(L)); -ts->tsv.tt=4; -ts->tsv.reserved=0; -memcpy(ts+1,str,l*sizeof(char)); -((char*)(ts+1))[l]='\0'; -tb=&G(L)->strt; -h=lmod(h,tb->size); -ts->tsv.next=tb->hash[h]; -tb->hash[h]=obj2gco(ts); -tb->nuse++; -if(tb->nuse>cast(lu_int32,tb->size)&&tb->size<=(INT_MAX-2)/2) -luaS_resize(L,tb->size*2); -return ts; -} -static TString*luaS_newlstr(lua_State*L,const char*str,size_t l){ -GCObject*o; -unsigned int h=cast(unsigned int,l); -size_t step=(l>>5)+1; -size_t l1; -for(l1=l;l1>=step;l1-=step) -h=h^((h<<5)+(h>>2)+cast(unsigned char,str[l1-1])); -for(o=G(L)->strt.hash[lmod(h,G(L)->strt.size)]; -o!=NULL; -o=o->gch.next){ -TString*ts=rawgco2ts(o); -if(ts->tsv.len==l&&(memcmp(str,getstr(ts),l)==0)){ -if(isdead(G(L),o))changewhite(o); -return ts; -} -} -return newlstr(L,str,l,h); -} -static Udata*luaS_newudata(lua_State*L,size_t s,Table*e){ -Udata*u; -if(s>((size_t)(~(size_t)0)-2)-sizeof(Udata)) -luaM_toobig(L); -u=cast(Udata*,luaM_malloc(L,s+sizeof(Udata))); -u->uv.marked=luaC_white(G(L)); -u->uv.tt=7; -u->uv.len=s; -u->uv.metatable=NULL; -u->uv.env=e; -u->uv.next=G(L)->mainthread->next; -G(L)->mainthread->next=obj2gco(u); -return u; -} -#define hashpow2(t,n)(gnode(t,lmod((n),sizenode(t)))) -#define hashstr(t,str)hashpow2(t,(str)->tsv.hash) -#define hashboolean(t,p)hashpow2(t,p) -#define hashmod(t,n)(gnode(t,((n)%((sizenode(t)-1)|1)))) -#define hashpointer(t,p)hashmod(t,IntPoint(p)) -static const Node dummynode_={ -{{NULL},0}, -{{{NULL},0,NULL}} -}; -static Node*hashnum(const Table*t,lua_Number n){ -unsigned int a[cast_int(sizeof(lua_Number)/sizeof(int))]; -int i; -if(luai_numeq(n,0)) -return gnode(t,0); -memcpy(a,&n,sizeof(a)); -for(i=1;isizearray) -return i-1; -else{ -Node*n=mainposition(t,key); -do{ -if(luaO_rawequalObj(key2tval(n),key)|| -(ttype(gkey(n))==(8+3)&&iscollectable(key)&& -gcvalue(gkey(n))==gcvalue(key))){ -i=cast_int(n-gnode(t,0)); -return i+t->sizearray; -} -else n=gnext(n); -}while(n); -luaG_runerror(L,"invalid key to "LUA_QL("next")); -return 0; -} -} -static int luaH_next(lua_State*L,Table*t,StkId key){ -int i=findindex(L,t,key); -for(i++;isizearray;i++){ -if(!ttisnil(&t->array[i])){ -setnvalue(key,cast_num(i+1)); -setobj(L,key+1,&t->array[i]); -return 1; -} -} -for(i-=t->sizearray;i<(int)sizenode(t);i++){ -if(!ttisnil(gval(gnode(t,i)))){ -setobj(L,key,key2tval(gnode(t,i))); -setobj(L,key+1,gval(gnode(t,i))); -return 1; -} -} -return 0; -} -static int computesizes(int nums[],int*narray){ -int i; -int twotoi; -int a=0; -int na=0; -int n=0; -for(i=0,twotoi=1;twotoi/2<*narray;i++,twotoi*=2){ -if(nums[i]>0){ -a+=nums[i]; -if(a>twotoi/2){ -n=twotoi; -na=a; -} -} -if(a==*narray)break; -} -*narray=n; -return na; -} -static int countint(const TValue*key,int*nums){ -int k=arrayindex(key); -if(0t->sizearray){ -lim=t->sizearray; -if(i>lim) -break; -} -for(;i<=lim;i++){ -if(!ttisnil(&t->array[i-1])) -lc++; -} -nums[lg]+=lc; -ause+=lc; -} -return ause; -} -static int numusehash(const Table*t,int*nums,int*pnasize){ -int totaluse=0; -int ause=0; -int i=sizenode(t); -while(i--){ -Node*n=&t->node[i]; -if(!ttisnil(gval(n))){ -ause+=countint(key2tval(n),nums); -totaluse++; -} -} -*pnasize+=ause; -return totaluse; -} -static void setarrayvector(lua_State*L,Table*t,int size){ -int i; -luaM_reallocvector(L,t->array,t->sizearray,size,TValue); -for(i=t->sizearray;iarray[i]); -t->sizearray=size; -} -static void setnodevector(lua_State*L,Table*t,int size){ -int lsize; -if(size==0){ -t->node=cast(Node*,(&dummynode_)); -lsize=0; -} -else{ -int i; -lsize=ceillog2(size); -if(lsize>(32-2)) -luaG_runerror(L,"table overflow"); -size=twoto(lsize); -t->node=luaM_newvector(L,size,Node); -for(i=0;ilsizenode=cast_byte(lsize); -t->lastfree=gnode(t,size); -} -static void resize(lua_State*L,Table*t,int nasize,int nhsize){ -int i; -int oldasize=t->sizearray; -int oldhsize=t->lsizenode; -Node*nold=t->node; -if(nasize>oldasize) -setarrayvector(L,t,nasize); -setnodevector(L,t,nhsize); -if(nasizesizearray=nasize; -for(i=nasize;iarray[i])) -setobj(L,luaH_setnum(L,t,i+1),&t->array[i]); -} -luaM_reallocvector(L,t->array,oldasize,nasize,TValue); -} -for(i=twoto(oldhsize)-1;i>=0;i--){ -Node*old=nold+i; -if(!ttisnil(gval(old))) -setobj(L,luaH_set(L,t,key2tval(old)),gval(old)); -} -if(nold!=(&dummynode_)) -luaM_freearray(L,nold,twoto(oldhsize),Node); -} -static void luaH_resizearray(lua_State*L,Table*t,int nasize){ -int nsize=(t->node==(&dummynode_))?0:sizenode(t); -resize(L,t,nasize,nsize); -} -static void rehash(lua_State*L,Table*t,const TValue*ek){ -int nasize,na; -int nums[(32-2)+1]; -int i; -int totaluse; -for(i=0;i<=(32-2);i++)nums[i]=0; -nasize=numusearray(t,nums); -totaluse=nasize; -totaluse+=numusehash(t,nums,&nasize); -nasize+=countint(ek,nums); -totaluse++; -na=computesizes(nums,&nasize); -resize(L,t,nasize,totaluse-na); -} -static Table*luaH_new(lua_State*L,int narray,int nhash){ -Table*t=luaM_new(L,Table); -luaC_link(L,obj2gco(t),5); -t->metatable=NULL; -t->flags=cast_byte(~0); -t->array=NULL; -t->sizearray=0; -t->lsizenode=0; -t->node=cast(Node*,(&dummynode_)); -setarrayvector(L,t,narray); -setnodevector(L,t,nhash); -return t; -} -static void luaH_free(lua_State*L,Table*t){ -if(t->node!=(&dummynode_)) -luaM_freearray(L,t->node,sizenode(t),Node); -luaM_freearray(L,t->array,t->sizearray,TValue); -luaM_free(L,t); -} -static Node*getfreepos(Table*t){ -while(t->lastfree-->t->node){ -if(ttisnil(gkey(t->lastfree))) -return t->lastfree; -} -return NULL; -} -static TValue*newkey(lua_State*L,Table*t,const TValue*key){ -Node*mp=mainposition(t,key); -if(!ttisnil(gval(mp))||mp==(&dummynode_)){ -Node*othern; -Node*n=getfreepos(t); -if(n==NULL){ -rehash(L,t,key); -return luaH_set(L,t,key); -} -othern=mainposition(t,key2tval(mp)); -if(othern!=mp){ -while(gnext(othern)!=mp)othern=gnext(othern); -gnext(othern)=n; -*n=*mp; -gnext(mp)=NULL; -setnilvalue(gval(mp)); -} -else{ -gnext(n)=gnext(mp); -gnext(mp)=n; -mp=n; -} -} -gkey(mp)->value=key->value;gkey(mp)->tt=key->tt; -luaC_barriert(L,t,key); -return gval(mp); -} -static const TValue*luaH_getnum(Table*t,int key){ -if(cast(unsigned int,key)-1sizearray)) -return&t->array[key-1]; -else{ -lua_Number nk=cast_num(key); -Node*n=hashnum(t,nk); -do{ -if(ttisnumber(gkey(n))&&luai_numeq(nvalue(gkey(n)),nk)) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -} -static const TValue*luaH_getstr(Table*t,TString*key){ -Node*n=hashstr(t,key); -do{ -if(ttisstring(gkey(n))&&rawtsvalue(gkey(n))==key) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -static const TValue*luaH_get(Table*t,const TValue*key){ -switch(ttype(key)){ -case 0:return(&luaO_nilobject_); -case 4:return luaH_getstr(t,rawtsvalue(key)); -case 3:{ -int k; -lua_Number n=nvalue(key); -lua_number2int(k,n); -if(luai_numeq(cast_num(k),nvalue(key))) -return luaH_getnum(t,k); -} -default:{ -Node*n=mainposition(t,key); -do{ -if(luaO_rawequalObj(key2tval(n),key)) -return gval(n); -else n=gnext(n); -}while(n); -return(&luaO_nilobject_); -} -} -} -static TValue*luaH_set(lua_State*L,Table*t,const TValue*key){ -const TValue*p=luaH_get(t,key); -t->flags=0; -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -if(ttisnil(key))luaG_runerror(L,"table index is nil"); -else if(ttisnumber(key)&&luai_numisnan(nvalue(key))) -luaG_runerror(L,"table index is NaN"); -return newkey(L,t,key); -} -} -static TValue*luaH_setnum(lua_State*L,Table*t,int key){ -const TValue*p=luaH_getnum(t,key); -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -TValue k; -setnvalue(&k,cast_num(key)); -return newkey(L,t,&k); -} -} -static TValue*luaH_setstr(lua_State*L,Table*t,TString*key){ -const TValue*p=luaH_getstr(t,key); -if(p!=(&luaO_nilobject_)) -return cast(TValue*,p); -else{ -TValue k; -setsvalue(L,&k,key); -return newkey(L,t,&k); -} -} -static int unbound_search(Table*t,unsigned int j){ -unsigned int i=j; -j++; -while(!ttisnil(luaH_getnum(t,j))){ -i=j; -j*=2; -if(j>cast(unsigned int,(INT_MAX-2))){ -i=1; -while(!ttisnil(luaH_getnum(t,i)))i++; -return i-1; -} -} -while(j-i>1){ -unsigned int m=(i+j)/2; -if(ttisnil(luaH_getnum(t,m)))j=m; -else i=m; -} -return i; -} -static int luaH_getn(Table*t){ -unsigned int j=t->sizearray; -if(j>0&&ttisnil(&t->array[j-1])){ -unsigned int i=0; -while(j-i>1){ -unsigned int m=(i+j)/2; -if(ttisnil(&t->array[m-1]))j=m; -else i=m; -} -return i; -} -else if(t->node==(&dummynode_)) -return j; -else return unbound_search(t,j); -} -#define makewhite(g,x)((x)->gch.marked=cast_byte(((x)->gch.marked&cast_byte(~(bitmask(2)|bit2mask(0,1))))|luaC_white(g))) -#define white2gray(x)reset2bits((x)->gch.marked,0,1) -#define black2gray(x)resetbit((x)->gch.marked,2) -#define stringmark(s)reset2bits((s)->tsv.marked,0,1) -#define isfinalized(u)testbit((u)->marked,3) -#define markfinalized(u)l_setbit((u)->marked,3) -#define markvalue(g,o){checkconsistency(o);if(iscollectable(o)&&iswhite(gcvalue(o)))reallymarkobject(g,gcvalue(o));} -#define markobject(g,t){if(iswhite(obj2gco(t)))reallymarkobject(g,obj2gco(t));} -#define setthreshold(g)(g->GCthreshold=(g->estimate/100)*g->gcpause) -static void removeentry(Node*n){ -if(iscollectable(gkey(n))) -setttype(gkey(n),(8+3)); -} -static void reallymarkobject(global_State*g,GCObject*o){ -white2gray(o); -switch(o->gch.tt){ -case 4:{ -return; -} -case 7:{ -Table*mt=gco2u(o)->metatable; -gray2black(o); -if(mt)markobject(g,mt); -markobject(g,gco2u(o)->env); -return; -} -case(8+2):{ -UpVal*uv=gco2uv(o); -markvalue(g,uv->v); -if(uv->v==&uv->u.value) -gray2black(o); -return; -} -case 6:{ -gco2cl(o)->c.gclist=g->gray; -g->gray=o; -break; -} -case 5:{ -gco2h(o)->gclist=g->gray; -g->gray=o; -break; -} -case 8:{ -gco2th(o)->gclist=g->gray; -g->gray=o; -break; -} -case(8+1):{ -gco2p(o)->gclist=g->gray; -g->gray=o; -break; -} -default:; -} -} -static void marktmu(global_State*g){ -GCObject*u=g->tmudata; -if(u){ -do{ -u=u->gch.next; -makewhite(g,u); -reallymarkobject(g,u); -}while(u!=g->tmudata); -} -} -static size_t luaC_separateudata(lua_State*L,int all){ -global_State*g=G(L); -size_t deadmem=0; -GCObject**p=&g->mainthread->next; -GCObject*curr; -while((curr=*p)!=NULL){ -if(!(iswhite(curr)||all)||isfinalized(gco2u(curr))) -p=&curr->gch.next; -else if(fasttm(L,gco2u(curr)->metatable,TM_GC)==NULL){ -markfinalized(gco2u(curr)); -p=&curr->gch.next; -} -else{ -deadmem+=sizeudata(gco2u(curr)); -markfinalized(gco2u(curr)); -*p=curr->gch.next; -if(g->tmudata==NULL) -g->tmudata=curr->gch.next=curr; -else{ -curr->gch.next=g->tmudata->gch.next; -g->tmudata->gch.next=curr; -g->tmudata=curr; -} -} -} -return deadmem; -} -static int traversetable(global_State*g,Table*h){ -int i; -int weakkey=0; -int weakvalue=0; -const TValue*mode; -if(h->metatable) -markobject(g,h->metatable); -mode=gfasttm(g,h->metatable,TM_MODE); -if(mode&&ttisstring(mode)){ -weakkey=(strchr(svalue(mode),'k')!=NULL); -weakvalue=(strchr(svalue(mode),'v')!=NULL); -if(weakkey||weakvalue){ -h->marked&=~(bitmask(3)|bitmask(4)); -h->marked|=cast_byte((weakkey<<3)| -(weakvalue<<4)); -h->gclist=g->weak; -g->weak=obj2gco(h); -} -} -if(weakkey&&weakvalue)return 1; -if(!weakvalue){ -i=h->sizearray; -while(i--) -markvalue(g,&h->array[i]); -} -i=sizenode(h); -while(i--){ -Node*n=gnode(h,i); -if(ttisnil(gval(n))) -removeentry(n); -else{ -if(!weakkey)markvalue(g,gkey(n)); -if(!weakvalue)markvalue(g,gval(n)); -} -} -return weakkey||weakvalue; -} -static void traverseproto(global_State*g,Proto*f){ -int i; -if(f->source)stringmark(f->source); -for(i=0;isizek;i++) -markvalue(g,&f->k[i]); -for(i=0;isizeupvalues;i++){ -if(f->upvalues[i]) -stringmark(f->upvalues[i]); -} -for(i=0;isizep;i++){ -if(f->p[i]) -markobject(g,f->p[i]); -} -for(i=0;isizelocvars;i++){ -if(f->locvars[i].varname) -stringmark(f->locvars[i].varname); -} -} -static void traverseclosure(global_State*g,Closure*cl){ -markobject(g,cl->c.env); -if(cl->c.isC){ -int i; -for(i=0;ic.nupvalues;i++) -markvalue(g,&cl->c.upvalue[i]); -} -else{ -int i; -markobject(g,cl->l.p); -for(i=0;il.nupvalues;i++) -markobject(g,cl->l.upvals[i]); -} -} -static void checkstacksizes(lua_State*L,StkId max){ -int ci_used=cast_int(L->ci-L->base_ci); -int s_used=cast_int(max-L->stack); -if(L->size_ci>20000) -return; -if(4*ci_usedsize_ci&&2*8size_ci) -luaD_reallocCI(L,L->size_ci/2); -condhardstacktests(luaD_reallocCI(L,ci_used+1)); -if(4*s_usedstacksize&& -2*((2*20)+5)stacksize) -luaD_reallocstack(L,L->stacksize/2); -condhardstacktests(luaD_reallocstack(L,s_used)); -} -static void traversestack(global_State*g,lua_State*l){ -StkId o,lim; -CallInfo*ci; -markvalue(g,gt(l)); -lim=l->top; -for(ci=l->base_ci;ci<=l->ci;ci++){ -if(limtop)lim=ci->top; -} -for(o=l->stack;otop;o++) -markvalue(g,o); -for(;o<=lim;o++) -setnilvalue(o); -checkstacksizes(l,lim); -} -static l_mem propagatemark(global_State*g){ -GCObject*o=g->gray; -gray2black(o); -switch(o->gch.tt){ -case 5:{ -Table*h=gco2h(o); -g->gray=h->gclist; -if(traversetable(g,h)) -black2gray(o); -return sizeof(Table)+sizeof(TValue)*h->sizearray+ -sizeof(Node)*sizenode(h); -} -case 6:{ -Closure*cl=gco2cl(o); -g->gray=cl->c.gclist; -traverseclosure(g,cl); -return(cl->c.isC)?sizeCclosure(cl->c.nupvalues): -sizeLclosure(cl->l.nupvalues); -} -case 8:{ -lua_State*th=gco2th(o); -g->gray=th->gclist; -th->gclist=g->grayagain; -g->grayagain=o; -black2gray(o); -traversestack(g,th); -return sizeof(lua_State)+sizeof(TValue)*th->stacksize+ -sizeof(CallInfo)*th->size_ci; -} -case(8+1):{ -Proto*p=gco2p(o); -g->gray=p->gclist; -traverseproto(g,p); -return sizeof(Proto)+sizeof(Instruction)*p->sizecode+ -sizeof(Proto*)*p->sizep+ -sizeof(TValue)*p->sizek+ -sizeof(int)*p->sizelineinfo+ -sizeof(LocVar)*p->sizelocvars+ -sizeof(TString*)*p->sizeupvalues; -} -default:return 0; -} -} -static size_t propagateall(global_State*g){ -size_t m=0; -while(g->gray)m+=propagatemark(g); -return m; -} -static int iscleared(const TValue*o,int iskey){ -if(!iscollectable(o))return 0; -if(ttisstring(o)){ -stringmark(rawtsvalue(o)); -return 0; -} -return iswhite(gcvalue(o))|| -(ttisuserdata(o)&&(!iskey&&isfinalized(uvalue(o)))); -} -static void cleartable(GCObject*l){ -while(l){ -Table*h=gco2h(l); -int i=h->sizearray; -if(testbit(h->marked,4)){ -while(i--){ -TValue*o=&h->array[i]; -if(iscleared(o,0)) -setnilvalue(o); -} -} -i=sizenode(h); -while(i--){ -Node*n=gnode(h,i); -if(!ttisnil(gval(n))&& -(iscleared(key2tval(n),1)||iscleared(gval(n),0))){ -setnilvalue(gval(n)); -removeentry(n); -} -} -l=h->gclist; -} -} -static void freeobj(lua_State*L,GCObject*o){ -switch(o->gch.tt){ -case(8+1):luaF_freeproto(L,gco2p(o));break; -case 6:luaF_freeclosure(L,gco2cl(o));break; -case(8+2):luaF_freeupval(L,gco2uv(o));break; -case 5:luaH_free(L,gco2h(o));break; -case 8:{ -luaE_freethread(L,gco2th(o)); -break; -} -case 4:{ -G(L)->strt.nuse--; -luaM_freemem(L,o,sizestring(gco2ts(o))); -break; -} -case 7:{ -luaM_freemem(L,o,sizeudata(gco2u(o))); -break; -} -default:; -} -} -#define sweepwholelist(L,p)sweeplist(L,p,((lu_mem)(~(lu_mem)0)-2)) -static GCObject**sweeplist(lua_State*L,GCObject**p,lu_mem count){ -GCObject*curr; -global_State*g=G(L); -int deadmask=otherwhite(g); -while((curr=*p)!=NULL&&count-->0){ -if(curr->gch.tt==8) -sweepwholelist(L,&gco2th(curr)->openupval); -if((curr->gch.marked^bit2mask(0,1))&deadmask){ -makewhite(g,curr); -p=&curr->gch.next; -} -else{ -*p=curr->gch.next; -if(curr==g->rootgc) -g->rootgc=curr->gch.next; -freeobj(L,curr); -} -} -return p; -} -static void checkSizes(lua_State*L){ -global_State*g=G(L); -if(g->strt.nusestrt.size/4)&& -g->strt.size>32*2) -luaS_resize(L,g->strt.size/2); -if(luaZ_sizebuffer(&g->buff)>32*2){ -size_t newsize=luaZ_sizebuffer(&g->buff)/2; -luaZ_resizebuffer(L,&g->buff,newsize); -} -} -static void GCTM(lua_State*L){ -global_State*g=G(L); -GCObject*o=g->tmudata->gch.next; -Udata*udata=rawgco2u(o); -const TValue*tm; -if(o==g->tmudata) -g->tmudata=NULL; -else -g->tmudata->gch.next=udata->uv.next; -udata->uv.next=g->mainthread->next; -g->mainthread->next=o; -makewhite(g,o); -tm=fasttm(L,udata->uv.metatable,TM_GC); -if(tm!=NULL){ -lu_byte oldah=L->allowhook; -lu_mem oldt=g->GCthreshold; -L->allowhook=0; -g->GCthreshold=2*g->totalbytes; -setobj(L,L->top,tm); -setuvalue(L,L->top+1,udata); -L->top+=2; -luaD_call(L,L->top-2,0); -L->allowhook=oldah; -g->GCthreshold=oldt; -} -} -static void luaC_callGCTM(lua_State*L){ -while(G(L)->tmudata) -GCTM(L); -} -static void luaC_freeall(lua_State*L){ -global_State*g=G(L); -int i; -g->currentwhite=bit2mask(0,1)|bitmask(6); -sweepwholelist(L,&g->rootgc); -for(i=0;istrt.size;i++) -sweepwholelist(L,&g->strt.hash[i]); -} -static void markmt(global_State*g){ -int i; -for(i=0;i<(8+1);i++) -if(g->mt[i])markobject(g,g->mt[i]); -} -static void markroot(lua_State*L){ -global_State*g=G(L); -g->gray=NULL; -g->grayagain=NULL; -g->weak=NULL; -markobject(g,g->mainthread); -markvalue(g,gt(g->mainthread)); -markvalue(g,registry(L)); -markmt(g); -g->gcstate=1; -} -static void remarkupvals(global_State*g){ -UpVal*uv; -for(uv=g->uvhead.u.l.next;uv!=&g->uvhead;uv=uv->u.l.next){ -if(isgray(obj2gco(uv))) -markvalue(g,uv->v); -} -} -static void atomic(lua_State*L){ -global_State*g=G(L); -size_t udsize; -remarkupvals(g); -propagateall(g); -g->gray=g->weak; -g->weak=NULL; -markobject(g,L); -markmt(g); -propagateall(g); -g->gray=g->grayagain; -g->grayagain=NULL; -propagateall(g); -udsize=luaC_separateudata(L,0); -marktmu(g); -udsize+=propagateall(g); -cleartable(g->weak); -g->currentwhite=cast_byte(otherwhite(g)); -g->sweepstrgc=0; -g->sweepgc=&g->rootgc; -g->gcstate=2; -g->estimate=g->totalbytes-udsize; -} -static l_mem singlestep(lua_State*L){ -global_State*g=G(L); -switch(g->gcstate){ -case 0:{ -markroot(L); -return 0; -} -case 1:{ -if(g->gray) -return propagatemark(g); -else{ -atomic(L); -return 0; -} -} -case 2:{ -lu_mem old=g->totalbytes; -sweepwholelist(L,&g->strt.hash[g->sweepstrgc++]); -if(g->sweepstrgc>=g->strt.size) -g->gcstate=3; -g->estimate-=old-g->totalbytes; -return 10; -} -case 3:{ -lu_mem old=g->totalbytes; -g->sweepgc=sweeplist(L,g->sweepgc,40); -if(*g->sweepgc==NULL){ -checkSizes(L); -g->gcstate=4; -} -g->estimate-=old-g->totalbytes; -return 40*10; -} -case 4:{ -if(g->tmudata){ -GCTM(L); -if(g->estimate>100) -g->estimate-=100; -return 100; -} -else{ -g->gcstate=0; -g->gcdept=0; -return 0; -} -} -default:return 0; -} -} -static void luaC_step(lua_State*L){ -global_State*g=G(L); -l_mem lim=(1024u/100)*g->gcstepmul; -if(lim==0) -lim=(((lu_mem)(~(lu_mem)0)-2)-1)/2; -g->gcdept+=g->totalbytes-g->GCthreshold; -do{ -lim-=singlestep(L); -if(g->gcstate==0) -break; -}while(lim>0); -if(g->gcstate!=0){ -if(g->gcdept<1024u) -g->GCthreshold=g->totalbytes+1024u; -else{ -g->gcdept-=1024u; -g->GCthreshold=g->totalbytes; -} -} -else{ -setthreshold(g); -} -} -static void luaC_barrierf(lua_State*L,GCObject*o,GCObject*v){ -global_State*g=G(L); -if(g->gcstate==1) -reallymarkobject(g,v); -else -makewhite(g,o); -} -static void luaC_barrierback(lua_State*L,Table*t){ -global_State*g=G(L); -GCObject*o=obj2gco(t); -black2gray(o); -t->gclist=g->grayagain; -g->grayagain=o; -} -static void luaC_link(lua_State*L,GCObject*o,lu_byte tt){ -global_State*g=G(L); -o->gch.next=g->rootgc; -g->rootgc=o; -o->gch.marked=luaC_white(g); -o->gch.tt=tt; -} -static void luaC_linkupval(lua_State*L,UpVal*uv){ -global_State*g=G(L); -GCObject*o=obj2gco(uv); -o->gch.next=g->rootgc; -g->rootgc=o; -if(isgray(o)){ -if(g->gcstate==1){ -gray2black(o); -luaC_barrier(L,uv,uv->v); -} -else{ -makewhite(g,o); -} -} -} -typedef union{ -lua_Number r; -TString*ts; -}SemInfo; -typedef struct Token{ -int token; -SemInfo seminfo; -}Token; -typedef struct LexState{ -int current; -int linenumber; -int lastline; -Token t; -Token lookahead; -struct FuncState*fs; -struct lua_State*L; -ZIO*z; -Mbuffer*buff; -TString*source; -char decpoint; -}LexState; -static void luaX_init(lua_State*L); -static void luaX_lexerror(LexState*ls,const char*msg,int token); -#define state_size(x)(sizeof(x)+0) -#define fromstate(l)(cast(lu_byte*,(l))-0) -#define tostate(l)(cast(lua_State*,cast(lu_byte*,l)+0)) -typedef struct LG{ -lua_State l; -global_State g; -}LG; -static void stack_init(lua_State*L1,lua_State*L){ -L1->base_ci=luaM_newvector(L,8,CallInfo); -L1->ci=L1->base_ci; -L1->size_ci=8; -L1->end_ci=L1->base_ci+L1->size_ci-1; -L1->stack=luaM_newvector(L,(2*20)+5,TValue); -L1->stacksize=(2*20)+5; -L1->top=L1->stack; -L1->stack_last=L1->stack+(L1->stacksize-5)-1; -L1->ci->func=L1->top; -setnilvalue(L1->top++); -L1->base=L1->ci->base=L1->top; -L1->ci->top=L1->top+20; -} -static void freestack(lua_State*L,lua_State*L1){ -luaM_freearray(L,L1->base_ci,L1->size_ci,CallInfo); -luaM_freearray(L,L1->stack,L1->stacksize,TValue); -} -static void f_luaopen(lua_State*L,void*ud){ -global_State*g=G(L); -UNUSED(ud); -stack_init(L,L); -sethvalue(L,gt(L),luaH_new(L,0,2)); -sethvalue(L,registry(L),luaH_new(L,0,2)); -luaS_resize(L,32); -luaT_init(L); -luaX_init(L); -luaS_fix(luaS_newliteral(L,"not enough memory")); -g->GCthreshold=4*g->totalbytes; -} -static void preinit_state(lua_State*L,global_State*g){ -G(L)=g; -L->stack=NULL; -L->stacksize=0; -L->errorJmp=NULL; -L->hook=NULL; -L->hookmask=0; -L->basehookcount=0; -L->allowhook=1; -resethookcount(L); -L->openupval=NULL; -L->size_ci=0; -L->nCcalls=L->baseCcalls=0; -L->status=0; -L->base_ci=L->ci=NULL; -L->savedpc=NULL; -L->errfunc=0; -setnilvalue(gt(L)); -} -static void close_state(lua_State*L){ -global_State*g=G(L); -luaF_close(L,L->stack); -luaC_freeall(L); -luaM_freearray(L,G(L)->strt.hash,G(L)->strt.size,TString*); -luaZ_freebuffer(L,&g->buff); -freestack(L,L); -(*g->frealloc)(g->ud,fromstate(L),state_size(LG),0); -} -static void luaE_freethread(lua_State*L,lua_State*L1){ -luaF_close(L1,L1->stack); -freestack(L,L1); -luaM_freemem(L,fromstate(L1),state_size(lua_State)); -} -static lua_State*lua_newstate(lua_Alloc f,void*ud){ -int i; -lua_State*L; -global_State*g; -void*l=(*f)(ud,NULL,0,state_size(LG)); -if(l==NULL)return NULL; -L=tostate(l); -g=&((LG*)L)->g; -L->next=NULL; -L->tt=8; -g->currentwhite=bit2mask(0,5); -L->marked=luaC_white(g); -set2bits(L->marked,5,6); -preinit_state(L,g); -g->frealloc=f; -g->ud=ud; -g->mainthread=L; -g->uvhead.u.l.prev=&g->uvhead; -g->uvhead.u.l.next=&g->uvhead; -g->GCthreshold=0; -g->strt.size=0; -g->strt.nuse=0; -g->strt.hash=NULL; -setnilvalue(registry(L)); -luaZ_initbuffer(L,&g->buff); -g->panic=NULL; -g->gcstate=0; -g->rootgc=obj2gco(L); -g->sweepstrgc=0; -g->sweepgc=&g->rootgc; -g->gray=NULL; -g->grayagain=NULL; -g->weak=NULL; -g->tmudata=NULL; -g->totalbytes=sizeof(LG); -g->gcpause=200; -g->gcstepmul=200; -g->gcdept=0; -for(i=0;i<(8+1);i++)g->mt[i]=NULL; -if(luaD_rawrunprotected(L,f_luaopen,NULL)!=0){ -close_state(L); -L=NULL; -} -else -{} -return L; -} -static void callallgcTM(lua_State*L,void*ud){ -UNUSED(ud); -luaC_callGCTM(L); -} -static void lua_close(lua_State*L){ -L=G(L)->mainthread; -luaF_close(L,L->stack); -luaC_separateudata(L,1); -L->errfunc=0; -do{ -L->ci=L->base_ci; -L->base=L->top=L->ci->base; -L->nCcalls=L->baseCcalls=0; -}while(luaD_rawrunprotected(L,callallgcTM,NULL)!=0); -close_state(L); -} -#define getcode(fs,e)((fs)->f->code[(e)->u.s.info]) -#define luaK_codeAsBx(fs,o,A,sBx)luaK_codeABx(fs,o,A,(sBx)+(((1<<(9+9))-1)>>1)) -#define luaK_setmultret(fs,e)luaK_setreturns(fs,e,(-1)) -static int luaK_codeABx(FuncState*fs,OpCode o,int A,unsigned int Bx); -static int luaK_codeABC(FuncState*fs,OpCode o,int A,int B,int C); -static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults); -static void luaK_patchtohere(FuncState*fs,int list); -static void luaK_concat(FuncState*fs,int*l1,int l2); -static int currentpc(lua_State*L,CallInfo*ci){ -if(!isLua(ci))return-1; -if(ci==L->ci) -ci->savedpc=L->savedpc; -return pcRel(ci->savedpc,ci_func(ci)->l.p); -} -static int currentline(lua_State*L,CallInfo*ci){ -int pc=currentpc(L,ci); -if(pc<0) -return-1; -else -return getline_(ci_func(ci)->l.p,pc); -} -static int lua_getstack(lua_State*L,int level,lua_Debug*ar){ -int status; -CallInfo*ci; -for(ci=L->ci;level>0&&ci>L->base_ci;ci--){ -level--; -if(f_isLua(ci)) -level-=ci->tailcalls; -} -if(level==0&&ci>L->base_ci){ -status=1; -ar->i_ci=cast_int(ci-L->base_ci); -} -else if(level<0){ -status=1; -ar->i_ci=0; -} -else status=0; -return status; -} -static Proto*getluaproto(CallInfo*ci){ -return(isLua(ci)?ci_func(ci)->l.p:NULL); -} -static void funcinfo(lua_Debug*ar,Closure*cl){ -if(cl->c.isC){ -ar->source="=[C]"; -ar->linedefined=-1; -ar->lastlinedefined=-1; -ar->what="C"; -} -else{ -ar->source=getstr(cl->l.p->source); -ar->linedefined=cl->l.p->linedefined; -ar->lastlinedefined=cl->l.p->lastlinedefined; -ar->what=(ar->linedefined==0)?"main":"Lua"; -} -luaO_chunkid(ar->short_src,ar->source,60); -} -static void info_tailcall(lua_Debug*ar){ -ar->name=ar->namewhat=""; -ar->what="tail"; -ar->lastlinedefined=ar->linedefined=ar->currentline=-1; -ar->source="=(tail call)"; -luaO_chunkid(ar->short_src,ar->source,60); -ar->nups=0; -} -static void collectvalidlines(lua_State*L,Closure*f){ -if(f==NULL||f->c.isC){ -setnilvalue(L->top); -} -else{ -Table*t=luaH_new(L,0,0); -int*lineinfo=f->l.p->lineinfo; -int i; -for(i=0;il.p->sizelineinfo;i++) -setbvalue(luaH_setnum(L,t,lineinfo[i]),1); -sethvalue(L,L->top,t); -} -incr_top(L); -} -static int auxgetinfo(lua_State*L,const char*what,lua_Debug*ar, -Closure*f,CallInfo*ci){ -int status=1; -if(f==NULL){ -info_tailcall(ar); -return status; -} -for(;*what;what++){ -switch(*what){ -case'S':{ -funcinfo(ar,f); -break; -} -case'l':{ -ar->currentline=(ci)?currentline(L,ci):-1; -break; -} -case'u':{ -ar->nups=f->c.nupvalues; -break; -} -case'n':{ -ar->namewhat=(ci)?NULL:NULL; -if(ar->namewhat==NULL){ -ar->namewhat=""; -ar->name=NULL; -} -break; -} -case'L': -case'f': -break; -default:status=0; -} -} -return status; -} -static int lua_getinfo(lua_State*L,const char*what,lua_Debug*ar){ -int status; -Closure*f=NULL; -CallInfo*ci=NULL; -if(*what=='>'){ -StkId func=L->top-1; -luai_apicheck(L,ttisfunction(func)); -what++; -f=clvalue(func); -L->top--; -} -else if(ar->i_ci!=0){ -ci=L->base_ci+ar->i_ci; -f=clvalue(ci->func); -} -status=auxgetinfo(L,what,ar,f,ci); -if(strchr(what,'f')){ -if(f==NULL)setnilvalue(L->top); -else setclvalue(L,L->top,f); -incr_top(L); -} -if(strchr(what,'L')) -collectvalidlines(L,f); -return status; -} -static int isinstack(CallInfo*ci,const TValue*o){ -StkId p; -for(p=ci->base;ptop;p++) -if(o==p)return 1; -return 0; -} -static void luaG_typeerror(lua_State*L,const TValue*o,const char*op){ -const char*name=NULL; -const char*t=luaT_typenames[ttype(o)]; -const char*kind=(isinstack(L->ci,o))? -NULL: -NULL; -if(kind) -luaG_runerror(L,"attempt to %s %s "LUA_QL("%s")" (a %s value)", -op,kind,name,t); -else -luaG_runerror(L,"attempt to %s a %s value",op,t); -} -static void luaG_concaterror(lua_State*L,StkId p1,StkId p2){ -if(ttisstring(p1)||ttisnumber(p1))p1=p2; -luaG_typeerror(L,p1,"concatenate"); -} -static void luaG_aritherror(lua_State*L,const TValue*p1,const TValue*p2){ -TValue temp; -if(luaV_tonumber(p1,&temp)==NULL) -p2=p1; -luaG_typeerror(L,p2,"perform arithmetic on"); -} -static int luaG_ordererror(lua_State*L,const TValue*p1,const TValue*p2){ -const char*t1=luaT_typenames[ttype(p1)]; -const char*t2=luaT_typenames[ttype(p2)]; -if(t1[2]==t2[2]) -luaG_runerror(L,"attempt to compare two %s values",t1); -else -luaG_runerror(L,"attempt to compare %s with %s",t1,t2); -return 0; -} -static void addinfo(lua_State*L,const char*msg){ -CallInfo*ci=L->ci; -if(isLua(ci)){ -char buff[60]; -int line=currentline(L,ci); -luaO_chunkid(buff,getstr(getluaproto(ci)->source),60); -luaO_pushfstring(L,"%s:%d: %s",buff,line,msg); -} -} -static void luaG_errormsg(lua_State*L){ -if(L->errfunc!=0){ -StkId errfunc=restorestack(L,L->errfunc); -if(!ttisfunction(errfunc))luaD_throw(L,5); -setobj(L,L->top,L->top-1); -setobj(L,L->top-1,errfunc); -incr_top(L); -luaD_call(L,L->top-2,1); -} -luaD_throw(L,2); -} -static void luaG_runerror(lua_State*L,const char*fmt,...){ -va_list argp; -va_start(argp,fmt); -addinfo(L,luaO_pushvfstring(L,fmt,argp)); -va_end(argp); -luaG_errormsg(L); -} -static int luaZ_fill(ZIO*z){ -size_t size; -lua_State*L=z->L; -const char*buff; -buff=z->reader(L,z->data,&size); -if(buff==NULL||size==0)return(-1); -z->n=size-1; -z->p=buff; -return char2int(*(z->p++)); -} -static void luaZ_init(lua_State*L,ZIO*z,lua_Reader reader,void*data){ -z->L=L; -z->reader=reader; -z->data=data; -z->n=0; -z->p=NULL; -} -static char*luaZ_openspace(lua_State*L,Mbuffer*buff,size_t n){ -if(n>buff->buffsize){ -if(n<32)n=32; -luaZ_resizebuffer(L,buff,n); -} -return buff->buffer; -} -#define opmode(t,a,b,c,m)(((t)<<7)|((a)<<6)|((b)<<4)|((c)<<2)|(m)) -static const lu_byte luaP_opmodes[(cast(int,OP_VARARG)+1)]={ -opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgK,OpArgN,iABx) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgU,OpArgN,iABC) -,opmode(0,1,OpArgK,OpArgN,iABx) -,opmode(0,1,OpArgR,OpArgK,iABC) -,opmode(0,0,OpArgK,OpArgN,iABx) -,opmode(0,0,OpArgU,OpArgN,iABC) -,opmode(0,0,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgR,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgK,OpArgK,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgR,iABC) -,opmode(0,0,OpArgR,OpArgN,iAsBx) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,0,OpArgK,OpArgK,iABC) -,opmode(1,1,OpArgR,OpArgU,iABC) -,opmode(1,1,OpArgR,OpArgU,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,1,OpArgU,OpArgU,iABC) -,opmode(0,0,OpArgU,OpArgN,iABC) -,opmode(0,1,OpArgR,OpArgN,iAsBx) -,opmode(0,1,OpArgR,OpArgN,iAsBx) -,opmode(1,0,OpArgN,OpArgU,iABC) -,opmode(0,0,OpArgU,OpArgU,iABC) -,opmode(0,0,OpArgN,OpArgN,iABC) -,opmode(0,1,OpArgU,OpArgN,iABx) -,opmode(0,1,OpArgU,OpArgN,iABC) -}; -#define next(ls)(ls->current=zgetc(ls->z)) -#define currIsNewline(ls)(ls->current=='\n'||ls->current=='\r') -static const char*const luaX_tokens[]={ -"and","break","do","else","elseif", -"end","false","for","function","if", -"in","local","nil","not","or","repeat", -"return","then","true","until","while", -"..","...","==",">=","<=","~=", -"","","","", -NULL -}; -#define save_and_next(ls)(save(ls,ls->current),next(ls)) -static void save(LexState*ls,int c){ -Mbuffer*b=ls->buff; -if(b->n+1>b->buffsize){ -size_t newsize; -if(b->buffsize>=((size_t)(~(size_t)0)-2)/2) -luaX_lexerror(ls,"lexical element too long",0); -newsize=b->buffsize*2; -luaZ_resizebuffer(ls->L,b,newsize); -} -b->buffer[b->n++]=cast(char,c); -} -static void luaX_init(lua_State*L){ -int i; -for(i=0;i<(cast(int,TK_WHILE-257+1));i++){ -TString*ts=luaS_new(L,luaX_tokens[i]); -luaS_fix(ts); -ts->tsv.reserved=cast_byte(i+1); -} -} -static const char*luaX_token2str(LexState*ls,int token){ -if(token<257){ -return(iscntrl(token))?luaO_pushfstring(ls->L,"char(%d)",token): -luaO_pushfstring(ls->L,"%c",token); -} -else -return luaX_tokens[token-257]; -} -static const char*txtToken(LexState*ls,int token){ -switch(token){ -case TK_NAME: -case TK_STRING: -case TK_NUMBER: -save(ls,'\0'); -return luaZ_buffer(ls->buff); -default: -return luaX_token2str(ls,token); -} -} -static void luaX_lexerror(LexState*ls,const char*msg,int token){ -char buff[80]; -luaO_chunkid(buff,getstr(ls->source),80); -msg=luaO_pushfstring(ls->L,"%s:%d: %s",buff,ls->linenumber,msg); -if(token) -luaO_pushfstring(ls->L,"%s near "LUA_QL("%s"),msg,txtToken(ls,token)); -luaD_throw(ls->L,3); -} -static void luaX_syntaxerror(LexState*ls,const char*msg){ -luaX_lexerror(ls,msg,ls->t.token); -} -static TString*luaX_newstring(LexState*ls,const char*str,size_t l){ -lua_State*L=ls->L; -TString*ts=luaS_newlstr(L,str,l); -TValue*o=luaH_setstr(L,ls->fs->h,ts); -if(ttisnil(o)){ -setbvalue(o,1); -luaC_checkGC(L); -} -return ts; -} -static void inclinenumber(LexState*ls){ -int old=ls->current; -next(ls); -if(currIsNewline(ls)&&ls->current!=old) -next(ls); -if(++ls->linenumber>=(INT_MAX-2)) -luaX_syntaxerror(ls,"chunk has too many lines"); -} -static void luaX_setinput(lua_State*L,LexState*ls,ZIO*z,TString*source){ -ls->decpoint='.'; -ls->L=L; -ls->lookahead.token=TK_EOS; -ls->z=z; -ls->fs=NULL; -ls->linenumber=1; -ls->lastline=1; -ls->source=source; -luaZ_resizebuffer(ls->L,ls->buff,32); -next(ls); -} -static int check_next(LexState*ls,const char*set){ -if(!strchr(set,ls->current)) -return 0; -save_and_next(ls); -return 1; -} -static void buffreplace(LexState*ls,char from,char to){ -size_t n=luaZ_bufflen(ls->buff); -char*p=luaZ_buffer(ls->buff); -while(n--) -if(p[n]==from)p[n]=to; -} -static void read_numeral(LexState*ls,SemInfo*seminfo){ -do{ -save_and_next(ls); -}while(isdigit(ls->current)||ls->current=='.'); -if(check_next(ls,"Ee")) -check_next(ls,"+-"); -while(isalnum(ls->current)||ls->current=='_') -save_and_next(ls); -save(ls,'\0'); -buffreplace(ls,'.',ls->decpoint); -if(!luaO_str2d(luaZ_buffer(ls->buff),&seminfo->r)) -luaX_lexerror(ls,"malformed number",TK_NUMBER); -} -static int skip_sep(LexState*ls){ -int count=0; -int s=ls->current; -save_and_next(ls); -while(ls->current=='='){ -save_and_next(ls); -count++; -} -return(ls->current==s)?count:(-count)-1; -} -static void read_long_string(LexState*ls,SemInfo*seminfo,int sep){ -int cont=0; -(void)(cont); -save_and_next(ls); -if(currIsNewline(ls)) -inclinenumber(ls); -for(;;){ -switch(ls->current){ -case(-1): -luaX_lexerror(ls,(seminfo)?"unfinished long string": -"unfinished long comment",TK_EOS); -break; -case']':{ -if(skip_sep(ls)==sep){ -save_and_next(ls); -goto endloop; -} -break; -} -case'\n': -case'\r':{ -save(ls,'\n'); -inclinenumber(ls); -if(!seminfo)luaZ_resetbuffer(ls->buff); -break; -} -default:{ -if(seminfo)save_and_next(ls); -else next(ls); -} -} -}endloop: -if(seminfo) -seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+(2+sep), -luaZ_bufflen(ls->buff)-2*(2+sep)); -} -static void read_string(LexState*ls,int del,SemInfo*seminfo){ -save_and_next(ls); -while(ls->current!=del){ -switch(ls->current){ -case(-1): -luaX_lexerror(ls,"unfinished string",TK_EOS); -continue; -case'\n': -case'\r': -luaX_lexerror(ls,"unfinished string",TK_STRING); -continue; -case'\\':{ -int c; -next(ls); -switch(ls->current){ -case'a':c='\a';break; -case'b':c='\b';break; -case'f':c='\f';break; -case'n':c='\n';break; -case'r':c='\r';break; -case't':c='\t';break; -case'v':c='\v';break; -case'\n': -case'\r':save(ls,'\n');inclinenumber(ls);continue; -case(-1):continue; -default:{ -if(!isdigit(ls->current)) -save_and_next(ls); -else{ -int i=0; -c=0; -do{ -c=10*c+(ls->current-'0'); -next(ls); -}while(++i<3&&isdigit(ls->current)); -if(c>UCHAR_MAX) -luaX_lexerror(ls,"escape sequence too large",TK_STRING); -save(ls,c); -} -continue; -} -} -save(ls,c); -next(ls); -continue; -} -default: -save_and_next(ls); -} -} -save_and_next(ls); -seminfo->ts=luaX_newstring(ls,luaZ_buffer(ls->buff)+1, -luaZ_bufflen(ls->buff)-2); -} -static int llex(LexState*ls,SemInfo*seminfo){ -luaZ_resetbuffer(ls->buff); -for(;;){ -switch(ls->current){ -case'\n': -case'\r':{ -inclinenumber(ls); -continue; -} -case'-':{ -next(ls); -if(ls->current!='-')return'-'; -next(ls); -if(ls->current=='['){ -int sep=skip_sep(ls); -luaZ_resetbuffer(ls->buff); -if(sep>=0){ -read_long_string(ls,NULL,sep); -luaZ_resetbuffer(ls->buff); -continue; -} -} -while(!currIsNewline(ls)&&ls->current!=(-1)) -next(ls); -continue; -} -case'[':{ -int sep=skip_sep(ls); -if(sep>=0){ -read_long_string(ls,seminfo,sep); -return TK_STRING; -} -else if(sep==-1)return'['; -else luaX_lexerror(ls,"invalid long string delimiter",TK_STRING); -} -case'=':{ -next(ls); -if(ls->current!='=')return'='; -else{next(ls);return TK_EQ;} -} -case'<':{ -next(ls); -if(ls->current!='=')return'<'; -else{next(ls);return TK_LE;} -} -case'>':{ -next(ls); -if(ls->current!='=')return'>'; -else{next(ls);return TK_GE;} -} -case'~':{ -next(ls); -if(ls->current!='=')return'~'; -else{next(ls);return TK_NE;} -} -case'"': -case'\'':{ -read_string(ls,ls->current,seminfo); -return TK_STRING; -} -case'.':{ -save_and_next(ls); -if(check_next(ls,".")){ -if(check_next(ls,".")) -return TK_DOTS; -else return TK_CONCAT; -} -else if(!isdigit(ls->current))return'.'; -else{ -read_numeral(ls,seminfo); -return TK_NUMBER; -} -} -case(-1):{ -return TK_EOS; -} -default:{ -if(isspace(ls->current)){ -next(ls); -continue; -} -else if(isdigit(ls->current)){ -read_numeral(ls,seminfo); -return TK_NUMBER; -} -else if(isalpha(ls->current)||ls->current=='_'){ -TString*ts; -do{ -save_and_next(ls); -}while(isalnum(ls->current)||ls->current=='_'); -ts=luaX_newstring(ls,luaZ_buffer(ls->buff), -luaZ_bufflen(ls->buff)); -if(ts->tsv.reserved>0) -return ts->tsv.reserved-1+257; -else{ -seminfo->ts=ts; -return TK_NAME; -} -} -else{ -int c=ls->current; -next(ls); -return c; -} -} -} -} -} -static void luaX_next(LexState*ls){ -ls->lastline=ls->linenumber; -if(ls->lookahead.token!=TK_EOS){ -ls->t=ls->lookahead; -ls->lookahead.token=TK_EOS; -} -else -ls->t.token=llex(ls,&ls->t.seminfo); -} -static void luaX_lookahead(LexState*ls){ -ls->lookahead.token=llex(ls,&ls->lookahead.seminfo); -} -#define hasjumps(e)((e)->t!=(e)->f) -static int isnumeral(expdesc*e){ -return(e->k==VKNUM&&e->t==(-1)&&e->f==(-1)); -} -static void luaK_nil(FuncState*fs,int from,int n){ -Instruction*previous; -if(fs->pc>fs->lasttarget){ -if(fs->pc==0){ -if(from>=fs->nactvar) -return; -} -else{ -previous=&fs->f->code[fs->pc-1]; -if(GET_OPCODE(*previous)==OP_LOADNIL){ -int pfrom=GETARG_A(*previous); -int pto=GETARG_B(*previous); -if(pfrom<=from&&from<=pto+1){ -if(from+n-1>pto) -SETARG_B(*previous,from+n-1); -return; -} -} -} -} -luaK_codeABC(fs,OP_LOADNIL,from,from+n-1,0); -} -static int luaK_jump(FuncState*fs){ -int jpc=fs->jpc; -int j; -fs->jpc=(-1); -j=luaK_codeAsBx(fs,OP_JMP,0,(-1)); -luaK_concat(fs,&j,jpc); -return j; -} -static void luaK_ret(FuncState*fs,int first,int nret){ -luaK_codeABC(fs,OP_RETURN,first,nret+1,0); -} -static int condjump(FuncState*fs,OpCode op,int A,int B,int C){ -luaK_codeABC(fs,op,A,B,C); -return luaK_jump(fs); -} -static void fixjump(FuncState*fs,int pc,int dest){ -Instruction*jmp=&fs->f->code[pc]; -int offset=dest-(pc+1); -if(abs(offset)>(((1<<(9+9))-1)>>1)) -luaX_syntaxerror(fs->ls,"control structure too long"); -SETARG_sBx(*jmp,offset); -} -static int luaK_getlabel(FuncState*fs){ -fs->lasttarget=fs->pc; -return fs->pc; -} -static int getjump(FuncState*fs,int pc){ -int offset=GETARG_sBx(fs->f->code[pc]); -if(offset==(-1)) -return(-1); -else -return(pc+1)+offset; -} -static Instruction*getjumpcontrol(FuncState*fs,int pc){ -Instruction*pi=&fs->f->code[pc]; -if(pc>=1&&testTMode(GET_OPCODE(*(pi-1)))) -return pi-1; -else -return pi; -} -static int need_value(FuncState*fs,int list){ -for(;list!=(-1);list=getjump(fs,list)){ -Instruction i=*getjumpcontrol(fs,list); -if(GET_OPCODE(i)!=OP_TESTSET)return 1; -} -return 0; -} -static int patchtestreg(FuncState*fs,int node,int reg){ -Instruction*i=getjumpcontrol(fs,node); -if(GET_OPCODE(*i)!=OP_TESTSET) -return 0; -if(reg!=((1<<8)-1)&®!=GETARG_B(*i)) -SETARG_A(*i,reg); -else -*i=CREATE_ABC(OP_TEST,GETARG_B(*i),0,GETARG_C(*i)); -return 1; -} -static void removevalues(FuncState*fs,int list){ -for(;list!=(-1);list=getjump(fs,list)) -patchtestreg(fs,list,((1<<8)-1)); -} -static void patchlistaux(FuncState*fs,int list,int vtarget,int reg, -int dtarget){ -while(list!=(-1)){ -int next=getjump(fs,list); -if(patchtestreg(fs,list,reg)) -fixjump(fs,list,vtarget); -else -fixjump(fs,list,dtarget); -list=next; -} -} -static void dischargejpc(FuncState*fs){ -patchlistaux(fs,fs->jpc,fs->pc,((1<<8)-1),fs->pc); -fs->jpc=(-1); -} -static void luaK_patchlist(FuncState*fs,int list,int target){ -if(target==fs->pc) -luaK_patchtohere(fs,list); -else{ -patchlistaux(fs,list,target,((1<<8)-1),target); -} -} -static void luaK_patchtohere(FuncState*fs,int list){ -luaK_getlabel(fs); -luaK_concat(fs,&fs->jpc,list); -} -static void luaK_concat(FuncState*fs,int*l1,int l2){ -if(l2==(-1))return; -else if(*l1==(-1)) -*l1=l2; -else{ -int list=*l1; -int next; -while((next=getjump(fs,list))!=(-1)) -list=next; -fixjump(fs,list,l2); -} -} -static void luaK_checkstack(FuncState*fs,int n){ -int newstack=fs->freereg+n; -if(newstack>fs->f->maxstacksize){ -if(newstack>=250) -luaX_syntaxerror(fs->ls,"function or expression too complex"); -fs->f->maxstacksize=cast_byte(newstack); -} -} -static void luaK_reserveregs(FuncState*fs,int n){ -luaK_checkstack(fs,n); -fs->freereg+=n; -} -static void freereg(FuncState*fs,int reg){ -if(!ISK(reg)&®>=fs->nactvar){ -fs->freereg--; -} -} -static void freeexp(FuncState*fs,expdesc*e){ -if(e->k==VNONRELOC) -freereg(fs,e->u.s.info); -} -static int addk(FuncState*fs,TValue*k,TValue*v){ -lua_State*L=fs->L; -TValue*idx=luaH_set(L,fs->h,k); -Proto*f=fs->f; -int oldsize=f->sizek; -if(ttisnumber(idx)){ -return cast_int(nvalue(idx)); -} -else{ -setnvalue(idx,cast_num(fs->nk)); -luaM_growvector(L,f->k,fs->nk,f->sizek,TValue, -((1<<(9+9))-1),"constant table overflow"); -while(oldsizesizek)setnilvalue(&f->k[oldsize++]); -setobj(L,&f->k[fs->nk],v); -luaC_barrier(L,f,v); -return fs->nk++; -} -} -static int luaK_stringK(FuncState*fs,TString*s){ -TValue o; -setsvalue(fs->L,&o,s); -return addk(fs,&o,&o); -} -static int luaK_numberK(FuncState*fs,lua_Number r){ -TValue o; -setnvalue(&o,r); -return addk(fs,&o,&o); -} -static int boolK(FuncState*fs,int b){ -TValue o; -setbvalue(&o,b); -return addk(fs,&o,&o); -} -static int nilK(FuncState*fs){ -TValue k,v; -setnilvalue(&v); -sethvalue(fs->L,&k,fs->h); -return addk(fs,&k,&v); -} -static void luaK_setreturns(FuncState*fs,expdesc*e,int nresults){ -if(e->k==VCALL){ -SETARG_C(getcode(fs,e),nresults+1); -} -else if(e->k==VVARARG){ -SETARG_B(getcode(fs,e),nresults+1); -SETARG_A(getcode(fs,e),fs->freereg); -luaK_reserveregs(fs,1); -} -} -static void luaK_setoneret(FuncState*fs,expdesc*e){ -if(e->k==VCALL){ -e->k=VNONRELOC; -e->u.s.info=GETARG_A(getcode(fs,e)); -} -else if(e->k==VVARARG){ -SETARG_B(getcode(fs,e),2); -e->k=VRELOCABLE; -} -} -static void luaK_dischargevars(FuncState*fs,expdesc*e){ -switch(e->k){ -case VLOCAL:{ -e->k=VNONRELOC; -break; -} -case VUPVAL:{ -e->u.s.info=luaK_codeABC(fs,OP_GETUPVAL,0,e->u.s.info,0); -e->k=VRELOCABLE; -break; -} -case VGLOBAL:{ -e->u.s.info=luaK_codeABx(fs,OP_GETGLOBAL,0,e->u.s.info); -e->k=VRELOCABLE; -break; -} -case VINDEXED:{ -freereg(fs,e->u.s.aux); -freereg(fs,e->u.s.info); -e->u.s.info=luaK_codeABC(fs,OP_GETTABLE,0,e->u.s.info,e->u.s.aux); -e->k=VRELOCABLE; -break; -} -case VVARARG: -case VCALL:{ -luaK_setoneret(fs,e); -break; -} -default:break; -} -} -static int code_label(FuncState*fs,int A,int b,int jump){ -luaK_getlabel(fs); -return luaK_codeABC(fs,OP_LOADBOOL,A,b,jump); -} -static void discharge2reg(FuncState*fs,expdesc*e,int reg){ -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:{ -luaK_nil(fs,reg,1); -break; -} -case VFALSE:case VTRUE:{ -luaK_codeABC(fs,OP_LOADBOOL,reg,e->k==VTRUE,0); -break; -} -case VK:{ -luaK_codeABx(fs,OP_LOADK,reg,e->u.s.info); -break; -} -case VKNUM:{ -luaK_codeABx(fs,OP_LOADK,reg,luaK_numberK(fs,e->u.nval)); -break; -} -case VRELOCABLE:{ -Instruction*pc=&getcode(fs,e); -SETARG_A(*pc,reg); -break; -} -case VNONRELOC:{ -if(reg!=e->u.s.info) -luaK_codeABC(fs,OP_MOVE,reg,e->u.s.info,0); -break; -} -default:{ -return; -} -} -e->u.s.info=reg; -e->k=VNONRELOC; -} -static void discharge2anyreg(FuncState*fs,expdesc*e){ -if(e->k!=VNONRELOC){ -luaK_reserveregs(fs,1); -discharge2reg(fs,e,fs->freereg-1); -} -} -static void exp2reg(FuncState*fs,expdesc*e,int reg){ -discharge2reg(fs,e,reg); -if(e->k==VJMP) -luaK_concat(fs,&e->t,e->u.s.info); -if(hasjumps(e)){ -int final; -int p_f=(-1); -int p_t=(-1); -if(need_value(fs,e->t)||need_value(fs,e->f)){ -int fj=(e->k==VJMP)?(-1):luaK_jump(fs); -p_f=code_label(fs,reg,0,1); -p_t=code_label(fs,reg,1,0); -luaK_patchtohere(fs,fj); -} -final=luaK_getlabel(fs); -patchlistaux(fs,e->f,final,reg,p_f); -patchlistaux(fs,e->t,final,reg,p_t); -} -e->f=e->t=(-1); -e->u.s.info=reg; -e->k=VNONRELOC; -} -static void luaK_exp2nextreg(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -freeexp(fs,e); -luaK_reserveregs(fs,1); -exp2reg(fs,e,fs->freereg-1); -} -static int luaK_exp2anyreg(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -if(e->k==VNONRELOC){ -if(!hasjumps(e))return e->u.s.info; -if(e->u.s.info>=fs->nactvar){ -exp2reg(fs,e,e->u.s.info); -return e->u.s.info; -} -} -luaK_exp2nextreg(fs,e); -return e->u.s.info; -} -static void luaK_exp2val(FuncState*fs,expdesc*e){ -if(hasjumps(e)) -luaK_exp2anyreg(fs,e); -else -luaK_dischargevars(fs,e); -} -static int luaK_exp2RK(FuncState*fs,expdesc*e){ -luaK_exp2val(fs,e); -switch(e->k){ -case VKNUM: -case VTRUE: -case VFALSE: -case VNIL:{ -if(fs->nk<=((1<<(9-1))-1)){ -e->u.s.info=(e->k==VNIL)?nilK(fs): -(e->k==VKNUM)?luaK_numberK(fs,e->u.nval): -boolK(fs,(e->k==VTRUE)); -e->k=VK; -return RKASK(e->u.s.info); -} -else break; -} -case VK:{ -if(e->u.s.info<=((1<<(9-1))-1)) -return RKASK(e->u.s.info); -else break; -} -default:break; -} -return luaK_exp2anyreg(fs,e); -} -static void luaK_storevar(FuncState*fs,expdesc*var,expdesc*ex){ -switch(var->k){ -case VLOCAL:{ -freeexp(fs,ex); -exp2reg(fs,ex,var->u.s.info); -return; -} -case VUPVAL:{ -int e=luaK_exp2anyreg(fs,ex); -luaK_codeABC(fs,OP_SETUPVAL,e,var->u.s.info,0); -break; -} -case VGLOBAL:{ -int e=luaK_exp2anyreg(fs,ex); -luaK_codeABx(fs,OP_SETGLOBAL,e,var->u.s.info); -break; -} -case VINDEXED:{ -int e=luaK_exp2RK(fs,ex); -luaK_codeABC(fs,OP_SETTABLE,var->u.s.info,var->u.s.aux,e); -break; -} -default:{ -break; -} -} -freeexp(fs,ex); -} -static void luaK_self(FuncState*fs,expdesc*e,expdesc*key){ -int func; -luaK_exp2anyreg(fs,e); -freeexp(fs,e); -func=fs->freereg; -luaK_reserveregs(fs,2); -luaK_codeABC(fs,OP_SELF,func,e->u.s.info,luaK_exp2RK(fs,key)); -freeexp(fs,key); -e->u.s.info=func; -e->k=VNONRELOC; -} -static void invertjump(FuncState*fs,expdesc*e){ -Instruction*pc=getjumpcontrol(fs,e->u.s.info); -SETARG_A(*pc,!(GETARG_A(*pc))); -} -static int jumponcond(FuncState*fs,expdesc*e,int cond){ -if(e->k==VRELOCABLE){ -Instruction ie=getcode(fs,e); -if(GET_OPCODE(ie)==OP_NOT){ -fs->pc--; -return condjump(fs,OP_TEST,GETARG_B(ie),0,!cond); -} -} -discharge2anyreg(fs,e); -freeexp(fs,e); -return condjump(fs,OP_TESTSET,((1<<8)-1),e->u.s.info,cond); -} -static void luaK_goiftrue(FuncState*fs,expdesc*e){ -int pc; -luaK_dischargevars(fs,e); -switch(e->k){ -case VK:case VKNUM:case VTRUE:{ -pc=(-1); -break; -} -case VJMP:{ -invertjump(fs,e); -pc=e->u.s.info; -break; -} -default:{ -pc=jumponcond(fs,e,0); -break; -} -} -luaK_concat(fs,&e->f,pc); -luaK_patchtohere(fs,e->t); -e->t=(-1); -} -static void luaK_goiffalse(FuncState*fs,expdesc*e){ -int pc; -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:case VFALSE:{ -pc=(-1); -break; -} -case VJMP:{ -pc=e->u.s.info; -break; -} -default:{ -pc=jumponcond(fs,e,1); -break; -} -} -luaK_concat(fs,&e->t,pc); -luaK_patchtohere(fs,e->f); -e->f=(-1); -} -static void codenot(FuncState*fs,expdesc*e){ -luaK_dischargevars(fs,e); -switch(e->k){ -case VNIL:case VFALSE:{ -e->k=VTRUE; -break; -} -case VK:case VKNUM:case VTRUE:{ -e->k=VFALSE; -break; -} -case VJMP:{ -invertjump(fs,e); -break; -} -case VRELOCABLE: -case VNONRELOC:{ -discharge2anyreg(fs,e); -freeexp(fs,e); -e->u.s.info=luaK_codeABC(fs,OP_NOT,0,e->u.s.info,0); -e->k=VRELOCABLE; -break; -} -default:{ -break; -} -} -{int temp=e->f;e->f=e->t;e->t=temp;} -removevalues(fs,e->f); -removevalues(fs,e->t); -} -static void luaK_indexed(FuncState*fs,expdesc*t,expdesc*k){ -t->u.s.aux=luaK_exp2RK(fs,k); -t->k=VINDEXED; -} -static int constfolding(OpCode op,expdesc*e1,expdesc*e2){ -lua_Number v1,v2,r; -if(!isnumeral(e1)||!isnumeral(e2))return 0; -v1=e1->u.nval; -v2=e2->u.nval; -switch(op){ -case OP_ADD:r=luai_numadd(v1,v2);break; -case OP_SUB:r=luai_numsub(v1,v2);break; -case OP_MUL:r=luai_nummul(v1,v2);break; -case OP_DIV: -if(v2==0)return 0; -r=luai_numdiv(v1,v2);break; -case OP_MOD: -if(v2==0)return 0; -r=luai_nummod(v1,v2);break; -case OP_POW:r=luai_numpow(v1,v2);break; -case OP_UNM:r=luai_numunm(v1);break; -case OP_LEN:return 0; -default:r=0;break; -} -if(luai_numisnan(r))return 0; -e1->u.nval=r; -return 1; -} -static void codearith(FuncState*fs,OpCode op,expdesc*e1,expdesc*e2){ -if(constfolding(op,e1,e2)) -return; -else{ -int o2=(op!=OP_UNM&&op!=OP_LEN)?luaK_exp2RK(fs,e2):0; -int o1=luaK_exp2RK(fs,e1); -if(o1>o2){ -freeexp(fs,e1); -freeexp(fs,e2); -} -else{ -freeexp(fs,e2); -freeexp(fs,e1); -} -e1->u.s.info=luaK_codeABC(fs,op,0,o1,o2); -e1->k=VRELOCABLE; -} -} -static void codecomp(FuncState*fs,OpCode op,int cond,expdesc*e1, -expdesc*e2){ -int o1=luaK_exp2RK(fs,e1); -int o2=luaK_exp2RK(fs,e2); -freeexp(fs,e2); -freeexp(fs,e1); -if(cond==0&&op!=OP_EQ){ -int temp; -temp=o1;o1=o2;o2=temp; -cond=1; -} -e1->u.s.info=condjump(fs,op,cond,o1,o2); -e1->k=VJMP; -} -static void luaK_prefix(FuncState*fs,UnOpr op,expdesc*e){ -expdesc e2; -e2.t=e2.f=(-1);e2.k=VKNUM;e2.u.nval=0; -switch(op){ -case OPR_MINUS:{ -if(!isnumeral(e)) -luaK_exp2anyreg(fs,e); -codearith(fs,OP_UNM,e,&e2); -break; -} -case OPR_NOT:codenot(fs,e);break; -case OPR_LEN:{ -luaK_exp2anyreg(fs,e); -codearith(fs,OP_LEN,e,&e2); -break; -} -default:; -} -} -static void luaK_infix(FuncState*fs,BinOpr op,expdesc*v){ -switch(op){ -case OPR_AND:{ -luaK_goiftrue(fs,v); -break; -} -case OPR_OR:{ -luaK_goiffalse(fs,v); -break; -} -case OPR_CONCAT:{ -luaK_exp2nextreg(fs,v); -break; -} -case OPR_ADD:case OPR_SUB:case OPR_MUL:case OPR_DIV: -case OPR_MOD:case OPR_POW:{ -if(!isnumeral(v))luaK_exp2RK(fs,v); -break; -} -default:{ -luaK_exp2RK(fs,v); -break; -} -} -} -static void luaK_posfix(FuncState*fs,BinOpr op,expdesc*e1,expdesc*e2){ -switch(op){ -case OPR_AND:{ -luaK_dischargevars(fs,e2); -luaK_concat(fs,&e2->f,e1->f); -*e1=*e2; -break; -} -case OPR_OR:{ -luaK_dischargevars(fs,e2); -luaK_concat(fs,&e2->t,e1->t); -*e1=*e2; -break; -} -case OPR_CONCAT:{ -luaK_exp2val(fs,e2); -if(e2->k==VRELOCABLE&&GET_OPCODE(getcode(fs,e2))==OP_CONCAT){ -freeexp(fs,e1); -SETARG_B(getcode(fs,e2),e1->u.s.info); -e1->k=VRELOCABLE;e1->u.s.info=e2->u.s.info; -} -else{ -luaK_exp2nextreg(fs,e2); -codearith(fs,OP_CONCAT,e1,e2); -} -break; -} -case OPR_ADD:codearith(fs,OP_ADD,e1,e2);break; -case OPR_SUB:codearith(fs,OP_SUB,e1,e2);break; -case OPR_MUL:codearith(fs,OP_MUL,e1,e2);break; -case OPR_DIV:codearith(fs,OP_DIV,e1,e2);break; -case OPR_MOD:codearith(fs,OP_MOD,e1,e2);break; -case OPR_POW:codearith(fs,OP_POW,e1,e2);break; -case OPR_EQ:codecomp(fs,OP_EQ,1,e1,e2);break; -case OPR_NE:codecomp(fs,OP_EQ,0,e1,e2);break; -case OPR_LT:codecomp(fs,OP_LT,1,e1,e2);break; -case OPR_LE:codecomp(fs,OP_LE,1,e1,e2);break; -case OPR_GT:codecomp(fs,OP_LT,0,e1,e2);break; -case OPR_GE:codecomp(fs,OP_LE,0,e1,e2);break; -default:; -} -} -static void luaK_fixline(FuncState*fs,int line){ -fs->f->lineinfo[fs->pc-1]=line; -} -static int luaK_code(FuncState*fs,Instruction i,int line){ -Proto*f=fs->f; -dischargejpc(fs); -luaM_growvector(fs->L,f->code,fs->pc,f->sizecode,Instruction, -(INT_MAX-2),"code size overflow"); -f->code[fs->pc]=i; -luaM_growvector(fs->L,f->lineinfo,fs->pc,f->sizelineinfo,int, -(INT_MAX-2),"code size overflow"); -f->lineinfo[fs->pc]=line; -return fs->pc++; -} -static int luaK_codeABC(FuncState*fs,OpCode o,int a,int b,int c){ -return luaK_code(fs,CREATE_ABC(o,a,b,c),fs->ls->lastline); -} -static int luaK_codeABx(FuncState*fs,OpCode o,int a,unsigned int bc){ -return luaK_code(fs,CREATE_ABx(o,a,bc),fs->ls->lastline); -} -static void luaK_setlist(FuncState*fs,int base,int nelems,int tostore){ -int c=(nelems-1)/50+1; -int b=(tostore==(-1))?0:tostore; -if(c<=((1<<9)-1)) -luaK_codeABC(fs,OP_SETLIST,base,b,c); -else{ -luaK_codeABC(fs,OP_SETLIST,base,b,0); -luaK_code(fs,cast(Instruction,c),fs->ls->lastline); -} -fs->freereg=base+1; -} -#define hasmultret(k)((k)==VCALL||(k)==VVARARG) -#define getlocvar(fs,i)((fs)->f->locvars[(fs)->actvar[i]]) -#define luaY_checklimit(fs,v,l,m)if((v)>(l))errorlimit(fs,l,m) -typedef struct BlockCnt{ -struct BlockCnt*previous; -int breaklist; -lu_byte nactvar; -lu_byte upval; -lu_byte isbreakable; -}BlockCnt; -static void chunk(LexState*ls); -static void expr(LexState*ls,expdesc*v); -static void anchor_token(LexState*ls){ -if(ls->t.token==TK_NAME||ls->t.token==TK_STRING){ -TString*ts=ls->t.seminfo.ts; -luaX_newstring(ls,getstr(ts),ts->tsv.len); -} -} -static void error_expected(LexState*ls,int token){ -luaX_syntaxerror(ls, -luaO_pushfstring(ls->L,LUA_QL("%s")" expected",luaX_token2str(ls,token))); -} -static void errorlimit(FuncState*fs,int limit,const char*what){ -const char*msg=(fs->f->linedefined==0)? -luaO_pushfstring(fs->L,"main function has more than %d %s",limit,what): -luaO_pushfstring(fs->L,"function at line %d has more than %d %s", -fs->f->linedefined,limit,what); -luaX_lexerror(fs->ls,msg,0); -} -static int testnext(LexState*ls,int c){ -if(ls->t.token==c){ -luaX_next(ls); -return 1; -} -else return 0; -} -static void check(LexState*ls,int c){ -if(ls->t.token!=c) -error_expected(ls,c); -} -static void checknext(LexState*ls,int c){ -check(ls,c); -luaX_next(ls); -} -#define check_condition(ls,c,msg){if(!(c))luaX_syntaxerror(ls,msg);} -static void check_match(LexState*ls,int what,int who,int where){ -if(!testnext(ls,what)){ -if(where==ls->linenumber) -error_expected(ls,what); -else{ -luaX_syntaxerror(ls,luaO_pushfstring(ls->L, -LUA_QL("%s")" expected (to close "LUA_QL("%s")" at line %d)", -luaX_token2str(ls,what),luaX_token2str(ls,who),where)); -} -} -} -static TString*str_checkname(LexState*ls){ -TString*ts; -check(ls,TK_NAME); -ts=ls->t.seminfo.ts; -luaX_next(ls); -return ts; -} -static void init_exp(expdesc*e,expkind k,int i){ -e->f=e->t=(-1); -e->k=k; -e->u.s.info=i; -} -static void codestring(LexState*ls,expdesc*e,TString*s){ -init_exp(e,VK,luaK_stringK(ls->fs,s)); -} -static void checkname(LexState*ls,expdesc*e){ -codestring(ls,e,str_checkname(ls)); -} -static int registerlocalvar(LexState*ls,TString*varname){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int oldsize=f->sizelocvars; -luaM_growvector(ls->L,f->locvars,fs->nlocvars,f->sizelocvars, -LocVar,SHRT_MAX,"too many local variables"); -while(oldsizesizelocvars)f->locvars[oldsize++].varname=NULL; -f->locvars[fs->nlocvars].varname=varname; -luaC_objbarrier(ls->L,f,varname); -return fs->nlocvars++; -} -#define new_localvarliteral(ls,v,n)new_localvar(ls,luaX_newstring(ls,""v,(sizeof(v)/sizeof(char))-1),n) -static void new_localvar(LexState*ls,TString*name,int n){ -FuncState*fs=ls->fs; -luaY_checklimit(fs,fs->nactvar+n+1,200,"local variables"); -fs->actvar[fs->nactvar+n]=cast(unsigned short,registerlocalvar(ls,name)); -} -static void adjustlocalvars(LexState*ls,int nvars){ -FuncState*fs=ls->fs; -fs->nactvar=cast_byte(fs->nactvar+nvars); -for(;nvars;nvars--){ -getlocvar(fs,fs->nactvar-nvars).startpc=fs->pc; -} -} -static void removevars(LexState*ls,int tolevel){ -FuncState*fs=ls->fs; -while(fs->nactvar>tolevel) -getlocvar(fs,--fs->nactvar).endpc=fs->pc; -} -static int indexupvalue(FuncState*fs,TString*name,expdesc*v){ -int i; -Proto*f=fs->f; -int oldsize=f->sizeupvalues; -for(i=0;inups;i++){ -if(fs->upvalues[i].k==v->k&&fs->upvalues[i].info==v->u.s.info){ -return i; -} -} -luaY_checklimit(fs,f->nups+1,60,"upvalues"); -luaM_growvector(fs->L,f->upvalues,f->nups,f->sizeupvalues, -TString*,(INT_MAX-2),""); -while(oldsizesizeupvalues)f->upvalues[oldsize++]=NULL; -f->upvalues[f->nups]=name; -luaC_objbarrier(fs->L,f,name); -fs->upvalues[f->nups].k=cast_byte(v->k); -fs->upvalues[f->nups].info=cast_byte(v->u.s.info); -return f->nups++; -} -static int searchvar(FuncState*fs,TString*n){ -int i; -for(i=fs->nactvar-1;i>=0;i--){ -if(n==getlocvar(fs,i).varname) -return i; -} -return-1; -} -static void markupval(FuncState*fs,int level){ -BlockCnt*bl=fs->bl; -while(bl&&bl->nactvar>level)bl=bl->previous; -if(bl)bl->upval=1; -} -static int singlevaraux(FuncState*fs,TString*n,expdesc*var,int base){ -if(fs==NULL){ -init_exp(var,VGLOBAL,((1<<8)-1)); -return VGLOBAL; -} -else{ -int v=searchvar(fs,n); -if(v>=0){ -init_exp(var,VLOCAL,v); -if(!base) -markupval(fs,v); -return VLOCAL; -} -else{ -if(singlevaraux(fs->prev,n,var,0)==VGLOBAL) -return VGLOBAL; -var->u.s.info=indexupvalue(fs,n,var); -var->k=VUPVAL; -return VUPVAL; -} -} -} -static void singlevar(LexState*ls,expdesc*var){ -TString*varname=str_checkname(ls); -FuncState*fs=ls->fs; -if(singlevaraux(fs,varname,var,1)==VGLOBAL) -var->u.s.info=luaK_stringK(fs,varname); -} -static void adjust_assign(LexState*ls,int nvars,int nexps,expdesc*e){ -FuncState*fs=ls->fs; -int extra=nvars-nexps; -if(hasmultret(e->k)){ -extra++; -if(extra<0)extra=0; -luaK_setreturns(fs,e,extra); -if(extra>1)luaK_reserveregs(fs,extra-1); -} -else{ -if(e->k!=VVOID)luaK_exp2nextreg(fs,e); -if(extra>0){ -int reg=fs->freereg; -luaK_reserveregs(fs,extra); -luaK_nil(fs,reg,extra); -} -} -} -static void enterlevel(LexState*ls){ -if(++ls->L->nCcalls>200) -luaX_lexerror(ls,"chunk has too many syntax levels",0); -} -#define leavelevel(ls)((ls)->L->nCcalls--) -static void enterblock(FuncState*fs,BlockCnt*bl,lu_byte isbreakable){ -bl->breaklist=(-1); -bl->isbreakable=isbreakable; -bl->nactvar=fs->nactvar; -bl->upval=0; -bl->previous=fs->bl; -fs->bl=bl; -} -static void leaveblock(FuncState*fs){ -BlockCnt*bl=fs->bl; -fs->bl=bl->previous; -removevars(fs->ls,bl->nactvar); -if(bl->upval) -luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0); -fs->freereg=fs->nactvar; -luaK_patchtohere(fs,bl->breaklist); -} -static void pushclosure(LexState*ls,FuncState*func,expdesc*v){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int oldsize=f->sizep; -int i; -luaM_growvector(ls->L,f->p,fs->np,f->sizep,Proto*, -((1<<(9+9))-1),"constant table overflow"); -while(oldsizesizep)f->p[oldsize++]=NULL; -f->p[fs->np++]=func->f; -luaC_objbarrier(ls->L,f,func->f); -init_exp(v,VRELOCABLE,luaK_codeABx(fs,OP_CLOSURE,0,fs->np-1)); -for(i=0;if->nups;i++){ -OpCode o=(func->upvalues[i].k==VLOCAL)?OP_MOVE:OP_GETUPVAL; -luaK_codeABC(fs,o,0,func->upvalues[i].info,0); -} -} -static void open_func(LexState*ls,FuncState*fs){ -lua_State*L=ls->L; -Proto*f=luaF_newproto(L); -fs->f=f; -fs->prev=ls->fs; -fs->ls=ls; -fs->L=L; -ls->fs=fs; -fs->pc=0; -fs->lasttarget=-1; -fs->jpc=(-1); -fs->freereg=0; -fs->nk=0; -fs->np=0; -fs->nlocvars=0; -fs->nactvar=0; -fs->bl=NULL; -f->source=ls->source; -f->maxstacksize=2; -fs->h=luaH_new(L,0,0); -sethvalue(L,L->top,fs->h); -incr_top(L); -setptvalue(L,L->top,f); -incr_top(L); -} -static void close_func(LexState*ls){ -lua_State*L=ls->L; -FuncState*fs=ls->fs; -Proto*f=fs->f; -removevars(ls,0); -luaK_ret(fs,0,0); -luaM_reallocvector(L,f->code,f->sizecode,fs->pc,Instruction); -f->sizecode=fs->pc; -luaM_reallocvector(L,f->lineinfo,f->sizelineinfo,fs->pc,int); -f->sizelineinfo=fs->pc; -luaM_reallocvector(L,f->k,f->sizek,fs->nk,TValue); -f->sizek=fs->nk; -luaM_reallocvector(L,f->p,f->sizep,fs->np,Proto*); -f->sizep=fs->np; -luaM_reallocvector(L,f->locvars,f->sizelocvars,fs->nlocvars,LocVar); -f->sizelocvars=fs->nlocvars; -luaM_reallocvector(L,f->upvalues,f->sizeupvalues,f->nups,TString*); -f->sizeupvalues=f->nups; -ls->fs=fs->prev; -if(fs)anchor_token(ls); -L->top-=2; -} -static Proto*luaY_parser(lua_State*L,ZIO*z,Mbuffer*buff,const char*name){ -struct LexState lexstate; -struct FuncState funcstate; -lexstate.buff=buff; -luaX_setinput(L,&lexstate,z,luaS_new(L,name)); -open_func(&lexstate,&funcstate); -funcstate.f->is_vararg=2; -luaX_next(&lexstate); -chunk(&lexstate); -check(&lexstate,TK_EOS); -close_func(&lexstate); -return funcstate.f; -} -static void field(LexState*ls,expdesc*v){ -FuncState*fs=ls->fs; -expdesc key; -luaK_exp2anyreg(fs,v); -luaX_next(ls); -checkname(ls,&key); -luaK_indexed(fs,v,&key); -} -static void yindex(LexState*ls,expdesc*v){ -luaX_next(ls); -expr(ls,v); -luaK_exp2val(ls->fs,v); -checknext(ls,']'); -} -struct ConsControl{ -expdesc v; -expdesc*t; -int nh; -int na; -int tostore; -}; -static void recfield(LexState*ls,struct ConsControl*cc){ -FuncState*fs=ls->fs; -int reg=ls->fs->freereg; -expdesc key,val; -int rkkey; -if(ls->t.token==TK_NAME){ -luaY_checklimit(fs,cc->nh,(INT_MAX-2),"items in a constructor"); -checkname(ls,&key); -} -else -yindex(ls,&key); -cc->nh++; -checknext(ls,'='); -rkkey=luaK_exp2RK(fs,&key); -expr(ls,&val); -luaK_codeABC(fs,OP_SETTABLE,cc->t->u.s.info,rkkey,luaK_exp2RK(fs,&val)); -fs->freereg=reg; -} -static void closelistfield(FuncState*fs,struct ConsControl*cc){ -if(cc->v.k==VVOID)return; -luaK_exp2nextreg(fs,&cc->v); -cc->v.k=VVOID; -if(cc->tostore==50){ -luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore); -cc->tostore=0; -} -} -static void lastlistfield(FuncState*fs,struct ConsControl*cc){ -if(cc->tostore==0)return; -if(hasmultret(cc->v.k)){ -luaK_setmultret(fs,&cc->v); -luaK_setlist(fs,cc->t->u.s.info,cc->na,(-1)); -cc->na--; -} -else{ -if(cc->v.k!=VVOID) -luaK_exp2nextreg(fs,&cc->v); -luaK_setlist(fs,cc->t->u.s.info,cc->na,cc->tostore); -} -} -static void listfield(LexState*ls,struct ConsControl*cc){ -expr(ls,&cc->v); -luaY_checklimit(ls->fs,cc->na,(INT_MAX-2),"items in a constructor"); -cc->na++; -cc->tostore++; -} -static void constructor(LexState*ls,expdesc*t){ -FuncState*fs=ls->fs; -int line=ls->linenumber; -int pc=luaK_codeABC(fs,OP_NEWTABLE,0,0,0); -struct ConsControl cc; -cc.na=cc.nh=cc.tostore=0; -cc.t=t; -init_exp(t,VRELOCABLE,pc); -init_exp(&cc.v,VVOID,0); -luaK_exp2nextreg(ls->fs,t); -checknext(ls,'{'); -do{ -if(ls->t.token=='}')break; -closelistfield(fs,&cc); -switch(ls->t.token){ -case TK_NAME:{ -luaX_lookahead(ls); -if(ls->lookahead.token!='=') -listfield(ls,&cc); -else -recfield(ls,&cc); -break; -} -case'[':{ -recfield(ls,&cc); -break; -} -default:{ -listfield(ls,&cc); -break; -} -} -}while(testnext(ls,',')||testnext(ls,';')); -check_match(ls,'}','{',line); -lastlistfield(fs,&cc); -SETARG_B(fs->f->code[pc],luaO_int2fb(cc.na)); -SETARG_C(fs->f->code[pc],luaO_int2fb(cc.nh)); -} -static void parlist(LexState*ls){ -FuncState*fs=ls->fs; -Proto*f=fs->f; -int nparams=0; -f->is_vararg=0; -if(ls->t.token!=')'){ -do{ -switch(ls->t.token){ -case TK_NAME:{ -new_localvar(ls,str_checkname(ls),nparams++); -break; -} -case TK_DOTS:{ -luaX_next(ls); -f->is_vararg|=2; -break; -} -default:luaX_syntaxerror(ls," or "LUA_QL("...")" expected"); -} -}while(!f->is_vararg&&testnext(ls,',')); -} -adjustlocalvars(ls,nparams); -f->numparams=cast_byte(fs->nactvar-(f->is_vararg&1)); -luaK_reserveregs(fs,fs->nactvar); -} -static void body(LexState*ls,expdesc*e,int needself,int line){ -FuncState new_fs; -open_func(ls,&new_fs); -new_fs.f->linedefined=line; -checknext(ls,'('); -if(needself){ -new_localvarliteral(ls,"self",0); -adjustlocalvars(ls,1); -} -parlist(ls); -checknext(ls,')'); -chunk(ls); -new_fs.f->lastlinedefined=ls->linenumber; -check_match(ls,TK_END,TK_FUNCTION,line); -close_func(ls); -pushclosure(ls,&new_fs,e); -} -static int explist1(LexState*ls,expdesc*v){ -int n=1; -expr(ls,v); -while(testnext(ls,',')){ -luaK_exp2nextreg(ls->fs,v); -expr(ls,v); -n++; -} -return n; -} -static void funcargs(LexState*ls,expdesc*f){ -FuncState*fs=ls->fs; -expdesc args; -int base,nparams; -int line=ls->linenumber; -switch(ls->t.token){ -case'(':{ -if(line!=ls->lastline) -luaX_syntaxerror(ls,"ambiguous syntax (function call x new statement)"); -luaX_next(ls); -if(ls->t.token==')') -args.k=VVOID; -else{ -explist1(ls,&args); -luaK_setmultret(fs,&args); -} -check_match(ls,')','(',line); -break; -} -case'{':{ -constructor(ls,&args); -break; -} -case TK_STRING:{ -codestring(ls,&args,ls->t.seminfo.ts); -luaX_next(ls); -break; -} -default:{ -luaX_syntaxerror(ls,"function arguments expected"); -return; -} -} -base=f->u.s.info; -if(hasmultret(args.k)) -nparams=(-1); -else{ -if(args.k!=VVOID) -luaK_exp2nextreg(fs,&args); -nparams=fs->freereg-(base+1); -} -init_exp(f,VCALL,luaK_codeABC(fs,OP_CALL,base,nparams+1,2)); -luaK_fixline(fs,line); -fs->freereg=base+1; -} -static void prefixexp(LexState*ls,expdesc*v){ -switch(ls->t.token){ -case'(':{ -int line=ls->linenumber; -luaX_next(ls); -expr(ls,v); -check_match(ls,')','(',line); -luaK_dischargevars(ls->fs,v); -return; -} -case TK_NAME:{ -singlevar(ls,v); -return; -} -default:{ -luaX_syntaxerror(ls,"unexpected symbol"); -return; -} -} -} -static void primaryexp(LexState*ls,expdesc*v){ -FuncState*fs=ls->fs; -prefixexp(ls,v); -for(;;){ -switch(ls->t.token){ -case'.':{ -field(ls,v); -break; -} -case'[':{ -expdesc key; -luaK_exp2anyreg(fs,v); -yindex(ls,&key); -luaK_indexed(fs,v,&key); -break; -} -case':':{ -expdesc key; -luaX_next(ls); -checkname(ls,&key); -luaK_self(fs,v,&key); -funcargs(ls,v); -break; -} -case'(':case TK_STRING:case'{':{ -luaK_exp2nextreg(fs,v); -funcargs(ls,v); -break; -} -default:return; -} -} -} -static void simpleexp(LexState*ls,expdesc*v){ -switch(ls->t.token){ -case TK_NUMBER:{ -init_exp(v,VKNUM,0); -v->u.nval=ls->t.seminfo.r; -break; -} -case TK_STRING:{ -codestring(ls,v,ls->t.seminfo.ts); -break; -} -case TK_NIL:{ -init_exp(v,VNIL,0); -break; -} -case TK_TRUE:{ -init_exp(v,VTRUE,0); -break; -} -case TK_FALSE:{ -init_exp(v,VFALSE,0); -break; -} -case TK_DOTS:{ -FuncState*fs=ls->fs; -check_condition(ls,fs->f->is_vararg, -"cannot use "LUA_QL("...")" outside a vararg function"); -fs->f->is_vararg&=~4; -init_exp(v,VVARARG,luaK_codeABC(fs,OP_VARARG,0,1,0)); -break; -} -case'{':{ -constructor(ls,v); -return; -} -case TK_FUNCTION:{ -luaX_next(ls); -body(ls,v,0,ls->linenumber); -return; -} -default:{ -primaryexp(ls,v); -return; -} -} -luaX_next(ls); -} -static UnOpr getunopr(int op){ -switch(op){ -case TK_NOT:return OPR_NOT; -case'-':return OPR_MINUS; -case'#':return OPR_LEN; -default:return OPR_NOUNOPR; -} -} -static BinOpr getbinopr(int op){ -switch(op){ -case'+':return OPR_ADD; -case'-':return OPR_SUB; -case'*':return OPR_MUL; -case'/':return OPR_DIV; -case'%':return OPR_MOD; -case'^':return OPR_POW; -case TK_CONCAT:return OPR_CONCAT; -case TK_NE:return OPR_NE; -case TK_EQ:return OPR_EQ; -case'<':return OPR_LT; -case TK_LE:return OPR_LE; -case'>':return OPR_GT; -case TK_GE:return OPR_GE; -case TK_AND:return OPR_AND; -case TK_OR:return OPR_OR; -default:return OPR_NOBINOPR; -} -} -static const struct{ -lu_byte left; -lu_byte right; -}priority[]={ -{6,6},{6,6},{7,7},{7,7},{7,7}, -{10,9},{5,4}, -{3,3},{3,3}, -{3,3},{3,3},{3,3},{3,3}, -{2,2},{1,1} -}; -static BinOpr subexpr(LexState*ls,expdesc*v,unsigned int limit){ -BinOpr op; -UnOpr uop; -enterlevel(ls); -uop=getunopr(ls->t.token); -if(uop!=OPR_NOUNOPR){ -luaX_next(ls); -subexpr(ls,v,8); -luaK_prefix(ls->fs,uop,v); -} -else simpleexp(ls,v); -op=getbinopr(ls->t.token); -while(op!=OPR_NOBINOPR&&priority[op].left>limit){ -expdesc v2; -BinOpr nextop; -luaX_next(ls); -luaK_infix(ls->fs,op,v); -nextop=subexpr(ls,&v2,priority[op].right); -luaK_posfix(ls->fs,op,v,&v2); -op=nextop; -} -leavelevel(ls); -return op; -} -static void expr(LexState*ls,expdesc*v){ -subexpr(ls,v,0); -} -static int block_follow(int token){ -switch(token){ -case TK_ELSE:case TK_ELSEIF:case TK_END: -case TK_UNTIL:case TK_EOS: -return 1; -default:return 0; -} -} -static void block(LexState*ls){ -FuncState*fs=ls->fs; -BlockCnt bl; -enterblock(fs,&bl,0); -chunk(ls); -leaveblock(fs); -} -struct LHS_assign{ -struct LHS_assign*prev; -expdesc v; -}; -static void check_conflict(LexState*ls,struct LHS_assign*lh,expdesc*v){ -FuncState*fs=ls->fs; -int extra=fs->freereg; -int conflict=0; -for(;lh;lh=lh->prev){ -if(lh->v.k==VINDEXED){ -if(lh->v.u.s.info==v->u.s.info){ -conflict=1; -lh->v.u.s.info=extra; -} -if(lh->v.u.s.aux==v->u.s.info){ -conflict=1; -lh->v.u.s.aux=extra; -} -} -} -if(conflict){ -luaK_codeABC(fs,OP_MOVE,fs->freereg,v->u.s.info,0); -luaK_reserveregs(fs,1); -} -} -static void assignment(LexState*ls,struct LHS_assign*lh,int nvars){ -expdesc e; -check_condition(ls,VLOCAL<=lh->v.k&&lh->v.k<=VINDEXED, -"syntax error"); -if(testnext(ls,',')){ -struct LHS_assign nv; -nv.prev=lh; -primaryexp(ls,&nv.v); -if(nv.v.k==VLOCAL) -check_conflict(ls,lh,&nv.v); -luaY_checklimit(ls->fs,nvars,200-ls->L->nCcalls, -"variables in assignment"); -assignment(ls,&nv,nvars+1); -} -else{ -int nexps; -checknext(ls,'='); -nexps=explist1(ls,&e); -if(nexps!=nvars){ -adjust_assign(ls,nvars,nexps,&e); -if(nexps>nvars) -ls->fs->freereg-=nexps-nvars; -} -else{ -luaK_setoneret(ls->fs,&e); -luaK_storevar(ls->fs,&lh->v,&e); -return; -} -} -init_exp(&e,VNONRELOC,ls->fs->freereg-1); -luaK_storevar(ls->fs,&lh->v,&e); -} -static int cond(LexState*ls){ -expdesc v; -expr(ls,&v); -if(v.k==VNIL)v.k=VFALSE; -luaK_goiftrue(ls->fs,&v); -return v.f; -} -static void breakstat(LexState*ls){ -FuncState*fs=ls->fs; -BlockCnt*bl=fs->bl; -int upval=0; -while(bl&&!bl->isbreakable){ -upval|=bl->upval; -bl=bl->previous; -} -if(!bl) -luaX_syntaxerror(ls,"no loop to break"); -if(upval) -luaK_codeABC(fs,OP_CLOSE,bl->nactvar,0,0); -luaK_concat(fs,&bl->breaklist,luaK_jump(fs)); -} -static void whilestat(LexState*ls,int line){ -FuncState*fs=ls->fs; -int whileinit; -int condexit; -BlockCnt bl; -luaX_next(ls); -whileinit=luaK_getlabel(fs); -condexit=cond(ls); -enterblock(fs,&bl,1); -checknext(ls,TK_DO); -block(ls); -luaK_patchlist(fs,luaK_jump(fs),whileinit); -check_match(ls,TK_END,TK_WHILE,line); -leaveblock(fs); -luaK_patchtohere(fs,condexit); -} -static void repeatstat(LexState*ls,int line){ -int condexit; -FuncState*fs=ls->fs; -int repeat_init=luaK_getlabel(fs); -BlockCnt bl1,bl2; -enterblock(fs,&bl1,1); -enterblock(fs,&bl2,0); -luaX_next(ls); -chunk(ls); -check_match(ls,TK_UNTIL,TK_REPEAT,line); -condexit=cond(ls); -if(!bl2.upval){ -leaveblock(fs); -luaK_patchlist(ls->fs,condexit,repeat_init); -} -else{ -breakstat(ls); -luaK_patchtohere(ls->fs,condexit); -leaveblock(fs); -luaK_patchlist(ls->fs,luaK_jump(fs),repeat_init); -} -leaveblock(fs); -} -static int exp1(LexState*ls){ -expdesc e; -int k; -expr(ls,&e); -k=e.k; -luaK_exp2nextreg(ls->fs,&e); -return k; -} -static void forbody(LexState*ls,int base,int line,int nvars,int isnum){ -BlockCnt bl; -FuncState*fs=ls->fs; -int prep,endfor; -adjustlocalvars(ls,3); -checknext(ls,TK_DO); -prep=isnum?luaK_codeAsBx(fs,OP_FORPREP,base,(-1)):luaK_jump(fs); -enterblock(fs,&bl,0); -adjustlocalvars(ls,nvars); -luaK_reserveregs(fs,nvars); -block(ls); -leaveblock(fs); -luaK_patchtohere(fs,prep); -endfor=(isnum)?luaK_codeAsBx(fs,OP_FORLOOP,base,(-1)): -luaK_codeABC(fs,OP_TFORLOOP,base,0,nvars); -luaK_fixline(fs,line); -luaK_patchlist(fs,(isnum?endfor:luaK_jump(fs)),prep+1); -} -static void fornum(LexState*ls,TString*varname,int line){ -FuncState*fs=ls->fs; -int base=fs->freereg; -new_localvarliteral(ls,"(for index)",0); -new_localvarliteral(ls,"(for limit)",1); -new_localvarliteral(ls,"(for step)",2); -new_localvar(ls,varname,3); -checknext(ls,'='); -exp1(ls); -checknext(ls,','); -exp1(ls); -if(testnext(ls,',')) -exp1(ls); -else{ -luaK_codeABx(fs,OP_LOADK,fs->freereg,luaK_numberK(fs,1)); -luaK_reserveregs(fs,1); -} -forbody(ls,base,line,1,1); -} -static void forlist(LexState*ls,TString*indexname){ -FuncState*fs=ls->fs; -expdesc e; -int nvars=0; -int line; -int base=fs->freereg; -new_localvarliteral(ls,"(for generator)",nvars++); -new_localvarliteral(ls,"(for state)",nvars++); -new_localvarliteral(ls,"(for control)",nvars++); -new_localvar(ls,indexname,nvars++); -while(testnext(ls,',')) -new_localvar(ls,str_checkname(ls),nvars++); -checknext(ls,TK_IN); -line=ls->linenumber; -adjust_assign(ls,3,explist1(ls,&e),&e); -luaK_checkstack(fs,3); -forbody(ls,base,line,nvars-3,0); -} -static void forstat(LexState*ls,int line){ -FuncState*fs=ls->fs; -TString*varname; -BlockCnt bl; -enterblock(fs,&bl,1); -luaX_next(ls); -varname=str_checkname(ls); -switch(ls->t.token){ -case'=':fornum(ls,varname,line);break; -case',':case TK_IN:forlist(ls,varname);break; -default:luaX_syntaxerror(ls,LUA_QL("=")" or "LUA_QL("in")" expected"); -} -check_match(ls,TK_END,TK_FOR,line); -leaveblock(fs); -} -static int test_then_block(LexState*ls){ -int condexit; -luaX_next(ls); -condexit=cond(ls); -checknext(ls,TK_THEN); -block(ls); -return condexit; -} -static void ifstat(LexState*ls,int line){ -FuncState*fs=ls->fs; -int flist; -int escapelist=(-1); -flist=test_then_block(ls); -while(ls->t.token==TK_ELSEIF){ -luaK_concat(fs,&escapelist,luaK_jump(fs)); -luaK_patchtohere(fs,flist); -flist=test_then_block(ls); -} -if(ls->t.token==TK_ELSE){ -luaK_concat(fs,&escapelist,luaK_jump(fs)); -luaK_patchtohere(fs,flist); -luaX_next(ls); -block(ls); -} -else -luaK_concat(fs,&escapelist,flist); -luaK_patchtohere(fs,escapelist); -check_match(ls,TK_END,TK_IF,line); -} -static void localfunc(LexState*ls){ -expdesc v,b; -FuncState*fs=ls->fs; -new_localvar(ls,str_checkname(ls),0); -init_exp(&v,VLOCAL,fs->freereg); -luaK_reserveregs(fs,1); -adjustlocalvars(ls,1); -body(ls,&b,0,ls->linenumber); -luaK_storevar(fs,&v,&b); -getlocvar(fs,fs->nactvar-1).startpc=fs->pc; -} -static void localstat(LexState*ls){ -int nvars=0; -int nexps; -expdesc e; -do{ -new_localvar(ls,str_checkname(ls),nvars++); -}while(testnext(ls,',')); -if(testnext(ls,'=')) -nexps=explist1(ls,&e); -else{ -e.k=VVOID; -nexps=0; -} -adjust_assign(ls,nvars,nexps,&e); -adjustlocalvars(ls,nvars); -} -static int funcname(LexState*ls,expdesc*v){ -int needself=0; -singlevar(ls,v); -while(ls->t.token=='.') -field(ls,v); -if(ls->t.token==':'){ -needself=1; -field(ls,v); -} -return needself; -} -static void funcstat(LexState*ls,int line){ -int needself; -expdesc v,b; -luaX_next(ls); -needself=funcname(ls,&v); -body(ls,&b,needself,line); -luaK_storevar(ls->fs,&v,&b); -luaK_fixline(ls->fs,line); -} -static void exprstat(LexState*ls){ -FuncState*fs=ls->fs; -struct LHS_assign v; -primaryexp(ls,&v.v); -if(v.v.k==VCALL) -SETARG_C(getcode(fs,&v.v),1); -else{ -v.prev=NULL; -assignment(ls,&v,1); -} -} -static void retstat(LexState*ls){ -FuncState*fs=ls->fs; -expdesc e; -int first,nret; -luaX_next(ls); -if(block_follow(ls->t.token)||ls->t.token==';') -first=nret=0; -else{ -nret=explist1(ls,&e); -if(hasmultret(e.k)){ -luaK_setmultret(fs,&e); -if(e.k==VCALL&&nret==1){ -SET_OPCODE(getcode(fs,&e),OP_TAILCALL); -} -first=fs->nactvar; -nret=(-1); -} -else{ -if(nret==1) -first=luaK_exp2anyreg(fs,&e); -else{ -luaK_exp2nextreg(fs,&e); -first=fs->nactvar; -} -} -} -luaK_ret(fs,first,nret); -} -static int statement(LexState*ls){ -int line=ls->linenumber; -switch(ls->t.token){ -case TK_IF:{ -ifstat(ls,line); -return 0; -} -case TK_WHILE:{ -whilestat(ls,line); -return 0; -} -case TK_DO:{ -luaX_next(ls); -block(ls); -check_match(ls,TK_END,TK_DO,line); -return 0; -} -case TK_FOR:{ -forstat(ls,line); -return 0; -} -case TK_REPEAT:{ -repeatstat(ls,line); -return 0; -} -case TK_FUNCTION:{ -funcstat(ls,line); -return 0; -} -case TK_LOCAL:{ -luaX_next(ls); -if(testnext(ls,TK_FUNCTION)) -localfunc(ls); -else -localstat(ls); -return 0; -} -case TK_RETURN:{ -retstat(ls); -return 1; -} -case TK_BREAK:{ -luaX_next(ls); -breakstat(ls); -return 1; -} -default:{ -exprstat(ls); -return 0; -} -} -} -static void chunk(LexState*ls){ -int islast=0; -enterlevel(ls); -while(!islast&&!block_follow(ls->t.token)){ -islast=statement(ls); -testnext(ls,';'); -ls->fs->freereg=ls->fs->nactvar; -} -leavelevel(ls); -} -static const TValue*luaV_tonumber(const TValue*obj,TValue*n){ -lua_Number num; -if(ttisnumber(obj))return obj; -if(ttisstring(obj)&&luaO_str2d(svalue(obj),&num)){ -setnvalue(n,num); -return n; -} -else -return NULL; -} -static int luaV_tostring(lua_State*L,StkId obj){ -if(!ttisnumber(obj)) -return 0; -else{ -char s[32]; -lua_Number n=nvalue(obj); -lua_number2str(s,n); -setsvalue(L,obj,luaS_new(L,s)); -return 1; -} -} -static void callTMres(lua_State*L,StkId res,const TValue*f, -const TValue*p1,const TValue*p2){ -ptrdiff_t result=savestack(L,res); -setobj(L,L->top,f); -setobj(L,L->top+1,p1); -setobj(L,L->top+2,p2); -luaD_checkstack(L,3); -L->top+=3; -luaD_call(L,L->top-3,1); -res=restorestack(L,result); -L->top--; -setobj(L,res,L->top); -} -static void callTM(lua_State*L,const TValue*f,const TValue*p1, -const TValue*p2,const TValue*p3){ -setobj(L,L->top,f); -setobj(L,L->top+1,p1); -setobj(L,L->top+2,p2); -setobj(L,L->top+3,p3); -luaD_checkstack(L,4); -L->top+=4; -luaD_call(L,L->top-4,0); -} -static void luaV_gettable(lua_State*L,const TValue*t,TValue*key,StkId val){ -int loop; -for(loop=0;loop<100;loop++){ -const TValue*tm; -if(ttistable(t)){ -Table*h=hvalue(t); -const TValue*res=luaH_get(h,key); -if(!ttisnil(res)|| -(tm=fasttm(L,h->metatable,TM_INDEX))==NULL){ -setobj(L,val,res); -return; -} -} -else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_INDEX))) -luaG_typeerror(L,t,"index"); -if(ttisfunction(tm)){ -callTMres(L,val,tm,t,key); -return; -} -t=tm; -} -luaG_runerror(L,"loop in gettable"); -} -static void luaV_settable(lua_State*L,const TValue*t,TValue*key,StkId val){ -int loop; -TValue temp; -for(loop=0;loop<100;loop++){ -const TValue*tm; -if(ttistable(t)){ -Table*h=hvalue(t); -TValue*oldval=luaH_set(L,h,key); -if(!ttisnil(oldval)|| -(tm=fasttm(L,h->metatable,TM_NEWINDEX))==NULL){ -setobj(L,oldval,val); -h->flags=0; -luaC_barriert(L,h,val); -return; -} -} -else if(ttisnil(tm=luaT_gettmbyobj(L,t,TM_NEWINDEX))) -luaG_typeerror(L,t,"index"); -if(ttisfunction(tm)){ -callTM(L,tm,t,key,val); -return; -} -setobj(L,&temp,tm); -t=&temp; -} -luaG_runerror(L,"loop in settable"); -} -static int call_binTM(lua_State*L,const TValue*p1,const TValue*p2, -StkId res,TMS event){ -const TValue*tm=luaT_gettmbyobj(L,p1,event); -if(ttisnil(tm)) -tm=luaT_gettmbyobj(L,p2,event); -if(ttisnil(tm))return 0; -callTMres(L,res,tm,p1,p2); -return 1; -} -static const TValue*get_compTM(lua_State*L,Table*mt1,Table*mt2, -TMS event){ -const TValue*tm1=fasttm(L,mt1,event); -const TValue*tm2; -if(tm1==NULL)return NULL; -if(mt1==mt2)return tm1; -tm2=fasttm(L,mt2,event); -if(tm2==NULL)return NULL; -if(luaO_rawequalObj(tm1,tm2)) -return tm1; -return NULL; -} -static int call_orderTM(lua_State*L,const TValue*p1,const TValue*p2, -TMS event){ -const TValue*tm1=luaT_gettmbyobj(L,p1,event); -const TValue*tm2; -if(ttisnil(tm1))return-1; -tm2=luaT_gettmbyobj(L,p2,event); -if(!luaO_rawequalObj(tm1,tm2)) -return-1; -callTMres(L,L->top,tm1,p1,p2); -return!l_isfalse(L->top); -} -static int l_strcmp(const TString*ls,const TString*rs){ -const char*l=getstr(ls); -size_t ll=ls->tsv.len; -const char*r=getstr(rs); -size_t lr=rs->tsv.len; -for(;;){ -int temp=strcoll(l,r); -if(temp!=0)return temp; -else{ -size_t len=strlen(l); -if(len==lr) -return(len==ll)?0:1; -else if(len==ll) -return-1; -len++; -l+=len;ll-=len;r+=len;lr-=len; -} -} -} -static int luaV_lessthan(lua_State*L,const TValue*l,const TValue*r){ -int res; -if(ttype(l)!=ttype(r)) -return luaG_ordererror(L,l,r); -else if(ttisnumber(l)) -return luai_numlt(nvalue(l),nvalue(r)); -else if(ttisstring(l)) -return l_strcmp(rawtsvalue(l),rawtsvalue(r))<0; -else if((res=call_orderTM(L,l,r,TM_LT))!=-1) -return res; -return luaG_ordererror(L,l,r); -} -static int lessequal(lua_State*L,const TValue*l,const TValue*r){ -int res; -if(ttype(l)!=ttype(r)) -return luaG_ordererror(L,l,r); -else if(ttisnumber(l)) -return luai_numle(nvalue(l),nvalue(r)); -else if(ttisstring(l)) -return l_strcmp(rawtsvalue(l),rawtsvalue(r))<=0; -else if((res=call_orderTM(L,l,r,TM_LE))!=-1) -return res; -else if((res=call_orderTM(L,r,l,TM_LT))!=-1) -return!res; -return luaG_ordererror(L,l,r); -} -static int luaV_equalval(lua_State*L,const TValue*t1,const TValue*t2){ -const TValue*tm; -switch(ttype(t1)){ -case 0:return 1; -case 3:return luai_numeq(nvalue(t1),nvalue(t2)); -case 1:return bvalue(t1)==bvalue(t2); -case 2:return pvalue(t1)==pvalue(t2); -case 7:{ -if(uvalue(t1)==uvalue(t2))return 1; -tm=get_compTM(L,uvalue(t1)->metatable,uvalue(t2)->metatable, -TM_EQ); -break; -} -case 5:{ -if(hvalue(t1)==hvalue(t2))return 1; -tm=get_compTM(L,hvalue(t1)->metatable,hvalue(t2)->metatable,TM_EQ); -break; -} -default:return gcvalue(t1)==gcvalue(t2); -} -if(tm==NULL)return 0; -callTMres(L,L->top,tm,t1,t2); -return!l_isfalse(L->top); -} -static void luaV_concat(lua_State*L,int total,int last){ -do{ -StkId top=L->base+last+1; -int n=2; -if(!(ttisstring(top-2)||ttisnumber(top-2))||!tostring(L,top-1)){ -if(!call_binTM(L,top-2,top-1,top-2,TM_CONCAT)) -luaG_concaterror(L,top-2,top-1); -}else if(tsvalue(top-1)->len==0) -(void)tostring(L,top-2); -else{ -size_t tl=tsvalue(top-1)->len; -char*buffer; -int i; -for(n=1;nlen; -if(l>=((size_t)(~(size_t)0)-2)-tl)luaG_runerror(L,"string length overflow"); -tl+=l; -} -buffer=luaZ_openspace(L,&G(L)->buff,tl); -tl=0; -for(i=n;i>0;i--){ -size_t l=tsvalue(top-i)->len; -memcpy(buffer+tl,svalue(top-i),l); -tl+=l; -} -setsvalue(L,top-n,luaS_newlstr(L,buffer,tl)); -} -total-=n-1; -last-=n-1; -}while(total>1); -} -static void Arith(lua_State*L,StkId ra,const TValue*rb, -const TValue*rc,TMS op){ -TValue tempb,tempc; -const TValue*b,*c; -if((b=luaV_tonumber(rb,&tempb))!=NULL&& -(c=luaV_tonumber(rc,&tempc))!=NULL){ -lua_Number nb=nvalue(b),nc=nvalue(c); -switch(op){ -case TM_ADD:setnvalue(ra,luai_numadd(nb,nc));break; -case TM_SUB:setnvalue(ra,luai_numsub(nb,nc));break; -case TM_MUL:setnvalue(ra,luai_nummul(nb,nc));break; -case TM_DIV:setnvalue(ra,luai_numdiv(nb,nc));break; -case TM_MOD:setnvalue(ra,luai_nummod(nb,nc));break; -case TM_POW:setnvalue(ra,luai_numpow(nb,nc));break; -case TM_UNM:setnvalue(ra,luai_numunm(nb));break; -default:break; -} -} -else if(!call_binTM(L,rb,rc,ra,op)) -luaG_aritherror(L,rb,rc); -} -#define runtime_check(L,c){if(!(c))break;} -#define RA(i)(base+GETARG_A(i)) -#define RB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgR,base+GETARG_B(i)) -#define RKB(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_B(i))?k+INDEXK(GETARG_B(i)):base+GETARG_B(i)) -#define RKC(i)check_exp(getCMode(GET_OPCODE(i))==OpArgK,ISK(GETARG_C(i))?k+INDEXK(GETARG_C(i)):base+GETARG_C(i)) -#define KBx(i)check_exp(getBMode(GET_OPCODE(i))==OpArgK,k+GETARG_Bx(i)) -#define dojump(L,pc,i){(pc)+=(i);} -#define Protect(x){L->savedpc=pc;{x;};base=L->base;} -#define arith_op(op,tm){TValue*rb=RKB(i);TValue*rc=RKC(i);if(ttisnumber(rb)&&ttisnumber(rc)){lua_Number nb=nvalue(rb),nc=nvalue(rc);setnvalue(ra,op(nb,nc));}else Protect(Arith(L,ra,rb,rc,tm));} -static void luaV_execute(lua_State*L,int nexeccalls){ -LClosure*cl; -StkId base; -TValue*k; -const Instruction*pc; -reentry: -pc=L->savedpc; -cl=&clvalue(L->ci->func)->l; -base=L->base; -k=cl->p->k; -for(;;){ -const Instruction i=*pc++; -StkId ra; -ra=RA(i); -switch(GET_OPCODE(i)){ -case OP_MOVE:{ -setobj(L,ra,RB(i)); -continue; -} -case OP_LOADK:{ -setobj(L,ra,KBx(i)); -continue; -} -case OP_LOADBOOL:{ -setbvalue(ra,GETARG_B(i)); -if(GETARG_C(i))pc++; -continue; -} -case OP_LOADNIL:{ -TValue*rb=RB(i); -do{ -setnilvalue(rb--); -}while(rb>=ra); -continue; -} -case OP_GETUPVAL:{ -int b=GETARG_B(i); -setobj(L,ra,cl->upvals[b]->v); -continue; -} -case OP_GETGLOBAL:{ -TValue g; -TValue*rb=KBx(i); -sethvalue(L,&g,cl->env); -Protect(luaV_gettable(L,&g,rb,ra)); -continue; -} -case OP_GETTABLE:{ -Protect(luaV_gettable(L,RB(i),RKC(i),ra)); -continue; -} -case OP_SETGLOBAL:{ -TValue g; -sethvalue(L,&g,cl->env); -Protect(luaV_settable(L,&g,KBx(i),ra)); -continue; -} -case OP_SETUPVAL:{ -UpVal*uv=cl->upvals[GETARG_B(i)]; -setobj(L,uv->v,ra); -luaC_barrier(L,uv,ra); -continue; -} -case OP_SETTABLE:{ -Protect(luaV_settable(L,ra,RKB(i),RKC(i))); -continue; -} -case OP_NEWTABLE:{ -int b=GETARG_B(i); -int c=GETARG_C(i); -sethvalue(L,ra,luaH_new(L,luaO_fb2int(b),luaO_fb2int(c))); -Protect(luaC_checkGC(L)); -continue; -} -case OP_SELF:{ -StkId rb=RB(i); -setobj(L,ra+1,rb); -Protect(luaV_gettable(L,rb,RKC(i),ra)); -continue; -} -case OP_ADD:{ -arith_op(luai_numadd,TM_ADD); -continue; -} -case OP_SUB:{ -arith_op(luai_numsub,TM_SUB); -continue; -} -case OP_MUL:{ -arith_op(luai_nummul,TM_MUL); -continue; -} -case OP_DIV:{ -arith_op(luai_numdiv,TM_DIV); -continue; -} -case OP_MOD:{ -arith_op(luai_nummod,TM_MOD); -continue; -} -case OP_POW:{ -arith_op(luai_numpow,TM_POW); -continue; -} -case OP_UNM:{ -TValue*rb=RB(i); -if(ttisnumber(rb)){ -lua_Number nb=nvalue(rb); -setnvalue(ra,luai_numunm(nb)); -} -else{ -Protect(Arith(L,ra,rb,rb,TM_UNM)); -} -continue; -} -case OP_NOT:{ -int res=l_isfalse(RB(i)); -setbvalue(ra,res); -continue; -} -case OP_LEN:{ -const TValue*rb=RB(i); -switch(ttype(rb)){ -case 5:{ -setnvalue(ra,cast_num(luaH_getn(hvalue(rb)))); -break; -} -case 4:{ -setnvalue(ra,cast_num(tsvalue(rb)->len)); -break; -} -default:{ -Protect( -if(!call_binTM(L,rb,(&luaO_nilobject_),ra,TM_LEN)) -luaG_typeerror(L,rb,"get length of"); -) -} -} -continue; -} -case OP_CONCAT:{ -int b=GETARG_B(i); -int c=GETARG_C(i); -Protect(luaV_concat(L,c-b+1,c);luaC_checkGC(L)); -setobj(L,RA(i),base+b); -continue; -} -case OP_JMP:{ -dojump(L,pc,GETARG_sBx(i)); -continue; -} -case OP_EQ:{ -TValue*rb=RKB(i); -TValue*rc=RKC(i); -Protect( -if(equalobj(L,rb,rc)==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_LT:{ -Protect( -if(luaV_lessthan(L,RKB(i),RKC(i))==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_LE:{ -Protect( -if(lessequal(L,RKB(i),RKC(i))==GETARG_A(i)) -dojump(L,pc,GETARG_sBx(*pc)); -) -pc++; -continue; -} -case OP_TEST:{ -if(l_isfalse(ra)!=GETARG_C(i)) -dojump(L,pc,GETARG_sBx(*pc)); -pc++; -continue; -} -case OP_TESTSET:{ -TValue*rb=RB(i); -if(l_isfalse(rb)!=GETARG_C(i)){ -setobj(L,ra,rb); -dojump(L,pc,GETARG_sBx(*pc)); -} -pc++; -continue; -} -case OP_CALL:{ -int b=GETARG_B(i); -int nresults=GETARG_C(i)-1; -if(b!=0)L->top=ra+b; -L->savedpc=pc; -switch(luaD_precall(L,ra,nresults)){ -case 0:{ -nexeccalls++; -goto reentry; -} -case 1:{ -if(nresults>=0)L->top=L->ci->top; -base=L->base; -continue; -} -default:{ -return; -} -} -} -case OP_TAILCALL:{ -int b=GETARG_B(i); -if(b!=0)L->top=ra+b; -L->savedpc=pc; -switch(luaD_precall(L,ra,(-1))){ -case 0:{ -CallInfo*ci=L->ci-1; -int aux; -StkId func=ci->func; -StkId pfunc=(ci+1)->func; -if(L->openupval)luaF_close(L,ci->base); -L->base=ci->base=ci->func+((ci+1)->base-pfunc); -for(aux=0;pfunc+auxtop;aux++) -setobj(L,func+aux,pfunc+aux); -ci->top=L->top=func+aux; -ci->savedpc=L->savedpc; -ci->tailcalls++; -L->ci--; -goto reentry; -} -case 1:{ -base=L->base; -continue; -} -default:{ -return; -} -} -} -case OP_RETURN:{ -int b=GETARG_B(i); -if(b!=0)L->top=ra+b-1; -if(L->openupval)luaF_close(L,base); -L->savedpc=pc; -b=luaD_poscall(L,ra); -if(--nexeccalls==0) -return; -else{ -if(b)L->top=L->ci->top; -goto reentry; -} -} -case OP_FORLOOP:{ -lua_Number step=nvalue(ra+2); -lua_Number idx=luai_numadd(nvalue(ra),step); -lua_Number limit=nvalue(ra+1); -if(luai_numlt(0,step)?luai_numle(idx,limit) -:luai_numle(limit,idx)){ -dojump(L,pc,GETARG_sBx(i)); -setnvalue(ra,idx); -setnvalue(ra+3,idx); -} -continue; -} -case OP_FORPREP:{ -const TValue*init=ra; -const TValue*plimit=ra+1; -const TValue*pstep=ra+2; -L->savedpc=pc; -if(!tonumber(init,ra)) -luaG_runerror(L,LUA_QL("for")" initial value must be a number"); -else if(!tonumber(plimit,ra+1)) -luaG_runerror(L,LUA_QL("for")" limit must be a number"); -else if(!tonumber(pstep,ra+2)) -luaG_runerror(L,LUA_QL("for")" step must be a number"); -setnvalue(ra,luai_numsub(nvalue(ra),nvalue(pstep))); -dojump(L,pc,GETARG_sBx(i)); -continue; -} -case OP_TFORLOOP:{ -StkId cb=ra+3; -setobj(L,cb+2,ra+2); -setobj(L,cb+1,ra+1); -setobj(L,cb,ra); -L->top=cb+3; -Protect(luaD_call(L,cb,GETARG_C(i))); -L->top=L->ci->top; -cb=RA(i)+3; -if(!ttisnil(cb)){ -setobj(L,cb-1,cb); -dojump(L,pc,GETARG_sBx(*pc)); -} -pc++; -continue; -} -case OP_SETLIST:{ -int n=GETARG_B(i); -int c=GETARG_C(i); -int last; -Table*h; -if(n==0){ -n=cast_int(L->top-ra)-1; -L->top=L->ci->top; -} -if(c==0)c=cast_int(*pc++); -runtime_check(L,ttistable(ra)); -h=hvalue(ra); -last=((c-1)*50)+n; -if(last>h->sizearray) -luaH_resizearray(L,h,last); -for(;n>0;n--){ -TValue*val=ra+n; -setobj(L,luaH_setnum(L,h,last--),val); -luaC_barriert(L,h,val); -} -continue; -} -case OP_CLOSE:{ -luaF_close(L,ra); -continue; -} -case OP_CLOSURE:{ -Proto*p; -Closure*ncl; -int nup,j; -p=cl->p->p[GETARG_Bx(i)]; -nup=p->nups; -ncl=luaF_newLclosure(L,nup,cl->env); -ncl->l.p=p; -for(j=0;jl.upvals[j]=cl->upvals[GETARG_B(*pc)]; -else{ -ncl->l.upvals[j]=luaF_findupval(L,base+GETARG_B(*pc)); -} -} -setclvalue(L,ra,ncl); -Protect(luaC_checkGC(L)); -continue; -} -case OP_VARARG:{ -int b=GETARG_B(i)-1; -int j; -CallInfo*ci=L->ci; -int n=cast_int(ci->base-ci->func)-cl->p->numparams-1; -if(b==(-1)){ -Protect(luaD_checkstack(L,n)); -ra=RA(i); -b=n; -L->top=ra+n; -} -for(j=0;jbase-n+j); -} -else{ -setnilvalue(ra+j); -} -} -continue; -} -} -} -} -#define api_checknelems(L,n)luai_apicheck(L,(n)<=(L->top-L->base)) -#define api_checkvalidindex(L,i)luai_apicheck(L,(i)!=(&luaO_nilobject_)) -#define api_incr_top(L){luai_apicheck(L,L->topci->top);L->top++;} -static TValue*index2adr(lua_State*L,int idx){ -if(idx>0){ -TValue*o=L->base+(idx-1); -luai_apicheck(L,idx<=L->ci->top-L->base); -if(o>=L->top)return cast(TValue*,(&luaO_nilobject_)); -else return o; -} -else if(idx>(-10000)){ -luai_apicheck(L,idx!=0&&-idx<=L->top-L->base); -return L->top+idx; -} -else switch(idx){ -case(-10000):return registry(L); -case(-10001):{ -Closure*func=curr_func(L); -sethvalue(L,&L->env,func->c.env); -return&L->env; -} -case(-10002):return gt(L); -default:{ -Closure*func=curr_func(L); -idx=(-10002)-idx; -return(idx<=func->c.nupvalues) -?&func->c.upvalue[idx-1] -:cast(TValue*,(&luaO_nilobject_)); -} -} -} -static Table*getcurrenv(lua_State*L){ -if(L->ci==L->base_ci) -return hvalue(gt(L)); -else{ -Closure*func=curr_func(L); -return func->c.env; -} -} -static int lua_checkstack(lua_State*L,int size){ -int res=1; -if(size>8000||(L->top-L->base+size)>8000) -res=0; -else if(size>0){ -luaD_checkstack(L,size); -if(L->ci->toptop+size) -L->ci->top=L->top+size; -} -return res; -} -static lua_CFunction lua_atpanic(lua_State*L,lua_CFunction panicf){ -lua_CFunction old; -old=G(L)->panic; -G(L)->panic=panicf; -return old; -} -static int lua_gettop(lua_State*L){ -return cast_int(L->top-L->base); -} -static void lua_settop(lua_State*L,int idx){ -if(idx>=0){ -luai_apicheck(L,idx<=L->stack_last-L->base); -while(L->topbase+idx) -setnilvalue(L->top++); -L->top=L->base+idx; -} -else{ -luai_apicheck(L,-(idx+1)<=(L->top-L->base)); -L->top+=idx+1; -} -} -static void lua_remove(lua_State*L,int idx){ -StkId p; -p=index2adr(L,idx); -api_checkvalidindex(L,p); -while(++ptop)setobj(L,p-1,p); -L->top--; -} -static void lua_insert(lua_State*L,int idx){ -StkId p; -StkId q; -p=index2adr(L,idx); -api_checkvalidindex(L,p); -for(q=L->top;q>p;q--)setobj(L,q,q-1); -setobj(L,p,L->top); -} -static void lua_replace(lua_State*L,int idx){ -StkId o; -if(idx==(-10001)&&L->ci==L->base_ci) -luaG_runerror(L,"no calling environment"); -api_checknelems(L,1); -o=index2adr(L,idx); -api_checkvalidindex(L,o); -if(idx==(-10001)){ -Closure*func=curr_func(L); -luai_apicheck(L,ttistable(L->top-1)); -func->c.env=hvalue(L->top-1); -luaC_barrier(L,func,L->top-1); -} -else{ -setobj(L,o,L->top-1); -if(idx<(-10002)) -luaC_barrier(L,curr_func(L),L->top-1); -} -L->top--; -} -static void lua_pushvalue(lua_State*L,int idx){ -setobj(L,L->top,index2adr(L,idx)); -api_incr_top(L); -} -static int lua_type(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return(o==(&luaO_nilobject_))?(-1):ttype(o); -} -static const char*lua_typename(lua_State*L,int t){ -UNUSED(L); -return(t==(-1))?"no value":luaT_typenames[t]; -} -static int lua_iscfunction(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return iscfunction(o); -} -static int lua_isnumber(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -return tonumber(o,&n); -} -static int lua_isstring(lua_State*L,int idx){ -int t=lua_type(L,idx); -return(t==4||t==3); -} -static int lua_rawequal(lua_State*L,int index1,int index2){ -StkId o1=index2adr(L,index1); -StkId o2=index2adr(L,index2); -return(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0 -:luaO_rawequalObj(o1,o2); -} -static int lua_lessthan(lua_State*L,int index1,int index2){ -StkId o1,o2; -int i; -o1=index2adr(L,index1); -o2=index2adr(L,index2); -i=(o1==(&luaO_nilobject_)||o2==(&luaO_nilobject_))?0 -:luaV_lessthan(L,o1,o2); -return i; -} -static lua_Number lua_tonumber(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -if(tonumber(o,&n)) -return nvalue(o); -else -return 0; -} -static lua_Integer lua_tointeger(lua_State*L,int idx){ -TValue n; -const TValue*o=index2adr(L,idx); -if(tonumber(o,&n)){ -lua_Integer res; -lua_Number num=nvalue(o); -lua_number2integer(res,num); -return res; -} -else -return 0; -} -static int lua_toboolean(lua_State*L,int idx){ -const TValue*o=index2adr(L,idx); -return!l_isfalse(o); -} -static const char*lua_tolstring(lua_State*L,int idx,size_t*len){ -StkId o=index2adr(L,idx); -if(!ttisstring(o)){ -if(!luaV_tostring(L,o)){ -if(len!=NULL)*len=0; -return NULL; -} -luaC_checkGC(L); -o=index2adr(L,idx); -} -if(len!=NULL)*len=tsvalue(o)->len; -return svalue(o); -} -static size_t lua_objlen(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -switch(ttype(o)){ -case 4:return tsvalue(o)->len; -case 7:return uvalue(o)->len; -case 5:return luaH_getn(hvalue(o)); -case 3:{ -size_t l; -l=(luaV_tostring(L,o)?tsvalue(o)->len:0); -return l; -} -default:return 0; -} -} -static lua_CFunction lua_tocfunction(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -return(!iscfunction(o))?NULL:clvalue(o)->c.f; -} -static void*lua_touserdata(lua_State*L,int idx){ -StkId o=index2adr(L,idx); -switch(ttype(o)){ -case 7:return(rawuvalue(o)+1); -case 2:return pvalue(o); -default:return NULL; -} -} -static void lua_pushnil(lua_State*L){ -setnilvalue(L->top); -api_incr_top(L); -} -static void lua_pushnumber(lua_State*L,lua_Number n){ -setnvalue(L->top,n); -api_incr_top(L); -} -static void lua_pushinteger(lua_State*L,lua_Integer n){ -setnvalue(L->top,cast_num(n)); -api_incr_top(L); -} -static void lua_pushlstring(lua_State*L,const char*s,size_t len){ -luaC_checkGC(L); -setsvalue(L,L->top,luaS_newlstr(L,s,len)); -api_incr_top(L); -} -static void lua_pushstring(lua_State*L,const char*s){ -if(s==NULL) -lua_pushnil(L); -else -lua_pushlstring(L,s,strlen(s)); -} -static const char*lua_pushvfstring(lua_State*L,const char*fmt, -va_list argp){ -const char*ret; -luaC_checkGC(L); -ret=luaO_pushvfstring(L,fmt,argp); -return ret; -} -static const char*lua_pushfstring(lua_State*L,const char*fmt,...){ -const char*ret; -va_list argp; -luaC_checkGC(L); -va_start(argp,fmt); -ret=luaO_pushvfstring(L,fmt,argp); -va_end(argp); -return ret; -} -static void lua_pushcclosure(lua_State*L,lua_CFunction fn,int n){ -Closure*cl; -luaC_checkGC(L); -api_checknelems(L,n); -cl=luaF_newCclosure(L,n,getcurrenv(L)); -cl->c.f=fn; -L->top-=n; -while(n--) -setobj(L,&cl->c.upvalue[n],L->top+n); -setclvalue(L,L->top,cl); -api_incr_top(L); -} -static void lua_pushboolean(lua_State*L,int b){ -setbvalue(L->top,(b!=0)); -api_incr_top(L); -} -static int lua_pushthread(lua_State*L){ -setthvalue(L,L->top,L); -api_incr_top(L); -return(G(L)->mainthread==L); -} -static void lua_gettable(lua_State*L,int idx){ -StkId t; -t=index2adr(L,idx); -api_checkvalidindex(L,t); -luaV_gettable(L,t,L->top-1,L->top-1); -} -static void lua_getfield(lua_State*L,int idx,const char*k){ -StkId t; -TValue key; -t=index2adr(L,idx); -api_checkvalidindex(L,t); -setsvalue(L,&key,luaS_new(L,k)); -luaV_gettable(L,t,&key,L->top); -api_incr_top(L); -} -static void lua_rawget(lua_State*L,int idx){ -StkId t; -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -setobj(L,L->top-1,luaH_get(hvalue(t),L->top-1)); -} -static void lua_rawgeti(lua_State*L,int idx,int n){ -StkId o; -o=index2adr(L,idx); -luai_apicheck(L,ttistable(o)); -setobj(L,L->top,luaH_getnum(hvalue(o),n)); -api_incr_top(L); -} -static void lua_createtable(lua_State*L,int narray,int nrec){ -luaC_checkGC(L); -sethvalue(L,L->top,luaH_new(L,narray,nrec)); -api_incr_top(L); -} -static int lua_getmetatable(lua_State*L,int objindex){ -const TValue*obj; -Table*mt=NULL; -int res; -obj=index2adr(L,objindex); -switch(ttype(obj)){ -case 5: -mt=hvalue(obj)->metatable; -break; -case 7: -mt=uvalue(obj)->metatable; -break; -default: -mt=G(L)->mt[ttype(obj)]; -break; -} -if(mt==NULL) -res=0; -else{ -sethvalue(L,L->top,mt); -api_incr_top(L); -res=1; -} -return res; -} -static void lua_getfenv(lua_State*L,int idx){ -StkId o; -o=index2adr(L,idx); -api_checkvalidindex(L,o); -switch(ttype(o)){ -case 6: -sethvalue(L,L->top,clvalue(o)->c.env); -break; -case 7: -sethvalue(L,L->top,uvalue(o)->env); -break; -case 8: -setobj(L,L->top,gt(thvalue(o))); -break; -default: -setnilvalue(L->top); -break; -} -api_incr_top(L); -} -static void lua_settable(lua_State*L,int idx){ -StkId t; -api_checknelems(L,2); -t=index2adr(L,idx); -api_checkvalidindex(L,t); -luaV_settable(L,t,L->top-2,L->top-1); -L->top-=2; -} -static void lua_setfield(lua_State*L,int idx,const char*k){ -StkId t; -TValue key; -api_checknelems(L,1); -t=index2adr(L,idx); -api_checkvalidindex(L,t); -setsvalue(L,&key,luaS_new(L,k)); -luaV_settable(L,t,&key,L->top-1); -L->top--; -} -static void lua_rawset(lua_State*L,int idx){ -StkId t; -api_checknelems(L,2); -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -setobj(L,luaH_set(L,hvalue(t),L->top-2),L->top-1); -luaC_barriert(L,hvalue(t),L->top-1); -L->top-=2; -} -static void lua_rawseti(lua_State*L,int idx,int n){ -StkId o; -api_checknelems(L,1); -o=index2adr(L,idx); -luai_apicheck(L,ttistable(o)); -setobj(L,luaH_setnum(L,hvalue(o),n),L->top-1); -luaC_barriert(L,hvalue(o),L->top-1); -L->top--; -} -static int lua_setmetatable(lua_State*L,int objindex){ -TValue*obj; -Table*mt; -api_checknelems(L,1); -obj=index2adr(L,objindex); -api_checkvalidindex(L,obj); -if(ttisnil(L->top-1)) -mt=NULL; -else{ -luai_apicheck(L,ttistable(L->top-1)); -mt=hvalue(L->top-1); -} -switch(ttype(obj)){ -case 5:{ -hvalue(obj)->metatable=mt; -if(mt) -luaC_objbarriert(L,hvalue(obj),mt); -break; -} -case 7:{ -uvalue(obj)->metatable=mt; -if(mt) -luaC_objbarrier(L,rawuvalue(obj),mt); -break; -} -default:{ -G(L)->mt[ttype(obj)]=mt; -break; -} -} -L->top--; -return 1; -} -static int lua_setfenv(lua_State*L,int idx){ -StkId o; -int res=1; -api_checknelems(L,1); -o=index2adr(L,idx); -api_checkvalidindex(L,o); -luai_apicheck(L,ttistable(L->top-1)); -switch(ttype(o)){ -case 6: -clvalue(o)->c.env=hvalue(L->top-1); -break; -case 7: -uvalue(o)->env=hvalue(L->top-1); -break; -case 8: -sethvalue(L,gt(thvalue(o)),hvalue(L->top-1)); -break; -default: -res=0; -break; -} -if(res)luaC_objbarrier(L,gcvalue(o),hvalue(L->top-1)); -L->top--; -return res; -} -#define adjustresults(L,nres){if(nres==(-1)&&L->top>=L->ci->top)L->ci->top=L->top;} -#define checkresults(L,na,nr)luai_apicheck(L,(nr)==(-1)||(L->ci->top-L->top>=(nr)-(na))) -static void lua_call(lua_State*L,int nargs,int nresults){ -StkId func; -api_checknelems(L,nargs+1); -checkresults(L,nargs,nresults); -func=L->top-(nargs+1); -luaD_call(L,func,nresults); -adjustresults(L,nresults); -} -struct CallS{ -StkId func; -int nresults; -}; -static void f_call(lua_State*L,void*ud){ -struct CallS*c=cast(struct CallS*,ud); -luaD_call(L,c->func,c->nresults); -} -static int lua_pcall(lua_State*L,int nargs,int nresults,int errfunc){ -struct CallS c; -int status; -ptrdiff_t func; -api_checknelems(L,nargs+1); -checkresults(L,nargs,nresults); -if(errfunc==0) -func=0; -else{ -StkId o=index2adr(L,errfunc); -api_checkvalidindex(L,o); -func=savestack(L,o); -} -c.func=L->top-(nargs+1); -c.nresults=nresults; -status=luaD_pcall(L,f_call,&c,savestack(L,c.func),func); -adjustresults(L,nresults); -return status; -} -static int lua_load(lua_State*L,lua_Reader reader,void*data, -const char*chunkname){ -ZIO z; -int status; -if(!chunkname)chunkname="?"; -luaZ_init(L,&z,reader,data); -status=luaD_protectedparser(L,&z,chunkname); -return status; -} -static int lua_error(lua_State*L){ -api_checknelems(L,1); -luaG_errormsg(L); -return 0; -} -static int lua_next(lua_State*L,int idx){ -StkId t; -int more; -t=index2adr(L,idx); -luai_apicheck(L,ttistable(t)); -more=luaH_next(L,hvalue(t),L->top-1); -if(more){ -api_incr_top(L); -} -else -L->top-=1; -return more; -} -static void lua_concat(lua_State*L,int n){ -api_checknelems(L,n); -if(n>=2){ -luaC_checkGC(L); -luaV_concat(L,n,cast_int(L->top-L->base)-1); -L->top-=(n-1); -} -else if(n==0){ -setsvalue(L,L->top,luaS_newlstr(L,"",0)); -api_incr_top(L); -} -} -static void*lua_newuserdata(lua_State*L,size_t size){ -Udata*u; -luaC_checkGC(L); -u=luaS_newudata(L,size,getcurrenv(L)); -setuvalue(L,L->top,u); -api_incr_top(L); -return u+1; -} -#define luaL_getn(L,i)((int)lua_objlen(L,i)) -#define luaL_setn(L,i,j)((void)0) -typedef struct luaL_Reg{ -const char*name; -lua_CFunction func; -}luaL_Reg; -static void luaI_openlib(lua_State*L,const char*libname, -const luaL_Reg*l,int nup); -static int luaL_argerror(lua_State*L,int numarg,const char*extramsg); -static const char* luaL_checklstring(lua_State*L,int numArg, -size_t*l); -static const char* luaL_optlstring(lua_State*L,int numArg, -const char*def,size_t*l); -static lua_Integer luaL_checkinteger(lua_State*L,int numArg); -static lua_Integer luaL_optinteger(lua_State*L,int nArg, -lua_Integer def); -static int luaL_error(lua_State*L,const char*fmt,...); -static const char* luaL_findtable(lua_State*L,int idx, -const char*fname,int szhint); -#define luaL_argcheck(L,cond,numarg,extramsg)((void)((cond)||luaL_argerror(L,(numarg),(extramsg)))) -#define luaL_checkstring(L,n)(luaL_checklstring(L,(n),NULL)) -#define luaL_optstring(L,n,d)(luaL_optlstring(L,(n),(d),NULL)) -#define luaL_checkint(L,n)((int)luaL_checkinteger(L,(n))) -#define luaL_optint(L,n,d)((int)luaL_optinteger(L,(n),(d))) -#define luaL_typename(L,i)lua_typename(L,lua_type(L,(i))) -#define luaL_getmetatable(L,n)(lua_getfield(L,(-10000),(n))) -#define luaL_opt(L,f,n,d)(lua_isnoneornil(L,(n))?(d):f(L,(n))) -typedef struct luaL_Buffer{ -char*p; -int lvl; -lua_State*L; -char buffer[BUFSIZ]; -}luaL_Buffer; -#define luaL_addchar(B,c)((void)((B)->p<((B)->buffer+BUFSIZ)||luaL_prepbuffer(B)),(*(B)->p++=(char)(c))) -#define luaL_addsize(B,n)((B)->p+=(n)) -static char* luaL_prepbuffer(luaL_Buffer*B); -static int luaL_argerror(lua_State*L,int narg,const char*extramsg){ -lua_Debug ar; -if(!lua_getstack(L,0,&ar)) -return luaL_error(L,"bad argument #%d (%s)",narg,extramsg); -lua_getinfo(L,"n",&ar); -if(strcmp(ar.namewhat,"method")==0){ -narg--; -if(narg==0) -return luaL_error(L,"calling "LUA_QL("%s")" on bad self (%s)", -ar.name,extramsg); -} -if(ar.name==NULL) -ar.name="?"; -return luaL_error(L,"bad argument #%d to "LUA_QL("%s")" (%s)", -narg,ar.name,extramsg); -} -static int luaL_typerror(lua_State*L,int narg,const char*tname){ -const char*msg=lua_pushfstring(L,"%s expected, got %s", -tname,luaL_typename(L,narg)); -return luaL_argerror(L,narg,msg); -} -static void tag_error(lua_State*L,int narg,int tag){ -luaL_typerror(L,narg,lua_typename(L,tag)); -} -static void luaL_where(lua_State*L,int level){ -lua_Debug ar; -if(lua_getstack(L,level,&ar)){ -lua_getinfo(L,"Sl",&ar); -if(ar.currentline>0){ -lua_pushfstring(L,"%s:%d: ",ar.short_src,ar.currentline); -return; -} -} -lua_pushliteral(L,""); -} -static int luaL_error(lua_State*L,const char*fmt,...){ -va_list argp; -va_start(argp,fmt); -luaL_where(L,1); -lua_pushvfstring(L,fmt,argp); -va_end(argp); -lua_concat(L,2); -return lua_error(L); -} -static int luaL_newmetatable(lua_State*L,const char*tname){ -lua_getfield(L,(-10000),tname); -if(!lua_isnil(L,-1)) -return 0; -lua_pop(L,1); -lua_newtable(L); -lua_pushvalue(L,-1); -lua_setfield(L,(-10000),tname); -return 1; -} -static void*luaL_checkudata(lua_State*L,int ud,const char*tname){ -void*p=lua_touserdata(L,ud); -if(p!=NULL){ -if(lua_getmetatable(L,ud)){ -lua_getfield(L,(-10000),tname); -if(lua_rawequal(L,-1,-2)){ -lua_pop(L,2); -return p; -} -} -} -luaL_typerror(L,ud,tname); -return NULL; -} -static void luaL_checkstack(lua_State*L,int space,const char*mes){ -if(!lua_checkstack(L,space)) -luaL_error(L,"stack overflow (%s)",mes); -} -static void luaL_checktype(lua_State*L,int narg,int t){ -if(lua_type(L,narg)!=t) -tag_error(L,narg,t); -} -static void luaL_checkany(lua_State*L,int narg){ -if(lua_type(L,narg)==(-1)) -luaL_argerror(L,narg,"value expected"); -} -static const char*luaL_checklstring(lua_State*L,int narg,size_t*len){ -const char*s=lua_tolstring(L,narg,len); -if(!s)tag_error(L,narg,4); -return s; -} -static const char*luaL_optlstring(lua_State*L,int narg, -const char*def,size_t*len){ -if(lua_isnoneornil(L,narg)){ -if(len) -*len=(def?strlen(def):0); -return def; -} -else return luaL_checklstring(L,narg,len); -} -static lua_Number luaL_checknumber(lua_State*L,int narg){ -lua_Number d=lua_tonumber(L,narg); -if(d==0&&!lua_isnumber(L,narg)) -tag_error(L,narg,3); -return d; -} -static lua_Integer luaL_checkinteger(lua_State*L,int narg){ -lua_Integer d=lua_tointeger(L,narg); -if(d==0&&!lua_isnumber(L,narg)) -tag_error(L,narg,3); -return d; -} -static lua_Integer luaL_optinteger(lua_State*L,int narg, -lua_Integer def){ -return luaL_opt(L,luaL_checkinteger,narg,def); -} -static int luaL_getmetafield(lua_State*L,int obj,const char*event){ -if(!lua_getmetatable(L,obj)) -return 0; -lua_pushstring(L,event); -lua_rawget(L,-2); -if(lua_isnil(L,-1)){ -lua_pop(L,2); -return 0; -} -else{ -lua_remove(L,-2); -return 1; -} -} -static void luaL_register(lua_State*L,const char*libname, -const luaL_Reg*l){ -luaI_openlib(L,libname,l,0); -} -static int libsize(const luaL_Reg*l){ -int size=0; -for(;l->name;l++)size++; -return size; -} -static void luaI_openlib(lua_State*L,const char*libname, -const luaL_Reg*l,int nup){ -if(libname){ -int size=libsize(l); -luaL_findtable(L,(-10000),"_LOADED",1); -lua_getfield(L,-1,libname); -if(!lua_istable(L,-1)){ -lua_pop(L,1); -if(luaL_findtable(L,(-10002),libname,size)!=NULL) -luaL_error(L,"name conflict for module "LUA_QL("%s"),libname); -lua_pushvalue(L,-1); -lua_setfield(L,-3,libname); -} -lua_remove(L,-2); -lua_insert(L,-(nup+1)); -} -for(;l->name;l++){ -int i; -for(i=0;ifunc,nup); -lua_setfield(L,-(nup+2),l->name); -} -lua_pop(L,nup); -} -static const char*luaL_findtable(lua_State*L,int idx, -const char*fname,int szhint){ -const char*e; -lua_pushvalue(L,idx); -do{ -e=strchr(fname,'.'); -if(e==NULL)e=fname+strlen(fname); -lua_pushlstring(L,fname,e-fname); -lua_rawget(L,-2); -if(lua_isnil(L,-1)){ -lua_pop(L,1); -lua_createtable(L,0,(*e=='.'?1:szhint)); -lua_pushlstring(L,fname,e-fname); -lua_pushvalue(L,-2); -lua_settable(L,-4); -} -else if(!lua_istable(L,-1)){ -lua_pop(L,2); -return fname; -} -lua_remove(L,-2); -fname=e+1; -}while(*e=='.'); -return NULL; -} -#define bufflen(B)((B)->p-(B)->buffer) -#define bufffree(B)((size_t)(BUFSIZ-bufflen(B))) -static int emptybuffer(luaL_Buffer*B){ -size_t l=bufflen(B); -if(l==0)return 0; -else{ -lua_pushlstring(B->L,B->buffer,l); -B->p=B->buffer; -B->lvl++; -return 1; -} -} -static void adjuststack(luaL_Buffer*B){ -if(B->lvl>1){ -lua_State*L=B->L; -int toget=1; -size_t toplen=lua_strlen(L,-1); -do{ -size_t l=lua_strlen(L,-(toget+1)); -if(B->lvl-toget+1>=(20/2)||toplen>l){ -toplen+=l; -toget++; -} -else break; -}while(togetlvl); -lua_concat(L,toget); -B->lvl=B->lvl-toget+1; -} -} -static char*luaL_prepbuffer(luaL_Buffer*B){ -if(emptybuffer(B)) -adjuststack(B); -return B->buffer; -} -static void luaL_addlstring(luaL_Buffer*B,const char*s,size_t l){ -while(l--) -luaL_addchar(B,*s++); -} -static void luaL_pushresult(luaL_Buffer*B){ -emptybuffer(B); -lua_concat(B->L,B->lvl); -B->lvl=1; -} -static void luaL_addvalue(luaL_Buffer*B){ -lua_State*L=B->L; -size_t vl; -const char*s=lua_tolstring(L,-1,&vl); -if(vl<=bufffree(B)){ -memcpy(B->p,s,vl); -B->p+=vl; -lua_pop(L,1); -} -else{ -if(emptybuffer(B)) -lua_insert(L,-2); -B->lvl++; -adjuststack(B); -} -} -static void luaL_buffinit(lua_State*L,luaL_Buffer*B){ -B->L=L; -B->p=B->buffer; -B->lvl=0; -} -typedef struct LoadF{ -int extraline; -FILE*f; -char buff[BUFSIZ]; -}LoadF; -static const char*getF(lua_State*L,void*ud,size_t*size){ -LoadF*lf=(LoadF*)ud; -(void)L; -if(lf->extraline){ -lf->extraline=0; -*size=1; -return"\n"; -} -if(feof(lf->f))return NULL; -*size=fread(lf->buff,1,sizeof(lf->buff),lf->f); -return(*size>0)?lf->buff:NULL; -} -static int errfile(lua_State*L,const char*what,int fnameindex){ -const char*serr=strerror(errno); -const char*filename=lua_tostring(L,fnameindex)+1; -lua_pushfstring(L,"cannot %s %s: %s",what,filename,serr); -lua_remove(L,fnameindex); -return(5+1); -} -static int luaL_loadfile(lua_State*L,const char*filename){ -LoadF lf; -int status,readstatus; -int c; -int fnameindex=lua_gettop(L)+1; -lf.extraline=0; -if(filename==NULL){ -lua_pushliteral(L,"=stdin"); -lf.f=stdin; -} -else{ -lua_pushfstring(L,"@%s",filename); -lf.f=fopen(filename,"r"); -if(lf.f==NULL)return errfile(L,"open",fnameindex); -} -c=getc(lf.f); -if(c=='#'){ -lf.extraline=1; -while((c=getc(lf.f))!=EOF&&c!='\n'); -if(c=='\n')c=getc(lf.f); -} -if(c=="\033Lua"[0]&&filename){ -lf.f=freopen(filename,"rb",lf.f); -if(lf.f==NULL)return errfile(L,"reopen",fnameindex); -while((c=getc(lf.f))!=EOF&&c!="\033Lua"[0]); -lf.extraline=0; -} -ungetc(c,lf.f); -status=lua_load(L,getF,&lf,lua_tostring(L,-1)); -readstatus=ferror(lf.f); -if(filename)fclose(lf.f); -if(readstatus){ -lua_settop(L,fnameindex); -return errfile(L,"read",fnameindex); -} -lua_remove(L,fnameindex); -return status; -} -typedef struct LoadS{ -const char*s; -size_t size; -}LoadS; -static const char*getS(lua_State*L,void*ud,size_t*size){ -LoadS*ls=(LoadS*)ud; -(void)L; -if(ls->size==0)return NULL; -*size=ls->size; -ls->size=0; -return ls->s; -} -static int luaL_loadbuffer(lua_State*L,const char*buff,size_t size, -const char*name){ -LoadS ls; -ls.s=buff; -ls.size=size; -return lua_load(L,getS,&ls,name); -} -static void*l_alloc(void*ud,void*ptr,size_t osize,size_t nsize){ -(void)ud; -(void)osize; -if(nsize==0){ -free(ptr); -return NULL; -} -else -return realloc(ptr,nsize); -} -static int panic(lua_State*L){ -(void)L; -fprintf(stderr,"PANIC: unprotected error in call to Lua API (%s)\n", -lua_tostring(L,-1)); -return 0; -} -static lua_State*luaL_newstate(void){ -lua_State*L=lua_newstate(l_alloc,NULL); -if(L)lua_atpanic(L,&panic); -return L; -} -static int luaB_tonumber(lua_State*L){ -int base=luaL_optint(L,2,10); -if(base==10){ -luaL_checkany(L,1); -if(lua_isnumber(L,1)){ -lua_pushnumber(L,lua_tonumber(L,1)); -return 1; -} -} -else{ -const char*s1=luaL_checkstring(L,1); -char*s2; -unsigned long n; -luaL_argcheck(L,2<=base&&base<=36,2,"base out of range"); -n=strtoul(s1,&s2,base); -if(s1!=s2){ -while(isspace((unsigned char)(*s2)))s2++; -if(*s2=='\0'){ -lua_pushnumber(L,(lua_Number)n); -return 1; -} -} -} -lua_pushnil(L); -return 1; -} -static int luaB_error(lua_State*L){ -int level=luaL_optint(L,2,1); -lua_settop(L,1); -if(lua_isstring(L,1)&&level>0){ -luaL_where(L,level); -lua_pushvalue(L,1); -lua_concat(L,2); -} -return lua_error(L); -} -static int luaB_setmetatable(lua_State*L){ -int t=lua_type(L,2); -luaL_checktype(L,1,5); -luaL_argcheck(L,t==0||t==5,2, -"nil or table expected"); -if(luaL_getmetafield(L,1,"__metatable")) -luaL_error(L,"cannot change a protected metatable"); -lua_settop(L,2); -lua_setmetatable(L,1); -return 1; -} -static void getfunc(lua_State*L,int opt){ -if(lua_isfunction(L,1))lua_pushvalue(L,1); -else{ -lua_Debug ar; -int level=opt?luaL_optint(L,1,1):luaL_checkint(L,1); -luaL_argcheck(L,level>=0,1,"level must be non-negative"); -if(lua_getstack(L,level,&ar)==0) -luaL_argerror(L,1,"invalid level"); -lua_getinfo(L,"f",&ar); -if(lua_isnil(L,-1)) -luaL_error(L,"no function environment for tail call at level %d", -level); -} -} -static int luaB_setfenv(lua_State*L){ -luaL_checktype(L,2,5); -getfunc(L,0); -lua_pushvalue(L,2); -if(lua_isnumber(L,1)&&lua_tonumber(L,1)==0){ -lua_pushthread(L); -lua_insert(L,-2); -lua_setfenv(L,-2); -return 0; -} -else if(lua_iscfunction(L,-2)||lua_setfenv(L,-2)==0) -luaL_error(L, -LUA_QL("setfenv")" cannot change environment of given object"); -return 1; -} -static int luaB_rawget(lua_State*L){ -luaL_checktype(L,1,5); -luaL_checkany(L,2); -lua_settop(L,2); -lua_rawget(L,1); -return 1; -} -static int luaB_type(lua_State*L){ -luaL_checkany(L,1); -lua_pushstring(L,luaL_typename(L,1)); -return 1; -} -static int luaB_next(lua_State*L){ -luaL_checktype(L,1,5); -lua_settop(L,2); -if(lua_next(L,1)) -return 2; -else{ -lua_pushnil(L); -return 1; -} -} -static int luaB_pairs(lua_State*L){ -luaL_checktype(L,1,5); -lua_pushvalue(L,lua_upvalueindex(1)); -lua_pushvalue(L,1); -lua_pushnil(L); -return 3; -} -static int ipairsaux(lua_State*L){ -int i=luaL_checkint(L,2); -luaL_checktype(L,1,5); -i++; -lua_pushinteger(L,i); -lua_rawgeti(L,1,i); -return(lua_isnil(L,-1))?0:2; -} -static int luaB_ipairs(lua_State*L){ -luaL_checktype(L,1,5); -lua_pushvalue(L,lua_upvalueindex(1)); -lua_pushvalue(L,1); -lua_pushinteger(L,0); -return 3; -} -static int load_aux(lua_State*L,int status){ -if(status==0) -return 1; -else{ -lua_pushnil(L); -lua_insert(L,-2); -return 2; -} -} -static int luaB_loadstring(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -const char*chunkname=luaL_optstring(L,2,s); -return load_aux(L,luaL_loadbuffer(L,s,l,chunkname)); -} -static int luaB_loadfile(lua_State*L){ -const char*fname=luaL_optstring(L,1,NULL); -return load_aux(L,luaL_loadfile(L,fname)); -} -static int luaB_assert(lua_State*L){ -luaL_checkany(L,1); -if(!lua_toboolean(L,1)) -return luaL_error(L,"%s",luaL_optstring(L,2,"assertion failed!")); -return lua_gettop(L); -} -static int luaB_unpack(lua_State*L){ -int i,e,n; -luaL_checktype(L,1,5); -i=luaL_optint(L,2,1); -e=luaL_opt(L,luaL_checkint,3,luaL_getn(L,1)); -if(i>e)return 0; -n=e-i+1; -if(n<=0||!lua_checkstack(L,n)) -return luaL_error(L,"too many results to unpack"); -lua_rawgeti(L,1,i); -while(i++e)e=pos; -for(i=e;i>pos;i--){ -lua_rawgeti(L,1,i-1); -lua_rawseti(L,1,i); -} -break; -} -default:{ -return luaL_error(L,"wrong number of arguments to "LUA_QL("insert")); -} -} -luaL_setn(L,1,e); -lua_rawseti(L,1,pos); -return 0; -} -static int tremove(lua_State*L){ -int e=aux_getn(L,1); -int pos=luaL_optint(L,2,e); -if(!(1<=pos&&pos<=e)) -return 0; -luaL_setn(L,1,e-1); -lua_rawgeti(L,1,pos); -for(;posu)luaL_error(L,"invalid order function for sorting"); -lua_pop(L,1); -} -while(lua_rawgeti(L,1,--j),sort_comp(L,-3,-1)){ -if(j0); -} -l=strlen(p); -if(l==0||p[l-1]!='\n') -luaL_addsize(&b,l); -else{ -luaL_addsize(&b,l-1); -luaL_pushresult(&b); -return 1; -} -} -} -static int read_chars(lua_State*L,FILE*f,size_t n){ -size_t rlen; -size_t nr; -luaL_Buffer b; -luaL_buffinit(L,&b); -rlen=BUFSIZ; -do{ -char*p=luaL_prepbuffer(&b); -if(rlen>n)rlen=n; -nr=fread(p,sizeof(char),rlen,f); -luaL_addsize(&b,nr); -n-=nr; -}while(n>0&&nr==rlen); -luaL_pushresult(&b); -return(n==0||lua_objlen(L,-1)>0); -} -static int g_read(lua_State*L,FILE*f,int first){ -int nargs=lua_gettop(L)-1; -int success; -int n; -clearerr(f); -if(nargs==0){ -success=read_line(L,f); -n=first+1; -} -else{ -luaL_checkstack(L,nargs+20,"too many arguments"); -success=1; -for(n=first;nargs--&&success;n++){ -if(lua_type(L,n)==3){ -size_t l=(size_t)lua_tointeger(L,n); -success=(l==0)?test_eof(L,f):read_chars(L,f,l); -} -else{ -const char*p=lua_tostring(L,n); -luaL_argcheck(L,p&&p[0]=='*',n,"invalid option"); -switch(p[1]){ -case'n': -success=read_number(L,f); -break; -case'l': -success=read_line(L,f); -break; -case'a': -read_chars(L,f,~((size_t)0)); -success=1; -break; -default: -return luaL_argerror(L,n,"invalid format"); -} -} -} -} -if(ferror(f)) -return pushresult(L,0,NULL); -if(!success){ -lua_pop(L,1); -lua_pushnil(L); -} -return n-first; -} -static int io_read(lua_State*L){ -return g_read(L,getiofile(L,1),1); -} -static int f_read(lua_State*L){ -return g_read(L,tofile(L),2); -} -static int io_readline(lua_State*L){ -FILE*f=*(FILE**)lua_touserdata(L,lua_upvalueindex(1)); -int success; -if(f==NULL) -luaL_error(L,"file is already closed"); -success=read_line(L,f); -if(ferror(f)) -return luaL_error(L,"%s",strerror(errno)); -if(success)return 1; -else{ -if(lua_toboolean(L,lua_upvalueindex(2))){ -lua_settop(L,0); -lua_pushvalue(L,lua_upvalueindex(1)); -aux_close(L); -} -return 0; -} -} -static int g_write(lua_State*L,FILE*f,int arg){ -int nargs=lua_gettop(L)-1; -int status=1; -for(;nargs--;arg++){ -if(lua_type(L,arg)==3){ -status=status&& -fprintf(f,"%.14g",lua_tonumber(L,arg))>0; -} -else{ -size_t l; -const char*s=luaL_checklstring(L,arg,&l); -status=status&&(fwrite(s,sizeof(char),l,f)==l); -} -} -return pushresult(L,status,NULL); -} -static int io_write(lua_State*L){ -return g_write(L,getiofile(L,2),1); -} -static int f_write(lua_State*L){ -return g_write(L,tofile(L),2); -} -static int io_flush(lua_State*L){ -return pushresult(L,fflush(getiofile(L,2))==0,NULL); -} -static int f_flush(lua_State*L){ -return pushresult(L,fflush(tofile(L))==0,NULL); -} -static const luaL_Reg iolib[]={ -{"close",io_close}, -{"flush",io_flush}, -{"input",io_input}, -{"lines",io_lines}, -{"open",io_open}, -{"output",io_output}, -{"read",io_read}, -{"type",io_type}, -{"write",io_write}, -{NULL,NULL} -}; -static const luaL_Reg flib[]={ -{"close",io_close}, -{"flush",f_flush}, -{"lines",f_lines}, -{"read",f_read}, -{"write",f_write}, -{"__gc",io_gc}, -{NULL,NULL} -}; -static void createmeta(lua_State*L){ -luaL_newmetatable(L,"FILE*"); -lua_pushvalue(L,-1); -lua_setfield(L,-2,"__index"); -luaL_register(L,NULL,flib); -} -static void createstdfile(lua_State*L,FILE*f,int k,const char*fname){ -*newfile(L)=f; -if(k>0){ -lua_pushvalue(L,-1); -lua_rawseti(L,(-10001),k); -} -lua_pushvalue(L,-2); -lua_setfenv(L,-2); -lua_setfield(L,-3,fname); -} -static void newfenv(lua_State*L,lua_CFunction cls){ -lua_createtable(L,0,1); -lua_pushcfunction(L,cls); -lua_setfield(L,-2,"__close"); -} -static int luaopen_io(lua_State*L){ -createmeta(L); -newfenv(L,io_fclose); -lua_replace(L,(-10001)); -luaL_register(L,"io",iolib); -newfenv(L,io_noclose); -createstdfile(L,stdin,1,"stdin"); -createstdfile(L,stdout,2,"stdout"); -createstdfile(L,stderr,0,"stderr"); -lua_pop(L,1); -lua_getfield(L,-1,"popen"); -newfenv(L,io_pclose); -lua_setfenv(L,-2); -lua_pop(L,1); -return 1; -} -static int os_pushresult(lua_State*L,int i,const char*filename){ -int en=errno; -if(i){ -lua_pushboolean(L,1); -return 1; -} -else{ -lua_pushnil(L); -lua_pushfstring(L,"%s: %s",filename,strerror(en)); -lua_pushinteger(L,en); -return 3; -} -} -static int os_remove(lua_State*L){ -const char*filename=luaL_checkstring(L,1); -return os_pushresult(L,remove(filename)==0,filename); -} -static int os_exit(lua_State*L){ -exit(luaL_optint(L,1,EXIT_SUCCESS)); -} -static const luaL_Reg syslib[]={ -{"exit",os_exit}, -{"remove",os_remove}, -{NULL,NULL} -}; -static int luaopen_os(lua_State*L){ -luaL_register(L,"os",syslib); -return 1; -} -#define uchar(c)((unsigned char)(c)) -static ptrdiff_t posrelat(ptrdiff_t pos,size_t len){ -if(pos<0)pos+=(ptrdiff_t)len+1; -return(pos>=0)?pos:0; -} -static int str_sub(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -ptrdiff_t start=posrelat(luaL_checkinteger(L,2),l); -ptrdiff_t end=posrelat(luaL_optinteger(L,3,-1),l); -if(start<1)start=1; -if(end>(ptrdiff_t)l)end=(ptrdiff_t)l; -if(start<=end) -lua_pushlstring(L,s+start-1,end-start+1); -else lua_pushliteral(L,""); -return 1; -} -static int str_lower(lua_State*L){ -size_t l; -size_t i; -luaL_Buffer b; -const char*s=luaL_checklstring(L,1,&l); -luaL_buffinit(L,&b); -for(i=0;i0) -luaL_addlstring(&b,s,l); -luaL_pushresult(&b); -return 1; -} -static int str_byte(lua_State*L){ -size_t l; -const char*s=luaL_checklstring(L,1,&l); -ptrdiff_t posi=posrelat(luaL_optinteger(L,2,1),l); -ptrdiff_t pose=posrelat(luaL_optinteger(L,3,posi),l); -int n,i; -if(posi<=0)posi=1; -if((size_t)pose>l)pose=l; -if(posi>pose)return 0; -n=(int)(pose-posi+1); -if(posi+n<=pose) -luaL_error(L,"string slice too long"); -luaL_checkstack(L,n,"string slice too long"); -for(i=0;i=ms->level||ms->capture[l].len==(-1)) -return luaL_error(ms->L,"invalid capture index"); -return l; -} -static int capture_to_close(MatchState*ms){ -int level=ms->level; -for(level--;level>=0;level--) -if(ms->capture[level].len==(-1))return level; -return luaL_error(ms->L,"invalid pattern capture"); -} -static const char*classend(MatchState*ms,const char*p){ -switch(*p++){ -case'%':{ -if(*p=='\0') -luaL_error(ms->L,"malformed pattern (ends with "LUA_QL("%%")")"); -return p+1; -} -case'[':{ -if(*p=='^')p++; -do{ -if(*p=='\0') -luaL_error(ms->L,"malformed pattern (missing "LUA_QL("]")")"); -if(*(p++)=='%'&&*p!='\0') -p++; -}while(*p!=']'); -return p+1; -} -default:{ -return p; -} -} -} -static int match_class(int c,int cl){ -int res; -switch(tolower(cl)){ -case'a':res=isalpha(c);break; -case'c':res=iscntrl(c);break; -case'd':res=isdigit(c);break; -case'l':res=islower(c);break; -case'p':res=ispunct(c);break; -case's':res=isspace(c);break; -case'u':res=isupper(c);break; -case'w':res=isalnum(c);break; -case'x':res=isxdigit(c);break; -case'z':res=(c==0);break; -default:return(cl==c); -} -return(islower(cl)?res:!res); -} -static int matchbracketclass(int c,const char*p,const char*ec){ -int sig=1; -if(*(p+1)=='^'){ -sig=0; -p++; -} -while(++pL,"unbalanced pattern"); -if(*s!=*p)return NULL; -else{ -int b=*p; -int e=*(p+1); -int cont=1; -while(++ssrc_end){ -if(*s==e){ -if(--cont==0)return s+1; -} -else if(*s==b)cont++; -} -} -return NULL; -} -static const char*max_expand(MatchState*ms,const char*s, -const char*p,const char*ep){ -ptrdiff_t i=0; -while((s+i)src_end&&singlematch(uchar(*(s+i)),p,ep)) -i++; -while(i>=0){ -const char*res=match(ms,(s+i),ep+1); -if(res)return res; -i--; -} -return NULL; -} -static const char*min_expand(MatchState*ms,const char*s, -const char*p,const char*ep){ -for(;;){ -const char*res=match(ms,s,ep+1); -if(res!=NULL) -return res; -else if(ssrc_end&&singlematch(uchar(*s),p,ep)) -s++; -else return NULL; -} -} -static const char*start_capture(MatchState*ms,const char*s, -const char*p,int what){ -const char*res; -int level=ms->level; -if(level>=32)luaL_error(ms->L,"too many captures"); -ms->capture[level].init=s; -ms->capture[level].len=what; -ms->level=level+1; -if((res=match(ms,s,p))==NULL) -ms->level--; -return res; -} -static const char*end_capture(MatchState*ms,const char*s, -const char*p){ -int l=capture_to_close(ms); -const char*res; -ms->capture[l].len=s-ms->capture[l].init; -if((res=match(ms,s,p))==NULL) -ms->capture[l].len=(-1); -return res; -} -static const char*match_capture(MatchState*ms,const char*s,int l){ -size_t len; -l=check_capture(ms,l); -len=ms->capture[l].len; -if((size_t)(ms->src_end-s)>=len&& -memcmp(ms->capture[l].init,s,len)==0) -return s+len; -else return NULL; -} -static const char*match(MatchState*ms,const char*s,const char*p){ -init: -switch(*p){ -case'(':{ -if(*(p+1)==')') -return start_capture(ms,s,p+2,(-2)); -else -return start_capture(ms,s,p+1,(-1)); -} -case')':{ -return end_capture(ms,s,p+1); -} -case'%':{ -switch(*(p+1)){ -case'b':{ -s=matchbalance(ms,s,p+2); -if(s==NULL)return NULL; -p+=4;goto init; -} -case'f':{ -const char*ep;char previous; -p+=2; -if(*p!='[') -luaL_error(ms->L,"missing "LUA_QL("[")" after " -LUA_QL("%%f")" in pattern"); -ep=classend(ms,p); -previous=(s==ms->src_init)?'\0':*(s-1); -if(matchbracketclass(uchar(previous),p,ep-1)|| -!matchbracketclass(uchar(*s),p,ep-1))return NULL; -p=ep;goto init; -} -default:{ -if(isdigit(uchar(*(p+1)))){ -s=match_capture(ms,s,uchar(*(p+1))); -if(s==NULL)return NULL; -p+=2;goto init; -} -goto dflt; -} -} -} -case'\0':{ -return s; -} -case'$':{ -if(*(p+1)=='\0') -return(s==ms->src_end)?s:NULL; -else goto dflt; -} -default:dflt:{ -const char*ep=classend(ms,p); -int m=ssrc_end&&singlematch(uchar(*s),p,ep); -switch(*ep){ -case'?':{ -const char*res; -if(m&&((res=match(ms,s+1,ep+1))!=NULL)) -return res; -p=ep+1;goto init; -} -case'*':{ -return max_expand(ms,s,p,ep); -} -case'+':{ -return(m?max_expand(ms,s+1,p,ep):NULL); -} -case'-':{ -return min_expand(ms,s,p,ep); -} -default:{ -if(!m)return NULL; -s++;p=ep;goto init; -} -} -} -} -} -static const char*lmemfind(const char*s1,size_t l1, -const char*s2,size_t l2){ -if(l2==0)return s1; -else if(l2>l1)return NULL; -else{ -const char*init; -l2--; -l1=l1-l2; -while(l1>0&&(init=(const char*)memchr(s1,*s2,l1))!=NULL){ -init++; -if(memcmp(init,s2+1,l2)==0) -return init-1; -else{ -l1-=init-s1; -s1=init; -} -} -return NULL; -} -} -static void push_onecapture(MatchState*ms,int i,const char*s, -const char*e){ -if(i>=ms->level){ -if(i==0) -lua_pushlstring(ms->L,s,e-s); -else -luaL_error(ms->L,"invalid capture index"); -} -else{ -ptrdiff_t l=ms->capture[i].len; -if(l==(-1))luaL_error(ms->L,"unfinished capture"); -if(l==(-2)) -lua_pushinteger(ms->L,ms->capture[i].init-ms->src_init+1); -else -lua_pushlstring(ms->L,ms->capture[i].init,l); -} -} -static int push_captures(MatchState*ms,const char*s,const char*e){ -int i; -int nlevels=(ms->level==0&&s)?1:ms->level; -luaL_checkstack(ms->L,nlevels,"too many captures"); -for(i=0;il1)init=(ptrdiff_t)l1; -if(find&&(lua_toboolean(L,4)|| -strpbrk(p,"^$*+?.([%-")==NULL)){ -const char*s2=lmemfind(s+init,l1-init,p,l2); -if(s2){ -lua_pushinteger(L,s2-s+1); -lua_pushinteger(L,s2-s+l2); -return 2; -} -} -else{ -MatchState ms; -int anchor=(*p=='^')?(p++,1):0; -const char*s1=s+init; -ms.L=L; -ms.src_init=s; -ms.src_end=s+l1; -do{ -const char*res; -ms.level=0; -if((res=match(&ms,s1,p))!=NULL){ -if(find){ -lua_pushinteger(L,s1-s+1); -lua_pushinteger(L,res-s); -return push_captures(&ms,NULL,0)+2; -} -else -return push_captures(&ms,s1,res); -} -}while(s1++L,3,&l); -for(i=0;iL; -switch(lua_type(L,3)){ -case 3: -case 4:{ -add_s(ms,b,s,e); -return; -} -case 6:{ -int n; -lua_pushvalue(L,3); -n=push_captures(ms,s,e); -lua_call(L,n,1); -break; -} -case 5:{ -push_onecapture(ms,0,s,e); -lua_gettable(L,3); -break; -} -} -if(!lua_toboolean(L,-1)){ -lua_pop(L,1); -lua_pushlstring(L,s,e-s); -} -else if(!lua_isstring(L,-1)) -luaL_error(L,"invalid replacement value (a %s)",luaL_typename(L,-1)); -luaL_addvalue(b); -} -static int str_gsub(lua_State*L){ -size_t srcl; -const char*src=luaL_checklstring(L,1,&srcl); -const char*p=luaL_checkstring(L,2); -int tr=lua_type(L,3); -int max_s=luaL_optint(L,4,srcl+1); -int anchor=(*p=='^')?(p++,1):0; -int n=0; -MatchState ms; -luaL_Buffer b; -luaL_argcheck(L,tr==3||tr==4|| -tr==6||tr==5,3, -"string/function/table expected"); -luaL_buffinit(L,&b); -ms.L=L; -ms.src_init=src; -ms.src_end=src+srcl; -while(nsrc) -src=e; -else if(src=sizeof("-+ #0")) -luaL_error(L,"invalid format (repeated flags)"); -if(isdigit(uchar(*p)))p++; -if(isdigit(uchar(*p)))p++; -if(*p=='.'){ -p++; -if(isdigit(uchar(*p)))p++; -if(isdigit(uchar(*p)))p++; -} -if(isdigit(uchar(*p))) -luaL_error(L,"invalid format (width or precision too long)"); -*(form++)='%'; -strncpy(form,strfrmt,p-strfrmt+1); -form+=p-strfrmt+1; -*form='\0'; -return p; -} -static void addintlen(char*form){ -size_t l=strlen(form); -char spec=form[l-1]; -strcpy(form+l-1,"l"); -form[l+sizeof("l")-2]=spec; -form[l+sizeof("l")-1]='\0'; -} -static int str_format(lua_State*L){ -int top=lua_gettop(L); -int arg=1; -size_t sfl; -const char*strfrmt=luaL_checklstring(L,arg,&sfl); -const char*strfrmt_end=strfrmt+sfl; -luaL_Buffer b; -luaL_buffinit(L,&b); -while(strfrmttop) -luaL_argerror(L,arg,"no value"); -strfrmt=scanformat(L,strfrmt,form); -switch(*strfrmt++){ -case'c':{ -sprintf(buff,form,(int)luaL_checknumber(L,arg)); -break; -} -case'd':case'i':{ -addintlen(form); -sprintf(buff,form,(long)luaL_checknumber(L,arg)); -break; -} -case'o':case'u':case'x':case'X':{ -addintlen(form); -sprintf(buff,form,(unsigned long)luaL_checknumber(L,arg)); -break; -} -case'e':case'E':case'f': -case'g':case'G':{ -sprintf(buff,form,(double)luaL_checknumber(L,arg)); -break; -} -case'q':{ -addquoted(L,&b,arg); -continue; -} -case's':{ -size_t l; -const char*s=luaL_checklstring(L,arg,&l); -if(!strchr(form,'.')&&l>=100){ -lua_pushvalue(L,arg); -luaL_addvalue(&b); -continue; -} -else{ -sprintf(buff,form,s); -break; -} -} -default:{ -return luaL_error(L,"invalid option "LUA_QL("%%%c")" to " -LUA_QL("format"),*(strfrmt-1)); -} -} -luaL_addlstring(&b,buff,strlen(buff)); -} -} -luaL_pushresult(&b); -return 1; -} -static const luaL_Reg strlib[]={ -{"byte",str_byte}, -{"char",str_char}, -{"find",str_find}, -{"format",str_format}, -{"gmatch",gmatch}, -{"gsub",str_gsub}, -{"lower",str_lower}, -{"match",str_match}, -{"rep",str_rep}, -{"sub",str_sub}, -{"upper",str_upper}, -{NULL,NULL} -}; -static void createmetatable(lua_State*L){ -lua_createtable(L,0,1); -lua_pushliteral(L,""); -lua_pushvalue(L,-2); -lua_setmetatable(L,-2); -lua_pop(L,1); -lua_pushvalue(L,-2); -lua_setfield(L,-2,"__index"); -lua_pop(L,1); -} -static int luaopen_string(lua_State*L){ -luaL_register(L,"string",strlib); -createmetatable(L); -return 1; -} -static const luaL_Reg lualibs[]={ -{"",luaopen_base}, -{"table",luaopen_table}, -{"io",luaopen_io}, -{"os",luaopen_os}, -{"string",luaopen_string}, -{NULL,NULL} -}; -static void luaL_openlibs(lua_State*L){ -const luaL_Reg*lib=lualibs; -for(;lib->func;lib++){ -lua_pushcfunction(L,lib->func); -lua_pushstring(L,lib->name); -lua_call(L,1,0); -} -} -typedef unsigned int UB; -static UB barg(lua_State*L,int idx){ -union{lua_Number n;U64 b;}bn; -bn.n=lua_tonumber(L,idx)+6755399441055744.0; -if(bn.n==0.0&&!lua_isnumber(L,idx))luaL_typerror(L,idx,"number"); -return(UB)bn.b; -} -#define BRET(b)lua_pushnumber(L,(lua_Number)(int)(b));return 1; -static int tobit(lua_State*L){ -BRET(barg(L,1))} -static int bnot(lua_State*L){ -BRET(~barg(L,1))} -static int band(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b&=barg(L,i);BRET(b)} -static int bor(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b|=barg(L,i);BRET(b)} -static int bxor(lua_State*L){ -int i;UB b=barg(L,1);for(i=lua_gettop(L);i>1;i--)b^=barg(L,i);BRET(b)} -static int lshift(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET(b<>n)} -static int arshift(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((int)b>>n)} -static int rol(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b<>(32-n)))} -static int ror(lua_State*L){ -UB b=barg(L,1),n=barg(L,2)&31;BRET((b>>n)|(b<<(32-n)))} -static int bswap(lua_State*L){ -UB b=barg(L,1);b=(b>>24)|((b>>8)&0xff00)|((b&0xff00)<<8)|(b<<24);BRET(b)} -static int tohex(lua_State*L){ -UB b=barg(L,1); -int n=lua_isnone(L,2)?8:(int)barg(L,2); -const char*hexdigits="0123456789abcdef"; -char buf[8]; -int i; -if(n<0){n=-n;hexdigits="0123456789ABCDEF";} -if(n>8)n=8; -for(i=(int)n;--i>=0;){buf[i]=hexdigits[b&15];b>>=4;} -lua_pushlstring(L,buf,(size_t)n); -return 1; -} -static const struct luaL_Reg bitlib[]={ -{"tobit",tobit}, -{"bnot",bnot}, -{"band",band}, -{"bor",bor}, -{"bxor",bxor}, -{"lshift",lshift}, -{"rshift",rshift}, -{"arshift",arshift}, -{"rol",rol}, -{"ror",ror}, -{"bswap",bswap}, -{"tohex",tohex}, -{NULL,NULL} -}; -int main(int argc,char**argv){ -lua_State*L=luaL_newstate(); -int i; -luaL_openlibs(L); -luaL_register(L,"bit",bitlib); -if(argc<2)return sizeof(void*); -lua_createtable(L,0,1); -lua_pushstring(L,argv[1]); -lua_rawseti(L,-2,0); -lua_setglobal(L,"arg"); -if(luaL_loadfile(L,argv[1])) -goto err; -for(i=2;i -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE 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. diff --git a/ext/opcache/jit/libudis86/decode.c b/ext/opcache/jit/libudis86/decode.c deleted file mode 100644 index 1c97d280d98e5..0000000000000 --- a/ext/opcache/jit/libudis86/decode.c +++ /dev/null @@ -1,1266 +0,0 @@ -/* 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 -#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 up to 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/ext/opcache/jit/libudis86/decode.h b/ext/opcache/jit/libudis86/decode.h deleted file mode 100644 index 3949c4e269bff..0000000000000 --- a/ext/opcache/jit/libudis86/decode.h +++ /dev/null @@ -1,197 +0,0 @@ -/* 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/ext/opcache/jit/libudis86/extern.h b/ext/opcache/jit/libudis86/extern.h deleted file mode 100644 index 71a01fd9b4d85..0000000000000 --- a/ext/opcache/jit/libudis86/extern.h +++ /dev/null @@ -1,113 +0,0 @@ -/* 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/ext/opcache/jit/libudis86/itab.c b/ext/opcache/jit/libudis86/itab.c deleted file mode 100644 index 953f3e5227875..0000000000000 --- a/ext/opcache/jit/libudis86/itab.c +++ /dev/null @@ -1,5946 +0,0 @@ -/* 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/ext/opcache/jit/libudis86/itab.h b/ext/opcache/jit/libudis86/itab.h deleted file mode 100644 index 3d54c43546203..0000000000000 --- a/ext/opcache/jit/libudis86/itab.h +++ /dev/null @@ -1,939 +0,0 @@ -#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/ext/opcache/jit/libudis86/syn-att.c b/ext/opcache/jit/libudis86/syn-att.c deleted file mode 100644 index d1ba89b7ae217..0000000000000 --- a/ext/opcache/jit/libudis86/syn-att.c +++ /dev/null @@ -1,228 +0,0 @@ -/* 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/ext/opcache/jit/libudis86/syn-intel.c b/ext/opcache/jit/libudis86/syn-intel.c deleted file mode 100644 index 0664fea092770..0000000000000 --- a/ext/opcache/jit/libudis86/syn-intel.c +++ /dev/null @@ -1,224 +0,0 @@ -/* 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/ext/opcache/jit/libudis86/syn.c b/ext/opcache/jit/libudis86/syn.c deleted file mode 100644 index c7453d63b7821..0000000000000 --- a/ext/opcache/jit/libudis86/syn.c +++ /dev/null @@ -1,258 +0,0 @@ -/* 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) -{ -#if 1 - const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->adr_mode); -#else - const uint64_t trunc_mask = 0xffffffffffffffffull >> (64 - u->opr_mode); -#endif - 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 */ - } - } -#if 1 - if (u->sym_resolver) { - int64_t offset = 0; - const char *name = u->sym_resolver(u, v, &offset); - if (name) { - if (offset) { - ud_asmprintf(u, "%s%+" FMT64 "d", name, offset); - } else { - ud_asmprintf(u, "%s", name); - } - return; - } - } -#endif - 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 */ - } -#if 1 - if (u->sym_resolver) { - int64_t offset = 0; - const char *name = u->sym_resolver(u, v, &offset); - if (name) { - if (offset) { - ud_asmprintf(u, "%s%+" FMT64 "d", name, offset); - } else { - ud_asmprintf(u, "%s", name); - } - return; - } - } -#endif - 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 1 - if (u->sym_resolver) { - int64_t offset = 0; - const char *name = u->sym_resolver(u, v, &offset); - if (name) { - if (offset) { - ud_asmprintf(u, "%s%+" FMT64 "d", name, offset); - } else { - ud_asmprintf(u, "%s", name); - } - return; - } - } -#endif - 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/ext/opcache/jit/libudis86/syn.h b/ext/opcache/jit/libudis86/syn.h deleted file mode 100644 index d3b1e3fe04441..0000000000000 --- a/ext/opcache/jit/libudis86/syn.h +++ /dev/null @@ -1,53 +0,0 @@ -/* 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 -#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/ext/opcache/jit/libudis86/types.h b/ext/opcache/jit/libudis86/types.h deleted file mode 100644 index 69072ca480517..0000000000000 --- a/ext/opcache/jit/libudis86/types.h +++ /dev/null @@ -1,260 +0,0 @@ -/* 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 -# include -# ifndef __UD_STANDALONE__ -# define __UD_STANDALONE__ 1 -# endif -#endif /* __KERNEL__ */ - -#if !defined(__UD_STANDALONE__) -# include -# include -#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/ext/opcache/jit/libudis86/udint.h b/ext/opcache/jit/libudis86/udint.h deleted file mode 100644 index 0bf493c182bb6..0000000000000 --- a/ext/opcache/jit/libudis86/udint.h +++ /dev/null @@ -1,99 +0,0 @@ -/* 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" - -#ifdef HAVE_CONFIG_H -# include -#endif /* HAVE_CONFIG_H */ - -#if defined(UD_DEBUG) && HAVE_ASSERT_H -# include -# define UD_ASSERT(_x) assert(_x) -#else -# define UD_ASSERT(_x) -#endif /* !HAVE_ASSERT_H */ - -#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__) || defined(__OpenBSD__) -# 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/ext/opcache/jit/libudis86/udis86.c b/ext/opcache/jit/libudis86/udis86.c deleted file mode 100644 index 0e00729febf46..0000000000000 --- a/ext/opcache/jit/libudis86/udis86.c +++ /dev/null @@ -1,458 +0,0 @@ -/* 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__) -# if HAVE_STRING_H -# include -# endif -#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 "???"; - } -} - - -/* - * 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/ext/opcache/jit/vtune/ittnotify_config.h b/ext/opcache/jit/vtune/ittnotify_config.h deleted file mode 100644 index fc3a476cdd1c9..0000000000000 --- a/ext/opcache/jit/vtune/ittnotify_config.h +++ /dev/null @@ -1,596 +0,0 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - 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. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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 _ITTNOTIFY_CONFIG_H_ -#define _ITTNOTIFY_CONFIG_H_ - -/** @cond exclude_from_documentation */ -#ifndef ITT_OS_WIN -# define ITT_OS_WIN 1 -#endif /* ITT_OS_WIN */ - -#ifndef ITT_OS_LINUX -# define ITT_OS_LINUX 2 -#endif /* ITT_OS_LINUX */ - -#ifndef ITT_OS_MAC -# define ITT_OS_MAC 3 -#endif /* ITT_OS_MAC */ - -#ifndef ITT_OS_FREEBSD -# define ITT_OS_FREEBSD 4 -#endif /* ITT_OS_FREEBSD */ - -#ifndef ITT_OS -# if defined WIN32 || defined _WIN32 -# define ITT_OS ITT_OS_WIN -# elif defined( __APPLE__ ) && defined( __MACH__ ) -# define ITT_OS ITT_OS_MAC -# elif defined( __FreeBSD__ ) -# define ITT_OS ITT_OS_FREEBSD -# else -# define ITT_OS ITT_OS_LINUX -# endif -#endif /* ITT_OS */ - -#ifndef ITT_PLATFORM_WIN -# define ITT_PLATFORM_WIN 1 -#endif /* ITT_PLATFORM_WIN */ - -#ifndef ITT_PLATFORM_POSIX -# define ITT_PLATFORM_POSIX 2 -#endif /* ITT_PLATFORM_POSIX */ - -#ifndef ITT_PLATFORM_MAC -# define ITT_PLATFORM_MAC 3 -#endif /* ITT_PLATFORM_MAC */ - -#ifndef ITT_PLATFORM_FREEBSD -# define ITT_PLATFORM_FREEBSD 4 -#endif /* ITT_PLATFORM_FREEBSD */ - -#ifndef ITT_PLATFORM -# if ITT_OS==ITT_OS_WIN -# define ITT_PLATFORM ITT_PLATFORM_WIN -# elif ITT_OS==ITT_OS_MAC -# define ITT_PLATFORM ITT_PLATFORM_MAC -# elif ITT_OS==ITT_OS_FREEBSD -# define ITT_PLATFORM ITT_PLATFORM_FREEBSD -# else -# define ITT_PLATFORM ITT_PLATFORM_POSIX -# endif -#endif /* ITT_PLATFORM */ - -#if defined(_UNICODE) && !defined(UNICODE) -#define UNICODE -#endif - -#include -#if ITT_PLATFORM==ITT_PLATFORM_WIN -#include -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#include -#if defined(UNICODE) || defined(_UNICODE) -#include -#endif /* UNICODE || _UNICODE */ -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - -#ifndef ITTAPI_CDECL -# if ITT_PLATFORM==ITT_PLATFORM_WIN -# define ITTAPI_CDECL __cdecl -# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -# if defined _M_IX86 || defined __i386__ -# define ITTAPI_CDECL __attribute__ ((cdecl)) -# else /* _M_IX86 || __i386__ */ -# define ITTAPI_CDECL /* actual only on x86 platform */ -# endif /* _M_IX86 || __i386__ */ -# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#endif /* ITTAPI_CDECL */ - -#ifndef STDCALL -# if ITT_PLATFORM==ITT_PLATFORM_WIN -# define STDCALL __stdcall -# else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -# if defined _M_IX86 || defined __i386__ -# define STDCALL __attribute__ ((stdcall)) -# else /* _M_IX86 || __i386__ */ -# define STDCALL /* supported only on x86 platform */ -# endif /* _M_IX86 || __i386__ */ -# endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#endif /* STDCALL */ - -#define ITTAPI ITTAPI_CDECL -#define LIBITTAPI ITTAPI_CDECL - -/* TODO: Temporary for compatibility! */ -#define ITTAPI_CALL ITTAPI_CDECL -#define LIBITTAPI_CALL ITTAPI_CDECL - -#if ITT_PLATFORM==ITT_PLATFORM_WIN -/* use __forceinline (VC++ specific) */ -#define ITT_INLINE __forceinline -#define ITT_INLINE_ATTRIBUTE /* nothing */ -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -/* - * Generally, functions are not inlined unless optimization is specified. - * For functions declared inline, this attribute inlines the function even - * if no optimization level was specified. - */ -#ifdef __STRICT_ANSI__ -#define ITT_INLINE static -#define ITT_INLINE_ATTRIBUTE __attribute__((unused)) -#else /* __STRICT_ANSI__ */ -#define ITT_INLINE static inline -#define ITT_INLINE_ATTRIBUTE __attribute__((always_inline, unused)) -#endif /* __STRICT_ANSI__ */ -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -/** @endcond */ - -#ifndef ITT_ARCH_IA32 -# define ITT_ARCH_IA32 1 -#endif /* ITT_ARCH_IA32 */ - -#ifndef ITT_ARCH_IA32E -# define ITT_ARCH_IA32E 2 -#endif /* ITT_ARCH_IA32E */ - -#ifndef ITT_ARCH_ARM -# define ITT_ARCH_ARM 4 -#endif /* ITT_ARCH_ARM */ - -#ifndef ITT_ARCH_PPC64 -# define ITT_ARCH_PPC64 5 -#endif /* ITT_ARCH_PPC64 */ - -#ifndef ITT_ARCH -# if defined _M_IX86 || defined __i386__ -# define ITT_ARCH ITT_ARCH_IA32 -# elif defined _M_X64 || defined _M_AMD64 || defined __x86_64__ -# define ITT_ARCH ITT_ARCH_IA32E -# elif defined _M_IA64 || defined __ia64__ -# define ITT_ARCH ITT_ARCH_IA64 -# elif defined _M_ARM || defined __arm__ -# define ITT_ARCH ITT_ARCH_ARM -# elif defined __powerpc64__ -# define ITT_ARCH ITT_ARCH_PPC64 -# endif -#endif - -#ifdef __cplusplus -# define ITT_EXTERN_C extern "C" -# define ITT_EXTERN_C_BEGIN extern "C" { -# define ITT_EXTERN_C_END } -#else -# define ITT_EXTERN_C /* nothing */ -# define ITT_EXTERN_C_BEGIN /* nothing */ -# define ITT_EXTERN_C_END /* nothing */ -#endif /* __cplusplus */ - -#define ITT_TO_STR_AUX(x) #x -#define ITT_TO_STR(x) ITT_TO_STR_AUX(x) - -#define __ITT_BUILD_ASSERT(expr, suffix) do { \ - static char __itt_build_check_##suffix[(expr) ? 1 : -1]; \ - __itt_build_check_##suffix[0] = 0; \ -} while(0) -#define _ITT_BUILD_ASSERT(expr, suffix) __ITT_BUILD_ASSERT((expr), suffix) -#define ITT_BUILD_ASSERT(expr) _ITT_BUILD_ASSERT((expr), __LINE__) - -#define ITT_MAGIC { 0xED, 0xAB, 0xAB, 0xEC, 0x0D, 0xEE, 0xDA, 0x30 } - -/* Replace with snapshot date YYYYMMDD for promotion build. */ -#define API_VERSION_BUILD 20151119 - -#ifndef API_VERSION_NUM -#define API_VERSION_NUM 0.0.0 -#endif /* API_VERSION_NUM */ - -#define API_VERSION "ITT-API-Version " ITT_TO_STR(API_VERSION_NUM) \ - " (" ITT_TO_STR(API_VERSION_BUILD) ")" - -/* OS communication functions */ -#if ITT_PLATFORM==ITT_PLATFORM_WIN -#include -typedef HMODULE lib_t; -typedef DWORD TIDT; -typedef CRITICAL_SECTION mutex_t; -#define MUTEX_INITIALIZER { 0 } -#define strong_alias(name, aliasname) /* empty for Windows */ -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#include -#if defined(UNICODE) || defined(_UNICODE) -#include -#endif /* UNICODE */ -#ifndef _GNU_SOURCE -#define _GNU_SOURCE 1 /* need for PTHREAD_MUTEX_RECURSIVE */ -#endif /* _GNU_SOURCE */ -#ifndef __USE_UNIX98 -#define __USE_UNIX98 1 /* need for PTHREAD_MUTEX_RECURSIVE, on SLES11.1 with gcc 4.3.4 wherein pthread.h missing dependency on __USE_XOPEN2K8 */ -#endif /*__USE_UNIX98*/ -#include -typedef void* lib_t; -typedef pthread_t TIDT; -typedef pthread_mutex_t mutex_t; -#define MUTEX_INITIALIZER PTHREAD_MUTEX_INITIALIZER -#define _strong_alias(name, aliasname) \ - extern __typeof (name) aliasname __attribute__ ((alias (#name))); -#define strong_alias(name, aliasname) _strong_alias(name, aliasname) -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - -#if ITT_PLATFORM==ITT_PLATFORM_WIN -#define __itt_get_proc(lib, name) GetProcAddress(lib, name) -#define __itt_mutex_init(mutex) InitializeCriticalSection(mutex) -#define __itt_mutex_lock(mutex) EnterCriticalSection(mutex) -#define __itt_mutex_unlock(mutex) LeaveCriticalSection(mutex) -#define __itt_load_lib(name) LoadLibraryA(name) -#define __itt_unload_lib(handle) FreeLibrary(handle) -#define __itt_system_error() (int)GetLastError() -#define __itt_fstrcmp(s1, s2) lstrcmpA(s1, s2) -#define __itt_fstrnlen(s, l) strnlen_s(s, l) -#define __itt_fstrcpyn(s1, b, s2, l) strncpy_s(s1, b, s2, l) -#define __itt_fstrdup(s) _strdup(s) -#define __itt_thread_id() GetCurrentThreadId() -#define __itt_thread_yield() SwitchToThread() -#ifndef ITT_SIMPLE_INIT -ITT_INLINE long -__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE; -ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) -{ - return InterlockedIncrement(ptr); -} -#endif /* ITT_SIMPLE_INIT */ -#else /* ITT_PLATFORM!=ITT_PLATFORM_WIN */ -#define __itt_get_proc(lib, name) dlsym(lib, name) -#define __itt_mutex_init(mutex) {\ - pthread_mutexattr_t mutex_attr; \ - int error_code = pthread_mutexattr_init(&mutex_attr); \ - if (error_code) \ - __itt_report_error(__itt_error_system, "pthread_mutexattr_init", \ - error_code); \ - error_code = pthread_mutexattr_settype(&mutex_attr, \ - PTHREAD_MUTEX_RECURSIVE); \ - if (error_code) \ - __itt_report_error(__itt_error_system, "pthread_mutexattr_settype", \ - error_code); \ - error_code = pthread_mutex_init(mutex, &mutex_attr); \ - if (error_code) \ - __itt_report_error(__itt_error_system, "pthread_mutex_init", \ - error_code); \ - error_code = pthread_mutexattr_destroy(&mutex_attr); \ - if (error_code) \ - __itt_report_error(__itt_error_system, "pthread_mutexattr_destroy", \ - error_code); \ -} -#define __itt_mutex_lock(mutex) pthread_mutex_lock(mutex) -#define __itt_mutex_unlock(mutex) pthread_mutex_unlock(mutex) -#define __itt_load_lib(name) dlopen(name, RTLD_LAZY) -#define __itt_unload_lib(handle) dlclose(handle) -#define __itt_system_error() errno -#define __itt_fstrcmp(s1, s2) strcmp(s1, s2) - -/* makes customer code define safe APIs for SDL_STRNLEN_S and SDL_STRNCPY_S */ -#ifdef SDL_STRNLEN_S -#define __itt_fstrnlen(s, l) SDL_STRNLEN_S(s, l) -#else -#define __itt_fstrnlen(s, l) strlen(s) -#endif /* SDL_STRNLEN_S */ -#ifdef SDL_STRNCPY_S -#define __itt_fstrcpyn(s1, b, s2, l) SDL_STRNCPY_S(s1, b, s2, l) -#else -#define __itt_fstrcpyn(s1, b, s2, l) strncpy(s1, s2, l) -#endif /* SDL_STRNCPY_S */ - -#define __itt_fstrdup(s) strdup(s) -#define __itt_thread_id() pthread_self() -#define __itt_thread_yield() sched_yield() -#if ITT_ARCH==ITT_ARCH_IA64 -#ifdef __INTEL_COMPILER -#define __TBB_machine_fetchadd4(addr, val) __fetchadd4_acq((void *)addr, val) -#else /* __INTEL_COMPILER */ -/* TODO: Add Support for not Intel compilers for IA-64 architecture */ -#endif /* __INTEL_COMPILER */ -#elif ITT_ARCH==ITT_ARCH_IA32 || ITT_ARCH==ITT_ARCH_IA32E /* ITT_ARCH!=ITT_ARCH_IA64 */ -ITT_INLINE long -__TBB_machine_fetchadd4(volatile void* ptr, long addend) ITT_INLINE_ATTRIBUTE; -ITT_INLINE long __TBB_machine_fetchadd4(volatile void* ptr, long addend) -{ - long result; - __asm__ __volatile__("lock\nxadd %0,%1" - : "=r"(result),"=m"(*(int*)ptr) - : "0"(addend), "m"(*(int*)ptr) - : "memory"); - return result; -} -#elif ITT_ARCH==ITT_ARCH_ARM || ITT_ARCH==ITT_ARCH_PPC64 -#define __TBB_machine_fetchadd4(addr, val) __sync_fetch_and_add(addr, val) -#endif /* ITT_ARCH==ITT_ARCH_IA64 */ -#ifndef ITT_SIMPLE_INIT -ITT_INLINE long -__itt_interlocked_increment(volatile long* ptr) ITT_INLINE_ATTRIBUTE; -ITT_INLINE long __itt_interlocked_increment(volatile long* ptr) -{ - return __TBB_machine_fetchadd4(ptr, 1) + 1L; -} -#endif /* ITT_SIMPLE_INIT */ -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - -typedef enum { - __itt_collection_normal = 0, - __itt_collection_paused = 1 -} __itt_collection_state; - -typedef enum { - __itt_thread_normal = 0, - __itt_thread_ignored = 1 -} __itt_thread_state; - -#pragma pack(push, 8) - -typedef struct ___itt_thread_info -{ - const char* nameA; /*!< Copy of original name in ASCII. */ -#if defined(UNICODE) || defined(_UNICODE) - const wchar_t* nameW; /*!< Copy of original name in UNICODE. */ -#else /* UNICODE || _UNICODE */ - void* nameW; -#endif /* UNICODE || _UNICODE */ - TIDT tid; - __itt_thread_state state; /*!< Thread state (paused or normal) */ - int extra1; /*!< Reserved to the runtime */ - void* extra2; /*!< Reserved to the runtime */ - struct ___itt_thread_info* next; -} __itt_thread_info; - -#include "ittnotify_types.h" /* For __itt_group_id definition */ - -typedef struct ___itt_api_info_20101001 -{ - const char* name; - void** func_ptr; - void* init_func; - __itt_group_id group; -} __itt_api_info_20101001; - -typedef struct ___itt_api_info -{ - const char* name; - void** func_ptr; - void* init_func; - void* null_func; - __itt_group_id group; -} __itt_api_info; - -typedef struct __itt_counter_info -{ - const char* nameA; /*!< Copy of original name in ASCII. */ -#if defined(UNICODE) || defined(_UNICODE) - const wchar_t* nameW; /*!< Copy of original name in UNICODE. */ -#else /* UNICODE || _UNICODE */ - void* nameW; -#endif /* UNICODE || _UNICODE */ - const char* domainA; /*!< Copy of original name in ASCII. */ -#if defined(UNICODE) || defined(_UNICODE) - const wchar_t* domainW; /*!< Copy of original name in UNICODE. */ -#else /* UNICODE || _UNICODE */ - void* domainW; -#endif /* UNICODE || _UNICODE */ - int type; - long index; - int extra1; /*!< Reserved to the runtime */ - void* extra2; /*!< Reserved to the runtime */ - struct __itt_counter_info* next; -} __itt_counter_info_t; - -struct ___itt_domain; -struct ___itt_string_handle; - -typedef struct ___itt_global -{ - unsigned char magic[8]; - unsigned long version_major; - unsigned long version_minor; - unsigned long version_build; - volatile long api_initialized; - volatile long mutex_initialized; - volatile long atomic_counter; - mutex_t mutex; - lib_t lib; - void* error_handler; - const char** dll_path_ptr; - __itt_api_info* api_list_ptr; - struct ___itt_global* next; - /* Joinable structures below */ - __itt_thread_info* thread_list; - struct ___itt_domain* domain_list; - struct ___itt_string_handle* string_list; - __itt_collection_state state; - __itt_counter_info_t* counter_list; -} __itt_global; - -#pragma pack(pop) - -#define NEW_THREAD_INFO_W(gptr,h,h_tail,t,s,n) { \ - h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \ - if (h != NULL) { \ - h->tid = t; \ - h->nameA = NULL; \ - h->nameW = n ? _wcsdup(n) : NULL; \ - h->state = s; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->thread_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_THREAD_INFO_A(gptr,h,h_tail,t,s,n) { \ - h = (__itt_thread_info*)malloc(sizeof(__itt_thread_info)); \ - if (h != NULL) { \ - h->tid = t; \ - h->nameA = n ? __itt_fstrdup(n) : NULL; \ - h->nameW = NULL; \ - h->state = s; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->thread_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_DOMAIN_W(gptr,h,h_tail,name) { \ - h = (__itt_domain*)malloc(sizeof(__itt_domain)); \ - if (h != NULL) { \ - h->flags = 1; /* domain is enabled by default */ \ - h->nameA = NULL; \ - h->nameW = name ? _wcsdup(name) : NULL; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->domain_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_DOMAIN_A(gptr,h,h_tail,name) { \ - h = (__itt_domain*)malloc(sizeof(__itt_domain)); \ - if (h != NULL) { \ - h->flags = 1; /* domain is enabled by default */ \ - h->nameA = name ? __itt_fstrdup(name) : NULL; \ - h->nameW = NULL; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->domain_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_STRING_HANDLE_W(gptr,h,h_tail,name) { \ - h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \ - if (h != NULL) { \ - h->strA = NULL; \ - h->strW = name ? _wcsdup(name) : NULL; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->string_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_STRING_HANDLE_A(gptr,h,h_tail,name) { \ - h = (__itt_string_handle*)malloc(sizeof(__itt_string_handle)); \ - if (h != NULL) { \ - h->strA = name ? __itt_fstrdup(name) : NULL; \ - h->strW = NULL; \ - h->extra1 = 0; /* reserved */ \ - h->extra2 = NULL; /* reserved */ \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->string_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_COUNTER_W(gptr,h,h_tail,name,domain,type) { \ - h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \ - if (h != NULL) { \ - h->nameA = NULL; \ - h->nameW = name ? _wcsdup(name) : NULL; \ - h->domainA = NULL; \ - h->domainW = name ? _wcsdup(domain) : NULL; \ - h->type = type; \ - h->index = 0; \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->counter_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#define NEW_COUNTER_A(gptr,h,h_tail,name,domain,type) { \ - h = (__itt_counter_info_t*)malloc(sizeof(__itt_counter_info_t)); \ - if (h != NULL) { \ - h->nameA = name ? __itt_fstrdup(name) : NULL; \ - h->nameW = NULL; \ - h->domainA = domain ? __itt_fstrdup(domain) : NULL; \ - h->domainW = NULL; \ - h->type = type; \ - h->index = 0; \ - h->next = NULL; \ - if (h_tail == NULL) \ - (gptr)->counter_list = h; \ - else \ - h_tail->next = h; \ - } \ -} - -#endif /* _ITTNOTIFY_CONFIG_H_ */ diff --git a/ext/opcache/jit/vtune/ittnotify_types.h b/ext/opcache/jit/vtune/ittnotify_types.h deleted file mode 100644 index e10250bd63d4f..0000000000000 --- a/ext/opcache/jit/vtune/ittnotify_types.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - 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. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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 _ITTNOTIFY_TYPES_H_ -#define _ITTNOTIFY_TYPES_H_ - -typedef enum ___itt_group_id -{ - __itt_group_none = 0, - __itt_group_legacy = 1<<0, - __itt_group_control = 1<<1, - __itt_group_thread = 1<<2, - __itt_group_mark = 1<<3, - __itt_group_sync = 1<<4, - __itt_group_fsync = 1<<5, - __itt_group_jit = 1<<6, - __itt_group_model = 1<<7, - __itt_group_splitter_min = 1<<7, - __itt_group_counter = 1<<8, - __itt_group_frame = 1<<9, - __itt_group_stitch = 1<<10, - __itt_group_heap = 1<<11, - __itt_group_splitter_max = 1<<12, - __itt_group_structure = 1<<12, - __itt_group_suppress = 1<<13, - __itt_group_arrays = 1<<14, - __itt_group_all = -1 -} __itt_group_id; - -#pragma pack(push, 8) - -typedef struct ___itt_group_list -{ - __itt_group_id id; - const char* name; -} __itt_group_list; - -#pragma pack(pop) - -#define ITT_GROUP_LIST(varname) \ - static __itt_group_list varname[] = { \ - { __itt_group_all, "all" }, \ - { __itt_group_control, "control" }, \ - { __itt_group_thread, "thread" }, \ - { __itt_group_mark, "mark" }, \ - { __itt_group_sync, "sync" }, \ - { __itt_group_fsync, "fsync" }, \ - { __itt_group_jit, "jit" }, \ - { __itt_group_model, "model" }, \ - { __itt_group_counter, "counter" }, \ - { __itt_group_frame, "frame" }, \ - { __itt_group_stitch, "stitch" }, \ - { __itt_group_heap, "heap" }, \ - { __itt_group_structure, "structure" }, \ - { __itt_group_suppress, "suppress" }, \ - { __itt_group_arrays, "arrays" }, \ - { __itt_group_none, NULL } \ - } - -#endif /* _ITTNOTIFY_TYPES_H_ */ diff --git a/ext/opcache/jit/vtune/jitprofiling.c b/ext/opcache/jit/vtune/jitprofiling.c deleted file mode 100644 index 3154611fec620..0000000000000 --- a/ext/opcache/jit/vtune/jitprofiling.c +++ /dev/null @@ -1,312 +0,0 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - 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. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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 "ittnotify_config.h" - -#if ITT_PLATFORM==ITT_PLATFORM_WIN -#include -#pragma optimize("", off) -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ -#include - -#include "jitprofiling.h" - -static const char rcsid[] = "\n@(#) $Revision: 463960 $\n"; - -#define DLL_ENVIRONMENT_VAR "VS_PROFILER" - -#ifndef NEW_DLL_ENVIRONMENT_VAR -#if ITT_ARCH==ITT_ARCH_IA32 -#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER32" -#else -#define NEW_DLL_ENVIRONMENT_VAR "INTEL_JIT_PROFILER64" -#endif -#endif /* NEW_DLL_ENVIRONMENT_VAR */ - -#if ITT_PLATFORM==ITT_PLATFORM_WIN -#define DEFAULT_DLLNAME "JitPI.dll" -HINSTANCE m_libHandle = NULL; -#elif ITT_PLATFORM==ITT_PLATFORM_MAC -#define DEFAULT_DLLNAME "libJitPI.dylib" -void* m_libHandle = NULL; -#else -#define DEFAULT_DLLNAME "libJitPI.so" -void* m_libHandle = NULL; -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - -/* default location of JIT profiling agent on Android */ -#define ANDROID_JIT_AGENT_PATH "/data/intel/libittnotify.so" - -/* the function pointers */ -typedef unsigned int(JITAPI *TPInitialize)(void); -static TPInitialize FUNC_Initialize=NULL; - -typedef unsigned int(JITAPI *TPNotify)(unsigned int, void*); -static TPNotify FUNC_NotifyEvent=NULL; - -static iJIT_IsProfilingActiveFlags executionMode = iJIT_NOTHING_RUNNING; - -/* end collector dll part. */ - -/* loadiJIT_Funcs() : this function is called just in the beginning - * and is responsible to load the functions from BistroJavaCollector.dll - * result: - * on success: the functions loads, iJIT_DLL_is_missing=0, return value = 1 - * on failure: the functions are NULL, iJIT_DLL_is_missing=1, return value = 0 - */ -static int loadiJIT_Funcs(void); - -/* global representing whether the collector can't be loaded */ -static int iJIT_DLL_is_missing = 0; - -ITT_EXTERN_C int JITAPI -iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData) -{ - int ReturnValue; - - /* initialization part - the collector has not been loaded yet. */ - if (!FUNC_NotifyEvent) - { - if (iJIT_DLL_is_missing) - return 0; - - if (!loadiJIT_Funcs()) - return 0; - } - - if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED || - event_type == iJVM_EVENT_TYPE_METHOD_UPDATE) - { - if (((piJIT_Method_Load)EventSpecificData)->method_id == 0) - return 0; - } - else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2) - { - if (((piJIT_Method_Load_V2)EventSpecificData)->method_id == 0) - return 0; - } - else if (event_type == iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3) - { - if (((piJIT_Method_Load_V3)EventSpecificData)->method_id == 0) - return 0; - } - else if (event_type == iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED) - { - if (((piJIT_Method_Inline_Load)EventSpecificData)->method_id == 0 || - ((piJIT_Method_Inline_Load)EventSpecificData)->parent_method_id == 0) - return 0; - } - - ReturnValue = (int)FUNC_NotifyEvent(event_type, EventSpecificData); - - return ReturnValue; -} - -ITT_EXTERN_C iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void) -{ - if (!iJIT_DLL_is_missing) - { - loadiJIT_Funcs(); - } - - return executionMode; -} - -/* This function loads the collector dll and the relevant functions. - * on success: all functions load, iJIT_DLL_is_missing = 0, return value = 1 - * on failure: all functions are NULL, iJIT_DLL_is_missing = 1, return value = 0 - */ -static int loadiJIT_Funcs(void) -{ - static int bDllWasLoaded = 0; - char *dllName = (char*)rcsid; /* !! Just to avoid unused code elimination */ -#if ITT_PLATFORM==ITT_PLATFORM_WIN - DWORD dNameLength = 0; -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - - if(bDllWasLoaded) - { - /* dll was already loaded, no need to do it for the second time */ - return 1; - } - - /* Assumes that the DLL will not be found */ - iJIT_DLL_is_missing = 1; - FUNC_NotifyEvent = NULL; - - if (m_libHandle) - { -#if ITT_PLATFORM==ITT_PLATFORM_WIN - FreeLibrary(m_libHandle); -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - dlclose(m_libHandle); -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - m_libHandle = NULL; - } - - /* Try to get the dll name from the environment */ -#if ITT_PLATFORM==ITT_PLATFORM_WIN - dNameLength = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, NULL, 0); - if (dNameLength) - { - DWORD envret = 0; - dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); - if(dllName != NULL) - { - envret = GetEnvironmentVariableA(NEW_DLL_ENVIRONMENT_VAR, - dllName, dNameLength); - if (envret) - { - /* Try to load the dll from the PATH... */ - m_libHandle = LoadLibraryExA(dllName, - NULL, LOAD_WITH_ALTERED_SEARCH_PATH); - } - free(dllName); - } - } else { - /* Try to use old VS_PROFILER variable */ - dNameLength = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, NULL, 0); - if (dNameLength) - { - DWORD envret = 0; - dllName = (char*)malloc(sizeof(char) * (dNameLength + 1)); - if(dllName != NULL) - { - envret = GetEnvironmentVariableA(DLL_ENVIRONMENT_VAR, - dllName, dNameLength); - if (envret) - { - /* Try to load the dll from the PATH... */ - m_libHandle = LoadLibraryA(dllName); - } - free(dllName); - } - } - } -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - dllName = getenv(NEW_DLL_ENVIRONMENT_VAR); - if (!dllName) - dllName = getenv(DLL_ENVIRONMENT_VAR); -#if defined(__ANDROID__) || defined(ANDROID) - if (!dllName) - dllName = ANDROID_JIT_AGENT_PATH; -#endif - if (dllName) - { - /* Try to load the dll from the PATH... */ - m_libHandle = dlopen(dllName, RTLD_LAZY); - } -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - - if (!m_libHandle) - { -#if ITT_PLATFORM==ITT_PLATFORM_WIN - m_libHandle = LoadLibraryA(DEFAULT_DLLNAME); -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - m_libHandle = dlopen(DEFAULT_DLLNAME, RTLD_LAZY); -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - } - - /* if the dll wasn't loaded - exit. */ - if (!m_libHandle) - { - iJIT_DLL_is_missing = 1; /* don't try to initialize - * JIT agent the second time - */ - return 0; - } - -#if ITT_PLATFORM==ITT_PLATFORM_WIN - FUNC_NotifyEvent = (TPNotify)GetProcAddress(m_libHandle, "NotifyEvent"); -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - FUNC_NotifyEvent = (TPNotify)dlsym(m_libHandle, "NotifyEvent"); -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - if (!FUNC_NotifyEvent) - { - FUNC_Initialize = NULL; - return 0; - } - -#if ITT_PLATFORM==ITT_PLATFORM_WIN - FUNC_Initialize = (TPInitialize)GetProcAddress(m_libHandle, "Initialize"); -#else /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - FUNC_Initialize = (TPInitialize)dlsym(m_libHandle, "Initialize"); -#endif /* ITT_PLATFORM==ITT_PLATFORM_WIN */ - if (!FUNC_Initialize) - { - FUNC_NotifyEvent = NULL; - return 0; - } - - executionMode = (iJIT_IsProfilingActiveFlags)FUNC_Initialize(); - - bDllWasLoaded = 1; - iJIT_DLL_is_missing = 0; /* DLL is ok. */ - - return 1; -} - -ITT_EXTERN_C unsigned int JITAPI iJIT_GetNewMethodID(void) -{ - static unsigned int methodID = 1; - - if (methodID == 0) - return 0; /* ERROR : this is not a valid value */ - - return methodID++; -} diff --git a/ext/opcache/jit/vtune/jitprofiling.h b/ext/opcache/jit/vtune/jitprofiling.h deleted file mode 100644 index 21d23f8ec7d99..0000000000000 --- a/ext/opcache/jit/vtune/jitprofiling.h +++ /dev/null @@ -1,694 +0,0 @@ -/* - This file is provided under a dual BSD/GPLv2 license. When using or - redistributing this file, you may do so under either license. - - GPL LICENSE SUMMARY - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - - This program is free software; you can redistribute it and/or modify - it under the terms of version 2 of the GNU General Public License as - published by the Free Software Foundation. - - This program is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA. - The full GNU General Public License is included in this distribution - in the file called LICENSE.GPL. - - Contact Information: - http://software.intel.com/en-us/articles/intel-vtune-amplifier-xe/ - - BSD LICENSE - - Copyright (c) 2005-2014 Intel Corporation. All rights reserved. - 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. - * Neither the name of Intel Corporation nor the names of its - contributors may be used to endorse or promote products derived - from this software without specific prior written permission. - - 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 __JITPROFILING_H__ -#define __JITPROFILING_H__ - -/** - * @brief JIT Profiling APIs - * - * The JIT Profiling API is used to report information about just-in-time - * generated code that can be used by performance tools. The user inserts - * calls in the code generator to report information before JIT-compiled - * code goes to execution. This information is collected at runtime and used - * by tools like Intel(R) VTune(TM) Amplifier to display performance metrics - * associated with JIT-compiled code. - * - * These APIs can be used to\n - * - **Profile trace-based and method-based JIT-compiled - * code**. Some examples of environments that you can profile with these APIs: - * dynamic JIT compilation of JavaScript code traces, JIT execution in OpenCL(TM) - * software technology, Java/.NET managed execution environments, and custom - * ISV JIT engines. - * @code - * #include - * - * if (iJIT_IsProfilingActive != iJIT_SAMPLING_ON) { - * return; - * } - * - * iJIT_Method_Load jmethod = {0}; - * jmethod.method_id = iJIT_GetNewMethodID(); - * jmethod.method_name = "method_name"; - * jmethod.class_file_name = "class_name"; - * jmethod.source_file_name = "source_file_name"; - * jmethod.method_load_address = code_addr; - * jmethod.method_size = code_size; - * - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&jmethod); - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_SHUTDOWN, NULL); - * @endcode - * - * * Expected behavior: - * * If any iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an - * already reported method, then such a method becomes invalid and its - * memory region is treated as unloaded. VTune Amplifier displays the metrics - * collected by the method until it is overwritten. - * * If supplied line number information contains multiple source lines for - * the same assembly instruction (code location), then VTune Amplifier picks up - * the first line number. - * * Dynamically generated code can be associated with a module name. - * Use the iJIT_Method_Load_V2 structure.\n - * Clarification of some cases: - * * If you register a function with the same method ID multiple times, - * specifying different module names, then the VTune Amplifier picks up - * the module name registered first. If you want to distinguish the same - * function between different JIT engines, supply different method IDs for - * each function. Other symbolic information (for example, source file) - * can be identical. - * - * - **Analyze split functions** (multiple joint or disjoint code regions - * belonging to the same function) **including re-JIT** - * with potential overlapping of code regions in time, which is common in - * resource-limited environments. - * @code - * #include - * - * unsigned int method_id = iJIT_GetNewMethodID(); - * - * iJIT_Method_Load a = {0}; - * a.method_id = method_id; - * a.method_load_address = 0x100; - * a.method_size = 0x20; - * - * iJIT_Method_Load b = {0}; - * b.method_id = method_id; - * b.method_load_address = 0x200; - * b.method_size = 0x30; - * - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a); - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&b); - * @endcode - * - * * Expected behaviour: - * * If a iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED event overwrites an - * already reported method, then such a method becomes invalid and - * its memory region is treated as unloaded. - * * All code regions reported with the same method ID are considered as - * belonging to the same method. Symbolic information (method name, - * source file name) will be taken from the first notification, and all - * subsequent notifications with the same method ID will be processed - * only for line number table information. So, the VTune Amplifier will map - * samples to a source line using the line number table from the current - * notification while taking the source file name from the very first one.\n - * Clarification of some cases:\n - * * If you register a second code region with a different source file - * name and the same method ID, then this information will be saved and - * will not be considered as an extension of the first code region, but - * VTune Amplifier will use the source file of the first code region and map - * performance metrics incorrectly. - * * If you register a second code region with the same source file as - * for the first region and the same method ID, then the source file will be - * discarded but VTune Amplifier will map metrics to the source file correctly. - * * If you register a second code region with a null source file and - * the same method ID, then provided line number info will be associated - * with the source file of the first code region. - * - * - **Explore inline functions** including multi-level hierarchy of - * nested inline methods which shows how performance metrics are distributed through them. - * @code - * #include - * - * // method_id parent_id - * // [-- c --] 3000 2000 - * // [---- d -----] 2001 1000 - * // [---- b ----] 2000 1000 - * // [------------ a ----------------] 1000 n/a - * - * iJIT_Method_Load a = {0}; - * a.method_id = 1000; - * - * iJIT_Method_Inline_Load b = {0}; - * b.method_id = 2000; - * b.parent_method_id = 1000; - * - * iJIT_Method_Inline_Load c = {0}; - * c.method_id = 3000; - * c.parent_method_id = 2000; - * - * iJIT_Method_Inline_Load d = {0}; - * d.method_id = 2001; - * d.parent_method_id = 1000; - * - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED, (void*)&a); - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&b); - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&c); - * iJIT_NotifyEvent(iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, (void*)&d); - * @endcode - * - * * Requirements: - * * Each inline (iJIT_Method_Inline_Load) method should be associated - * with two method IDs: one for itself; one for its immediate parent. - * * Address regions of inline methods of the same parent method cannot - * overlap each other. - * * Execution of the parent method must not be started until it and all - * its inline methods are reported. - * * Expected behaviour: - * * In case of nested inline methods an order of - * iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED events is not important. - * * If any event overwrites either inline method or top parent method, - * then the parent, including inline methods, becomes invalid and its memory - * region is treated as unloaded. - * - * **Life time of allocated data**\n - * The client sends an event notification to the agent with event-specific - * data, which is a structure. The pointers in the structure refer to memory - * allocated by the client, which responsible for releasing it. The pointers are - * used by the iJIT_NotifyEvent method to copy client's data in a trace file, - * and they are not used after the iJIT_NotifyEvent method returns. - */ - -/** - * @defgroup jitapi JIT Profiling - * @ingroup internal - * @{ - */ - -/** - * @brief Enumerator for the types of notifications - */ -typedef enum iJIT_jvm_event -{ - iJVM_EVENT_TYPE_SHUTDOWN = 2, /**<\brief Send this to shutdown the agent. - * Use NULL for event data. */ - - iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED = 13, /**<\brief Send when dynamic code is - * JIT compiled and loaded into - * memory by the JIT engine, but - * before the code is executed. - * Use iJIT_Method_Load as event - * data. */ -/** @cond exclude_from_documentation */ - iJVM_EVENT_TYPE_METHOD_UNLOAD_START, /**<\brief Send when compiled dynamic - * code is being unloaded from memory. - * Use iJIT_Method_Load as event data.*/ -/** @endcond */ - - iJVM_EVENT_TYPE_METHOD_UPDATE, /**<\brief Send to provide new content for - * a previously reported dynamic code. - * The previous content will be invalidated - * starting from the time of the notification. - * Use iJIT_Method_Load as event data but - * required fields are following: - * - method_id identify the code to update. - * - method_load_address specify start address - * within identified code range - * where update should be started. - * - method_size specify length of updated code - * range. */ - - - iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED, /**<\brief Send when an inline dynamic - * code is JIT compiled and loaded - * into memory by the JIT engine, - * but before the parent code region - * starts executing. - * Use iJIT_Method_Inline_Load as event data.*/ - -/** @cond exclude_from_documentation */ - iJVM_EVENT_TYPE_METHOD_UPDATE_V2, -/** @endcond */ - - iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2 = 21, /**<\brief Send when a dynamic code is - * JIT compiled and loaded into - * memory by the JIT engine, but - * before the code is executed. - * Use iJIT_Method_Load_V2 as event data. */ - - iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3 /**<\brief Send when a dynamic code is - * JIT compiled and loaded into - * memory by the JIT engine, but - * before the code is executed. - * Use iJIT_Method_Load_V3 as event data. */ -} iJIT_JVM_EVENT; - -/** - * @brief Enumerator for the agent's mode - */ -typedef enum _iJIT_IsProfilingActiveFlags -{ - iJIT_NOTHING_RUNNING = 0x0000, /**<\brief The agent is not running; - * iJIT_NotifyEvent calls will - * not be processed. */ - iJIT_SAMPLING_ON = 0x0001, /**<\brief The agent is running and - * ready to process notifications. */ -} iJIT_IsProfilingActiveFlags; - -/** - * @brief Description of a single entry in the line number information of a code region. - * @details A table of line number entries gives information about how the reported code region - * is mapped to source file. - * Intel(R) VTune(TM) Amplifier uses line number information to attribute - * the samples (virtual address) to a line number. \n - * It is acceptable to report different code addresses for the same source line: - * @code - * Offset LineNumber - * 1 2 - * 12 4 - * 15 2 - * 18 1 - * 21 30 - * - * VTune Amplifier constructs the following table using the client data - * - * Code subrange Line number - * 0-1 2 - * 1-12 4 - * 12-15 2 - * 15-18 1 - * 18-21 30 - * @endcode - */ -typedef struct _LineNumberInfo -{ - unsigned int Offset; /**<\brief Offset from the beginning of the code region. */ - unsigned int LineNumber; /**<\brief Matching source line number offset (from beginning of source file). */ - -} *pLineNumberInfo, LineNumberInfo; - -/** - * @brief Enumerator for the code architecture. - */ -typedef enum _iJIT_CodeArchitecture -{ - iJIT_CA_NATIVE = 0, /**<\brief Native to the process architecture that is calling it. */ - - iJIT_CA_32, /**<\brief 32-bit machine code. */ - - iJIT_CA_64 /**<\brief 64-bit machine code. */ - -} iJIT_CodeArchitecture; - -#pragma pack(push, 8) - -/** - * @brief Description of a JIT-compiled method - * @details When you use the iJIT_Method_Load structure to describe - * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED - * as an event type to report it. - */ -typedef struct _iJIT_Method_Load -{ - unsigned int method_id; /**<\brief Unique method ID. Cannot be 0. - * You must either use the API function - * iJIT_GetNewMethodID to get a valid and unique - * method ID, or else manage ID uniqueness - * and correct range by yourself.\n - * You must use the same method ID for all code - * regions of the same method, otherwise different - * method IDs specify different methods. */ - - char* method_name; /**<\brief The name of the method. It can be optionally - * prefixed with its class name and appended with - * its complete signature. Can't be NULL. */ - - void* method_load_address; /**<\brief The start virtual address of the method code - * region. If NULL, data provided with - * event are not accepted. */ - - unsigned int method_size; /**<\brief The code size of the method in memory. - * If 0, then data provided with the event are not - * accepted. */ - - unsigned int line_number_size; /**<\brief The number of entries in the line number - * table.0 if none. */ - - pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info - * array. Can be NULL if - * line_number_size is 0. See - * LineNumberInfo Structure for a - * description of a single entry in - * the line number info array */ - - unsigned int class_id; /**<\brief This field is obsolete. */ - - char* class_file_name; /**<\brief Class name. Can be NULL.*/ - - char* source_file_name; /**<\brief Source file name. Can be NULL.*/ - -} *piJIT_Method_Load, iJIT_Method_Load; - -/** - * @brief Description of a JIT-compiled method - * @details When you use the iJIT_Method_Load_V2 structure to describe - * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V2 - * as an event type to report it. - */ -typedef struct _iJIT_Method_Load_V2 -{ - unsigned int method_id; /**<\brief Unique method ID. Cannot be 0. - * You must either use the API function - * iJIT_GetNewMethodID to get a valid and unique - * method ID, or else manage ID uniqueness - * and correct range by yourself.\n - * You must use the same method ID for all code - * regions of the same method, otherwise different - * method IDs specify different methods. */ - - char* method_name; /**<\brief The name of the method. It can be optionally - * prefixed with its class name and appended with - * its complete signature. Can't be NULL. */ - - void* method_load_address; /**<\brief The start virtual address of the method code - * region. If NULL, then data provided with the - * event are not accepted. */ - - unsigned int method_size; /**<\brief The code size of the method in memory. - * If 0, then data provided with the event are not - * accepted. */ - - unsigned int line_number_size; /**<\brief The number of entries in the line number - * table. 0 if none. */ - - pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info - * array. Can be NULL if - * line_number_size is 0. See - * LineNumberInfo Structure for a - * description of a single entry in - * the line number info array. */ - - char* class_file_name; /**<\brief Class name. Can be NULL. */ - - char* source_file_name; /**<\brief Source file name. Can be NULL. */ - - char* module_name; /**<\brief Module name. Can be NULL. - The module name can be useful for distinguishing among - different JIT engines. VTune Amplifier will display - reported methods grouped by specific module. */ - -} *piJIT_Method_Load_V2, iJIT_Method_Load_V2; - -/** - * @brief Description of a JIT-compiled method - * @details The iJIT_Method_Load_V3 structure is the same as iJIT_Method_Load_V2 - * with a newly introduced 'arch' field that specifies architecture of the code region. - * When you use the iJIT_Method_Load_V3 structure to describe - * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_LOAD_FINISHED_V3 - * as an event type to report it. - */ -typedef struct _iJIT_Method_Load_V3 -{ - unsigned int method_id; /**<\brief Unique method ID. Cannot be 0. - * You must either use the API function - * iJIT_GetNewMethodID to get a valid and unique - * method ID, or manage ID uniqueness - * and correct range by yourself.\n - * You must use the same method ID for all code - * regions of the same method, otherwise they are - * treated as regions of different methods. */ - - char* method_name; /**<\brief The name of the method. It can be optionally - * prefixed with its class name and appended with - * its complete signature. Cannot be NULL. */ - - void* method_load_address; /**<\brief The start virtual address of the method code - * region. If NULL, then data provided with the - * event are not accepted. */ - - unsigned int method_size; /**<\brief The code size of the method in memory. - * If 0, then data provided with the event are not - * accepted. */ - - unsigned int line_number_size; /**<\brief The number of entries in the line number - * table. 0 if none. */ - - pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info - * array. Can be NULL if - * line_number_size is 0. See - * LineNumberInfo Structure for a - * description of a single entry in - * the line number info array. */ - - char* class_file_name; /**<\brief Class name. Can be NULL. */ - - char* source_file_name; /**<\brief Source file name. Can be NULL. */ - - char* module_name; /**<\brief Module name. Can be NULL. - * The module name can be useful for distinguishing among - * different JIT engines. VTune Amplifier will display - * reported methods grouped by specific module. */ - - iJIT_CodeArchitecture module_arch; /**<\brief Architecture of the method's code region. - * By default, it is the same as the process - * architecture that is calling it. - * For example, you can use it if your 32-bit JIT - * engine generates 64-bit code. - * - * If JIT engine reports both 32-bit and 64-bit types - * of methods then VTune Amplifier splits the methods - * with the same module name but with different - * architectures in two different modules. VTune Amplifier - * modifies the original name provided with a 64-bit method - * version by ending it with '(64)' */ - -} *piJIT_Method_Load_V3, iJIT_Method_Load_V3; - -/** - * @brief Description of an inline JIT-compiled method - * @details When you use the_iJIT_Method_Inline_Load structure to describe - * the JIT compiled method, use iJVM_EVENT_TYPE_METHOD_INLINE_LOAD_FINISHED - * as an event type to report it. - */ -typedef struct _iJIT_Method_Inline_Load -{ - unsigned int method_id; /**<\brief Unique method ID. Cannot be 0. - * You must either use the API function - * iJIT_GetNewMethodID to get a valid and unique - * method ID, or else manage ID uniqueness - * and correct range by yourself. */ - - unsigned int parent_method_id; /**<\brief Unique immediate parent's method ID. - * Cannot be 0. - * You must either use the API function - * iJIT_GetNewMethodID to get a valid and unique - * method ID, or else manage ID uniqueness - * and correct range by yourself. */ - - char* method_name; /**<\brief The name of the method. It can be optionally - * prefixed with its class name and appended with - * its complete signature. Can't be NULL. */ - - void* method_load_address; /** <\brief The virtual address on which the method - * is inlined. If NULL, then data provided with - * the event are not accepted. */ - - unsigned int method_size; /**<\brief The code size of the method in memory. - * If 0, then data provided with the event are not - * accepted. */ - - unsigned int line_number_size; /**<\brief The number of entries in the line number - * table. 0 if none. */ - - pLineNumberInfo line_number_table; /**<\brief Pointer to the line numbers info - * array. Can be NULL if - * line_number_size is 0. See - * LineNumberInfo Structure for a - * description of a single entry in - * the line number info array */ - - char* class_file_name; /**<\brief Class name. Can be NULL.*/ - - char* source_file_name; /**<\brief Source file name. Can be NULL.*/ - -} *piJIT_Method_Inline_Load, iJIT_Method_Inline_Load; - -/** @cond exclude_from_documentation */ -/** - * @brief Description of a segment type - * @details Use the segment type to specify a type of data supplied - * with the iJVM_EVENT_TYPE_METHOD_UPDATE_V2 event to be applied to - * a certain code trace. - */ -typedef enum _iJIT_SegmentType -{ - iJIT_CT_UNKNOWN = 0, - - iJIT_CT_CODE, /**<\brief Executable code. */ - - iJIT_CT_DATA, /**<\brief Data (not executable code). - * VTune Amplifier uses the format string - * (see iJIT_Method_Update) to represent - * this data in the VTune Amplifier GUI */ - - iJIT_CT_KEEP, /**<\brief Use the previous markup for the trace. - * Can be used for the following - * iJVM_EVENT_TYPE_METHOD_UPDATE_V2 events, - * if the type of the previously reported segment - * type is the same. */ - iJIT_CT_EOF -} iJIT_SegmentType; - -/** - * @brief Description of a dynamic update of the content within JIT-compiled method - * @details The JIT engine may generate the methods that are updated at runtime - * partially by mixed (data + executable code) content. When you use the iJIT_Method_Update - * structure to describe the update of the content within a JIT-compiled method, - * use iJVM_EVENT_TYPE_METHOD_UPDATE_V2 as an event type to report it. - * - * On the first Update event, VTune Amplifier copies the original code range reported by - * the iJVM_EVENT_TYPE_METHOD_LOAD event, then modifies it with the supplied bytes and - * adds the modified range to the original method. For next update events, VTune Amplifier - * does the same but it uses the latest modified version of a code region for update. - * Eventually, VTune Amplifier GUI displays multiple code ranges for the method reported by - * the iJVM_EVENT_TYPE_METHOD_LOAD event. - * Notes: - * - Multiple update events with different types for the same trace are allowed - * but they must be reported for the same code ranges. - * Example, - * @code - * [-- data---] Allowed - * [-- code --] Allowed - * [code] Ignored - * [-- data---] Allowed - * [-- code --] Allowed - * [------------ trace ---------] - * @endcode - * - The types of previously reported events can be changed but they must be reported - * for the same code ranges. - * Example, - * @code - * [-- data---] Allowed - * [-- code --] Allowed - * [-- data---] Allowed - * [-- code --] Allowed - * [------------ trace ---------] - * @endcode - */ - -typedef struct _iJIT_Method_Update -{ - void* load_address; /**<\brief Start address of the update within a method */ - - unsigned int size; /**<\brief The update size */ - - iJIT_SegmentType type; /**<\brief Type of the update */ - - const char* data_format; /**<\brief C string that contains a format string - * that follows the same specifications as format in printf. - * The format string is used for iJIT_CT_CODE only - * and cannot be NULL. - * Format can be changed on the fly. */ -} *piJIT_Method_Update, iJIT_Method_Update; - -/** @endcond */ - -#pragma pack(pop) - -/** @cond exclude_from_documentation */ -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifndef JITAPI_CDECL -# if defined WIN32 || defined _WIN32 -# define JITAPI_CDECL __cdecl -# else /* defined WIN32 || defined _WIN32 */ -# if defined _M_IX86 || defined __i386__ -# define JITAPI_CDECL __attribute__ ((cdecl)) -# else /* _M_IX86 || __i386__ */ -# define JITAPI_CDECL /* actual only on x86_64 platform */ -# endif /* _M_IX86 || __i386__ */ -# endif /* defined WIN32 || defined _WIN32 */ -#endif /* JITAPI_CDECL */ - -#define JITAPI JITAPI_CDECL -/** @endcond */ - -/** - * @brief Generates a new unique method ID. - * - * You must use this API to obtain unique and valid method IDs for methods or - * traces reported to the agent if you don't have your own mechanism to generate - * unique method IDs. - * - * @return a new unique method ID. When out of unique method IDs, this API - * returns 0, which is not an accepted value. - */ -unsigned int JITAPI iJIT_GetNewMethodID(void); - -/** - * @brief Returns the current mode of the agent. - * - * @return iJIT_SAMPLING_ON, indicating that agent is running, or - * iJIT_NOTHING_RUNNING if no agent is running. - */ -iJIT_IsProfilingActiveFlags JITAPI iJIT_IsProfilingActive(void); - -/** - * @brief Reports information about JIT-compiled code to the agent. - * - * The reported information is used to attribute samples obtained from any - * Intel(R) VTune(TM) Amplifier collector. This API needs to be called - * after JIT compilation and before the first entry into the JIT-compiled - * code. - * - * @param[in] event_type - type of the data sent to the agent - * @param[in] EventSpecificData - pointer to event-specific data - * - * @returns 1 on success, otherwise 0. - */ -int JITAPI iJIT_NotifyEvent(iJIT_JVM_EVENT event_type, void *EventSpecificData); - -#ifdef __cplusplus -} -#endif /* __cplusplus */ -/** @endcond */ - -/** @} jitapi group */ - -#endif /* __JITPROFILING_H__ */ diff --git a/ext/opcache/jit/zend_elf.c b/ext/opcache/jit/zend_elf.c deleted file mode 100644 index 5327a28806048..0000000000000 --- a/ext/opcache/jit/zend_elf.c +++ /dev/null @@ -1,121 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Xinchen Hui | - +----------------------------------------------------------------------+ -*/ - -#include -#include -#if defined(__FreeBSD__) || defined(__DragonFly__) -#include -#elif defined(__HAIKU__) -#include -#endif -#include -#include - -#include "zend_API.h" -#include "zend_elf.h" - -static void* zend_elf_read_sect(int fd, zend_elf_sectheader *sect) -{ - void *s = emalloc(sect->size); - - if (lseek(fd, sect->ofs, SEEK_SET) < 0) { - efree(s); - return NULL; - } - if (read(fd, s, sect->size) != (ssize_t)sect->size) { - efree(s); - return NULL; - } - - return s; -} - -void zend_elf_load_symbols(void) -{ - zend_elf_header hdr; - zend_elf_sectheader sect; - int i; -#if defined(__linux__) - int fd = open("/proc/self/exe", O_RDONLY); -#elif defined(__NetBSD__) - int fd = open("/proc/curproc/exe", O_RDONLY); -#elif defined(__FreeBSD__) || defined(__DragonFly__) - char path[PATH_MAX]; - size_t pathlen = sizeof(path); - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; - if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) { - return; - } - int fd = open(path, O_RDONLY); -#elif defined(__sun) - int fd = open("/proc/self/path/a.out", O_RDONLY); -#elif defined(__HAIKU__) - char path[PATH_MAX]; - if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, - NULL, path, sizeof(path)) != B_OK) { - return; - } - - int fd = open(path, O_RDONLY); -#else - // To complete eventually for other ELF platforms. - // Otherwise APPLE is Mach-O - int fd = -1; -#endif - - if (fd >= 0) { - if (read(fd, &hdr, sizeof(hdr)) == sizeof(hdr) - && hdr.emagic[0] == '\177' - && hdr.emagic[1] == 'E' - && hdr.emagic[2] == 'L' - && hdr.emagic[3] == 'F' - && lseek(fd, hdr.shofs, SEEK_SET) >= 0) { - for (i = 0; i < hdr.shnum; i++) { - if (read(fd, §, sizeof(sect)) == sizeof(sect) - && sect.type == ELFSECT_TYPE_SYMTAB) { - uint32_t n, count = sect.size / sizeof(zend_elf_symbol); - zend_elf_symbol *syms = zend_elf_read_sect(fd, §); - char *str_tbl; - - if (syms) { - if (lseek(fd, hdr.shofs + sect.link * sizeof(sect), SEEK_SET) >= 0 - && read(fd, §, sizeof(sect)) == sizeof(sect) - && (str_tbl = (char*)zend_elf_read_sect(fd, §)) != NULL) { - for (n = 0; n < count; n++) { - if (syms[n].name - && (ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_FUNC - /*|| ELFSYM_TYPE(syms[n].info) == ELFSYM_TYPE_DATA*/) - && (ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_LOCAL - /*|| ELFSYM_BIND(syms[n].info) == ELFSYM_BIND_GLOBAL*/)) { - zend_jit_disasm_add_symbol(str_tbl + syms[n].name, syms[n].value, syms[n].size); - } - } - efree(str_tbl); - } - efree(syms); - } - if (lseek(fd, hdr.shofs + (i + 1) * sizeof(sect), SEEK_SET) < 0) { - break; - } - } - } - } - close(fd); - } -} diff --git a/ext/opcache/jit/zend_elf.h b/ext/opcache/jit/zend_elf.h deleted file mode 100644 index b850afb279638..0000000000000 --- a/ext/opcache/jit/zend_elf.h +++ /dev/null @@ -1,115 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Xinchen Hui | - +----------------------------------------------------------------------+ -*/ - -#ifndef ZEND_ELF -#define ZEND_ELF - -#if SIZEOF_SIZE_T == 8 -# define ELF64 -#else -# undef ELF64 -#endif - -typedef struct _zend_elf_header { - uint8_t emagic[4]; - uint8_t eclass; - uint8_t eendian; - uint8_t eversion; - uint8_t eosabi; - uint8_t eabiversion; - uint8_t epad[7]; - uint16_t type; - uint16_t machine; - uint32_t version; - uintptr_t entry; - uintptr_t phofs; - uintptr_t shofs; - uint32_t flags; - uint16_t ehsize; - uint16_t phentsize; - uint16_t phnum; - uint16_t shentsize; - uint16_t shnum; - uint16_t shstridx; -} zend_elf_header; - -typedef struct zend_elf_sectheader { - uint32_t name; - uint32_t type; - uintptr_t flags; - uintptr_t addr; - uintptr_t ofs; - uintptr_t size; - uint32_t link; - uint32_t info; - uintptr_t align; - uintptr_t entsize; -} zend_elf_sectheader; - -#define ELFSECT_IDX_ABS 0xfff1 - -enum { - ELFSECT_TYPE_PROGBITS = 1, - ELFSECT_TYPE_SYMTAB = 2, - ELFSECT_TYPE_STRTAB = 3, - ELFSECT_TYPE_NOBITS = 8, - ELFSECT_TYPE_DYNSYM = 11, -}; - -#define ELFSECT_FLAGS_WRITE (1 << 0) -#define ELFSECT_FLAGS_ALLOC (1 << 1) -#define ELFSECT_FLAGS_EXEC (1 << 2) -#define ELFSECT_FLAGS_TLS (1 << 10) - -typedef struct zend_elf_symbol { -#ifdef ELF64 - uint32_t name; - uint8_t info; - uint8_t other; - uint16_t sectidx; - uintptr_t value; - uint64_t size; -#else - uint32_t name; - uintptr_t value; - uint32_t size; - uint8_t info; - uint8_t other; - uint16_t sectidx; -#endif -} zend_elf_symbol; - -#define ELFSYM_BIND(info) ((info) >> 4) -#define ELFSYM_TYPE(info) ((info) & 0xf) -#define ELFSYM_INFO(bind, type) (((bind) << 4) | (type)) - -enum { - ELFSYM_TYPE_DATA = 2, - ELFSYM_TYPE_FUNC = 2, - ELFSYM_TYPE_FILE = 4, -}; - -enum { - ELFSYM_BIND_LOCAL = 0, - ELFSYM_BIND_GLOBAL = 1, -}; - -void zend_elf_load_symbols(void); - -#endif diff --git a/ext/opcache/jit/zend_jit.c b/ext/opcache/jit/zend_jit.c index 02cb0cab7976e..5b45dca51a9e2 100644 --- a/ext/opcache/jit/zend_jit.c +++ b/ext/opcache/jit/zend_jit.c @@ -38,16 +38,7 @@ #include "Optimizer/zend_inference.h" #include "Optimizer/zend_call_graph.h" #include "Optimizer/zend_dump.h" - -#ifndef ZEND_JIT_IR -#if ZEND_JIT_TARGET_X86 -# include "jit/zend_jit_x86.h" -#elif ZEND_JIT_TARGET_ARM64 -# include "jit/zend_jit_arm64.h" -#endif -#else #include "Optimizer/zend_worklist.h" -#endif #include "jit/zend_jit_internal.h" @@ -78,37 +69,6 @@ zend_jit_globals jit_globals; #define JIT_STUB_PREFIX "JIT$$" #define TRACE_PREFIX "TRACE-" -#ifndef ZEND_JIT_IR -#define DASM_M_GROW(ctx, t, p, sz, need) \ - do { \ - size_t _sz = (sz), _need = (need); \ - if (_sz < _need) { \ - if (_sz < 16) _sz = 16; \ - while (_sz < _need) _sz += _sz; \ - (p) = (t *)erealloc((p), _sz); \ - (sz) = _sz; \ - } \ - } while(0) - -#define DASM_M_FREE(ctx, p, sz) efree(p) - -#if ZEND_DEBUG -# define DASM_CHECKS 1 -#endif - -#include "dynasm/dasm_proto.h" - -typedef struct _zend_jit_stub { - const char *name; - int (*stub)(dasm_State **Dst); - uint32_t offset; - uint32_t adjustment; -} zend_jit_stub; - -#define JIT_STUB(name, offset, adjustment) \ - {JIT_STUB_PREFIX #name, zend_jit_ ## name ## _stub, offset, adjustment} -#endif /* ZEND_JIT_IR */ - zend_ulong zend_jit_profile_counter = 0; int zend_jit_profile_counter_rid = -1; @@ -147,50 +107,6 @@ static zend_string *zend_jit_func_name(const zend_op_array *op_array); static bool zend_jit_needs_arg_dtor(const zend_function *func, uint32_t arg_num, zend_call_info *call_info); -#ifndef ZEND_JIT_IR -#if ZEND_JIT_TARGET_ARM64 -static zend_jit_trace_info *zend_jit_get_current_trace_info(void); -static uint32_t zend_jit_trace_find_exit_point(const void* addr); -#endif - -#if ZEND_JIT_TARGET_X86 && defined(__linux__) -# if PHP_HAVE_BUILTIN_CPU_SUPPORTS && defined(__GNUC__) && (ZEND_GCC_VERSION >= 11000) -# define ZEND_JIT_SUPPORT_CLDEMOTE 1 -# else -# define ZEND_JIT_SUPPORT_CLDEMOTE 0 -# endif -#endif - -#if ZEND_JIT_SUPPORT_CLDEMOTE -#include -#pragma GCC push_options -#pragma GCC target("cldemote") -// check cldemote by CPUID when JIT startup -static int cpu_support_cldemote = 0; -static inline void shared_cacheline_demote(uintptr_t start, size_t size) { - uintptr_t cache_line_base = start & ~0x3F; - do { - _cldemote((void *)cache_line_base); - // next cacheline start size - cache_line_base += 64; - } while (cache_line_base < start + size); -} -#pragma GCC pop_options -#endif - -static int zend_jit_assign_to_variable(dasm_State **Dst, - const zend_op *opline, - zend_jit_addr var_use_addr, - zend_jit_addr var_addr, - uint32_t var_info, - uint32_t var_def_info, - uint8_t val_type, - zend_jit_addr val_addr, - uint32_t val_info, - zend_jit_addr res_addr, - bool check_exception); -#endif /* ZEND_JIT_IR */ - static bool dominates(const zend_basic_block *blocks, int a, int b) { while (blocks[b].level > blocks[a].level) { b = blocks[b].idom; @@ -248,31 +164,6 @@ static bool zend_ssa_is_last_use(const zend_op_array *op_array, const zend_ssa * return 0; } -#ifndef ZEND_JIT_IR -static bool zend_ival_is_last_use(const zend_lifetime_interval *ival, int use) -{ - if (ival->flags & ZREG_LAST_USE) { - const zend_life_range *range = &ival->range; - - while (range->next) { - range = range->next; - } - return range->end == use; - } - return 0; -} - -static bool zend_is_commutative(uint8_t opcode) -{ - return - opcode == ZEND_ADD || - opcode == ZEND_MUL || - opcode == ZEND_BW_OR || - opcode == ZEND_BW_AND || - opcode == ZEND_BW_XOR; -} -#endif - static int zend_jit_is_constant_cmp_long_long(const zend_op *opline, zend_ssa_range *op1_range, zend_jit_addr op1_addr, @@ -761,32 +652,8 @@ static bool zend_may_be_dynamic_property(zend_class_entry *ce, zend_string *memb #define OP2_RANGE() OP_RANGE(ssa_op, op2) #define OP1_DATA_RANGE() OP_RANGE(ssa_op + 1, op1) -#ifndef ZEND_JIT_IR -#if ZEND_JIT_TARGET_X86 -# include "dynasm/dasm_x86.h" -#elif ZEND_JIT_TARGET_ARM64 -static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset); -# define DASM_ADD_VENEER zend_jit_add_veneer -# include "dynasm/dasm_arm64.h" -#endif - -#include "jit/zend_jit_helpers.c" -#include "jit/zend_jit_disasm.c" -#ifndef _WIN32 -# include "jit/zend_jit_gdb.h" -# include "jit/zend_jit_perf_dump.c" -#endif - -#include "Zend/zend_cpuinfo.h" - -#ifdef HAVE_VALGRIND -# include -#endif - -#else /* ZEND_JIT_IR */ #include "jit/zend_jit_helpers.c" #include "Zend/zend_cpuinfo.h" -#endif /* ZEND_JIT_IR */ #ifdef HAVE_GCC_GLOBAL_REGS # define GCC_GLOBAL_REGS 1 @@ -803,19 +670,6 @@ static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int #define BP_JIT_IS 6 /* Used for ISSET_ISEMPTY_DIM_OBJ. see BP_VAR_*defines in Zend/zend_compile.h */ -#ifndef ZEND_JIT_IR -typedef enum _sp_adj_kind { - SP_ADJ_NONE, - SP_ADJ_RET, - SP_ADJ_VM, - SP_ADJ_JIT, - SP_ADJ_ASSIGN, - SP_ADJ_LAST -} sp_adj_kind; - -static int sp_adj[SP_ADJ_LAST]; -#endif - /* The generated code may contain tautological comparisons, ignore them. */ #if defined(__clang__) # pragma clang diagnostic push @@ -823,16 +677,7 @@ static int sp_adj[SP_ADJ_LAST]; # pragma clang diagnostic ignored "-Wstring-compare" #endif -#ifndef ZEND_JIT_IR -#if ZEND_JIT_TARGET_X86 -# include "jit/zend_jit_vtune.c" -# include "jit/zend_jit_x86.c" -#elif ZEND_JIT_TARGET_ARM64 -# include "jit/zend_jit_arm64.c" -#endif -#else #include "jit/zend_jit_ir.c" -#endif #if defined(__clang__) # pragma clang diagnostic pop @@ -895,281 +740,6 @@ static zend_string *zend_jit_func_name(const zend_op_array *op_array) } } -#ifndef ZEND_JIT_IR -#if ZEND_DEBUG -static void handle_dasm_error(int ret) { - switch (ret & 0xff000000u) { - case DASM_S_NOMEM: - fprintf(stderr, "DASM_S_NOMEM\n"); - break; - case DASM_S_PHASE: - fprintf(stderr, "DASM_S_PHASE\n"); - break; - case DASM_S_MATCH_SEC: - fprintf(stderr, "DASM_S_MATCH_SEC\n"); - break; - case DASM_S_RANGE_I: - fprintf(stderr, "DASM_S_RANGE_I\n"); - break; - case DASM_S_RANGE_SEC: - fprintf(stderr, "DASM_S_RANGE_SEC\n"); - break; - case DASM_S_RANGE_LG: - fprintf(stderr, "DASM_S_RANGE_LG\n"); - break; - case DASM_S_RANGE_PC: - fprintf(stderr, "DASM_S_RANGE_PC %d\n", ret & 0xffffffu); - break; -#ifdef DASM_S_RANGE_VREG - case DASM_S_RANGE_VREG: - fprintf(stderr, "DASM_S_RANGE_VREG\n"); - break; -#endif -#ifdef DASM_S_UNDEF_L - case DASM_S_UNDEF_L: - fprintf(stderr, "DASM_S_UNDEF_L\n"); - break; -#endif -#ifdef DASM_S_UNDEF_LG - case DASM_S_UNDEF_LG: - fprintf(stderr, "DASM_S_UNDEF_LG\n"); - break; -#endif -#ifdef DASM_S_RANGE_REL - case DASM_S_RANGE_REL: - fprintf(stderr, "DASM_S_RANGE_REL\n"); - break; -#endif - case DASM_S_UNDEF_PC: - fprintf(stderr, "DASM_S_UNDEF_PC %d\n", ret & 0xffffffu); - break; - default: - fprintf(stderr, "DASM_S_%0x\n", ret & 0xff000000u); - break; - } - ZEND_UNREACHABLE(); -} -#endif - -static void *dasm_link_and_encode(dasm_State **dasm_state, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_op *rt_opline, - zend_lifetime_interval **ra, - const char *name, - uint32_t trace_num, - uint32_t sp_offset, - uint32_t sp_adjustment) -{ - size_t size; - int ret; - void *entry; -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) - zend_string *str = NULL; -#endif - - if (rt_opline && ssa && ssa->cfg.map) { - /* Create additional entry point, to switch from interpreter to JIT-ed - * code at run-time. - */ - int b = ssa->cfg.map[rt_opline - op_array->opcodes]; - -//#ifdef CONTEXT_THREADED_JIT -// if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY))) { -//#else - if (!(ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY))) { -//#endif - zend_jit_label(dasm_state, ssa->cfg.blocks_count + b); - zend_jit_prologue(dasm_state); - if (ra) { - int i; - zend_lifetime_interval *ival; - zend_life_range *range; - uint32_t pos = rt_opline - op_array->opcodes; - - for (i = 0; i < ssa->vars_count; i++) { - ival = ra[i]; - - if (ival && ival->reg != ZREG_NONE) { - range = &ival->range; - - if (pos >= range->start && pos <= range->end) { - if (!zend_jit_load_var(dasm_state, ssa->var_info[i].type, ssa->vars[i].var, ival->reg)) { - return NULL; - } - break; - } - range = range->next; - } - } - } - zend_jit_jmp(dasm_state, b); - } - } - - ret = dasm_link(dasm_state, &size); - if (ret != DASM_S_OK) { -#if ZEND_DEBUG - handle_dasm_error(ret); -#endif - return NULL; - } - - if ((void*)((char*)*dasm_ptr + size) > dasm_end) { - *dasm_ptr = dasm_end; //prevent further try - // TODO: jit_buffer_size overflow ??? - return NULL; - } - -#if ZEND_JIT_TARGET_ARM64 - dasm_venners_size = 0; -#endif - - ret = dasm_encode(dasm_state, *dasm_ptr); - if (ret != DASM_S_OK) { -#if ZEND_DEBUG - handle_dasm_error(ret); -#endif - return NULL; - } - -#if ZEND_JIT_TARGET_ARM64 - size += dasm_venners_size; -#endif - - entry = *dasm_ptr; - *dasm_ptr = (void*)((char*)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(size, DASM_ALIGNMENT)); - - /* flush the hardware I-cache */ - JIT_CACHE_FLUSH(entry, entry + size); - /* hint to the hardware to push out the cache line that contains the linear address */ -#if ZEND_JIT_SUPPORT_CLDEMOTE - if (cpu_support_cldemote && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - shared_cacheline_demote((uintptr_t)entry, size); - } -#endif - - if (trace_num) { - zend_jit_trace_add_code(entry, dasm_getpclabel(dasm_state, 1)); - } - - if (op_array && ssa) { - int b; - - for (b = 0; b < ssa->cfg.blocks_count; b++) { -//#ifdef CONTEXT_THREADED_JIT -// if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) { -//#else - if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) { -//#endif - zend_op *opline = op_array->opcodes + ssa->cfg.blocks[b].start; - int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b); - - if (offset >= 0) { - opline->handler = (void*)(((char*)entry) + offset); - } - } - } - if (rt_opline && ssa && ssa->cfg.map) { - int b = ssa->cfg.map[rt_opline - op_array->opcodes]; - zend_op *opline = (zend_op*)rt_opline; - int offset = dasm_getpclabel(dasm_state, ssa->cfg.blocks_count + b); - - if (offset >= 0) { - opline->handler = (void*)(((char*)entry) + offset); - } - } - } - -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) - if (!name) { - if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_GDB|ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_VTUNE|ZEND_JIT_DEBUG_PERF_DUMP)) { - str = zend_jit_func_name(op_array); - if (str) { - name = ZSTR_VAL(str); - } - } -#ifdef HAVE_DISASM - if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) { - zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size); - zend_jit_disasm( - name, - (op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL, - op_array, - &ssa->cfg, - entry, - size); - } - } else { - if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM_STUBS|ZEND_JIT_DEBUG_ASM)) { - zend_jit_disasm_add_symbol(name, (uintptr_t)entry, size); - if ((JIT_G(debug) & (trace_num ? ZEND_JIT_DEBUG_ASM : ZEND_JIT_DEBUG_ASM_STUBS)) != 0) { - zend_jit_disasm( - name, - (op_array && op_array->filename) ? ZSTR_VAL(op_array->filename) : NULL, - op_array, - ssa ? &ssa->cfg : NULL, - entry, - size); - } - } -# endif - } -#endif - -#ifdef HAVE_GDB - if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) { - if (name) { - zend_jit_gdb_register( - name, - op_array, - entry, - size, - sp_adj[sp_offset], - sp_adj[sp_adjustment]); - } - } -#endif - - -#ifdef HAVE_PERFTOOLS - if (JIT_G(debug) & (ZEND_JIT_DEBUG_PERF|ZEND_JIT_DEBUG_PERF_DUMP)) { - if (name) { - zend_jit_perf_map_register( - name, - entry, - size); - if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) { - zend_jit_perf_jitdump_register( - name, - entry, - size); - } - } - } -#endif - -#ifdef HAVE_VTUNE - if (JIT_G(debug) & ZEND_JIT_DEBUG_VTUNE) { - if (name) { - zend_jit_vtune_register( - name, - entry, - size); - } - } -#endif - -#if defined(HAVE_DISASM) || defined(HAVE_GDB) || defined(HAVE_PERFTOOLS) || defined(HAVE_VTUNE) - if (str) { - zend_string_release(str); - } -#endif - - return entry; -} -#endif /* ZEND_JIT_IR */ - static int zend_may_overflow(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa) { int res; @@ -1376,1331 +946,45 @@ static int zend_jit_op_array_analyze1(const zend_op_array *op_array, zend_script } #endif - /* TODO: move this to zend_cfg.c ? */ - if (!op_array->function_name) { - ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; - } - - if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) - && ssa->cfg.blocks - && op_array->last_try_catch == 0 - && !(op_array->fn_flags & ZEND_ACC_GENERATOR) - && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) { - if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) { - return FAILURE; - } - - zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa); - - zend_ssa_find_false_dependencies(op_array, ssa); - - zend_ssa_find_sccs(op_array, ssa); - } - - return SUCCESS; -} - -static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa, uint32_t optimization_level) -{ - if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) - && ssa->cfg.blocks - && op_array->last_try_catch == 0 - && !(op_array->fn_flags & ZEND_ACC_GENERATOR) - && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) { - if (zend_ssa_inference(&CG(arena), op_array, script, ssa, - optimization_level & ~ZEND_OPTIMIZER_NARROW_TO_DOUBLE) != SUCCESS) { - return FAILURE; - } - } - - return SUCCESS; -} - -#ifndef ZEND_JIT_IR -static int zend_jit_add_range(zend_lifetime_interval **intervals, int var, uint32_t from, uint32_t to) -{ - zend_lifetime_interval *ival = intervals[var]; - - if (!ival) { - ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval)); - if (!ival) { - return FAILURE; - } - ival->ssa_var = var; - ival->reg = ZREG_NONE; - ival->flags = 0; - ival->range.start = from; - ival->range.end = to; - ival->range.next = NULL; - ival->hint = NULL; - ival->used_as_hint = NULL; - intervals[var] = ival; - } else if (ival->range.start > to + 1) { - zend_life_range *range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range)); - - if (!range) { - return FAILURE; - } - range->start = ival->range.start; - range->end = ival->range.end; - range->next = ival->range.next; - ival->range.start = from; - ival->range.end = to; - ival->range.next = range; - } else if (ival->range.start == to + 1) { - ival->range.start = from; - } else { - zend_life_range *range = &ival->range; - zend_life_range *last = NULL; - - do { - if (range->start > to + 1) { - break; - } else if (range->end + 1 >= from) { - if (range->start > from) { - range->start = from; - } - last = range; - range = range->next; - while (range) { - if (range->start > to + 1) { - break; - } - last->end = range->end; - range = range->next; - last->next = range; - } - if (to > last->end) { - last->end = to; - } - return SUCCESS; - } - last = range; - range = range->next; - } while (range); - - range = zend_arena_alloc(&CG(arena), sizeof(zend_life_range)); - if (!range) { - return FAILURE; - } - range->start = from; - range->end = to; - range->next = last->next; - last->next = range; - } - - return SUCCESS; -} - -static int zend_jit_begin_range(zend_lifetime_interval **intervals, int var, uint32_t block_start, uint32_t from) -{ - if (block_start != from && intervals[var]) { - zend_life_range *range = &intervals[var]->range; - - do { - if (from >= range->start && from <= range->end) { - if (range->start == block_start) { - range->start = from; - } else { - zend_life_range *r = zend_arena_alloc(&CG(arena), sizeof(zend_life_range)); - if (!r) { - return FAILURE; - } - r->start = from; - r->end = range->end; - r->next = range->next; - range->end = block_start - 1; - range->next = r; - } - return SUCCESS; - } - range = range->next; - } while (range); - } - - // dead store - return zend_jit_add_range(intervals, var, from, from); -} - -static void zend_jit_insert_interval(zend_lifetime_interval **list, zend_lifetime_interval *ival) -{ - while (1) { - if (*list == NULL) { - *list = ival; - ival->list_next = NULL; - return; - } else if (ival->range.start < (*list)->range.start) { - ival->list_next = *list; - *list = ival; - return; - } - list = &(*list)->list_next; - } -} - -static int zend_jit_split_interval(zend_lifetime_interval *current, uint32_t pos, zend_lifetime_interval **list, zend_lifetime_interval **free) -{ - zend_lifetime_interval *ival; - zend_life_range *range = ¤t->range; - zend_life_range *prev = NULL; - - if (*free) { - ival = *free; - *free = ival->list_next; - } else { - ival = zend_arena_alloc(&CG(arena), sizeof(zend_lifetime_interval)); - - if (!ival) { - return FAILURE; - } - } - - current->flags |= ZREG_STORE; - - ival->ssa_var = current->ssa_var; - ival->reg = ZREG_NONE; - ival->flags |= ZREG_SPLIT | ZREG_LOAD; - ival->flags &= ~ZREG_STORE; - ival->hint = NULL; - - do { - if (pos >= range->start && pos <= range->end) { - break; - } - prev = range; - range = range->next; - } while(range); - - ZEND_ASSERT(range != NULL); - - ival->range.start = pos; - ival->range.end = range->end; - ival->range.next = range->next; - - if (pos == range->start) { - ZEND_ASSERT(prev != NULL); - prev->next = NULL; - } else { - range->end = pos - 1; - } - - zend_jit_insert_interval(list, ival); - - return SUCCESS; -} - -static zend_lifetime_interval *zend_jit_sort_intervals(zend_lifetime_interval **intervals, int count) -{ - zend_lifetime_interval *list, *last; - int i; - - list = NULL; - i = 0; - while (i < count) { - list = intervals[i]; - i++; - if (list) { - last = list; - last->list_next = NULL; - break; - } - } - - while (i < count) { - zend_lifetime_interval *ival = intervals[i]; - - i++; - if (ival) { - if ((ival->range.start > last->range.start) || - (ival->range.start == last->range.start && - ((!ival->hint && last->hint && last->hint != ival) || - ival->range.end > last->range.end))) { - last->list_next = ival; - last = ival; - ival->list_next = NULL; - } else { - zend_lifetime_interval **p = &list; - - while (1) { - if (*p == NULL) { - *p = last = ival; - ival->list_next = NULL; - break; - } else if ((ival->range.start < (*p)->range.start) || - (ival->range.start == (*p)->range.start && - ((ival->hint && !(*p)->hint && ival->hint != *p) || - ival->range.end < (*p)->range.end))) { - ival->list_next = *p; - *p = ival; - break; - } - p = &(*p)->list_next; - } - } - } - } - - return list; -} - -static ZEND_ATTRIBUTE_UNUSED void zend_jit_print_regset(zend_regset regset) -{ - zend_reg reg; - int first = 1; - - ZEND_REGSET_FOREACH(regset, reg) { - if (first) { - first = 0; - fprintf(stderr, "%s", zend_reg_name[reg]); - } else { - fprintf(stderr, ", %s", zend_reg_name[reg]); - } - } ZEND_REGSET_FOREACH_END(); -} - -static int *zend_jit_compute_block_order_int(zend_ssa *ssa, int n, int *block_order) -{ - zend_basic_block *b = ssa->cfg.blocks + n; - -tail_call: - *block_order = n; - block_order++; - - n = b->children; - while (n >= 0) { - b = ssa->cfg.blocks + n; - if (b->next_child < 0) { - goto tail_call; - } - block_order = zend_jit_compute_block_order_int(ssa, n, block_order); - n = b->next_child; - } - - return block_order; -} - -static int zend_jit_compute_block_order(zend_ssa *ssa, int *block_order) -{ - int *end = zend_jit_compute_block_order_int(ssa, 0, block_order); - - return end - block_order; -} - -static bool zend_jit_in_loop(zend_ssa *ssa, int header, zend_basic_block *b) -{ - while (b->loop_header >= 0) { - if (b->loop_header == header) { - return 1; - } - b = ssa->cfg.blocks + b->loop_header; - } - return 0; -} - -static void zend_jit_compute_loop_body(zend_ssa *ssa, int header, int n, zend_bitset loop_body) -{ - zend_basic_block *b = ssa->cfg.blocks + n; - uint32_t i; - -tail_call: - if (b->len) { - for (i = b->start; i < b->start + b->len; i++) { - zend_bitset_incl(loop_body, i); - } - } - - n = b->children; - while (n >= 0) { - b = ssa->cfg.blocks + n; - if (zend_jit_in_loop(ssa, header, b)) { - if (b->next_child < 0) { - goto tail_call; - } - zend_jit_compute_loop_body(ssa, header, n, loop_body); - } - n = b->next_child; - } -} - -static void zend_jit_add_hint(zend_lifetime_interval **intervals, int dst, int src) -{ - if (intervals[dst]->range.start < intervals[src]->range.start) { - int tmp = src; - src = dst; - dst = tmp; - } - while (dst != src && intervals[dst]->hint) { - if (intervals[dst]->hint->range.start < intervals[src]->range.start) { - int tmp = src; - src = intervals[dst]->hint->ssa_var; - dst = tmp; - } else { - dst = intervals[dst]->hint->ssa_var; - } - } - if (dst != src) { - intervals[dst]->hint = intervals[src]; - } -} - -/* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and - Michael Franz, CGO'10 (2010), Figure 4. */ -static int zend_jit_compute_liveness(const zend_op_array *op_array, zend_ssa *ssa, zend_bitset candidates, zend_lifetime_interval **list) -{ - int set_size, i, j, k, l; - uint32_t n; - zend_bitset live, live_in, pi_vars, loop_body; - int *block_order; - zend_ssa_phi *phi; - zend_lifetime_interval **intervals; - size_t mem_size; - ALLOCA_FLAG(use_heap); - - set_size = zend_bitset_len(ssa->vars_count); - mem_size = - ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*)) + - ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE) + - ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) + - ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE) + - ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE) + - ZEND_MM_ALIGNED_SIZE(ssa->cfg.blocks_count * sizeof(int)); - intervals = do_alloca(mem_size, use_heap); - if (!intervals) { - *list = NULL; - return FAILURE; - } - - live_in = (zend_bitset)((char*)intervals + ZEND_MM_ALIGNED_SIZE(ssa->vars_count * sizeof(zend_lifetime_interval*))); - live = (zend_bitset)((char*)live_in + ZEND_MM_ALIGNED_SIZE((set_size * ssa->cfg.blocks_count) * ZEND_BITSET_ELM_SIZE)); - pi_vars = (zend_bitset)((char*)live + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE)); - loop_body = (zend_bitset)((char*)pi_vars + ZEND_MM_ALIGNED_SIZE(set_size * ZEND_BITSET_ELM_SIZE)); - block_order = (int*)((char*)loop_body + ZEND_MM_ALIGNED_SIZE(zend_bitset_len(op_array->last) * ZEND_BITSET_ELM_SIZE)); - - memset(intervals, 0, ssa->vars_count * sizeof(zend_lifetime_interval*)); - zend_bitset_clear(live_in, set_size * ssa->cfg.blocks_count); - - /* TODO: Provide a linear block order where all dominators of a block - * are before this block, and where all blocks belonging to the same loop - * are contiguous ??? - */ - for (l = zend_jit_compute_block_order(ssa, block_order) - 1; l >= 0; l--) { - zend_basic_block *b; - - i = block_order[l]; - b = ssa->cfg.blocks + i; - - /* live = UNION of successor.liveIn for each successor of b */ - /* live.add(phi.inputOf(b)) for each phi of successors of b */ - zend_bitset_clear(live, set_size); - for (j = 0; j < b->successors_count; j++) { - int succ = b->successors[j]; - - zend_bitset_union(live, live_in + set_size * succ, set_size); - zend_bitset_clear(pi_vars, set_size); - for (phi = ssa->blocks[succ].phis; phi; phi = phi->next) { - if (ssa->vars[phi->ssa_var].no_val) { - /* skip */ - } else if (phi->pi >= 0) { - if (phi->pi == i && phi->sources[0] >= 0) { - if (zend_bitset_in(candidates, phi->sources[0])) { - zend_bitset_incl(live, phi->sources[0]); - } - zend_bitset_incl(pi_vars, phi->var); - } - } else if (!zend_bitset_in(pi_vars, phi->var)) { - for (k = 0; k < ssa->cfg.blocks[succ].predecessors_count; k++) { - if (ssa->cfg.predecessors[ssa->cfg.blocks[succ].predecessor_offset + k] == i) { - if (phi->sources[k] >= 0 && zend_bitset_in(candidates, phi->sources[k])) { - zend_bitset_incl(live, phi->sources[k]); - } - break; - } - } - } - } - } - - /* addRange(var, b.from, b.to) for each var in live */ - ZEND_BITSET_FOREACH(live, set_size, j) { - if (zend_bitset_in(candidates, j)) { - if (zend_jit_add_range(intervals, j, b->start, b->start + b->len - 1) != SUCCESS) { - goto failure; - } - } - } ZEND_BITSET_FOREACH_END(); - - /* for each operation op of b in reverse order */ - for (n = b->start + b->len; n > b->start;) { - zend_ssa_op *op; - const zend_op *opline; - uint32_t num; - - n--; - op = ssa->ops + n; - opline = op_array->opcodes + n; - - if (UNEXPECTED(opline->opcode == ZEND_OP_DATA)) { - num = n - 1; - } else { - num = n; - } - - /* for each output operand opd of op do */ - /* setFrom(opd, op) */ - /* live.remove(opd) */ - if (op->op1_def >= 0 && zend_bitset_in(candidates, op->op1_def)) { - if (zend_jit_begin_range(intervals, op->op1_def, b->start, num) != SUCCESS) { - goto failure; - } - zend_bitset_excl(live, op->op1_def); - } - if (op->op2_def >= 0 && zend_bitset_in(candidates, op->op2_def)) { - if (zend_jit_begin_range(intervals, op->op2_def, b->start, num) != SUCCESS) { - goto failure; - } - zend_bitset_excl(live, op->op2_def); - } - if (op->result_def >= 0 && zend_bitset_in(candidates, op->result_def)) { - if (zend_jit_begin_range(intervals, op->result_def, b->start, num) != SUCCESS) { - goto failure; - } - zend_bitset_excl(live, op->result_def); - } - - /* for each input operand opd of op do */ - /* live.add(opd) */ - /* addRange(opd, b.from, op) */ - if (op->op1_use >= 0 - && zend_bitset_in(candidates, op->op1_use) - && !zend_ssa_is_no_val_use(opline, op, op->op1_use)) { - zend_bitset_incl(live, op->op1_use); - if (zend_jit_add_range(intervals, op->op1_use, b->start, num) != SUCCESS) { - goto failure; - } - } - if (op->op2_use >= 0 - && zend_bitset_in(candidates, op->op2_use) - && !zend_ssa_is_no_val_use(opline, op, op->op2_use)) { - zend_bitset_incl(live, op->op2_use); - if (zend_jit_add_range(intervals, op->op2_use, b->start, num) != SUCCESS) { - goto failure; - } - } - if (op->result_use >= 0 - && zend_bitset_in(candidates, op->result_use) - && !zend_ssa_is_no_val_use(opline, op, op->result_use)) { - zend_bitset_incl(live, op->result_use); - if (zend_jit_add_range(intervals, op->result_use, b->start, num) != SUCCESS) { - goto failure; - } - } - } - - /* live.remove(phi.output) for each phi of b */ - for (phi = ssa->blocks[i].phis; phi; phi = phi->next) { - zend_bitset_excl(live, phi->ssa_var); - } - - /* b.liveIn = live */ - zend_bitset_copy(live_in + set_size * i, live, set_size); - } - - for (i = ssa->cfg.blocks_count - 1; i >= 0; i--) { - zend_basic_block *b = ssa->cfg.blocks + i; - - /* if b is loop header */ - if ((b->flags & ZEND_BB_LOOP_HEADER)) { - live = live_in + set_size * i; - - if (!zend_bitset_empty(live, set_size)) { - uint32_t set_size2 = zend_bitset_len(op_array->last); - - zend_bitset_clear(loop_body, set_size2); - zend_jit_compute_loop_body(ssa, i, i, loop_body); - while (!zend_bitset_empty(loop_body, set_size2)) { - uint32_t from = zend_bitset_first(loop_body, set_size2); - uint32_t to = from; - - do { - zend_bitset_excl(loop_body, to); - to++; - } while (zend_bitset_in(loop_body, to)); - to--; - - ZEND_BITSET_FOREACH(live, set_size, j) { - if (zend_jit_add_range(intervals, j, from, to) != SUCCESS) { - goto failure; - } - } ZEND_BITSET_FOREACH_END(); - } - } - } - - } - - if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) { - /* Register hinting (a cheap way for register coalescing) */ - for (i = 0; i < ssa->vars_count; i++) { - if (intervals[i]) { - int src; - - if (ssa->vars[i].definition_phi) { - zend_ssa_phi *phi = ssa->vars[i].definition_phi; - - if (phi->pi >= 0) { - src = phi->sources[0]; - if (intervals[src]) { - zend_jit_add_hint(intervals, i, src); - } - } else { - for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) { - src = phi->sources[k]; - if (src >= 0) { - if (ssa->vars[src].definition_phi - && ssa->vars[src].definition_phi->pi >= 0 - && phi->block == ssa->vars[src].definition_phi->block) { - /* Skip zero-length interval for Pi variable */ - src = ssa->vars[src].definition_phi->sources[0]; - } - if (intervals[src]) { - zend_jit_add_hint(intervals, i, src); - } - } - } - } - } - } - } - for (i = 0; i < ssa->vars_count; i++) { - if (intervals[i] && !intervals[i]->hint) { - - if (ssa->vars[i].definition >= 0) { - uint32_t line = ssa->vars[i].definition; - const zend_op *opline = op_array->opcodes + line; - - switch (opline->opcode) { - case ZEND_QM_ASSIGN: - case ZEND_POST_INC: - case ZEND_POST_DEC: - if (ssa->ops[line].op1_use >= 0 && - intervals[ssa->ops[line].op1_use] && - (i == ssa->ops[line].op1_def || - (i == ssa->ops[line].result_def && - (ssa->ops[line].op1_def < 0 || - !intervals[ssa->ops[line].op1_def])))) { - zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use); - } - break; - case ZEND_SEND_VAR: - case ZEND_PRE_INC: - case ZEND_PRE_DEC: - if (i == ssa->ops[line].op1_def && - ssa->ops[line].op1_use >= 0 && - intervals[ssa->ops[line].op1_use]) { - zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use); - } - break; - case ZEND_ASSIGN: - if (ssa->ops[line].op2_use >= 0 && - intervals[ssa->ops[line].op2_use] && - (i == ssa->ops[line].op2_def || - (i == ssa->ops[line].op1_def && - (ssa->ops[line].op2_def < 0 || - !intervals[ssa->ops[line].op2_def])) || - (i == ssa->ops[line].result_def && - (ssa->ops[line].op2_def < 0 || - !intervals[ssa->ops[line].op2_def]) && - (ssa->ops[line].op1_def < 0 || - !intervals[ssa->ops[line].op1_def])))) { - zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use); - } - break; - case ZEND_SUB: - case ZEND_ADD: - case ZEND_MUL: - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - if (i == ssa->ops[line].result_def) { - if (ssa->ops[line].op1_use >= 0 && - intervals[ssa->ops[line].op1_use] && - ssa->ops[line].op1_use_chain < 0 && - !ssa->vars[ssa->ops[line].op1_use].phi_use_chain && - (ssa->var_info[i].type & MAY_BE_ANY) == - (ssa->var_info[ssa->ops[line].op1_use].type & MAY_BE_ANY)) { - zend_jit_add_hint(intervals, i, ssa->ops[line].op1_use); - } else if (opline->opcode != ZEND_SUB && - ssa->ops[line].op2_use >= 0 && - intervals[ssa->ops[line].op2_use] && - ssa->ops[line].op2_use_chain < 0 && - !ssa->vars[ssa->ops[line].op2_use].phi_use_chain && - (ssa->var_info[i].type & MAY_BE_ANY) == - (ssa->var_info[ssa->ops[line].op2_use].type & MAY_BE_ANY)) { - zend_jit_add_hint(intervals, i, ssa->ops[line].op2_use); - } - } - break; - } - } - } - } - } - - *list = zend_jit_sort_intervals(intervals, ssa->vars_count); - - if (*list) { - zend_lifetime_interval *ival = *list; - while (ival) { - if (ival->hint) { - ival->hint->used_as_hint = ival; - } - ival = ival->list_next; - } - } - - free_alloca(intervals, use_heap); - return SUCCESS; - -failure: - *list = NULL; - free_alloca(intervals, use_heap); - return FAILURE; -} - -static uint32_t zend_interval_end(zend_lifetime_interval *ival) -{ - zend_life_range *range = &ival->range; - - while (range->next) { - range = range->next; - } - return range->end; -} - -static bool zend_interval_covers(zend_lifetime_interval *ival, uint32_t position) -{ - zend_life_range *range = &ival->range; - - do { - if (position >= range->start && position <= range->end) { - return 1; - } - range = range->next; - } while (range); - - return 0; -} - -static uint32_t zend_interval_intersection(zend_lifetime_interval *ival1, zend_lifetime_interval *ival2) -{ - zend_life_range *r1 = &ival1->range; - zend_life_range *r2 = &ival2->range; - - do { - if (r1->start <= r2->end) { - if (r2->start <= r1->end) { - return MAX(r1->start, r2->start); - } else { - r2 = r2->next; - } - } else { - r1 = r1->next; - } - } while (r1 && r2); - - return 0xffffffff; -} - -/* See "Optimized Interval Splitting in a Linear Scan Register Allocator", - Christian Wimmer VEE'05 (2005), Figure 4. Allocation without spilling */ -static int zend_jit_try_allocate_free_reg(const zend_op_array *op_array, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *current, zend_regset available, zend_regset *hints, zend_lifetime_interval *active, zend_lifetime_interval *inactive, zend_lifetime_interval **list, zend_lifetime_interval **free) -{ - zend_lifetime_interval *it; - uint32_t freeUntilPos[ZREG_NUM]; - uint32_t pos, pos2; - zend_reg i, reg, reg2; - zend_reg hint = ZREG_NONE; - zend_regset low_priority_regs; - zend_life_range *range; - - if ((ssa->var_info[current->ssa_var].type & MAY_BE_ANY) == MAY_BE_DOUBLE) { - available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_FP); - } else { - available = ZEND_REGSET_INTERSECTION(available, ZEND_REGSET_GP); - } - - /* TODO: Allow usage of preserved registers ??? - * Their values have to be stored in prologue and restored in epilogue - */ - available = ZEND_REGSET_DIFFERENCE(available, ZEND_REGSET_PRESERVED); - - /* Set freeUntilPos of all physical registers to maxInt */ - for (i = 0; i < ZREG_NUM; i++) { - freeUntilPos[i] = 0xffffffff; - } - - /* for each interval it in active do */ - /* freeUntilPos[it.reg] = 0 */ - it = active; - if (ssa->vars[current->ssa_var].definition == current->range.start) { - while (it) { - if (current->range.start != zend_interval_end(it)) { - freeUntilPos[it->reg] = 0; - } else if (zend_jit_may_reuse_reg( - ssa_opcodes ? ssa_opcodes[current->range.start] : op_array->opcodes + current->range.start, - ssa->ops + current->range.start, ssa, current->ssa_var, it->ssa_var)) { - if (!ZEND_REGSET_IN(*hints, it->reg) && - /* TODO: Avoid most often scratch registers. Find a better way ??? */ - (!current->used_as_hint || - !ZEND_REGSET_IN(ZEND_REGSET_LOW_PRIORITY, it->reg))) { - hint = it->reg; - } - } else { - freeUntilPos[it->reg] = 0; - } - it = it->list_next; - } - } else { - while (it) { - freeUntilPos[it->reg] = 0; - it = it->list_next; - } - } - if (current->hint) { - hint = current->hint->reg; - if (hint != ZREG_NONE && current->hint->used_as_hint == current) { - ZEND_REGSET_EXCL(*hints, hint); - } - } - - if (hint == ZREG_NONE && ZEND_REGSET_IS_EMPTY(available)) { - return 0; - } - - /* See "Linear Scan Register Allocation on SSA Form", Christian Wimmer and - Michael Franz, CGO'10 (2010), Figure 6. */ - if (current->flags & ZREG_SPLIT) { - /* for each interval it in inactive intersecting with current do */ - /* freeUntilPos[it.reg] = next intersection of it with current */ - it = inactive; - while (it) { - uint32_t next = zend_interval_intersection(current, it); - - //ZEND_ASSERT(next != 0xffffffff && !current->split); - if (next < freeUntilPos[it->reg]) { - freeUntilPos[it->reg] = next; - } - it = it->list_next; - } - } - - /* Handle Scratch Registers */ - /* TODO: Optimize ??? */ - range = ¤t->range; - do { - uint32_t line = range->start; - uint32_t last_use_line = (uint32_t)-1; - zend_regset regset; - zend_reg reg; - - if ((current->flags & ZREG_LAST_USE) && !range->next) { - last_use_line = range->end; - } - if (ssa->ops[line].op1_def == current->ssa_var || - ssa->ops[line].op2_def == current->ssa_var || - ssa->ops[line].result_def == current->ssa_var) { - regset = zend_jit_get_def_scratch_regset( - ssa_opcodes ? ssa_opcodes[line] : op_array->opcodes + line, - ssa->ops + line, - op_array, ssa, current->ssa_var, line == last_use_line); - ZEND_REGSET_FOREACH(regset, reg) { - if (line < freeUntilPos[reg]) { - freeUntilPos[reg] = line; - } - } ZEND_REGSET_FOREACH_END(); - line++; - } - while (line <= range->end) { - regset = zend_jit_get_scratch_regset( - ssa_opcodes ? ssa_opcodes[line] : op_array->opcodes + line, - ssa->ops + line, - op_array, ssa, current->ssa_var, line == last_use_line); - ZEND_REGSET_FOREACH(regset, reg) { - if (line < freeUntilPos[reg]) { - freeUntilPos[reg] = line; - } - } ZEND_REGSET_FOREACH_END(); - line++; - } - range = range->next; - } while (range); - -#if 0 - /* Coalescing */ - if (ssa->vars[current->ssa_var].definition == current->start) { - zend_op *opline = op_array->opcodes + current->start; - int hint = -1; - - switch (opline->opcode) { - case ZEND_ASSIGN: - hint = ssa->ops[current->start].op2_use; - case ZEND_QM_ASSIGN: - hint = ssa->ops[current->start].op1_use; - break; - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - hint = ssa->ops[current->start].op1_use; - break; - case ZEND_ASSIGN_OP: - if (opline->extended_value == ZEND_ADD - || opline->extended_value == ZEND_SUB - || opline->extended_value == ZEND_MUL) { - hint = ssa->ops[current->start].op1_use; - } - break; - } - if (hint >= 0) { - } - } -#endif - - if (hint != ZREG_NONE && freeUntilPos[hint] > zend_interval_end(current)) { - current->reg = hint; - if (current->used_as_hint) { - ZEND_REGSET_INCL(*hints, hint); - } - return 1; - } - - if (ZEND_REGSET_IS_EMPTY(available)) { - return 0; - } - - pos = 0; reg = ZREG_NONE; - pos2 = 0; reg2 = ZREG_NONE; - low_priority_regs = *hints; - if (current->used_as_hint) { - /* TODO: Avoid most often scratch registers. Find a better way ??? */ - low_priority_regs = ZEND_REGSET_UNION(low_priority_regs, ZEND_REGSET_LOW_PRIORITY); - } - - ZEND_REGSET_FOREACH(available, i) { - if (ZEND_REGSET_IN(low_priority_regs, i)) { - if (freeUntilPos[i] > pos2) { - reg2 = i; - pos2 = freeUntilPos[i]; - } - } else if (freeUntilPos[i] > pos) { - reg = i; - pos = freeUntilPos[i]; - } - } ZEND_REGSET_FOREACH_END(); - - if (reg == ZREG_NONE) { - if (reg2 != ZREG_NONE) { - reg = reg2; - pos = pos2; - reg2 = ZREG_NONE; - } - } - - if (reg == ZREG_NONE) { - /* no register available without spilling */ - return 0; - } else if (zend_interval_end(current) < pos) { - /* register available for the whole interval */ - current->reg = reg; - if (current->used_as_hint) { - ZEND_REGSET_INCL(*hints, reg); - } - return 1; -#if 0 - // TODO: allow low priority register usage - } else if (reg2 != ZREG_NONE && zend_interval_end(current) < pos2) { - /* register available for the whole interval */ - current->reg = reg2; - if (current->used_as_hint) { - ZEND_REGSET_INCL(*hints, reg2); - } - return 1; -#endif - } else { - /* TODO: enable interval splitting ??? */ - /* register available for the first part of the interval */ - if (1 || zend_jit_split_interval(current, pos, list, free) != SUCCESS) { - return 0; - } - current->reg = reg; - if (current->used_as_hint) { - ZEND_REGSET_INCL(*hints, reg); - } - return 1; - } -} - -/* See "Optimized Interval Splitting in a Linear Scan Register Allocator", - Christian Wimmer VEE'05 (2005), Figure 5. Allocation with spilling. - and "Linear Scan Register Allocation on SSA Form", Christian Wimmer and - Michael Franz, CGO'10 (2010), Figure 6. */ -static int zend_jit_allocate_blocked_reg(void) -{ - /* TODO: ??? */ - return 0; -} - -/* See "Optimized Interval Splitting in a Linear Scan Register Allocator", - Christian Wimmer VEE'10 (2005), Figure 2. */ -static zend_lifetime_interval* zend_jit_linear_scan(const zend_op_array *op_array, const zend_op **ssa_opcodes, zend_ssa *ssa, zend_lifetime_interval *list) -{ - zend_lifetime_interval *unhandled, *active, *inactive, *handled, *free; - zend_lifetime_interval *current, **p, *q; - uint32_t position; - zend_regset available = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP); - zend_regset hints = ZEND_REGSET_EMPTY; - - unhandled = list; - /* active = inactive = handled = free = {} */ - active = inactive = handled = free = NULL; - while (unhandled != NULL) { - current = unhandled; - unhandled = unhandled->list_next; - position = current->range.start; - - p = &active; - while (*p) { - uint32_t end = zend_interval_end(*p); - - q = *p; - if (end < position) { - /* move ival from active to handled */ - ZEND_REGSET_INCL(available, q->reg); - *p = q->list_next; - q->list_next = handled; - handled = q; - } else if (!zend_interval_covers(q, position)) { - /* move ival from active to inactive */ - ZEND_REGSET_INCL(available, q->reg); - *p = q->list_next; - q->list_next = inactive; - inactive = q; - } else { - p = &q->list_next; - } - } - - p = &inactive; - while (*p) { - uint32_t end = zend_interval_end(*p); - - q = *p; - if (end < position) { - /* move ival from inactive to handled */ - *p = q->list_next; - q->list_next = handled; - handled = q; - } else if (zend_interval_covers(q, position)) { - /* move ival from inactive to active */ - ZEND_REGSET_EXCL(available, q->reg); - *p = q->list_next; - q->list_next = active; - active = q; - } else { - p = &q->list_next; - } - } - - if (zend_jit_try_allocate_free_reg(op_array, ssa_opcodes, ssa, current, available, &hints, active, inactive, &unhandled, &free) || - zend_jit_allocate_blocked_reg()) { - ZEND_REGSET_EXCL(available, current->reg); - current->list_next = active; - active = current; - } else { - current->list_next = free; - free = current; - } - } - - /* move active to handled */ - while (active) { - current = active; - active = active->list_next; - current->list_next = handled; - handled = current; - } - - /* move inactive to handled */ - while (inactive) { - current = inactive; - inactive = inactive->list_next; - current->list_next = handled; - handled = current; - } - - return handled; -} - -static void zend_jit_dump_lifetime_interval(const zend_op_array *op_array, const zend_ssa *ssa, const zend_lifetime_interval *ival) -{ - zend_life_range *range; - int var_num = ssa->vars[ival->ssa_var].var; - - fprintf(stderr, "#%d.", ival->ssa_var); - zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num); - fprintf(stderr, ": %u-%u", ival->range.start, ival->range.end); - range = ival->range.next; - while (range) { - fprintf(stderr, ", %u-%u", range->start, range->end); - range = range->next; - } - if (ival->reg != ZREG_NONE) { - fprintf(stderr, " (%s)", zend_reg_name[ival->reg]); - } - if (ival->flags & ZREG_LAST_USE) { - fprintf(stderr, " last_use"); - } - if (ival->flags & ZREG_LOAD) { - fprintf(stderr, " load"); - } - if (ival->flags & ZREG_STORE) { - fprintf(stderr, " store"); - } - if (ival->hint) { - fprintf(stderr, " hint"); - if (ival->hint->ssa_var >= 0) { - var_num = ssa->vars[ival->hint->ssa_var].var; - fprintf(stderr, "=#%d.", ival->hint->ssa_var); - zend_dump_var(op_array, (var_num < op_array->last_var ? IS_CV : 0), var_num); - } - if (ival->hint->reg != ZREG_NONE) { - fprintf(stderr, " (%s)", zend_reg_name[ival->hint->reg]); - } - } - fprintf(stderr, "\n"); -} - -static zend_lifetime_interval** zend_jit_allocate_registers(const zend_op_array *op_array, zend_ssa *ssa) -{ - void *checkpoint; - int set_size, candidates_count, i; - zend_bitset candidates = NULL; - zend_lifetime_interval *list, *ival; - zend_lifetime_interval **intervals; - ALLOCA_FLAG(use_heap); - - if (!ssa->var_info) { - return NULL; - } - - /* Identify SSA variables suitable for register allocation */ - set_size = zend_bitset_len(ssa->vars_count); - candidates = ZEND_BITSET_ALLOCA(set_size, use_heap); - if (!candidates) { - return NULL; - } - candidates_count = 0; - zend_bitset_clear(candidates, set_size); - for (i = 0; i < ssa->vars_count; i++) { - if (zend_jit_may_be_in_reg(op_array, ssa, i)) { - zend_bitset_incl(candidates, i); - candidates_count++; - } - } - if (!candidates_count) { - free_alloca(candidates, use_heap); - return NULL; - } - - checkpoint = zend_arena_checkpoint(CG(arena)); - - /* Find life-time intervals */ - if (zend_jit_compute_liveness(op_array, ssa, candidates, &list) != SUCCESS) { - goto failure; - } - - if (list) { - /* Set ZREG_LAST_USE flags */ - ival = list; - while (ival) { - zend_life_range *range = &ival->range; - - while (range->next) { - range = range->next; - } - if (zend_ssa_is_last_use(op_array, ssa, ival->ssa_var, range->end)) { - ival->flags |= ZREG_LAST_USE; - } - ival = ival->list_next; - } - } - - if (list) { - if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) { - fprintf(stderr, "Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]"); - ival = list; - while (ival) { - zend_jit_dump_lifetime_interval(op_array, ssa, ival); - ival = ival->list_next; - } - fprintf(stderr, "\n"); - } - - /* Linear Scan Register Allocation */ - list = zend_jit_linear_scan(op_array, NULL, ssa, list); - - if (list) { - intervals = zend_arena_calloc(&CG(arena), ssa->vars_count, sizeof(zend_lifetime_interval*)); - if (!intervals) { - goto failure; - } - - ival = list; - while (ival != NULL) { - zend_lifetime_interval *next = ival->list_next; - - ival->list_next = intervals[ival->ssa_var]; - intervals[ival->ssa_var] = ival; - ival = next; - } - - if (JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) { - /* Naive SSA resolution */ - for (i = 0; i < ssa->vars_count; i++) { - if (ssa->vars[i].definition_phi && !ssa->vars[i].no_val) { - zend_ssa_phi *phi = ssa->vars[i].definition_phi; - int k, src; - - if (phi->pi >= 0) { - if (!ssa->vars[i].phi_use_chain - || ssa->vars[i].phi_use_chain->block != phi->block) { - src = phi->sources[0]; - if (intervals[i]) { - if (!intervals[src]) { - intervals[i]->flags |= ZREG_LOAD; - } else if (intervals[i]->reg != intervals[src]->reg) { - intervals[i]->flags |= ZREG_LOAD; - intervals[src]->flags |= ZREG_STORE; - } - } else if (intervals[src]) { - intervals[src]->flags |= ZREG_STORE; - } - } - } else { - int need_move = 0; - - for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) { - src = phi->sources[k]; - if (src >= 0) { - if (ssa->vars[src].definition_phi - && ssa->vars[src].definition_phi->pi >= 0 - && phi->block == ssa->vars[src].definition_phi->block) { - /* Skip zero-length interval for Pi variable */ - src = ssa->vars[src].definition_phi->sources[0]; - } - if (intervals[i]) { - if (!intervals[src]) { - need_move = 1; - } else if (intervals[i]->reg != intervals[src]->reg) { - need_move = 1; - } - } else if (intervals[src]) { - need_move = 1; - } - } - } - if (need_move) { - if (intervals[i]) { - intervals[i]->flags |= ZREG_LOAD; - } - for (k = 0; k < ssa->cfg.blocks[phi->block].predecessors_count; k++) { - src = phi->sources[k]; - if (src >= 0) { - if (ssa->vars[src].definition_phi - && ssa->vars[src].definition_phi->pi >= 0 - && phi->block == ssa->vars[src].definition_phi->block) { - /* Skip zero-length interval for Pi variable */ - src = ssa->vars[src].definition_phi->sources[0]; - } - if (intervals[src]) { - intervals[src]->flags |= ZREG_STORE; - } - } - } - } - } - } - } - /* Remove useless register allocation */ - for (i = 0; i < ssa->vars_count; i++) { - if (intervals[i] && - ((intervals[i]->flags & ZREG_LOAD) || - ((intervals[i]->flags & ZREG_STORE) && ssa->vars[i].definition >= 0)) && - ssa->vars[i].use_chain < 0) { - bool may_remove = 1; - zend_ssa_phi *phi = ssa->vars[i].phi_use_chain; - - while (phi) { - if (intervals[phi->ssa_var] && - !(intervals[phi->ssa_var]->flags & ZREG_LOAD)) { - may_remove = 0; - break; - } - phi = zend_ssa_next_use_phi(ssa, i, phi); - } - if (may_remove) { - intervals[i] = NULL; - } - } - } - /* Remove intervals used once */ - for (i = 0; i < ssa->vars_count; i++) { - if (intervals[i] && - (intervals[i]->flags & ZREG_LOAD) && - (intervals[i]->flags & ZREG_STORE) && - (ssa->vars[i].use_chain < 0 || - zend_ssa_next_use(ssa->ops, i, ssa->vars[i].use_chain) < 0)) { - bool may_remove = 1; - zend_ssa_phi *phi = ssa->vars[i].phi_use_chain; - - while (phi) { - if (intervals[phi->ssa_var] && - !(intervals[phi->ssa_var]->flags & ZREG_LOAD)) { - may_remove = 0; - break; - } - phi = zend_ssa_next_use_phi(ssa, i, phi); - } - if (may_remove) { - intervals[i] = NULL; - } - } - } - } - - if (JIT_G(debug) & ZEND_JIT_DEBUG_REG_ALLOC) { - fprintf(stderr, "Allocated Live Ranges \"%s\"\n", op_array->function_name ? ZSTR_VAL(op_array->function_name) : "[main]"); - for (i = 0; i < ssa->vars_count; i++) { - ival = intervals[i]; - while (ival) { - zend_jit_dump_lifetime_interval(op_array, ssa, ival); - ival = ival->list_next; - } - } - fprintf(stderr, "\n"); - } - - free_alloca(candidates, use_heap); - return intervals; + /* TODO: move this to zend_cfg.c ? */ + if (!op_array->function_name) { + ssa->cfg.flags |= ZEND_FUNC_INDIRECT_VAR_ACCESS; + } + + if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) + && ssa->cfg.blocks + && op_array->last_try_catch == 0 + && !(op_array->fn_flags & ZEND_ACC_GENERATOR) + && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) { + if (zend_build_ssa(&CG(arena), script, op_array, ZEND_SSA_RC_INFERENCE | ZEND_SSA_USE_CV_RESULTS, ssa) != SUCCESS) { + return FAILURE; } + + zend_ssa_compute_use_def_chains(&CG(arena), op_array, ssa); + + zend_ssa_find_false_dependencies(op_array, ssa); + + zend_ssa_find_sccs(op_array, ssa); } -failure: - zend_arena_release(&CG(arena), checkpoint); - free_alloca(candidates, use_heap); - return NULL; + return SUCCESS; } -#else /* ZEND_JIT_IR */ +static int zend_jit_op_array_analyze2(const zend_op_array *op_array, zend_script *script, zend_ssa *ssa, uint32_t optimization_level) +{ + if ((JIT_G(opt_level) >= ZEND_JIT_LEVEL_OPT_FUNC) + && ssa->cfg.blocks + && op_array->last_try_catch == 0 + && !(op_array->fn_flags & ZEND_ACC_GENERATOR) + && !(ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS)) { + if (zend_ssa_inference(&CG(arena), op_array, script, ssa, + optimization_level & ~ZEND_OPTIMIZER_NARROW_TO_DOUBLE) != SUCCESS) { + return FAILURE; + } + } + + return SUCCESS; +} static void zend_jit_allocate_registers(zend_jit_ctx *ctx, const zend_op_array *op_array, zend_ssa *ssa) { @@ -2890,7 +1174,6 @@ static int zend_jit_compute_post_order(zend_cfg *cfg, int start, int *post_order ZEND_WORKLIST_FREE_ALLOCA(&worklist, use_heap); return count; } -#endif /* ZEND_JIT_IR */ static bool zend_jit_next_is_send_result(const zend_op *opline) { @@ -2936,15 +1219,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op { int b, i, end; zend_op *opline; -#ifndef ZEND_JIT_IR - dasm_State* ctx = NULL; - zend_lifetime_interval **ra = NULL; - bool is_terminated = 1; /* previous basic block is terminated by jump */ -#else zend_jit_ctx ctx; zend_jit_ctx *jit = &ctx; zend_jit_reg_var *ra = NULL; -#endif void *handler; int call_level = 0; void *checkpoint = NULL; @@ -2971,138 +1248,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } } -#ifndef ZEND_JIT_IR - if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) { - checkpoint = zend_arena_checkpoint(CG(arena)); - ra = zend_jit_allocate_registers(op_array, ssa); - } - - /* mark hidden branch targets */ - for (b = 0; b < ssa->cfg.blocks_count; b++) { - if (ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE && - ssa->cfg.blocks[b].len > 1) { - - opline = op_array->opcodes + ssa->cfg.blocks[b].start + ssa->cfg.blocks[b].len - 1; - if (opline->opcode == ZEND_DO_FCALL && - (opline-1)->opcode == ZEND_NEW) { - ssa->cfg.blocks[ssa->cfg.blocks[b].successors[0]].flags |= ZEND_BB_TARGET; - } - } - } - - dasm_init(&ctx, DASM_MAXSECTION); - dasm_setupglobal(&ctx, dasm_labels, zend_lb_MAX); - dasm_setup(&ctx, dasm_actions); - - dasm_growpc(&ctx, ssa->cfg.blocks_count * 2 + 1); - - zend_jit_align_func(&ctx); - for (b = 0; b < ssa->cfg.blocks_count; b++) { - if ((ssa->cfg.blocks[b].flags & ZEND_BB_REACHABLE) == 0) { - continue; - } -//#ifndef CONTEXT_THREADED_JIT - if (ssa->cfg.blocks[b].flags & ZEND_BB_ENTRY) { - if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) { - /* pass */ - } else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE && - ssa->cfg.blocks[b].len == 1 && - (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT) && - op_array->opcodes[ssa->cfg.blocks[b].start].opcode != ZEND_JMP) { - /* don't generate code for BB with single opcode */ - continue; - } - if (ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW) { - if (!is_terminated) { - zend_jit_jmp(&ctx, b); - } - } - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - zend_jit_prologue(&ctx); - } else -//#endif - if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY)) { - opline = op_array->opcodes + ssa->cfg.blocks[b].start; - if (ssa->cfg.flags & ZEND_CFG_RECV_ENTRY) { - if (opline->opcode == ZEND_RECV_INIT) { - if (opline == op_array->opcodes || - (opline-1)->opcode != ZEND_RECV_INIT) { - if (recv_emitted) { - zend_jit_jmp(&ctx, b); - } - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - for (i = 1; (opline+i)->opcode == ZEND_RECV_INIT; i++) { - zend_jit_label(&ctx, ssa->cfg.blocks_count + b + i); - } - zend_jit_prologue(&ctx); - } - recv_emitted = 1; - } else if (opline->opcode == ZEND_RECV) { - if (!(op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - /* skip */ - continue; - } else if (recv_emitted) { - zend_jit_jmp(&ctx, b); - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - zend_jit_prologue(&ctx); - } else { - zend_arg_info *arg_info; - - if (opline->op1.num <= op_array->num_args) { - arg_info = &op_array->arg_info[opline->op1.num - 1]; - } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) { - arg_info = &op_array->arg_info[op_array->num_args]; - } else { - /* skip */ - continue; - } - if (!ZEND_TYPE_IS_SET(arg_info->type)) { - /* skip */ - continue; - } - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - zend_jit_prologue(&ctx); - recv_emitted = 1; - } - } else { - if (recv_emitted) { - zend_jit_jmp(&ctx, b); - } else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE && - ssa->cfg.blocks[b].len == 1 && - (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) { - /* don't generate code for BB with single opcode */ - dasm_free(&ctx); - - if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) { - zend_arena_release(&CG(arena), checkpoint); - } - return SUCCESS; - } - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - zend_jit_prologue(&ctx); - recv_emitted = 1; - } - } else if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE && - ssa->cfg.blocks[b].len == 1 && - (ssa->cfg.blocks[b].flags & ZEND_BB_EXIT)) { - /* don't generate code for BB with single opcode */ - dasm_free(&ctx); - - if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) { - zend_arena_release(&CG(arena), checkpoint); - } - return SUCCESS; - } else { - zend_jit_label(&ctx, ssa->cfg.blocks_count + b); - zend_jit_prologue(&ctx); - } - } - - is_terminated = 0; - - zend_jit_label(&ctx, b); -#else /* ZEND_JIT_IR */ - if (ssa->cfg.flags & ZEND_FUNC_IRREDUCIBLE) { /* We can't order blocks properly */ return FAILURE; @@ -3208,7 +1353,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op && rt_opline == op_array->opcodes + ssa->cfg.blocks[b].start) { zend_jit_osr_entry(&ctx, b); /* OSR (On-Stack-Replacement) Entry-Point */ } -#endif /* ZEND_JIT_IR */ if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) { if ((ssa->cfg.blocks[b].flags & ZEND_BB_FOLLOW) @@ -3217,33 +1361,16 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_LONG || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_SWITCH_STRING || op_array->opcodes[ssa->cfg.blocks[b].start - 1].opcode == ZEND_MATCH)) { -#ifndef ZEND_JIT_IR - zend_jit_reset_last_valid_opline(); - if (!zend_jit_set_ip(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start)) { - goto jit_failure; - } -#else zend_jit_reset_last_valid_opline(&ctx); -#endif } else { -#ifndef ZEND_JIT_IR - zend_jit_set_last_valid_opline(op_array->opcodes + ssa->cfg.blocks[b].start); -#else zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start); -#endif } } else if (ssa->cfg.blocks[b].flags & ZEND_BB_TARGET) { -#ifndef ZEND_JIT_IR - zend_jit_reset_last_valid_opline(); - } else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_RECV_ENTRY|ZEND_BB_ENTRY)) { - zend_jit_set_last_valid_opline(op_array->opcodes + ssa->cfg.blocks[b].start); -#else zend_jit_reset_last_valid_opline(&ctx); } else if (ssa->cfg.blocks[b].flags & ZEND_BB_RECV_ENTRY) { zend_jit_reset_last_valid_opline(&ctx); } else if (ssa->cfg.blocks[b].flags & (ZEND_BB_START|ZEND_BB_ENTRY)) { zend_jit_set_last_valid_opline(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start); -#endif } if (ssa->cfg.blocks[b].flags & ZEND_BB_LOOP_HEADER) { if (!zend_jit_check_timeout(&ctx, op_array->opcodes + ssa->cfg.blocks[b].start, NULL)) { @@ -3251,34 +1378,13 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } } if (!ssa->cfg.blocks[b].len) { -#ifdef ZEND_JIT_IR zend_jit_bb_end(&ctx, b); -#endif continue; } if ((JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL) && ra) { zend_ssa_phi *phi = ssa->blocks[b].phis; while (phi) { -#ifndef ZEND_JIT_IR - zend_lifetime_interval *ival = ra[phi->ssa_var]; - - if (ival) { - if (ival->flags & ZREG_LOAD) { - ZEND_ASSERT(ival->reg != ZREG_NONE); - - if (!zend_jit_load_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg)) { - goto jit_failure; - } - } else if (ival->flags & ZREG_STORE) { - ZEND_ASSERT(ival->reg != ZREG_NONE); - - if (!zend_jit_store_var(&ctx, ssa->var_info[phi->ssa_var].type, ssa->vars[phi->ssa_var].var, ival->reg, 1)) { - goto jit_failure; - } - } - } -#else zend_jit_reg_var *ival = &ra[phi->ssa_var]; if (ival->ref) { @@ -3296,8 +1402,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } } } -#endif - phi = phi->next; } } @@ -3374,11 +1478,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } op1_info = OP1_INFO(); op2_info = OP2_INFO(); -#ifndef ZEND_JIT_IR - if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { - break; - } -#endif if (!(op1_info & MAY_BE_LONG) || !(op2_info & MAY_BE_LONG)) { break; @@ -3738,9 +1837,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op OP1_DEF_INFO(), OP1_DEF_REG_ADDR(), OP2_INFO(), op2_addr, op2_def_addr, res_info, res_addr, -#ifdef ZEND_JIT_IR 0, -#endif zend_may_throw(opline, ssa_op, op_array, ssa))) { goto jit_failure; } @@ -3837,9 +1934,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op } goto done; case ZEND_DO_UCALL: -#ifndef ZEND_JIT_IR - is_terminated = 1; -#endif ZEND_FALLTHROUGH; case ZEND_DO_ICALL: case ZEND_DO_FCALL_BY_NAME: @@ -3893,10 +1987,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if ((opline->result_type & IS_TMP_VAR) && (i + 1) <= end && ((opline+1)->opcode == ZEND_JMPZ -#ifdef ZEND_JIT_IR || (opline+1)->opcode == ZEND_JMPZ_EX || (opline+1)->opcode == ZEND_JMPNZ_EX -#endif || (opline+1)->opcode == ZEND_JMPNZ) && (opline+1)->op1_type == IS_TMP_VAR && (opline+1)->op1.var == opline->result.var) { @@ -3904,13 +1996,11 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op smart_branch_opcode = (opline+1)->opcode; target_label = ssa->cfg.blocks[b].successors[0]; target_label2 = ssa->cfg.blocks[b].successors[1]; -#ifdef ZEND_JIT_IR /* For EX variant write into the result of EX opcode. */ if ((opline+1)->opcode == ZEND_JMPZ_EX || (opline+1)->opcode == ZEND_JMPNZ_EX) { res_addr = OP_REG_ADDR(opline + 1, result_type, result, result_def); } -#endif } else { smart_branch_opcode = 0; target_label = target_label2 = (uint32_t)-1; @@ -3983,49 +2073,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op op1_info, OP1_REG_ADDR())) { goto jit_failure; } -#ifndef ZEND_JIT_IR - bool left_frame = 0; - if (jit_return_label >= 0) { - if (!zend_jit_jmp(&ctx, jit_return_label)) { - goto jit_failure; - } - goto done; - } - jit_return_label = ssa->cfg.blocks_count * 2; - if (!zend_jit_label(&ctx, jit_return_label)) { - goto jit_failure; - } - if (op_array->last_var > 100) { - /* To many CVs to unroll */ - if (!zend_jit_free_cvs(&ctx)) { - goto jit_failure; - } - left_frame = 1; - } - if (!left_frame) { - int j; - - for (j = 0 ; j < op_array->last_var; j++) { - uint32_t info = zend_ssa_cv_info(op_array, ssa, j); - - if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - if (!left_frame) { - left_frame = 1; - if (!zend_jit_leave_frame(&ctx)) { - goto jit_failure; - } - } - if (!zend_jit_free_cv(&ctx, info, j)) { - goto jit_failure; - } - } - } - } - if (!zend_jit_leave_func(&ctx, op_array, opline, op1_info, left_frame, - NULL, NULL, (ssa->cfg.flags & ZEND_FUNC_INDIRECT_VAR_ACCESS) != 0, 1)) { - goto jit_failure; - } -#endif } goto done; case ZEND_BOOL: @@ -4365,9 +2412,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (!zend_jit_init_method_call(&ctx, opline, b, op_array, ssa, ssa_op, call_level, op1_info, op1_addr, ce, ce_is_instanceof, on_this, 0, NULL, NULL, 0, -#ifdef ZEND_JIT_IR -1, -1, -#endif 0)) { goto jit_failure; } @@ -4399,11 +2444,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto jit_failure; } } -#ifndef ZEND_JIT_IR - zend_jit_set_last_valid_opline(opline+1); -#else zend_jit_set_last_valid_opline(&ctx, opline+1); -#endif break; case ZEND_NOP: case ZEND_OP_DATA: @@ -4419,12 +2460,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto jit_failure; } } -#ifndef ZEND_JIT_IR - if (!zend_jit_jmp(&ctx, ssa->cfg.blocks[b].successors[0])) { - goto jit_failure; - } - is_terminated = 1; -#endif break; case ZEND_CATCH: case ZEND_FAST_CALL: @@ -4438,20 +2473,14 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op /* switch through trampoline */ case ZEND_YIELD: case ZEND_YIELD_FROM: -#ifdef ZEND_JIT_IR case ZEND_THROW: case ZEND_VERIFY_NEVER_TYPE: -#endif if (!zend_jit_tail_handler(&ctx, opline)) { goto jit_failure; } -#ifndef ZEND_JIT_IR - is_terminated = 1; -#else /* THROW and EXIT may be used in the middle of BB */ /* don't generate code for the rest of BB */ i = end; -#endif break; /* stackless execution */ case ZEND_INCLUDE_OR_EVAL: @@ -4461,9 +2490,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (!zend_jit_call(&ctx, opline, b + 1)) { goto jit_failure; } -#ifndef ZEND_JIT_IR - is_terminated = 1; -#endif break; case ZEND_JMPZ: case ZEND_JMPNZ: @@ -4522,18 +2548,8 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (!ce || !(ce->ce_flags & ZEND_ACC_LINKED) || ce->constructor) { const zend_op *next_opline = opline + 1; -#ifndef ZEND_JIT_IR - zend_jit_cond_jmp(&ctx, next_opline, ssa->cfg.blocks[b].successors[0]); - if (JIT_G(opt_level) < ZEND_JIT_LEVEL_INLINE) { - zend_jit_call(&ctx, next_opline, b + 1); - is_terminated = 1; - } else { - zend_jit_do_fcall(&ctx, next_opline, op_array, ssa, call_level, b + 1, NULL); - } -#else ZEND_ASSERT(b + 1 == ssa->cfg.blocks[b].successors[0]); zend_jit_constructor(&ctx, next_opline, op_array, ssa, call_level, b + 1); -#endif } /* We skip over the DO_FCALL, so decrement call_level ourselves. */ @@ -4548,19 +2564,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op if (i == end && (opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) { /* smart branch split across basic blocks */ -#ifndef ZEND_JIT_IR - if (!zend_jit_cond_jmp(&ctx, opline + 2, ssa->cfg.blocks[b+1].successors[0])) { - goto jit_failure; - } - if (!zend_jit_jmp(&ctx, ssa->cfg.blocks[b+1].successors[1])) { - goto jit_failure; - } - is_terminated = 1; -#else if (!zend_jit_set_cond(&ctx, opline + 2, opline->result.var)) { goto jit_failure; } -#endif } } done: @@ -4573,19 +2579,9 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op call_level--; } } -#ifdef ZEND_JIT_IR zend_jit_bb_end(&ctx, b); -#endif } -#ifndef ZEND_JIT_IR - handler = dasm_link_and_encode(&ctx, op_array, ssa, rt_opline, ra, NULL, 0, - (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) ? SP_ADJ_VM : SP_ADJ_RET, SP_ADJ_JIT); - if (!handler) { - goto jit_failure; - } - dasm_free(&ctx); -#else if (jit->return_inputs) { zend_jit_common_return(jit); @@ -4627,7 +2623,6 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op goto jit_failure; } zend_jit_free_ctx(&ctx); -#endif if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) { zend_arena_release(&CG(arena), checkpoint); @@ -4635,13 +2630,7 @@ static int zend_jit(const zend_op_array *op_array, zend_ssa *ssa, const zend_op return SUCCESS; jit_failure: -#ifndef ZEND_JIT_IR - if (ctx) { - dasm_free(&ctx); - } -#else zend_jit_free_ctx(&ctx); -#endif if (JIT_G(opt_flags) & (ZEND_JIT_REG_ALLOC_LOCAL|ZEND_JIT_REG_ALLOC_GLOBAL)) { zend_arena_release(&CG(arena), checkpoint); } @@ -5201,15 +3190,6 @@ ZEND_EXT_API void zend_jit_protect(void) static void zend_jit_init_handlers(void) { if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { -#ifndef ZEND_JIT_IR - zend_jit_runtime_jit_handler = dasm_labels[zend_lbhybrid_runtime_jit]; - zend_jit_profile_jit_handler = dasm_labels[zend_lbhybrid_profile_jit]; - zend_jit_func_hot_counter_handler = dasm_labels[zend_lbhybrid_func_hot_counter]; - zend_jit_loop_hot_counter_handler = dasm_labels[zend_lbhybrid_loop_hot_counter]; - zend_jit_func_trace_counter_handler = dasm_labels[zend_lbhybrid_func_trace_counter]; - zend_jit_ret_trace_counter_handler = dasm_labels[zend_lbhybrid_ret_trace_counter]; - zend_jit_loop_trace_counter_handler = dasm_labels[zend_lbhybrid_loop_trace_counter]; -#else zend_jit_runtime_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_runtime_jit]; zend_jit_profile_jit_handler = zend_jit_stub_handlers[jit_stub_hybrid_profile_jit]; zend_jit_func_hot_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_hot_counter]; @@ -5217,7 +3197,6 @@ static void zend_jit_init_handlers(void) zend_jit_func_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_func_trace_counter]; zend_jit_ret_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_ret_trace_counter]; zend_jit_loop_trace_counter_handler = zend_jit_stub_handlers[jit_stub_hybrid_loop_trace_counter]; -#endif } else { zend_jit_runtime_jit_handler = (const void*)zend_runtime_jit; zend_jit_profile_jit_handler = (const void*)zend_jit_profile_helper; @@ -5229,34 +3208,6 @@ static void zend_jit_init_handlers(void) } } -#ifndef ZEND_JIT_IR -static int zend_jit_make_stubs(void) -{ - dasm_State* dasm_state = NULL; - uint32_t i; - - dasm_init(&dasm_state, DASM_MAXSECTION); - dasm_setupglobal(&dasm_state, dasm_labels, zend_lb_MAX); - - for (i = 0; i < sizeof(zend_jit_stubs)/sizeof(zend_jit_stubs[0]); i++) { - dasm_setup(&dasm_state, dasm_actions); - zend_jit_align_stub(&dasm_state); - if (!zend_jit_stubs[i].stub(&dasm_state)) { - return 0; - } - if (!dasm_link_and_encode(&dasm_state, NULL, NULL, NULL, NULL, zend_jit_stubs[i].name, 0, - zend_jit_stubs[i].offset, zend_jit_stubs[i].adjustment)) { - return 0; - } - } - - zend_jit_init_handlers(); - - dasm_free(&dasm_state); - return 1; -} -#endif - static void zend_jit_globals_ctor(zend_jit_globals *jit_globals) { memset(jit_globals, 0, sizeof(zend_jit_globals)); @@ -5366,15 +3317,6 @@ ZEND_EXT_API int zend_jit_debug_config(zend_long old_val, zend_long new_val, int } return FAILURE; } -#ifdef HAVE_DISASM - if (new_val & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) { - if (JIT_G(enabled) && !JIT_G(symbols) && !zend_jit_disasm_init()) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - // TODO: symbols for JIT-ed code compiled before are missing ??? - } -#endif } return SUCCESS; } @@ -5432,10 +3374,6 @@ ZEND_EXT_API int zend_jit_check_support(void) ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached) { -#ifndef ZEND_JIT_IR - int ret; -#endif - zend_jit_halt_op = zend_get_halt_op(); zend_jit_profile_counter_rid = zend_get_op_array_extension_handle(ACCELERATOR_PRODUCT_NAME); @@ -5491,13 +3429,10 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached) if (!reattached) { zend_jit_unprotect(); *dasm_ptr = dasm_buf; -#if defined(_WIN32) && !defined(ZEND_JIT_IR) - /* reserve space for global labels */ - *dasm_ptr = (void**)*dasm_ptr + zend_lb_MAX; -#elif defined(_WIN32) && defined(ZEND_JIT_IR) +#if defined(_WIN32) zend_jit_stub_handlers = dasm_buf; *dasm_ptr = (void**)*dasm_ptr + sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0]); -#elif defined(IR_TARGET_AARCH64) && defined(ZEND_JIT_IR) +#elif defined(IR_TARGET_AARCH64) zend_jit_stub_handlers = dasm_buf; *dasm_ptr = (void**)*dasm_ptr + (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2; memset(zend_jit_stub_handlers, 0, (sizeof(zend_jit_stubs) / sizeof(zend_jit_stubs[0])) * 2 * sizeof(void*)); @@ -5505,67 +3440,12 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached) *dasm_ptr = (void*)ZEND_MM_ALIGNED_SIZE_EX(((size_t)(*dasm_ptr)), 16); zend_jit_protect(); } else { -#if (defined(_WIN32) || defined(IR_TARGET_AARCH64)) && defined(ZEND_JIT_IR) +#if defined(_WIN32) || defined(IR_TARGET_AARCH64) zend_jit_stub_handlers = dasm_buf; zend_jit_init_handlers(); #endif } -#ifndef ZEND_JIT_IR - if (zend_jit_setup() != SUCCESS) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - -#ifdef HAVE_GDB - zend_jit_gdb_init(); -#endif - -#ifdef HAVE_OPROFILE - if (JIT_G(debug) & ZEND_JIT_DEBUG_OPROFILE) { - if (!zend_jit_oprofile_startup()) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - } -#endif - -#ifdef HAVE_DISASM - if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) { - if (!zend_jit_disasm_init()) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - } -#endif - -#ifdef HAVE_PERFTOOLS - if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) { - zend_jit_perf_jitdump_open(); - } -#endif - - if (!reattached) { - zend_jit_unprotect(); - ret = zend_jit_make_stubs(); -#if defined(_WIN32) && !defined(ZEND_JIT_IR) - /* save global labels */ - memcpy(dasm_buf, dasm_labels, sizeof(void*) * zend_lb_MAX); -#endif - zend_jit_protect(); - if (!ret) { - // TODO: error reporting and cleanup ??? - return FAILURE; - } - } else { -#if defined(_WIN32) - /* restore global labels */ - memcpy(dasm_labels, dasm_buf, sizeof(void*) * zend_lb_MAX); - zend_jit_init_handlers(); -#endif - } - -#else /* ZEND_JIT_IR */ zend_jit_unprotect(); if (zend_jit_setup() != SUCCESS) { zend_jit_protect(); @@ -5574,21 +3454,12 @@ ZEND_EXT_API int zend_jit_startup(void *buf, size_t size, bool reattached) } zend_jit_protect(); zend_jit_init_handlers(); -#endif /* ZEND_JIT_IR */ if (zend_jit_trace_startup(reattached) != SUCCESS) { return FAILURE; } zend_jit_unprotect(); -#ifndef ZEND_JIT_IR -#if ZEND_JIT_TARGET_ARM64 - /* reserve space for global labels veneers */ - dasm_labels_veneers = *dasm_ptr; - *dasm_ptr = (void**)*dasm_ptr + ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT); - memset(dasm_labels_veneers, 0, sizeof(void*) * ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT)); -#endif -#endif /* save JIT buffer pos */ dasm_ptr[1] = dasm_ptr[0]; zend_jit_protect(); @@ -5602,25 +3473,7 @@ ZEND_EXT_API void zend_jit_shutdown(void) fprintf(stderr, "\nJIT memory usage: %td\n", (ptrdiff_t)((char*)*dasm_ptr - (char*)dasm_buf)); } -#ifndef ZEND_JIT_IR -#ifdef HAVE_GDB - if (JIT_G(debug) & ZEND_JIT_DEBUG_GDB) { - zend_jit_gdb_unregister(); - } -#endif - -#ifdef HAVE_DISASM - zend_jit_disasm_shutdown(); -#endif - -#ifdef HAVE_PERFTOOLS - if (JIT_G(debug) & ZEND_JIT_DEBUG_PERF_DUMP) { - zend_jit_perf_jitdump_close(); - } -#endif -#else zend_jit_shutdown_ir(); -#endif #ifdef ZTS ts_free_id(jit_globals_id); @@ -5739,12 +3592,6 @@ ZEND_EXT_API void zend_jit_restart(void) if (dasm_buf) { zend_jit_unprotect(); -#ifndef ZEND_JIT_IR //??? -#if ZEND_JIT_TARGET_ARM64 - memset(dasm_labels_veneers, 0, sizeof(void*) * ZEND_MM_ALIGNED_SIZE_EX(zend_lb_MAX, DASM_ALIGNMENT)); -#endif -#endif - /* restore JIT buffer pos */ dasm_ptr[0] = dasm_ptr[1]; @@ -5763,13 +3610,6 @@ ZEND_EXT_API void zend_jit_restart(void) } zend_jit_protect(); - -#ifdef HAVE_DISASM - if (JIT_G(debug) & (ZEND_JIT_DEBUG_ASM|ZEND_JIT_DEBUG_ASM_STUBS)) { - zend_jit_disasm_shutdown(); - zend_jit_disasm_init(); - } -#endif } } diff --git a/ext/opcache/jit/zend_jit.h b/ext/opcache/jit/zend_jit.h index 8a1aab1d03909..d9f0f72a4b69e 100644 --- a/ext/opcache/jit/zend_jit.h +++ b/ext/opcache/jit/zend_jit.h @@ -165,8 +165,6 @@ ZEND_EXT_API void zend_jit_deactivate(void); ZEND_EXT_API void zend_jit_status(zval *ret); ZEND_EXT_API void zend_jit_restart(void); -#ifdef ZEND_JIT_IR - #define ZREG_LOAD (1<<0) #define ZREG_STORE (1<<1) #define ZREG_LAST_USE (1<<2) @@ -185,39 +183,4 @@ ZEND_EXT_API void zend_jit_restart(void); #define ZREG_NONE -1 -#else -typedef struct _zend_lifetime_interval zend_lifetime_interval; -typedef struct _zend_life_range zend_life_range; - -struct _zend_life_range { - uint32_t start; - uint32_t end; - zend_life_range *next; -}; - -#define ZREG_FLAGS_SHIFT 8 - -#define ZREG_STORE (1<<0) -#define ZREG_LOAD (1<<1) -#define ZREG_LAST_USE (1<<2) -#define ZREG_SPLIT (1<<3) - -struct _zend_lifetime_interval { - int ssa_var; - union { - struct { - ZEND_ENDIAN_LOHI_3( - int8_t reg, - uint8_t flags, - uint16_t reserved - )}; - uint32_t reg_flags; - }; - zend_life_range range; - zend_lifetime_interval *hint; - zend_lifetime_interval *used_as_hint; - zend_lifetime_interval *list_next; -}; -#endif - #endif /* HAVE_JIT_H */ diff --git a/ext/opcache/jit/zend_jit_arm64.dasc b/ext/opcache/jit/zend_jit_arm64.dasc deleted file mode 100644 index 3ef9c572bc953..0000000000000 --- a/ext/opcache/jit/zend_jit_arm64.dasc +++ /dev/null @@ -1,15624 +0,0 @@ -/* - * +----------------------------------------------------------------------+ - * | Zend JIT | - * +----------------------------------------------------------------------+ - * | Copyright (c) The PHP Group | - * +----------------------------------------------------------------------+ - * | This source file is subject to version 3.01 of the PHP license, | - * | that is bundled with this package in the file LICENSE, and is | - * | available through the world-wide-web at the following url: | - * | https://www.php.net/license/3_01.txt | - * | If you did not receive a copy of the PHP license and are unable to | - * | obtain it through the world-wide-web, please send a note to | - * | license@php.net so we can mail you a copy immediately. | - * +----------------------------------------------------------------------+ - * | Authors: Dmitry Stogov | - * | Xinchen Hui | - * | Hao Sun | - * +----------------------------------------------------------------------+ - */ - -|.arch arm64 - -|.define FP, x27 -|.define IP, x28 -|.define IPl, w28 -|.define RX, x28 // the same as VM IP reused as a general purpose reg -|.define LR, x30 -|.define CARG1, x0 -|.define CARG2, x1 -|.define CARG3, x2 -|.define CARG4, x3 -|.define CARG5, x4 -|.define CARG6, x5 -|.define CARG1w, w0 -|.define CARG2w, w1 -|.define CARG3w, w2 -|.define CARG4w, w3 -|.define CARG5w, w4 -|.define CARG6w, w5 -|.define RETVALx, x0 -|.define RETVALw, w0 -|.define FCARG1x, x0 -|.define FCARG1w, w0 -|.define FCARG2x, x1 -|.define FCARG2w, w1 -|.define SPAD, 0x20 // padding for CPU stack alignment -|.define NR_SPAD, 0x30 // padding for CPU stack alignment -|.define T3, [sp, #0x28] // Used to store old value of IP (CALL VM only) -|.define T2, [sp, #0x20] // Used to store old value of FP (CALL VM only) -|.define T1, [sp, #0x10] - -// We use REG0/1/2 and FPR0/1 to replace r0/1/2 and xmm0/1 in the x86 implementation. -// Scratch registers -|.define REG0, x8 -|.define REG0w, w8 -|.define REG1, x9 -|.define REG1w, w9 -|.define REG2, x10 -|.define REG2w, w10 -|.define FPR0, d0 -|.define FPR1, d1 - -|.define ZREG_REG0, ZREG_X8 -|.define ZREG_REG1, ZREG_X9 -|.define ZREG_REG2, ZREG_X10 -|.define ZREG_FPR0, ZREG_V0 -|.define ZREG_FPR1, ZREG_V1 - -// Temporaries, not preserved across calls -|.define TMP1, x15 -|.define TMP1w, w15 -|.define TMP2, x16 -|.define TMP2w, w16 -|.define TMP3, x17 // TODO: remember about hard-coded: mrs TMP3, tpidr_el0 -|.define TMP3w, w17 -|.define FPTMP, d16 - -|.define ZREG_TMP1, ZREG_X15 -|.define ZREG_TMP2, ZREG_X16 -|.define ZREG_TMP3, ZREG_X17 -|.define ZREG_FPTMP, ZREG_V16 - -|.define HYBRID_SPAD, 32 // padding for stack alignment - -#define TMP_ZVAL_OFFSET 16 -#define DASM_ALIGNMENT 16 - -const char* zend_reg_name[] = { - "x0", "x1", "x2", "x3", "x4", "x5", "x6", "x7", - "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", - "x16", "x17", "x18", "x19", "x20", "x21", "x22", "x23", - "x24", "x25", "x26", "x27", "x28", "x29", "x30", "sp", - "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7", - "d8", "d9", "d10", "d11", "d12", "d13", "d14", "d15", - "d16", "d17", "d18", "d19", "d20", "d21", "d22", "d23", - "d24", "d25", "d26", "d27", "d28", "d29", "d30", "d31" -}; - -#define ZREG_FCARG1 ZREG_X0 -#define ZREG_FCARG2 ZREG_X1 - -|.type EX, zend_execute_data, FP -|.type OP, zend_op -|.type ZVAL, zval -|.actionlist dasm_actions -|.globals zend_lb -|.section code, cold_code, jmp_table - -static void* dasm_labels[zend_lb_MAX]; - -#if ZTS -static size_t tsrm_ls_cache_tcb_offset = 0; -# ifdef __APPLE__ -struct TLVDescriptor { - void* (*thunk)(struct TLVDescriptor*); - uint64_t key; - uint64_t offset; -}; -typedef struct TLVDescriptor TLVDescriptor; -# endif -#endif - -#define IS_SIGNED_32BIT(val) ((((intptr_t)(val)) <= 0x7fffffff) && (((intptr_t)(val)) >= (-2147483647 - 1))) - -/* Encoding of immediate. */ -#define MAX_IMM12 0xfff // maximum value for imm12 -#define MAX_IMM16 0xffff // maximum value for imm16 -#define MOVZ_IMM MAX_IMM16 // movz insn -#define LDR_STR_PIMM64 (MAX_IMM12*8) // ldr/str insn for 64-bit register: pimm is imm12 * 8 -#define LDR_STR_PIMM32 (MAX_IMM12*4) // ldr/str insn for 32-bit register: pimm is imm12 * 4 -#define LDRB_STRB_PIMM MAX_IMM12 // ldrb/strb insn - -#define B_IMM (1<<27) // signed imm26 * 4 -#define ADR_IMM (1<<20) // signed imm21 -#define ADRP_IMM (1LL<<32) // signed imm21 * 4096 - -static bool arm64_may_use_b(const void *addr) -{ - if (addr >= dasm_buf && addr < dasm_end) { - return (((char*)dasm_end - (char*)dasm_buf) < B_IMM); - } else if (addr >= dasm_end) { - return (((char*)addr - (char*)dasm_buf) < B_IMM); - } else if (addr < dasm_buf) { - return (((char*)dasm_end - (char*)addr) < B_IMM); - } - return 0; -} - -static bool arm64_may_use_adr(const void *addr) -{ - if (addr >= dasm_buf && addr < dasm_end) { - return (((char*)dasm_end - (char*)dasm_buf) < ADR_IMM); - } else if (addr >= dasm_end) { - return (((char*)addr - (char*)dasm_buf) < ADR_IMM); - } else if (addr < dasm_buf) { - return (((char*)dasm_end - (char*)addr) < ADR_IMM); - } - return 0; -} - -static bool arm64_may_use_adrp(const void *addr) -{ - if (addr >= dasm_buf && addr < dasm_end) { - return (((char*)dasm_end - (char*)dasm_buf) < ADRP_IMM); - } else if (addr >= dasm_end) { - return (((char*)addr - (char*)dasm_buf) < ADRP_IMM); - } else if (addr < dasm_buf) { - return (((char*)dasm_end - (char*)addr) < ADRP_IMM); - } - return 0; -} - -/* Determine whether "val" falls into two allowed ranges: - * Range 1: [0, 0xfff] - * Range 2: LSL #12 to Range 1 - * Used to guard the immediate encoding for add/adds/sub/subs/cmp/cmn instructions. */ -static bool arm64_may_encode_imm12(const int64_t val) -{ - return (val >= 0 && (val <= MAX_IMM12 || !(val & 0xffffffffff000fff))); -} - -/* Determine whether an immediate value can be encoded as the immediate operand of logical instructions. */ -static bool logical_immediate_p(uint64_t value, uint32_t reg_size) -{ - /* fast path: power of two */ - if (value > 0 && !(value & (value - 1))) { - return true; - } - - if (reg_size == 32) { - if (dasm_imm13((uint32_t)value, (uint32_t)value) != -1) { - return true; - } - } else if (reg_size == 64) { - if (dasm_imm13((uint32_t)value, (uint32_t)(value >> 32)) != -1) { - return true; - } - } else { - ZEND_UNREACHABLE(); - } - - return false; -} - -/* Not Implemented Yet */ -|.macro NIY -|| //ZEND_ASSERT(0); -| brk #0 -|.endmacro - -|.macro NIY_STUB -|| //ZEND_ASSERT(0); -| brk #0 -|.endmacro - -|.macro ADD_HYBRID_SPAD -||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE -| add sp, sp, # HYBRID_SPAD -||#endif -|.endmacro - -|.macro SUB_HYBRID_SPAD -||#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE -| sub sp, sp, # HYBRID_SPAD -||#endif -|.endmacro - -/* Move address into register. TODO: Support 52-bit address */ -|.macro LOAD_ADDR, reg, addr -| // 48-bit virtual address -|| if (((uintptr_t)(addr)) == 0) { -| mov reg, xzr -|| } else if (((uintptr_t)(addr)) <= MOVZ_IMM) { -| movz reg, #((uint64_t)(addr)) -|| } else if (arm64_may_use_adr((void*)(addr))) { -| adr reg, &addr -|| } else if (arm64_may_use_adrp((void*)(addr))) { -| adrp reg, &(((uintptr_t)(addr))) -|| if (((uintptr_t)(addr)) & 0xfff) { -| add reg, reg, #(((uintptr_t)(addr)) & 0xfff) -|| } -|| } else if ((uintptr_t)(addr) & 0xffff) { -| movz reg, #((uintptr_t)(addr) & 0xffff) -|| if (((uintptr_t)(addr) >> 16) & 0xffff) { -| movk reg, #(((uintptr_t)(addr) >> 16) & 0xffff), lsl #16 -|| } -|| if (((uintptr_t)(addr) >> 32) & 0xffff) { -| movk reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32 -|| } -|| } else if (((uintptr_t)(addr) >> 16) & 0xffff) { -| movz reg, #(((uintptr_t)(addr) >> 16) & 0xffff), lsl #16 -|| if (((uintptr_t)(addr) >> 32) & 0xffff) { -| movk reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32 -|| } -|| } else { -| movz reg, #(((uintptr_t)(addr) >> 32) & 0xffff), lsl #32 -|| } -|.endmacro - -/* Move 32-bit immediate value into register. */ -|.macro LOAD_32BIT_VAL, reg, val -|| if (((uint32_t)(val)) <= MOVZ_IMM) { -| movz reg, #((uint32_t)(val)) -|| } else if (((uint32_t)(val) & 0xffff)) { -| movz reg, #((uint32_t)(val) & 0xffff) -|| if ((((uint32_t)(val) >> 16) & 0xffff)) { -| movk reg, #(((uint32_t)(val) >> 16) & 0xffff), lsl #16 -|| } -|| } else { -| movz reg, #(((uint32_t)(val) >> 16) & 0xffff), lsl #16 -|| } -|.endmacro - -/* Move 64-bit immediate value into register. */ -|.macro LOAD_64BIT_VAL, reg, val -|| if (((uint64_t)(val)) == 0) { -| mov reg, xzr -|| } else if (((uint64_t)(val)) <= MOVZ_IMM) { -| movz reg, #((uint64_t)(val)) -|| } else if (~((uint64_t)(val)) <= MOVZ_IMM) { -| movn reg, #(~((uint64_t)(val))) -|| } else if ((uint64_t)(val) & 0xffff) { -| movz reg, #((uint64_t)(val) & 0xffff) -|| if (((uint64_t)(val) >> 16) & 0xffff) { -| movk reg, #(((uint64_t)(val) >> 16) & 0xffff), lsl #16 -|| } -|| if (((uint64_t)(val) >> 32) & 0xffff) { -| movk reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32 -|| } -|| if ((((uint64_t)(val) >> 48) & 0xffff)) { -| movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48 -|| } -|| } else if (((uint64_t)(val) >> 16) & 0xffff) { -| movz reg, #(((uint64_t)(val) >> 16) & 0xffff), lsl #16 -|| if (((uint64_t)(val) >> 32) & 0xffff) { -| movk reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32 -|| } -|| if ((((uint64_t)(val) >> 48) & 0xffff)) { -| movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48 -|| } -|| } else if (((uint64_t)(val) >> 32) & 0xffff) { -| movz reg, #(((uint64_t)(val) >> 32) & 0xffff), lsl #32 -|| if ((((uint64_t)(val) >> 48) & 0xffff)) { -| movk reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48 -|| } -|| } else { -| movz reg, #(((uint64_t)(val) >> 48) & 0xffff), lsl #48 -|| } -|.endmacro - -/* Extract the low 8 bits from 'src_reg' into 'dst_reg'. - * Note: 0xff can be encoded as imm for 'and' instruction. */ -|.macro GET_LOW_8BITS, dst_reg, src_reg -| and dst_reg, src_reg, #0xff -|.endmacro - -/* Bitwise operation with immediate. 'bw_ins' can be and/orr/eor/ands. - * 32-bit and 64-bit registers are distinguished. */ -|.macro BW_OP_32_WITH_CONST, bw_ins, dst_reg, src_reg1, val, tmp_reg -|| if (val == 0) { -| bw_ins dst_reg, src_reg1, wzr -|| } else if (logical_immediate_p((uint32_t)val, 32)) { -| bw_ins dst_reg, src_reg1, #val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| bw_ins dst_reg, src_reg1, tmp_reg -|| } -|.endmacro - -|.macro BW_OP_64_WITH_CONST, bw_ins, dst_reg, src_reg1, val, tmp_reg -|| if (val == 0) { -| bw_ins dst_reg, src_reg1, xzr -|| } else if (logical_immediate_p(val, 64)) { -| bw_ins dst_reg, src_reg1, #val -|| } else { -| LOAD_64BIT_VAL tmp_reg, val -| bw_ins dst_reg, src_reg1, tmp_reg -|| } -|.endmacro - -/* Test bits 'tst' with immediate. 32-bit and 64-bit registers are distinguished. */ -|.macro TST_32_WITH_CONST, reg, val, tmp_reg -|| if (val == 0) { -| tst reg, wzr -|| } else if (logical_immediate_p((uint32_t)val, 32)) { -| tst reg, #val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| tst reg, tmp_reg -|| } -|.endmacro - -|.macro TST_64_WITH_CONST, reg, val, tmp_reg -|| if (val == 0) { -| tst reg, xzr -|| } else if (logical_immediate_p(val, 64)) { -| tst reg, #val -|| } else { -| LOAD_64BIT_VAL tmp_reg, val -| tst reg, tmp_reg -|| } -|.endmacro - -/* Test bits between 64-bit register with constant 1. */ -|.macro TST_64_WITH_ONE, reg -| tst reg, #1 -|.endmacro - -/* Compare a register value with immediate. 32-bit and 64-bit registers are distinguished. - * Note: Comparing 64-bit register with 32-bit immediate is handled in CMP_64_WITH_CONST_32. */ -|.macro CMP_32_WITH_CONST, reg, val, tmp_reg -|| if (val == 0) { -| cmp reg, wzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| cmp reg, #val -|| } else if (arm64_may_encode_imm12((int64_t)(-val))) { -| cmn reg, #-val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| cmp reg, tmp_reg -|| } -|.endmacro - -|.macro CMP_64_WITH_CONST_32, reg, val, tmp_reg -|| if (val == 0) { -| cmp reg, xzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| cmp reg, #val -|| } else if (arm64_may_encode_imm12((int64_t)(-val))) { -| cmn reg, #-val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| cmp reg, tmp_reg -|| } -|.endmacro - -|.macro CMP_64_WITH_CONST, reg, val, tmp_reg -|| if (val == 0) { -| cmp reg, xzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| cmp reg, #val -|| } else if (arm64_may_encode_imm12((int64_t)(-val))) { -| cmn reg, #-val -|| } else { -| LOAD_64BIT_VAL tmp_reg, val -| cmp reg, tmp_reg -|| } -|.endmacro - -/* Add/sub a register value with immediate. 'add_sub_ins' can be add/sub/adds/subs. - * 32-bit and 64-bit registers are distinguished. - * Note: Case of 64-bit register with 32-bit immediate is handled in ADD_SUB_64_WITH_CONST_32. */ -|.macro ADD_SUB_32_WITH_CONST, add_sub_ins, dst_reg, src_reg1, val, tmp_reg -|| if (val == 0) { -| add_sub_ins dst_reg, src_reg1, wzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| add_sub_ins dst_reg, src_reg1, #val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| add_sub_ins dst_reg, src_reg1, tmp_reg -|| } -|.endmacro - -|.macro ADD_SUB_64_WITH_CONST_32, add_sub_ins, dst_reg, src_reg1, val, tmp_reg -|| if (val == 0) { -| add_sub_ins dst_reg, src_reg1, xzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| add_sub_ins dst_reg, src_reg1, #val -|| } else { -| LOAD_32BIT_VAL tmp_reg, val -| add_sub_ins dst_reg, src_reg1, tmp_reg -|| } -|.endmacro - -|.macro ADD_SUB_64_WITH_CONST, add_sub_ins, dst_reg, src_reg1, val, tmp_reg -|| if (val == 0) { -| add_sub_ins dst_reg, src_reg1, xzr -|| } else if (arm64_may_encode_imm12((int64_t)(val))) { -| add_sub_ins dst_reg, src_reg1, #val -|| } else { -| LOAD_64BIT_VAL tmp_reg, val -| add_sub_ins dst_reg, src_reg1, tmp_reg -|| } -|.endmacro - -/* Memory access(load/store) with 32-bit 'offset'. - * Use "unsigned offset" variant if 'offset' can be encoded, otherwise move 'offset' into temp register. - * 8-bit, 32-bit and 64-bit registers to be transferred are distinguished. - * Note: 'reg' can be used as 'tmp_reg' if 1) 'reg' is one GPR, AND 2) 'reg' != 'base_reg', AND 3) ins is 'ldr'. */ -|.macro MEM_ACCESS_64_WITH_UOFFSET, ldr_str_ins, reg, base_reg, offset, tmp_reg -|| if (((uintptr_t)(offset)) > LDR_STR_PIMM64) { -| LOAD_32BIT_VAL tmp_reg, offset -| ldr_str_ins reg, [base_reg, tmp_reg] -|| } else { -| ldr_str_ins reg, [base_reg, #(offset)] -|| } -|.endmacro - -|.macro MEM_ACCESS_32_WITH_UOFFSET, ldr_str_ins, reg, base_reg, offset, tmp_reg -|| if (((uintptr_t)(offset)) > LDR_STR_PIMM32) { -| LOAD_32BIT_VAL tmp_reg, offset -| ldr_str_ins reg, [base_reg, tmp_reg] -|| } else { -| ldr_str_ins reg, [base_reg, #(offset)] -|| } -|.endmacro - -|.macro MEM_ACCESS_8_WITH_UOFFSET, ldrb_strb_ins, reg, base_reg, offset, tmp_reg -|| if (((uintptr_t)(offset)) > LDRB_STRB_PIMM) { -| LOAD_32BIT_VAL tmp_reg, offset -| ldrb_strb_ins reg, [base_reg, tmp_reg] -|| } else { -| ldrb_strb_ins reg, [base_reg, #(offset)] -|| } -|.endmacro - -/* Memory access(load/store) with 64-bit 'offset'. - * Use "unsigned offset" variant if 'offset' can be encoded, otherwise move 'offset' into temp register. */ -|.macro MEM_ACCESS_64_WITH_UOFFSET_64, ldr_str_ins, reg, base_reg, offset, tmp_reg -|| if (((uintptr_t)(offset)) > LDR_STR_PIMM64) { -| LOAD_64BIT_VAL tmp_reg, offset -| ldr_str_ins reg, [base_reg, tmp_reg] -|| } else { -| ldr_str_ins reg, [base_reg, #(offset)] -|| } -|.endmacro - -/* ZTS: get thread local variable "_tsrm_ls_cache" */ -|.macro LOAD_TSRM_CACHE, reg -||#ifdef __APPLE__ -| .long 0xd53bd071 // TODO: hard-coded: mrs TMP3, tpidrro_el0 -| and TMP3, TMP3, #0xfffffffffffffff8 -| MEM_ACCESS_64_WITH_UOFFSET_64 ldr, TMP3, TMP3, (((TLVDescriptor*)tsrm_ls_cache_tcb_offset)->key << 3), TMP1 -| MEM_ACCESS_64_WITH_UOFFSET_64 ldr, reg, TMP3, (((TLVDescriptor*)tsrm_ls_cache_tcb_offset)->offset), TMP1 -||#else -| .long 0xd53bd051 // TODO: hard-coded: mrs TMP3, tpidr_el0 -|| ZEND_ASSERT(tsrm_ls_cache_tcb_offset <= LDR_STR_PIMM64); -| ldr reg, [TMP3, #tsrm_ls_cache_tcb_offset] -||#endif -|.endmacro - -|.macro LOAD_ADDR_ZTS, reg, struct, field -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| ADD_SUB_64_WITH_CONST_32 add, reg, TMP3, (struct.._offset + offsetof(zend_..struct, field)), reg -| .else -| LOAD_ADDR reg, &struct.field -| .endif -|.endmacro - -/* Store address 'addr' into memory 'mem'. */ -|.macro ADDR_STORE, mem, addr, tmp_reg -| LOAD_ADDR tmp_reg, addr -| str tmp_reg, mem -|.endmacro - -/* Store a register value 'reg' into memory 'addr'. - * For ZTS mode, base register with unsigned offset variant is used, - * and 8-bit/32-bit/64-bit registers to be transferred are distinguished. */ -|.macro MEM_STORE, str_ins, reg, addr, tmp_reg -|| if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adr((void*)(addr))) { -| adr tmp_reg, &addr -| str_ins reg, [tmp_reg] -|| } else if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adrp((void*)(addr))) { -| adrp tmp_reg, &(((uintptr_t)(addr))) -| str_ins reg, [tmp_reg, #(((uintptr_t)(addr)) & 0xfff)] -|| } else { -| LOAD_ADDR tmp_reg, addr -| str_ins reg, [tmp_reg] -|| } -|.endmacro - -|.macro MEM_STORE_64_ZTS, str_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_64_WITH_UOFFSET str_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_STORE str_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -|.macro MEM_STORE_32_ZTS, str_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_32_WITH_UOFFSET str_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_STORE str_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -|.macro MEM_STORE_8_ZTS, strb_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_8_WITH_UOFFSET strb_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_STORE strb_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -/* Load value from memory 'addr' and write it into register 'reg'. - * For ZTS mode, base register with unsigned offset variant is used, - * and 8-bit/32-bit/64-bit registers to be transferred are distinguished. */ -|.macro MEM_LOAD, ldr_ins, reg, addr, tmp_reg -|| if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adr((void*)(addr))) { -| adr tmp_reg, &addr -| ldr_ins reg, [tmp_reg] -|| } else if (((uintptr_t)(addr)) > MOVZ_IMM && arm64_may_use_adrp((void*)(addr))) { -| adrp tmp_reg, &(((uintptr_t)(addr))) -| ldr_ins reg, [tmp_reg, #(((uintptr_t)(addr)) & 0xfff)] -|| } else { -| LOAD_ADDR tmp_reg, addr -| ldr_ins reg, [tmp_reg] -|| } -|.endmacro - -|.macro MEM_LOAD_64_ZTS, ldr_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_64_WITH_UOFFSET ldr_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_LOAD ldr_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -|.macro MEM_LOAD_32_ZTS, ldr_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_32_WITH_UOFFSET ldr_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_LOAD ldr_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -|.macro MEM_LOAD_8_ZTS, ldrb_ins, reg, struct, field, tmp_reg -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_8_WITH_UOFFSET ldrb_ins, reg, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| .else -| MEM_LOAD ldrb_ins, reg, &struct.field, tmp_reg -| .endif -|.endmacro - -/* Conduct arithmetic operation between the value in memory 'addr' and register value in 'reg', - * and the computation result is stored back in 'reg'. 'op_ins' can be add/sub. */ -|.macro MEM_LOAD_OP, op_ins, ldr_ins, reg, addr, tmp_reg1, tmp_reg2 -| MEM_LOAD ldr_ins, tmp_reg1, addr, tmp_reg2 -| op_ins reg, reg, tmp_reg1 -|.endmacro - -|.macro MEM_LOAD_OP_ZTS, op_ins, ldr_ins, reg, struct, field, tmp_reg1, tmp_reg2 -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -| MEM_ACCESS_64_WITH_UOFFSET ldr_ins, tmp_reg2, TMP3, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg1 -| op_ins reg, reg, tmp_reg2 -| .else -| MEM_LOAD_OP op_ins, ldr_ins, reg, &struct.field, tmp_reg1, tmp_reg2 -| .endif -|.endmacro - -/* Conduct arithmetic operation between the value in memory 'addr' and operand 'op', and the computation - * result is stored back to memory 'addr'. Operand 'op' can be either a register value or an immediate value. - * Currently, only add instruction is used as 'op_ins'. - * Note: It should be guaranteed that the immediate value can be encoded for 'op_ins'. */ -|.macro MEM_UPDATE, op_ins, ldr_ins, str_ins, op, addr, tmp_reg1, tmp_reg2 -| LOAD_ADDR tmp_reg2, addr -| ldr_ins, tmp_reg1, [tmp_reg2] -| op_ins tmp_reg1, tmp_reg1, op -| str_ins tmp_reg1, [tmp_reg2] -|.endmacro - -|.macro MEM_UPDATE_ZTS, op_ins, ldr_ins, str_ins, op, struct, field, tmp_reg1, tmp_reg2 -| .if ZTS -| LOAD_TSRM_CACHE TMP3 -|| if (((uintptr_t)(struct.._offset+offsetof(zend_..struct, field))) > LDR_STR_PIMM64) { -| LOAD_32BIT_VAL tmp_reg1, (struct.._offset+offsetof(zend_..struct, field)) -| ldr_ins tmp_reg2, [TMP3, tmp_reg1] -| op_ins tmp_reg2, tmp_reg2, op -| str_ins tmp_reg2, [TMP3, tmp_reg1] -|| } else { -| ldr_ins tmp_reg2, [TMP3, #(struct.._offset+offsetof(zend_..struct, field))] -| op_ins tmp_reg2, tmp_reg2, op -| str_ins tmp_reg2, [TMP3, #(struct.._offset+offsetof(zend_..struct, field))] -|| } -| .else -| MEM_UPDATE op_ins, ldr_ins, str_ins, op, &struct.field, tmp_reg1, tmp_reg2 -| .endif -|.endmacro - -|.macro EXT_CALL, func, tmp_reg -|| if (arm64_may_use_b(func)) { -| bl &func -|| } else { -| LOAD_ADDR tmp_reg, func -| blr tmp_reg -|| } -|.endmacro - -|.macro EXT_JMP, func, tmp_reg -|| if (arm64_may_use_b(func)) { -| b &func -|| } else { -| LOAD_ADDR tmp_reg, func -| br tmp_reg -|| } -|.endmacro - -|.macro SAVE_IP -|| if (GCC_GLOBAL_REGS) { -| str IP, EX->opline -|| } -|.endmacro - -|.macro LOAD_IP -|| if (GCC_GLOBAL_REGS) { -| ldr IP, EX->opline -|| } -|.endmacro - -|.macro LOAD_IP_ADDR, addr -|| if (GCC_GLOBAL_REGS) { -| LOAD_ADDR IP, addr -|| } else { -| ADDR_STORE EX->opline, addr, RX -|| } -|.endmacro - -|.macro LOAD_IP_ADDR_ZTS, struct, field, tmp_reg -| .if ZTS -|| if (GCC_GLOBAL_REGS) { -| LOAD_TSRM_CACHE IP -| MEM_ACCESS_64_WITH_UOFFSET ldr, IP, IP, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -|| } else { -| LOAD_TSRM_CACHE RX -| ADD_SUB_64_WITH_CONST_32 add, RX, RX, (struct.._offset+offsetof(zend_..struct, field)), tmp_reg -| str RX, EX->opline -|| } -| .else -| LOAD_IP_ADDR &struct.field -| .endif -|.endmacro - -|.macro GET_IP, reg -|| if (GCC_GLOBAL_REGS) { -| mov reg, IP -|| } else { -| ldr reg, EX->opline -|| } -|.endmacro - -/* Update IP with register 'reg'. Note: shift variant is handled by ADD_IP_SHIFT. */ -|.macro ADD_IP, reg, tmp_reg -|| if (GCC_GLOBAL_REGS) { -| add IP, IP, reg -|| } else { -| ldr tmp_reg, EX->opline -| add tmp_reg, tmp_reg, reg -| str tmp_reg, EX->opline -|| } -|.endmacro - -|.macro ADD_IP_SHIFT, reg, shift, tmp_reg -|| if (GCC_GLOBAL_REGS) { -| add IP, IP, reg, shift -|| } else { -| ldr tmp_reg, EX->opline -| add tmp_reg, tmp_reg, reg, shift -| str tmp_reg, EX->opline -|| } -|.endmacro - -/* Update IP with 32-bit immediate 'val'. */ -|.macro ADD_IP_WITH_CONST, val, tmp_reg -|| ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(val))); -|| if (GCC_GLOBAL_REGS) { -| add IP, IP, #val -|| } else { -| ldr tmp_reg, EX->opline -| add tmp_reg, tmp_reg, #val -| str tmp_reg, EX->opline -|| } -|.endmacro - -|.macro JMP_IP, tmp_reg -|| if (GCC_GLOBAL_REGS) { -| ldr tmp_reg, [IP] -| br tmp_reg -|| } else { -| ldr tmp_reg, EX:CARG1->opline -| br tmp_reg -|| } -|.endmacro - -|.macro CMP_IP, addr, tmp_reg1, tmp_reg2 -| LOAD_ADDR tmp_reg1, addr -|| if (GCC_GLOBAL_REGS) { -| cmp IP, tmp_reg1 -|| } else { -| ldr tmp_reg2, EX->opline -| cmp tmp_reg2, tmp_reg1 -|| } -|.endmacro - -|.macro LOAD_ZVAL_ADDR, reg, addr -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| LOAD_ADDR reg, Z_ZV(addr) -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -|| if (Z_OFFSET(addr)) { -| ADD_SUB_64_WITH_CONST_32 add, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), reg -|| } else { -|| if (Z_REG(addr) == ZREG_RSP) { -| mov reg, sp -|| } else { -| mov reg, Rx(Z_REG(addr)) -|| } -|| } -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro GET_Z_TYPE_INFO, reg, zv -| ldr reg, [zv, #offsetof(zval,u1.type_info)] -|.endmacro - -|.macro SET_Z_TYPE_INFO, zv, type, tmp_reg -| LOAD_32BIT_VAL tmp_reg, type -| str tmp_reg, [zv, #offsetof(zval,u1.type_info)] -|.endmacro - -|.macro GET_ZVAL_TYPE, reg, addr, tmp_reg -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_8_WITH_UOFFSET ldrb, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.v.type), tmp_reg -|.endmacro - -|.macro GET_ZVAL_TYPE_INFO, reg, addr, tmp_reg -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_32_WITH_UOFFSET ldr, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg -|.endmacro - -|.macro SET_ZVAL_TYPE_INFO, addr, type, tmp_reg1, tmp_reg2 -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| LOAD_32BIT_VAL tmp_reg1, type -| MEM_ACCESS_32_WITH_UOFFSET str, tmp_reg1, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg2 -|.endmacro - -|.macro SET_ZVAL_TYPE_INFO_FROM_REG, addr, reg, tmp_reg -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_32_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr)+offsetof(zval,u1.type_info), tmp_reg -|.endmacro - -|.macro GET_Z_PTR, reg, zv -| ldr reg, [zv] -|.endmacro - -|.macro GET_ZVAL_PTR, reg, addr, tmp_reg -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_64_WITH_UOFFSET ldr, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -|.endmacro - -|.macro SET_ZVAL_PTR, addr, reg, tmp_reg -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_64_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -|.endmacro - -|.macro UNDEF_OPLINE_RESULT, tmp_reg -| ldr REG0, EX->opline -| ldr REG0w, OP:REG0->result.var -| add REG0, FP, REG0 -| SET_Z_TYPE_INFO REG0, IS_UNDEF, tmp_reg -|.endmacro - -|.macro UNDEF_OPLINE_RESULT_IF_USED, tmp_reg1, tmp_reg2 -| ldrb tmp_reg1, OP:RX->result_type -| TST_32_WITH_CONST tmp_reg1, (IS_TMP_VAR|IS_VAR), tmp_reg2 -| beq >1 -| ldr REG0w, OP:RX->result.var -| add REG0, FP, REG0 -| SET_Z_TYPE_INFO REG0, IS_UNDEF, tmp_reg1 -|1: -|.endmacro - -/* Floating-point comparison between register 'reg' and value from memory 'addr'. - * Note: the equivalent macros in JIT/x86 are SSE_AVX_OP and SSE_OP. */ -|.macro DOUBLE_CMP, reg, addr, tmp_reg, fp_tmp_reg -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| MEM_LOAD ldr, Rd(fp_tmp_reg-ZREG_V0), Z_ZV(addr), Rx(tmp_reg) -| fcmp Rd(reg-ZREG_V0), Rd(fp_tmp_reg-ZREG_V0) -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, Rd(fp_tmp_reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg) -| fcmp Rd(reg-ZREG_V0), Rd(fp_tmp_reg-ZREG_V0) -|| } else if (Z_MODE(addr) == IS_REG) { -| fcmp Rd(reg-ZREG_V0), Rd(Z_REG(addr)-ZREG_V0) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -/* Convert LONG value 'val' into DOUBLE type, and move it into FP register 'reg'. - * Note: the equivalent macro in JIT/x86 is SSE_GET_LONG. */ -|.macro DOUBLE_GET_LONG, reg, val, tmp_reg -|| if (val == 0) { -| fmov Rd(reg-ZREG_V0), xzr // TODO: "movi d0, #0" is not recognized by DynASM/arm64 -|| } else { -| LOAD_64BIT_VAL Rx(tmp_reg), val -| scvtf Rd(reg-ZREG_V0), Rx(tmp_reg) -|| } -|.endmacro - -/* Convert LONG value from memory 'addr' into DOUBLE type, and move it into FP register 'reg'. - * Note: the equivalent macro in JIT/x86 is SSE_GET_ZVAL_LVAL. */ -|.macro DOUBLE_GET_ZVAL_LVAL, reg, addr, tmp_reg1, tmp_reg2 -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| DOUBLE_GET_LONG reg, Z_LVAL_P(Z_ZV(addr)), tmp_reg1 -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, Rx(tmp_reg1), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg2) -| scvtf Rd(reg-ZREG_V0), Rx(tmp_reg1) -|| } else if (Z_MODE(addr) == IS_REG) { -| scvtf Rd(reg-ZREG_V0), Rx(Z_REG(addr)) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -/* Floating-point arithmetic operation between two FP registers. - * Note: the equivalent macro in JIT/x86 is AVX_MATH_REG. */ -|.macro DOUBLE_MATH_REG, opcode, dst_reg, op1_reg, op2_reg -|| switch (opcode) { -|| case ZEND_ADD: -| fadd Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0) -|| break; -|| case ZEND_SUB: -| fsub Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0) -|| break; -|| case ZEND_MUL: -| fmul Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0) -|| break; -|| case ZEND_DIV: -| fdiv Rd(dst_reg-ZREG_V0), Rd(op1_reg-ZREG_V0), Rd(op2_reg-ZREG_V0) -|| break; -|| } -|.endmacro - -/* Conduct binary operation between register 'reg' and value from memory 'addr', - * and the computation result is stored in 'reg'. - * For LONG_ADD_SUB, 'add_sub_ins' can be adds/subs. For LONG_BW_OP, 'bw_ins' can be and/orr/eor. - * For LONG_CMP, 'cmp' instruction is used by default and only flag registers are affected. - * Note: the equivalent macro in JIT/x86 is LONG_OP. */ -|.macro LONG_ADD_SUB, add_sub_ins, reg, addr, tmp_reg -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| ADD_SUB_64_WITH_CONST add_sub_ins, Rx(reg), Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -| add_sub_ins Rx(reg), Rx(reg), tmp_reg -|| } else if (Z_MODE(addr) == IS_REG) { -| add_sub_ins Rx(reg), Rx(reg), Rx(Z_REG(addr)) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro LONG_BW_OP, bw_ins, reg, addr, tmp_reg -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| BW_OP_64_WITH_CONST bw_ins, Rx(reg), Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -| bw_ins Rx(reg), Rx(reg), tmp_reg -|| } else if (Z_MODE(addr) == IS_REG) { -| bw_ins Rx(reg), Rx(reg), Rx(Z_REG(addr)) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro LONG_CMP, reg, addr, tmp_reg -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| CMP_64_WITH_CONST Rx(reg), Z_LVAL_P(Z_ZV(addr)), tmp_reg -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -| cmp Rx(reg), tmp_reg -|| } else if (Z_MODE(addr) == IS_REG) { -| cmp Rx(reg), Rx(Z_REG(addr)) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -/* Conduct add/sub between value from memory 'addr' and an immediate value 'val', and - * the computation result is stored back into 'addr'. - * Note: it should be guaranteed that 'val' can be encoded into add/sub instruction. */ -|.macro LONG_ADD_SUB_WITH_IMM, add_sub_ins, addr, val, tmp_reg1, tmp_reg2 -|| ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(val))); -|| if (Z_MODE(addr) == IS_MEM_ZVAL) { -|| if (((uint32_t)(Z_OFFSET(addr))) > LDR_STR_PIMM64) { -| LOAD_32BIT_VAL tmp_reg2, Z_OFFSET(addr) -| ldr tmp_reg1, [Rx(Z_REG(addr)), tmp_reg2] -| add_sub_ins tmp_reg1, tmp_reg1, #val -| str tmp_reg1, [Rx(Z_REG(addr)), tmp_reg2] -|| } else { -| ldr tmp_reg1, [Rx(Z_REG(addr)), #Z_OFFSET(addr)] -| add_sub_ins tmp_reg1, tmp_reg1, #val -| str tmp_reg1, [Rx(Z_REG(addr)), #Z_OFFSET(addr)] -|| } -|| } else if (Z_MODE(addr) == IS_REG) { -| add_sub_ins Rx(Z_REG(addr)), Rx(Z_REG(addr)), #val -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -/* Compare value from memory 'addr' with immediate value 'val'. - * Note: the equivalent macro in JIT/x86 is LONG_OP_WITH_CONST. */ -|.macro LONG_CMP_WITH_CONST, addr, val, tmp_reg1, tmp_reg2 -|| if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, tmp_reg1, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg2 -| CMP_64_WITH_CONST tmp_reg1, val, tmp_reg2 -|| } else if (Z_MODE(addr) == IS_REG) { -| CMP_64_WITH_CONST Rx(Z_REG(addr)), val, tmp_reg1 -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro GET_ZVAL_LVAL, reg, addr, tmp_reg -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -|| if (Z_LVAL_P(Z_ZV(addr)) == 0) { -| mov Rx(reg), xzr -|| } else { -| LOAD_64BIT_VAL Rx(reg), Z_LVAL_P(Z_ZV(addr)) -|| } -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, Rx(reg), Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -|| } else if (Z_MODE(addr) == IS_REG) { -|| if (reg != Z_REG(addr)) { -| mov Rx(reg), Rx(Z_REG(addr)) -|| } -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro LONG_MATH, opcode, reg, addr, tmp_reg1 -|| switch (opcode) { -|| case ZEND_ADD: -| LONG_ADD_SUB adds, reg, addr, tmp_reg1 -|| break; -|| case ZEND_SUB: -| LONG_ADD_SUB subs, reg, addr, tmp_reg1 -|| break; -|| case ZEND_BW_OR: -| LONG_BW_OP orr, reg, addr, tmp_reg1 -|| break; -|| case ZEND_BW_AND: -| LONG_BW_OP and, reg, addr, tmp_reg1 -|| break; -|| case ZEND_BW_XOR: -| LONG_BW_OP eor, reg, addr, tmp_reg1 -|| break; -|| default: -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -|.macro LONG_MATH_REG, opcode, dst_reg, src_reg1, src_reg2 -|| switch (opcode) { -|| case ZEND_ADD: -| adds dst_reg, src_reg1, src_reg2 -|| break; -|| case ZEND_SUB: -| subs dst_reg, src_reg1, src_reg2 -|| break; -|| case ZEND_BW_OR: -| orr dst_reg, src_reg1, src_reg2 -|| break; -|| case ZEND_BW_AND: -| and dst_reg, src_reg1, src_reg2 -|| break; -|| case ZEND_BW_XOR: -| eor dst_reg, src_reg1, src_reg2 -|| break; -|| default: -|| ZEND_UNREACHABLE(); -|| } -|.endmacro - -/* Store LONG value into memory 'addr'. - * This LONG value can be an immediate value i.e. 'val' in macro SET_ZVAL_LVAL, or - * a register value i.e. 'reg' in macro SET_ZVAL_LVAL_FROM_REG. */ -|.macro SET_ZVAL_LVAL_FROM_REG, addr, reg, tmp_reg -|| if (Z_MODE(addr) == IS_REG) { -| mov Rx(Z_REG(addr)), reg -|| } else { -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_64_WITH_UOFFSET str, reg, Rx(Z_REG(addr)), Z_OFFSET(addr), tmp_reg -|| } -|.endmacro - -|.macro SET_ZVAL_LVAL, addr, val, tmp_reg1, tmp_reg2 -|| if (val == 0) { -| SET_ZVAL_LVAL_FROM_REG addr, xzr, tmp_reg2 -|| } else { -| LOAD_64BIT_VAL tmp_reg1, val -| SET_ZVAL_LVAL_FROM_REG addr, tmp_reg1, tmp_reg2 -|| } -|.endmacro - -/* Store DOUBLE value from FP register 'reg' into memory 'addr'. - * Note: the equivalent macro in JIT/x86 is SSE_SET_ZVAL_DVAL. */ -|.macro SET_ZVAL_DVAL, addr, reg, tmp_reg -|| if (Z_MODE(addr) == IS_REG) { -|| if (reg != Z_REG(addr)) { -| fmov Rd(Z_REG(addr)-ZREG_V0), Rd(reg-ZREG_V0) -|| } -|| } else { -|| ZEND_ASSERT(Z_MODE(addr) == IS_MEM_ZVAL); -| MEM_ACCESS_64_WITH_UOFFSET str, Rd(reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg) -|| } -|.endmacro - -/* Load DOUBLE value from memory 'addr' into FP register 'reg'. - * Note: the equivalent macro in JIT/x86 is SSE_GET_ZVAL_DVAL. */ -|.macro GET_ZVAL_DVAL, reg, addr, tmp_reg -|| if (Z_MODE(addr) != IS_REG || reg != Z_REG(addr)) { -|| if (Z_MODE(addr) == IS_CONST_ZVAL) { -| MEM_LOAD ldr, Rd(reg-ZREG_V0), Z_ZV(addr), Rx(tmp_reg) -|| } else if (Z_MODE(addr) == IS_MEM_ZVAL) { -| MEM_ACCESS_64_WITH_UOFFSET ldr, Rd(reg-ZREG_V0), Rx(Z_REG(addr)), Z_OFFSET(addr), Rx(tmp_reg) -|| } else if (Z_MODE(addr) == IS_REG) { -| fmov Rd(reg-ZREG_V0), Rd(Z_REG(addr)-ZREG_V0) -|| } else { -|| ZEND_UNREACHABLE(); -|| } -|| } -|.endmacro - -|.macro ZVAL_COPY_CONST, dst_addr, dst_info, dst_def_info, zv, tmp_reg1, tmp_reg2, fp_tmp_reg -|| if (Z_TYPE_P(zv) > IS_TRUE) { -|| if (Z_TYPE_P(zv) == IS_DOUBLE) { -|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : fp_tmp_reg; -| MEM_LOAD ldr, Rd(dst_reg-ZREG_V0), zv, Rx(tmp_reg1) -| SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2 -|| } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) { -|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? Z_REG(dst_addr) : fp_tmp_reg; -| DOUBLE_GET_LONG dst_reg, Z_LVAL_P(zv), tmp_reg1 -| SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2 -|| } else { -| // In x64, if the range of this LONG value can be represented via INT type, only move the low 32 bits into dst_addr. -| // Note that imm32 is signed extended to 64 bits during mov. -| // In aarch64, we choose to handle both cases in the same way. Even though 4 mov's are used for 64-bit value and 2 mov's are -| // needed for 32-bit value, an extra ext insn is needed for 32-bit value. -| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) -|| } -|| } -|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { -|| if (dst_def_info == MAY_BE_DOUBLE) { -|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { -| SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE, Rw(tmp_reg1), Rx(tmp_reg2) -|| } -|| } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1< IS_TRUE) { -|| if (Z_TYPE_P(zv) == IS_DOUBLE) { -|| zend_reg dst_reg = (Z_MODE(dst_addr) == IS_REG) ? -|| Z_REG(dst_addr) : ((Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : fp_tmp_reg); -| MEM_LOAD ldr, Rd(dst_reg-ZREG_V0), zv, Rx(tmp_reg1) -| SET_ZVAL_DVAL dst_addr, dst_reg, tmp_reg2 -| SET_ZVAL_DVAL res_addr, dst_reg, tmp_reg2 -|| } else if (Z_TYPE_P(zv) == IS_LONG && dst_def_info == MAY_BE_DOUBLE) { -|| if (Z_MODE(dst_addr) == IS_REG) { -| DOUBLE_GET_LONG Z_REG(dst_addr), Z_LVAL_P(zv), tmp_reg1 -| SET_ZVAL_DVAL res_addr, Z_REG(dst_addr), tmp_reg2 -|| } else if (Z_MODE(res_addr) == IS_REG) { -| DOUBLE_GET_LONG Z_REG(res_addr), Z_LVAL_P(zv), tmp_reg1 -| SET_ZVAL_DVAL dst_addr, Z_REG(res_addr), tmp_reg2 -|| } else { -| DOUBLE_GET_LONG fp_tmp_reg, Z_LVAL_P(zv), tmp_reg1 -| SET_ZVAL_DVAL dst_addr, fp_tmp_reg, tmp_reg2 -| SET_ZVAL_DVAL res_addr, fp_tmp_reg, tmp_reg2 -|| } -|| } else { -|| if (Z_MODE(dst_addr) == IS_REG) { -| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) -| SET_ZVAL_LVAL_FROM_REG res_addr, Rx(Z_REG(dst_addr)), Rx(tmp_reg1) -|| } else if (Z_MODE(res_addr) == IS_REG) { -| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) -| SET_ZVAL_LVAL_FROM_REG dst_addr, Rx(Z_REG(res_addr)), Rx(tmp_reg1) -|| } else { -| SET_ZVAL_LVAL dst_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) -| SET_ZVAL_LVAL res_addr, Z_LVAL_P(zv), Rx(tmp_reg1), Rx(tmp_reg2) -|| } -|| } -|| } -|| if (Z_MODE(dst_addr) == IS_MEM_ZVAL) { -|| if (dst_def_info == MAY_BE_DOUBLE) { -|| if ((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { -| SET_ZVAL_TYPE_INFO dst_addr, IS_DOUBLE, Rw(tmp_reg1), Rx(tmp_reg2) -|| } -|| } else if (((dst_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) != (1<1, tmp_reg -|| } -| GC_ADDREF value_ptr_reg, tmp_reg -|1: -|| } -|.endmacro - -|.macro TRY_ADDREF_2, val_info, type_flags_reg, value_ptr_reg, tmp_reg -|| if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { -|| if (val_info & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { -| IF_NOT_REFCOUNTED type_flags_reg, >1, tmp_reg -|| } -| ldr tmp_reg, [value_ptr_reg] -| add tmp_reg, tmp_reg, #2 -| str tmp_reg, [value_ptr_reg] -|1: -|| } -|.endmacro - -|.macro ZVAL_DEREF, reg, info, tmp_reg -|| if (info & MAY_BE_REF) { -| IF_NOT_Z_TYPE, reg, IS_REFERENCE, >1, tmp_reg -| GET_Z_PTR reg, reg -| add reg, reg, #offsetof(zend_reference, val) -|1: -|| } -|.endmacro - -|.macro SET_EX_OPLINE, op, tmp_reg -|| if (op == last_valid_opline) { -|| zend_jit_use_last_valid_opline(); -| SAVE_IP -|| } else { -| ADDR_STORE EX->opline, op, tmp_reg -|| if (!GCC_GLOBAL_REGS) { -|| zend_jit_reset_last_valid_opline(); -|| } -|| } -|.endmacro - -// arg1 "zval" should be in FCARG1x -|.macro ZVAL_DTOR_FUNC, var_info, opline, tmp_reg -|| do { -|| if (!((var_info) & MAY_BE_GUARD) -|| && has_concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { -|| uint8_t type = concrete_type((var_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)); -|| if (type == IS_STRING && !ZEND_DEBUG) { -| EXT_CALL _efree, tmp_reg -|| break; -|| } else if (type == IS_ARRAY) { -|| if ((var_info) & (MAY_BE_ARRAY_KEY_STRING|MAY_BE_ARRAY_OF_STRING|MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF)) { -|| if (opline && ((var_info) & (MAY_BE_ARRAY_OF_ARRAY|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_REF))) { -| SET_EX_OPLINE opline, tmp_reg -|| } -| EXT_CALL zend_array_destroy, tmp_reg -|| } else { -| EXT_CALL zend_jit_array_free, tmp_reg -|| } -|| break; -|| } else if (type == IS_OBJECT) { -|| if (opline) { -| SET_EX_OPLINE opline, REG0 -|| } -| EXT_CALL zend_objects_store_del, tmp_reg -|| break; -|| } -|| } -|| if (opline) { -| SET_EX_OPLINE opline, tmp_reg -|| } -| EXT_CALL rc_dtor_func, tmp_reg -|| } while(0); -|.endmacro - -|.macro ZVAL_PTR_DTOR, addr, op_info, gc, cold, opline, tmp_reg1, tmp_reg2 -|| if ((op_info) & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF|MAY_BE_GUARD)) { -|| if ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { -| // if (Z_REFCOUNTED_P(cv)) { -|| if (cold) { -| IF_ZVAL_REFCOUNTED addr, >1, tmp_reg1, tmp_reg2 -|.cold_code -|1: -|| } else { -| IF_NOT_ZVAL_REFCOUNTED addr, >4, tmp_reg1, tmp_reg2 -|| } -|| } -| // if (!Z_DELREF_P(cv)) { -| GET_ZVAL_PTR FCARG1x, addr, Rx(tmp_reg2) -| GC_DELREF FCARG1x, Rw(tmp_reg1) -|| if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_1(op_info)) { -|| if (((op_info) & MAY_BE_GUARD) || RC_MAY_BE_N(op_info)) { -|| if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) { -| bne >3 -|| } else { -| bne >4 -|| } -|| } -| // zval_dtor_func(r); -| ZVAL_DTOR_FUNC op_info, opline, Rx(tmp_reg1) -|| if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) { -| b >4 -|| } -|3: -|| } -|| if (gc && (((op_info) & MAY_BE_GUARD) || (RC_MAY_BE_N(op_info) && ((op_info) & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0))) { -|| if ((op_info) & (MAY_BE_REF|MAY_BE_GUARD)) { -|| zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, offsetof(zend_reference, val)); -| IF_NOT_ZVAL_TYPE addr, IS_REFERENCE, >1, tmp_reg1 -| IF_NOT_ZVAL_COLLECTABLE ref_addr, >4, tmp_reg1, tmp_reg2 -| GET_ZVAL_PTR FCARG1x, ref_addr, Rx(tmp_reg2) -|1: -|| } -| IF_GC_MAY_NOT_LEAK FCARG1x, >4, Rw(tmp_reg1), Rw(tmp_reg2) -| // gc_possible_root(Z_COUNTED_P(z)) -| EXT_CALL gc_possible_root, Rx(tmp_reg1) -|| } -|| if (cold && ((op_info) & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_INDIRECT|MAY_BE_GUARD)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) != 0) { -| b >4 -|.code -|| } -|4: -|| } -|.endmacro - -|.macro FREE_OP, op_type, op, op_info, cold, opline, tmp_reg1, tmp_reg2 -|| if (op_type & (IS_VAR|IS_TMP_VAR)) { -|| zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var); -| ZVAL_PTR_DTOR addr, op_info, 0, cold, opline, tmp_reg1, tmp_reg2 -|| } -|.endmacro - -|.macro SEPARATE_ARRAY, addr, op_info, cold, tmp_reg1, tmp_reg2 -|| if (RC_MAY_BE_N(op_info)) { -|| if (Z_REG(addr) != ZREG_FP) { -| GET_ZVAL_LVAL ZREG_REG0, addr, Rx(tmp_reg1) -|| if (RC_MAY_BE_1(op_info)) { -| // if (GC_REFCOUNT() > 1) -| ldr Rw(tmp_reg1), [REG0] -| cmp Rw(tmp_reg1), #1 -| bls >2 -|| } -|| if (Z_REG(addr) != ZREG_FCARG1 || Z_OFFSET(addr) != 0) { -| LOAD_ZVAL_ADDR FCARG1x, addr -|| } -| EXT_CALL zend_jit_zval_array_dup, REG0 -| mov REG0, RETVALx -|2: -| mov FCARG1x, REG0 -|| } else { -| GET_ZVAL_LVAL ZREG_FCARG1, addr, Rx(tmp_reg1) -|| if (RC_MAY_BE_1(op_info)) { -| // if (GC_REFCOUNT() > 1) -| ldr Rw(tmp_reg1), [FCARG1x] -| cmp Rw(tmp_reg1), #1 -|| if (cold) { -| bhi >1 -|.cold_code -|1: -|| } else { -| bls >2 -|| } -|| } -| IF_NOT_ZVAL_REFCOUNTED addr, >1, tmp_reg1, tmp_reg2 -| GC_DELREF FCARG1x, Rw(tmp_reg1) -|1: -| EXT_CALL zend_array_dup, REG0 -| mov REG0, RETVALx -| SET_ZVAL_PTR addr, REG0, Rx(tmp_reg1) -| SET_ZVAL_TYPE_INFO addr, IS_ARRAY_EX, Rw(tmp_reg1), Rx(tmp_reg2) -| mov FCARG1x, REG0 -|| if (RC_MAY_BE_1(op_info)) { -|| if (cold) { -| b >2 -|.code -|| } -|| } -|2: -|| } -|| } else { -| GET_ZVAL_LVAL ZREG_FCARG1, addr, Rx(tmp_reg1) -|| } -|.endmacro - -/* argument is passed in FCARG1x */ -|.macro EFREE_REFERENCE -||#if ZEND_DEBUG -| mov FCARG2x, xzr // filename -| mov CARG3w, wzr // lineno -| mov CARG4, xzr -| mov CARG5, xzr -| EXT_CALL _efree, REG0 -||#else -||#ifdef HAVE_BUILTIN_CONSTANT_P -| EXT_CALL _efree_32, REG0 -||#else -| EXT_CALL _efree, REG0 -||#endif -||#endif -|.endmacro - -|.macro EMALLOC, size, op_array, opline -||#if ZEND_DEBUG -|| const char *filename = op_array->filename ? op_array->filename->val : NULL; -| mov FCARG1x, #size -| LOAD_ADDR FCARG2x, filename -| LOAD_32BIT_VAL CARG3w, opline->lineno -| mov CARG4, xzr -| mov CARG5, xzr -| EXT_CALL _emalloc, REG0 -| mov REG0, RETVALx -||#else -||#ifdef HAVE_BUILTIN_CONSTANT_P -|| if (size > 24 && size <= 32) { -| EXT_CALL _emalloc_32, REG0 -| mov REG0, RETVALx -|| } else { -| mov FCARG1x, #size -| EXT_CALL _emalloc, REG0 -| mov REG0, RETVALx -|| } -||#else -| mov FCARG1x, #size -| EXT_CALL _emalloc, REG0 -| mov REG0, RETVALx -||#endif -||#endif -|.endmacro - -|.macro OBJ_RELEASE, reg, exit_label, tmp_reg1, tmp_reg2 -| GC_DELREF Rx(reg), Rw(tmp_reg1) -| bne >1 -| // zend_objects_store_del(obj); -|| if (reg != ZREG_FCARG1) { -| mov FCARG1x, Rx(reg) -|| } -| EXT_CALL zend_objects_store_del, Rx(tmp_reg1) -| b exit_label -|1: -| IF_GC_MAY_NOT_LEAK Rx(reg), >1, Rw(tmp_reg1), Rw(tmp_reg2) -| // gc_possible_root(obj) -|| if (reg != ZREG_FCARG1) { -| mov FCARG1x, Rx(reg) -|| } -| EXT_CALL gc_possible_root, Rx(tmp_reg1) -|1: -|.endmacro - -|.macro UNDEFINED_OFFSET, opline -|| if (opline == last_valid_opline) { -|| zend_jit_use_last_valid_opline(); -| bl ->undefined_offset_ex -|| } else { -| SET_EX_OPLINE opline, REG0 -| bl ->undefined_offset -|| } -|.endmacro - -|.macro UNDEFINED_INDEX, opline -|| if (opline == last_valid_opline) { -|| zend_jit_use_last_valid_opline(); -| bl ->undefined_index_ex -|| } else { -| SET_EX_OPLINE opline, REG0 -| bl ->undefined_index -|| } -|.endmacro - -|.macro CANNOT_ADD_ELEMENT, opline -|| if (opline == last_valid_opline) { -|| zend_jit_use_last_valid_opline(); -| bl ->cannot_add_element_ex -|| } else { -| SET_EX_OPLINE opline, REG0 -| bl ->cannot_add_element -|| } -|.endmacro - -static bool reuse_ip = 0; -static bool delayed_call_chain = 0; -static uint32_t delayed_call_level = 0; -static const zend_op *last_valid_opline = NULL; -static bool use_last_vald_opline = 0; -static bool track_last_valid_opline = 0; -static int jit_return_label = -1; -static uint32_t current_trace_num = 0; -static uint32_t allowed_opt_flags = 0; - -static void zend_jit_track_last_valid_opline(void) -{ - use_last_vald_opline = 0; - track_last_valid_opline = 1; -} - -static void zend_jit_use_last_valid_opline(void) -{ - if (track_last_valid_opline) { - use_last_vald_opline = 1; - track_last_valid_opline = 0; - } -} - -static bool zend_jit_trace_uses_initial_ip(void) -{ - return use_last_vald_opline; -} - -static void zend_jit_set_last_valid_opline(const zend_op *target_opline) -{ - if (!reuse_ip) { - track_last_valid_opline = 0; - last_valid_opline = target_opline; - } -} - -static void zend_jit_reset_last_valid_opline(void) -{ - track_last_valid_opline = 0; - last_valid_opline = NULL; -} - -static void zend_jit_start_reuse_ip(void) -{ - zend_jit_reset_last_valid_opline(); - reuse_ip = 1; -} - -static int zend_jit_reuse_ip(dasm_State **Dst) -{ - if (!reuse_ip) { - zend_jit_start_reuse_ip(); - | // call = EX(call); - | ldr RX, EX->call - } - return 1; -} - -static void zend_jit_stop_reuse_ip(void) -{ - reuse_ip = 0; -} - -static int zend_jit_interrupt_handler_stub(dasm_State **Dst) -{ - |->interrupt_handler: - | SAVE_IP - | //EG(vm_interrupt) = 0; - | MEM_STORE_8_ZTS strb, wzr, executor_globals, vm_interrupt, TMP1 - | //if (EG(timed_out)) { - | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, timed_out, TMP1 - | cbz TMP1w, >1 - | //zend_timeout(); - | EXT_CALL zend_timeout, TMP1 - |1: - | //} else if (zend_interrupt_function) { - if (zend_interrupt_function) { - | //zend_interrupt_function(execute_data); - | mov CARG1, FP - | EXT_CALL zend_interrupt_function, TMP1 - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbz REG0, >1 - | EXT_CALL zend_jit_exception_in_interrupt_handler_helper, TMP1 - |1: - | //ZEND_VM_ENTER(); - | //execute_data = EG(current_execute_data); - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1 - | LOAD_IP - } - | //ZEND_VM_CONTINUE() - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | JMP_IP TMP1 - } else { - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #1 // ZEND_VM_ENTER - | ret - } - - return 1; -} - -static int zend_jit_exception_handler_stub(dasm_State **Dst) -{ - |->exception_handler: - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - const void *handler = zend_get_opcode_handler_func(EG(exception_op)); - - | ADD_HYBRID_SPAD - | EXT_CALL handler, REG0 - | JMP_IP TMP1 - } else { - const void *handler = EG(exception_op)->handler; - - if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | EXT_JMP handler, REG0 - } else { - | mov FCARG1x, FP - | EXT_CALL handler, REG0 - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | tbnz RETVALw, #31, >1 - | mov RETVALw, #1 // ZEND_VM_ENTER - |1: - | ret - } - } - - return 1; -} - -static int zend_jit_exception_handler_undef_stub(dasm_State **Dst) -{ - |->exception_handler_undef: - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, opline_before_exception, REG0 - | ldrb TMP1w, OP:REG0->result_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >1 - | ldr REG0w, OP:REG0->result.var - | add REG0, REG0, FP - | SET_Z_TYPE_INFO REG0, IS_UNDEF, TMP1w - |1: - | b ->exception_handler - - return 1; -} - -static int zend_jit_exception_handler_free_op1_op2_stub(dasm_State **Dst) -{ - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - |->exception_handler_free_op1_op2: - | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w - | ldrb TMP1w, OP:RX->op1_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op1.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | ldrb TMP1w, OP:RX->op2_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op2.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | b ->exception_handler - return 1; -} - -static int zend_jit_exception_handler_free_op2_stub(dasm_State **Dst) -{ - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - |->exception_handler_free_op2: - | MEM_LOAD_64_ZTS ldr, RX, executor_globals, opline_before_exception, REG0 - | UNDEF_OPLINE_RESULT_IF_USED TMP1w, TMP2w - | ldrb TMP1w, OP:RX->op2_type - | TST_32_WITH_CONST TMP1w, (IS_TMP_VAR|IS_VAR), TMP2w - | beq >9 - | ldr REG0w, OP:RX->op2.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | b ->exception_handler - return 1; -} - -static int zend_jit_leave_function_stub(dasm_State **Dst) -{ - |->leave_function_handler: - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | TST_32_WITH_CONST FCARG1w, ZEND_CALL_TOP, TMP1w - | bne >1 - | EXT_CALL zend_jit_leave_nested_func_helper, REG0 - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - |1: - | EXT_CALL zend_jit_leave_top_func_helper, REG0 - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - } else { - if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - } else { - | mov FCARG2x, FP - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - } - | TST_32_WITH_CONST FCARG1w, ZEND_CALL_TOP, TMP1w - | bne >1 - | EXT_JMP zend_jit_leave_nested_func_helper, REG0 - |1: - | EXT_JMP zend_jit_leave_top_func_helper, REG0 - } - - return 1; -} - -static int zend_jit_leave_throw_stub(dasm_State **Dst) -{ - |->leave_throw_handler: - | // if (opline->opcode != ZEND_HANDLE_EXCEPTION) { - if (GCC_GLOBAL_REGS) { - | ldrb TMP1w, OP:IP->opcode - | cmp TMP1w, #ZEND_HANDLE_EXCEPTION - | beq >5 - | // EG(opline_before_exception) = opline; - | MEM_STORE_64_ZTS str, IP, executor_globals, opline_before_exception, TMP2 - |5: - | // opline = EG(exception_op); - | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2 - | // HANDLE_EXCEPTION() - | b ->exception_handler - } else { - | GET_IP TMP1 - | ldrb TMP2w, OP:TMP1->opcode - | cmp TMP2w, #ZEND_HANDLE_EXCEPTION - | beq >5 - | // EG(opline_before_exception) = opline; - | MEM_STORE_64_ZTS str, TMP1, executor_globals, opline_before_exception, TMP2 - |5: - | // opline = EG(exception_op); - | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2 - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #2 // ZEND_VM_LEAVE - | ret - } - - return 1; -} - -static int zend_jit_icall_throw_stub(dasm_State **Dst) -{ - |->icall_throw_handler: - | // zend_rethrow_exception(zend_execute_data *execute_data) - | ldr IP, EX->opline - | // if (EX(opline)->opcode != ZEND_HANDLE_EXCEPTION) { - | ldrb TMP1w, OP:IP->opcode - | cmp TMP1w, #ZEND_HANDLE_EXCEPTION - | beq >1 - | // EG(opline_before_exception) = opline; - | MEM_STORE_64_ZTS str, IP, executor_globals, opline_before_exception, TMP2 - |1: - | // opline = EG(exception_op); - | LOAD_IP_ADDR_ZTS executor_globals, exception_op, TMP2 - || if (GCC_GLOBAL_REGS) { - | str IP, EX->opline - || } - | // HANDLE_EXCEPTION() - | b ->exception_handler - - return 1; -} - -static int zend_jit_throw_cannot_pass_by_ref_stub(dasm_State **Dst) -{ - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - |->throw_cannot_pass_by_ref: - | ldr REG0, EX->opline - | ldr REG1w, OP:REG0->result.var - | add REG1, REG1, RX - | SET_Z_TYPE_INFO REG1, IS_UNDEF, TMP1w - | // last EX(call) frame may be delayed - | ldr TMP1, EX->call - | cmp RX, TMP1 - | beq >1 - | ldr REG1, EX->call - | str REG1, EX:RX->prev_execute_data - | str RX, EX->call - |1: - | mov RX, REG0 - | ldr FCARG1w, OP:REG0->op2.num - | EXT_CALL zend_cannot_pass_by_reference, REG0 - | ldrb TMP1w, OP:RX->op1_type - | cmp TMP1w, #IS_TMP_VAR - | bne >9 - | ldr REG0w, OP:RX->op1.var - | add REG0, REG0, FP - | ZVAL_PTR_DTOR addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF, 0, 0, NULL, ZREG_TMP1, ZREG_TMP2 - |9: - | b ->exception_handler - - return 1; -} - -static int zend_jit_undefined_offset_ex_stub(dasm_State **Dst) -{ - |->undefined_offset_ex: - | SAVE_IP - | b ->undefined_offset - - return 1; -} - -static int zend_jit_undefined_offset_stub(dasm_State **Dst) -{ - |->undefined_offset: -#ifdef __APPLE__ - | stp x29, x30, [sp, # -16]! - | mov x29, sp -#endif - | //sub r4, 8 - | ldr REG0, EX->opline - | ldr REG1w, OP:REG0->result.var - | add REG1, REG1, FP - | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w - | ldrb REG1w, OP:REG0->op2_type - | cmp REG1w, #IS_CONST - | bne >2 - | ldrsw REG1, OP:REG0->op2.constant - | add REG0, REG0, REG1 - | b >3 - |2: - | ldr REG0w, OP:REG0->op2.var - | add REG0, REG0, FP - |3: - | mov CARG1, #E_WARNING - | LOAD_ADDR CARG2, "Undefined array key " ZEND_LONG_FMT - | ldr CARG3, [REG0] -#ifdef __APPLE__ - | str CARG3, [sp, #-16]! - | EXT_CALL zend_error, REG0 - | add sp, sp, #16 - | ldp x29, x30, [sp], #16 - | ret -#else - | EXT_JMP zend_error, REG0 // tail call - | //add r4, 8 // stack alignment - | //ret -#endif - - return 1; -} - -static int zend_jit_undefined_index_ex_stub(dasm_State **Dst) -{ - |->undefined_index_ex: - | SAVE_IP - | b ->undefined_index - - return 1; -} - -static int zend_jit_undefined_index_stub(dasm_State **Dst) -{ - |->undefined_index: -#ifdef __APPLE__ - | stp x29, x30, [sp, # -16]! - | mov x29, sp -#endif - | //sub r4, 8 - | ldr REG0, EX->opline - | ldr REG1w, OP:REG0->result.var - | add REG1, REG1, FP - | SET_Z_TYPE_INFO REG1, IS_NULL, TMP1w - | ldrb REG1w, OP:REG0->op2_type - | cmp REG1w, #IS_CONST - | bne >2 - | ldrsw REG1, OP:REG0->op2.constant - | add REG0, REG0, REG1 - | b >3 - |2: - | ldr REG0w, OP:REG0->op2.var - | add REG0, REG0, FP - |3: - | mov CARG1, #E_WARNING - | LOAD_ADDR CARG2, "Undefined array key \"%s\"" - | ldr CARG3, [REG0] - | add CARG3, CARG3, #offsetof(zend_string, val) -#ifdef __APPLE__ - | str CARG3, [sp, #-16]! - | EXT_CALL zend_error, REG0 - | add sp, sp, #16 - | ldp x29, x30, [sp], #16 - | ret -#else - | EXT_JMP zend_error, REG0 // tail call - | //add r4, 8 - | //ret -#endif - - return 1; -} - -static int zend_jit_cannot_add_element_ex_stub(dasm_State **Dst) -{ - |->cannot_add_element_ex: - | SAVE_IP - | b ->cannot_add_element - - return 1; -} - -static int zend_jit_cannot_add_element_stub(dasm_State **Dst) -{ - |->cannot_add_element: - | // sub r4, 8 - | ldr REG0, EX->opline - | ldrb TMP1w, OP:REG0->result_type - | cmp TMP1w, #IS_UNUSED - | beq >1 - | ldr REG0w, OP:REG0->result.var - | add REG0, REG0, FP - | SET_Z_TYPE_INFO REG0, IS_NULL, TMP1w - |1: - | mov CARG1, xzr - | LOAD_ADDR CARG2, "Cannot add element to the array as the next element is already occupied" - | EXT_JMP zend_throw_error, REG0 // tail call - | // add r4, 8 - | //ret - - return 1; -} - -static int zend_jit_undefined_function_stub(dasm_State **Dst) -{ - |->undefined_function: - | ldr REG0, EX->opline - | mov CARG1, xzr - | LOAD_ADDR CARG2, "Call to undefined function %s()" - | ldrsw CARG3, [REG0, #offsetof(zend_op, op2.constant)] - | ldr CARG3, [REG0, CARG3] - | add CARG3, CARG3, #offsetof(zend_string, val) -#ifdef __APPLE__ - | str CARG3, [sp, #-16]! -#endif - | EXT_CALL zend_throw_error, REG0 -#ifdef __APPLE__ - | add sp, sp, #16 -#endif - | b ->exception_handler - return 1; -} - -static int zend_jit_negative_shift_stub(dasm_State **Dst) -{ - |->negative_shift: - | ldr RX, EX->opline - | LOAD_ADDR CARG1, zend_ce_arithmetic_error - | LOAD_ADDR CARG2, "Bit shift by negative number" - | EXT_CALL zend_throw_error, REG0 - | b ->exception_handler_free_op1_op2 - return 1; -} - -static int zend_jit_mod_by_zero_stub(dasm_State **Dst) -{ - |->mod_by_zero: - | ldr RX, EX->opline - | LOAD_ADDR CARG1, zend_ce_division_by_zero_error - | LOAD_ADDR CARG2, "Modulo by zero" - | EXT_CALL zend_throw_error, REG0 - | b ->exception_handler_free_op1_op2 - return 1; -} - -static int zend_jit_invalid_this_stub(dasm_State **Dst) -{ - |->invalid_this: - | UNDEF_OPLINE_RESULT TMP1w - | mov CARG1, xzr - | LOAD_ADDR CARG2, "Using $this when not in object context" - | EXT_CALL zend_throw_error, REG0 - | b ->exception_handler - - return 1; -} - -static int zend_jit_hybrid_runtime_jit_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) { - return 1; - } - - |->hybrid_runtime_jit: - | EXT_CALL zend_runtime_jit, REG0 - | JMP_IP TMP1 - return 1; -} - -static int zend_jit_hybrid_profile_jit_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) { - return 1; - } - - |->hybrid_profile_jit: - | // ++zend_jit_profile_counter; - | LOAD_ADDR REG0, &zend_jit_profile_counter - | ldr TMP1, [REG0] - | add TMP1, TMP1, #1 - | str TMP1, [REG0] - | // op_array = (zend_op_array*)EX(func); - | ldr REG0, EX->func - | // run_time_cache = EX(run_time_cache); - | ldr REG2, EX->run_time_cache - | // jit_extension = (const void*)ZEND_FUNC_INFO(op_array); - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | // ++ZEND_COUNTER_INFO(op_array) - || if ((zend_jit_profile_counter_rid * sizeof(void*)) > LDR_STR_PIMM64) { - | LOAD_32BIT_VAL TMP1, (zend_jit_profile_counter_rid * sizeof(void*)) - | ldr TMP2, [REG2, TMP1] - | add TMP2, TMP2, #1 - | str TMP2, [REG2, TMP1] - || } else { - | ldr TMP2, [REG2, #(zend_jit_profile_counter_rid * sizeof(void*))] - | add TMP2, TMP2, #1 - | str TMP2, [REG2, #(zend_jit_profile_counter_rid * sizeof(void*))] - || } - | // return ((zend_vm_opcode_handler_t)jit_extension->orig_handler)() - | ldr TMP1, [REG0, #offsetof(zend_jit_op_array_extension, orig_handler)] - | br TMP1 - return 1; -} - -static int zend_jit_hybrid_hot_code_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) { - return 1; - } - - |->hybrid_hot_code: - || ZEND_ASSERT(ZEND_JIT_COUNTER_INIT <= MOVZ_IMM); - | movz TMP1w, #ZEND_JIT_COUNTER_INIT - | strh TMP1w, [REG2] - | mov FCARG1x, FP - | GET_IP FCARG2x - | EXT_CALL zend_jit_hot_func, REG0 - | JMP_IP TMP1 - return 1; -} - -/* - * This code is based Mike Pall's "Hashed profile counters" idea, implemented - * in LuaJIT. The full description may be found in "LuaJIT 2.0 intellectual - * property disclosure and research opportunities" email - * at http://lua-users.org/lists/lua-l/2009-11/msg00089.html - * - * In addition we use a variation of Knuth's multiplicative hash function - * described at https://code.i-harness.com/en/q/a21ce - * - * uint64_t hash(uint64_t x) { - * x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9; - * x = (x ^ (x >> 27)) * 0x94d049bb133111eb; - * x = x ^ (x >> 31); - * return x; - * } - * - * uint_32_t hash(uint32_t x) { - * x = ((x >> 16) ^ x) * 0x45d9f3b; - * x = ((x >> 16) ^ x) * 0x45d9f3b; - * x = (x >> 16) ^ x; - * return x; - * } - * - */ -static int zend_jit_hybrid_hot_counter_stub(dasm_State **Dst, uint32_t cost) -{ - | ldr REG0, EX->func - | ldr REG1, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG2, [REG1, #offsetof(zend_jit_op_array_hot_extension, counter)] - | ldrh TMP2w, [REG2] - | ADD_SUB_32_WITH_CONST subs, TMP2w, TMP2w, cost, TMP1w - | strh TMP2w, [REG2] - | ble ->hybrid_hot_code - | GET_IP REG2 - | ldr TMP1, [REG0, #offsetof(zend_op_array, opcodes)] - | sub REG2, REG2, TMP1 - | // divide by sizeof(zend_op) - || ZEND_ASSERT(sizeof(zend_op) == 32); - | add TMP1, REG1, REG2, asr #2 - | ldr TMP1, [TMP1, #offsetof(zend_jit_op_array_hot_extension, orig_handlers)] - | br TMP1 - return 1; -} - -static int zend_jit_hybrid_func_hot_counter_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) { - return 1; - } - - |->hybrid_func_hot_counter: - - return zend_jit_hybrid_hot_counter_stub(Dst, - ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func))); -} - -static int zend_jit_hybrid_loop_hot_counter_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) { - return 1; - } - - |->hybrid_loop_hot_counter: - - return zend_jit_hybrid_hot_counter_stub(Dst, - ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop))); -} - -static int zend_jit_hybrid_hot_trace_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID) { - return 1; - } - - // On entry from counter stub: - // REG2 -> zend_op_trace_info.counter - - |->hybrid_hot_trace: - | mov TMP1w, #ZEND_JIT_COUNTER_INIT - | strh TMP1w, [REG2] - | mov FCARG1x, FP - | GET_IP FCARG2x - | EXT_CALL zend_jit_trace_hot_root, REG0 - | tbnz RETVALw, #31, >1 // Result is < 0 on failure. - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0 - | LOAD_IP - | JMP_IP TMP1 - |1: - | EXT_JMP zend_jit_halt_op->handler, REG0 - - return 1; -} - -static int zend_jit_hybrid_trace_counter_stub(dasm_State **Dst, uint32_t cost) -{ - | ldr REG0, EX->func - | ldr REG1, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG1, [REG1, #offsetof(zend_jit_op_array_trace_extension, offset)] - | add TMP1, REG1, IP - | ldr REG2, [TMP1, #offsetof(zend_op_trace_info, counter)] - | ldrh TMP2w, [REG2] - | ADD_SUB_32_WITH_CONST subs, TMP2w, TMP2w, cost, TMP1w - | strh TMP2w, [REG2] - | ble ->hybrid_hot_trace - // Note: "REG1 + IP" is re-calculated as TMP1 is used as temporary register by the prior - // ADD_SUB_32_WITH_CONST. Will optimize in the future if more temporary registers are available. - | add TMP1, REG1, IP - | ldr TMP2, [TMP1, #offsetof(zend_op_trace_info, orig_handler)] - | br TMP2 - - return 1; -} - -static int zend_jit_hybrid_func_trace_counter_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_func)) { - return 1; - } - - |->hybrid_func_trace_counter: - - return zend_jit_hybrid_trace_counter_stub(Dst, - ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_func) - 1) / JIT_G(hot_func))); -} - -static int zend_jit_hybrid_ret_trace_counter_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_return)) { - return 1; - } - - |->hybrid_ret_trace_counter: - - return zend_jit_hybrid_trace_counter_stub(Dst, - ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_return) - 1) / JIT_G(hot_return))); -} - -static int zend_jit_hybrid_loop_trace_counter_stub(dasm_State **Dst) -{ - if (zend_jit_vm_kind != ZEND_VM_KIND_HYBRID || !JIT_G(hot_loop)) { - return 1; - } - - |->hybrid_loop_trace_counter: - - return zend_jit_hybrid_trace_counter_stub(Dst, - ((ZEND_JIT_COUNTER_INIT + JIT_G(hot_loop) - 1) / JIT_G(hot_loop))); -} - -static int zend_jit_trace_halt_stub(dasm_State **Dst) -{ - |->trace_halt: - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | EXT_JMP zend_jit_halt_op->handler, REG0 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | mov IP, xzr // PC must be zero - | ret - } else { - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | movn RETVALx, #0 // ZEND_VM_RETURN (-1) - | ret - } - return 1; -} - -static int zend_jit_trace_exit_stub(dasm_State **Dst) -{ - |->trace_exit: - | - | // Save CPU registers(32 GP regs + 32 FP regs) on stack in the order of d31 to x0 - | - | stp d30, d31, [sp, #-16]! - | stp d28, d29, [sp, #-16]! - | stp d26, d27, [sp, #-16]! - | stp d24, d25, [sp, #-16]! - | stp d22, d23, [sp, #-16]! - | stp d20, d21, [sp, #-16]! - | stp d18, d19, [sp, #-16]! - | stp d16, d17, [sp, #-16]! - | //stp d14, d15, [sp, #-16]! // we don't use preserved registers yet - | //stp d12, d13, [sp, #-16]! - | //stp d10, d11, [sp, #-16]! - | //stp d8, d9, [sp, #-16]! - | stp d6, d7, [sp, #(-16*5)]! - | stp d4, d5, [sp, #-16]! - | stp d2, d3, [sp, #-16]! - | stp d0, d1, [sp, #-16]! - | - | //str x30, [sp, #-16]! // we don't use callee-saved registers yet (x31 can be omitted) - | stp x28, x29, [sp, #(-16*2)]! // we have to store RX (x28) - | //stp x26, x27, [sp, #-16]! // we don't use callee-saved registers yet - | //stp x24, x25, [sp, #-16]! - | //stp x22, x23, [sp, #-16]! - | //stp x20, x21, [sp, #-16]! - | //stp x18, x19, [sp, #-16]! - | //stp x16, x17, [sp, #-16]! // we don't need temporary registers - | stp x14, x15, [sp, #-(16*7)]! - | stp x12, x13, [sp, #-16]! - | stp x10, x11, [sp, #-16]! - | stp x8, x9, [sp, #-16]! - | stp x6, x7, [sp, #-16]! - | stp x4, x5, [sp, #-16]! - | stp x2, x3, [sp, #-16]! - | stp x0, x1, [sp, #-16]! - | - | mov FCARG1w, TMP1w // exit_num - | mov FCARG2x, sp - | - | // EX(opline) = opline - | SAVE_IP - | // zend_jit_trace_exit(trace_num, exit_num) - | EXT_CALL zend_jit_trace_exit, REG0 - | - | add sp, sp, #(32 * 16) // restore sp - | - - | tst RETVALw, RETVALw - | bne >1 // not zero - - | // execute_data = EG(current_execute_data) - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0 - | // opline = EX(opline) - | LOAD_IP - - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | JMP_IP TMP1 - } else { - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #1 // ZEND_VM_ENTER - | ret - } - - |1: - | blt ->trace_halt - - | // execute_data = EG(current_execute_data) - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, REG0 - | // opline = EX(opline) - | LOAD_IP - - | // check for interrupt (try to avoid this ???) - | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1 - | cbnz TMP1w, ->interrupt_handler - - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | br REG0 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | br REG0 - } else { - | ldr IP, EX->opline - | mov FCARG1x, FP - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | blr REG0 - | - | tst RETVALw, RETVALw - | blt ->trace_halt - | - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #1 // ZEND_VM_ENTER - | ret - } - - return 1; -} - -static int zend_jit_trace_escape_stub(dasm_State **Dst) -{ - |->trace_escape: - | - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | JMP_IP, TMP1 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | JMP_IP, TMP1 - } else { - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #1 // ZEND_VM_ENTER - | ret - } - - return 1; -} - -/* Keep 32 exit points in a single code block */ -#define ZEND_JIT_EXIT_POINTS_SPACING 4 // bl = bytes -#define ZEND_JIT_EXIT_POINTS_PER_GROUP 32 // number of continuous exit points - -static int zend_jit_trace_exit_group_stub(dasm_State **Dst, uint32_t n) -{ - uint32_t i; - - | bl >2 - |1: - for (i = 1; i < ZEND_JIT_EXIT_POINTS_PER_GROUP; i++) { - | bl >2 - } - |2: - | adr TMP1, <1 - | sub TMP1, lr, TMP1 - | lsr TMP1, TMP1, #2 - if (n) { - | ADD_SUB_32_WITH_CONST add, TMP1w, TMP1w, n, TMP2w - } - | b ->trace_exit // pass exit_num in TMP1w - - return 1; -} - -#ifdef CONTEXT_THREADED_JIT -static int zend_jit_context_threaded_call_stub(dasm_State **Dst) -{ - |->context_threaded_call: - | NIY_STUB // TODO - return 1; -} -#endif - -static int zend_jit_assign_const_stub(dasm_State **Dst) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN; - - |->assign_const: - | stp x29, x30, [sp, #-32]! - | mov x29, sp - if (!zend_jit_assign_to_variable( - Dst, NULL, - var_addr, var_addr, -1, -1, - IS_CONST, val_addr, val_info, - 0, 0)) { - return 0; - } - | ldp x29, x30, [sp], #32 - | ret - return 1; -} - -static int zend_jit_assign_tmp_stub(dasm_State **Dst) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN; - - |->assign_tmp: - | stp x29, x30, [sp, #-32]! - | mov x29, sp - if (!zend_jit_assign_to_variable( - Dst, NULL, - var_addr, var_addr, -1, -1, - IS_TMP_VAR, val_addr, val_info, - 0, 0)) { - return 0; - } - | ldp x29, x30, [sp], #32 - | ret - return 1; -} - -static int zend_jit_assign_var_stub(dasm_State **Dst) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF; - - |->assign_var: - | stp x29, x30, [sp, #-32]! - | mov x29, sp - if (!zend_jit_assign_to_variable( - Dst, NULL, - var_addr, var_addr, -1, -1, - IS_VAR, val_addr, val_info, - 0, 0)) { - return 0; - } - | ldp x29, x30, [sp], #32 - | ret - return 1; -} - -static int zend_jit_assign_cv_noref_stub(dasm_State **Dst) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN/*|MAY_BE_UNDEF*/; - - |->assign_cv_noref: - | stp x29, x30, [sp, #-32]! - | mov x29, sp - if (!zend_jit_assign_to_variable( - Dst, NULL, - var_addr, var_addr, -1, -1, - IS_CV, val_addr, val_info, - 0, 0)) { - return 0; - } - | ldp x29, x30, [sp], #32 - | ret - return 1; -} - -static int zend_jit_assign_cv_stub(dasm_State **Dst) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - uint32_t val_info = MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN|MAY_BE_REF/*|MAY_BE_UNDEF*/; - - |->assign_cv: - | stp x29, x30, [sp, #-32]! - | mov x29, sp - if (!zend_jit_assign_to_variable( - Dst, NULL, - var_addr, var_addr, -1, -1, - IS_CV, val_addr, val_info, - 0, 0)) { - return 0; - } - | ldp x29, x30, [sp], #32 - | ret - return 1; -} - -static const zend_jit_stub zend_jit_stubs[] = { - JIT_STUB(interrupt_handler, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(exception_handler, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(exception_handler_undef, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(exception_handler_free_op1_op2, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(exception_handler_free_op2, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(leave_function, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(leave_throw, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(icall_throw, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(throw_cannot_pass_by_ref, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(undefined_offset, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(undefined_index, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(cannot_add_element, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(undefined_offset_ex, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(undefined_index_ex, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(cannot_add_element_ex, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(undefined_function, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(negative_shift, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(mod_by_zero, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(invalid_this, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(trace_halt, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(trace_exit, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(trace_escape, SP_ADJ_JIT, SP_ADJ_VM), - JIT_STUB(hybrid_runtime_jit, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_profile_jit, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_hot_code, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_func_hot_counter, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_loop_hot_counter, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_hot_trace, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_func_trace_counter, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_ret_trace_counter, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(hybrid_loop_trace_counter, SP_ADJ_VM, SP_ADJ_NONE), - JIT_STUB(assign_const, SP_ADJ_RET, SP_ADJ_ASSIGN), - JIT_STUB(assign_tmp, SP_ADJ_RET, SP_ADJ_ASSIGN), - JIT_STUB(assign_var, SP_ADJ_RET, SP_ADJ_ASSIGN), - JIT_STUB(assign_cv_noref, SP_ADJ_RET, SP_ADJ_ASSIGN), - JIT_STUB(assign_cv, SP_ADJ_RET, SP_ADJ_ASSIGN), -#ifdef CONTEXT_THREADED_JIT - JIT_STUB(context_threaded_call, SP_ADJ_NONE, SP_ADJ_NONE), -#endif -}; - -#ifdef HAVE_GDB -# if 0 -typedef struct _Unwind_Context _Unwind_Context; -typedef int (*_Unwind_Trace_Fn)(_Unwind_Context *, void *); -extern int _Unwind_Backtrace(_Unwind_Trace_Fn, void *); -extern uintptr_t _Unwind_GetCFA(_Unwind_Context *); - -typedef struct _zend_jit_unwind_arg { - int cnt; - uintptr_t cfa[3]; -} zend_jit_unwind_arg; - -static int zend_jit_unwind_cb(_Unwind_Context *ctx, void *a) -{ - zend_jit_unwind_arg *arg = (zend_jit_unwind_arg*)a; - arg->cfa[arg->cnt] = _Unwind_GetCFA(ctx); - arg->cnt++; - if (arg->cnt == 3) { - return 5; // _URC_END_OF_STACK - } - return 0; // _URC_NO_REASON; -} - -static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data) -{ - zend_jit_unwind_arg arg; - - memset(&arg, 0, sizeof(arg)); - _Unwind_Backtrace(zend_jit_unwind_cb, &arg); - if (arg.cnt == 3) { - sp_adj[SP_ADJ_VM] = arg.cfa[2] - arg.cfa[1]; - } -} -# else -static void ZEND_FASTCALL zend_jit_touch_vm_stack_data(void *vm_stack_data) -{ - uintptr_t ret; - - __asm__ ( - "ldr %0, [x29]\n\t" - "sub %0 ,%0, x29" - : "=r"(ret)); - - sp_adj[SP_ADJ_VM] = ret; -} -# endif - -extern void (ZEND_FASTCALL *zend_touch_vm_stack_data)(void *vm_stack_data); - -static zend_never_inline void zend_jit_set_sp_adj_vm(void) -{ - void (ZEND_FASTCALL *orig_zend_touch_vm_stack_data)(void *); - - orig_zend_touch_vm_stack_data = zend_touch_vm_stack_data; - zend_touch_vm_stack_data = zend_jit_touch_vm_stack_data; - execute_ex(NULL); // set sp_adj[SP_ADJ_VM] - zend_touch_vm_stack_data = orig_zend_touch_vm_stack_data; -} -#endif - -static int zend_jit_setup(void) -{ - allowed_opt_flags = 0; - -#if ZTS - tsrm_ls_cache_tcb_offset = tsrm_get_ls_cache_tcb_offset(); - ZEND_ASSERT(tsrm_ls_cache_tcb_offset != 0); -#endif - - memset(sp_adj, 0, sizeof(sp_adj)); -#ifdef HAVE_GDB - sp_adj[SP_ADJ_RET] = 0; - sp_adj[SP_ADJ_ASSIGN] = 32; - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - zend_jit_set_sp_adj_vm(); // set sp_adj[SP_ADJ_VM] -#ifndef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE - || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM] + HYBRID_SPAD; // sub r4, HYBRID_SPAD -#else - || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_VM]; -#endif - } else if (GCC_GLOBAL_REGS) { - || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + SPAD; // sub r4, SPAD - } else { - || sp_adj[SP_ADJ_JIT] = sp_adj[SP_ADJ_RET] + NR_SPAD; // sub r4, NR_SPAD - } -#endif - - return SUCCESS; -} - -static ZEND_ATTRIBUTE_UNUSED int zend_jit_trap(dasm_State **Dst) -{ - | brk #0 - return 1; -} - -static int zend_jit_align_func(dasm_State **Dst) -{ - reuse_ip = 0; - delayed_call_chain = 0; - last_valid_opline = NULL; - use_last_vald_opline = 0; - track_last_valid_opline = 0; - jit_return_label = -1; - |.align 16 - return 1; -} - -static int zend_jit_align_stub(dasm_State **Dst) -{ - |.align 16 - return 1; -} - -static int zend_jit_prologue(dasm_State **Dst) -{ - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | SUB_HYBRID_SPAD - } else if (GCC_GLOBAL_REGS) { - | stp x29, x30, [sp, # -SPAD]! // stack alignment - |// mov x29, sp - } else { - | stp x29, x30, [sp, # -NR_SPAD]! // stack alignment - |// mov x29, sp - | stp FP, RX, T2 // save FP and IP - | mov FP, FCARG1x - } - return 1; -} - -static int zend_jit_label(dasm_State **Dst, unsigned int label) -{ - |=>label: - return 1; -} - -static int zend_jit_save_call_chain(dasm_State **Dst, uint32_t call_level) -{ - | // call->prev_execute_data = EX(call); - if (call_level == 1) { - | str xzr, EX:RX->prev_execute_data - } else { - | ldr REG0, EX->call - | str REG0, EX:RX->prev_execute_data - } - | // EX(call) = call; - | str RX, EX->call - - delayed_call_chain = 0; - - return 1; -} - -static int zend_jit_set_ip(dasm_State **Dst, const zend_op *opline) -{ - if (last_valid_opline == opline) { - zend_jit_use_last_valid_opline(); - } else if (GCC_GLOBAL_REGS && last_valid_opline) { - zend_jit_use_last_valid_opline(); - | LOAD_64BIT_VAL TMP1, (opline - last_valid_opline) * sizeof(zend_op) - | ADD_IP TMP1, TMP2 - } else { - | LOAD_IP_ADDR opline - } - zend_jit_set_last_valid_opline(opline); - - return 1; -} - -static int zend_jit_set_ip_ex(dasm_State **Dst, const zend_op *opline, bool set_ip_reg) -{ - return zend_jit_set_ip(Dst, opline); -} - -static int zend_jit_set_valid_ip(dasm_State **Dst, const zend_op *opline) -{ - if (delayed_call_chain) { - if (!zend_jit_save_call_chain(Dst, delayed_call_level)) { - return 0; - } - } - if (!zend_jit_set_ip(Dst, opline)) { - return 0; - } - reuse_ip = 0; - return 1; -} - -static int zend_jit_check_timeout(dasm_State **Dst, const zend_op *opline, const void *exit_addr) -{ - | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1 - if (exit_addr) { - | cbnz TMP1w, &exit_addr - } else if (last_valid_opline == opline) { - || zend_jit_use_last_valid_opline(); - | cbnz TMP1w, ->interrupt_handler - } else { - | cbnz TMP1w, >1 - |.cold_code - |1: - | LOAD_IP_ADDR opline - | b ->interrupt_handler - |.code - } - return 1; -} - -static int zend_jit_trace_end_loop(dasm_State **Dst, int loop_label, const void *timeout_exit_addr) -{ - if (timeout_exit_addr) { - | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1 - | cbz TMP1w, =>loop_label - | b &timeout_exit_addr - } else { - | b =>loop_label - } - return 1; -} - -static int zend_jit_check_exception(dasm_State **Dst) -{ - | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1 - | cbnz TMP2, ->exception_handler - return 1; -} - -static int zend_jit_check_exception_undef_result(dasm_State **Dst, const zend_op *opline) -{ - if (opline->result_type & (IS_TMP_VAR|IS_VAR)) { - | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1 - | cbnz TMP2, ->exception_handler_undef - return 1; - } - return zend_jit_check_exception(Dst); -} - -static int zend_jit_trace_begin(dasm_State **Dst, uint32_t trace_num, zend_jit_trace_info *parent, uint32_t exit_num) -{ - - current_trace_num = trace_num; - - | // EG(jit_trace_num) = trace_num; - | LOAD_32BIT_VAL TMP1w, trace_num - | MEM_STORE_32_ZTS str, TMP1w, executor_globals, jit_trace_num, TMP2 - - return 1; -} - -static int zend_jit_trace_end(dasm_State **Dst, zend_jit_trace_info *t) -{ - uint32_t i; - const void *exit_addr; - - /* Emit veneers table for exit points (B instruction for each exit number) */ - |.cold_code - for (i = 0; i < t->exit_count; i++) { - exit_addr = zend_jit_trace_get_exit_addr(i); - if (!exit_addr) { - return 0; - } - | b &exit_addr - } - |=>1: // end of the code - |.code - return 1; -} - -static int zend_jit_patch(const void *code, size_t size, uint32_t jmp_table_size, const void *from_addr, const void *to_addr) -{ - int ret = 0; - uint8_t *p, *end; - const void *veneer = NULL; - ptrdiff_t delta; - - if (jmp_table_size) { - const void **jmp_slot = (const void **)((char*)code + ZEND_MM_ALIGNED_SIZE_EX(size, sizeof(void*))); - - do { - if (*jmp_slot == from_addr) { - *jmp_slot = to_addr; - ret++; - } - jmp_slot++; - } while (--jmp_table_size); - } - - end = (uint8_t*)code; - p = end + size; - while (p > end) { - uint32_t *ins_ptr; - uint32_t ins; - - p -= 4; - ins_ptr = (uint32_t*)p; - ins = *ins_ptr; - if ((ins & 0xfc000000u) == 0x14000000u) { - // B (imm26:0..25) - delta = (uint32_t*)from_addr - ins_ptr; - if (((ins ^ (uint32_t)delta) & 0x01ffffffu) == 0) { - delta = (uint32_t*)to_addr - ins_ptr; - if (((delta + 0x02000000) >> 26) != 0) { - abort(); // branch target out of range - } - *ins_ptr = (ins & 0xfc000000u) | ((uint32_t)delta & 0x03ffffffu); - ret++; - if (!veneer) { - veneer = p; - } - } - } else if ((ins & 0xff000000u) == 0x54000000u || - (ins & 0x7e000000u) == 0x34000000u) { - // B.cond, CBZ, CBNZ (imm19:5..23) - delta = (uint32_t*)from_addr - ins_ptr; - if (((ins ^ ((uint32_t)delta << 5)) & 0x00ffffe0u) == 0) { - delta = (uint32_t*)to_addr - ins_ptr; - if (((delta + 0x40000) >> 19) != 0) { - if (veneer) { - delta = (uint32_t*)veneer - ins_ptr; - if (((delta + 0x40000) >> 19) != 0) { - abort(); // branch target out of range - } - } else { - abort(); // branch target out of range - } - } - *ins_ptr = (ins & 0xff00001fu) | (((uint32_t)delta & 0x7ffffu) << 5); - ret++; - } - } else if ((ins & 0x7e000000u) == 0x36000000u) { - // TBZ, TBNZ (imm14:5..18) - delta = (uint32_t*)from_addr - ins_ptr; - if (((ins ^ ((uint32_t)delta << 5)) & 0x0007ffe0u) == 0) { - delta = (uint32_t*)to_addr - ins_ptr; - if (((delta + 0x2000) >> 14) != 0) { - if (veneer) { - delta = (uint32_t*)veneer - ins_ptr; - if (((delta + 0x2000) >> 14) != 0) { - abort(); // branch target out of range - } - } else { - abort(); // branch target out of range - } - } - *ins_ptr = (ins & 0xfff8001fu) | (((uint32_t)delta & 0x3fffu) << 5); - ret++; - } - } - } - - JIT_CACHE_FLUSH(code, (char*)code + size); - -#ifdef HAVE_VALGRIND - VALGRIND_DISCARD_TRANSLATIONS(code, size); -#endif - - return ret; -} - -static int zend_jit_link_side_trace(const void *code, size_t size, uint32_t jmp_table_size, uint32_t exit_num, const void *addr) -{ - return zend_jit_patch(code, size, jmp_table_size, zend_jit_trace_get_exit_addr(exit_num), addr); -} - -static int zend_jit_trace_link_to_root(dasm_State **Dst, zend_jit_trace_info *t, const void *timeout_exit_addr) -{ - const void *link_addr; - size_t prologue_size; - - /* Skip prologue. */ - // TODO: don't hardcode this ??? - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { -#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE - prologue_size = 0; -#else - // sub sp, sp, #0x20 - prologue_size = 4; -#endif - } else if (GCC_GLOBAL_REGS) { - // stp x29, x30, [sp, # -SPAD]! - prologue_size = 4; - } else { - // stp x29, x30, [sp, # -NR_SPAD]! // stack alignment - // stp FP, RX, T2 - // mov FP, FCARG1x - prologue_size = 12; - } - link_addr = (const void*)((const char*)t->code_start + prologue_size); - - if (timeout_exit_addr) { - /* Check timeout for links to LOOP */ - | MEM_LOAD_8_ZTS ldrb, TMP1w, executor_globals, vm_interrupt, TMP1 - | cbz TMP1w, &link_addr - | b &timeout_exit_addr - } else { - | b &link_addr - } - return 1; -} - -static int zend_jit_trace_return(dasm_State **Dst, bool original_handler, const zend_op *opline) -{ - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - if (!original_handler) { - | JMP_IP TMP1 - } else { - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | br REG0 - } - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - if (!original_handler) { - | JMP_IP TMP1 - } else { - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | br REG0 - } - } else { - if (original_handler) { - | mov FCARG1x, FP - | ldr REG0, EX->func - | ldr REG0, [REG0, #offsetof(zend_op_array, reserved[zend_func_info_rid])] - | ldr REG0, [REG0, #offsetof(zend_jit_op_array_trace_extension, offset)] - | ldr REG0, [IP, REG0] - | blr REG0 - } - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - if (!original_handler || !opline || - (opline->opcode != ZEND_RETURN - && opline->opcode != ZEND_RETURN_BY_REF - && opline->opcode != ZEND_GENERATOR_RETURN - && opline->opcode != ZEND_GENERATOR_CREATE - && opline->opcode != ZEND_YIELD - && opline->opcode != ZEND_YIELD_FROM)) { - | mov RETVALx, #2 // ZEND_VM_LEAVE - } - | ret - } - return 1; -} - -static int zend_jit_type_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint8_t type) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - - if (!exit_addr) { - return 0; - } - - | IF_NOT_ZVAL_TYPE var_addr, type, &exit_addr, ZREG_TMP1 - - return 1; -} - -static int zend_jit_scalar_type_guard(dasm_State **Dst, const zend_op *opline, uint32_t var) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, FP, var+offsetof(zval, u1.v.type), TMP1 - | cmp TMP1w, #IS_STRING - | bhs &exit_addr - - return 1; -} -static int zend_jit_packed_guard(dasm_State **Dst, const zend_op *opline, uint32_t var, uint32_t op_info) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - - if (!exit_addr) { - return 0; - } - - | GET_ZVAL_LVAL ZREG_FCARG1, var_addr, TMP1 - if (op_info & MAY_BE_ARRAY_PACKED) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | beq &exit_addr - } else { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | bne &exit_addr - } - - return 1; -} - -static int zend_jit_trace_handler(dasm_State **Dst, const zend_op_array *op_array, const zend_op *opline, int may_throw, zend_jit_trace_rec *trace) -{ - zend_jit_op_array_trace_extension *jit_extension = - (zend_jit_op_array_trace_extension*)ZEND_FUNC_INFO(op_array); - size_t offset = jit_extension->offset; - const void *handler = - (zend_vm_opcode_handler_t)ZEND_OP_TRACE_INFO(opline, offset)->call_handler; - - if (!zend_jit_set_valid_ip(Dst, opline)) { - return 0; - } - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, FP - } - | EXT_CALL handler, REG0 - if (may_throw - && opline->opcode != ZEND_RETURN - && opline->opcode != ZEND_RETURN_BY_REF) { - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbnz REG0, ->exception_handler - } - - while (trace->op != ZEND_JIT_TRACE_VM && trace->op != ZEND_JIT_TRACE_END) { - trace++; - } - - if (!GCC_GLOBAL_REGS - && (trace->op != ZEND_JIT_TRACE_END || trace->stop != ZEND_JIT_TRACE_STOP_RETURN)) { - if (opline->opcode == ZEND_RETURN || - opline->opcode == ZEND_RETURN_BY_REF || - opline->opcode == ZEND_DO_UCALL || - opline->opcode == ZEND_DO_FCALL_BY_NAME || - opline->opcode == ZEND_DO_FCALL || - opline->opcode == ZEND_GENERATOR_CREATE) { - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1 - } - } - - if (zend_jit_trace_may_exit(op_array, opline)) { - if (opline->opcode == ZEND_RETURN || - opline->opcode == ZEND_RETURN_BY_REF || - opline->opcode == ZEND_GENERATOR_CREATE) { - - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { -#if 0 - /* this check should be handled by the following OPLINE guard or jmp [IP] */ - | LOAD_ADDR TMP1, zend_jit_halt_op - | cmp IP, TMP1 - | beq ->trace_halt -#endif - } else if (GCC_GLOBAL_REGS) { - | cbz IP, ->trace_halt - } else { - | tst RETVALw, RETVALw - | blt ->trace_halt - } - } else if (opline->opcode == ZEND_EXIT || - opline->opcode == ZEND_GENERATOR_RETURN || - opline->opcode == ZEND_YIELD || - opline->opcode == ZEND_YIELD_FROM) { - | b ->trace_halt - } - if (trace->op != ZEND_JIT_TRACE_END || - (trace->stop != ZEND_JIT_TRACE_STOP_RETURN && - trace->stop != ZEND_JIT_TRACE_STOP_INTERPRETER)) { - - const zend_op *next_opline = trace->opline; - const zend_op *exit_opline = NULL; - uint32_t exit_point; - const void *exit_addr; - uint32_t old_info = 0; - uint32_t old_res_info = 0; - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - - if (zend_is_smart_branch(opline)) { - bool exit_if_true = 0; - exit_opline = zend_jit_trace_get_exit_opline(trace, opline + 1, &exit_if_true); - } else { - switch (opline->opcode) { - case ZEND_JMPZ: - case ZEND_JMPNZ: - case ZEND_JMPZ_EX: - case ZEND_JMPNZ_EX: - case ZEND_JMP_SET: - case ZEND_COALESCE: - case ZEND_JMP_NULL: - case ZEND_FE_RESET_R: - case ZEND_FE_RESET_RW: - exit_opline = (trace->opline == opline + 1) ? - OP_JMP_ADDR(opline, opline->op2) : - opline + 1; - break; - case ZEND_FE_FETCH_R: - case ZEND_FE_FETCH_RW: - exit_opline = (trace->opline == opline + 1) ? - ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) : - opline + 1; - break; - - } - } - - switch (opline->opcode) { - case ZEND_FE_FETCH_R: - case ZEND_FE_FETCH_RW: - if (opline->op2_type != IS_UNUSED) { - old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op2.var), IS_UNKNOWN, 1); - } - break; - case ZEND_BIND_INIT_STATIC_OR_JMP: - if (opline->op1_type == IS_CV) { - old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_UNKNOWN, 1); - } - break; - } - - if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) { - old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1); - } - exit_point = zend_jit_trace_get_exit_point(exit_opline, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (opline->result_type == IS_VAR || opline->result_type == IS_TMP_VAR) { - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info); - } - switch (opline->opcode) { - case ZEND_FE_FETCH_R: - case ZEND_FE_FETCH_RW: - if (opline->op2_type != IS_UNUSED) { - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op2.var), old_info); - } - break; - case ZEND_BIND_INIT_STATIC_OR_JMP: - if (opline->op1_type == IS_CV) { - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_info); - } - break; - } - - if (!exit_addr) { - return 0; - } - | CMP_IP next_opline, TMP1, TMP2 - | bne &exit_addr - } - } - - zend_jit_set_last_valid_opline(trace->opline); - - return 1; -} - -static int zend_jit_handler(dasm_State **Dst, const zend_op *opline, int may_throw) -{ - const void *handler; - - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - handler = zend_get_opcode_handler_func(opline); - } else { - handler = opline->handler; - } - - if (!zend_jit_set_valid_ip(Dst, opline)) { - return 0; - } - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, FP - } - | EXT_CALL handler, REG0 - if (may_throw) { - zend_jit_check_exception(Dst); - } - - /* Skip the following OP_DATA */ - switch (opline->opcode) { - case ZEND_ASSIGN_DIM: - case ZEND_ASSIGN_OBJ: - case ZEND_ASSIGN_STATIC_PROP: - case ZEND_ASSIGN_DIM_OP: - case ZEND_ASSIGN_OBJ_OP: - case ZEND_ASSIGN_STATIC_PROP_OP: - case ZEND_ASSIGN_STATIC_PROP_REF: - case ZEND_ASSIGN_OBJ_REF: - zend_jit_set_last_valid_opline(opline + 2); - break; - default: - zend_jit_set_last_valid_opline(opline + 1); - break; - } - - return 1; -} - -static int zend_jit_tail_handler(dasm_State **Dst, const zend_op *opline) -{ - if (!zend_jit_set_valid_ip(Dst, opline)) { - return 0; - } - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - if (opline->opcode == ZEND_DO_UCALL || - opline->opcode == ZEND_DO_FCALL_BY_NAME || - opline->opcode == ZEND_DO_FCALL || - opline->opcode == ZEND_RETURN) { - - /* Use inlined HYBRID VM handler */ - const void *handler = opline->handler; - - | ADD_HYBRID_SPAD - | EXT_JMP handler, REG0 - } else { - const void *handler = zend_get_opcode_handler_func(opline); - - | EXT_CALL handler, REG0 - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - } - } else { - const void *handler = opline->handler; - - if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - } else { - | mov FCARG1x, FP - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - } - | EXT_JMP handler, REG0 - } - zend_jit_reset_last_valid_opline(); - return 1; -} - -static int zend_jit_trace_opline_guard(dasm_State **Dst, const zend_op *opline) -{ - uint32_t exit_point = zend_jit_trace_get_exit_point(NULL, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | CMP_IP opline, TMP1, TMP2 - | bne &exit_addr - - zend_jit_set_last_valid_opline(opline); - - return 1; -} - -static int zend_jit_jmp(dasm_State **Dst, unsigned int target_label) -{ - | b =>target_label - return 1; -} - -static int zend_jit_cond_jmp(dasm_State **Dst, const zend_op *next_opline, unsigned int target_label) -{ - | CMP_IP next_opline, TMP1, TMP2 - | bne =>target_label - - zend_jit_set_last_valid_opline(next_opline); - - return 1; -} - -#ifdef CONTEXT_THREADED_JIT -static int zend_jit_context_threaded_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block) -{ - | NIY // TODO - return 1; -} -#endif - -static int zend_jit_call(dasm_State **Dst, const zend_op *opline, unsigned int next_block) -{ -#ifdef CONTEXT_THREADED_JIT - return zend_jit_context_threaded_call(Dst, opline, next_block); -#else - return zend_jit_tail_handler(Dst, opline); -#endif -} - -static int zend_jit_spill_store(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info, bool set_type) -{ - ZEND_ASSERT(Z_MODE(src) == IS_REG); - ZEND_ASSERT(Z_MODE(dst) == IS_MEM_ZVAL); - - if ((info & MAY_BE_ANY) == MAY_BE_LONG) { - | SET_ZVAL_LVAL_FROM_REG dst, Rx(Z_REG(src)), TMP1 - if (set_type && - (Z_REG(dst) != ZREG_FP || - !JIT_G(current_frame) || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_LONG)) { - | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2 - } - } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) { - | SET_ZVAL_DVAL dst, Z_REG(src), ZREG_TMP1 - if (set_type && - (Z_REG(dst) != ZREG_FP || - !JIT_G(current_frame) || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(dst))) != IS_DOUBLE)) { - | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2 - } - } else { - ZEND_UNREACHABLE(); - } - return 1; -} - -static int zend_jit_load_reg(dasm_State **Dst, zend_jit_addr src, zend_jit_addr dst, uint32_t info) -{ - ZEND_ASSERT(Z_MODE(src) == IS_MEM_ZVAL); - ZEND_ASSERT(Z_MODE(dst) == IS_REG); - - if ((info & MAY_BE_ANY) == MAY_BE_LONG) { - | GET_ZVAL_LVAL Z_REG(dst), src, TMP1 - } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) { - | GET_ZVAL_DVAL Z_REG(dst), src, ZREG_TMP1 - } else { - ZEND_UNREACHABLE(); - } - return 1; -} - -static int zend_jit_store_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg, bool set_type) -{ - zend_jit_addr src = ZEND_ADDR_REG(reg); - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var)); - - return zend_jit_spill_store(Dst, src, dst, info, set_type); -} - -static int zend_jit_store_var_type(dasm_State **Dst, int var, uint32_t type) -{ - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var)); - - | SET_ZVAL_TYPE_INFO dst, type, TMP1w, TMP2 - return 1; -} - -static int zend_jit_store_var_if_necessary(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info) -{ - if (Z_MODE(src) == IS_REG && Z_STORE(src)) { - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - return zend_jit_spill_store(Dst, src, dst, info, 1); - } - return 1; -} - -static int zend_jit_store_var_if_necessary_ex(dasm_State **Dst, int var, zend_jit_addr src, uint32_t info, zend_jit_addr old, uint32_t old_info) -{ - if (Z_MODE(src) == IS_REG && Z_STORE(src)) { - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - bool set_type = 1; - - if ((info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == - (old_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF))) { - if (Z_MODE(old) != IS_REG || Z_LOAD(old) || Z_STORE(old)) { - set_type = 0; - } - } - return zend_jit_spill_store(Dst, src, dst, info, set_type); - } - return 1; -} - -static int zend_jit_load_var(dasm_State **Dst, uint32_t info, int var, zend_reg reg) -{ - zend_jit_addr src = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var)); - zend_jit_addr dst = ZEND_ADDR_REG(reg); - - return zend_jit_load_reg(Dst, src, dst, info); -} - -static int zend_jit_invalidate_var_if_necessary(dasm_State **Dst, uint8_t op_type, zend_jit_addr addr, znode_op op) -{ - if ((op_type & (IS_TMP_VAR|IS_VAR)) && Z_MODE(addr) == IS_REG && !Z_LOAD(addr) && !Z_STORE(addr)) { - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var); - | SET_ZVAL_TYPE_INFO dst, IS_UNDEF, TMP1w, TMP2 - } - return 1; -} - -static int zend_jit_update_regs(dasm_State **Dst, uint32_t var, zend_jit_addr src, zend_jit_addr dst, uint32_t info) -{ - if (!zend_jit_same_addr(src, dst)) { - if (Z_MODE(src) == IS_REG) { - if (Z_MODE(dst) == IS_REG) { - if ((info & MAY_BE_ANY) == MAY_BE_LONG) { - | mov Rx(Z_REG(dst)), Rx(Z_REG(src)) - } else if ((info & MAY_BE_ANY) == MAY_BE_DOUBLE) { - | fmov Rd(Z_REG(dst)-ZREG_V0), Rd(Z_REG(src)-ZREG_V0) - } else { - ZEND_UNREACHABLE(); - } - if (!Z_LOAD(src) && !Z_STORE(src) && Z_STORE(dst)) { - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - - if (!zend_jit_spill_store(Dst, dst, var_addr, info, - JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - JIT_G(current_frame) == NULL || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN || - (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY) - )) { - return 0; - } - } - } else if (Z_MODE(dst) == IS_MEM_ZVAL) { - if (!Z_LOAD(src) && !Z_STORE(src)) { - if (!zend_jit_spill_store(Dst, src, dst, info, - JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - JIT_G(current_frame) == NULL || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN || - (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY) - )) { - return 0; - } - } - } else { - ZEND_UNREACHABLE(); - } - } else if (Z_MODE(src) == IS_MEM_ZVAL) { - if (Z_MODE(dst) == IS_REG) { - if (!zend_jit_load_reg(Dst, src, dst, info)) { - return 0; - } - } else { - ZEND_UNREACHABLE(); - } - } else { - ZEND_UNREACHABLE(); - } - } else if (Z_MODE(dst) == IS_REG && Z_STORE(dst)) { - dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - if (!zend_jit_spill_store(Dst, src, dst, info, - JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - JIT_G(current_frame) == NULL || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var)) == IS_UNKNOWN || - (1 << STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(var))) != (info & MAY_BE_ANY) - )) { - return 0; - } - } - return 1; -} - -static int zend_jit_escape_if_undef_r0(dasm_State **Dst, int var, uint32_t flags, const zend_op *opline) -{ - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1 - - if (flags & ZEND_JIT_EXIT_RESTORE_CALL) { - if (!zend_jit_save_call_chain(Dst, -1)) { - return 0; - } - } - - ZEND_ASSERT(opline); - - if ((opline-1)->opcode != ZEND_FETCH_CONSTANT - && (opline-1)->opcode != ZEND_FETCH_LIST_R - && ((opline-1)->op1_type & (IS_VAR|IS_TMP_VAR)) - && !(flags & ZEND_JIT_EXIT_FREE_OP1)) { - val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, (opline-1)->op1.var); - - | IF_NOT_ZVAL_REFCOUNTED val_addr, >2, ZREG_TMP1, ZREG_TMP2 - | GET_ZVAL_PTR TMP1, val_addr, TMP2 - | GC_ADDREF TMP1, TMP2w - |2: - } - - | LOAD_IP_ADDR (opline - 1) - | b ->trace_escape - |1: - - return 1; -} - -static int zend_jit_store_const(dasm_State **Dst, int var, zend_reg reg) -{ - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, EX_NUM_TO_VAR(var)); - - if (reg == ZREG_LONG_MIN_MINUS_1) { - uint64_t val = 0xc3e0000000000000; - | SET_ZVAL_LVAL dst, val, TMP1, TMP2 - | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2 - } else if (reg == ZREG_LONG_MIN) { - uint64_t val = 0x8000000000000000; - | SET_ZVAL_LVAL dst, val, TMP1, TMP2 - | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2 - } else if (reg == ZREG_LONG_MAX) { - uint64_t val = 0x7fffffffffffffff; - | SET_ZVAL_LVAL dst, val, TMP1, TMP2 - | SET_ZVAL_TYPE_INFO dst, IS_LONG, TMP1w, TMP2 - } else if (reg == ZREG_LONG_MAX_PLUS_1) { - uint64_t val = 0x43e0000000000000; - | SET_ZVAL_LVAL dst, val, TMP1, TMP2 - | SET_ZVAL_TYPE_INFO dst, IS_DOUBLE, TMP1w, TMP2 - } else if (reg == ZREG_NULL) { - | SET_ZVAL_TYPE_INFO dst, IS_NULL, TMP1w, TMP2 - } else if (reg == ZREG_ZVAL_TRY_ADDREF) { - | IF_NOT_ZVAL_REFCOUNTED dst, >1, ZREG_TMP1, ZREG_TMP2 - | GET_ZVAL_PTR TMP1, dst, TMP2 - | GC_ADDREF TMP1, TMP2w - |1: - } else if (reg == ZREG_ZVAL_COPY_GPR0) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - | ZVAL_COPY_VALUE dst, -1, val_addr, -1, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF -1, REG1w, REG2, TMP1w - } else { - ZEND_UNREACHABLE(); - } - return 1; -} - -static int zend_jit_free_trampoline(dasm_State **Dst) -{ - | // if (UNEXPECTED(func->common.fn_flags & ZEND_ACC_CALL_VIA_TRAMPOLINE)) - | ldr TMP1w, [REG0, #offsetof(zend_function, common.fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_CALL_VIA_TRAMPOLINE, TMP2w - | beq >1 - | mov FCARG1x, REG0 - | EXT_CALL zend_jit_free_trampoline_helper, REG0 - |1: - return 1; -} - -static int zend_jit_inc_dec(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op1_def_info, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw) -{ - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2, ZREG_TMP1 - } - if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, MAY_BE_LONG)) { - return 0; - } - if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { - | LONG_ADD_SUB_WITH_IMM adds, op1_def_addr, Z_L(1), TMP1, TMP2 - } else { - | LONG_ADD_SUB_WITH_IMM subs, op1_def_addr, Z_L(1), TMP1, TMP2 - } - - if (may_overflow && - (((op1_def_info & MAY_BE_GUARD) && (op1_def_info & MAY_BE_LONG)) || - ((opline->result_type != IS_UNUSED && (res_info & MAY_BE_GUARD) && (res_info & MAY_BE_LONG))))) { - int32_t exit_point; - const void *exit_addr; - zend_jit_trace_stack *stack; - uint32_t old_op1_info, old_res_info = 0; - - stack = JIT_G(current_frame)->stack; - old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->op1.var), IS_DOUBLE, 0); - if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MAX_PLUS_1); - } else { - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_LONG_MIN_MINUS_1); - } - if (opline->result_type != IS_UNUSED) { - old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - if (opline->opcode == ZEND_PRE_INC) { - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX_PLUS_1); - } else if (opline->opcode == ZEND_PRE_DEC) { - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN_MINUS_1); - } else if (opline->opcode == ZEND_POST_INC) { - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MAX); - } else if (opline->opcode == ZEND_POST_DEC) { - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_LONG, 0); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_LONG_MIN); - } - } - - exit_point = zend_jit_trace_get_exit_point(opline + 1, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | bvs &exit_addr - - if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) && - opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info); - if (opline->result_type != IS_UNUSED) { - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info); - } - } else if (may_overflow) { - | bvs >1 - if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) && - opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - |.cold_code - |1: - if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { - uint64_t val = 0x43e0000000000000; - if (Z_MODE(op1_def_addr) == IS_REG) { - | LOAD_64BIT_VAL TMP1, val - | fmov Rd(Z_REG(op1_def_addr)-ZREG_V0), TMP1 - } else { - | SET_ZVAL_LVAL op1_def_addr, val, TMP2, TMP1 - } - } else { - uint64_t val = 0xc3e0000000000000; - if (Z_MODE(op1_def_addr) == IS_REG) { - | LOAD_64BIT_VAL TMP1, val - | fmov Rd(Z_REG(op1_def_addr)-ZREG_V0), TMP1 - } else { - | SET_ZVAL_LVAL op1_def_addr, val, TMP2, TMP1 - } - } - if (Z_MODE(op1_def_addr) == IS_MEM_ZVAL) { - | SET_ZVAL_TYPE_INFO op1_def_addr, IS_DOUBLE, TMP1w, TMP2 - } - if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) && - opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_DOUBLE, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - | b >3 - |.code - } else { - if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) && - opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_def_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - } - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { - |.cold_code - |2: - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | SET_EX_OPLINE opline, REG0 - if (op1_info & MAY_BE_UNDEF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >2, ZREG_TMP1 - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2 - op1_info |= MAY_BE_NULL; - } - |2: - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - - | // ZVAL_DEREF(var_ptr); - if (op1_info & MAY_BE_REF) { - | IF_NOT_Z_TYPE, FCARG1x, IS_REFERENCE, >2, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbz TMP1, >1 - if (RETURN_VALUE_USED(opline)) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - } else { - | mov FCARG2x, xzr - } - if (opline->opcode == ZEND_PRE_INC) { - | EXT_CALL zend_jit_pre_inc_typed_ref, REG0 - } else if (opline->opcode == ZEND_PRE_DEC) { - | EXT_CALL zend_jit_pre_dec_typed_ref, REG0 - } else if (opline->opcode == ZEND_POST_INC) { - | EXT_CALL zend_jit_post_inc_typed_ref, REG0 - } else if (opline->opcode == ZEND_POST_DEC) { - | EXT_CALL zend_jit_post_dec_typed_ref, REG0 - } else { - ZEND_UNREACHABLE(); - } - zend_jit_check_exception(Dst); - | b >3 - |1: - | add FCARG1x, FCARG1x, #offsetof(zend_reference, val) - |2: - } - - if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - - | ZVAL_COPY_VALUE res_addr, res_use_info, val_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF op1_info, REG0w, REG2, TMP1w - } - if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { - if (opline->opcode == ZEND_PRE_INC && opline->result_type != IS_UNUSED) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | EXT_CALL zend_jit_pre_inc, REG0 - } else { - | EXT_CALL increment_function, REG0 - } - } else { - if (opline->opcode == ZEND_PRE_DEC && opline->result_type != IS_UNUSED) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | EXT_CALL zend_jit_pre_dec, REG0 - } else { - | EXT_CALL decrement_function, REG0 - } - } - if (may_throw) { - zend_jit_check_exception(Dst); - } - } else { - zend_reg tmp_reg; - - if (opline->opcode == ZEND_POST_INC || opline->opcode == ZEND_POST_DEC) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, MAY_BE_DOUBLE, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - if (Z_MODE(op1_def_addr) == IS_REG) { - tmp_reg = Z_REG(op1_def_addr); - } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) { - tmp_reg = Z_REG(op1_addr); - } else { - tmp_reg = ZREG_FPR0; - } - | GET_ZVAL_DVAL tmp_reg, op1_addr, ZREG_TMP1 - if (opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_POST_INC) { - uint64_t val = 0x3ff0000000000000; // 1.0 - | LOAD_64BIT_VAL TMP1, val - | fmov FPTMP, TMP1 - | fadd Rd(tmp_reg-ZREG_V0), Rd(tmp_reg-ZREG_V0), FPTMP - } else { - uint64_t val = 0x3ff0000000000000; // 1.0 - | LOAD_64BIT_VAL TMP1, val - | fmov FPTMP, TMP1 - | fsub Rd(tmp_reg-ZREG_V0), Rd(tmp_reg-ZREG_V0), FPTMP - } - | SET_ZVAL_DVAL op1_def_addr, tmp_reg, ZREG_TMP1 - if ((opline->opcode == ZEND_PRE_INC || opline->opcode == ZEND_PRE_DEC) && - opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, res_use_info, op1_addr, op1_def_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF op1_def_info, REG0w, REG1, TMP1w - } - } - | b >3 - |.code - } - |3: - if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_def_addr, op1_def_info, op1_addr, op1_info)) { - return 0; - } - if (opline->result_type != IS_UNUSED) { - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - } - return 1; -} - -static int zend_jit_opline_uses_reg(const zend_op *opline, int8_t reg) -{ - if ((opline+1)->opcode == ZEND_OP_DATA - && ((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) - && JIT_G(current_frame)->stack[EX_VAR_TO_NUM((opline+1)->op1.var)].reg == reg) { - return 1; - } - return - ((opline->result_type & (IS_VAR|IS_TMP_VAR|IS_CV)) && - JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->result.var)].reg == reg) || - ((opline->op1_type & (IS_VAR|IS_TMP_VAR|IS_CV)) && - JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op1.var)].reg == reg) || - ((opline->op2_type & (IS_VAR|IS_TMP_VAR|IS_CV)) && - JIT_G(current_frame)->stack[EX_VAR_TO_NUM(opline->op2.var)].reg == reg); -} - -static int zend_jit_math_long_long(dasm_State **Dst, - const zend_op *opline, - uint8_t opcode, - zend_jit_addr op1_addr, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - uint32_t res_info, - uint32_t res_use_info, - int may_overflow) -{ - bool same_ops = zend_jit_same_addr(op1_addr, op2_addr); - zend_reg result_reg; - zend_reg tmp_reg = ZREG_REG0; - bool use_ovf_flag = 1; - - if (Z_MODE(res_addr) == IS_REG && (res_info & MAY_BE_LONG)) { - if (may_overflow && (res_info & MAY_BE_GUARD) - && JIT_G(current_frame) - && zend_jit_opline_uses_reg(opline, Z_REG(res_addr))) { - result_reg = ZREG_REG0; - } else { - result_reg = Z_REG(res_addr); - } - } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr) && !may_overflow) { - result_reg = Z_REG(op1_addr); - } else if (Z_REG(res_addr) != ZREG_REG0) { - result_reg = ZREG_REG0; - } else { - /* ASSIGN_DIM_OP */ - result_reg = ZREG_FCARG1; - tmp_reg = ZREG_FCARG1; - } - - if (opcode == ZEND_MUL && - Z_MODE(op2_addr) == IS_CONST_ZVAL && - Z_LVAL_P(Z_ZV(op2_addr)) == 2) { - if (Z_MODE(op1_addr) == IS_REG) { - | adds Rx(result_reg), Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr)) - } else { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | adds Rx(result_reg), Rx(result_reg), Rx(result_reg) - } - } else if (opcode == ZEND_MUL && - Z_MODE(op2_addr) == IS_CONST_ZVAL && - !may_overflow && - zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr)))) { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | mov TMP1, #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr))) - | lsl Rx(result_reg), Rx(result_reg), TMP1 - } else if (opcode == ZEND_MUL && - Z_MODE(op1_addr) == IS_CONST_ZVAL && - Z_LVAL_P(Z_ZV(op1_addr)) == 2) { - if (Z_MODE(op2_addr) == IS_REG) { - | adds Rx(result_reg), Rx(Z_REG(op2_addr)), Rx(Z_REG(op2_addr)) - } else { - | GET_ZVAL_LVAL result_reg, op2_addr, TMP1 - | adds Rx(result_reg), Rx(result_reg), Rx(result_reg) - } - } else if (opcode == ZEND_MUL && - Z_MODE(op1_addr) == IS_CONST_ZVAL && - !may_overflow && - zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op1_addr)))) { - | GET_ZVAL_LVAL result_reg, op2_addr, TMP1 - | mov TMP1, #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op1_addr))) - | lsl Rx(result_reg), Rx(result_reg), TMP1 - } else if (opcode == ZEND_DIV && - (Z_MODE(op2_addr) == IS_CONST_ZVAL && - zend_long_is_power_of_two(Z_LVAL_P(Z_ZV(op2_addr))))) { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | asr Rx(result_reg), Rx(result_reg), #zend_long_floor_log2(Z_LVAL_P(Z_ZV(op2_addr))) -#if 0 - /* x86 specific optimizations through LEA instraction are not supported on ARM */ - } else if (opcode == ZEND_ADD && - !may_overflow && - Z_MODE(op1_addr) == IS_REG && - Z_MODE(op2_addr) == IS_CONST_ZVAL) { - | NIY // TODO: test - } else if (opcode == ZEND_ADD && - !may_overflow && - Z_MODE(op2_addr) == IS_REG && - Z_MODE(op1_addr) == IS_CONST_ZVAL) { - | NIY // TODO: test - } else if (opcode == ZEND_SUB && - !may_overflow && - Z_MODE(op1_addr) == IS_REG && - Z_MODE(op2_addr) == IS_CONST_ZVAL) { - | NIY // TODO: test -#endif - } else if (opcode == ZEND_MUL) { - | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1 - | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2 - | mul Rx(result_reg), TMP1, TMP2 - if(may_overflow) { - /* Use 'smulh' to get the upper 64 bits fo the 128-bit result. - * For signed multiplication, the top 65 bits of the result will contain - * either all zeros or all ones if no overflow occurred. - * Flag: bne -> overflow. beq -> no overflow. - */ - use_ovf_flag = 0; - | smulh TMP1, TMP1, TMP2 - | cmp TMP1, Rx(result_reg), asr #63 - } - } else { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - if ((opcode == ZEND_ADD || opcode == ZEND_SUB) - && Z_MODE(op2_addr) == IS_CONST_ZVAL - && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { - /* +/- 0 */ - may_overflow = 0; - } else if (same_ops && opcode != ZEND_DIV) { - | LONG_MATH_REG opcode, Rx(result_reg), Rx(result_reg), Rx(result_reg) - } else { - | LONG_MATH opcode, result_reg, op2_addr, TMP1 - } - } - if (may_overflow) { - if (res_info & MAY_BE_GUARD) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - if ((res_info & MAY_BE_ANY) == MAY_BE_LONG) { - if (use_ovf_flag) { - | bvs &exit_addr - } else { - | bne &exit_addr - } - if (Z_MODE(res_addr) == IS_REG && result_reg != Z_REG(res_addr)) { - | mov Rx(Z_REG(res_addr)), Rx(result_reg) - } - } else if ((res_info & MAY_BE_ANY) == MAY_BE_DOUBLE) { - if (use_ovf_flag) { - | bvc &exit_addr - } else { - | beq &exit_addr - } - } else { - ZEND_UNREACHABLE(); - } - } else { - if (res_info & MAY_BE_LONG) { - if (use_ovf_flag) { - | bvs >1 - } else { - | bne >1 - } - } else { - if (use_ovf_flag) { - | bvc >1 - } else { - | beq >1 - } - } - } - } - - if (Z_MODE(res_addr) == IS_MEM_ZVAL && (res_info & MAY_BE_LONG)) { - | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(result_reg), TMP1 - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) { - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - } - } - - if (may_overflow && (!(res_info & MAY_BE_GUARD) || (res_info & MAY_BE_ANY) == MAY_BE_DOUBLE)) { - zend_reg tmp_reg1 = ZREG_FPR0; - zend_reg tmp_reg2 = ZREG_FPR1; - - if (res_info & MAY_BE_LONG) { - |.cold_code - |1: - } - - do { - if ((Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 1) || - (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 1)) { - if (opcode == ZEND_ADD) { - uint64_t val = 0x43e0000000000000; - if (Z_MODE(res_addr) == IS_REG) { - | LOAD_64BIT_VAL TMP1, val - | fmov Rd(Z_REG(res_addr)-ZREG_V0), TMP1 - } else { - | SET_ZVAL_LVAL res_addr, val, TMP2, TMP1 - } - break; - } else if (opcode == ZEND_SUB) { - uint64_t val = 0xc3e0000000000000; - if (Z_MODE(res_addr) == IS_REG) { - | LOAD_64BIT_VAL TMP1, val - | fmov Rd(Z_REG(res_addr)-ZREG_V0), TMP1 - } else { - | SET_ZVAL_LVAL res_addr, val, TMP2, TMP1 - } - break; - } - } - - | DOUBLE_GET_ZVAL_LVAL tmp_reg1, op1_addr, tmp_reg, ZREG_TMP1 - | DOUBLE_GET_ZVAL_LVAL tmp_reg2, op2_addr, tmp_reg, ZREG_TMP1 - | DOUBLE_MATH_REG opcode, tmp_reg1, tmp_reg1, tmp_reg2 - | SET_ZVAL_DVAL res_addr, tmp_reg1, ZREG_TMP1 - } while (0); - - if (Z_MODE(res_addr) == IS_MEM_ZVAL - && (res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - if (res_info & MAY_BE_LONG) { - | b >2 - |.code - } - |2: - } - - return 1; -} - -static int zend_jit_math_long_double(dasm_State **Dst, - uint8_t opcode, - zend_jit_addr op1_addr, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - uint32_t res_use_info) -{ - zend_reg result_reg = - (Z_MODE(res_addr) == IS_REG) ? Z_REG(res_addr) : ZREG_FPR0; - zend_reg op2_reg; - - | DOUBLE_GET_ZVAL_LVAL result_reg, op1_addr, ZREG_TMP1, ZREG_TMP2 - - if (Z_MODE(op2_addr) == IS_REG) { - op2_reg = Z_REG(op2_addr); - } else { - op2_reg = ZREG_FPTMP; - | GET_ZVAL_DVAL op2_reg, op2_addr, ZREG_TMP1 - } - - | DOUBLE_MATH_REG opcode, result_reg, result_reg, op2_reg - - | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1 - - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - } - - return 1; -} - -static int zend_jit_math_double_long(dasm_State **Dst, - uint8_t opcode, - zend_jit_addr op1_addr, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - uint32_t res_use_info) -{ - zend_reg result_reg, op1_reg, op2_reg; - - if (zend_is_commutative(opcode) - && (Z_MODE(res_addr) != IS_REG || Z_MODE(op1_addr) != IS_REG || Z_REG(res_addr) != Z_REG(op1_addr))) { - if (Z_MODE(res_addr) == IS_REG) { - result_reg = Z_REG(res_addr); - } else { - result_reg = ZREG_FPR0; - } - | DOUBLE_GET_ZVAL_LVAL result_reg, op2_addr, ZREG_TMP1, ZREG_TMP2 - if (Z_MODE(op1_addr) == IS_REG) { - op1_reg = Z_REG(op1_addr); - } else { - op1_reg = ZREG_FPTMP; - | GET_ZVAL_DVAL op1_reg, op1_addr, ZREG_TMP1 - } - | DOUBLE_MATH_REG opcode, result_reg, result_reg, op1_reg - } else { - if (Z_MODE(res_addr) == IS_REG) { - result_reg = Z_REG(res_addr); - } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) { - result_reg = Z_REG(op1_addr); - } else { - result_reg = ZREG_FPR0; - } - - if (Z_MODE(op1_addr) == IS_REG) { - op1_reg = Z_REG(op1_addr); - } else { - | GET_ZVAL_DVAL result_reg, op1_addr, ZREG_TMP1 - op1_reg = result_reg; - } - if ((opcode == ZEND_ADD || opcode == ZEND_SUB) - && Z_MODE(op2_addr) == IS_CONST_ZVAL - && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { - /* +/- 0 */ - } else { - op2_reg = ZREG_FPTMP; - | DOUBLE_GET_ZVAL_LVAL op2_reg, op2_addr, ZREG_TMP1, ZREG_TMP2 - | DOUBLE_MATH_REG opcode, result_reg, op1_reg, op2_reg - } - } - - | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1 - - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - } - } - - return 1; -} - -static int zend_jit_math_double_double(dasm_State **Dst, - uint8_t opcode, - zend_jit_addr op1_addr, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - uint32_t res_use_info) -{ - bool same_ops = zend_jit_same_addr(op1_addr, op2_addr); - zend_reg result_reg, op1_reg, op2_reg; - zend_jit_addr val_addr; - - if (Z_MODE(res_addr) == IS_REG) { - result_reg = Z_REG(res_addr); - } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) { - result_reg = Z_REG(op1_addr); - } else if (zend_is_commutative(opcode) && Z_MODE(op2_addr) == IS_REG && Z_LAST_USE(op2_addr)) { - result_reg = Z_REG(op2_addr); - } else { - result_reg = ZREG_FPR0; - } - - if (Z_MODE(op1_addr) == IS_REG) { - op1_reg = Z_REG(op1_addr); - val_addr = op2_addr; - } else if (Z_MODE(op2_addr) == IS_REG && zend_is_commutative(opcode)) { - op1_reg = Z_REG(op2_addr); - val_addr = op1_addr; - } else { - | GET_ZVAL_DVAL result_reg, op1_addr, ZREG_TMP1 - op1_reg = result_reg; - val_addr = op2_addr; - } - - if ((opcode == ZEND_MUL) && - Z_MODE(val_addr) == IS_CONST_ZVAL && Z_DVAL_P(Z_ZV(val_addr)) == 2.0) { - | DOUBLE_MATH_REG ZEND_ADD, result_reg, op1_reg, op1_reg - } else { - if (same_ops) { - op2_reg = op1_reg; - } else if (Z_MODE(val_addr) == IS_REG) { - op2_reg = Z_REG(val_addr); - } else { - op2_reg = ZREG_FPTMP; - | GET_ZVAL_DVAL op2_reg, val_addr, ZREG_TMP1 - } - | DOUBLE_MATH_REG opcode, result_reg, op1_reg, op2_reg - } - - | SET_ZVAL_DVAL res_addr, result_reg, ZREG_TMP1 - - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_DOUBLE) { - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - } - } - return 1; -} - -static int zend_jit_math_helper(dasm_State **Dst, - const zend_op *opline, - uint8_t opcode, - uint8_t op1_type, - znode_op op1, - zend_jit_addr op1_addr, - uint32_t op1_info, - uint8_t op2_type, - znode_op op2, - zend_jit_addr op2_addr, - uint32_t op2_info, - uint32_t res_var, - zend_jit_addr res_addr, - uint32_t res_info, - uint32_t res_use_info, - int may_overflow, - int may_throw) -/* Labels: 1,2,3,4,5,6 */ -{ - bool same_ops = zend_jit_same_addr(op1_addr, op2_addr); - - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - if (op1_info & (MAY_BE_ANY-MAY_BE_LONG)) { - if (op1_info & MAY_BE_DOUBLE) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1 - } - } - if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_LONG))) { - if (op2_info & MAY_BE_DOUBLE) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >1, ZREG_TMP1 - |.cold_code - |1: - if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - | b >5 - |.code - } else { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1 - } - } - if (!zend_jit_math_long_long(Dst, opline, opcode, op1_addr, op2_addr, res_addr, res_info, res_use_info, may_overflow)) { - return 0; - } - if (op1_info & MAY_BE_DOUBLE) { - |.cold_code - |3: - if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - if (op2_info & MAY_BE_DOUBLE) { - if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) { - if (!same_ops) { - | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >1, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE, op2_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - } - if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - | b >5 - } - if (!same_ops) { - |1: - if (op2_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1 - } - if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - | b >5 - } - |.code - } - } else if ((op1_info & MAY_BE_DOUBLE) && - !(op1_info & MAY_BE_LONG) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (res_info & MAY_BE_DOUBLE)) { - if (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - if (op2_info & MAY_BE_DOUBLE) { - if (!same_ops && (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) { - if (!same_ops && (op2_info & MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >1, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - } - if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - } - if (!same_ops && (op2_info & MAY_BE_LONG)) { - if (op2_info & MAY_BE_DOUBLE) { - |.cold_code - } - |1: - if (op2_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1 - } - if (!zend_jit_math_double_long(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - if (op2_info & MAY_BE_DOUBLE) { - | b >5 - |.code - } - } - } else if ((op2_info & MAY_BE_DOUBLE) && - !(op2_info & MAY_BE_LONG) && - (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (res_info & MAY_BE_DOUBLE)) { - if (op2_info & (MAY_BE_ANY-MAY_BE_DOUBLE)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - if (op1_info & MAY_BE_DOUBLE) { - if (!same_ops && (op1_info & (MAY_BE_ANY-MAY_BE_DOUBLE))) { - if (!same_ops && (op1_info & MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >1, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >6, ZREG_TMP1 - } - } - if (!zend_jit_math_double_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - } - if (!same_ops && (op1_info & MAY_BE_LONG)) { - if (op1_info & MAY_BE_DOUBLE) { - |.cold_code - } - |1: - if (op1_info & (MAY_BE_ANY-(MAY_BE_DOUBLE|MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1 - } - if (!zend_jit_math_long_double(Dst, opcode, op1_addr, op2_addr, res_addr, res_use_info)) { - return 0; - } - if (op1_info & MAY_BE_DOUBLE) { - | b >5 - |.code - } - } - } - - |5: - - if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) || - (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) { - if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - |.cold_code - } - |6: - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) { - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - | LOAD_ZVAL_ADDR FCARG1x, real_addr - } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - } else { - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - | LOAD_ZVAL_ADDR FCARG1x, real_addr - } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - } - if (Z_MODE(op2_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var); - if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) { - return 0; - } - op2_addr = real_addr; - } - | LOAD_ZVAL_ADDR CARG3, op2_addr - | SET_EX_OPLINE opline, REG0 - if (opcode == ZEND_ADD) { - | EXT_CALL add_function, REG0 - } else if (opcode == ZEND_SUB) { - | EXT_CALL sub_function, REG0 - } else if (opcode == ZEND_MUL) { - | EXT_CALL mul_function, REG0 - } else if (opcode == ZEND_DIV) { - | EXT_CALL div_function, REG0 - } else { - ZEND_UNREACHABLE(); - } - | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) { - | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1 - | cbnz TMP2, ->exception_handler_free_op2 - } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { - zend_jit_check_exception_undef_result(Dst, opline); - } else { - zend_jit_check_exception(Dst); - } - } - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) { - return 0; - } - } - if ((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (res_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - | b <5 - |.code - } - } - - return 1; -} - -static int zend_jit_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_overflow, int may_throw) -{ - ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF)); - ZEND_ASSERT((op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))); - - if (!zend_jit_math_helper(Dst, opline, opline->opcode, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->result.var, res_addr, res_info, res_use_info, may_overflow, may_throw)) { - return 0; - } - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - return 1; -} - -static int zend_jit_add_arrays(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr res_addr) -{ - if (Z_MODE(op2_addr) != IS_MEM_ZVAL || Z_REG(op2_addr) != ZREG_FCARG1) { - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - } else if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) { - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - } else { - | GET_ZVAL_LVAL ZREG_REG0, op2_addr, TMP1 - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - | mov FCARG2x, REG0 - } - | EXT_CALL zend_jit_add_arrays_helper, REG0 - | SET_ZVAL_PTR res_addr, RETVALx, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_ARRAY_EX, TMP1w, TMP2 - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - return 1; -} - -static int zend_jit_long_math_helper(dasm_State **Dst, - const zend_op *opline, - uint8_t opcode, - uint8_t op1_type, - znode_op op1, - zend_jit_addr op1_addr, - uint32_t op1_info, - zend_ssa_range *op1_range, - uint8_t op2_type, - znode_op op2, - zend_jit_addr op2_addr, - uint32_t op2_info, - zend_ssa_range *op2_range, - uint32_t res_var, - zend_jit_addr res_addr, - uint32_t res_info, - uint32_t res_use_info, - int may_throw) -/* Labels: 6 */ -{ - bool same_ops = zend_jit_same_addr(op1_addr, op2_addr); - zend_reg result_reg; - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1 - } - if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >6, ZREG_TMP1 - } - - if (Z_MODE(res_addr) == IS_REG) { - if ((opline->opcode == ZEND_SL || opline->opcode == ZEND_SR) - && opline->op2_type != IS_CONST) { - result_reg = ZREG_REG0; - } else { - result_reg = Z_REG(res_addr); - } - } else if (Z_MODE(op1_addr) == IS_REG && Z_LAST_USE(op1_addr)) { - result_reg = Z_REG(op1_addr); - } else if (Z_REG(res_addr) != ZREG_REG0) { - result_reg = ZREG_REG0; - } else { - /* ASSIGN_DIM_OP */ - result_reg = ZREG_FCARG1; - } - - if (opcode == ZEND_SL) { - if (Z_MODE(op2_addr) == IS_CONST_ZVAL) { - zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr)); - - if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { - if (EXPECTED(op2_lval > 0)) { - | mov Rx(result_reg), xzr - } else { - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->negative_shift - } - } else if (Z_MODE(op1_addr) == IS_REG && op2_lval == 1) { - | add Rx(result_reg), Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr)) - } else { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | lsl Rx(result_reg), Rx(result_reg), #op2_lval - } - } else { - zend_reg op2_reg; - - if (Z_MODE(op2_addr) == IS_REG) { - op2_reg = Z_REG(op2_addr); - } else { - op2_reg = ZREG_TMP2; - | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2 - } - if (!op2_range || - op2_range->min < 0 || - op2_range->max >= SIZEOF_ZEND_LONG * 8) { - - | cmp Rx(op2_reg), #(SIZEOF_ZEND_LONG*8) - | bhs >1 - |.cold_code - |1: - | mov Rx(result_reg), xzr - | cmp Rx(op2_reg), xzr - | bgt >1 - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->negative_shift - |.code - } - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | lsl Rx(result_reg), Rx(result_reg), Rx(op2_reg) - |1: - } - } else if (opcode == ZEND_SR) { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - if (Z_MODE(op2_addr) == IS_CONST_ZVAL) { - zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr)); - - if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) { - if (EXPECTED(op2_lval > 0)) { - | asr Rx(result_reg), Rx(result_reg), #((SIZEOF_ZEND_LONG * 8) - 1) - } else { - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->negative_shift - } - } else { - | asr Rx(result_reg), Rx(result_reg), #op2_lval - } - } else { - zend_reg op2_reg; - - if (Z_MODE(op2_addr) == IS_REG) { - op2_reg = Z_REG(op2_addr); - } else { - op2_reg = ZREG_TMP2; - | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2 - } - if (!op2_range || - op2_range->min < 0 || - op2_range->max >= SIZEOF_ZEND_LONG * 8) { - | cmp Rx(op2_reg), #(SIZEOF_ZEND_LONG*8) - | bhs >1 - |.cold_code - |1: - | cmp Rx(op2_reg), xzr - | mov Rx(op2_reg), #((SIZEOF_ZEND_LONG * 8) - 1) - | bgt >1 - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->negative_shift - |.code - } - |1: - | asr Rx(result_reg), Rx(result_reg), Rx(op2_reg) - } - } else if (opcode == ZEND_MOD) { - if (Z_MODE(op2_addr) == IS_CONST_ZVAL) { - zend_long op2_lval = Z_LVAL_P(Z_ZV(op2_addr)); - - if (op2_lval == 0) { - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->mod_by_zero - } else if (op2_lval == -1) { - | mov Rx(result_reg), xzr - } else if (zend_long_is_power_of_two(op2_lval) && op1_range && op1_range->min >= 0) { - zval tmp; - zend_jit_addr tmp_addr; - - /* Optimisation for mod of power of 2 */ - ZVAL_LONG(&tmp, op2_lval - 1); - tmp_addr = ZEND_ADDR_CONST_ZVAL(&tmp); - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | LONG_MATH ZEND_BW_AND, result_reg, tmp_addr, TMP1 - } else { - | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1 - | GET_ZVAL_LVAL ZREG_TMP2, op2_addr, TMP2 - | sdiv Rx(result_reg), TMP1, TMP2 - | msub Rx(result_reg), Rx(result_reg), TMP2, TMP1 - } - } else { - zend_reg op2_reg; - - if (Z_MODE(op2_addr) == IS_MEM_ZVAL) { - | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP2, Rx(Z_REG(op2_addr)), Z_OFFSET(op2_addr), TMP2 - op2_reg = ZREG_TMP2; - } else { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_REG); - op2_reg = Z_REG(op2_addr); - } - - if ((op2_type & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE)) || !op2_range || (op2_range->min <= 0 && op2_range->max >= 0)) { - | cbz Rx(op2_reg), >1 - |.cold_code - |1: - zend_jit_invalidate_var_if_necessary(Dst, op1_type, op1_addr, op1); - zend_jit_invalidate_var_if_necessary(Dst, op2_type, op2_addr, op2); - | SET_EX_OPLINE opline, REG0 - | b ->mod_by_zero - |.code - } - - /* Prevent overflow error/crash if op1 == LONG_MIN and op2 == -1 */ - if (!op2_range || (op2_range->min <= -1 && op2_range->max >= -1)) { - | cmn Rx(op2_reg), #1 - | beq >1 - |.cold_code - |1: - | SET_ZVAL_LVAL_FROM_REG res_addr, xzr, TMP1 - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) { - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - } - } - | b >5 - |.code - } - - | GET_ZVAL_LVAL ZREG_TMP1, op1_addr, TMP1 - | sdiv Rx(result_reg), TMP1, Rx(op2_reg) - | msub Rx(result_reg), Rx(result_reg), Rx(op2_reg), TMP1 - } - } else if (same_ops) { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | LONG_MATH_REG opcode, Rx(result_reg), Rx(result_reg), Rx(result_reg) - } else { - | GET_ZVAL_LVAL result_reg, op1_addr, TMP1 - | LONG_MATH opcode, result_reg, op2_addr, TMP1 - } - - if (Z_MODE(res_addr) != IS_REG || Z_REG(res_addr) != result_reg) { - | SET_ZVAL_LVAL_FROM_REG res_addr, Rx(result_reg), TMP1 - } - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != Z_REG(res_addr) || Z_OFFSET(op1_addr) != Z_OFFSET(res_addr)) { - if ((res_use_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF|MAY_BE_GUARD)) != MAY_BE_LONG) { - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - } - } - - if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) || - (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) { - if ((op1_info & MAY_BE_LONG) && - (op2_info & MAY_BE_LONG)) { - |.cold_code - } - |6: - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) { - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - | LOAD_ZVAL_ADDR FCARG1x, real_addr - } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - } else { - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - | LOAD_ZVAL_ADDR FCARG1x, real_addr - } else if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - } - if (Z_MODE(op2_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, op2.var); - if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) { - return 0; - } - op2_addr = real_addr; - } - | LOAD_ZVAL_ADDR CARG3, op2_addr - | SET_EX_OPLINE opline, REG0 - if (opcode == ZEND_BW_OR) { - | EXT_CALL bitwise_or_function, REG0 - } else if (opcode == ZEND_BW_AND) { - | EXT_CALL bitwise_and_function, REG0 - } else if (opcode == ZEND_BW_XOR) { - | EXT_CALL bitwise_xor_function, REG0 - } else if (opcode == ZEND_SL) { - | EXT_CALL shift_left_function, REG0 - } else if (opcode == ZEND_SR) { - | EXT_CALL shift_right_function, REG0 - } else if (opcode == ZEND_MOD) { - | EXT_CALL mod_function, REG0 - } else { - ZEND_UNREACHABLE(); - } - if (op1_addr == res_addr && (op2_info & MAY_BE_RCN)) { - /* compound assignment may decrement "op2" refcount */ - op2_info |= MAY_BE_RC1; - } - | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - if (opline->opcode == ZEND_ASSIGN_DIM_OP && (opline->op2_type & (IS_VAR|IS_TMP_VAR))) { - | MEM_LOAD_64_ZTS ldr, TMP2, executor_globals, exception, TMP1 - | cbnz TMP2, ->exception_handler_free_op2 - } else if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { - zend_jit_check_exception_undef_result(Dst, opline); - } else { - zend_jit_check_exception(Dst); - } - } - if (Z_MODE(res_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, res_var); - if (!zend_jit_load_reg(Dst, real_addr, res_addr, res_info)) { - return 0; - } - } - if ((op1_info & MAY_BE_LONG) && - (op2_info & MAY_BE_LONG)) { - | b >5 - |.code - } - } - |5: - - return 1; -} - -static int zend_jit_long_math(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_ssa_range *op1_range, zend_jit_addr op1_addr, uint32_t op2_info, zend_ssa_range *op2_range, zend_jit_addr op2_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr, int may_throw) -{ - ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF)); - ZEND_ASSERT((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)); - - if (!zend_jit_long_math_helper(Dst, opline, opline->opcode, - opline->op1_type, opline->op1, op1_addr, op1_info, op1_range, - opline->op2_type, opline->op2, op2_addr, op2_info, op2_range, - opline->result.var, res_addr, res_info, res_use_info, may_throw)) { - return 0; - } - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - return 1; -} - -static int zend_jit_concat_helper(dasm_State **Dst, - const zend_op *opline, - uint8_t op1_type, - znode_op op1, - zend_jit_addr op1_addr, - uint32_t op1_info, - uint8_t op2_type, - znode_op op2, - zend_jit_addr op2_addr, - uint32_t op2_info, - zend_jit_addr res_addr, - int may_throw) -{ - if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) { - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1 - } - if (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >6, ZREG_TMP1 - } - if (Z_MODE(op1_addr) == IS_MEM_ZVAL && Z_REG(op1_addr) == Z_REG(res_addr) && Z_OFFSET(op1_addr) == Z_OFFSET(res_addr)) { - if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | EXT_CALL zend_jit_fast_assign_concat_helper, REG0 - /* concatenation with itself may reduce refcount */ - op2_info |= MAY_BE_RC1; - } else { - if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - | LOAD_ZVAL_ADDR CARG3, op2_addr - if (op1_type == IS_CV || op1_type == IS_CONST) { - | EXT_CALL zend_jit_fast_concat_helper, REG0 - } else { - | EXT_CALL zend_jit_fast_concat_tmp_helper, REG0 - } - } - /* concatenation with empty string may increase refcount */ - op2_info |= MAY_BE_RCN; - | FREE_OP op2_type, op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - |5: - } - if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING)) || - (op2_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF) - MAY_BE_STRING))) { - if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) { - |.cold_code - |6: - } - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1) { - if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - } else { - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - } - | LOAD_ZVAL_ADDR CARG3, op2_addr - | SET_EX_OPLINE opline, REG0 - | EXT_CALL concat_function, REG0 - /* concatenation with empty string may increase refcount */ - op1_info |= MAY_BE_RCN; - op2_info |= MAY_BE_RCN; - | FREE_OP op1_type, op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - | FREE_OP op2_type, op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - if (Z_MODE(res_addr) == IS_MEM_ZVAL && Z_REG(res_addr) == ZREG_RX) { - zend_jit_check_exception_undef_result(Dst, opline); - } else { - zend_jit_check_exception(Dst); - } - } - if ((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)) { - | b <5 - |.code - } - } - - return 1; -} - -static int zend_jit_concat(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, zend_jit_addr res_addr, int may_throw) -{ - zend_jit_addr op1_addr, op2_addr; - - ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF)); - ZEND_ASSERT((op1_info & MAY_BE_STRING) && (op2_info & MAY_BE_STRING)); - - op1_addr = OP1_ADDR(); - op2_addr = OP2_ADDR(); - - return zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, res_addr, may_throw); -} - -static int zend_jit_fetch_dimension_address_inner(dasm_State **Dst, const zend_op *opline, uint32_t type, uint32_t op1_info, uint32_t op2_info, uint8_t dim_type, const void *found_exit_addr, const void *not_found_exit_addr, const void *exit_addr) -/* Labels: 1,2,3,4,5 */ -{ - zend_jit_addr op2_addr = OP2_ADDR(); - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && type == BP_VAR_R - && !exit_addr) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - } - - if (op2_info & MAY_BE_LONG) { - bool op2_loaded = 0; - bool packed_loaded = 0; - bool bad_packed_key = 0; - - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_LONG)) { - | // if (EXPECTED(Z_TYPE_P(dim) == IS_LONG)) - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3, ZREG_TMP1 - } - if (op1_info & MAY_BE_PACKED_GUARD) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - if (op1_info & MAY_BE_ARRAY_PACKED) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | beq &exit_addr - } else { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | bne &exit_addr - } - } - if (type == BP_VAR_W) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - op2_loaded = 1; - } - if (op1_info & MAY_BE_ARRAY_PACKED) { - zend_long val = -1; - - if (Z_MODE(op2_addr) == IS_CONST_ZVAL) { - val = Z_LVAL_P(Z_ZV(op2_addr)); - if (val >= 0 && val < HT_MAX_SIZE) { - packed_loaded = 1; - } else { - bad_packed_key = 1; - } - } else { - if (!op2_loaded) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - op2_loaded = 1; - } - packed_loaded = 1; - } - - if (dim_type == IS_UNDEF && type == BP_VAR_W) { - /* don't generate "fast" code for packed array */ - packed_loaded = 0; - } - - if (packed_loaded) { - | // ZEND_HASH_INDEX_FIND(ht, hval, retval, num_undef); - if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | beq >4 // HASH_FIND - } - | // if (EXPECTED((zend_ulong)(_h) < (zend_ulong)(_ht)->nNumUsed)) - - | ldr REG0w, [FCARG1x, #offsetof(zend_array, nNumUsed)] - if (val == 0) { - | cmp REG0, xzr - } else if (val > 0 && !op2_loaded) { - | CMP_64_WITH_CONST REG0, val, TMP1 - } else { - | cmp REG0, FCARG2x - } - - if (type == BP_JIT_IS) { - if (not_found_exit_addr) { - | bls ¬_found_exit_addr - } else { - | bls >9 // NOT_FOUND - } - } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - | bls &exit_addr - } else if (type == BP_VAR_IS && not_found_exit_addr) { - | bls ¬_found_exit_addr - } else if (type == BP_VAR_RW && not_found_exit_addr) { - | bls ¬_found_exit_addr - } else if (type == BP_VAR_IS && found_exit_addr) { - | bls >7 // NOT_FOUND - } else { - | bls >2 // NOT_FOUND - } - | // _ret = &_ht->arPacked[_h].val; - if (val >= 0) { - | ldr REG0, [FCARG1x, #offsetof(zend_array, arPacked)] - if (val != 0) { - | ADD_SUB_64_WITH_CONST add, REG0, REG0, (val * sizeof(zval)), TMP1 - } - } else { - | ldr TMP1, [FCARG1x, #offsetof(zend_array, arPacked)] - | add REG0, TMP1, FCARG2x, lsl #4 - } - } - } - switch (type) { - case BP_JIT_IS: - if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { - if (packed_loaded) { - | b >5 - } - |4: - if (!op2_loaded) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - } - if (packed_loaded) { - | EXT_CALL _zend_hash_index_find, REG0 - } else { - | EXT_CALL zend_hash_index_find, REG0 - } - | mov REG0, RETVALx - if (not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - } else { - | cbz REG0, >9 // NOT_FOUND - } - if (op2_info & MAY_BE_STRING) { - | b >5 - } - } else if (packed_loaded) { - if (op2_info & MAY_BE_STRING) { - | b >5 - } - } else if (not_found_exit_addr) { - | b ¬_found_exit_addr - } else { - | b >9 // NOT_FOUND - } - break; - case BP_VAR_R: - case BP_VAR_IS: - case BP_VAR_UNSET: - if (packed_loaded) { - if (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) { - | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w - } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - /* perform IS_UNDEF check only after result type guard (during deoptimization) */ - if (!found_exit_addr || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) { - | IF_Z_TYPE REG0, IS_UNDEF, &exit_addr, TMP1w - } - } else if (type == BP_VAR_IS && not_found_exit_addr) { - | IF_Z_TYPE REG0, IS_UNDEF, ¬_found_exit_addr, TMP1w - } else if (type == BP_VAR_IS && found_exit_addr) { - | IF_Z_TYPE REG0, IS_UNDEF, >7, TMP1w // NOT_FOUND - } else { - | IF_Z_TYPE REG0, IS_UNDEF, >2, TMP1w // NOT_FOUND - } - } - if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (packed_loaded && (op1_info & MAY_BE_ARRAY_NUMERIC_HASH))) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - | b &exit_addr - } else if (type == BP_VAR_IS && not_found_exit_addr) { - | b ¬_found_exit_addr - } else if (type == BP_VAR_IS && found_exit_addr) { - | b >7 // NOT_FOUND - } else { - | b >2 // NOT_FOUND - } - } - if (!packed_loaded || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) { - |4: - if (!op2_loaded) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - } - if (packed_loaded) { - | EXT_CALL _zend_hash_index_find, REG0 - } else { - | EXT_CALL zend_hash_index_find, REG0 - } - | mov REG0, RETVALx - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - | cbz REG0, &exit_addr - } else if (type == BP_VAR_IS && not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - } else if (type == BP_VAR_IS && found_exit_addr) { - | cbz REG0, >7 // NOT_FOUND - } else { - | cbz REG0, >2 // NOT_FOUND - } - } - |.cold_code - |2: - switch (type) { - case BP_VAR_R: - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - | // zend_error(E_WARNING,"Undefined array key " ZEND_LONG_FMT, hval); - | // retval = &EG(uninitialized_zval); - | UNDEFINED_OFFSET opline - | b >9 - } - break; - case BP_VAR_IS: - case BP_VAR_UNSET: - if (!not_found_exit_addr && !found_exit_addr) { - | // retval = &EG(uninitialized_zval); - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - | b >9 - } - break; - default: - ZEND_UNREACHABLE(); - } - |.code - break; - case BP_VAR_RW: - if (packed_loaded && !not_found_exit_addr) { - | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w - } - if (!packed_loaded || - !not_found_exit_addr || - (op1_info & MAY_BE_ARRAY_NUMERIC_HASH)) { - if (packed_loaded && not_found_exit_addr) { - |.cold_code - } - |2: - |4: - if (!op2_loaded) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - } - if (packed_loaded) { - | EXT_CALL zend_jit_hash_index_lookup_rw_no_packed, REG0 - } else { - | EXT_CALL zend_jit_hash_index_lookup_rw, REG0 - } - | mov REG0, RETVALx - if (not_found_exit_addr) { - if (packed_loaded) { - | cbnz REG0, >8 - | b ¬_found_exit_addr - |.code - } else { - | cbz REG0, ¬_found_exit_addr - } - } else { - | cbz REG0, >9 - } - } - break; - case BP_VAR_W: - if (packed_loaded) { - | IF_NOT_Z_TYPE REG0, IS_UNDEF, >8, TMP1w - } - if (!(op1_info & MAY_BE_ARRAY_KEY_LONG) || (op1_info & MAY_BE_ARRAY_NUMERIC_HASH) || packed_loaded || bad_packed_key || dim_type == IS_UNDEF) { - |2: - |4: - if (!op2_loaded) { - | // hval = Z_LVAL_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - } - | EXT_CALL zend_hash_index_lookup, REG0 - | mov REG0, RETVALx - } - break; - default: - ZEND_UNREACHABLE(); - } - - if (type != BP_JIT_IS && (op2_info & MAY_BE_STRING)) { - | b >8 - } - } - - if (op2_info & MAY_BE_STRING) { - |3: - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) { - | // if (EXPECTED(Z_TYPE_P(dim) == IS_STRING)) - | IF_NOT_ZVAL_TYPE op2_addr, IS_STRING, >3, ZREG_TMP1 - } - | // offset_key = Z_STR_P(dim); - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - | // retval = zend_hash_find(ht, offset_key); - switch (type) { - case BP_JIT_IS: - if (opline->op2_type != IS_CONST) { - | ldrb TMP1w, [FCARG2x, #offsetof(zend_string, val)] - | cmp TMP1w, #((uint8_t) ('9')) - | ble >1 - |.cold_code - |1: - | EXT_CALL zend_jit_symtable_find, REG0 - | b >1 - |.code - | EXT_CALL zend_hash_find, REG0 - |1: - } else { - | EXT_CALL zend_hash_find_known_hash, REG0 - } - | mov REG0, RETVALx - if (not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - } else { - | cbz REG0, >9 // NOT_FOUND - } - break; - case BP_VAR_R: - case BP_VAR_IS: - case BP_VAR_UNSET: - if (opline->op2_type != IS_CONST) { - | ldrb TMP1w, [FCARG2x, #offsetof(zend_string, val)] - | cmp TMP1w, #((uint8_t) ('9')) - | ble >1 - |.cold_code - |1: - | EXT_CALL zend_jit_symtable_find, REG0 - | b >1 - |.code - | EXT_CALL zend_hash_find, REG0 - |1: - } else { - | EXT_CALL zend_hash_find_known_hash, REG0 - } - | mov REG0, RETVALx - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && type == BP_VAR_R) { - | cbz REG0, &exit_addr - } else if (type == BP_VAR_IS && not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - } else if (type == BP_VAR_IS && found_exit_addr) { - | cbz REG0, >7 - } else { - | cbz REG0, >2 // NOT_FOUND - |.cold_code - |2: - switch (type) { - case BP_VAR_R: - // zend_error(E_WARNING, "Undefined array key \"%s\"", ZSTR_VAL(offset_key)); - | UNDEFINED_INDEX opline - | b >9 - break; - case BP_VAR_IS: - case BP_VAR_UNSET: - | // retval = &EG(uninitialized_zval); - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - | b >9 - break; - default: - ZEND_UNREACHABLE(); - } - |.code - } - break; - case BP_VAR_RW: - if (opline->op2_type != IS_CONST) { - | EXT_CALL zend_jit_symtable_lookup_rw, REG0 - } else { - | EXT_CALL zend_jit_hash_lookup_rw, REG0 - } - | mov REG0, RETVALx - if (not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - } else { - | cbz REG0, >9 - } - break; - case BP_VAR_W: - if (opline->op2_type != IS_CONST) { - | EXT_CALL zend_jit_symtable_lookup_w, REG0 - } else { - | EXT_CALL zend_hash_lookup, REG0 - } - | mov REG0, RETVALx - break; - default: - ZEND_UNREACHABLE(); - } - } - - if (type == BP_JIT_IS && (op2_info & (MAY_BE_LONG|MAY_BE_STRING))) { - |5: - if (op1_info & MAY_BE_ARRAY_OF_REF) { - | ZVAL_DEREF REG0, MAY_BE_REF, TMP1w - } - | ldrb TMP1w, [REG0,#offsetof(zval, u1.v.type)] - | cmp TMP1w, #IS_NULL - if (not_found_exit_addr) { - | ble ¬_found_exit_addr - } else if (found_exit_addr) { - | bgt &found_exit_addr - } else { - | ble >9 // NOT FOUND - } - } - - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) { - if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) { - |.cold_code - |3: - } - if (type != BP_VAR_RW) { - | SET_EX_OPLINE opline, REG0 - } - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - switch (type) { - case BP_VAR_R: - | LOAD_ZVAL_ADDR CARG3, res_addr - | EXT_CALL zend_jit_fetch_dim_r_helper, REG0 - | mov REG0, RETVALx - | b >9 - break; - case BP_JIT_IS: - | EXT_CALL zend_jit_fetch_dim_isset_helper, REG0 - | mov REG0, RETVALx - if (not_found_exit_addr) { - | cbz REG0, ¬_found_exit_addr - if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) { - | b >8 - } - } else if (found_exit_addr) { - | cbnz REG0, &found_exit_addr - if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) { - | b >9 - } - } else { - | cbnz REG0, >8 - | b >9 - } - break; - case BP_VAR_IS: - case BP_VAR_UNSET: - | LOAD_ZVAL_ADDR CARG3, res_addr - | EXT_CALL zend_jit_fetch_dim_is_helper, REG0 - | mov REG0, RETVALx - | b >9 - break; - case BP_VAR_RW: - | EXT_CALL zend_jit_fetch_dim_rw_helper, REG0 - | mov REG0, RETVALx - | cbnz REG0, >8 - | b >9 - break; - case BP_VAR_W: - | EXT_CALL zend_jit_fetch_dim_w_helper, REG0 - | mov REG0, RETVALx - | cbnz REG0, >8 - | b >9 - break; - default: - ZEND_UNREACHABLE(); - } - if (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) { - |.code - } - } - - return 1; -} - -static int zend_jit_simple_assign(dasm_State **Dst, - const zend_op *opline, - zend_jit_addr var_addr, - uint32_t var_info, - uint32_t var_def_info, - uint8_t val_type, - zend_jit_addr val_addr, - uint32_t val_info, - zend_jit_addr res_addr, - int in_cold, - int save_r1, - bool check_exception) -/* Labels: 1,2,3 */ -{ - zend_reg tmp_reg; - - if (Z_MODE(var_addr) == IS_REG || Z_REG(var_addr) != ZREG_REG0) { - tmp_reg = ZREG_REG0; - } else { - /* ASSIGN_DIM */ - tmp_reg = ZREG_FCARG1; - } - - if (Z_MODE(val_addr) == IS_CONST_ZVAL) { - zval *zv = Z_ZV(val_addr); - - if (!res_addr) { - | ZVAL_COPY_CONST var_addr, var_info, var_def_info, zv, tmp_reg, ZREG_TMP1, ZREG_FPR0 - } else { - | ZVAL_COPY_CONST_2 var_addr, res_addr, var_info, var_def_info, zv, tmp_reg, ZREG_TMP1, ZREG_FPR0 - } - if (Z_REFCOUNTED_P(zv)) { - if (!res_addr) { - | ADDREF_CONST zv, TMP1, TMP2 - } else { - | ADDREF_CONST_2 zv, TMP1, TMP2 - } - } - } else { - if (val_info & MAY_BE_UNDEF) { - if (in_cold) { - | IF_NOT_ZVAL_TYPE val_addr, IS_UNDEF, >2, ZREG_TMP1 - } else { - | IF_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1 - |.cold_code - |1: - } - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - if (save_r1) { - | str FCARG1x, T1 // save - } - | SET_ZVAL_TYPE_INFO var_addr, IS_NULL, TMP1w, TMP2 - if (res_addr) { - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - } - if (opline) { - | SET_EX_OPLINE opline, Rx(tmp_reg) - } - ZEND_ASSERT(Z_MODE(val_addr) == IS_MEM_ZVAL && Z_REG(val_addr) == ZREG_FP); - | LOAD_32BIT_VAL FCARG1w, Z_OFFSET(val_addr) - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (check_exception) { - | cbz RETVALx, ->exception_handler_undef - } - if (save_r1) { - | ldr FCARG1x, T1 // restore - } - | b >3 - if (in_cold) { - |2: - } else { - |.code - } - } - if (val_info & MAY_BE_REF) { - if (val_type == IS_CV) { - ZEND_ASSERT(Z_REG(var_addr) != ZREG_REG2); - if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_REG2 || Z_OFFSET(val_addr) != 0) { - | LOAD_ZVAL_ADDR REG2, val_addr - } - | ZVAL_DEREF REG2, val_info, TMP1w - val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, 0); - } else { - zend_jit_addr ref_addr; - - if (in_cold) { - | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, >1, ZREG_TMP1 - } else { - | IF_ZVAL_TYPE val_addr, IS_REFERENCE, >1, ZREG_TMP1 - |.cold_code - |1: - } - if (Z_REG(val_addr) == ZREG_REG2) { - | str REG2, T1 // save - } - | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - | GET_ZVAL_PTR REG2, val_addr, TMP1 - | GC_DELREF REG2, TMP1w - | // ZVAL_COPY_VALUE(return_value, &ref->val); - ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, offsetof(zend_reference, val)); - if (!res_addr) { - | ZVAL_COPY_VALUE var_addr, var_info, ref_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } else { - | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, ref_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - | beq >2 // GC_DELREF() reached zero - | IF_NOT_REFCOUNTED REG2w, >3, TMP1w - if (!res_addr) { - | GC_ADDREF Rx(tmp_reg), TMP1w - } else { - | GC_ADDREF_2 Rx(tmp_reg), TMP1w - } - | b >3 - |2: - if (res_addr) { - | IF_NOT_REFCOUNTED REG2w, >2, TMP1w - | GC_ADDREF Rx(tmp_reg), TMP1w - |2: - } - if (Z_REG(val_addr) == ZREG_REG2) { - | ldr REG2, T1 // restore - } - if (save_r1) { - | str FCARG1x, T1 // save - } - | GET_ZVAL_PTR FCARG1x, val_addr, TMP1 - | EFREE_REFERENCE - if (save_r1) { - | ldr FCARG1x, T1 // restore - } - | b >3 - if (in_cold) { - |1: - } else { - |.code - } - } - } - - if (!res_addr) { - | ZVAL_COPY_VALUE var_addr, var_info, val_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } else { - | ZVAL_COPY_VALUE_2 var_addr, var_info, res_addr, val_addr, val_info, ZREG_REG2, tmp_reg, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - - if (val_type == IS_CV) { - if (!res_addr) { - | TRY_ADDREF val_info, REG2w, Rx(tmp_reg), TMP1w - } else { - | TRY_ADDREF_2 val_info, REG2w, Rx(tmp_reg), TMP1w - } - } else { - if (res_addr) { - | TRY_ADDREF val_info, REG2w, Rx(tmp_reg), TMP1w - } - } - |3: - } - return 1; -} - -static int zend_jit_assign_to_typed_ref(dasm_State **Dst, - const zend_op *opline, - uint8_t val_type, - zend_jit_addr val_addr, - zend_jit_addr res_addr, - bool check_exception) -{ - | // if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) { - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbnz TMP1, >2 - |.cold_code - |2: - if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG2x, val_addr - } - if (opline) { - | SET_EX_OPLINE opline, REG0 - } - if (!res_addr) { - if (val_type == IS_CONST) { - | EXT_CALL zend_jit_assign_const_to_typed_ref, REG0 - } else if (val_type == IS_TMP_VAR) { - | EXT_CALL zend_jit_assign_tmp_to_typed_ref, REG0 - } else if (val_type == IS_VAR) { - | EXT_CALL zend_jit_assign_var_to_typed_ref, REG0 - } else if (val_type == IS_CV) { - | EXT_CALL zend_jit_assign_cv_to_typed_ref, REG0 - } else { - ZEND_UNREACHABLE(); - } - } else { - | LOAD_ZVAL_ADDR CARG3, res_addr - if (val_type == IS_CONST) { - | EXT_CALL zend_jit_assign_const_to_typed_ref2, REG0 - } else if (val_type == IS_TMP_VAR) { - | EXT_CALL zend_jit_assign_tmp_to_typed_ref2, REG0 - } else if (val_type == IS_VAR) { - | EXT_CALL zend_jit_assign_var_to_typed_ref2, REG0 - } else if (val_type == IS_CV) { - | EXT_CALL zend_jit_assign_cv_to_typed_ref2, REG0 - } else { - ZEND_UNREACHABLE(); - } - } - if (check_exception) { - | // if (UNEXPECTED(EG(exception) != NULL)) { - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbz REG0, >8 // END OF zend_jit_assign_to_variable() - | b ->exception_handler - } else { - | b >8 - } - |.code - - return 1; -} - -static int zend_jit_assign_to_variable_call(dasm_State **Dst, - const zend_op *opline, - zend_jit_addr __var_use_addr, - zend_jit_addr var_addr, - uint32_t __var_info, - uint32_t __var_def_info, - uint8_t val_type, - zend_jit_addr val_addr, - uint32_t val_info, - zend_jit_addr __res_addr, - bool __check_exception) -{ - if (val_info & MAY_BE_UNDEF) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | IF_ZVAL_TYPE val_addr, IS_UNDEF, &exit_addr, ZREG_TMP1 - } else { - | IF_ZVAL_TYPE val_addr, IS_UNDEF, >1, ZREG_TMP1 - |.cold_code - |1: - ZEND_ASSERT(Z_REG(val_addr) == ZREG_FP); - if (Z_REG(var_addr) != ZREG_FP) { - | str Rx(Z_REG(var_addr)), T1 // save - } - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, Z_OFFSET(val_addr) - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (Z_REG(var_addr) != ZREG_FP) { - | ldr Rx(Z_REG(var_addr)), T1 // restore - } - if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, var_addr - } - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | bl ->assign_const - | b >9 - |.code - |1: - } - } - if (Z_MODE(var_addr) != IS_MEM_ZVAL || Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, var_addr - } - if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG2x, val_addr - } - if (opline) { - | SET_EX_OPLINE opline, REG0 - } - if (!(val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { - | bl ->assign_tmp - } else if (val_type == IS_CONST) { - | bl ->assign_const - } else if (val_type == IS_TMP_VAR) { - | bl ->assign_tmp - } else if (val_type == IS_VAR) { - if (!(val_info & MAY_BE_REF)) { - | bl ->assign_tmp - } else { - | bl ->assign_var - } - } else if (val_type == IS_CV) { - if (!(val_info & MAY_BE_REF)) { - | bl ->assign_cv_noref - } else { - | bl ->assign_cv - } - if ((val_info & MAY_BE_UNDEF) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - |9: - } - } else { - ZEND_UNREACHABLE(); - } - - return 1; -} - -static int zend_jit_assign_to_variable(dasm_State **Dst, - const zend_op *opline, - zend_jit_addr var_use_addr, - zend_jit_addr var_addr, - uint32_t var_info, - uint32_t var_def_info, - uint8_t val_type, - zend_jit_addr val_addr, - uint32_t val_info, - zend_jit_addr res_addr, - bool check_exception) -/* Labels: 1,2,3,4,5,8 */ -{ - int done = 0; - zend_reg ref_reg, tmp_reg; - - if (Z_MODE(var_addr) == IS_REG || Z_REG(var_use_addr) != ZREG_REG0) { - ref_reg = ZREG_FCARG1; - tmp_reg = ZREG_REG0; - } else { - /* ASSIGN_DIM */ - ref_reg = ZREG_REG0; - tmp_reg = ZREG_FCARG1; - } - - if (var_info & MAY_BE_REF) { - if (Z_MODE(var_use_addr) != IS_MEM_ZVAL || Z_REG(var_use_addr) != ref_reg || Z_OFFSET(var_use_addr) != 0) { - | LOAD_ZVAL_ADDR Rx(ref_reg), var_use_addr - var_addr = var_use_addr = ZEND_ADDR_MEM_ZVAL(ref_reg, 0); - } - | // if (Z_ISREF_P(variable_ptr)) { - | IF_NOT_Z_TYPE Rx(ref_reg), IS_REFERENCE, >3, TMP1w - | // if (UNEXPECTED(ZEND_REF_HAS_TYPE_SOURCES(Z_REF_P(variable_ptr)))) { - | GET_Z_PTR FCARG1x, Rx(ref_reg) - if (!zend_jit_assign_to_typed_ref(Dst, opline, val_type, val_addr, res_addr, check_exception)) { - return 0; - } - | add Rx(ref_reg), FCARG1x, #offsetof(zend_reference, val) - |3: - } - if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - if (RC_MAY_BE_1(var_info)) { - int in_cold = 0; - - if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | IF_ZVAL_REFCOUNTED var_use_addr, >1, ZREG_TMP1, ZREG_TMP2 - |.cold_code - |1: - in_cold = 1; - } - if (Z_REG(var_use_addr) == ZREG_FCARG1 || Z_REG(var_use_addr) == ZREG_REG0) { - bool keep_gc = 0; - - | GET_ZVAL_PTR Rx(tmp_reg), var_use_addr, TMP1 -#if 0 - // TODO: This optiization doesn't work on ARM - if (tmp_reg == ZREG_FCARG1) { - if (Z_MODE(val_addr) == IS_REG) { - keep_gc = 1; - } else if ((val_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) == 0) { - keep_gc = 1; - } else if (Z_MODE(val_addr) == IS_CONST_ZVAL) { - zval *zv = Z_ZV(val_addr); - if (Z_TYPE_P(zv) == IS_DOUBLE) { - if (Z_DVAL_P(zv) == 0) { - keep_gc = 1; - } - } else if (IS_SIGNED_32BIT(Z_LVAL_P(zv))) { - keep_gc = 1; - } - } else if (Z_MODE(val_addr) == IS_MEM_ZVAL) { - if ((val_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_GUARD)) == MAY_BE_DOUBLE) { - keep_gc = 1; - } - } - } -#endif - if (!keep_gc) { - | str Rx(tmp_reg), T1 // save - } - if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 0, 0)) { - return 0; - } - if (!keep_gc) { - | ldr FCARG1x, T1 // restore - } - } else { - | GET_ZVAL_PTR FCARG1x, var_use_addr, TMP1 - if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, in_cold, 1, 0)) { - return 0; - } - } - | GC_DELREF FCARG1x, TMP1w - if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) { - | bne >4 - } else { - | bne >8 - } - | ZVAL_DTOR_FUNC var_info, opline, TMP1 - if (in_cold || (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0)) { - if (check_exception && !(val_info & MAY_BE_UNDEF)) { - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbz REG0, >8 - | b ->exception_handler - } else { - | b >8 - } - } - if (RC_MAY_BE_N(var_info) && (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) != 0) { - |4: - | IF_GC_MAY_NOT_LEAK FCARG1x, >8, TMP1w, TMP2w - | EXT_CALL gc_possible_root, REG0 - if (in_cold) { - | b >8 - } - } - if (check_exception && (val_info & MAY_BE_UNDEF)) { - |8: - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbz REG0, >8 - | b ->exception_handler - } - if (in_cold) { - |.code - } else { - done = 1; - } - } else /* if (RC_MAY_BE_N(var_info)) */ { - if (var_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | IF_NOT_ZVAL_REFCOUNTED var_use_addr, >5, ZREG_TMP1, ZREG_TMP2 - } - if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT)) { - if (Z_REG(var_use_addr) != ZREG_FP) { - | str Rx(Z_REG(var_use_addr)), T1 // save - } - | GET_ZVAL_PTR FCARG1x, var_use_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - | IF_GC_MAY_NOT_LEAK FCARG1x, >5, TMP1w, TMP2w - | EXT_CALL gc_possible_root, TMP1 - if (Z_REG(var_use_addr) != ZREG_FP) { - | ldr Rx(Z_REG(var_use_addr)), T1 // restore - } - } else { - | GET_ZVAL_PTR Rx(tmp_reg), var_use_addr, TMP1 - | GC_DELREF Rx(tmp_reg), TMP1w - } - |5: - } - } - - if (!done && !zend_jit_simple_assign(Dst, opline, var_addr, var_info, var_def_info, val_type, val_addr, val_info, res_addr, 0, 0, check_exception)) { - return 0; - } - - |8: - - return 1; -} - -static int zend_jit_assign_dim(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t val_info, uint8_t dim_type, int may_throw) -{ - zend_jit_addr op2_addr, op3_addr, res_addr; - - op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0; - op3_addr = OP1_DATA_ADDR(); - if (opline->result_type == IS_UNUSED) { - res_addr = 0; - } else { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - } - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && (val_info & MAY_BE_UNDEF)) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | IF_ZVAL_TYPE op3_addr, IS_UNDEF, &exit_addr, ZREG_TMP1 - - val_info &= ~MAY_BE_UNDEF; - } - - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w - | GET_Z_PTR FCARG2x, FCARG1x - | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))] - | cmp TMP1w, #IS_ARRAY - | bne >2 - | add FCARG1x, FCARG2x, #offsetof(zend_reference, val) - | b >3 - |.cold_code - |2: - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0 - | mov FCARG1x, RETVALx - | cbnz FCARG1x, >1 - | b ->exception_handler_undef - |.code - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & MAY_BE_ARRAY) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - |3: - | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2 - } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) { - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1 - | bgt >7 - } - | // ZVAL_ARR(container, zend_new_array(8)); - if (Z_REG(op1_addr) != ZREG_FP) { - | str Rx(Z_REG(op1_addr)), T1 // save - } - | EXT_CALL _zend_new_array_0, REG0 - | mov REG0, RETVALx - if (Z_REG(op1_addr) != ZREG_FP) { - | ldr Rx(Z_REG(op1_addr)), T1 // restore - } - | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2 - | mov FCARG1x, REG0 - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - |6: - if (opline->op2_type == IS_UNUSED) { - uint32_t var_info = MAY_BE_NULL; - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | EXT_CALL zend_hash_next_index_insert, REG0 - | // if (UNEXPECTED(!var_ptr)) { - | mov REG0, RETVALx - | cbz REG0, >1 - |.cold_code - |1: - | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); - | CANNOT_ADD_ELEMENT opline - | //ZEND_VM_C_GOTO(assign_dim_op_ret_null); - | b >9 - |.code - - if (!zend_jit_simple_assign(Dst, opline, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0, 0, 0)) { - return 0; - } - } else { - uint32_t var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0); - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_W, op1_info, op2_info, dim_type, NULL, NULL, NULL)) { - return 0; - } - - if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) { - var_info |= MAY_BE_REF; - } - if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - var_info |= MAY_BE_RC1; - } - - |8: - | // value = zend_assign_to_variable(variable_ptr, value, OP_DATA_TYPE); - if (opline->op1_type == IS_VAR) { - ZEND_ASSERT(opline->result_type == IS_UNUSED); - if (!zend_jit_assign_to_variable_call(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) { - return 0; - } - } else { - if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, var_info, -1, (opline+1)->op1_type, op3_addr, val_info, res_addr, 0)) { - return 0; - } - } - } - } - - if (((op1_info & MAY_BE_ARRAY) && - (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) || - (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY)))) { - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - |.cold_code - |7: - } - - if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) && - (op1_info & MAY_BE_ARRAY)) { - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1 - | bgt >2 - } - | // ZVAL_ARR(container, zend_new_array(8)); - if (Z_REG(op1_addr) != ZREG_FP) { - | str Rx(Z_REG(op1_addr)), T1 // save - } - | EXT_CALL _zend_new_array_0, REG0 - | mov REG0, RETVALx - if (Z_REG(op1_addr) != ZREG_FP) { - | ldr Rx(Z_REG(op1_addr)), T1 // restore - } - | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2 - | mov FCARG1x, REG0 - | // ZEND_VM_C_GOTO(assign_dim_op_new_array); - | b <6 - |2: - } - - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_UNUSED) { - | mov FCARG2x, xzr - } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL); - | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1) - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - if (opline->result_type == IS_UNUSED) { - | mov CARG4, xzr - } else { - | LOAD_ZVAL_ADDR CARG4, res_addr - } - | LOAD_ZVAL_ADDR CARG3, op3_addr - | EXT_CALL zend_jit_assign_dim_helper, REG0 - -#ifdef ZEND_JIT_USE_RC_INFERENCE - if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) && (val_info & MAY_BE_RC1)) { - /* ASSIGN_DIM may increase refcount of the value */ - val_info |= MAY_BE_RCN; - } -#endif - - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | b >9 // END - } - |.code - } - } - -#ifdef ZEND_JIT_USE_RC_INFERENCE - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) { - /* ASSIGN_DIM may increase refcount of the key */ - op2_info |= MAY_BE_RCN; - } -#endif - - |9: - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - - if (may_throw) { - zend_jit_check_exception(Dst); - } - - return 1; -} - -static int zend_jit_assign_dim_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, uint32_t op1_data_info, zend_ssa_range *op1_data_range, uint8_t dim_type, int may_throw) -{ - zend_jit_addr op2_addr, op3_addr, var_addr; - const void *not_found_exit_addr = NULL; - uint32_t var_info = MAY_BE_NULL; - - ZEND_ASSERT(opline->result_type == IS_UNUSED); - - op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0; - op3_addr = OP1_DATA_ADDR(); - - | SET_EX_OPLINE opline, REG0 - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w - | GET_Z_PTR FCARG2x, FCARG1x - | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))] - | cmp TMP1w, #IS_ARRAY - | bne >2 - | add FCARG1x, FCARG2x, #offsetof(zend_reference, val) - | b >3 - |.cold_code - |2: - | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0 - | mov FCARG1x, RETVALx - | cbnz RETVALx, >1 - | b ->exception_handler_undef - |.code - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & MAY_BE_ARRAY) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - |3: - | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2 - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) { - if (op1_info & MAY_BE_ARRAY) { - |.cold_code - |7: - } - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1 - | bgt >7 - } - if (Z_REG(op1_addr) != ZREG_FP) { - | str Rx(Z_REG(op1_addr)), T1 // save - } - if (op1_info & MAY_BE_UNDEF) { - if (op1_info & MAY_BE_NULL) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - } - | LOAD_32BIT_VAL FCARG1x, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - } - | // ZVAL_ARR(container, zend_new_array(8)); - | EXT_CALL _zend_new_array_0, REG0 - | mov REG0, RETVALx - if (Z_REG(op1_addr) != ZREG_FP) { - | ldr Rx(Z_REG(op1_addr)), T1 // restore - } - | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2 - | mov FCARG1x, REG0 - if (op1_info & MAY_BE_ARRAY) { - | b >1 - |.code - |1: - } - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - uint32_t var_def_info = zend_array_element_type(op1_def_info, opline->op1_type, 1, 0); - - |6: - if (opline->op2_type == IS_UNUSED) { - var_info = MAY_BE_NULL; - - | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | EXT_CALL zend_hash_next_index_insert, REG0 - | mov REG0, RETVALx - | // if (UNEXPECTED(!var_ptr)) { - | cbz REG0, >1 - |.cold_code - |1: - | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); - | CANNOT_ADD_ELEMENT opline - | //ZEND_VM_C_GOTO(assign_dim_op_ret_null); - | b >9 - |.code - } else { - var_info = zend_array_element_type(op1_info, opline->op1_type, 0, 0); - if (op1_info & (MAY_BE_ARRAY_OF_REF|MAY_BE_OBJECT)) { - var_info |= MAY_BE_REF; - } - if (var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - var_info |= MAY_BE_RC1; - } - - if (dim_type != IS_UNKNOWN - && dim_type != IS_UNDEF - && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY - && (op2_info & (MAY_BE_LONG|MAY_BE_STRING)) - && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!not_found_exit_addr) { - return 0; - } - } - - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_VAR_RW, op1_info, op2_info, dim_type, NULL, not_found_exit_addr, NULL)) { - return 0; - } - - |8: - if (not_found_exit_addr && dim_type != IS_REFERENCE) { - | IF_NOT_Z_TYPE, REG0, dim_type, ¬_found_exit_addr, TMP1w - var_info = (1 << dim_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)); - } - if (var_info & MAY_BE_REF) { - binary_op_type binary_op = get_binary_op(opline->extended_value); - | IF_NOT_Z_TYPE, REG0, IS_REFERENCE, >1, TMP1w - | GET_Z_PTR FCARG1x, REG0 - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbnz TMP1, >2 - | add REG0, FCARG1x, #offsetof(zend_reference, val) - |.cold_code - |2: - | LOAD_ZVAL_ADDR FCARG2x, op3_addr - | LOAD_ADDR CARG3, binary_op - if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) - && (op1_data_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0 - } else { - | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0 - } - | b >9 - |.code - |1: - } - } - - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - switch (opline->extended_value) { - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - case ZEND_DIV: - if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, 0, var_addr, var_def_info, var_info, - 1 /* may overflow */, may_throw)) { - return 0; - } - break; - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - case ZEND_SL: - case ZEND_SR: - case ZEND_MOD: - if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value, - IS_CV, opline->op1, var_addr, var_info, NULL, - (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, - op1_data_range, - 0, var_addr, var_def_info, var_info, may_throw)) { - return 0; - } - break; - case ZEND_CONCAT: - if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, op3_addr, op1_data_info, var_addr, - may_throw)) { - return 0; - } - break; - default: - ZEND_UNREACHABLE(); - } - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - binary_op_type binary_op; - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - |.cold_code - |7: - } - - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_UNUSED) { - | mov FCARG2x, xzr - } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL); - | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1) - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - binary_op = get_binary_op(opline->extended_value); - | LOAD_ZVAL_ADDR CARG3, op3_addr - | LOAD_ADDR CARG4, binary_op - | EXT_CALL zend_jit_assign_dim_op_helper, REG0 - - |9: - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, op1_data_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception(Dst); - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - | b >9 // END - |.code - |9: - } - } else if ((op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) - && (!not_found_exit_addr || (var_info & MAY_BE_REF))) { - |.cold_code - |9: - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, op1_data_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception(Dst); - } - | b >9 - |.code - |9: - } - - return 1; -} - -static int zend_jit_assign_op(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op1_def_info, zend_ssa_range *op1_range, uint32_t op2_info, zend_ssa_range *op2_range, int may_overflow, int may_throw) -{ - zend_jit_addr op1_addr, op2_addr; - - ZEND_ASSERT(opline->op1_type == IS_CV && opline->result_type == IS_UNUSED); - ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF) && !(op2_info & MAY_BE_UNDEF)); - - op1_addr = OP1_ADDR(); - op2_addr = OP2_ADDR(); - - if (op1_info & MAY_BE_REF) { - binary_op_type binary_op = get_binary_op(opline->extended_value); - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE, FCARG1x, IS_REFERENCE, >1, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbnz TMP1, >2 - | add FCARG1x, FCARG1x, #offsetof(zend_reference, val) - |.cold_code - |2: - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | LOAD_ADDR CARG3, binary_op - | SET_EX_OPLINE opline, REG0 - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) - && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0 - } else { - | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0 - } - zend_jit_check_exception(Dst); - | b >9 - |.code - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - int result; - switch (opline->extended_value) { - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - case ZEND_DIV: - result = zend_jit_math_helper(Dst, opline, opline->extended_value, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, opline->op1.var, op1_addr, op1_def_info, op1_info, may_overflow, may_throw); - break; - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - case ZEND_SL: - case ZEND_SR: - case ZEND_MOD: - result = zend_jit_long_math_helper(Dst, opline, opline->extended_value, - opline->op1_type, opline->op1, op1_addr, op1_info, op1_range, - opline->op2_type, opline->op2, op2_addr, op2_info, op2_range, - opline->op1.var, op1_addr, op1_def_info, op1_info, may_throw); - break; - case ZEND_CONCAT: - result = zend_jit_concat_helper(Dst, opline, opline->op1_type, opline->op1, op1_addr, op1_info, opline->op2_type, opline->op2, op2_addr, op2_info, op1_addr, may_throw); - break; - default: - ZEND_UNREACHABLE(); - } - |9: - return result; -} - -static int zend_jit_cmp_long_long(dasm_State **Dst, - const zend_op *opline, - zend_ssa_range *op1_range, - zend_jit_addr op1_addr, - zend_ssa_range *op2_range, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - uint8_t smart_branch_opcode, - uint32_t target_label, - uint32_t target_label2, - const void *exit_addr, - bool skip_comparison) -{ - bool swap = 0; - bool result; - - if (zend_jit_is_constant_cmp_long_long(opline, op1_range, op1_addr, op2_range, op2_addr, &result)) { - if (!smart_branch_opcode || - smart_branch_opcode == ZEND_JMPZ_EX || - smart_branch_opcode == ZEND_JMPNZ_EX) { - | SET_ZVAL_TYPE_INFO res_addr, (result ? IS_TRUE : IS_FALSE), TMP1w, TMP2 - } - if (smart_branch_opcode && !exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ || - smart_branch_opcode == ZEND_JMPZ_EX) { - if (!result) { - | b => target_label - } - } else if (smart_branch_opcode == ZEND_JMPNZ || - smart_branch_opcode == ZEND_JMPNZ_EX) { - if (result) { - | b => target_label - } - } else { - ZEND_UNREACHABLE(); - } - } - return 1; - } - - if (skip_comparison) { - if (Z_MODE(op1_addr) != IS_REG && - (Z_MODE(op2_addr) == IS_REG || - (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL))) { - swap = 1; - } - } else if (Z_MODE(op1_addr) == IS_REG) { - if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { - | cmp Rx(Z_REG(op1_addr)), xzr - } else { - | LONG_CMP Z_REG(op1_addr), op2_addr, TMP1 - } - } else if (Z_MODE(op2_addr) == IS_REG) { - if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op1_addr)) == 0) { - | cmp Rx(Z_REG(op2_addr)), xzr - } else { - | LONG_CMP Z_REG(op2_addr), op1_addr, TMP1 - } - swap = 1; - } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) != IS_CONST_ZVAL) { - | LONG_CMP_WITH_CONST op2_addr, Z_LVAL_P(Z_ZV(op1_addr)), TMP1, TMP2 - swap = 1; - } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_MODE(op1_addr) != IS_CONST_ZVAL) { - | LONG_CMP_WITH_CONST op1_addr, Z_LVAL_P(Z_ZV(op2_addr)), TMP1, TMP2 - } else { - | GET_ZVAL_LVAL ZREG_REG0, op1_addr, TMP1 - if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_LVAL_P(Z_ZV(op2_addr)) == 0) { - | cmp Rx(ZREG_REG0), xzr - } else { - | LONG_CMP ZREG_REG0, op2_addr, TMP1 - } - } - - if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ_EX || - smart_branch_opcode == ZEND_JMPNZ_EX) { - - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | cset REG0w, eq - break; - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_NOT_IDENTICAL: - | cset REG0w, ne - break; - case ZEND_IS_SMALLER: - if (swap) { - | cset REG0w, gt - } else { - | cset REG0w, lt - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - | cset REG0w, ge - } else { - | cset REG0w, le - } - break; - default: - ZEND_UNREACHABLE(); - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if (smart_branch_opcode == ZEND_JMPZ || - smart_branch_opcode == ZEND_JMPZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_NOT_EQUAL: - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - break; - case ZEND_IS_NOT_IDENTICAL: - if (exit_addr) { - | bne &exit_addr - } else { - | beq => target_label - } - break; - case ZEND_IS_SMALLER: - if (swap) { - if (exit_addr) { - | ble &exit_addr - } else { - | ble => target_label - } - } else { - if (exit_addr) { - | bge &exit_addr - } else { - | bge => target_label - } - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - if (exit_addr) { - | blt &exit_addr - } else { - | blt => target_label - } - } else { - if (exit_addr) { - | bgt &exit_addr - } else { - | bgt => target_label - } - } - break; - default: - ZEND_UNREACHABLE(); - } - } else if (smart_branch_opcode == ZEND_JMPNZ || - smart_branch_opcode == ZEND_JMPNZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - break; - case ZEND_IS_NOT_EQUAL: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_NOT_IDENTICAL: - if (exit_addr) { - | beq &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_SMALLER: - if (swap) { - if (exit_addr) { - | bgt &exit_addr - } else { - | bgt => target_label - } - } else { - if (exit_addr) { - | blt &exit_addr - } else { - | blt => target_label - } - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - if (exit_addr) { - | bge &exit_addr - } else { - | bge => target_label - } - } else { - if (exit_addr) { - | ble &exit_addr - } else { - | ble => target_label - } - } - break; - default: - ZEND_UNREACHABLE(); - } - } else { - ZEND_UNREACHABLE(); - } - } else { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | cset REG0w, eq - break; - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_NOT_IDENTICAL: - | cset REG0w, ne - break; - case ZEND_IS_SMALLER: - if (swap) { - | cset REG0w, gt - } else { - | cset REG0w, lt - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - | cset REG0w, ge - } else { - | cset REG0w, le - } - break; - default: - ZEND_UNREACHABLE(); - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - - return 1; -} - -static int zend_jit_cmp_double_common(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, bool swap, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_NOT_EQUAL: - | bvs >1 - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - |1: - break; - case ZEND_IS_NOT_IDENTICAL: - if (exit_addr) { - | bvs &exit_addr - | bne &exit_addr - } else { - | bvs >1 - | beq => target_label - |1: - } - break; - case ZEND_IS_SMALLER: - if (swap) { - if (exit_addr) { - | bvs &exit_addr - | bls &exit_addr - } else { - | bvs => target_label - | bls => target_label - } - } else { - if (exit_addr) { - | bhs &exit_addr - } else { - | bhs => target_label - } - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - if (exit_addr) { - | bvs &exit_addr - | blo &exit_addr - } else { - | bvs => target_label - | blo => target_label - } - } else { - if (exit_addr) { - | bhi &exit_addr - } else { - | bhi => target_label - } - } - break; - default: - ZEND_UNREACHABLE(); - } - } else if (smart_branch_opcode == ZEND_JMPNZ) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | bvs >1 - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - |1: - break; - case ZEND_IS_NOT_EQUAL: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_NOT_IDENTICAL: - if (exit_addr) { - | bvs >1 - | beq &exit_addr - |1: - } else { - | bne => target_label - } - break; - case ZEND_IS_SMALLER: - if (swap) { - | bvs >1 // Always False if involving NaN - if (exit_addr) { - | bhi &exit_addr - } else { - | bhi => target_label - } - |1: - } else { - | bvs >1 - if (exit_addr) { - | blo &exit_addr - } else { - | blo => target_label - } - |1: - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - | bvs >1 // Always False if involving NaN - if (exit_addr) { - | bhs &exit_addr - } else { - | bhs => target_label - } - |1: - } else { - | bvs >1 - if (exit_addr) { - | bls &exit_addr - } else { - | bls => target_label - } - |1: - } - break; - default: - ZEND_UNREACHABLE(); - } - } else if (smart_branch_opcode == ZEND_JMPZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | bne => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - break; - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_NOT_IDENTICAL: - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | beq => target_label - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - break; - case ZEND_IS_SMALLER: - if (swap) { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | bvs => target_label - | bls => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | bhs => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | bvs => target_label - | blo => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | bhi => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - break; - default: - ZEND_UNREACHABLE(); - } - } else if (smart_branch_opcode == ZEND_JMPNZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | beq => target_label - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - break; - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_NOT_IDENTICAL: - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | bvs => target_label - | bne => target_label - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - break; - case ZEND_IS_SMALLER: - if (swap) { - | cset REG0w, hi - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - | bvs >1 // Always False if involving NaN - | bhi => target_label - |1: - } else { - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | blo => target_label - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (swap) { - | cset REG0w, hs - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - | bvs >1 // Always False if involving NaN - | bhs => target_label - |1: - } else { - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | bls => target_label - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - break; - default: - ZEND_UNREACHABLE(); - } - } else { - ZEND_UNREACHABLE(); - } - } else { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_CASE: - case ZEND_CASE_STRICT: - | bvs >1 - | mov REG0, #IS_TRUE - | beq >2 - |1: - | mov REG0, #IS_FALSE - |2: - break; - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_NOT_IDENTICAL: - | bvs >1 - | mov REG0, #IS_FALSE - | beq >2 - |1: - | mov REG0, #IS_TRUE - |2: - break; - case ZEND_IS_SMALLER: - | bvs >1 - | mov REG0, #IS_TRUE - || if (swap) { - | bhi >2 - || } else { - | blo >2 - || } - |1: - | mov REG0, #IS_FALSE - |2: - break; - case ZEND_IS_SMALLER_OR_EQUAL: - | bvs >1 - | mov REG0, #IS_TRUE - || if (swap) { - | bhs >2 - || } else { - | bls >2 - || } - |1: - | mov REG0, #IS_FALSE - |2: - break; - default: - ZEND_UNREACHABLE(); - } - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - - return 1; -} - -static int zend_jit_cmp_long_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - zend_reg tmp_reg = ZREG_FPR0; - - | DOUBLE_GET_ZVAL_LVAL tmp_reg, op1_addr, ZREG_REG0, ZREG_TMP1 - | DOUBLE_CMP tmp_reg, op2_addr, ZREG_TMP1, ZREG_FPTMP - - return zend_jit_cmp_double_common(Dst, opline, res_addr, 0, smart_branch_opcode, target_label, target_label2, exit_addr); -} - -static int zend_jit_cmp_double_long(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - zend_reg tmp_reg = ZREG_FPR0; - - | DOUBLE_GET_ZVAL_LVAL tmp_reg, op2_addr, ZREG_REG0, ZREG_TMP1 - | DOUBLE_CMP tmp_reg, op1_addr, ZREG_TMP1, ZREG_FPTMP - - return zend_jit_cmp_double_common(Dst, opline, res_addr, /* swap */ 1, smart_branch_opcode, target_label, target_label2, exit_addr); -} - -static int zend_jit_cmp_double_double(dasm_State **Dst, const zend_op *opline, zend_jit_addr op1_addr, zend_jit_addr op2_addr, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - bool swap = 0; - - if (Z_MODE(op1_addr) == IS_REG) { - | DOUBLE_CMP Z_REG(op1_addr), op2_addr, ZREG_TMP1, ZREG_FPTMP - } else if (Z_MODE(op2_addr) == IS_REG) { - | DOUBLE_CMP Z_REG(op2_addr), op1_addr, ZREG_TMP1, ZREG_FPTMP - swap = 1; - } else { - zend_reg tmp_reg = ZREG_FPR0; - - | GET_ZVAL_DVAL tmp_reg, op1_addr, ZREG_TMP1 - | DOUBLE_CMP tmp_reg, op2_addr, ZREG_TMP1, ZREG_FPTMP - } - - return zend_jit_cmp_double_common(Dst, opline, res_addr, swap, smart_branch_opcode, target_label, target_label2, exit_addr); -} - -static int zend_jit_cmp_slow(dasm_State **Dst, const zend_op *opline, zend_jit_addr res_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - | tst RETVALw, RETVALw - if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ_EX || - smart_branch_opcode == ZEND_JMPNZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_CASE: - | cset REG0w, eq - break; - case ZEND_IS_NOT_EQUAL: - | cset REG0w, ne - break; - case ZEND_IS_SMALLER: - | cset REG0w, lt - break; - case ZEND_IS_SMALLER_OR_EQUAL: - | cset REG0w, le - break; - default: - ZEND_UNREACHABLE(); - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if (smart_branch_opcode == ZEND_JMPZ || - smart_branch_opcode == ZEND_JMPZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_CASE: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_NOT_EQUAL: - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - break; - case ZEND_IS_SMALLER: - if (exit_addr) { - | bge &exit_addr - } else { - | bge => target_label - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (exit_addr) { - | bgt &exit_addr - } else { - | bgt => target_label - } - break; - default: - ZEND_UNREACHABLE(); - } - } else if (smart_branch_opcode == ZEND_JMPNZ || - smart_branch_opcode == ZEND_JMPNZ_EX) { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_CASE: - if (exit_addr) { - | beq &exit_addr - } else { - | beq => target_label - } - break; - case ZEND_IS_NOT_EQUAL: - if (exit_addr) { - | bne &exit_addr - } else { - | bne => target_label - } - break; - case ZEND_IS_SMALLER: - if (exit_addr) { - | blt &exit_addr - } else { - | blt => target_label - } - break; - case ZEND_IS_SMALLER_OR_EQUAL: - if (exit_addr) { - | ble &exit_addr - } else { - | ble => target_label - } - break; - default: - ZEND_UNREACHABLE(); - } - } else { - ZEND_UNREACHABLE(); - } - } else { - switch (opline->opcode) { - case ZEND_IS_EQUAL: - case ZEND_CASE: - | cset REG0w, eq - break; - case ZEND_IS_NOT_EQUAL: - | cset REG0w, ne - break; - case ZEND_IS_SMALLER: - | cset REG0w, lt - break; - case ZEND_IS_SMALLER_OR_EQUAL: - | cset REG0w, le - break; - default: - ZEND_UNREACHABLE(); - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - - return 1; -} - -static int zend_jit_cmp(dasm_State **Dst, - const zend_op *opline, - uint32_t op1_info, - zend_ssa_range *op1_range, - zend_jit_addr op1_addr, - uint32_t op2_info, - zend_ssa_range *op2_range, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - int may_throw, - uint8_t smart_branch_opcode, - uint32_t target_label, - uint32_t target_label2, - const void *exit_addr, - bool skip_comparison) -{ - bool same_ops = (opline->op1_type == opline->op2_type) && (opline->op1.var == opline->op2.var); - bool has_slow; - - has_slow = - (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE)) && - ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) || - (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))); - - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { - if (op1_info & MAY_BE_DOUBLE) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >4, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9, ZREG_TMP1 - } - } - if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG))) { - if (op2_info & MAY_BE_DOUBLE) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >3, ZREG_TMP1 - |.cold_code - |3: - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - | b >6 - |.code - } else { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1 - } - } - if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) { - return 0; - } - if (op1_info & MAY_BE_DOUBLE) { - |.cold_code - |4: - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - if (op2_info & MAY_BE_DOUBLE) { - if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) { - if (!same_ops) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >5, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - } - if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - | b >6 - } - if (!same_ops) { - |5: - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1 - } - if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - | b >6 - } - |.code - } - } else if ((op1_info & MAY_BE_DOUBLE) && - !(op1_info & MAY_BE_LONG) && - (op2_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - if (op2_info & MAY_BE_DOUBLE) { - if (!same_ops && (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) { - if (!same_ops && (op2_info & MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - } - if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - } - if (!same_ops && (op2_info & MAY_BE_LONG)) { - if (op2_info & MAY_BE_DOUBLE) { - |.cold_code - } - |3: - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_LONG, >9, ZREG_TMP1 - } - if (!zend_jit_cmp_double_long(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - if (op2_info & MAY_BE_DOUBLE) { - | b >6 - |.code - } - } - } else if ((op2_info & MAY_BE_DOUBLE) && - !(op2_info & MAY_BE_LONG) && - (op1_info & (MAY_BE_LONG|MAY_BE_DOUBLE))) { - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - if (op1_info & MAY_BE_DOUBLE) { - if (!same_ops && (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_DOUBLE))) { - if (!same_ops && (op1_info & MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_DOUBLE, >9, ZREG_TMP1 - } - } - if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - } - if (!same_ops && (op1_info & MAY_BE_LONG)) { - if (op1_info & MAY_BE_DOUBLE) { - |.cold_code - } - |3: - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_DOUBLE|MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >9, ZREG_TMP1 - } - if (!zend_jit_cmp_long_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - if (op1_info & MAY_BE_DOUBLE) { - | b >6 - |.code - } - } - } - - if (has_slow || - (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) || - (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) { - if (has_slow) { - |.cold_code - |9: - } - | SET_EX_OPLINE opline, REG0 - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - if (Z_MODE(op2_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); - if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) { - return 0; - } - op2_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - if (opline->op1_type == IS_CV && (op1_info & MAY_BE_UNDEF)) { - | IF_NOT_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w - | LOAD_32BIT_VAL FCARG1x, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval - |1: - } - if (opline->op2_type == IS_CV && (op2_info & MAY_BE_UNDEF)) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1 - | str FCARG1x, T1 // save - | LOAD_32BIT_VAL FCARG1x, opline->op2.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - | ldr FCARG1x, T1 // restore - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | b >2 - |1: - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - |2: - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - | EXT_CALL zend_compare, REG0 - if ((opline->opcode != ZEND_CASE && - (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) || - ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && - (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { - | str RETVALw, T1 // save - if (opline->opcode != ZEND_CASE) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - } - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - | ldr RETVALw, T1 // restore - } - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - if (!zend_jit_cmp_slow(Dst, opline, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - if (has_slow) { - | b >6 - |.code - } - } - - |6: - - return 1; -} - -static int zend_jit_identical(dasm_State **Dst, - const zend_op *opline, - uint32_t op1_info, - zend_ssa_range *op1_range, - zend_jit_addr op1_addr, - uint32_t op2_info, - zend_ssa_range *op2_range, - zend_jit_addr op2_addr, - zend_jit_addr res_addr, - int may_throw, - uint8_t smart_branch_opcode, - uint32_t target_label, - uint32_t target_label2, - const void *exit_addr, - bool skip_comparison) -{ - uint32_t identical_label = (uint32_t)-1; - uint32_t not_identical_label = (uint32_t)-1; - - if (smart_branch_opcode && !exit_addr) { - if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { - if (smart_branch_opcode == ZEND_JMPZ) { - not_identical_label = target_label; - } else if (smart_branch_opcode == ZEND_JMPNZ) { - identical_label = target_label; - } else { - ZEND_UNREACHABLE(); - } - } else { - if (smart_branch_opcode == ZEND_JMPZ) { - identical_label = target_label; - } else if (smart_branch_opcode == ZEND_JMPNZ) { - not_identical_label = target_label; - } else { - ZEND_UNREACHABLE(); - } - } - } - - if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG && - (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) { - if (!zend_jit_cmp_long_long(Dst, opline, op1_range, op1_addr, op2_range, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr, skip_comparison)) { - return 0; - } - return 1; - } else if ((op1_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE && - (op2_info & (MAY_BE_REF|MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_DOUBLE) { - if (!zend_jit_cmp_double_double(Dst, opline, op1_addr, op2_addr, res_addr, smart_branch_opcode, target_label, target_label2, exit_addr)) { - return 0; - } - return 1; - } - - if ((op1_info & MAY_BE_UNDEF) && (op2_info & MAY_BE_UNDEF)) { - op1_info |= MAY_BE_NULL; - op2_info |= MAY_BE_NULL; - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w - |.cold_code - |1: - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval - | b >1 - |.code - |1: - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | IF_Z_TYPE FCARG2x, IS_UNDEF, >1, TMP1w - |.cold_code - |1: - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | SET_EX_OPLINE opline, REG0 - | str FCARG1x, T1 // save - | LOAD_32BIT_VAL FCARG1w, opline->op2.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - | ldr FCARG1x, T1 // restore - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | b >1 - |.code - |1: - } else if (op1_info & MAY_BE_UNDEF) { - op1_info |= MAY_BE_NULL; - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_Z_TYPE FCARG1x, IS_UNDEF, >1, TMP1w - |.cold_code - |1: - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval - | b >1 - |.code - |1: - if (opline->op2_type != IS_CONST) { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - } else if (op2_info & MAY_BE_UNDEF) { - op2_info |= MAY_BE_NULL; - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | IF_Z_TYPE FCARG2x, IS_UNDEF, >1, TMP1w - |.cold_code - |1: - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op2.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | b >1 - |.code - |1: - if (opline->op1_type != IS_CONST) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - } else if ((op1_info & op2_info & MAY_BE_ANY) != 0) { - if (opline->op1_type != IS_CONST) { - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - if (!zend_jit_spill_store(Dst, op1_addr, real_addr, op1_info, 1)) { - return 0; - } - op1_addr = real_addr; - } - } - if (opline->op2_type != IS_CONST) { - if (Z_MODE(op2_addr) == IS_REG) { - zend_jit_addr real_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); - if (!zend_jit_spill_store(Dst, op2_addr, real_addr, op2_info, 1)) { - return 0; - } - op2_addr = real_addr; - } - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - if (opline->op1_type != IS_CONST) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - } - - if ((op1_info & op2_info & MAY_BE_ANY) == 0) { - if ((opline->opcode != ZEND_CASE_STRICT && - (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) || - ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && - (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { - if (opline->opcode != ZEND_CASE_STRICT) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - if (smart_branch_opcode) { - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (not_identical_label != (uint32_t)-1) { - | b =>not_identical_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE), TMP1w, TMP2 - if (may_throw) { - zend_jit_check_exception(Dst); - } - } - return 1; - } - - if (opline->op1_type & (IS_CV|IS_VAR)) { - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - } - if (opline->op2_type & (IS_CV|IS_VAR)) { - | ZVAL_DEREF FCARG2x, op2_info, TMP1w - } - - if (has_concrete_type(op1_info) - && has_concrete_type(op2_info) - && concrete_type(op1_info) == concrete_type(op2_info) - && concrete_type(op1_info) <= IS_TRUE) { - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } - } else if (identical_label != (uint32_t)-1) { - | b =>identical_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE), TMP1w, TMP2 - } - } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_MODE(op2_addr) == IS_CONST_ZVAL) { - if (zend_is_identical(Z_ZV(op1_addr), Z_ZV(op2_addr))) { - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } - } else if (identical_label != (uint32_t)-1) { - | b =>identical_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_TRUE : IS_FALSE), TMP1w, TMP2 - } - } else { - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (not_identical_label != (uint32_t)-1) { - | b =>not_identical_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, (opline->opcode != ZEND_IS_NOT_IDENTICAL ? IS_FALSE : IS_TRUE), TMP1w, TMP2 - } - } - } else if (Z_MODE(op1_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op1_addr)) <= IS_TRUE) { - zval *val = Z_ZV(op1_addr); - - | ldrb TMP1w, [FCARG2x, #offsetof(zval, u1.v.type)] - | cmp TMP1w, #Z_TYPE_P(val) - if (smart_branch_opcode) { - if (opline->op2_type == IS_VAR && (op2_info & MAY_BE_REF)) { - | bne >8 - | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } else if (identical_label != (uint32_t)-1) { - | b =>identical_label - } else { - | b >9 - } - |8: - } else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) { - | beq &exit_addr - } else if (identical_label != (uint32_t)-1) { - | beq =>identical_label - } else { - | beq >9 - } - } else { - if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { - | cset REG0w, eq - } else { - | cset REG0w, ne - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && - (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { - | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - } - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (smart_branch_opcode && not_identical_label != (uint32_t)-1) { - | b =>not_identical_label - } - } else if (Z_MODE(op2_addr) == IS_CONST_ZVAL && Z_TYPE_P(Z_ZV(op2_addr)) <= IS_TRUE) { - zval *val = Z_ZV(op2_addr); - - | ldrb TMP1w, [FCARG1x, #offsetof(zval, u1.v.type)] - | cmp TMP1w, #Z_TYPE_P(val) - if (smart_branch_opcode) { - if (opline->opcode != ZEND_CASE_STRICT - && opline->op1_type == IS_VAR && (op1_info & MAY_BE_REF)) { - | bne >8 - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } else if (identical_label != (uint32_t)-1) { - | b =>identical_label - } else { - | b >9 - } - |8: - } else if (exit_addr && smart_branch_opcode == ZEND_JMPNZ) { - | beq &exit_addr - } else if (identical_label != (uint32_t)-1) { - | beq =>identical_label - } else { - | beq >9 - } - } else { - if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { - | cset REG0w, eq - } else { - | cset REG0w, ne - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if (opline->opcode != ZEND_CASE_STRICT - && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - } - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (not_identical_label != (uint32_t)-1) { - | b =>not_identical_label - } - } - } else { - if (opline->op1_type == IS_CONST) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_CONST) { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - | EXT_CALL zend_is_identical, REG0 - if ((opline->opcode != ZEND_CASE_STRICT && - (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) || - ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) && - (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)))) { - | str RETVALw, T1 // save - if (opline->opcode != ZEND_CASE_STRICT) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - | FREE_OP opline->op2_type, opline->op2, op2_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - zend_jit_check_exception_undef_result(Dst, opline); - } - | ldr RETVALw, T1 // restore - } - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | cbnz RETVALw, &exit_addr - } else { - | cbz RETVALw, &exit_addr - } - } else if (not_identical_label != (uint32_t)-1) { - | cbz RETVALw, =>not_identical_label - if (identical_label != (uint32_t)-1) { - | b =>identical_label - } - } else if (identical_label != (uint32_t)-1) { - | cbnz RETVALw, =>identical_label - } - } else { - if (opline->opcode != ZEND_IS_NOT_IDENTICAL) { - | add RETVALw, RETVALw, #2 - } else { - | neg RETVALw, RETVALw - | add RETVALw, RETVALw, #3 - } - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, RETVALw, TMP1 - } - } - - |9: - if (may_throw) { - zend_jit_check_exception(Dst); - } - return 1; -} - -static int zend_jit_bool_jmpznz(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, uint32_t target_label, uint32_t target_label2, int may_throw, uint8_t branch_opcode, const void *exit_addr) -{ - uint32_t true_label = -1; - uint32_t false_label = -1; - bool set_bool = 0; - bool set_bool_not = 0; - bool set_delayed = 0; - bool jmp_done = 0; - - if (branch_opcode == ZEND_BOOL) { - set_bool = 1; - } else if (branch_opcode == ZEND_BOOL_NOT) { - set_bool = 1; - set_bool_not = 1; - } else if (branch_opcode == ZEND_JMPZ) { - false_label = target_label; - } else if (branch_opcode == ZEND_JMPNZ) { - true_label = target_label; - } else if (branch_opcode == ZEND_JMPZ_EX) { - set_bool = 1; - false_label = target_label; - } else if (branch_opcode == ZEND_JMPNZ_EX) { - set_bool = 1; - true_label = target_label; - } else { - ZEND_UNREACHABLE(); - } - - if (Z_MODE(op1_addr) == IS_CONST_ZVAL) { - if (zend_is_true(Z_ZV(op1_addr))) { - /* Always TRUE */ - if (set_bool) { - if (set_bool_not) { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - } - if (true_label != (uint32_t)-1) { - | b =>true_label - } - } else { - /* Always FALSE */ - if (set_bool) { - if (set_bool_not) { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - } - if (false_label != (uint32_t)-1) { - | b =>false_label - } - } - return 1; - } - - if (opline->op1_type == IS_CV && (op1_info & MAY_BE_REF)) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE)) { - if (!(op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)-MAY_BE_TRUE))) { - /* Always TRUE */ - if (set_bool) { - if (set_bool_not) { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - } - if (true_label != (uint32_t)-1) { - | b =>true_label - } - } else { - if (!(op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE)))) { - /* Always FALSE */ - if (set_bool) { - if (set_bool_not) { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - } - } else { - | CMP_ZVAL_TYPE op1_addr, IS_TRUE, ZREG_TMP1 - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE))) { - if ((op1_info & MAY_BE_LONG) && - !(op1_info & MAY_BE_UNDEF) && - !set_bool) { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ) { - | blt >9 - } else { - | blt &exit_addr - } - } else if (false_label != (uint32_t)-1) { - | blt =>false_label - } else { - | blt >9 - } - jmp_done = 1; - } else { - | bgt >2 - } - } - if (!(op1_info & MAY_BE_TRUE)) { - /* It's FALSE */ - if (set_bool) { - if (set_bool_not) { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - } - } else { - if (exit_addr) { - if (set_bool) { - | bne >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | b &exit_addr - } else { - | b >9 - } - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) { - if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) { - | bne &exit_addr - } - } - } else { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | beq &exit_addr - } else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) { - | bne &exit_addr - } else { - | beq >9 - } - } - } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) { - if (set_bool) { - | bne >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - if (true_label != (uint32_t)-1) { - | b =>true_label - } else { - | b >9 - } - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } else { - if (true_label != (uint32_t)-1) { - | beq =>true_label - } else if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_LONG))) { - | bne =>false_label - jmp_done = 1; - } else { - | beq >9 - } - } - } else if (set_bool) { - | cset REG0w, eq - if (set_bool_not) { - | neg REG0w, REG0w - | add REG0w, REG0w, #3 - } else { - | add REG0w, REG0w, #2 - } - if ((op1_info & MAY_BE_UNDEF) && (op1_info & MAY_BE_ANY)) { - set_delayed = 1; - } else { - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - } - } - } - - /* It's FALSE, but may be UNDEF */ - if (op1_info & MAY_BE_UNDEF) { - if (op1_info & MAY_BE_ANY) { - if (set_delayed) { - | CMP_ZVAL_TYPE op1_addr, IS_UNDEF, ZREG_TMP1 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - | beq >1 - } else { - | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - } - |.cold_code - |1: - } - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_undefined_op_helper, REG0 - - if (may_throw) { - if (!zend_jit_check_exception_undef_result(Dst, opline)) { - return 0; - } - } - - if (exit_addr) { - if (branch_opcode == ZEND_JMPZ || branch_opcode == ZEND_JMPZ_EX) { - | b &exit_addr - } - } else if (false_label != (uint32_t)-1) { - | b =>false_label - } - if (op1_info & MAY_BE_ANY) { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | b >9 - } - } else if (false_label == (uint32_t)-1) { - | b >9 - } - |.code - } - } - - if (!jmp_done) { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - if (op1_info & MAY_BE_LONG) { - | b >9 - } - } else if (op1_info & MAY_BE_LONG) { - | b &exit_addr - } - } else if (false_label != (uint32_t)-1) { - | b =>false_label - } else if ((op1_info & MAY_BE_LONG) || (op1_info & MAY_BE_ANY) == MAY_BE_DOUBLE) { - | b >9 - } - } - } - } - - if (op1_info & MAY_BE_LONG) { - |2: - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >2, ZREG_TMP1 - } - if (Z_MODE(op1_addr) == IS_REG) { - | tst Rx(Z_REG(op1_addr)), Rx(Z_REG(op1_addr)) - } else { - | LONG_CMP_WITH_CONST op1_addr, Z_L(0), TMP1, TMP2 - } - if (set_bool) { - | cset REG0w, ne - if (set_bool_not) { - | neg REG0w, REG0w - | add REG0w, REG0w, #3 - } else { - | add REG0w, REG0w, #2 - } - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | bne &exit_addr - } else { - | beq &exit_addr - } - } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) { - if (true_label != (uint32_t)-1) { - | bne =>true_label - if (false_label != (uint32_t)-1) { - | b =>false_label - } - } else { - | beq =>false_label - } - } - } - - if ((op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) == MAY_BE_DOUBLE) { - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - |.cold_code - } - |2: - | fmov FPR0, xzr // TODO: "movi d0, #0" is not recognized by DynASM/arm64 - | DOUBLE_CMP ZREG_FPR0, op1_addr, ZREG_TMP1, ZREG_FPTMP - - if (set_bool) { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | bvs &exit_addr - | bne &exit_addr - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } else { - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | beq &exit_addr - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - } else if (false_label != (uint32_t)-1) { // JMPZ_EX - | bvs >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | beq => false_label - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } else if (true_label != (uint32_t)-1) { // JMPNZ_EX - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | bvs => true_label - | bne => true_label - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } else if (set_bool_not) { // BOOL_NOT - | mov REG0w, #IS_FALSE - | bvs >1 - | bne >1 - | mov REG0w, #IS_TRUE - |1: - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } else { // BOOL - | mov REG0w, #IS_TRUE - | bvs >1 - | bne >1 - | mov REG0w, #IS_FALSE - |1: - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - |.code - } - } else { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | bvs &exit_addr - | bne &exit_addr - |1: - } else { - | bvs >1 - | beq &exit_addr - |1: - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } else { - ZEND_ASSERT(true_label != (uint32_t)-1 || false_label != (uint32_t)-1); - if (false_label != (uint32_t)-1 ) { - | bvs >1 - | beq => false_label - |1: - if (true_label != (uint32_t)-1) { - | b =>true_label - } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } else { - | bvs => true_label - | bne => true_label - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - |.code - } - } - } else if (op1_info & (MAY_BE_ANY - (MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG))) { - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - |.cold_code - |2: - } - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_is_true, REG0 - | mov REG0, RETVALx - - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | IF_NOT_ZVAL_REFCOUNTED op1_addr, >3, ZREG_TMP1, ZREG_TMP2 - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - | bne >3 - // In x86, r0 is used in macro ZVAL_DTOR_FUNC as temporary register, hence, r0 should be saved/restored - // before/after this macro. In AArch64, TMP1 is used, but we still have to store REG0, - // because it's clobbered by function call. - | str REG0, T1 // save - | ZVAL_DTOR_FUNC op1_info, opline, TMP1 - | ldr REG0, T1 // restore - |3: - } - if (may_throw) { - | MEM_LOAD_64_ZTS ldr, REG1, executor_globals, exception, TMP1 - | cbnz REG1, ->exception_handler_undef - } - - if (set_bool) { - if (set_bool_not) { - | neg REG0w, REG0w - | add REG0w, REG0w, #3 - } else { - | add REG0w, REG0w, #2 - } - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - if (exit_addr) { - | CMP_ZVAL_TYPE res_addr, IS_FALSE, ZREG_TMP1 - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | bne &exit_addr - } else { - | beq &exit_addr - } - } else if (true_label != (uint32_t)-1 || false_label != (uint32_t)-1) { - | CMP_ZVAL_TYPE res_addr, IS_FALSE, ZREG_TMP1 - if (true_label != (uint32_t)-1) { - | bne =>true_label - if (false_label != (uint32_t)-1) { - | b =>false_label - } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } else { - | beq =>false_label - } - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - |.code - } - } else { - if (exit_addr) { - if (branch_opcode == ZEND_JMPNZ || branch_opcode == ZEND_JMPNZ_EX) { - | cbnz REG0w, &exit_addr - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } else { - | cbz REG0w, &exit_addr - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } - } else if (true_label != (uint32_t)-1) { - | cbnz REG0w, =>true_label - if (false_label != (uint32_t)-1) { - | b =>false_label - } else if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } else { - | cbz REG0w, =>false_label - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - | b >9 - } - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG)) { - |.code - } - } - } - - |9: - - return 1; -} - -static int zend_jit_qm_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr, uint32_t res_use_info, uint32_t res_info, zend_jit_addr res_addr) -{ - if (op1_addr != op1_def_addr) { - if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) { - return 0; - } - if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) { - op1_addr = op1_def_addr; - } - } - - if (!zend_jit_simple_assign(Dst, opline, res_addr, res_use_info, res_info, opline->op1_type, op1_addr, op1_info, 0, 0, 0, 1)) { - return 0; - } - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - if (op1_info & MAY_BE_UNDEF) { - zend_jit_check_exception(Dst); - } - return 1; -} - -static int zend_jit_assign(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_use_addr, uint32_t op1_def_info, zend_jit_addr op1_addr, uint32_t op2_info, zend_jit_addr op2_addr, zend_jit_addr op2_def_addr, uint32_t res_info, zend_jit_addr res_addr, int may_throw) -{ - ZEND_ASSERT(opline->op1_type == IS_CV); - - if (op2_addr != op2_def_addr) { - if (!zend_jit_update_regs(Dst, opline->op2.var, op2_addr, op2_def_addr, op2_info)) { - return 0; - } - if (Z_MODE(op2_def_addr) == IS_REG && Z_MODE(op2_addr) != IS_REG) { - op2_addr = op2_def_addr; - } - } - - if (Z_MODE(op1_addr) != IS_REG - && Z_MODE(op1_use_addr) == IS_REG - && !Z_LOAD(op1_use_addr) - && !Z_STORE(op1_use_addr)) { - /* Force type update */ - op1_info |= MAY_BE_UNDEF; - } - if (!zend_jit_assign_to_variable(Dst, opline, op1_use_addr, op1_addr, op1_info, op1_def_info, opline->op2_type, op2_addr, op2_info, res_addr, - may_throw)) { - return 0; - } - if (!zend_jit_store_var_if_necessary_ex(Dst, opline->op1.var, op1_addr, op1_def_info, op1_use_addr, op1_info)) { - return 0; - } - if (opline->result_type != IS_UNUSED) { - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - } - - return 1; -} - -/* copy of hidden zend_closure */ -typedef struct _zend_closure { - zend_object std; - zend_function func; - zval this_ptr; - zend_class_entry *called_scope; - zif_handler orig_internal_handler; -} zend_closure; - -static int zend_jit_stack_check(dasm_State **Dst, const zend_op *opline, uint32_t used_stack) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | // Check Stack Overflow - | MEM_LOAD_64_ZTS ldr, REG1, executor_globals, vm_stack_end, TMP1 - | MEM_LOAD_OP_ZTS sub, ldr, REG1, executor_globals, vm_stack_top, TMP1, TMP2 - | CMP_64_WITH_CONST_32 REG1, used_stack, TMP1 - | blo &exit_addr - - return 1; -} - -static int zend_jit_push_call_frame(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_function *func, bool is_closure, bool delayed_fetch_this, int checked_stack) -{ - uint32_t used_stack; - bool stack_check = 1; - - // REG0 -> zend_function - // FCARG1 -> used_stack - - if (func) { - used_stack = zend_vm_calc_used_stack(opline->extended_value, func); - if ((int)used_stack <= checked_stack) { - stack_check = 0; - } - } else { - used_stack = (ZEND_CALL_FRAME_SLOT + opline->extended_value + ZEND_OBSERVER_ENABLED) * sizeof(zval); - - | // if (EXPECTED(ZEND_USER_CODE(func->type))) { - if (!is_closure) { - | LOAD_32BIT_VAL FCARG1w, used_stack - | // Check whether REG0 is an internal function. - | ldrb TMP1w, [REG0, #offsetof(zend_function, type)] - | TST_32_WITH_CONST TMP1w, 1, TMP2w - | bne >1 - } else { - | LOAD_32BIT_VAL FCARG1w, used_stack - } - | // used_stack += (func->op_array.last_var + func->op_array.T - MIN(func->op_array.num_args, num_args)) * sizeof(zval); - | LOAD_32BIT_VAL REG2w, opline->extended_value - if (!is_closure) { - | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.num_args)] - | cmp REG2w, TMP1w - | csel REG2w, REG2w, TMP1w, le - | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.last_var)] - | sub REG2w, REG2w, TMP1w - | ldr TMP1w, [REG0, #offsetof(zend_function, op_array.T)] - | sub REG2w, REG2w, TMP1w - } else { - | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.num_args)] - | cmp REG2w, TMP1w - | csel REG2w, REG2w, TMP1w, le - | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.last_var)] - | sub REG2w, REG2w, TMP1w - | ldr TMP1w, [REG0, #offsetof(zend_closure, func.op_array.T)] - | sub REG2w, REG2w, TMP1w - } - | sxtw REG2, REG2w - | sub FCARG1x, FCARG1x, REG2, lsl #4 - |1: - } - - zend_jit_start_reuse_ip(); - - | // if (UNEXPECTED(used_stack > (size_t)(((char*)EG(vm_stack_end)) - (char*)call))) { - | MEM_LOAD_64_ZTS ldr, RX, executor_globals, vm_stack_top, TMP1 - - if (stack_check) { - | // Check Stack Overflow - | MEM_LOAD_64_ZTS ldr, REG2, executor_globals, vm_stack_end, TMP1 - | sub REG2, REG2, RX - if (func) { - | CMP_64_WITH_CONST_32 REG2, used_stack, TMP1 - } else { - | cmp REG2, FCARG1x - } - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | blo &exit_addr - } else { - | blo >1 - | // EG(vm_stack_top) = (zval*)((char*)call + used_stack); - |.cold_code - |1: - if (func) { - | LOAD_32BIT_VAL FCARG1w, used_stack - } - if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) { - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_int_extend_stack_helper, REG0 - } else { - if (!is_closure) { - | mov FCARG2x, REG0 - } else { - | add FCARG2x, REG0, #offsetof(zend_closure, func) - } - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_extend_stack_helper, REG0 - } - | mov RX, RETVALx - | b >1 - |.code - } - } - - if (func) { - || if (arm64_may_encode_imm12((int64_t)used_stack)) { - | MEM_UPDATE_ZTS add, ldr, str, #used_stack, executor_globals, vm_stack_top, REG2, TMP1 - || } else { - | LOAD_32BIT_VAL TMP1w, used_stack - | MEM_UPDATE_ZTS add, ldr, str, TMP1, executor_globals, vm_stack_top, REG2, TMP2 - || } - } else { - | MEM_UPDATE_ZTS add, ldr, str, FCARG1x, executor_globals, vm_stack_top, REG2, TMP1 - } - | // zend_vm_init_call_frame(call, call_info, func, num_args, called_scope, object); - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || opline->opcode != ZEND_INIT_METHOD_CALL) { - | // ZEND_SET_CALL_INFO(call, 0, call_info); - | LOAD_32BIT_VAL TMP1w, (IS_UNDEF | ZEND_CALL_NESTED_FUNCTION) - | str TMP1w, EX:RX->This.u1.type_info - } - if (opline->opcode == ZEND_INIT_FCALL && func && func->type == ZEND_INTERNAL_FUNCTION) { - | // call->func = func; - |1: - | ADDR_STORE EX:RX->func, func, REG1 - } else { - if (!is_closure) { - | // call->func = func; - | str REG0, EX:RX->func - } else { - | // call->func = &closure->func; - | add REG1, REG0, #offsetof(zend_closure, func) - | str REG1, EX:RX->func - } - |1: - } - if (opline->opcode == ZEND_INIT_METHOD_CALL) { - | // Z_PTR(call->This) = obj; - | ldr REG1, T1 - | str REG1, EX:RX->This.value.ptr - if (opline->op1_type == IS_UNUSED || delayed_fetch_this) { - | // call->call_info |= ZEND_CALL_HAS_THIS; - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - | LOAD_32BIT_VAL TMP1w, ZEND_CALL_HAS_THIS - | str TMP1w, EX:RX->This.u1.type_info - } else { - | ldr TMP1w, EX:RX->This.u1.type_info - | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_HAS_THIS, TMP2w - | str TMP1w, EX:RX->This.u1.type_info - } - } else { - if (opline->op1_type == IS_CV) { - | // GC_ADDREF(obj); - | GC_ADDREF REG1, TMP1w - } - | // call->call_info |= ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS; - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - | LOAD_32BIT_VAL TMP1w, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS) - | str TMP1w, EX:RX->This.u1.type_info - } else { - | ldr TMP1w, EX:RX->This.u1.type_info - | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, (ZEND_CALL_HAS_THIS | ZEND_CALL_RELEASE_THIS), TMP2w - | str TMP1w, EX:RX->This.u1.type_info - } - } - } else if (!is_closure) { - | // Z_CE(call->This) = called_scope; - | str xzr, EX:RX->This.value.ptr - } else { - if (opline->op2_type == IS_CV) { - | // GC_ADDREF(closure); - | GC_ADDREF REG0, TMP1w - } - | // object_or_called_scope = closure->called_scope; - | ldr REG1, [REG0, #offsetof(zend_closure, called_scope)] - | str REG1, EX:RX->This.value.ptr - | // call_info = ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE | - | // (closure->func->common.fn_flags & ZEND_ACC_FAKE_CLOSURE); - | ldr REG2w, [REG0, #offsetof(zend_closure, func.common.fn_flags)] - | BW_OP_32_WITH_CONST and, REG2w, REG2w, ZEND_ACC_FAKE_CLOSURE, TMP1w - | BW_OP_32_WITH_CONST orr, REG2w, REG2w, (ZEND_CALL_NESTED_FUNCTION | ZEND_CALL_DYNAMIC | ZEND_CALL_CLOSURE), TMP1w - | // if (Z_TYPE(closure->this_ptr) != IS_UNDEF) { - | ldrb TMP1w, [REG0, #offsetof(zend_closure, this_ptr.u1.v.type)] - | cmp TMP1w, #IS_UNDEF - | beq >1 - | // call_info |= ZEND_CALL_HAS_THIS; - | BW_OP_32_WITH_CONST orr, REG2w, REG2w, ZEND_CALL_HAS_THIS, TMP1w - | // object_or_called_scope = Z_OBJ(closure->this_ptr); - | ldr REG1, [REG0, #offsetof(zend_closure, this_ptr.value.ptr)] - |1: - | // ZEND_SET_CALL_INFO(call, 0, call_info); - | ldr TMP1w, EX:RX->This.u1.type_info - | orr TMP1w, TMP1w, REG2w - | str TMP1w, EX:RX->This.u1.type_info - | // Z_PTR(call->This) = object_or_called_scope; - | str REG1, EX:RX->This.value.ptr - | ldr TMP1, [REG0, #offsetof(zend_closure, func.op_array.run_time_cache__ptr)] - | cbnz TMP1, >1 - | add FCARG1x, REG0, #offsetof(zend_closure, func) - | EXT_CALL zend_jit_init_func_run_time_cache_helper, REG0 - |1: - } - | // ZEND_CALL_NUM_ARGS(call) = num_args; - | LOAD_32BIT_VAL TMP1w, opline->extended_value - | str TMP1w, EX:RX->This.u2.num_args - - return 1; -} - -static int zend_jit_init_fcall_guard(dasm_State **Dst, uint32_t level, const zend_function *func, const zend_op *to_opline) -{ - int32_t exit_point; - const void *exit_addr; - - if (func->type == ZEND_INTERNAL_FUNCTION) { -#ifdef ZEND_WIN32 - // TODO: ASLR may cause different addresses in different workers ??? - return 0; -#endif - } else if (func->type == ZEND_USER_FUNCTION) { - if (!zend_accel_in_shm(func->op_array.opcodes)) { - /* op_array and op_array->opcodes are not persistent. We can't link. */ - return 0; - } - } else { - ZEND_UNREACHABLE(); - return 0; - } - - exit_point = zend_jit_trace_get_exit_point(to_opline, ZEND_JIT_EXIT_POLYMORPHISM); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - | // call = EX(call); - | ldr REG1, EX->call - while (level > 0) { - | ldr REG1, EX:REG1->prev_execute_data - level--; - } - - if (func->type == ZEND_USER_FUNCTION && - (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) || - (func->common.fn_flags & ZEND_ACC_CLOSURE) || - !func->common.function_name)) { - const zend_op *opcodes = func->op_array.opcodes; - - | ldr REG1, EX:REG1->func - | LOAD_ADDR REG2, ((ptrdiff_t)opcodes) - | ldr TMP1, [REG1, #offsetof(zend_op_array, opcodes)] - | cmp TMP1, REG2 - | bne &exit_addr - } else { - | LOAD_ADDR REG2, ((ptrdiff_t)func) - | ldr TMP1, EX:REG1->func - | cmp TMP1, REG2 - | bne &exit_addr - } - - return 1; -} - -static int zend_jit_init_fcall(dasm_State **Dst, const zend_op *opline, uint32_t b, const zend_op_array *op_array, zend_ssa *ssa, const zend_ssa_op *ssa_op, int call_level, zend_jit_trace_rec *trace, int checked_stack) -{ - zend_func_info *info = ZEND_FUNC_INFO(op_array); - zend_call_info *call_info = NULL; - zend_function *func = NULL; - - if (delayed_call_chain) { - if (!zend_jit_save_call_chain(Dst, delayed_call_level)) { - return 0; - } - } - - if (info) { - call_info = info->callee_info; - while (call_info && call_info->caller_init_opline != opline) { - call_info = call_info->next_callee; - } - if (call_info && call_info->callee_func && !call_info->is_prototype) { - func = call_info->callee_func; - } - } - - if (!func - && trace - && trace->op == ZEND_JIT_TRACE_INIT_CALL) { - func = (zend_function*)trace->func; - } - - if (opline->opcode == ZEND_INIT_FCALL - && func - && func->type == ZEND_INTERNAL_FUNCTION) { - /* load constant address later */ - } else if (func && op_array == &func->op_array) { - /* recursive call */ - | ldr REG0, EX->func - } else { - | // if (CACHED_PTR(opline->result.num)) - | ldr REG2, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG2, opline->result.num, TMP1 - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && func - && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) - && opline->opcode != ZEND_INIT_FCALL) { - /* Called func may be changed because of recompilation. See ext/opcache/tests/jit/init_fcall_003.phpt */ - | LOAD_ADDR REG1, ((ptrdiff_t)func) - | cmp REG0, REG1 - | bne >1 - } else { - | cbz REG0, >1 - } - |.cold_code - |1: - if (opline->opcode == ZEND_INIT_FCALL - && func - && func->type == ZEND_USER_FUNCTION - && (func->op_array.fn_flags & ZEND_ACC_IMMUTABLE)) { - | LOAD_ADDR FCARG1x, func - | MEM_ACCESS_64_WITH_UOFFSET str, FCARG1x, REG2, opline->result.num, TMP1 - | EXT_CALL zend_jit_init_func_run_time_cache_helper, REG0 - | mov REG0, RETVALx - | b >3 - } else { - zval *zv = RT_CONSTANT(opline, opline->op2); - - if (opline->opcode == ZEND_INIT_FCALL) { - | LOAD_ADDR FCARG1x, Z_STR_P(zv); - | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1 - | EXT_CALL zend_jit_find_func_helper, REG0 - } else if (opline->opcode == ZEND_INIT_FCALL_BY_NAME) { - | LOAD_ADDR FCARG1x, Z_STR_P(zv + 1); - | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1 - | EXT_CALL zend_jit_find_func_helper, REG0 - } else if (opline->opcode == ZEND_INIT_NS_FCALL_BY_NAME) { - | LOAD_ADDR FCARG1x, zv; - | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, REG2, opline->result.num, TMP1 - | EXT_CALL zend_jit_find_ns_func_helper, REG0 - } else { - ZEND_UNREACHABLE(); - } - | // Get the return value of function zend_jit_find_func_helper/zend_jit_find_ns_func_helper - | mov REG0, RETVALx - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, - func && (func->common.fn_flags & ZEND_ACC_IMMUTABLE) ? ZEND_JIT_EXIT_INVALIDATE : 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - if (!func || opline->opcode == ZEND_INIT_FCALL) { - | cbnz REG0, >3 - } else if (func->type == ZEND_USER_FUNCTION - && !(func->common.fn_flags & ZEND_ACC_IMMUTABLE)) { - const zend_op *opcodes = func->op_array.opcodes; - - | LOAD_ADDR REG1, ((ptrdiff_t)opcodes) - | ldr TMP1, [REG0, #offsetof(zend_op_array, opcodes)] - | cmp TMP1, REG1 - | beq >3 - } else { - | LOAD_ADDR REG1, ((ptrdiff_t)func) - | cmp REG0, REG1 - | beq >3 - } - | b &exit_addr - } else { - | cbnz REG0, >3 - | // SAVE_OPLINE(); - | SET_EX_OPLINE opline, REG0 - | b ->undefined_function - } - } - |.code - |3: - } - - if (!zend_jit_push_call_frame(Dst, opline, op_array, func, 0, 0, checked_stack)) { - return 0; - } - - if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) { - if (!zend_jit_save_call_chain(Dst, call_level)) { - return 0; - } - } else { - delayed_call_chain = 1; - delayed_call_level = call_level; - } - - return 1; -} - -static int zend_jit_init_method_call(dasm_State **Dst, - const zend_op *opline, - uint32_t b, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - int call_level, - uint32_t op1_info, - zend_jit_addr op1_addr, - zend_class_entry *ce, - bool ce_is_instanceof, - bool on_this, - bool delayed_fetch_this, - zend_class_entry *trace_ce, - zend_jit_trace_rec *trace, - int checked_stack, - bool polymorphic_side_trace) -{ - zend_func_info *info = ZEND_FUNC_INFO(op_array); - zend_call_info *call_info = NULL; - zend_function *func = NULL; - zval *function_name; - - ZEND_ASSERT(opline->op2_type == IS_CONST); - ZEND_ASSERT(op1_info & MAY_BE_OBJECT); - - function_name = RT_CONSTANT(opline, opline->op2); - - if (info) { - call_info = info->callee_info; - while (call_info && call_info->caller_init_opline != opline) { - call_info = call_info->next_callee; - } - if (call_info && call_info->callee_func && !call_info->is_prototype) { - func = call_info->callee_func; - } - } - - if (polymorphic_side_trace) { - /* function is passed in r0 from parent_trace */ - } else { - if (on_this) { - zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); - - | GET_ZVAL_PTR FCARG1x, this_addr, TMP1 - } else { - if (op1_info & MAY_BE_REF) { - if (opline->op1_type == IS_CV) { - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } else { - /* Hack: Convert reference to regular value to simplify JIT code */ - ZEND_ASSERT(Z_REG(op1_addr) == ZREG_FP); - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1 - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | EXT_CALL zend_jit_unref_helper, REG0 - |1: - } - } - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1 - |.cold_code - |1: - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | SET_EX_OPLINE opline, REG0 - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) { - | EXT_CALL zend_jit_invalid_method_call_tmp, REG0 - } else { - | EXT_CALL zend_jit_invalid_method_call, REG0 - } - | b ->exception_handler - |.code - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - } - - if (delayed_call_chain) { - if (!zend_jit_save_call_chain(Dst, delayed_call_level)) { - return 0; - } - } - - | str FCARG1x, T1 // save - - if (func) { - | // fbc = CACHED_PTR(opline->result.num + sizeof(void*)); - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->result.num + sizeof(void*)), TMP1 - | cbz REG0, >1 - } else { - | // if (CACHED_PTR(opline->result.num) == obj->ce)) { - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->result.num, TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] - | cmp REG2, TMP1 - | bne >1 - | // fbc = CACHED_PTR(opline->result.num + sizeof(void*)); - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->result.num + sizeof(void*)), TMP1 - } - - |.cold_code - |1: - | LOAD_ADDR FCARG2x, function_name - if (TMP_ZVAL_OFFSET == 0) { - | mov CARG3, sp - } else { - | add CARG3, sp, #TMP_ZVAL_OFFSET - } - | SET_EX_OPLINE opline, REG0 - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) { - | EXT_CALL zend_jit_find_method_tmp_helper, REG0 - } else { - | EXT_CALL zend_jit_find_method_helper, REG0 - } - | mov REG0, RETVALx - | cbnz REG0, >2 - | b ->exception_handler - |.code - |2: - } - - if ((!func || zend_jit_may_be_modified(func, op_array)) - && trace - && trace->op == ZEND_JIT_TRACE_INIT_CALL - && trace->func - ) { - int32_t exit_point; - const void *exit_addr; - - exit_point = zend_jit_trace_get_exit_point(opline, func ? ZEND_JIT_EXIT_INVALIDATE : ZEND_JIT_EXIT_METHOD_CALL); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - func = (zend_function*)trace->func; - - if (func->type == ZEND_USER_FUNCTION && - (!(func->common.fn_flags & ZEND_ACC_IMMUTABLE) || - (func->common.fn_flags & ZEND_ACC_CLOSURE) || - !func->common.function_name)) { - const zend_op *opcodes = func->op_array.opcodes; - - | LOAD_ADDR TMP1, opcodes - | ldr TMP2, [REG0, #offsetof(zend_op_array, opcodes)] - | cmp TMP2, TMP1 - | bne &exit_addr - } else { - | LOAD_ADDR TMP1, func - | cmp REG0, TMP1 - | bne &exit_addr - } - } - - if (!func) { - | // if (fbc->common.fn_flags & ZEND_ACC_STATIC) { - | ldr TMP1w, [REG0, #offsetof(zend_function, common.fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_STATIC, TMP2w - | bne >1 - |.cold_code - |1: - } - - if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) != 0) { - | ldr FCARG1x, T1 // restore - | mov FCARG2x, REG0 - | LOAD_32BIT_VAL CARG3w, opline->extended_value - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && !delayed_fetch_this) { - | EXT_CALL zend_jit_push_static_metod_call_frame_tmp, REG0 - } else { - | EXT_CALL zend_jit_push_static_metod_call_frame, REG0 - } - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR) && !delayed_fetch_this)) { - | cbz RETVALx, ->exception_handler - } - | mov RX, RETVALx - } - - if (!func) { - | b >9 - |.code - } - - if (!func || (func->common.fn_flags & ZEND_ACC_STATIC) == 0) { - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 0, delayed_fetch_this, checked_stack)) { - return 0; - } - } - - if (!func) { - |9: - } - zend_jit_start_reuse_ip(); - - if (zend_jit_needs_call_chain(call_info, b, op_array, ssa, ssa_op, opline, call_level, trace)) { - if (!zend_jit_save_call_chain(Dst, call_level)) { - return 0; - } - } else { - delayed_call_chain = 1; - delayed_call_level = call_level; - } - - return 1; -} - -static int zend_jit_init_closure_call(dasm_State **Dst, - const zend_op *opline, - uint32_t b, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - int call_level, - zend_jit_trace_rec *trace, - int checked_stack) -{ - zend_function *func = NULL; - zend_jit_addr op2_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); - - | GET_ZVAL_PTR REG0, op2_addr, TMP1 - - if (ssa->var_info[ssa_op->op2_use].ce != zend_ce_closure - && !(ssa->var_info[ssa_op->op2_use].type & MAY_BE_CLASS_GUARD)) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | LOAD_ADDR FCARG1x, ((ptrdiff_t)zend_ce_closure) - | ldr, TMP1, [REG0, #offsetof(zend_object, ce)] - | cmp TMP1, FCARG1x - | bne &exit_addr - if (ssa->var_info && ssa_op->op2_use >= 0) { - ssa->var_info[ssa_op->op2_use].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op2_use].ce = zend_ce_closure; - ssa->var_info[ssa_op->op2_use].is_instanceof = 0; - } - } - - if (trace - && trace->op == ZEND_JIT_TRACE_INIT_CALL - && trace->func - && trace->func->type == ZEND_USER_FUNCTION) { - const zend_op *opcodes; - int32_t exit_point; - const void *exit_addr; - - func = (zend_function*)trace->func; - opcodes = func->op_array.opcodes; - exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_CLOSURE_CALL); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - | LOAD_ADDR FCARG1x, ((ptrdiff_t)opcodes) - | ldr TMP1, [REG0, #offsetof(zend_closure, func.op_array.opcodes)] - | cmp TMP1, FCARG1x - | bne &exit_addr - } - - if (delayed_call_chain) { - if (!zend_jit_save_call_chain(Dst, delayed_call_level)) { - return 0; - } - } - - if (!zend_jit_push_call_frame(Dst, opline, NULL, func, 1, 0, checked_stack)) { - return 0; - } - - if (zend_jit_needs_call_chain(NULL, b, op_array, ssa, ssa_op, opline, call_level, trace)) { - if (!zend_jit_save_call_chain(Dst, call_level)) { - return 0; - } - } else { - delayed_call_chain = 1; - delayed_call_level = call_level; - } - - if (trace - && trace->op == ZEND_JIT_TRACE_END - && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) { - if (!zend_jit_set_valid_ip(Dst, opline + 1)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_do_fcall(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, int call_level, unsigned int next_block, zend_jit_trace_rec *trace) -{ - zend_func_info *info = ZEND_FUNC_INFO(op_array); - zend_call_info *call_info = NULL; - const zend_function *func = NULL; - uint32_t i; - zend_jit_addr res_addr; - uint32_t call_num_args = 0; - bool unknown_num_args = 0; - const void *exit_addr = NULL; - const zend_op *prev_opline; - - if (RETURN_VALUE_USED(opline)) { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - } else { - /* CPU stack allocated temporary zval */ - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RSP, TMP_ZVAL_OFFSET); - } - - prev_opline = opline - 1; - while (prev_opline->opcode == ZEND_EXT_FCALL_BEGIN || prev_opline->opcode == ZEND_TICKS) { - prev_opline--; - } - if (prev_opline->opcode == ZEND_SEND_UNPACK || prev_opline->opcode == ZEND_SEND_ARRAY || - prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) { - unknown_num_args = 1; - } - - if (info) { - call_info = info->callee_info; - while (call_info && call_info->caller_call_opline != opline) { - call_info = call_info->next_callee; - } - if (call_info && call_info->callee_func && !call_info->is_prototype) { - func = call_info->callee_func; - } - if ((op_array->fn_flags & ZEND_ACC_TRAIT_CLONE) - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && !JIT_G(current_frame)->call->func) { - call_info = NULL; func = NULL; /* megamorphic call from trait */ - } - } - if (!func) { - /* resolve function at run time */ - } else if (func->type == ZEND_USER_FUNCTION) { - ZEND_ASSERT(opline->opcode != ZEND_DO_ICALL); - call_num_args = call_info->num_args; - } else if (func->type == ZEND_INTERNAL_FUNCTION) { - ZEND_ASSERT(opline->opcode != ZEND_DO_UCALL); - call_num_args = call_info->num_args; - } else { - ZEND_UNREACHABLE(); - } - - if (trace && !func) { - if (trace->op == ZEND_JIT_TRACE_DO_ICALL) { - ZEND_ASSERT(trace->func->type == ZEND_INTERNAL_FUNCTION); -#ifndef ZEND_WIN32 - // TODO: ASLR may cause different addresses in different workers ??? - func = trace->func; - if (JIT_G(current_frame) && - JIT_G(current_frame)->call && - TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) { - call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call); - } else { - unknown_num_args = 1; - } -#endif - } else if (trace->op == ZEND_JIT_TRACE_ENTER) { - ZEND_ASSERT(trace->func->type == ZEND_USER_FUNCTION); - if (zend_accel_in_shm(trace->func->op_array.opcodes)) { - func = trace->func; - if (JIT_G(current_frame) && - JIT_G(current_frame)->call && - TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call) >= 0) { - call_num_args = TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)->call); - } else { - unknown_num_args = 1; - } - } - } - } - - bool may_have_extra_named_params = - opline->extended_value == ZEND_FCALL_MAY_HAVE_EXTRA_NAMED_PARAMS && - (!func || func->common.fn_flags & ZEND_ACC_VARIADIC); - - if (!reuse_ip) { - zend_jit_start_reuse_ip(); - | // call = EX(call); - | ldr RX, EX->call - } - zend_jit_stop_reuse_ip(); - - | // fbc = call->func; - | // mov r2, EX:RX->func ??? - | // SAVE_OPLINE(); - | SET_EX_OPLINE opline, REG0 - - if (opline->opcode == ZEND_DO_FCALL) { - if (!func) { - if (trace) { - uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w - | bne &exit_addr - } - } - } - - if (!delayed_call_chain) { - if (call_level == 1) { - | str xzr, EX->call - } else { - | //EX(call) = call->prev_execute_data; - | ldr REG0, EX:RX->prev_execute_data - | str REG0, EX->call - } - } - delayed_call_chain = 0; - - | //call->prev_execute_data = execute_data; - | str EX, EX:RX->prev_execute_data - - if (!func) { - | ldr REG0, EX:RX->func - } - - if (opline->opcode == ZEND_DO_FCALL) { - if (!func) { - if (!trace) { - | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w - | bne >1 - |.cold_code - |1: - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, RX - } - | EXT_CALL zend_jit_deprecated_helper, REG0 - | GET_LOW_8BITS RETVALw, RETVALw - | ldr REG0, EX:RX->func // reload - | cbnz RETVALw, >1 // Result is 0 on exception - | b ->exception_handler - |.code - |1: - } - } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, RX - } - | EXT_CALL zend_jit_deprecated_helper, REG0 - | cbz RETVALw, ->exception_handler - } - } - - if (!func - && opline->opcode != ZEND_DO_UCALL - && opline->opcode != ZEND_DO_ICALL) { - | ldrb TMP1w, [REG0, #offsetof(zend_function, type)] - | cmp TMP1w, #ZEND_USER_FUNCTION - | bne >8 - } - - if ((!func || func->type == ZEND_USER_FUNCTION) - && opline->opcode != ZEND_DO_ICALL) { - | // EX(call) = NULL; - | str xzr, EX:RX->call - - if (RETURN_VALUE_USED(opline)) { - | // EX(return_value) = EX_VAR(opline->result.var); - | LOAD_ZVAL_ADDR REG2, res_addr - | str REG2, EX:RX->return_value - } else { - | // EX(return_value) = 0; - | str xzr, EX:RX->return_value - } - - //EX_LOAD_RUN_TIME_CACHE(op_array); - if (!func || func->op_array.cache_size) { - if (func && op_array == &func->op_array) { - /* recursive call */ - if (trace || func->op_array.cache_size > sizeof(void*)) { - | ldr REG2, EX->run_time_cache - | str REG2, EX:RX->run_time_cache - } - } else { - if (func - && !(func->op_array.fn_flags & ZEND_ACC_CLOSURE) - && ZEND_MAP_PTR_IS_OFFSET(func->op_array.run_time_cache)) { - | MEM_LOAD_64_ZTS ldr, REG2, compiler_globals, map_ptr_base, TMP1 - | ADD_SUB_64_WITH_CONST add, REG2, REG2, (uintptr_t)ZEND_MAP_PTR(func->op_array.run_time_cache), TMP1 - | ldr REG2, [REG2] - } else if ((func && (func->op_array.fn_flags & ZEND_ACC_CLOSURE)) || - (JIT_G(current_frame) && - JIT_G(current_frame)->call && - TRACE_FRAME_IS_CLOSURE_CALL(JIT_G(current_frame)->call))) { - /* Closures always use direct pointers */ - | ldr REG0, EX:RX->func - | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)] - } else { - if (func) { - | ldr REG0, EX:RX->func - } - | ldr REG2, [REG0, #offsetof(zend_op_array, run_time_cache__ptr)] - | TST_64_WITH_ONE REG2 - | beq >1 - | MEM_LOAD_OP_ZTS add, ldr, REG2, compiler_globals, map_ptr_base, REG1, TMP1 - | ldr REG2, [REG2] - |1: - } - | str REG2, EX:RX->run_time_cache - } - } - - | // EG(current_execute_data) = execute_data; - | MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1 - | mov FP, RX - - | // opline = op_array->opcodes; - if (func && !unknown_num_args) { - | ADD_SUB_64_WITH_CONST_32 add, TMP1, RX, (EX_NUM_TO_VAR(call_num_args) + offsetof(zval, u1.type_info)), TMP1 // induction variable - for (i = call_num_args; i < func->op_array.last_var; i++) { - | // ZVAL_UNDEF(EX_VAR(n)) - | str wzr, [TMP1], #16 - } - - if (call_num_args <= func->op_array.num_args) { - if (!trace || (trace->op == ZEND_JIT_TRACE_END - && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) { - uint32_t num_args; - - if ((func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) != 0) { - if (trace) { - num_args = 0; - } else if (call_info) { - num_args = skip_valid_arguments(op_array, ssa, call_info); - } else { - num_args = call_num_args; - } - } else { - num_args = call_num_args; - } - if (zend_accel_in_shm(func->op_array.opcodes)) { - | LOAD_IP_ADDR (func->op_array.opcodes + num_args) - } else { - | ldr REG0, EX->func - || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(num_args * sizeof(zend_op)))); - if (GCC_GLOBAL_REGS) { - | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)] - if (num_args) { - | add IP, IP, #(num_args * sizeof(zend_op)) - } - } else { - | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)] - if (num_args) { - | add FCARG1x, FCARG1x, #(num_args * sizeof(zend_op)) - } - | str FCARG1x, EX->opline - } - } - - if (GCC_GLOBAL_REGS && !trace && op_array == &func->op_array - && num_args >= op_array->required_num_args) { - /* recursive call */ - if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP - | mov FCARG1x, FP - | EXT_CALL zend_observer_fcall_begin, REG0 - } -#ifdef CONTEXT_THREADED_JIT - | NIY // TODO -#else - | b =>num_args -#endif - return 1; - } - } - } else { - if (!trace || (trace->op == ZEND_JIT_TRACE_END - && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER)) { - if (func && zend_accel_in_shm(func->op_array.opcodes)) { - | LOAD_IP_ADDR (func->op_array.opcodes) - } else if (GCC_GLOBAL_REGS) { - | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)] - } else { - | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)] - | str FCARG1x, EX->opline - } - } - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, FP - } - | EXT_CALL zend_jit_copy_extra_args_helper, REG0 - } - } else { - | // opline = op_array->opcodes - if (func && zend_accel_in_shm(func->op_array.opcodes)) { - | LOAD_IP_ADDR (func->op_array.opcodes) - } else if (GCC_GLOBAL_REGS) { - | ldr IP, [REG0, #offsetof(zend_op_array, opcodes)] - } else { - | ldr FCARG1x, [REG0, #offsetof(zend_op_array, opcodes)] - | str FCARG1x, EX->opline - } - if (func) { - | // num_args = EX_NUM_ARGS(); - | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)] - | // if (UNEXPECTED(num_args > first_extra_arg)) - | CMP_32_WITH_CONST REG1w, (func->op_array.num_args), TMP1w - } else { - | // first_extra_arg = op_array->num_args; - | ldr REG2w, [REG0, #offsetof(zend_op_array, num_args)] - | // num_args = EX_NUM_ARGS(); - | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)] - | // if (UNEXPECTED(num_args > first_extra_arg)) - | cmp REG1w, REG2w - } - | bgt >1 - |.cold_code - |1: - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, FP - } - | EXT_CALL zend_jit_copy_extra_args_helper, REG0 - if (!func) { - | ldr REG0, EX->func // reload - } - | ldr REG1w, [FP, #offsetof(zend_execute_data, This.u2.num_args)] // reload - | b >1 - |.code - if (!func || (func->op_array.fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0) { - if (!func) { - | // if (EXPECTED((op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) == 0)) - | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_HAS_TYPE_HINTS, TMP2w - | bne >1 - } - | // opline += num_args; - || ZEND_ASSERT(sizeof(zend_op) == 32); - | mov REG2w, REG1w - | ADD_IP_SHIFT REG2, lsl #5, TMP1 - } - |1: - | // if (EXPECTED((int)num_args < op_array->last_var)) { - if (func) { - | LOAD_32BIT_VAL REG2w, func->op_array.last_var - } else { - | ldr REG2w, [REG0, #offsetof(zend_op_array, last_var)] - } - | subs REG2w, REG2w, REG1w - | ble >3 - | // zval *var = EX_VAR_NUM(num_args); - | add REG1, FP, REG1, lsl #4 - || ZEND_ASSERT(arm64_may_encode_imm12((int64_t)(ZEND_CALL_FRAME_SLOT * sizeof(zval)))); - | add REG1, REG1, #(ZEND_CALL_FRAME_SLOT * sizeof(zval)) - |2: - | SET_Z_TYPE_INFO REG1, IS_UNDEF, TMP1w - | add REG1, REG1, #16 - | subs REG2w, REG2w, #1 - | bne <2 - |3: - } - - if (ZEND_OBSERVER_ENABLED) { - | SAVE_IP - | mov FCARG1x, FP - | EXT_CALL zend_observer_fcall_begin, REG0 - } - - if (trace) { - if (!func && (opline->opcode != ZEND_DO_UCALL)) { - | b >9 - } - } else { -#ifdef CONTEXT_THREADED_JIT - | NIY // TODO: CONTEXT_THREADED_JIT is always undefined. -#else - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD - | JMP_IP TMP1 - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment - | JMP_IP TMP1 - } else { - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #1 // ZEND_VM_ENTER - | ret - } - } -#endif - } - - if ((!func || func->type == ZEND_INTERNAL_FUNCTION) - && (opline->opcode != ZEND_DO_UCALL)) { - if (!func && (opline->opcode != ZEND_DO_ICALL)) { - |8: - } - if (opline->opcode == ZEND_DO_FCALL_BY_NAME) { - if (!func) { - if (trace) { - uint32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w - | bne &exit_addr - } else { - | ldr TMP1w, [REG0, #offsetof(zend_op_array, fn_flags)] - | TST_32_WITH_CONST TMP1w, ZEND_ACC_DEPRECATED, TMP2w - | bne >1 - |.cold_code - |1: - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, RX - } - | EXT_CALL zend_jit_deprecated_helper, REG0 - | GET_LOW_8BITS RETVALw, RETVALw - | ldr REG0, EX:RX->func // reload - | cbnz RETVALw, >1 // Result is 0 on exception - | b ->exception_handler - |.code - |1: - } - } else if (func->common.fn_flags & ZEND_ACC_DEPRECATED) { - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, RX - } - | EXT_CALL zend_jit_deprecated_helper, REG0 - | cbz RETVALw, ->exception_handler - | ldr REG0, EX:RX->func // reload - } - } - - | // EG(current_execute_data) = execute_data; - | MEM_STORE_64_ZTS str, RX, executor_globals, current_execute_data, REG1 - - if (ZEND_OBSERVER_ENABLED) { - | mov FCARG1x, RX - | EXT_CALL zend_observer_fcall_begin, REG0 - | ldr REG0, EX:RX->func // reload - } - - | // ZVAL_NULL(EX_VAR(opline->result.var)); - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | SET_Z_TYPE_INFO FCARG2x, IS_NULL, TMP1w - - zend_jit_reset_last_valid_opline(); - - | // (zend_execute_internal ? zend_execute_internal : fbc->internal_function.handler)(call, ret); - | mov FCARG1x, RX - if (zend_execute_internal) { - | EXT_CALL zend_execute_internal, REG0 - } else { - if (func) { - | EXT_CALL func->internal_function.handler, REG0 - } else { - | ldr TMP1, [REG0, #offsetof(zend_internal_function, handler)] - | blr TMP1 - } - } - - if (ZEND_OBSERVER_ENABLED) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | mov FCARG1x, RX - | EXT_CALL zend_observer_fcall_end, REG0 - } - - | // EG(current_execute_data) = execute_data; - | MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0 - - | // zend_vm_stack_free_args(call); - if (func && !unknown_num_args) { - for (i = 0; i < call_num_args; i++ ) { - if (zend_jit_needs_arg_dtor(func, i, call_info)) { - uint32_t offset = EX_NUM_TO_VAR(i); - zend_jit_addr arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, offset); - | ZVAL_PTR_DTOR arg_addr, (MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN), 0, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - } - } else { - | mov FCARG1x, RX - | EXT_CALL zend_jit_vm_stack_free_args_helper, REG0 - } - if (may_have_extra_named_params) { - | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 3)] - | TST_32_WITH_CONST TMP1w, (ZEND_CALL_HAS_EXTRA_NAMED_PARAMS >> 24), TMP2w - | bne >1 - |.cold_code - |1: - | ldr FCARG1x, [RX, #offsetof(zend_execute_data, extra_named_params)] - | EXT_CALL zend_free_extra_named_params, REG0 - | b >2 - |.code - |2: - } - - |8: - if (opline->opcode == ZEND_DO_FCALL) { - // TODO: optimize ??? - | // if (UNEXPECTED(ZEND_CALL_INFO(call) & ZEND_CALL_RELEASE_THIS)) - | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 2)] - | TST_32_WITH_CONST TMP1w, (ZEND_CALL_RELEASE_THIS >> 16), TMP2w - | bne >1 - |.cold_code - |1: - | add TMP1, RX, #offsetof(zend_execute_data, This) - | GET_Z_PTR FCARG1x, TMP1 - | // OBJ_RELEASE(object); - | OBJ_RELEASE ZREG_FCARG1, >2, ZREG_TMP1, ZREG_TMP2 - | b >2 - |.code - |2: - } - - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - !JIT_G(current_frame) || - !JIT_G(current_frame)->call || - !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)->call) || - prev_opline->opcode == ZEND_SEND_UNPACK || - prev_opline->opcode == ZEND_SEND_ARRAY || - prev_opline->opcode == ZEND_CHECK_UNDEF_ARGS) { - - | // zend_vm_stack_free_call_frame(call); - | ldrb TMP1w, [RX, #(offsetof(zend_execute_data, This.u1.type_info) + 2)] - | TST_32_WITH_CONST TMP1w, ((ZEND_CALL_ALLOCATED >> 16) & 0xff), TMP2w - | bne >1 - |.cold_code - |1: - | mov FCARG1x, RX - | EXT_CALL zend_jit_free_call_frame, REG0 - | b >1 - |.code - } - | MEM_STORE_64_ZTS str, RX, executor_globals, vm_stack_top, REG0 - |1: - - if (!RETURN_VALUE_USED(opline)) { - zend_class_entry *ce; - bool ce_is_instanceof; - uint32_t func_info = call_info ? - zend_get_func_info(call_info, ssa, &ce, &ce_is_instanceof) : - (MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN); - - /* If an exception is thrown, the return_value may stay at the - * original value of null. */ - func_info |= MAY_BE_NULL; - - if (func_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - | ZVAL_PTR_DTOR res_addr, func_info, 1, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - } - - | // if (UNEXPECTED(EG(exception) != NULL)) { - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbnz REG0, ->icall_throw_handler - - // TODO: Can we avoid checking for interrupts after each call ??? - if (trace && last_valid_opline != opline) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline + 1, ZEND_JIT_EXIT_TO_VM); - - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - } else { - exit_addr = NULL; - } - if (!zend_jit_check_timeout(Dst, opline + 1, exit_addr)) { - return 0; - } - - if ((!trace || !func) && opline->opcode != ZEND_DO_ICALL) { - | LOAD_IP_ADDR (opline + 1) - } else if (trace - && trace->op == ZEND_JIT_TRACE_END - && trace->stop == ZEND_JIT_TRACE_STOP_INTERPRETER) { - | LOAD_IP_ADDR (opline + 1) - } - } - - if (!func) { - |9: - } - - return 1; -} - -static int zend_jit_send_val(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr) -{ - uint32_t arg_num = opline->op2.num; - zend_jit_addr arg_addr; - - ZEND_ASSERT(opline->opcode == ZEND_SEND_VAL || arg_num <= MAX_ARG_FLAG_NUM); - - if (!zend_jit_reuse_ip(Dst)) { - return 0; - } - - if (opline->opcode == ZEND_SEND_VAL_EX) { - uint32_t mask = ZEND_SEND_BY_REF << ((arg_num + 3) * 2); - - ZEND_ASSERT(arg_num <= MAX_ARG_FLAG_NUM); - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && JIT_G(current_frame)->call->func) { - if (ARG_MUST_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - /* Don't generate code that always throws exception */ - return 0; - } - } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne &exit_addr - } else { - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne >1 - |.cold_code - |1: - if (Z_MODE(op1_addr) == IS_REG) { - /* set type to avoid zval_ptr_dtor() on uninitialized value */ - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - | SET_ZVAL_TYPE_INFO addr, IS_UNDEF, TMP1w, TMP2 - } - | SET_EX_OPLINE opline, REG0 - | b ->throw_cannot_pass_by_ref - |.code - } - } - - arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var); - - if (opline->op1_type == IS_CONST) { - zval *zv = RT_CONSTANT(opline, opline->op1); - - | ZVAL_COPY_CONST arg_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0 - if (Z_REFCOUNTED_P(zv)) { - | ADDREF_CONST zv, REG0, TMP1 - } - } else { - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - - return 1; -} - -static int zend_jit_check_undef_args(dasm_State **Dst, const zend_op *opline) -{ - | ldr FCARG1x, EX->call - | ldrb TMP1w, [FCARG1x, #(offsetof(zend_execute_data, This.u1.type_info) + 3)] - | TST_32_WITH_CONST TMP1w, (ZEND_CALL_MAY_HAVE_UNDEF >> 24), TMP2w - | bne >1 - |.cold_code - |1: - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_handle_undef_args, REG0 - | cbz RETVALw, >2 - | b ->exception_handler - |.code - |2: - - return 1; -} - -static int zend_jit_send_ref(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, int cold) -{ - zend_jit_addr op1_addr, arg_addr, ref_addr; - - op1_addr = OP1_ADDR(); - arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var); - - if (!zend_jit_reuse_ip(Dst)) { - return 0; - } - - if (opline->op1_type == IS_VAR) { - if (op1_info & MAY_BE_INDIRECT) { - | LOAD_ZVAL_ADDR REG0, op1_addr - | // if (EXPECTED(Z_TYPE_P(ret) == IS_INDIRECT)) { - | IF_NOT_Z_TYPE REG0, IS_INDIRECT, >1, TMP1w - | // ret = Z_INDIRECT_P(ret); - | GET_Z_PTR REG0, REG0 - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - } - } else if (opline->op1_type == IS_CV) { - if (op1_info & MAY_BE_UNDEF) { - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2 - | b >2 - |1: - } - op1_info &= ~MAY_BE_UNDEF; - op1_info |= MAY_BE_NULL; - } - } else { - ZEND_UNREACHABLE(); - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) { - if (op1_info & MAY_BE_REF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >2, ZREG_TMP1 - | GET_ZVAL_PTR REG1, op1_addr, TMP1 - | GC_ADDREF REG1, TMP1w - | SET_ZVAL_PTR arg_addr, REG1, TMP1 - | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX, TMP1w, TMP2 - | b >6 - } - |2: - | // ZVAL_NEW_REF(arg, varptr); - if (opline->op1_type == IS_VAR) { - if (Z_REG(op1_addr) != ZREG_REG0 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR REG0, op1_addr - } - | str REG0, T1 // save - } - | EMALLOC sizeof(zend_reference), op_array, opline // Allocate space in REG0 - | mov TMP1w, #2 - | str TMP1w, [REG0] - || ZEND_ASSERT(GC_REFERENCE <= MOVZ_IMM); - | movz TMP1w, #GC_REFERENCE - | str TMP1w, [REG0, #offsetof(zend_reference, gc.u.type_info)] - | str xzr, [REG0, #offsetof(zend_reference, sources.ptr)] - ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, offsetof(zend_reference, val)); - if (opline->op1_type == IS_VAR) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG1, 0); - - | ldr REG1, T1 // restore - | ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_REG2, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | SET_ZVAL_PTR val_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO val_addr, IS_REFERENCE_EX, TMP1w, TMP2 - } else { - | ZVAL_COPY_VALUE ref_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | SET_ZVAL_PTR op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2 - } - | SET_ZVAL_PTR arg_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO arg_addr, IS_REFERENCE_EX, TMP1w, TMP2 - } - - |6: - | FREE_OP opline->op1_type, opline->op1, op1_info, !cold, opline, ZREG_TMP1, ZREG_TMP2 - |7: - - return 1; -} - -static int zend_jit_send_var(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr op1_def_addr) -{ - uint32_t arg_num = opline->op2.num; - zend_jit_addr arg_addr; - - ZEND_ASSERT((opline->opcode != ZEND_SEND_VAR_EX && - opline->opcode != ZEND_SEND_VAR_NO_REF_EX) || - arg_num <= MAX_ARG_FLAG_NUM); - - arg_addr = ZEND_ADDR_MEM_ZVAL(ZREG_RX, opline->result.var); - - if (!zend_jit_reuse_ip(Dst)) { - return 0; - } - - if (opline->opcode == ZEND_SEND_VAR_EX) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && JIT_G(current_frame)->call->func) { - if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) { - return 0; - } - return 1; - } - } else { - uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2); - - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne >1 - |.cold_code - |1: - if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) { - return 0; - } - | b >7 - |.code - } - } else if (opline->opcode == ZEND_SEND_VAR_NO_REF_EX) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && JIT_G(current_frame)->call->func) { - if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - - if (!ARG_MAY_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - if (!(op1_info & MAY_BE_REF)) { - /* Don't generate code that always throws exception */ - return 0; - } else { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | GET_LOW_8BITS TMP1w, REG1w - | cmp TMP1w, #IS_REFERENCE - | bne &exit_addr - } - } - return 1; - } - } else { - uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2); - - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne >1 - |.cold_code - |1: - - mask = ZEND_SEND_PREFER_REF << ((arg_num + 3) * 2); - - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - if (op1_info & MAY_BE_REF) { - | GET_LOW_8BITS TMP1w, REG1w - | cmp TMP1w, #IS_REFERENCE - | beq >7 - } - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne >7 - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | b &exit_addr - } else { - | SET_EX_OPLINE opline, REG0 - | LOAD_ZVAL_ADDR FCARG1x, arg_addr - | EXT_CALL zend_jit_only_vars_by_reference, REG0 - if (!zend_jit_check_exception(Dst)) { - return 0; - } - | b >7 - } - - |.code - } - } else if (opline->opcode == ZEND_SEND_FUNC_ARG) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && JIT_G(current_frame)->call->func) { - if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 0)) { - return 0; - } - return 1; - } - } else { - | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | TST_32_WITH_CONST TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w - | bne >1 - |.cold_code - |1: - if (!zend_jit_send_ref(Dst, opline, op_array, op1_info, 1)) { - return 0; - } - | b >7 - |.code - } - } - - if (op1_info & MAY_BE_UNDEF) { - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - |.cold_code - |1: - } - - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - | SET_ZVAL_TYPE_INFO arg_addr, IS_NULL, TMP1w, TMP2 - | cbz RETVALx, ->exception_handler - - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - | b >7 - |.code - } else { - |7: - return 1; - } - } - - if (opline->opcode == ZEND_SEND_VAR_NO_REF) { - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - if (op1_info & MAY_BE_REF) { - | GET_LOW_8BITS TMP1w, REG1w - | cmp TMP1w, #IS_REFERENCE - | beq >7 - } - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | b &exit_addr - } else { - | SET_EX_OPLINE opline, REG0 - | LOAD_ZVAL_ADDR FCARG1x, arg_addr - | EXT_CALL zend_jit_only_vars_by_reference, REG0 - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - } else { - if (op1_info & MAY_BE_REF) { - if (opline->op1_type == IS_CV) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, val_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF op1_info, REG0w, REG2, TMP1w - } else { - zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 8); - - | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1 - |.cold_code - |1: - | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | // ZVAL_COPY_VALUE(return_value, &ref->value); - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | GC_DELREF FCARG1x, TMP1w - | beq >1 - | IF_NOT_REFCOUNTED REG0w, >2, TMP1w - | GC_ADDREF REG2, TMP1w - | b >2 - |1: - | EFREE_REFERENCE - | b >2 - |.code - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - |2: - } - } else { - if (op1_addr != op1_def_addr) { - if (!zend_jit_update_regs(Dst, opline->op1.var, op1_addr, op1_def_addr, op1_info)) { - return 0; - } - if (Z_MODE(op1_def_addr) == IS_REG && Z_MODE(op1_addr) != IS_REG) { - op1_addr= op1_def_addr; - } - } - | ZVAL_COPY_VALUE arg_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - if (opline->op1_type == IS_CV) { - | TRY_ADDREF op1_info, REG0w, REG2, TMP1w - } - } - } - |7: - - return 1; -} - -static int zend_jit_check_func_arg(dasm_State **Dst, const zend_op *opline) -{ - uint32_t arg_num = opline->op2.num; - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->call - && JIT_G(current_frame)->call->func) { - if (ARG_SHOULD_BE_SENT_BY_REF(JIT_G(current_frame)->call->func, arg_num)) { - if (!TRACE_FRAME_IS_LAST_SEND_BY_REF(JIT_G(current_frame)->call)) { - TRACE_FRAME_SET_LAST_SEND_BY_REF(JIT_G(current_frame)->call); - | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); - || if (reuse_ip) { - | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w - | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - || } else { - | ldr REG0, EX->call - | ldr TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w - | str TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)] - || } - } - } else { - if (!TRACE_FRAME_IS_LAST_SEND_BY_VAL(JIT_G(current_frame)->call)) { - TRACE_FRAME_SET_LAST_SEND_BY_VAL(JIT_G(current_frame)->call); - | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); - || if (reuse_ip) { - | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~ZEND_CALL_SEND_ARG_BY_REF), TMP2w - | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - || } else { - | ldr REG0, EX->call - | ldr TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~ZEND_CALL_SEND_ARG_BY_REF), TMP2w - | str TMP1w, [REG0, #offsetof(zend_execute_data, This.u1.type_info)] - || } - } - } - } else { - // if (QUICK_ARG_SHOULD_BE_SENT_BY_REF(EX(call)->func, arg_num)) { - uint32_t mask = (ZEND_SEND_BY_REF|ZEND_SEND_PREFER_REF) << ((arg_num + 3) * 2); - - if (!zend_jit_reuse_ip(Dst)) { - return 0; - } - - | ldr REG0, EX:RX->func - | ldr TMP1w, [REG0, #offsetof(zend_function, quick_arg_flags)] - | TST_32_WITH_CONST TMP1w, mask, TMP2w - | bne >1 - |.cold_code - |1: - | // ZEND_ADD_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); - | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST orr, TMP1w, TMP1w, ZEND_CALL_SEND_ARG_BY_REF, TMP2w - | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | b >1 - |.code - | // ZEND_DEL_CALL_FLAG(EX(call), ZEND_CALL_SEND_ARG_BY_REF); - | ldr TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - | BW_OP_32_WITH_CONST and, TMP1w, TMP1w, (~(ZEND_CALL_SEND_ARG_BY_REF)), TMP2w - | str TMP1w, [RX, #offsetof(zend_execute_data, This.u1.type_info)] - |1: - } - - return 1; -} - -static int zend_jit_smart_true(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2) -{ - if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - if (jmp) { - | b >7 - } - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | b =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - if (jmp) { - | b >7 - } - } - - return 1; -} - -static int zend_jit_smart_false(dasm_State **Dst, const zend_op *opline, int jmp, uint8_t smart_branch_opcode, uint32_t target_label) -{ - if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - if (jmp) { - | b >7 - } - } else { - ZEND_UNREACHABLE(); - } - } else { - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - if (jmp) { - | b >7 - } - } - - return 1; -} - -static int zend_jit_defined(dasm_State **Dst, const zend_op *opline, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - uint32_t defined_label = (uint32_t)-1; - uint32_t undefined_label = (uint32_t)-1; - zval *zv = RT_CONSTANT(opline, opline->op1); - zend_jit_addr res_addr = 0; - - if (smart_branch_opcode && !exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - undefined_label = target_label; - } else if (smart_branch_opcode == ZEND_JMPNZ) { - defined_label = target_label; - } else { - ZEND_UNREACHABLE(); - } - } - - | // if (CACHED_PTR(opline->extended_value)) { - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, opline->extended_value, TMP1 - | cbz REG0, >1 - | TST_64_WITH_ONE REG0 - | bne >4 - |.cold_code - |4: - | MEM_LOAD_64_ZTS ldr, FCARG1x, executor_globals, zend_constants, FCARG1x - | ldr TMP1w, [FCARG1x, #offsetof(HashTable, nNumOfElements)] - | cmp TMP1, REG0, lsr #1 - - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | beq &exit_addr - } else { - | beq >3 - } - } else if (undefined_label != (uint32_t)-1) { - | beq =>undefined_label - } else { - | beq >3 - } - } else { - | beq >2 - } - |1: - | SET_EX_OPLINE opline, REG0 - | LOAD_ADDR FCARG1x, zv - | EXT_CALL zend_jit_check_constant, REG0 - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | cbz RETVALx, >3 - } else { - | cbnz RETVALx, >3 - } - | b &exit_addr - } else if (smart_branch_opcode) { - if (undefined_label != (uint32_t)-1) { - | cbz RETVALx, =>undefined_label - } else { - | cbz RETVALx, >3 - } - if (defined_label != (uint32_t)-1) { - | b =>defined_label - } else { - | b >3 - } - } else { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - | cbnz RETVALx, >1 - |2: - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - | b >3 - } - |.code - if (smart_branch_opcode) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } - } else if (defined_label != (uint32_t)-1) { - | b =>defined_label - } - } else { - |1: - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - |3: - - return 1; -} - -static int zend_jit_type_check(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - uint32_t mask; - zend_jit_addr op1_addr = OP1_ADDR(); - - // TODO: support for is_resource() ??? - ZEND_ASSERT(opline->extended_value != MAY_BE_RESOURCE); - - if (op1_info & MAY_BE_UNDEF) { - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - | IF_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - |.cold_code - |1: - } - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - zend_jit_check_exception_undef_result(Dst, opline); - if (opline->extended_value & MAY_BE_NULL) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) { - | b >7 - } - } else if (!zend_jit_smart_true(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label, target_label2)) { - return 0; - } - } else { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0) { - | b >7 - } - } else if (!zend_jit_smart_false(Dst, opline, (op1_info & (MAY_BE_ANY|MAY_BE_REF)) != 0, smart_branch_opcode, target_label)) { - return 0; - } - } - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - |.code - } - } - - if (op1_info & (MAY_BE_ANY|MAY_BE_REF)) { - mask = opline->extended_value; - if (!(op1_info & MAY_BE_GUARD) && !(op1_info & (MAY_BE_ANY - mask))) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } - } else if (!zend_jit_smart_true(Dst, opline, 0, smart_branch_opcode, target_label, target_label2)) { - return 0; - } - } else if (!(op1_info & MAY_BE_GUARD) && !(op1_info & mask)) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (!zend_jit_smart_false(Dst, opline, 0, smart_branch_opcode, target_label)) { - return 0; - } - } else { - bool invert = 0; - uint8_t type; - - switch (mask) { - case MAY_BE_NULL: type = IS_NULL; break; - case MAY_BE_FALSE: type = IS_FALSE; break; - case MAY_BE_TRUE: type = IS_TRUE; break; - case MAY_BE_LONG: type = IS_LONG; break; - case MAY_BE_DOUBLE: type = IS_DOUBLE; break; - case MAY_BE_STRING: type = IS_STRING; break; - case MAY_BE_ARRAY: type = IS_ARRAY; break; - case MAY_BE_OBJECT: type = IS_OBJECT; break; - case MAY_BE_ANY - MAY_BE_NULL: type = IS_NULL; invert = 1; break; - case MAY_BE_ANY - MAY_BE_FALSE: type = IS_FALSE; invert = 1; break; - case MAY_BE_ANY - MAY_BE_TRUE: type = IS_TRUE; invert = 1; break; - case MAY_BE_ANY - MAY_BE_LONG: type = IS_LONG; invert = 1; break; - case MAY_BE_ANY - MAY_BE_DOUBLE: type = IS_DOUBLE; invert = 1; break; - case MAY_BE_ANY - MAY_BE_STRING: type = IS_STRING; invert = 1; break; - case MAY_BE_ANY - MAY_BE_ARRAY: type = IS_ARRAY; invert = 1; break; - case MAY_BE_ANY - MAY_BE_OBJECT: type = IS_OBJECT; invert = 1; break; - case MAY_BE_ANY - MAY_BE_RESOURCE: type = IS_OBJECT; invert = 1; break; - default: - type = 0; - } - - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR REG0, op1_addr - | ZVAL_DEREF REG0, op1_info, TMP1w - } - if (type == 0) { - if (smart_branch_opcode && - (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | // if (Z_REFCOUNTED_P(cv)) { - | IF_ZVAL_REFCOUNTED op1_addr, >1, ZREG_TMP1, ZREG_TMP2 - |.cold_code - |1: - } - | // if (!Z_DELREF_P(cv)) { - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - if (RC_MAY_BE_1(op1_info)) { - if (RC_MAY_BE_N(op1_info)) { - | bne >3 - } - if (op1_info & MAY_BE_REF) { - | ldrb REG0w, [REG0, #offsetof(zval,u1.v.type)] - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG0w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - } - | str REG0w, T1 // save - | // zval_dtor_func(r); - | ZVAL_DTOR_FUNC op1_info, opline, TMP1 - | ldr REG1w, T1 // restore - | b >2 - } - if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (!RC_MAY_BE_1(op1_info)) { - | b >3 - } - |.code - } - |3: - if (op1_info & MAY_BE_REF) { - | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)] - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - } - |2: - } else { - if (op1_info & MAY_BE_REF) { - | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)] - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - } - } - | mov REG0w, #1 - | lsl REG0w, REG0w, REG1w - | TST_32_WITH_CONST REG0w, mask, TMP1w - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | bne &exit_addr - } else { - | beq &exit_addr - } - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | beq =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | bne =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - | cset REG0w, ne - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - } else { - if (smart_branch_opcode && - (opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | // if (Z_REFCOUNTED_P(cv)) { - | IF_ZVAL_REFCOUNTED op1_addr, >1, ZREG_TMP1, ZREG_TMP2 - |.cold_code - |1: - } - | // if (!Z_DELREF_P(cv)) { - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - if (RC_MAY_BE_1(op1_info)) { - if (RC_MAY_BE_N(op1_info)) { - | bne >3 - } - if (op1_info & MAY_BE_REF) { - | ldrb REG0w, [REG0, #offsetof(zval,u1.v.type)] - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG0w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - } - | str REG0w, T1 // save - | // zval_dtor_func(r); - | ZVAL_DTOR_FUNC op1_info, opline, TMP1 - | ldr REG1w, T1 // restore - | b >2 - } - if ((op1_info) & (MAY_BE_ANY-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (!RC_MAY_BE_1(op1_info)) { - | b >3 - } - |.code - } - |3: - if (op1_info & MAY_BE_REF) { - | ldrb REG1w, [REG0, #offsetof(zval,u1.v.type)] - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - } - |2: - // Note: 'type' is of uchar type and holds a positive value, - // hence it's safe to directly encode it as the imm field of 'cmp' instruction. - | cmp REG1w, #type - } else { - if (op1_info & MAY_BE_REF) { - | ldrb TMP1w, [REG0, #offsetof(zval,u1.v.type)] - | cmp TMP1w, #type - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, FP, (opline->op1.var + offsetof(zval,u1.v.type)), TMP1 - | cmp TMP1w, #type - } - } - if (exit_addr) { - if (invert) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | bne &exit_addr - } else { - | beq &exit_addr - } - } else { - if (smart_branch_opcode == ZEND_JMPNZ) { - | beq &exit_addr - } else { - | bne &exit_addr - } - } - } else if (smart_branch_opcode) { - if (invert) { - if (smart_branch_opcode == ZEND_JMPZ) { - | beq =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | bne =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - if (smart_branch_opcode == ZEND_JMPZ) { - | bne =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | beq =>target_label - } else { - ZEND_UNREACHABLE(); - } - } - } else { - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - if (invert) { - | cset REG0w, ne - } else { - | cset REG0w, eq - } - | add REG0w, REG0w, #2 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - } - } - } - - |7: - - return 1; -} - -static int zend_jit_leave_frame(dasm_State **Dst) -{ - | // EG(current_execute_data) = EX(prev_execute_data); - | ldr REG0, EX->prev_execute_data - | MEM_STORE_64_ZTS str, REG0, executor_globals, current_execute_data, REG2 - return 1; -} - -static int zend_jit_free_cvs(dasm_State **Dst) -{ - | // EG(current_execute_data) = EX(prev_execute_data); - | ldr FCARG1x, EX->prev_execute_data - | MEM_STORE_64_ZTS str, FCARG1x, executor_globals, current_execute_data, REG0 - | // zend_free_compiled_variables(execute_data); - | mov FCARG1x, FP - | EXT_CALL zend_free_compiled_variables, REG0 - return 1; -} - -static int zend_jit_free_cv(dasm_State **Dst, uint32_t info, uint32_t var) -{ - if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - uint32_t offset = EX_NUM_TO_VAR(var); - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offset); - | ZVAL_PTR_DTOR addr, info, 1, 1, NULL, ZREG_TMP1, ZREG_TMP2 - } - return 1; -} - -static int zend_jit_free_op(dasm_State **Dst, const zend_op *opline, uint32_t info, uint32_t var_offset) -{ - if (info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - zend_jit_addr addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var_offset); - | ZVAL_PTR_DTOR addr, info, 0, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - return 1; -} - -static int zend_jit_leave_func(dasm_State **Dst, - const zend_op_array *op_array, - const zend_op *opline, - uint32_t op1_info, - bool left_frame, - zend_jit_trace_rec *trace, - zend_jit_trace_info *trace_info, - int indirect_var_access, - int may_throw) -{ - bool may_be_top_frame = - JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - !JIT_G(current_frame) || - !TRACE_FRAME_IS_NESTED(JIT_G(current_frame)); - bool may_need_call_helper = - indirect_var_access || /* may have symbol table */ - !op_array->function_name || /* may have symbol table */ - may_be_top_frame || - (op_array->fn_flags & ZEND_ACC_VARIADIC) || /* may have extra named args */ - JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - !JIT_G(current_frame) || - TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) == -1 || /* unknown number of args */ - (uint32_t)TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) > op_array->num_args; /* extra args */ - bool may_need_release_this = - !(op_array->fn_flags & ZEND_ACC_CLOSURE) && - op_array->scope && - !(op_array->fn_flags & ZEND_ACC_STATIC) && - (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - !JIT_G(current_frame) || - !TRACE_FRAME_NO_NEED_RELEASE_THIS(JIT_G(current_frame))); - - if (may_need_call_helper || may_need_release_this) { - | ldr FCARG1w, [FP, #offsetof(zend_execute_data, This.u1.type_info)] - } - if (may_need_call_helper) { - if (!left_frame) { - left_frame = 1; - if (!zend_jit_leave_frame(Dst)) { - return 0; - } - } - /* ZEND_CALL_FAKE_CLOSURE handled on slow path to eliminate check for ZEND_CALL_CLOSURE on fast path */ - - | TST_32_WITH_CONST FCARG1w, (ZEND_CALL_TOP|ZEND_CALL_HAS_SYMBOL_TABLE|ZEND_CALL_FREE_EXTRA_ARGS|ZEND_CALL_ALLOCATED|ZEND_CALL_HAS_EXTRA_NAMED_PARAMS|ZEND_CALL_FAKE_CLOSURE), TMP1w - if (trace && trace->op != ZEND_JIT_TRACE_END) { - | bne >1 - |.cold_code - |1: - if (!GCC_GLOBAL_REGS) { - | mov FCARG1x, FP - } - | EXT_CALL zend_jit_leave_func_helper, REG0 - - if (may_be_top_frame) { - // TODO: try to avoid this check ??? - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { -#if 0 - /* this check should be handled by the following OPLINE guard */ - | LOAD_ADDR TMP1, zend_jit_halt_op - | cmp IP, TMP1 - | beq ->trace_halt -#endif - } else if (GCC_GLOBAL_REGS) { - | cbz IP, ->trace_halt - } else { - | tst RETVALw, RETVALw - | blt ->trace_halt - } - } - - if (!GCC_GLOBAL_REGS) { - | // execute_data = EG(current_execute_data) - | MEM_LOAD_64_ZTS ldr, FP, executor_globals, current_execute_data, TMP1 - } - | b >8 - |.code - } else { - | bne ->leave_function_handler - } - } - - if (op_array->fn_flags & ZEND_ACC_CLOSURE) { - if (!left_frame) { - left_frame = 1; - if (!zend_jit_leave_frame(Dst)) { - return 0; - } - } - | // OBJ_RELEASE(ZEND_CLOSURE_OBJECT(EX(func))); - | ldr FCARG1x, EX->func - | sub FCARG1x, FCARG1x, #sizeof(zend_object) - | OBJ_RELEASE ZREG_FCARG1, >4, ZREG_TMP1, ZREG_TMP2 - |4: - } else if (may_need_release_this) { - if (!left_frame) { - left_frame = 1; - if (!zend_jit_leave_frame(Dst)) { - return 0; - } - } - if (!JIT_G(current_frame) || !TRACE_FRAME_ALWAYS_RELEASE_THIS(JIT_G(current_frame))) { - | // if (call_info & ZEND_CALL_RELEASE_THIS) - | TST_32_WITH_CONST FCARG1w, ZEND_CALL_RELEASE_THIS, TMP1w - | beq >4 - } - | // zend_object *object = Z_OBJ(execute_data->This); - | ldr FCARG1x, EX->This.value.obj - | // OBJ_RELEASE(object); - | OBJ_RELEASE ZREG_FCARG1, >4, ZREG_TMP1, ZREG_TMP2 - |4: - // TODO: avoid EG(excption) check for $this->foo() calls - may_throw = 1; - } - - | // EG(vm_stack_top) = (zval*)execute_data; - | MEM_STORE_64_ZTS str, FP, executor_globals, vm_stack_top, REG0 - | // execute_data = EX(prev_execute_data); - | ldr FP, EX->prev_execute_data - - if (!left_frame) { - | // EG(current_execute_data) = execute_data; - | MEM_STORE_64_ZTS str, FP, executor_globals, current_execute_data, REG0 - } - - |9: - if (trace) { - if (trace->op != ZEND_JIT_TRACE_END - && (JIT_G(current_frame) && !TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) { - zend_jit_reset_last_valid_opline(); - } else { - | LOAD_IP - | ADD_IP_WITH_CONST sizeof(zend_op), TMP1 - } - - |8: - - if (trace->op == ZEND_JIT_TRACE_BACK - && (!JIT_G(current_frame) || TRACE_FRAME_IS_UNKNOWN_RETURN(JIT_G(current_frame)))) { - const zend_op *next_opline = trace->opline; - - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && (op1_info & MAY_BE_RC1) - && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) { - /* exception might be thrown during destruction of unused return value */ - | // if (EG(exception)) - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbnz REG0, ->leave_throw_handler - } - do { - trace++; - } while (trace->op == ZEND_JIT_TRACE_INIT_CALL); - ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END); - next_opline = trace->opline; - ZEND_ASSERT(next_opline != NULL); - - if (trace->op == ZEND_JIT_TRACE_END - && trace->stop == ZEND_JIT_TRACE_STOP_RECURSIVE_RET) { - trace_info->flags |= ZEND_JIT_TRACE_LOOP; - | CMP_IP next_opline, TMP1, TMP2 - | beq =>0 // LOOP -#ifdef ZEND_VM_HYBRID_JIT_RED_ZONE_SIZE - | JMP_IP TMP1 -#else - | b ->trace_escape -#endif - } else { - | CMP_IP next_opline, TMP1, TMP2 - | bne ->trace_escape - } - - zend_jit_set_last_valid_opline(trace->opline); - - return 1; - } else if (may_throw || - (((opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && (op1_info & MAY_BE_RC1) - && (op1_info & (MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_ARRAY_OF_OBJECT|MAY_BE_ARRAY_OF_RESOURCE|MAY_BE_ARRAY_OF_ARRAY))) - && (!JIT_G(current_frame) || TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))))) { - | // if (EG(exception)) - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | cbnz REG0, ->leave_throw_handler - } - - return 1; - } else { - | // if (EG(exception)) - | MEM_LOAD_64_ZTS ldr, REG0, executor_globals, exception, TMP1 - | LOAD_IP - | cbnz REG0, ->leave_throw_handler - | // opline = EX(opline) + 1 - | ADD_IP_WITH_CONST sizeof(zend_op), TMP1 - } - - if (zend_jit_vm_kind == ZEND_VM_KIND_HYBRID) { - | ADD_HYBRID_SPAD -#ifdef CONTEXT_THREADED_JIT - | NIY // TODO: CONTEXT_THREADED_JIT is always undefined -#else - | JMP_IP TMP1 -#endif - } else if (GCC_GLOBAL_REGS) { - | ldp x29, x30, [sp], # SPAD // stack alignment -#ifdef CONTEXT_THREADED_JIT - | NIY // TODO -#else - | JMP_IP TMP1 -#endif - } else { -#ifdef CONTEXT_THREADED_JIT - ZEND_UNREACHABLE(); - // TODO: context threading can't work without GLOBAL REGS because we have to change - // the value of execute_data in execute_ex() - | NIY // TODO -#else - | ldp FP, RX, T2 // restore FP and IP - | ldp x29, x30, [sp], # NR_SPAD // stack alignment - | mov RETVALx, #2 // ZEND_VM_LEAVE ???? - | ret -#endif - } - - return 1; -} - -static int zend_jit_return(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info, zend_jit_addr op1_addr) -{ - zend_jit_addr ret_addr; - int8_t return_value_used; - - ZEND_ASSERT(op_array->type != ZEND_EVAL_CODE && op_array->function_name); - ZEND_ASSERT(!(op1_info & MAY_BE_UNDEF)); - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && JIT_G(current_frame)) { - if (TRACE_FRAME_IS_RETURN_VALUE_USED(JIT_G(current_frame))) { - return_value_used = 1; - } else if (TRACE_FRAME_IS_RETURN_VALUE_UNUSED(JIT_G(current_frame))) { - return_value_used = 0; - } else { - return_value_used = -1; - } - } else { - return_value_used = -1; - } - - if (ZEND_OBSERVER_ENABLED) { - if (Z_MODE(op1_addr) == IS_REG) { - zend_jit_addr dst = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - - if (!zend_jit_spill_store(Dst, op1_addr, dst, op1_info, 1)) { - return 0; - } - op1_addr = dst; - } - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - | mov FCARG1x, FP - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_observer_fcall_end, REG0 - } - - // if (!EX(return_value)) - if (Z_MODE(op1_addr) == IS_REG && Z_REG(op1_addr) == ZREG_REG1) { - if (return_value_used != 0) { - | ldr REG2, EX->return_value - } - ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG2, 0); - } else { - if (return_value_used != 0) { - | ldr REG1, EX->return_value - } - ret_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG1, 0); - } - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (return_value_used == -1) { - | cbz Rx(Z_REG(ret_addr)), >1 - |.cold_code - |1: - } - if (return_value_used != 1) { - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)-(MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (jit_return_label >= 0) { - | IF_NOT_ZVAL_REFCOUNTED op1_addr, =>jit_return_label, ZREG_TMP1, ZREG_TMP2 - } else { - | IF_NOT_ZVAL_REFCOUNTED op1_addr, >9, ZREG_TMP1, ZREG_TMP2 - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - if (RC_MAY_BE_1(op1_info)) { - if (RC_MAY_BE_N(op1_info)) { - if (jit_return_label >= 0) { - | bne =>jit_return_label - } else { - | bne >9 - } - } - | //SAVE_OPLINE() - | ZVAL_DTOR_FUNC op1_info, opline, TMP1 - | //????ldr REG1, EX->return_value // reload ??? - } - if (return_value_used == -1) { - if (jit_return_label >= 0) { - | b =>jit_return_label - } else { - | b >9 - } - |.code - } - } - } else if (return_value_used == -1) { - if (jit_return_label >= 0) { - | cbz Rx(Z_REG(ret_addr)), =>jit_return_label - } else { - | cbz Rx(Z_REG(ret_addr)), >9 - } - } - - if (return_value_used == 0) { - |9: - return 1; - } - - if (opline->op1_type == IS_CONST) { - zval *zv = RT_CONSTANT(opline, opline->op1); - | ZVAL_COPY_CONST ret_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0 - if (Z_REFCOUNTED_P(zv)) { - | ADDREF_CONST zv, REG0, TMP1 - } - } else if (opline->op1_type == IS_TMP_VAR) { - | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } else if (opline->op1_type == IS_CV) { - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR REG0, op1_addr - | ZVAL_DEREF REG0, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - } - | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - (op1_info & (MAY_BE_REF|MAY_BE_OBJECT)) || - !op_array->function_name) { - | TRY_ADDREF op1_info, REG0w, REG2, TMP1w - } else if (return_value_used != 1) { - | // if (EXPECTED(!(EX_CALL_INFO() & ZEND_CALL_CODE))) ZVAL_NULL(retval_ptr); - | SET_ZVAL_TYPE_INFO op1_addr, IS_NULL, TMP1w, TMP2 - } - } - } else { - if (op1_info & MAY_BE_REF) { - zend_jit_addr ref_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, offsetof(zend_reference, val)); - - | IF_ZVAL_TYPE op1_addr, IS_REFERENCE, >1, ZREG_TMP1 - |.cold_code - |1: - | // zend_refcounted *ref = Z_COUNTED_P(retval_ptr); - | GET_ZVAL_PTR REG0, op1_addr, TMP1 - | // ZVAL_COPY_VALUE(return_value, &ref->value); - | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, ref_addr, op1_info, ZREG_REG2, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | GC_DELREF REG0, TMP1w - | beq >2 - | // if (IS_REFCOUNTED()) - if (jit_return_label >= 0) { - | IF_NOT_REFCOUNTED REG2w, =>jit_return_label, TMP1w - } else { - | IF_NOT_REFCOUNTED REG2w, >9, TMP1w - } - | // ADDREF - | GET_ZVAL_PTR REG2, ret_addr, TMP1 // reload - | GC_ADDREF REG2, TMP1w - if (jit_return_label >= 0) { - | b =>jit_return_label - } else { - | b >9 - } - |2: - | mov FCARG1x, REG0 - | EFREE_REFERENCE - if (jit_return_label >= 0) { - | b =>jit_return_label - } else { - | b >9 - } - |.code - } - | ZVAL_COPY_VALUE ret_addr, MAY_BE_ANY, op1_addr, op1_info, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - - |9: - return 1; -} - -static int zend_jit_zval_copy_deref(dasm_State **Dst, zend_jit_addr res_addr, zend_jit_addr val_addr, zend_reg type_reg) -{ - ZEND_ASSERT(type_reg == ZREG_REG2); - - | GET_ZVAL_PTR REG1, val_addr, TMP1 - | IF_NOT_REFCOUNTED REG2w, >2, TMP1w - | GET_LOW_8BITS TMP2w, REG2w - | IF_NOT_TYPE TMP2w, IS_REFERENCE, >1 - | add REG1, REG1, #offsetof(zend_reference, val) - | GET_Z_TYPE_INFO REG2w, REG1 - | GET_Z_PTR REG1, REG1 - | IF_NOT_REFCOUNTED REG2w, >2, TMP1w - |1: - | GC_ADDREF REG1, TMP2w - |2: - | SET_ZVAL_PTR res_addr, REG1, TMP1 - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1 - - return 1; -} - -static int zend_jit_fetch_dim_read(dasm_State **Dst, - const zend_op *opline, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - uint32_t op1_info, - zend_jit_addr op1_addr, - bool op1_avoid_refcounting, - uint32_t op2_info, - uint32_t res_info, - zend_jit_addr res_addr, - uint8_t dim_type) -{ - zend_jit_addr orig_op1_addr, op2_addr; - const void *exit_addr = NULL; - const void *not_found_exit_addr = NULL; - const void *res_exit_addr = NULL; - bool result_avoid_refcounting = 0; - uint32_t may_be_string = (opline->opcode != ZEND_FETCH_LIST_R) ? MAY_BE_STRING : 0; - int may_throw = 0; - - orig_op1_addr = OP1_ADDR(); - op2_addr = OP2_ADDR(); - - if (opline->opcode != ZEND_FETCH_DIM_IS - && JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - } - - if ((res_info & MAY_BE_GUARD) - && JIT_G(current_frame) - && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) { - uint32_t flags = 0; - uint32_t old_op1_info = 0; - uint32_t old_info; - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - int32_t exit_point; - - if (opline->opcode != ZEND_FETCH_LIST_R - && (opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && !op1_avoid_refcounting) { - flags |= ZEND_JIT_EXIT_FREE_OP1; - } - if ((opline->op2_type & (IS_VAR|IS_TMP_VAR)) - && (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - flags |= ZEND_JIT_EXIT_FREE_OP2; - } - if ((opline->result_type & (IS_VAR|IS_TMP_VAR)) - && !(flags & ZEND_JIT_EXIT_FREE_OP1) - && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) - && (ssa_op+1)->op1_use == ssa_op->result_def - && !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG))) - && zend_jit_may_avoid_refcounting(opline+1, res_info)) { - result_avoid_refcounting = 1; - ssa->var_info[ssa_op->result_def].avoid_refcounting = 1; - } - - if (op1_avoid_refcounting) { - old_op1_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var)); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE); - } - - if (!(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF) - (MAY_BE_STRING|MAY_BE_LONG)))) { - old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0); - exit_point = zend_jit_trace_get_exit_point(opline+1, flags); - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); - res_exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!res_exit_addr) { - return 0; - } - res_info &= ~MAY_BE_GUARD; - ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; - } - - if (opline->opcode == ZEND_FETCH_DIM_IS - && !(res_info & MAY_BE_NULL)) { - old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_NULL, 0); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_NULL); - exit_point = zend_jit_trace_get_exit_point(opline+1, flags); - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); - not_found_exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!not_found_exit_addr) { - return 0; - } - } - - if (op1_avoid_refcounting) { - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->op1.var), old_op1_info); - } - } - - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & MAY_BE_ARRAY) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) { - if (exit_addr && !(op1_info & (MAY_BE_OBJECT|may_be_string))) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - } - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - if ((op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) || - (opline->opcode != ZEND_FETCH_DIM_IS && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE)) { - may_throw = 1; - } - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, (opline->opcode != ZEND_FETCH_DIM_IS) ? BP_VAR_R : BP_VAR_IS, op1_info, op2_info, dim_type, res_exit_addr, not_found_exit_addr, exit_addr)) { - return 0; - } - } - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) { - if (op1_info & MAY_BE_ARRAY) { - |.cold_code - |7: - } - - if (opline->opcode != ZEND_FETCH_LIST_R && (op1_info & MAY_BE_STRING)) { - may_throw = 1; - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING))) { - if (exit_addr && !(op1_info & MAY_BE_OBJECT)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1 - } - } - | SET_EX_OPLINE opline, REG0 - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - if (opline->opcode != ZEND_FETCH_DIM_IS) { - if ((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_GUARD)) == MAY_BE_LONG) { - | GET_ZVAL_LVAL ZREG_FCARG2, op2_addr, TMP1 - | EXT_CALL zend_jit_fetch_dim_str_offset_r_helper, REG0 - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | EXT_CALL zend_jit_fetch_dim_str_r_helper, REG0 - } - | SET_ZVAL_PTR res_addr, RETVALx, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_STRING, TMP1w, TMP2 - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - | LOAD_ZVAL_ADDR CARG3, res_addr - | EXT_CALL zend_jit_fetch_dim_str_is_helper, REG0 - } - if ((op1_info & MAY_BE_ARRAY) || - (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_STRING)))) { - | b >9 // END - } - |6: - } - - if (op1_info & MAY_BE_OBJECT) { - may_throw = 1; - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) { - if (exit_addr) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >6, ZREG_TMP1 - } - } - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL); - | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1) - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - | LOAD_ZVAL_ADDR CARG3, res_addr - if (opline->opcode != ZEND_FETCH_DIM_IS) { - | EXT_CALL zend_jit_fetch_dim_obj_r_helper, REG0 - } else { - | EXT_CALL zend_jit_fetch_dim_obj_is_helper, REG0 - } - if ((op1_info & MAY_BE_ARRAY) || - (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) { - | b >9 // END - } - |6: - } - - if ((op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string))) - && (!exit_addr || !(op1_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|may_be_string)))) { - if ((opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) || (op2_info & MAY_BE_UNDEF)) { - | SET_EX_OPLINE opline, REG0 - if (opline->opcode != ZEND_FETCH_DIM_IS && (op1_info & MAY_BE_UNDEF)) { - may_throw = 1; - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - } - - if (op2_info & MAY_BE_UNDEF) { - may_throw = 1; - | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1 - | LOAD_32BIT_VAL FCARG1w, opline->op2.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - } - } - - if (opline->opcode != ZEND_FETCH_DIM_IS && opline->opcode != ZEND_FETCH_LIST_R) { - may_throw = 1; - if ((op1_info & MAY_BE_UNDEF) || (op2_info & MAY_BE_UNDEF)) { - | LOAD_ZVAL_ADDR FCARG1x, orig_op1_addr - } else { - | SET_EX_OPLINE opline, REG0 - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || - Z_REG(op1_addr) != ZREG_FCARG1 || - Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - } - | EXT_CALL zend_jit_invalid_array_access, REG0 - } - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - if (op1_info & MAY_BE_ARRAY) { - | b >9 // END - } - } - - if (op1_info & MAY_BE_ARRAY) { - |.code - } - } - - if (op1_info & MAY_BE_ARRAY) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - - |8: - if (res_exit_addr) { - uint32_t type = concrete_type(res_info); - if ((op1_info & MAY_BE_ARRAY_OF_REF) - && dim_type != IS_UNKNOWN - && dim_type != IS_REFERENCE) { - if (type < IS_STRING) { - | IF_NOT_ZVAL_TYPE val_addr, type, >1, ZREG_TMP1 - |.cold_code - |1: - | IF_NOT_ZVAL_TYPE val_addr, IS_REFERENCE, &res_exit_addr, ZREG_TMP1 - | GET_Z_PTR REG0, REG0 - | add REG0, REG0, #offsetof(zend_reference, val) - | IF_ZVAL_TYPE val_addr, type, >1, ZREG_TMP1 - | b &res_exit_addr - |.code - |1: - } else { - | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1 - | GET_LOW_8BITS TMP1w, REG2w - | IF_NOT_TYPE TMP1w, type, >1 - |.cold_code - |1: - | IF_NOT_TYPE TMP1w, IS_REFERENCE, &res_exit_addr - | GET_Z_PTR REG0, REG0 - | add REG0, REG0, #offsetof(zend_reference, val) - | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1 - | GET_LOW_8BITS TMP1w, REG2w - | IF_TYPE TMP1w, type, >1 - | b &res_exit_addr - |.code - |1: - } - } else { - if (op1_info & MAY_BE_ARRAY_OF_REF) { - | ZVAL_DEREF REG0, MAY_BE_REF, TMP1w - } - if (type < IS_STRING) { - | IF_NOT_ZVAL_TYPE val_addr, type, &res_exit_addr, ZREG_TMP1 - } else { - | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1 - | GET_LOW_8BITS TMP1w, REG2w - | IF_NOT_TYPE TMP1w, type, &res_exit_addr - } - } - | // ZVAL_COPY - |7: - | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0 - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - if (type < IS_STRING) { - if (Z_REG(res_addr) != ZREG_FP || - JIT_G(current_frame) == NULL || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) { - | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2 - } - } else { - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1 - if (!result_avoid_refcounting) { - | TRY_ADDREF res_info, REG2w, REG1, TMP1w - } - } - } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - } else if (op1_info & MAY_BE_ARRAY_OF_REF) { - | // ZVAL_COPY_DEREF - | GET_ZVAL_TYPE_INFO Rw(ZREG_REG2), val_addr, TMP1 - if (!zend_jit_zval_copy_deref(Dst, res_addr, val_addr, ZREG_REG2)) { - return 0; - } - } else { - | // ZVAL_COPY - | ZVAL_COPY_VALUE res_addr, -1, val_addr, res_info, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF res_info, REG1w, REG2, TMP1w - } - } - |9: // END - -#ifdef ZEND_JIT_USE_RC_INFERENCE - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) { - /* Magic offsetGet() may increase refcount of the key */ - op2_info |= MAY_BE_RCN; - } -#endif - - if (opline->op2_type & (IS_TMP_VAR|IS_VAR)) { - if ((op2_info & MAY_HAVE_DTOR) && (op2_info & MAY_BE_RC1)) { - may_throw = 1; - } - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - if (opline->opcode != ZEND_FETCH_LIST_R && !op1_avoid_refcounting) { - if (opline->op1_type & (IS_TMP_VAR|IS_VAR)) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { - may_throw = 1; - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - } - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_fetch_dim(dasm_State **Dst, - const zend_op *opline, - uint32_t op1_info, - zend_jit_addr op1_addr, - uint32_t op2_info, - zend_jit_addr res_addr, - uint8_t dim_type) -{ - zend_jit_addr op2_addr; - int may_throw = 0; - - op2_addr = (opline->op2_type != IS_UNUSED) ? OP2_ADDR() : 0; - - if (opline->opcode == ZEND_FETCH_DIM_RW) { - | SET_EX_OPLINE opline, REG0 - } - if (op1_info & MAY_BE_REF) { - may_throw = 1; - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_REFERENCE, >1, TMP1w - | GET_Z_PTR FCARG2x, FCARG1x - | ldrb TMP1w, [FCARG2x, #(offsetof(zend_reference, val) + offsetof(zval, u1.v.type))] - | cmp TMP1w, #IS_ARRAY - | bne >2 - | add FCARG1x, FCARG2x, #offsetof(zend_reference, val) - | b >3 - |.cold_code - |2: - | SET_EX_OPLINE opline, REG0 - if (opline->opcode != ZEND_FETCH_DIM_RW) { - | EXT_CALL zend_jit_prepare_assign_dim_ref, REG0 - } - | mov FCARG1x, RETVALx - | cbnz FCARG1x, >1 - | b ->exception_handler_undef - |.code - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & MAY_BE_ARRAY) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - |3: - | SEPARATE_ARRAY op1_addr, op1_info, 1, ZREG_TMP1, ZREG_TMP2 - } - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL)) { - if (op1_info & MAY_BE_ARRAY) { - |.cold_code - |7: - } - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - | CMP_ZVAL_TYPE op1_addr, IS_NULL, ZREG_TMP1 - | bgt >7 - } - if (Z_REG(op1_addr) != ZREG_FP) { - | str Rx(Z_REG(op1_addr)), T1 // save - } - if ((op1_info & MAY_BE_UNDEF) - && opline->opcode == ZEND_FETCH_DIM_RW) { - may_throw = 1; - if (op1_info & MAY_BE_NULL) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - } - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - } - | // ZVAL_ARR(container, zend_new_array(8)); - | EXT_CALL _zend_new_array_0, REG0 - | mov REG0, RETVALx - if (Z_REG(op1_addr) != ZREG_FP) { - | ldr Rx(Z_REG(op1_addr)), T1 // restore - } - | SET_ZVAL_LVAL_FROM_REG op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_ARRAY_EX, TMP1w, TMP2 - | mov FCARG1x, REG0 - if (op1_info & MAY_BE_ARRAY) { - | b >1 - |.code - |1: - } - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - |6: - if (opline->op2_type == IS_UNUSED) { - may_throw = 1; - | // var_ptr = zend_hash_next_index_insert(Z_ARRVAL_P(container), &EG(uninitialized_zval)); - | LOAD_ADDR_ZTS FCARG2x, executor_globals, uninitialized_zval - | EXT_CALL zend_hash_next_index_insert, REG0 - | // if (UNEXPECTED(!var_ptr)) { - | cbz RETVALx, >1 - |.cold_code - |1: - | // zend_throw_error(NULL, "Cannot add element to the array as the next element is already occupied"); - | CANNOT_ADD_ELEMENT opline - | SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF, TMP1w, TMP2 - | //ZEND_VM_C_GOTO(assign_dim_op_ret_null); - | b >8 - |.code - | SET_ZVAL_PTR res_addr, RETVALx, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2 - } else { - uint32_t type; - - switch (opline->opcode) { - case ZEND_FETCH_DIM_W: - case ZEND_FETCH_LIST_W: - type = BP_VAR_W; - break; - case ZEND_FETCH_DIM_RW: - may_throw = 1; - type = BP_VAR_RW; - break; - case ZEND_FETCH_DIM_UNSET: - type = BP_VAR_UNSET; - break; - default: - ZEND_UNREACHABLE(); - } - - if (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING))) { - may_throw = 1; - } - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, type, op1_info, op2_info, dim_type, NULL, NULL, NULL)) { - return 0; - } - - |8: - | SET_ZVAL_PTR res_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2 - - if (type == BP_VAR_RW || (op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_STRING)))) { - |.cold_code - |9: - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - | b >8 - |.code - } - } - } - - if (op1_info & (MAY_BE_ANY-(MAY_BE_NULL|MAY_BE_ARRAY))) { - may_throw = 1; - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - |.cold_code - |7: - } - - if (opline->opcode != ZEND_FETCH_DIM_RW) { - | SET_EX_OPLINE opline, REG0 - } - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_UNUSED) { - | mov FCARG2x, xzr - } else if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL); - | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1) - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - | LOAD_ZVAL_ADDR CARG3, res_addr - switch (opline->opcode) { - case ZEND_FETCH_DIM_W: - case ZEND_FETCH_LIST_W: - | EXT_CALL zend_jit_fetch_dim_obj_w_helper, REG0 - break; - case ZEND_FETCH_DIM_RW: - | EXT_CALL zend_jit_fetch_dim_obj_rw_helper, REG0 - break; -// case ZEND_FETCH_DIM_UNSET: -// | EXT_CALL zend_jit_fetch_dim_obj_unset_helper, REG0 -// break; - default: - ZEND_UNREACHABLE(); - } - - if (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_ARRAY)) { - | b >8 // END - |.code - } - } - -#ifdef ZEND_JIT_USE_RC_INFERENCE - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & (MAY_BE_UNDEF|MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_ARRAY|MAY_BE_OBJECT))) { - /* ASSIGN_DIM may increase refcount of the key */ - op2_info |= MAY_BE_RCN; - } -#endif - - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) - && (op2_info & MAY_HAVE_DTOR) - && (op2_info & MAY_BE_RC1)) { - may_throw = 1; - } - |8: - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - return 1; -} - -static int zend_jit_isset_isempty_dim(dasm_State **Dst, - const zend_op *opline, - uint32_t op1_info, - zend_jit_addr op1_addr, - bool op1_avoid_refcounting, - uint32_t op2_info, - uint8_t dim_type, - int may_throw, - uint8_t smart_branch_opcode, - uint32_t target_label, - uint32_t target_label2, - const void *exit_addr) -{ - zend_jit_addr op2_addr, res_addr; - - // TODO: support for empty() ??? - ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY)); - - op2_addr = OP2_ADDR(); - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - - if (op1_info & MAY_BE_ARRAY) { - const void *found_exit_addr = NULL; - const void *not_found_exit_addr = NULL; - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY)) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - | GET_ZVAL_LVAL ZREG_FCARG1, op1_addr, TMP1 - if (exit_addr - && !(op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) - && !may_throw - && (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || op1_avoid_refcounting) - && (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)))) { - if (smart_branch_opcode == ZEND_JMPNZ) { - found_exit_addr = exit_addr; - } else { - not_found_exit_addr = exit_addr; - } - } - if (!zend_jit_fetch_dimension_address_inner(Dst, opline, BP_JIT_IS, op1_info, op2_info, dim_type, found_exit_addr, not_found_exit_addr, NULL)) { - return 0; - } - - if (found_exit_addr) { - |9: - return 1; - } else if (not_found_exit_addr) { - |8: - return 1; - } - } - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_ARRAY)) { - if (op1_info & MAY_BE_ARRAY) { - |.cold_code - |7: - } - - if (op1_info & (MAY_BE_STRING|MAY_BE_OBJECT)) { - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - if (opline->op2_type == IS_CONST && Z_EXTRA_P(RT_CONSTANT(opline, opline->op2)) == ZEND_EXTRA_VALUE) { - ZEND_ASSERT(Z_MODE(op2_addr) == IS_CONST_ZVAL); - | LOAD_ADDR FCARG2x, (Z_ZV(op2_addr) + 1) - } else { - | LOAD_ZVAL_ADDR FCARG2x, op2_addr - } - | EXT_CALL zend_jit_isset_dim_helper, REG0 - | cbz RETVALw, >9 - if (op1_info & MAY_BE_ARRAY) { - | b >8 - |.code - } - } else { - if (op2_info & MAY_BE_UNDEF) { - if (op2_info & MAY_BE_ANY) { - | IF_NOT_ZVAL_TYPE op2_addr, IS_UNDEF, >1, ZREG_TMP1 - } - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op2.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - } - if (op1_info & MAY_BE_ARRAY) { - | b >9 - |.code - } - } - } - -#ifdef ZEND_JIT_USE_RC_INFERENCE - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && (op1_info & MAY_BE_OBJECT)) { - /* Magic offsetExists() may increase refcount of the key */ - op2_info |= MAY_BE_RCN; - } -#endif - - if (op1_info & (MAY_BE_ARRAY|MAY_BE_STRING|MAY_BE_OBJECT)) { - |8: - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - if (!op1_avoid_refcounting) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - if (may_throw) { - if (!zend_jit_check_exception_undef_result(Dst, opline)) { - return 0; - } - } - if (!(opline->extended_value & ZEND_ISEMPTY)) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b &exit_addr - } else { - | b >8 - } - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b =>target_label2 - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | b =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - | b >8 - } - } else { - | NIY // TODO: support for empty() - } - } - - |9: // not found - | FREE_OP opline->op2_type, opline->op2, op2_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - if (!op1_avoid_refcounting) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - if (may_throw) { - if (!zend_jit_check_exception_undef_result(Dst, opline)) { - return 0; - } - } - if (!(opline->extended_value & ZEND_ISEMPTY)) { - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b &exit_addr - } - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | b =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - } else { - ZEND_UNREACHABLE(); - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - } else { - | NIY // TODO: support for empty() - } - - |8: - - return 1; -} - -static int zend_jit_bind_global(dasm_State **Dst, const zend_op *opline, uint32_t op1_info) -{ - zend_jit_addr op1_addr = OP1_ADDR(); - zend_string *varname = Z_STR_P(RT_CONSTANT(opline, opline->op2)); - - | // idx = (uint32_t)(uintptr_t)CACHED_PTR(opline->extended_value) - 1; - | ldr FCARG2x, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, FCARG2x, opline->extended_value, TMP1 - | sub REG0, REG0, #1 - | // if (EXPECTED(idx < EG(symbol_table).nNumUsed * sizeof(Bucket))) - | MEM_LOAD_32_ZTS ldr, REG1w, executor_globals, symbol_table.nNumUsed, REG1 - | cmp REG0, REG1, lsl #5 - | bhs >9 - | // Bucket *p = (Bucket*)((char*)EG(symbol_table).arData + idx); - | MEM_LOAD_64_ZTS ldr, TMP1, executor_globals, symbol_table.arData, REG1 - | add REG0, REG0, TMP1 - | IF_NOT_Z_TYPE REG0, IS_REFERENCE, >9, TMP1w - | // (EXPECTED(p->key == varname)) - | ldr TMP1, [REG0, #offsetof(Bucket, key)] - | LOAD_ADDR TMP2, varname - | cmp TMP1, TMP2 - | bne >9 - | GET_Z_PTR REG0, REG0 - | GC_ADDREF REG0, TMP1w - |1: - if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | // if (UNEXPECTED(Z_REFCOUNTED_P(variable_ptr))) - | IF_ZVAL_REFCOUNTED op1_addr, >2, ZREG_TMP1, ZREG_TMP2 - |.cold_code - |2: - } - | // zend_refcounted *garbage = Z_COUNTED_P(variable_ptr); - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - | // ZVAL_REF(variable_ptr, ref) - | SET_ZVAL_PTR op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2 - | // if (GC_DELREF(garbage) == 0) - | GC_DELREF FCARG1x, TMP1w - if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) { - | bne >3 - } else { - | bne >5 - } - | ZVAL_DTOR_FUNC op1_info, opline, TMP1 - | b >5 - if (op1_info & (MAY_BE_REF|MAY_BE_ARRAY|MAY_BE_OBJECT)) { - |3: - | // GC_ZVAL_CHECK_POSSIBLE_ROOT(variable_ptr) - | IF_GC_MAY_NOT_LEAK FCARG1x, >5, TMP1w, TMP2w - | EXT_CALL gc_possible_root, REG0 - | b >5 - } - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - |.code - } - } - - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF) - (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | // ZVAL_REF(variable_ptr, ref) - | SET_ZVAL_PTR op1_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO op1_addr, IS_REFERENCE_EX, TMP1w, TMP2 - } - |5: - //END of handler - - |.cold_code - |9: - | LOAD_ADDR FCARG1x, (ptrdiff_t)varname - if (opline->extended_value) { - | ADD_SUB_64_WITH_CONST_32 add, FCARG2x, FCARG2x, opline->extended_value, TMP1 - } - | EXT_CALL zend_jit_fetch_global_helper, REG0 - | mov REG0, RETVALx - | b <1 - |.code - - return 1; -} - -static int zend_jit_verify_arg_type(dasm_State **Dst, const zend_op *opline, zend_arg_info *arg_info, bool check_exception) -{ - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - bool in_cold = 0; - uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY; - zend_reg tmp_reg = (type_mask == 0 || is_power_of_two(type_mask)) ? ZREG_FCARG1 : ZREG_REG0; - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && JIT_G(current_frame)->prev) { - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - uint8_t type = STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var)); - - if (type != IS_UNKNOWN && (type_mask & (1u << type))) { - return 1; - } - } - - if (ZEND_ARG_SEND_MODE(arg_info)) { - if (opline->opcode == ZEND_RECV_INIT) { - | LOAD_ZVAL_ADDR Rx(tmp_reg), res_addr - | ZVAL_DEREF Rx(tmp_reg), MAY_BE_REF, TMP1w - res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, 0); - } else { - | GET_ZVAL_PTR Rx(tmp_reg), res_addr, TMP1 - res_addr = ZEND_ADDR_MEM_ZVAL(tmp_reg, offsetof(zend_reference, val)); - } - } - - if (type_mask != 0) { - if (is_power_of_two(type_mask)) { - uint32_t type_code = concrete_type(type_mask); - | IF_NOT_ZVAL_TYPE res_addr, type_code, >1, ZREG_TMP1 - } else { - | mov REG2w, #1 - | MEM_ACCESS_8_WITH_UOFFSET ldrb, REG1w, Rx(Z_REG(res_addr)), Z_OFFSET(res_addr)+offsetof(zval, u1.v.type), TMP1 - | lsl REG2w, REG2w, REG1w - | TST_32_WITH_CONST REG2w, type_mask, TMP1w - | beq >1 - } - - |.cold_code - |1: - - in_cold = 1; - } - - if (Z_REG(res_addr) != ZREG_FCARG1 || Z_OFFSET(res_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, res_addr - } - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - | SET_EX_OPLINE opline, REG0 - } else { - | ADDR_STORE EX->opline, opline, REG0 - } - | LOAD_ADDR FCARG2x, (ptrdiff_t)arg_info - | EXT_CALL zend_jit_verify_arg_slow, REG0 - - if (check_exception) { - | GET_LOW_8BITS REG0w, RETVALw - if (in_cold) { - | cbnz REG0w, >1 - | b ->exception_handler - |.code - |1: - } else { - | cbz REG0w, ->exception_handler - } - } else if (in_cold) { - | b >1 - |.code - |1: - } - - return 1; -} - -static int zend_jit_recv(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array) -{ - uint32_t arg_num = opline->op1.num; - zend_arg_info *arg_info = NULL; - - if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - if (EXPECTED(arg_num <= op_array->num_args)) { - arg_info = &op_array->arg_info[arg_num-1]; - } else if (UNEXPECTED(op_array->fn_flags & ZEND_ACC_VARIADIC)) { - arg_info = &op_array->arg_info[op_array->num_args]; - } - if (arg_info && !ZEND_TYPE_IS_SET(arg_info->type)) { - arg_info = NULL; - } - } - - if (arg_info || (opline+1)->opcode != ZEND_RECV) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - if (!JIT_G(current_frame) || - TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) < 0 || - arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | ldr TMP1w, EX->This.u2.num_args - | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w - | blo &exit_addr - } - } else { - | ldr TMP1w, EX->This.u2.num_args - | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w - | blo >1 - |.cold_code - |1: - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - | SET_EX_OPLINE opline, REG0 - } else { - | ADDR_STORE EX->opline, opline, REG0 - } - | mov FCARG1x, FP - | EXT_CALL zend_missing_arg_error, REG0 - | b ->exception_handler - |.code - } - } - - if (arg_info) { - if (!zend_jit_verify_arg_type(Dst, opline, arg_info, 1)) { - return 0; - } - } - - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - if ((opline+1)->opcode != ZEND_RECV && (opline+1)->opcode != ZEND_RECV_INIT) { - | LOAD_IP_ADDR (opline + 1) - zend_jit_set_last_valid_opline(opline + 1); - } - } - - return 1; -} - -static int zend_jit_recv_init(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool is_last, int may_throw) -{ - uint32_t arg_num = opline->op1.num; - zval *zv = RT_CONSTANT(opline, opline->op2); - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && JIT_G(current_frame) - && TRACE_FRAME_NUM_ARGS(JIT_G(current_frame)) >= 0) { - if (arg_num > TRACE_FRAME_NUM_ARGS(JIT_G(current_frame))) { - | ZVAL_COPY_CONST res_addr, -1, -1, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0 - if (Z_REFCOUNTED_P(zv)) { - | ADDREF_CONST zv, REG0, TMP1 - } - } - } else { - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || - (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS)) { - | ldr TMP1w, EX->This.u2.num_args - | CMP_32_WITH_CONST TMP1w, arg_num, TMP2w - | bhs >5 - } - | ZVAL_COPY_CONST res_addr, -1, -1, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0 - if (Z_REFCOUNTED_P(zv)) { - | ADDREF_CONST zv, REG0, TMP1 - } - } - - if (Z_CONSTANT_P(zv)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - | SET_EX_OPLINE opline, REG0 - } else { - | ADDR_STORE EX->opline, opline, REG0 - } - | LOAD_ZVAL_ADDR FCARG1x, res_addr - | ldr REG0, EX->func - | ldr FCARG2x, [REG0, #offsetof(zend_op_array, scope)] - | EXT_CALL zval_update_constant_ex, REG0 - | cbnz RETVALw, >1 - |.cold_code - |1: - | ZVAL_PTR_DTOR res_addr, MAY_BE_ANY|MAY_BE_RC1|MAY_BE_RCN, 1, 0, opline, ZREG_TMP1, ZREG_TMP2 - | SET_ZVAL_TYPE_INFO res_addr, IS_UNDEF, TMP1w, TMP2 - | b ->exception_handler - |.code - } - - |5: - - if (op_array->fn_flags & ZEND_ACC_HAS_TYPE_HINTS) { - do { - zend_arg_info *arg_info; - - if (arg_num <= op_array->num_args) { - arg_info = &op_array->arg_info[arg_num-1]; - } else if (op_array->fn_flags & ZEND_ACC_VARIADIC) { - arg_info = &op_array->arg_info[op_array->num_args]; - } else { - break; - } - if (!ZEND_TYPE_IS_SET(arg_info->type)) { - break; - } - if (!zend_jit_verify_arg_type(Dst, opline, arg_info, may_throw)) { - return 0; - } - } while (0); - } - - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - if (is_last) { - | LOAD_IP_ADDR (opline + 1) - zend_jit_set_last_valid_opline(opline + 1); - } - } - return 1; -} - -static int zend_jit_class_guard(dasm_State **Dst, const zend_op *opline, zend_class_entry *ce) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | LOAD_ADDR TMP1, ((ptrdiff_t)ce) - | ldr TMP2, [FCARG1x, #offsetof(zend_object, ce)] - | cmp TMP2, TMP1 - | bne &exit_addr - - return 1; -} - -static int zend_jit_fetch_obj(dasm_State **Dst, - const zend_op *opline, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - uint32_t op1_info, - zend_jit_addr op1_addr, - bool op1_indirect, - zend_class_entry *ce, - bool ce_is_instanceof, - bool on_this, - bool delayed_fetch_this, - bool op1_avoid_refcounting, - zend_class_entry *trace_ce, - uint8_t prop_type, - int may_throw) -{ - zval *member; - zend_property_info *prop_info; - bool may_be_dynamic = 1; - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); - zend_jit_addr prop_addr; - uint32_t res_info = RES_INFO(); - bool type_loaded = 0; - - ZEND_ASSERT(opline->op2_type == IS_CONST); - ZEND_ASSERT(op1_info & MAY_BE_OBJECT); - - member = RT_CONSTANT(opline, opline->op2); - ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0'); - prop_info = zend_get_known_property_info(op_array, ce, Z_STR_P(member), on_this, op_array->filename); - - if (on_this) { - | GET_ZVAL_PTR FCARG1x, this_addr, TMP1 - } else { - if (opline->op1_type == IS_VAR - && opline->opcode == ZEND_FETCH_OBJ_W - && (op1_info & MAY_BE_INDIRECT) - && Z_REG(op1_addr) == ZREG_FP) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & MAY_BE_REF) { - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >7, ZREG_TMP1 - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - } - - if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) { - prop_info = zend_get_known_property_info(op_array, trace_ce, Z_STR_P(member), on_this, op_array->filename); - if (prop_info) { - ce = trace_ce; - ce_is_instanceof = 0; - if (!(op1_info & MAY_BE_CLASS_GUARD)) { - if (on_this && JIT_G(current_frame) - && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) { - ZEND_ASSERT(JIT_G(current_frame)->ce == ce); - } else if (zend_jit_class_guard(Dst, opline, ce)) { - if (on_this && JIT_G(current_frame)) { - JIT_G(current_frame)->ce = ce; - TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame)); - } - } else { - return 0; - } - if (ssa->var_info && ssa_op->op1_use >= 0) { - ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_use].ce = ce; - ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof; - } - } - } - } - - if (!prop_info) { - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, (opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS), TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] - | cmp REG2, TMP1 - | bne >5 - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, ((opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*)), TMP1 - may_be_dynamic = zend_may_be_dynamic_property(ce, Z_STR_P(member), opline->op1_type == IS_UNUSED, op_array->filename); - if (may_be_dynamic) { - | tst REG0, REG0 - if (opline->opcode == ZEND_FETCH_OBJ_W) { - | blt >5 - } else { - | blt >8 // dynamic property - } - } - | add TMP1, FCARG1x, REG0 - | ldr REG2w, [TMP1, #offsetof(zval,u1.type_info)] - | IF_UNDEF REG2w, >5 - | mov FCARG1x, TMP1 - type_loaded = 1; - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - if (opline->opcode == ZEND_FETCH_OBJ_W - && (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT)))) { - uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; - - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, ((opline->extended_value & ~ZEND_FETCH_OBJ_FLAGS) + sizeof(void*) * 2), TMP1 - | cbnz FCARG2x, >1 - |.cold_code - |1: - | ldr TMP1w, [FCARG2x, #offsetof(zend_property_info, flags)] - | tst TMP1w, #ZEND_ACC_READONLY - if (flags) { - | beq >3 - } else { - | beq >4 - } - | IF_NOT_TYPE REG2w, IS_OBJECT_EX, >2 - | GET_Z_PTR REG2, FCARG1x - | GC_ADDREF REG2, TMP1w - | SET_ZVAL_PTR res_addr, REG2, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX, TMP1w, TMP2 - | b >9 - |2: - | ldr REG0w, [FCARG1x, #offsetof(zval, u2.extra)] - | TST_32_WITH_CONST REG0w, IS_PROP_REINITABLE, TMP1w - | beq >6 - | and REG0w, REG0w, #(~IS_PROP_REINITABLE) - | str REG0w, [FCARG1x, #offsetof(zval, u2.extra)] - if (flags) { - | b >3 - } else { - | b >4 - } - |6: - | mov FCARG1x, FCARG2x - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_readonly_property_modification_error, REG0 - | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2 - | b >9 - |3: - if (flags == ZEND_FETCH_DIM_WRITE) { - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_check_array_promotion, REG0 - | b >9 - } else if (flags == ZEND_FETCH_REF) { - | LOAD_ZVAL_ADDR CARG3, res_addr - | EXT_CALL zend_jit_create_typed_ref, REG0 - | b >9 - } else { - ZEND_ASSERT(flags == 0); - } - |.code - |4: - } - } else { - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset); - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - if (opline->opcode == ZEND_FETCH_OBJ_W || !(res_info & MAY_BE_GUARD) || !JIT_G(current_frame)) { - /* perform IS_UNDEF check only after result type guard (during deoptimization) */ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - | IF_UNDEF REG2w, &exit_addr - } - } else { - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - | IF_UNDEF REG2w, >5 - } - if (opline->opcode == ZEND_FETCH_OBJ_W && (prop_info->flags & ZEND_ACC_READONLY)) { - if (!type_loaded) { - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - } - | IF_NOT_TYPE REG2w, IS_OBJECT_EX, >4 - | GET_ZVAL_PTR REG2, prop_addr, TMP1 - | GC_ADDREF REG2, TMP1w - | SET_ZVAL_PTR res_addr, REG2, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_OBJECT_EX, TMP1w, TMP2 - | b >9 - |.cold_code - |4: - | ldr REG0w, [FCARG1x, #(prop_info->offset + offsetof(zval, u2.extra))] - | TST_32_WITH_CONST REG0w, IS_PROP_REINITABLE, TMP1w - | beq >6 - | and REG0w, REG0w, #(~IS_PROP_REINITABLE) - | str REG0w, [FCARG1x, #(prop_info->offset + offsetof(zval, u2.extra))] - | b >4 - |6: - | LOAD_ADDR FCARG1x, prop_info - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_readonly_property_modification_error, REG0 - | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2 - | b >9 - |.code - |4: - } - if (opline->opcode == ZEND_FETCH_OBJ_W - && (opline->extended_value & ZEND_FETCH_OBJ_FLAGS) - && ZEND_TYPE_IS_SET(prop_info->type)) { - uint32_t flags = opline->extended_value & ZEND_FETCH_OBJ_FLAGS; - - if (flags == ZEND_FETCH_DIM_WRITE) { - if ((ZEND_TYPE_FULL_MASK(prop_info->type) & MAY_BE_ARRAY) == 0) { - if (!type_loaded) { - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - } - | cmp REG2w, #IS_FALSE - | ble >1 - |.cold_code - |1: - if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - } - | LOAD_ADDR FCARG2x, prop_info - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_check_array_promotion, REG0 - | b >9 - |.code - } - } else if (flags == ZEND_FETCH_REF) { - if (!type_loaded) { - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - } - | GET_LOW_8BITS TMP1w, REG2w - | IF_TYPE TMP1w, IS_REFERENCE, >1 - if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) { - | LOAD_ADDR FCARG2x, prop_info - } else { - int prop_info_offset = - (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*)); - - | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)] - | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)] - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1 - } - if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - } - | LOAD_ZVAL_ADDR CARG3, res_addr - | EXT_CALL zend_jit_create_typed_ref, REG0 - | b >9 - |1: - } else { - ZEND_UNREACHABLE(); - } - } - } - if (opline->opcode == ZEND_FETCH_OBJ_W) { - if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - } - | SET_ZVAL_PTR res_addr, FCARG1x, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_INDIRECT, TMP1w, TMP2 - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE && prop_info) { - ssa->var_info[ssa_op->result_def].indirect_reference = 1; - } - } else { - bool result_avoid_refcounting = 0; - - if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame) && prop_info) { - uint32_t flags = 0; - uint32_t old_info; - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - int32_t exit_point; - const void *exit_addr; - uint32_t type; - zend_jit_addr val_addr = prop_addr; - - if ((opline->op1_type & (IS_VAR|IS_TMP_VAR)) - && !delayed_fetch_this - && !op1_avoid_refcounting) { - flags = ZEND_JIT_EXIT_FREE_OP1; - } - - if ((opline->result_type & (IS_VAR|IS_TMP_VAR)) - && !(flags & ZEND_JIT_EXIT_FREE_OP1) - && (res_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) - && (ssa_op+1)->op1_use == ssa_op->result_def - && zend_jit_may_avoid_refcounting(opline+1, res_info)) { - result_avoid_refcounting = 1; - ssa->var_info[ssa_op->result_def].avoid_refcounting = 1; - } - - type = concrete_type(res_info); - - if (prop_type != IS_UNKNOWN - && prop_type != IS_UNDEF - && prop_type != IS_REFERENCE - && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT) { - exit_point = zend_jit_trace_get_exit_point(opline, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - } else { - val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - | LOAD_ZVAL_ADDR REG0, prop_addr - if (op1_avoid_refcounting) { - SET_STACK_REG(JIT_G(current_frame)->stack, - EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE); - } - old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0); - exit_point = zend_jit_trace_get_exit_point(opline+1, flags); - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - if (!type_loaded) { - type_loaded = 1; - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.type_info)), TMP1 - } - | // ZVAL_DEREF() - | GET_LOW_8BITS TMP1w, REG2w - | IF_NOT_TYPE TMP1w, IS_REFERENCE, >1 - | GET_Z_PTR REG0, REG0 - | add REG0, REG0, #offsetof(zend_reference, val) - | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1 - } - res_info &= ~MAY_BE_GUARD; - ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; - if (type < IS_STRING) { - |1: - if (type_loaded) { - | IF_NOT_TYPE REG2w, type, &exit_addr - } else { - | IF_NOT_ZVAL_TYPE val_addr, type, &exit_addr, ZREG_TMP1 - } - } else { - if (!type_loaded) { - type_loaded = 1; - | GET_ZVAL_TYPE_INFO REG2w, val_addr, TMP1 - } - |1: - | GET_LOW_8BITS TMP1w, REG2w - | IF_NOT_TYPE TMP1w, type, &exit_addr - } - | // ZVAL_COPY - | ZVAL_COPY_VALUE_V res_addr, -1, val_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0 - if (type < IS_STRING) { - if (Z_REG(res_addr) != ZREG_FP || - JIT_G(current_frame) == NULL || - STACK_MEM_TYPE(JIT_G(current_frame)->stack, EX_VAR_TO_NUM(Z_OFFSET(res_addr))) != type) { - | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2 - } - } else { - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1 - if (!result_avoid_refcounting) { - | TRY_ADDREF res_info, REG2w, REG1, TMP1w - } - } - } else { - if (!zend_jit_zval_copy_deref(Dst, res_addr, prop_addr, ZREG_REG2)) { - return 0; - } - } - } - - if (op1_avoid_refcounting) { - SET_STACK_REG(JIT_G(current_frame)->stack, - EX_VAR_TO_NUM(opline->op1.var), ZREG_NONE); - } - - |.cold_code - - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE || !prop_info) { - |5: - | SET_EX_OPLINE opline, REG0 - if (opline->opcode == ZEND_FETCH_OBJ_W) { - | EXT_CALL zend_jit_fetch_obj_w_slow, REG0 - } else if (opline->opcode != ZEND_FETCH_OBJ_IS) { - | EXT_CALL zend_jit_fetch_obj_r_slow, REG0 - } else { - | EXT_CALL zend_jit_fetch_obj_is_slow, REG0 - } - | b >9 - } - - if ((op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)- MAY_BE_OBJECT)) && JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - |7: - if (opline->opcode != ZEND_FETCH_OBJ_IS) { - | SET_EX_OPLINE opline, REG0 - if (opline->opcode != ZEND_FETCH_OBJ_W - && (op1_info & MAY_BE_UNDEF)) { - zend_jit_addr orig_op1_addr = OP1_ADDR(); - - if (op1_info & MAY_BE_ANY) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >1, ZREG_TMP1 - } - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - |1: - | LOAD_ZVAL_ADDR FCARG1x, orig_op1_addr - } else if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | LOAD_ADDR FCARG2x, Z_STRVAL_P(member) - if (opline->opcode == ZEND_FETCH_OBJ_W) { - | EXT_CALL zend_jit_invalid_property_write, REG0 - | SET_ZVAL_TYPE_INFO res_addr, _IS_ERROR, TMP1w, TMP2 - } else { - | EXT_CALL zend_jit_invalid_property_read, REG0 - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - } - | b >9 - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - | b >9 - } - } - - if (!prop_info - && may_be_dynamic - && opline->opcode != ZEND_FETCH_OBJ_W) { - |8: - | mov FCARG2x, REG0 - | SET_EX_OPLINE opline, REG0 - if (opline->opcode != ZEND_FETCH_OBJ_IS) { - | EXT_CALL zend_jit_fetch_obj_r_dynamic, REG0 - } else { - | EXT_CALL zend_jit_fetch_obj_is_dynamic, REG0 - } - | b >9 - } - - |.code; - |9: // END - if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) { - if (opline->op1_type == IS_VAR - && opline->opcode == ZEND_FETCH_OBJ_W - && (op1_info & MAY_BE_RC1)) { - zend_jit_addr orig_op1_addr = OP1_ADDR(); - - | IF_NOT_ZVAL_REFCOUNTED orig_op1_addr, >1, ZREG_TMP1, ZREG_TMP2 - | GET_ZVAL_PTR FCARG1x, orig_op1_addr, TMP1 - | GC_DELREF FCARG1x, TMP1w - | bne >1 - | SET_EX_OPLINE opline, REG0 - | EXT_CALL zend_jit_extract_helper, REG0 - |1: - } else if (!op1_avoid_refcounting) { - if (on_this) { - op1_info &= ~MAY_BE_RC1; - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - } - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && prop_info - && (opline->opcode != ZEND_FETCH_OBJ_W || - !(opline->extended_value & ZEND_FETCH_OBJ_FLAGS) || - !ZEND_TYPE_IS_SET(prop_info->type)) - && (!(opline->op1_type & (IS_VAR|IS_TMP_VAR)) || on_this || op1_indirect)) { - may_throw = 0; - } - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_incdec_obj(dasm_State **Dst, - const zend_op *opline, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - uint32_t op1_info, - zend_jit_addr op1_addr, - bool op1_indirect, - zend_class_entry *ce, - bool ce_is_instanceof, - bool on_this, - bool delayed_fetch_this, - zend_class_entry *trace_ce, - uint8_t prop_type) -{ - zval *member; - zend_string *name; - zend_property_info *prop_info; - zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); - zend_jit_addr res_addr = 0; - zend_jit_addr prop_addr; - bool needs_slow_path = 0; - bool use_prop_guard = 0; - bool may_throw = 0; - uint32_t res_info = (opline->result_type != IS_UNDEF) ? RES_INFO() : 0; - - ZEND_ASSERT(opline->op2_type == IS_CONST); - ZEND_ASSERT(op1_info & MAY_BE_OBJECT); - - if (opline->result_type != IS_UNUSED) { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - } - - member = RT_CONSTANT(opline, opline->op2); - ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0'); - name = Z_STR_P(member); - prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename); - - if (on_this) { - | GET_ZVAL_PTR FCARG1x, this_addr, TMP1 - } else { - if (opline->op1_type == IS_VAR - && (op1_info & MAY_BE_INDIRECT) - && Z_REG(op1_addr) == ZREG_FP) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & MAY_BE_REF) { - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1 - |.cold_code - |1: - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | LOAD_ADDR FCARG2x, ZSTR_VAL(name) - | EXT_CALL zend_jit_invalid_property_incdec, REG0 - | b ->exception_handler - |.code - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - } - - if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) { - prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename); - if (prop_info) { - ce = trace_ce; - ce_is_instanceof = 0; - if (!(op1_info & MAY_BE_CLASS_GUARD)) { - if (on_this && JIT_G(current_frame) - && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) { - ZEND_ASSERT(JIT_G(current_frame)->ce == ce); - } else if (zend_jit_class_guard(Dst, opline, ce)) { - if (on_this && JIT_G(current_frame)) { - JIT_G(current_frame)->ce = ce; - TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame)); - } - } else { - return 0; - } - if (ssa->var_info && ssa_op->op1_use >= 0) { - ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_use].ce = ce; - ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof; - } - if (ssa->var_info && ssa_op->op1_def >= 0) { - ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_def].ce = ce; - ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof; - } - } - } - } - - use_prop_guard = (prop_type != IS_UNKNOWN - && prop_type != IS_UNDEF - && prop_type != IS_REFERENCE - && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT); - - if (!prop_info) { - needs_slow_path = 1; - - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->extended_value, TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] - | cmp REG2, TMP1 - | bne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { - | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1 - | cbnz TMP1, >7 - } - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->extended_value + sizeof(void*)), TMP1 - | tst REG0, REG0 - | blt >7 - | add TMP1, FCARG1x, REG0 - if (!use_prop_guard) { - | ldrb TMP2w, [TMP1, #offsetof(zval,u1.v.type)] - | IF_TYPE TMP2w , IS_UNDEF, >7 - } - | mov FCARG1x, TMP1 - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } else { - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, &exit_addr - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, >7 - needs_slow_path = 1; - } - } - if (ZEND_TYPE_IS_SET(prop_info->type)) { - may_throw = 1; - | SET_EX_OPLINE opline, REG0 - if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) { - | LOAD_ADDR FCARG2x, prop_info - } else { - int prop_info_offset = - (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*)); - - | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)] - | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)] - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1 - } - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - if (opline->result_type == IS_UNUSED) { - switch (opline->opcode) { - case ZEND_PRE_INC_OBJ: - case ZEND_POST_INC_OBJ: - | EXT_CALL zend_jit_inc_typed_prop, REG0 - break; - case ZEND_PRE_DEC_OBJ: - case ZEND_POST_DEC_OBJ: - | EXT_CALL zend_jit_dec_typed_prop, REG0 - break; - default: - ZEND_UNREACHABLE(); - } - } else { - | LOAD_ZVAL_ADDR CARG3, res_addr - switch (opline->opcode) { - case ZEND_PRE_INC_OBJ: - | EXT_CALL zend_jit_pre_inc_typed_prop, REG0 - break; - case ZEND_PRE_DEC_OBJ: - | EXT_CALL zend_jit_pre_dec_typed_prop, REG0 - break; - case ZEND_POST_INC_OBJ: - | EXT_CALL zend_jit_post_inc_typed_prop, REG0 - break; - case ZEND_POST_DEC_OBJ: - | EXT_CALL zend_jit_post_dec_typed_prop, REG0 - break; - default: - ZEND_UNREACHABLE(); - } - } - } - } - - if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) { - uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; - zend_jit_addr var_addr = prop_addr; - - if (use_prop_guard) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - | IF_NOT_ZVAL_TYPE var_addr, prop_type, &exit_addr, ZREG_TMP1 - var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)); - } - - if (var_info & MAY_BE_REF) { - may_throw = 1; - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - if (Z_REG(prop_addr) != ZREG_FCARG1 || Z_OFFSET(prop_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - } - | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2, ZREG_TMP1 - | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbnz TMP1, >1 - | add FCARG1x, FCARG1x, #offsetof(zend_reference, val) - |.cold_code - |1: - if (opline) { - | SET_EX_OPLINE opline, REG0 - } - if (opline->result_type == IS_UNUSED) { - | mov FCARG2x, xzr - } else { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - } - switch (opline->opcode) { - case ZEND_PRE_INC_OBJ: - | EXT_CALL zend_jit_pre_inc_typed_ref, REG0 - break; - case ZEND_PRE_DEC_OBJ: - | EXT_CALL zend_jit_pre_dec_typed_ref, REG0 - break; - case ZEND_POST_INC_OBJ: - | EXT_CALL zend_jit_post_inc_typed_ref, REG0 - break; - case ZEND_POST_DEC_OBJ: - | EXT_CALL zend_jit_post_dec_typed_ref, REG0 - break; - default: - ZEND_UNREACHABLE(); - } - | b >9 - |.code - |2: - } - - if (var_info & MAY_BE_LONG) { - if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) { - | IF_NOT_ZVAL_TYPE var_addr, IS_LONG, >2, ZREG_TMP1 - } - if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) { - if (opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_REG1, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - } - if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) { - | LONG_ADD_SUB_WITH_IMM adds, var_addr, Z_L(1), TMP1, TMP2 - } else { - | LONG_ADD_SUB_WITH_IMM subs, var_addr, Z_L(1), TMP1, TMP2 - } - | bvs >3 - if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) { - if (opline->result_type != IS_UNUSED) { - | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_LONG, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - } - } - |.cold_code - } - if (var_info & (MAY_BE_ANY - MAY_BE_LONG)) { - if (var_info & (MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - may_throw = 1; - } - if (var_info & MAY_BE_LONG) { - |2: - } - if (Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) { - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - } - if (opline->opcode == ZEND_POST_INC_OBJ || opline->opcode == ZEND_POST_DEC_OBJ) { - | ZVAL_COPY_VALUE res_addr, -1, var_addr, MAY_BE_ANY, ZREG_REG0, ZREG_REG2, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF MAY_BE_ANY, REG0w, REG2, TMP1w - } - if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) { - if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | EXT_CALL zend_jit_pre_inc, REG0 - } else { - | EXT_CALL increment_function, REG0 - } - } else { - if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) { - | LOAD_ZVAL_ADDR FCARG2x, res_addr - | EXT_CALL zend_jit_pre_dec, REG0 - } else { - | EXT_CALL decrement_function, REG0 - } - } - if (var_info & MAY_BE_LONG) { - | b >4 - } - } - - if (var_info & MAY_BE_LONG) { - |3: - if (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_POST_INC_OBJ) { - uint64_t val = 0x43e0000000000000; - | LOAD_64BIT_VAL TMP2, val - | SET_ZVAL_LVAL_FROM_REG var_addr, TMP2, TMP1 - | SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE, TMP1w, TMP2 - if (opline->opcode == ZEND_PRE_INC_OBJ && opline->result_type != IS_UNUSED) { - | SET_ZVAL_LVAL_FROM_REG res_addr, TMP2, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - } else { - uint64_t val = 0xc3e0000000000000; - | LOAD_64BIT_VAL TMP2, val - | SET_ZVAL_LVAL_FROM_REG var_addr, TMP2, TMP1 - | SET_ZVAL_TYPE_INFO var_addr, IS_DOUBLE, TMP1w, TMP2 - if (opline->opcode == ZEND_PRE_DEC_OBJ && opline->result_type != IS_UNUSED) { - | SET_ZVAL_LVAL_FROM_REG res_addr, TMP2, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_DOUBLE, TMP1w, TMP2 - } - } - if (opline->result_type != IS_UNUSED - && (opline->opcode == ZEND_PRE_INC_OBJ || opline->opcode == ZEND_PRE_DEC_OBJ) - && prop_info - && !ZEND_TYPE_IS_SET(prop_info->type) - && (res_info & MAY_BE_GUARD) - && (res_info & MAY_BE_LONG)) { - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - uint32_t old_res_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - int32_t exit_point; - const void *exit_addr; - - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_DOUBLE, 0); - exit_point = zend_jit_trace_get_exit_point(opline + 1, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_res_info); - ssa->var_info[ssa_op->result_def].type = res_info & ~MAY_BE_GUARD; - | b &exit_addr - |.code - } else { - | b >4 - |.code - |4: - } - } - } - - if (needs_slow_path) { - may_throw = 1; - |.cold_code - |7: - | SET_EX_OPLINE opline, REG0 - | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value)); - | LOAD_ADDR FCARG2x, name - | ldr CARG3, EX->run_time_cache - | ADD_SUB_64_WITH_CONST_32 add, CARG3, CARG3, opline->extended_value, TMP1 - if (opline->result_type == IS_UNUSED) { - | mov CARG4, xzr - } else { - | LOAD_ZVAL_ADDR CARG4, res_addr - } - - switch (opline->opcode) { - case ZEND_PRE_INC_OBJ: - | EXT_CALL zend_jit_pre_inc_obj_helper, REG0 - break; - case ZEND_PRE_DEC_OBJ: - | EXT_CALL zend_jit_pre_dec_obj_helper, REG0 - break; - case ZEND_POST_INC_OBJ: - | EXT_CALL zend_jit_post_inc_obj_helper, REG0 - break; - case ZEND_POST_DEC_OBJ: - | EXT_CALL zend_jit_post_dec_obj_helper, REG0 - break; - default: - ZEND_UNREACHABLE(); - } - - | b >9 - |.code - } - - |9: - if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { - may_throw = 1; - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_assign_obj_op(dasm_State **Dst, - const zend_op *opline, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - uint32_t op1_info, - zend_jit_addr op1_addr, - uint32_t val_info, - zend_ssa_range *val_range, - bool op1_indirect, - zend_class_entry *ce, - bool ce_is_instanceof, - bool on_this, - bool delayed_fetch_this, - zend_class_entry *trace_ce, - uint8_t prop_type) -{ - zval *member; - zend_string *name; - zend_property_info *prop_info; - zend_jit_addr val_addr = OP1_DATA_ADDR(); - zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); - zend_jit_addr prop_addr; - bool needs_slow_path = 0; - bool use_prop_guard = 0; - bool may_throw = 0; - binary_op_type binary_op = get_binary_op(opline->extended_value); - - ZEND_ASSERT(opline->op2_type == IS_CONST); - ZEND_ASSERT(op1_info & MAY_BE_OBJECT); - ZEND_ASSERT(opline->result_type == IS_UNUSED); - - member = RT_CONSTANT(opline, opline->op2); - ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0'); - name = Z_STR_P(member); - prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename); - - if (on_this) { - | GET_ZVAL_PTR FCARG1x, this_addr, TMP1 - } else { - if (opline->op1_type == IS_VAR - && (op1_info & MAY_BE_INDIRECT) - && Z_REG(op1_addr) == ZREG_FP) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & MAY_BE_REF) { - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1 - |.cold_code - |1: - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | LOAD_ADDR FCARG2x, ZSTR_VAL(name) - if (op1_info & MAY_BE_UNDEF) { - | EXT_CALL zend_jit_invalid_property_assign_op, REG0 - } else { - | EXT_CALL zend_jit_invalid_property_assign, REG0 - } - may_throw = 1; - if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR)) - && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | b >8 - } else { - | b >9 - } - |.code - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - } - - if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) { - prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename); - if (prop_info) { - ce = trace_ce; - ce_is_instanceof = 0; - if (!(op1_info & MAY_BE_CLASS_GUARD)) { - if (on_this && JIT_G(current_frame) - && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) { - ZEND_ASSERT(JIT_G(current_frame)->ce == ce); - } else if (zend_jit_class_guard(Dst, opline, ce)) { - if (on_this && JIT_G(current_frame)) { - JIT_G(current_frame)->ce = ce; - TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame)); - } - } else { - return 0; - } - if (ssa->var_info && ssa_op->op1_use >= 0) { - ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_use].ce = ce; - ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof; - } - if (ssa->var_info && ssa_op->op1_def >= 0) { - ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_def].ce = ce; - ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof; - } - } - } - } - - use_prop_guard = (prop_type != IS_UNKNOWN - && prop_type != IS_UNDEF - && prop_type != IS_REFERENCE - && (op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_OBJECT); - - if (!prop_info) { - needs_slow_path = 1; - - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, ((opline+1)->extended_value), TMP1 - | ldr TMP2, [FCARG1x, #offsetof(zend_object, ce)] - | cmp REG2, TMP2 - | bne >7 - if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { - | MEM_ACCESS_64_WITH_UOFFSET ldr, TMP1, REG0, ((opline+1)->extended_value + sizeof(void*) * 2), TMP1 - | cbnz TMP1, >7 - } - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, ((opline+1)->extended_value + sizeof(void*)), TMP1 - | tst REG0, REG0 - | blt >7 - | add TMP1, FCARG1x, REG0 - if (!use_prop_guard) { - | ldrb TMP2w, [TMP1, #offsetof(zval,u1.v.type)] - | IF_TYPE TMP2w, IS_UNDEF, >7 - } - | mov FCARG1x, TMP1 - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } else { - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset); - if (ZEND_TYPE_IS_SET(prop_info->type) || !use_prop_guard) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, &exit_addr - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, >7 - needs_slow_path = 1; - } - } - if (ZEND_TYPE_IS_SET(prop_info->type)) { - uint32_t info = val_info; - - may_throw = 1; - - if (opline) { - | SET_EX_OPLINE opline, REG0 - } - - | IF_ZVAL_TYPE prop_addr, IS_REFERENCE, >1, ZREG_TMP1 - |.cold_code - |1: - | GET_ZVAL_PTR FCARG1x, prop_addr, TMP1 - if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG2x, val_addr - } - | LOAD_ADDR CARG3, binary_op - if ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) - && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0 - } else { - | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0 - } - | b >9 - |.code - - | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - - if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) { - | LOAD_ADDR FCARG2x, prop_info - } else { - int prop_info_offset = - (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*)); - - | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)] - | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)] - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1 - } - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - | LOAD_ZVAL_ADDR CARG3, val_addr - | LOAD_ADDR CARG4, binary_op - - | EXT_CALL zend_jit_assign_op_to_typed_prop, REG0 - - if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - info |= MAY_BE_RC1|MAY_BE_RCN; - } - - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - } - } - - if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) { - zend_jit_addr var_addr = prop_addr; - uint32_t var_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; - uint32_t var_def_info = MAY_BE_ANY|MAY_BE_REF|MAY_BE_RC1|MAY_BE_RCN; - - if (use_prop_guard) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - - | IF_NOT_ZVAL_TYPE var_addr, prop_type, &exit_addr, ZREG_TMP1 - var_info = (1 << prop_type) | (var_info & ~(MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)); - } - - if (var_info & MAY_BE_REF) { - may_throw = 1; - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - | LOAD_ZVAL_ADDR REG0, prop_addr - | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, >2, ZREG_TMP1 - | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_reference, sources.ptr)] - | cbnz TMP1, >1 - | add REG0, FCARG1x, #offsetof(zend_reference, val) - |.cold_code - |1: - if (Z_MODE(val_addr) != IS_MEM_ZVAL || Z_REG(val_addr) != ZREG_FCARG2 || Z_OFFSET(val_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG2x, val_addr - } - if (opline) { - | SET_EX_OPLINE opline, REG0 - } - | LOAD_ADDR CARG3, binary_op - if (((opline+1)->op1_type & (IS_TMP_VAR|IS_VAR)) - && (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | EXT_CALL zend_jit_assign_op_to_typed_ref_tmp, REG0 - } else { - | EXT_CALL zend_jit_assign_op_to_typed_ref, REG0 - } - | b >9 - |.code - |2: - } - - switch (opline->extended_value) { - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || - (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (opline->extended_value != ZEND_ADD || - (var_info & MAY_BE_ANY) != MAY_BE_ARRAY || - (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) { - may_throw = 1; - } - } - if (!zend_jit_math_helper(Dst, opline, opline->extended_value, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, 0, var_addr, var_def_info, var_info, - 1 /* may overflow */, 0)) { - return 0; - } - break; - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - may_throw = 1; - if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || - (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if ((var_info & MAY_BE_ANY) != MAY_BE_STRING || - (val_info & MAY_BE_ANY) != MAY_BE_STRING) { - may_throw = 1; - } - } - goto long_math; - case ZEND_SL: - case ZEND_SR: - if ((var_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || - (val_info & (MAY_BE_STRING|MAY_BE_DOUBLE|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - may_throw = 1; - } - if ((opline+1)->op1_type != IS_CONST || - Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG || - Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) < 0) { - may_throw = 1; - } - goto long_math; - case ZEND_MOD: - if ((var_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) || - (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - if (opline->extended_value != ZEND_ADD || - (var_info & MAY_BE_ANY) != MAY_BE_ARRAY || - (val_info & MAY_BE_ANY) == MAY_BE_ARRAY) { - may_throw = 1; - } - } - if ((opline+1)->op1_type != IS_CONST || - Z_TYPE_P(RT_CONSTANT((opline+1), (opline+1)->op1)) != IS_LONG || - Z_LVAL_P(RT_CONSTANT((opline+1), (opline+1)->op1)) == 0) { - may_throw = 1; - } -long_math: - if (!zend_jit_long_math_helper(Dst, opline, opline->extended_value, - IS_CV, opline->op1, var_addr, var_info, NULL, - (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, - val_range, - 0, var_addr, var_def_info, var_info, 0)) { - return 0; - } - break; - case ZEND_CONCAT: - may_throw = 1; - if (!zend_jit_concat_helper(Dst, opline, IS_CV, opline->op1, var_addr, var_info, (opline+1)->op1_type, (opline+1)->op1, val_addr, val_info, var_addr, - 0)) { - return 0; - } - break; - default: - ZEND_UNREACHABLE(); - } - } - - if (needs_slow_path) { - may_throw = 1; - |.cold_code - |7: - | SET_EX_OPLINE opline, REG0 - | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value)); - | LOAD_ADDR FCARG2x, name - | LOAD_ZVAL_ADDR CARG3, val_addr - | ldr CARG4, EX->run_time_cache - | ADD_SUB_64_WITH_CONST_32 add, CARG4, CARG4, (opline+1)->extended_value, TMP1 - | LOAD_ADDR CARG5, binary_op - | EXT_CALL zend_jit_assign_obj_op_helper, REG0 - - if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - val_info |= MAY_BE_RC1|MAY_BE_RCN; - } - - |8: - | // FREE_OP_DATA(); - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - | b >9 - |.code - } - - |9: - if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) { - if ((op1_info & MAY_HAVE_DTOR) && (op1_info & MAY_BE_RC1)) { - may_throw = 1; - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_assign_obj(dasm_State **Dst, - const zend_op *opline, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - uint32_t op1_info, - zend_jit_addr op1_addr, - uint32_t val_info, - bool op1_indirect, - zend_class_entry *ce, - bool ce_is_instanceof, - bool on_this, - bool delayed_fetch_this, - zend_class_entry *trace_ce, - uint8_t prop_type, - int may_throw) -{ - zval *member; - zend_string *name; - zend_property_info *prop_info; - zend_jit_addr val_addr = OP1_DATA_ADDR(); - zend_jit_addr res_addr = 0; - zend_jit_addr this_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, offsetof(zend_execute_data, This)); - zend_jit_addr prop_addr; - bool needs_slow_path = 0; - bool needs_val_dtor = 0; - - if (RETURN_VALUE_USED(opline)) { - res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - } - - ZEND_ASSERT(opline->op2_type == IS_CONST); - ZEND_ASSERT(op1_info & MAY_BE_OBJECT); - - member = RT_CONSTANT(opline, opline->op2); - ZEND_ASSERT(Z_TYPE_P(member) == IS_STRING && Z_STRVAL_P(member)[0] != '\0'); - name = Z_STR_P(member); - prop_info = zend_get_known_property_info(op_array, ce, name, on_this, op_array->filename); - - if (on_this) { - | GET_ZVAL_PTR FCARG1x, this_addr, TMP1 - } else { - if (opline->op1_type == IS_VAR - && (op1_info & MAY_BE_INDIRECT) - && Z_REG(op1_addr) == ZREG_FP) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - | IF_NOT_Z_TYPE FCARG1x, IS_INDIRECT, >1, TMP1w - | GET_Z_PTR FCARG1x, FCARG1x - |1: - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & MAY_BE_REF) { - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - if (op1_info & ((MAY_BE_UNDEF|MAY_BE_ANY)- MAY_BE_OBJECT)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, &exit_addr, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_OBJECT, >1, ZREG_TMP1 - |.cold_code - |1: - | SET_EX_OPLINE opline, REG0 - if (Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - } - | LOAD_ADDR FCARG2x, ZSTR_VAL(name) - | EXT_CALL zend_jit_invalid_property_assign, REG0 - if (RETURN_VALUE_USED(opline)) { - | SET_ZVAL_TYPE_INFO res_addr, IS_NULL, TMP1w, TMP2 - } - if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR)) - && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - needs_val_dtor = 1; - | b >7 - } else { - | b >9 - } - |.code - } - } - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - } - - if (!prop_info && trace_ce && (trace_ce->ce_flags & ZEND_ACC_IMMUTABLE)) { - prop_info = zend_get_known_property_info(op_array, trace_ce, name, on_this, op_array->filename); - if (prop_info) { - ce = trace_ce; - ce_is_instanceof = 0; - if (!(op1_info & MAY_BE_CLASS_GUARD)) { - if (on_this && JIT_G(current_frame) - && TRACE_FRAME_IS_THIS_CLASS_CHECKED(JIT_G(current_frame))) { - ZEND_ASSERT(JIT_G(current_frame)->ce == ce); - } else if (zend_jit_class_guard(Dst, opline, ce)) { - if (on_this && JIT_G(current_frame)) { - JIT_G(current_frame)->ce = ce; - TRACE_FRAME_SET_THIS_CLASS_CHECKED(JIT_G(current_frame)); - } - } else { - return 0; - } - if (ssa->var_info && ssa_op->op1_use >= 0) { - ssa->var_info[ssa_op->op1_use].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_use].ce = ce; - ssa->var_info[ssa_op->op1_use].is_instanceof = ce_is_instanceof; - } - if (ssa->var_info && ssa_op->op1_def >= 0) { - ssa->var_info[ssa_op->op1_def].type |= MAY_BE_CLASS_GUARD; - ssa->var_info[ssa_op->op1_def].ce = ce; - ssa->var_info[ssa_op->op1_def].is_instanceof = ce_is_instanceof; - } - } - } - } - - if (!prop_info) { - needs_slow_path = 1; - - | ldr REG0, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG2, REG0, opline->extended_value, TMP1 - | ldr TMP1, [FCARG1x, #offsetof(zend_object, ce)] - | cmp REG2, TMP1 - | bne >5 - if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, (opline->extended_value + sizeof(void*) * 2), TMP1 - } - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, REG0, (opline->extended_value + sizeof(void*)), TMP1 - | tst REG0, REG0 - | blt >5 - | add TMP2, FCARG1x, REG0 - | ldrb TMP1w, [TMP2, #offsetof(zval,u1.v.type)] - | IF_TYPE TMP1w, IS_UNDEF, >5 - | mov FCARG1x, TMP2 - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - if (!ce || ce_is_instanceof || (ce->ce_flags & (ZEND_ACC_HAS_TYPE_HINTS|ZEND_ACC_TRAIT))) { - | cbnz FCARG2x, >1 - |.cold_code - |1: - | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - | SET_EX_OPLINE opline, REG0 - | LOAD_ZVAL_ADDR CARG3, val_addr - if (RETURN_VALUE_USED(opline)) { - | LOAD_ZVAL_ADDR CARG4, res_addr - } else { - | mov CARG4, xzr - } - - | EXT_CALL zend_jit_assign_to_typed_prop, REG0 - - if ((opline+1)->op1_type == IS_CONST) { - | // TODO: ??? - | // if (Z_TYPE_P(value) == orig_type) { - | // CACHE_PTR_EX(cache_slot + 2, NULL); - } - - if (((opline+1)->op1_type & (IS_VAR|IS_TMP_VAR)) - && (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) { - | b >7 - } else { - | b >9 - } - |.code - } - } else { - prop_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, prop_info->offset); - if (!ce || ce_is_instanceof || !(ce->ce_flags & ZEND_ACC_IMMUTABLE) || ce->__get || ce->__set || (prop_info->flags & ZEND_ACC_READONLY)) { - // Undefined property with magic __get()/__set() - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, &exit_addr - } else { - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP2w, FCARG1x, (prop_info->offset + offsetof(zval,u1.v.type)), TMP1 - | IF_TYPE TMP2w, IS_UNDEF, >5 - needs_slow_path = 1; - } - } - if (ZEND_TYPE_IS_SET(prop_info->type)) { - uint32_t info = val_info; - - | // value = zend_assign_to_typed_prop(prop_info, property_val, value EXECUTE_DATA_CC); - | SET_EX_OPLINE opline, REG0 - if (ce && ce->ce_flags & ZEND_ACC_IMMUTABLE) { - | LOAD_ADDR FCARG2x, prop_info - } else { - int prop_info_offset = - (((prop_info->offset - (sizeof(zend_object) - sizeof(zval))) / sizeof(zval)) * sizeof(void*)); - - | ldr REG0, [FCARG1x, #offsetof(zend_object, ce)] - | ldr REG0, [REG0, #offsetof(zend_class_entry, properties_info_table)] - | MEM_ACCESS_64_WITH_UOFFSET ldr, FCARG2x, REG0, prop_info_offset, TMP1 - } - | LOAD_ZVAL_ADDR FCARG1x, prop_addr - | LOAD_ZVAL_ADDR CARG3, val_addr - if (RETURN_VALUE_USED(opline)) { - | LOAD_ZVAL_ADDR CARG4, res_addr - } else { - | mov CARG4, xzr - } - - | EXT_CALL zend_jit_assign_to_typed_prop, REG0 - - if (info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - info |= MAY_BE_RC1|MAY_BE_RCN; - } - - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, info, 0, NULL, ZREG_TMP1, ZREG_TMP2 - } - } - - if (!prop_info || !ZEND_TYPE_IS_SET(prop_info->type)) { - // value = zend_assign_to_variable(property_val, value, OP_DATA_TYPE, EX_USES_STRICT_TYPES()); - if (opline->result_type == IS_UNUSED) { - if (!zend_jit_assign_to_variable_call(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) { - return 0; - } - } else { - if (!zend_jit_assign_to_variable(Dst, opline, prop_addr, prop_addr, -1, -1, (opline+1)->op1_type, val_addr, val_info, res_addr, 0)) { - return 0; - } - } - } - - if (needs_slow_path) { - |.cold_code - |5: - | SET_EX_OPLINE opline, REG0 - | // value = zobj->handlers->write_property(zobj, name, value, CACHE_ADDR(opline->extended_value)); - | LOAD_ADDR FCARG2x, name - - | LOAD_ZVAL_ADDR CARG3, val_addr - | ldr CARG4, EX->run_time_cache - | ADD_SUB_64_WITH_CONST_32 add, CARG4, CARG4, opline->extended_value, TMP1 - if (RETURN_VALUE_USED(opline)) { - | LOAD_ZVAL_ADDR CARG5, res_addr - } else { - | mov CARG5, xzr - } - - | EXT_CALL zend_jit_assign_obj_helper, REG0 - - if (val_info & (MAY_BE_REF|MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - val_info |= MAY_BE_RC1|MAY_BE_RCN; - } - - |7: - | // FREE_OP_DATA(); - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - | b >9 - |.code - } else if (needs_val_dtor) { - |.cold_code - |7: - | // FREE_OP_DATA(); - | FREE_OP (opline+1)->op1_type, (opline+1)->op1, val_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - | b >9 - |.code - } - - |9: - if (opline->op1_type != IS_UNUSED && !delayed_fetch_this && !op1_indirect) { - | FREE_OP opline->op1_type, opline->op1, op1_info, 1, opline, ZREG_TMP1, ZREG_TMP2 - } - - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - - return 1; -} - -static int zend_jit_free(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, int may_throw) -{ - zend_jit_addr op1_addr = OP1_ADDR(); - - if (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF)) { - if (may_throw) { - | SET_EX_OPLINE opline, REG0 - } - if (opline->opcode == ZEND_FE_FREE && (op1_info & (MAY_BE_OBJECT|MAY_BE_REF))) { - if (op1_info & MAY_BE_ARRAY) { - | IF_ZVAL_TYPE op1_addr, IS_ARRAY, >7, ZREG_TMP1 - } - | MEM_ACCESS_32_WITH_UOFFSET ldr, FCARG1w, FP, (opline->op1.var + offsetof(zval, u2.fe_iter_idx)), TMP1 - | mvn TMP1w, wzr // TODO: DynAsm fails loading #-1 - | cmp FCARG1w, TMP1w - | beq >7 - | EXT_CALL zend_hash_iterator_del, REG0 - |7: - } - | ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline, ZREG_TMP1, ZREG_TMP2 - if (may_throw) { - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - } - return 1; -} - -static int zend_jit_echo(dasm_State **Dst, const zend_op *opline, uint32_t op1_info) -{ - if (opline->op1_type == IS_CONST) { - zval *zv; - size_t len; - - zv = RT_CONSTANT(opline, opline->op1); - ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); - len = Z_STRLEN_P(zv); - - if (len > 0) { - const char *str = Z_STRVAL_P(zv); - - | SET_EX_OPLINE opline, REG0 - | LOAD_ADDR CARG1, str - | LOAD_64BIT_VAL CARG2, len - | EXT_CALL zend_write, REG0 - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - } else { - zend_jit_addr op1_addr = OP1_ADDR(); - - ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING); - - | SET_EX_OPLINE opline, REG0 - | GET_ZVAL_PTR REG0, op1_addr, TMP1 - | add CARG1, REG0, #offsetof(zend_string, val) - | ldr CARG2, [REG0, #offsetof(zend_string, len)] - | EXT_CALL zend_write, REG0 - if (opline->op1_type & (IS_VAR|IS_TMP_VAR)) { - | ZVAL_PTR_DTOR op1_addr, op1_info, 0, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - if (!zend_jit_check_exception(Dst)) { - return 0; - } - } - return 1; -} - -static int zend_jit_strlen(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr) -{ - if (opline->op1_type == IS_CONST) { - zval *zv; - size_t len; - - zv = RT_CONSTANT(opline, opline->op1); - ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); - len = Z_STRLEN_P(zv); - - | SET_ZVAL_LVAL res_addr, len, TMP1, TMP2 - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) { - return 0; - } - } else { - ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING); - - if (Z_MODE(res_addr) == IS_REG) { - | GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1 - | ldr Rx(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(zend_string, len)] - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) { - return 0; - } - } else { - | GET_ZVAL_PTR REG0, op1_addr, TMP1 - | ldr REG0, [REG0, #offsetof(zend_string, len)] - | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - return 1; -} - -static int zend_jit_count(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, zend_jit_addr res_addr, int may_throw) -{ - if (opline->op1_type == IS_CONST) { - zval *zv; - zend_long count; - - zv = RT_CONSTANT(opline, opline->op1); - ZEND_ASSERT(Z_TYPE_P(zv) == IS_ARRAY); - count = zend_hash_num_elements(Z_ARRVAL_P(zv)); - - | SET_ZVAL_LVAL res_addr, count, TMP1, TMP2 - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) { - return 0; - } - } else { - ZEND_ASSERT((op1_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_ARRAY); - // Note: See the implementation of ZEND_COUNT in Zend/zend_vm_def.h - arrays do not contain IS_UNDEF starting in php 8.1+. - - if (Z_MODE(res_addr) == IS_REG) { - | GET_ZVAL_PTR Rx(Z_REG(res_addr)), op1_addr, TMP1 - // Sign-extend the 32-bit value to a potentially 64-bit zend_long - | ldr Rw(Z_REG(res_addr)), [Rx(Z_REG(res_addr)), #offsetof(HashTable, nNumOfElements)] - if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, MAY_BE_LONG)) { - return 0; - } - } else { - | GET_ZVAL_PTR REG0, op1_addr, TMP1 - // Sign-extend the 32-bit value to a potentially 64-bit zend_long - | ldr REG0w, [REG0, #offsetof(HashTable, nNumOfElements)] - | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - | FREE_OP opline->op1_type, opline->op1, op1_info, 0, opline, ZREG_TMP1, ZREG_TMP2 - } - - if (may_throw) { - return zend_jit_check_exception(Dst); - } - return 1; -} - -static int zend_jit_load_this(dasm_State **Dst, uint32_t var) -{ - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, var); - - | ldr FCARG1x, EX->This.value.ptr - | SET_ZVAL_PTR var_addr, FCARG1x, TMP1 - | SET_ZVAL_TYPE_INFO var_addr, IS_OBJECT_EX, TMP1w, TMP2 - | GC_ADDREF FCARG1x, TMP1w - return 1; -} - -static int zend_jit_fetch_this(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, bool check_only) -{ - if (!op_array->scope || (op_array->fn_flags & ZEND_ACC_STATIC)) { - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - if (!JIT_G(current_frame) || - !TRACE_FRAME_IS_THIS_CHECKED(JIT_G(current_frame))) { - - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_TO_VM); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | ldrb TMP1w, EX->This.u1.v.type - | cmp TMP1w, #IS_OBJECT - | bne &exit_addr - - if (JIT_G(current_frame)) { - TRACE_FRAME_SET_THIS_CHECKED(JIT_G(current_frame)); - } - } - } else { - - | ldrb TMP1w, EX->This.u1.v.type - | cmp TMP1w, #IS_OBJECT - | bne >1 - |.cold_code - |1: - | SET_EX_OPLINE opline, REG0 - | b ->invalid_this - |.code - } - } - - if (!check_only) { - if (!zend_jit_load_this(Dst, opline->result.var)) { - return 0; - } - } - return 1; -} - -static int zend_jit_hash_jmp(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, HashTable *jumptable, int default_b, const void *default_label, const zend_op *next_opline, zend_jit_trace_info *trace_info) -{ - uint32_t count; - Bucket *p; - const zend_op *target; - int b; - int32_t exit_point; - const void *exit_addr; - - if (default_label) { - | cbz REG0, &default_label - } else if (next_opline) { - | cbz REG0, >3 - } else { - | cbz REG0, =>default_b - } - | LOAD_ADDR FCARG1x, jumptable - | ldr TMP1, [FCARG1x, #offsetof(HashTable, arData)] - | sub REG0, REG0, TMP1 - if (HT_IS_PACKED(jumptable)) { - | mov FCARG1x, #(sizeof(zval) / sizeof(void*)) - } else { - | mov FCARG1x, #(sizeof(Bucket) / sizeof(void*)) - } - | sdiv REG0, REG0, FCARG1x - | adr FCARG1x, >4 - | ldr TMP1, [FCARG1x, REG0] - | br TMP1 - - |.jmp_table - |.align 8 - |4: - if (trace_info) { - trace_info->jmp_table_size += zend_hash_num_elements(jumptable); - } - - count = jumptable->nNumUsed; - p = jumptable->arData; - do { - if (Z_TYPE(p->val) == IS_UNDEF) { - if (default_label) { - | .addr &default_label - } else if (next_opline) { - | .addr >3 - } else { - | .addr =>default_b - } - } else { - target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL(p->val)); - if (!next_opline) { - b = ssa->cfg.map[target - op_array->opcodes]; - | .addr =>b - } else if (next_opline == target) { - | .addr >3 - } else { - exit_point = zend_jit_trace_get_exit_point(target, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | .addr &exit_addr - } - } - if (HT_IS_PACKED(jumptable)) { - p = (Bucket*)(((zval*)p)+1); - } else { - p++; - } - count--; - } while (count); - |.code - - return 1; -} - -static int zend_jit_switch(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, zend_ssa *ssa, zend_jit_trace_rec *trace, zend_jit_trace_info *trace_info) -{ - HashTable *jumptable = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); - const zend_op *next_opline = NULL; - - if (trace) { - ZEND_ASSERT(trace->op == ZEND_JIT_TRACE_VM || trace->op == ZEND_JIT_TRACE_END); - ZEND_ASSERT(trace->opline != NULL); - next_opline = trace->opline; - } - - if (opline->op1_type == IS_CONST) { - zval *zv = RT_CONSTANT(opline, opline->op1); - zval *jump_zv = NULL; - int b; - - if (opline->opcode == ZEND_SWITCH_LONG) { - if (Z_TYPE_P(zv) == IS_LONG) { - jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv)); - } - } else if (opline->opcode == ZEND_SWITCH_STRING) { - if (Z_TYPE_P(zv) == IS_STRING) { - jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv)); - } - } else if (opline->opcode == ZEND_MATCH) { - if (Z_TYPE_P(zv) == IS_LONG) { - jump_zv = zend_hash_index_find(jumptable, Z_LVAL_P(zv)); - } else if (Z_TYPE_P(zv) == IS_STRING) { - jump_zv = zend_hash_find_known_hash(jumptable, Z_STR_P(zv)); - } - } else { - ZEND_UNREACHABLE(); - } - if (next_opline) { - const zend_op *target; - - if (jump_zv != NULL) { - target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)); - } else { - target = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); - } - ZEND_ASSERT(target == next_opline); - } else { - if (jump_zv != NULL) { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(jump_zv)) - op_array->opcodes]; - } else { - b = ssa->cfg.map[ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value) - op_array->opcodes]; - } - | b =>b - } - } else { - zend_ssa_op *ssa_op = &ssa->ops[opline - op_array->opcodes]; - uint32_t op1_info = OP1_INFO(); - zend_jit_addr op1_addr = OP1_ADDR(); - const zend_op *default_opline = ZEND_OFFSET_TO_OPLINE(opline, opline->extended_value); - const zend_op *target; - int default_b = next_opline ? -1 : ssa->cfg.map[default_opline - op_array->opcodes]; - int b; - int32_t exit_point; - const void *fallback_label = NULL; - const void *default_label = NULL; - const void *exit_addr; - - if (next_opline) { - if (next_opline != opline + 1) { - exit_point = zend_jit_trace_get_exit_point(opline + 1, 0); - fallback_label = zend_jit_trace_get_exit_addr(exit_point); - if (!fallback_label) { - return 0; - } - } - if (next_opline != default_opline) { - exit_point = zend_jit_trace_get_exit_point(default_opline, 0); - default_label = zend_jit_trace_get_exit_addr(exit_point); - if (!default_label) { - return 0; - } - } - } - - if (opline->opcode == ZEND_SWITCH_LONG) { - if (op1_info & MAY_BE_LONG) { - if (op1_info & MAY_BE_REF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >1, ZREG_TMP1 - | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1 - |.cold_code - |1: - | // ZVAL_DEREF(op) - if (fallback_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3, ZREG_TMP1 - } - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - if (fallback_label) { - | add TMP1, FCARG2x, #offsetof(zend_reference, val) - | IF_NOT_Z_TYPE TMP1, IS_LONG, &fallback_label, TMP2w - } else { - | add TMP1, FCARG2x, #offsetof(zend_reference, val) - | IF_NOT_Z_TYPE TMP1, IS_LONG, >3, TMP2w - } - | ldr FCARG2x, [FCARG2x, #offsetof(zend_reference, val.value.lval)] - | b >2 - |.code - |2: - } else { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { - if (fallback_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &fallback_label, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1 - } - } - | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1 - } - if (HT_IS_PACKED(jumptable)) { - uint32_t count = jumptable->nNumUsed; - zval *zv = jumptable->arPacked; - - | CMP_64_WITH_CONST_32 FCARG2x, jumptable->nNumUsed, TMP1 - if (default_label) { - | bhs &default_label - } else if (next_opline) { - | bhs >3 - } else { - | bhs =>default_b - } - | adr REG0, >4 - | ldr TMP1, [REG0, FCARG2x, lsl #3] - | br TMP1 - - |.jmp_table - |.align 8 - |4: - if (trace_info) { - trace_info->jmp_table_size += count; - } - do { - if (Z_TYPE_P(zv) == IS_UNDEF) { - if (default_label) { - | .addr &default_label - } else if (next_opline) { - | .addr >3 - } else { - | .addr =>default_b - } - } else { - target = ZEND_OFFSET_TO_OPLINE(opline, Z_LVAL_P(zv)); - if (!next_opline) { - b = ssa->cfg.map[target - op_array->opcodes]; - | .addr =>b - } else if (next_opline == target) { - | .addr >3 - } else { - exit_point = zend_jit_trace_get_exit_point(target, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - | .addr &exit_addr - } - } - zv++; - count--; - } while (count); - |.code - |3: - } else { - | LOAD_ADDR FCARG1x, jumptable - | EXT_CALL zend_hash_index_find, REG0 - | mov REG0, RETVALx - if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { - return 0; - } - |3: - } - } - } else if (opline->opcode == ZEND_SWITCH_STRING) { - if (op1_info & MAY_BE_STRING) { - if (op1_info & MAY_BE_REF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >1, ZREG_TMP1 - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - |.cold_code - |1: - | // ZVAL_DEREF(op) - if (fallback_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, &fallback_label, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_REFERENCE, >3, ZREG_TMP1 - } - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - if (fallback_label) { - | add TMP1, FCARG2x, #offsetof(zend_reference, val) - | IF_NOT_Z_TYPE TMP1, IS_STRING, &fallback_label, TMP2w - } else { - | add TMP1, FCARG2x, #offsetof(zend_reference, val) - | IF_NOT_Z_TYPE TMP1, IS_STRING, >3, TMP2w - } - | ldr FCARG2x, [FCARG2x, #offsetof(zend_reference, val.value.ptr)] - | b >2 - |.code - |2: - } else { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_STRING)) { - if (fallback_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &fallback_label, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3, ZREG_TMP1 - } - } - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - } - | LOAD_ADDR FCARG1x, jumptable - | EXT_CALL zend_hash_find, REG0 - | mov REG0, RETVALx - if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { - return 0; - } - |3: - } - } else if (opline->opcode == ZEND_MATCH) { - if (op1_info & (MAY_BE_LONG|MAY_BE_STRING)) { - if (op1_info & MAY_BE_REF) { - | LOAD_ZVAL_ADDR FCARG2x, op1_addr - | ZVAL_DEREF FCARG2x, op1_info, TMP1w - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - } - | LOAD_ADDR FCARG1x, jumptable - if (op1_info & MAY_BE_LONG) { - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-MAY_BE_LONG)) { - if (op1_info & MAY_BE_STRING) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >5, ZREG_TMP1 - } else if (op1_info & MAY_BE_UNDEF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >6, ZREG_TMP1 - } else if (default_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, &default_label, ZREG_TMP1 - } else if (next_opline) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_LONG, =>default_b, ZREG_TMP1 - } - } - | GET_ZVAL_LVAL ZREG_FCARG2, op1_addr, TMP1 - | EXT_CALL zend_hash_index_find, REG0 - | mov REG0, RETVALx - if (op1_info & MAY_BE_STRING) { - | b >2 - } - } - if (op1_info & MAY_BE_STRING) { - |5: - if (op1_info & ((MAY_BE_ANY|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_STRING))) { - if (op1_info & MAY_BE_UNDEF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >6, ZREG_TMP1 - } else if (default_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, &default_label, ZREG_TMP1 - } else if (next_opline) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_STRING, =>default_b, ZREG_TMP1 - } - } - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - | EXT_CALL zend_hash_find, REG0 - | mov REG0, RETVALx - } - |2: - if (!zend_jit_hash_jmp(Dst, opline, op_array, ssa, jumptable, default_b, default_label, next_opline, trace_info)) { - return 0; - } - } - if (op1_info & MAY_BE_UNDEF) { - |6: - if (op1_info & (MAY_BE_ANY-(MAY_BE_LONG|MAY_BE_STRING))) { - if (default_label) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, &default_label, ZREG_TMP1 - } else if (next_opline) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >3, ZREG_TMP1 - } else { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, =>default_b, ZREG_TMP1 - } - } - | // zend_error(E_WARNING, "Undefined variable $%s", ZSTR_VAL(CV_DEF_OF(EX_VAR_TO_NUM(opline->op1.var)))); - | SET_EX_OPLINE opline, REG0 - | LOAD_32BIT_VAL FCARG1w, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - if (!zend_jit_check_exception_undef_result(Dst, opline)) { - return 0; - } - } - if (default_label) { - | b &default_label - } else if (next_opline) { - | b >3 - } else { - | b =>default_b - } - |3: - } else { - ZEND_UNREACHABLE(); - } - } - return 1; -} - -static bool zend_jit_verify_return_type(dasm_State **Dst, const zend_op *opline, const zend_op_array *op_array, uint32_t op1_info) -{ - zend_arg_info *arg_info = &op_array->arg_info[-1]; - ZEND_ASSERT(ZEND_TYPE_IS_SET(arg_info->type)); - zend_jit_addr op1_addr = OP1_ADDR(); - bool needs_slow_check = 1; - bool slow_check_in_cold = 1; - uint32_t type_mask = ZEND_TYPE_PURE_MASK(arg_info->type) & MAY_BE_ANY; - - if (type_mask == 0) { - slow_check_in_cold = 0; - } else { - if (((op1_info & MAY_BE_ANY) & type_mask) == 0) { - slow_check_in_cold = 0; - } else if (((op1_info & MAY_BE_ANY) | type_mask) == type_mask) { - needs_slow_check = 0; - } else if (is_power_of_two(type_mask)) { - uint32_t type_code = concrete_type(type_mask); - | IF_NOT_ZVAL_TYPE op1_addr, type_code, >6, ZREG_TMP1 - } else { - | mov REG2w, #1 - | GET_ZVAL_TYPE REG1w, op1_addr, TMP1 - | lsl REG2w, REG2w, REG1w - | TST_32_WITH_CONST REG2w, type_mask, TMP1w - | beq >6 - } - } - if (needs_slow_check) { - if (slow_check_in_cold) { - |.cold_code - |6: - } - | SET_EX_OPLINE opline, REG1 - if (op1_info & MAY_BE_UNDEF) { - | IF_NOT_ZVAL_TYPE op1_addr, IS_UNDEF, >7, ZREG_TMP1 - | LOAD_32BIT_VAL FCARG1x, opline->op1.var - | EXT_CALL zend_jit_undefined_op_helper, REG0 - | cbz RETVALx, ->exception_handler - | LOAD_ADDR_ZTS FCARG1x, executor_globals, uninitialized_zval - | b >8 - } - |7: - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - |8: - | ldr FCARG2x, EX->func - | LOAD_ADDR CARG3, (ptrdiff_t)arg_info - | ldr REG0, EX->run_time_cache - | ADD_SUB_64_WITH_CONST_32 add, CARG4, REG0, opline->op2.num, TMP1 - | EXT_CALL zend_jit_verify_return_slow, REG0 - if (!zend_jit_check_exception(Dst)) { - return 0; - } - if (slow_check_in_cold) { - | b >9 - |.code - } - } - |9: - return 1; -} - -static int zend_jit_isset_isempty_cv(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - // TODO: support for empty() ??? - ZEND_ASSERT(!(opline->extended_value & ZEND_ISEMPTY)); - - if (op1_info & MAY_BE_REF) { - if (Z_MODE(op1_addr) != IS_MEM_ZVAL || Z_REG(op1_addr) != ZREG_FCARG1 || Z_OFFSET(op1_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, op1_addr - op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - } - | ZVAL_DEREF FCARG1x, op1_info, TMP1w - |1: - } - - if (!(op1_info & (MAY_BE_UNDEF|MAY_BE_NULL))) { - if (exit_addr) { - ZEND_ASSERT(smart_branch_opcode == ZEND_JMPZ); - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | b =>target_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_TRUE, TMP1w, TMP2 - } - } else if (!(op1_info & (MAY_BE_ANY - MAY_BE_NULL))) { - if (exit_addr) { - ZEND_ASSERT(smart_branch_opcode == ZEND_JMPNZ); - } else if (smart_branch_opcode) { - if (smart_branch_opcode != ZEND_JMPNZ) { - | b =>target_label - } - } else { - | SET_ZVAL_TYPE_INFO res_addr, IS_FALSE, TMP1w, TMP2 - } - } else { - ZEND_ASSERT(Z_MODE(op1_addr) == IS_MEM_ZVAL); - | MEM_ACCESS_8_WITH_UOFFSET ldrb, TMP1w, Rx(Z_REG(op1_addr)), (Z_OFFSET(op1_addr)+offsetof(zval, u1.v.type)), TMP1 - | cmp TMP1w, #IS_NULL - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPNZ) { - | bgt &exit_addr - } else { - | ble &exit_addr - } - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | ble =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | bgt =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - | cset REG0w, gt - | add REG0w, REG0w, #IS_FALSE - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - } - - return 1; -} - -static int zend_jit_fe_reset(dasm_State **Dst, const zend_op *opline, uint32_t op1_info) -{ - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - if (opline->op1_type == IS_CONST) { - zval *zv = RT_CONSTANT(opline, opline->op1); - - | ZVAL_COPY_CONST res_addr, MAY_BE_ANY, MAY_BE_ANY, zv, ZREG_REG0, ZREG_TMP1, ZREG_FPR0 - if (Z_REFCOUNTED_P(zv)) { - | ADDREF_CONST zv, REG0, TMP1 - } - } else { - zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - - | // ZVAL_COPY(res, value); - | ZVAL_COPY_VALUE res_addr, -1, op1_addr, op1_info, ZREG_REG0, ZREG_FCARG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - if (opline->op1_type == IS_CV) { - | TRY_ADDREF op1_info, REG0w, FCARG1x, TMP1w - } - } - | // Z_FE_POS_P(res) = 0; - | MEM_ACCESS_32_WITH_UOFFSET str, wzr, FP, (opline->result.var + offsetof(zval, u2.fe_pos)), TMP1 - - return 1; -} - -static int zend_jit_fe_fetch(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, uint32_t op2_info, unsigned int target_label, uint8_t exit_opcode, const void *exit_addr) -{ - zend_jit_addr op1_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op1.var); - - if (!MAY_BE_HASH(op1_info) && !MAY_BE_PACKED(op1_info)) { - /* empty array */ - if (exit_addr) { - if (exit_opcode == ZEND_JMP) { - | b &exit_addr - } - } else { - | b =>target_label - } - return 1; - } - - | // array = EX_VAR(opline->op1.var); - | // fe_ht = Z_ARRVAL_P(array); - | GET_ZVAL_PTR FCARG1x, op1_addr, TMP1 - - if (op1_info & MAY_BE_PACKED_GUARD) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, ZEND_JIT_EXIT_PACKED_GUARD); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - if (op1_info & MAY_BE_ARRAY_PACKED) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | beq &exit_addr - } else { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | bne &exit_addr - } - } - - | // pos = Z_FE_POS_P(array); - | MEM_ACCESS_32_WITH_UOFFSET ldr, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1 - - if (MAY_BE_HASH(op1_info)) { - if (MAY_BE_PACKED(op1_info)) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, u.flags)] - | TST_32_WITH_CONST TMP1w, HASH_FLAG_PACKED, TMP2w - | bne >2 - } - | // p = fe_ht->arData + pos; - || ZEND_ASSERT(sizeof(Bucket) == 32); - | mov FCARG2w, REG0w - | ldr TMP1, [FCARG1x, #offsetof(zend_array, arData)] - | add FCARG2x, TMP1, FCARG2x, lsl #5 - |1: - | // if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, nNumUsed)] - | cmp TMP1w, REG0w - | // ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); - | // ZEND_VM_CONTINUE(); - if (exit_addr) { - if (exit_opcode == ZEND_JMP) { - | bls &exit_addr - } else { - | bls >3 - } - } else { - | bls =>target_label - } - | // pos++; - | add REG0w, REG0w, #1 - | // value_type = Z_TYPE_INFO_P(value); - | // if (EXPECTED(value_type != IS_UNDEF)) { - if (!exit_addr || exit_opcode == ZEND_JMP) { - | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, >3, TMP1w - } else { - | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, &exit_addr, TMP1w - } - | // p++; - | add FCARG2x, FCARG2x, #sizeof(Bucket) - | b <1 - if (MAY_BE_PACKED(op1_info)) { - |2: - } - } - if (MAY_BE_PACKED(op1_info)) { - | // p = fe_ht->arPacked + pos; - || ZEND_ASSERT(sizeof(zval) == 16); - | mov FCARG2w, REG0w - | ldr TMP1, [FCARG1x, #offsetof(zend_array, arPacked)] - | add FCARG2x, TMP1, FCARG2x, lsl #4 - |1: - | // if (UNEXPECTED(pos >= fe_ht->nNumUsed)) { - | ldr TMP1w, [FCARG1x, #offsetof(zend_array, nNumUsed)] - | cmp TMP1w, REG0w - | // ZEND_VM_SET_RELATIVE_OPCODE(opline, opline->extended_value); - | // ZEND_VM_CONTINUE(); - if (exit_addr) { - if (exit_opcode == ZEND_JMP) { - | bls &exit_addr - } else { - | bls >4 - } - } else { - | bls =>target_label - } - | // pos++; - | add REG0w, REG0w, #1 - | // value_type = Z_TYPE_INFO_P(value); - | // if (EXPECTED(value_type != IS_UNDEF)) { - if (!exit_addr || exit_opcode == ZEND_JMP) { - | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, >4, TMP1w - } else { - | IF_NOT_Z_TYPE FCARG2x, IS_UNDEF, &exit_addr, TMP1w - } - | // p++; - | add FCARG2x, FCARG2x, #sizeof(zval) - | b <1 - } - - if (!exit_addr || exit_opcode == ZEND_JMP) { - zend_jit_addr val_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG2, 0); - zend_jit_addr var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->op2.var); - uint32_t val_info; - - if (RETURN_VALUE_USED(opline)) { - zend_jit_addr res_addr = RES_ADDR(); - - if (MAY_BE_HASH(op1_info)) { - |3: - | // Z_FE_POS_P(array) = pos + 1; - | MEM_ACCESS_32_WITH_UOFFSET str, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1 - - if ((op1_info & MAY_BE_ARRAY_KEY_LONG) - && (op1_info & MAY_BE_ARRAY_KEY_STRING)) { - | // if (!p->key) { - | ldr REG0, [FCARG2x, #offsetof(Bucket, key)] - | cbz REG0, >2 - } - if (op1_info & MAY_BE_ARRAY_KEY_STRING) { - | // ZVAL_STR_COPY(EX_VAR(opline->result.var), p->key); - | ldr REG0, [FCARG2x, #offsetof(Bucket, key)] - | SET_ZVAL_PTR res_addr, REG0, TMP1 - | ldr TMP1w, [REG0, #offsetof(zend_refcounted, gc.u.type_info)] - | TST_32_WITH_CONST TMP1w, IS_STR_INTERNED, TMP2w - | beq >1 - | SET_ZVAL_TYPE_INFO res_addr, IS_STRING, TMP1w, TMP2 - | b >3 - |1: - | GC_ADDREF REG0, TMP1w - | SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX, TMP1w, TMP2 - - if ((op1_info & MAY_BE_ARRAY_KEY_LONG) || MAY_BE_PACKED(op1_info)) { - | b >3 - |2: - } - } - if (op1_info & MAY_BE_ARRAY_KEY_LONG) { - | // ZVAL_LONG(EX_VAR(opline->result.var), p->h); - | ldr REG0, [FCARG2x, #offsetof(Bucket, h)] - | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - if (MAY_BE_PACKED(op1_info)) { - | b >3 - } - } - } - if (MAY_BE_PACKED(op1_info)) { - |4: - | // Z_FE_POS_P(array) = pos + 1; - | MEM_ACCESS_32_WITH_UOFFSET str, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1 - | sub REG0w, REG0w, #1 - | SET_ZVAL_LVAL_FROM_REG res_addr, REG0, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_LONG, TMP1w, TMP2 - } - |3: - } else { - |3: - |4: - | // Z_FE_POS_P(array) = pos + 1; - | MEM_ACCESS_32_WITH_UOFFSET str, REG0w, FP, (opline->op1.var + offsetof(zval, u2.fe_pos)), TMP1 - } - - val_info = ((op1_info & MAY_BE_ARRAY_OF_ANY) >> MAY_BE_ARRAY_SHIFT); - if (val_info & MAY_BE_ARRAY) { - val_info |= MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - } - if (op1_info & MAY_BE_ARRAY_OF_REF) { - val_info |= MAY_BE_REF | MAY_BE_RC1 | MAY_BE_RCN | MAY_BE_ANY | - MAY_BE_ARRAY_KEY_ANY | MAY_BE_ARRAY_OF_ANY | MAY_BE_ARRAY_OF_REF; - } else if (val_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)) { - val_info |= MAY_BE_RC1 | MAY_BE_RCN; - } - - if (opline->op2_type == IS_CV) { - | // zend_assign_to_variable(variable_ptr, value, IS_CV, EX_USES_STRICT_TYPES()); - if (!zend_jit_assign_to_variable(Dst, opline, var_addr, var_addr, op2_info, -1, IS_CV, val_addr, val_info, 0, 1)) { - return 0; - } - } else { - | // ZVAL_COPY(res, value); - | ZVAL_COPY_VALUE var_addr, -1, val_addr, val_info, ZREG_REG0, ZREG_FCARG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF val_info, REG0w, FCARG1x, TMP1w - } - } else { - |3: - |4: - } - - return 1; -} - -static int zend_jit_fetch_constant(dasm_State **Dst, - const zend_op *opline, - const zend_op_array *op_array, - zend_ssa *ssa, - const zend_ssa_op *ssa_op, - zend_jit_addr res_addr) -{ - zval *zv = RT_CONSTANT(opline, opline->op2) + 1; - zend_jit_addr const_addr = ZEND_ADDR_MEM_ZVAL(ZREG_REG0, 0); - uint32_t res_info = RES_INFO(); - - | // c = CACHED_PTR(opline->extended_value); - | ldr FCARG1x, EX->run_time_cache - | MEM_ACCESS_64_WITH_UOFFSET ldr, REG0, FCARG1x, opline->extended_value, TMP1 - | // if (c != NULL) - | cbz REG0, >9 - if (!zend_jit_is_persistent_constant(zv, opline->op1.num)) { - | // if (!IS_SPECIAL_CACHE_VAL(c)) - || ZEND_ASSERT(CACHE_SPECIAL == 1); - | TST_64_WITH_ONE REG0 - | bne >9 - } - |8: - - if ((res_info & MAY_BE_GUARD) && JIT_G(current_frame)) { - zend_jit_trace_stack *stack = JIT_G(current_frame)->stack; - uint32_t old_info = STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var)); - int32_t exit_point; - const void *exit_addr = NULL; - - SET_STACK_TYPE(stack, EX_VAR_TO_NUM(opline->result.var), IS_UNKNOWN, 1); - SET_STACK_REG(stack, EX_VAR_TO_NUM(opline->result.var), ZREG_ZVAL_COPY_GPR0); - exit_point = zend_jit_trace_get_exit_point(opline+1, 0); - SET_STACK_INFO(stack, EX_VAR_TO_NUM(opline->result.var), old_info); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - res_info &= ~MAY_BE_GUARD; - ssa->var_info[ssa_op->result_def].type &= ~MAY_BE_GUARD; - - uint32_t type = concrete_type(res_info); - - if (type < IS_STRING) { - | IF_NOT_ZVAL_TYPE const_addr, type, &exit_addr, ZREG_TMP1 - } else { - | GET_ZVAL_TYPE_INFO REG2w, const_addr, TMP1 - | IF_NOT_TYPE REG2w, type, &exit_addr - } - | ZVAL_COPY_VALUE_V res_addr, -1, const_addr, res_info, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_FPR0 - if (type < IS_STRING) { - if (Z_MODE(res_addr) == IS_MEM_ZVAL) { - | SET_ZVAL_TYPE_INFO res_addr, type, TMP1w, TMP2 - } else if (!zend_jit_store_var_if_necessary(Dst, opline->result.var, res_addr, res_info)) { - return 0; - } - } else { - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG2w, TMP1 - | TRY_ADDREF res_info, REG2w, REG1, TMP1w - } - } else { - | ZVAL_COPY_VALUE res_addr, MAY_BE_ANY, const_addr, MAY_BE_ANY, ZREG_REG0, ZREG_REG1, ZREG_TMP1, ZREG_TMP2, ZREG_FPR0 - | TRY_ADDREF MAY_BE_ANY, REG0w, REG1, TMP1w - } - - |.cold_code - |9: - | // SAVE_OPLINE(); - | SET_EX_OPLINE opline, REG0 - | // zend_quick_get_constant(RT_CONSTANT(opline, opline->op2) + 1, opline->op1.num OPLINE_CC EXECUTE_DATA_CC); - | LOAD_ADDR FCARG1x, zv - | LOAD_32BIT_VAL FCARG2w, opline->op1.num - | EXT_CALL zend_jit_get_constant, REG0 - | mov REG0, RETVALx - | // ZEND_VM_NEXT_OPCODE_CHECK_EXCEPTION(); - | cbnz REG0, <8 - | b ->exception_handler - |.code - return 1; -} - -static int zend_jit_in_array(dasm_State **Dst, const zend_op *opline, uint32_t op1_info, zend_jit_addr op1_addr, uint8_t smart_branch_opcode, uint32_t target_label, uint32_t target_label2, const void *exit_addr) -{ - HashTable *ht = Z_ARRVAL_P(RT_CONSTANT(opline, opline->op2)); - zend_jit_addr res_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FP, opline->result.var); - - ZEND_ASSERT(opline->op1_type != IS_VAR && opline->op1_type != IS_TMP_VAR); - ZEND_ASSERT((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) == MAY_BE_STRING); - - | // result = zend_hash_find_ex(ht, Z_STR_P(op1), OP1_TYPE == IS_CONST); - | LOAD_ADDR FCARG1x, ht - if (opline->op1_type != IS_CONST) { - | GET_ZVAL_PTR FCARG2x, op1_addr, TMP1 - | EXT_CALL zend_hash_find, REG0 - } else { - zend_string *str = Z_STR_P(RT_CONSTANT(opline, opline->op1)); - | LOAD_ADDR FCARG2x, str - | EXT_CALL zend_hash_find_known_hash, REG0 - } - if (exit_addr) { - if (smart_branch_opcode == ZEND_JMPZ) { - | cbz RETVALx, &exit_addr - } else { - | cbnz RETVALx, &exit_addr - } - } else if (smart_branch_opcode) { - if (smart_branch_opcode == ZEND_JMPZ) { - | cbz RETVALx, =>target_label - } else if (smart_branch_opcode == ZEND_JMPNZ) { - | cbnz RETVALx, =>target_label - } else { - ZEND_UNREACHABLE(); - } - } else { - | tst RETVALx, RETVALx - | cset REG0w, ne - | add REG0w, REG0w, #IS_FALSE - | SET_ZVAL_TYPE_INFO_FROM_REG res_addr, REG0w, TMP1 - } - - return 1; -} - -static int zend_jit_rope(dasm_State **Dst, const zend_op *opline, uint32_t op2_info) -{ - uint32_t offset; - - offset = (opline->opcode == ZEND_ROPE_INIT) ? - opline->result.var : - opline->op1.var + opline->extended_value * sizeof(zend_string*); - - if (opline->op2_type == IS_CONST) { - zval *zv = RT_CONSTANT(opline, opline->op2); - zend_string *str; - - ZEND_ASSERT(Z_TYPE_P(zv) == IS_STRING); - str = Z_STR_P(zv); - | LOAD_ADDR REG0, str - | MEM_ACCESS_64_WITH_UOFFSET str, REG0, FP, offset, TMP1 - } else { - zend_jit_addr op2_addr = OP2_ADDR(); - - ZEND_ASSERT((op2_info & (MAY_BE_UNDEF|MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_STRING); - - | GET_ZVAL_PTR REG1, op2_addr, TMP1 - | MEM_ACCESS_64_WITH_UOFFSET str, REG1, FP, offset, TMP1 - if (opline->op2_type == IS_CV) { - | GET_ZVAL_TYPE_INFO REG0w, op2_addr, TMP1 - | TRY_ADDREF op2_info, REG0w, REG1, TMP1w - } - } - - if (opline->opcode == ZEND_ROPE_END) { - zend_jit_addr res_addr = RES_ADDR(); - - | ADD_SUB_64_WITH_CONST add, FCARG1x, FP, opline->op1.var, TMP1 - | LOAD_32BIT_VAL FCARG2w, opline->extended_value - | EXT_CALL zend_jit_rope_end, TMP1 - | SET_ZVAL_PTR res_addr, RETVALx, TMP1 - | SET_ZVAL_TYPE_INFO res_addr, IS_STRING_EX, TMP1w, TMP2 - } - - return 1; -} - -static bool zend_jit_noref_guard(dasm_State **Dst, const zend_op *opline, zend_jit_addr var_addr) -{ - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr, ZREG_TMP1 - - return 1; -} - -static bool zend_jit_fetch_reference(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_ref_guard, bool add_type_guard) -{ - zend_jit_addr var_addr = *var_addr_ptr; - uint32_t var_info = *var_info_ptr; - const void *exit_addr = NULL; - - if (add_ref_guard || add_type_guard) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - if (!exit_addr) { - return 0; - } - } - - if (add_ref_guard) { - | IF_NOT_ZVAL_TYPE var_addr, IS_REFERENCE, &exit_addr, ZREG_TMP1 - } - if (opline->opcode == ZEND_INIT_METHOD_CALL && opline->op1_type == IS_VAR) { - /* Hack: Convert reference to regular value to simplify JIT code for INIT_METHOD_CALL */ - if (Z_REG(var_addr) != ZREG_FCARG1 || Z_OFFSET(var_addr) != 0) { - | LOAD_ZVAL_ADDR FCARG1x, var_addr - } - | EXT_CALL zend_jit_unref_helper, REG0 - } else { - | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, offsetof(zend_reference, val)); - *var_addr_ptr = var_addr; - } - - if (var_type != IS_UNKNOWN) { - var_type &= ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED); - } - if (add_type_guard - && var_type != IS_UNKNOWN - && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) { - | IF_NOT_ZVAL_TYPE var_addr, var_type, &exit_addr, ZREG_TMP1 - - ZEND_ASSERT(var_info & (1 << var_type)); - if (var_type < IS_STRING) { - var_info = (1 << var_type); - } else if (var_type != IS_ARRAY) { - var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN)); - } else { - var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN)); - } - - *var_info_ptr = var_info; - } else { - var_info &= ~MAY_BE_REF; - *var_info_ptr = var_info; - } - *var_info_ptr |= MAY_BE_GUARD; /* prevent generation of specialized zval dtor */ - - return 1; -} - -static bool zend_jit_fetch_indirect_var(dasm_State **Dst, const zend_op *opline, uint8_t var_type, uint32_t *var_info_ptr, zend_jit_addr *var_addr_ptr, bool add_indirect_guard) -{ - zend_jit_addr var_addr = *var_addr_ptr; - uint32_t var_info = *var_info_ptr; - int32_t exit_point; - const void *exit_addr; - - if (add_indirect_guard) { - int32_t exit_point = zend_jit_trace_get_exit_point(opline, 0); - const void *exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - | IF_NOT_ZVAL_TYPE var_addr, IS_INDIRECT, &exit_addr, ZREG_TMP1 - | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 - } else { - /* May be already loaded into FCARG1a or RAX by previous FETCH_OBJ_W/DIM_W */ - if (opline->op1_type != IS_VAR || - (opline-1)->result_type != IS_VAR || - (opline-1)->result.var != opline->op1.var || - (opline-1)->op2_type == IS_VAR || - (opline-1)->op2_type == IS_TMP_VAR) { - | GET_ZVAL_PTR FCARG1x, var_addr, TMP1 - } else if ((opline-1)->opcode == ZEND_FETCH_DIM_W || (opline-1)->opcode == ZEND_FETCH_DIM_RW) { - | mov FCARG1x, REG0 - } - } - *var_info_ptr &= ~MAY_BE_INDIRECT; - var_addr = ZEND_ADDR_MEM_ZVAL(ZREG_FCARG1, 0); - *var_addr_ptr = var_addr; - - if (var_type != IS_UNKNOWN) { - var_type &= ~(IS_TRACE_INDIRECT|IS_TRACE_PACKED); - } - if (!(var_type & IS_TRACE_REFERENCE) - && var_type != IS_UNKNOWN - && (var_info & (MAY_BE_ANY|MAY_BE_UNDEF)) != (1 << var_type)) { - exit_point = zend_jit_trace_get_exit_point(opline, 0); - exit_addr = zend_jit_trace_get_exit_addr(exit_point); - - if (!exit_addr) { - return 0; - } - - | IF_NOT_Z_TYPE FCARG1x, var_type, &exit_addr, TMP1w - - //var_info = zend_jit_trace_type_to_info_ex(var_type, var_info); - ZEND_ASSERT(var_info & (1 << var_type)); - if (var_type < IS_STRING) { - var_info = (1 << var_type); - } else if (var_type != IS_ARRAY) { - var_info = (1 << var_type) | (var_info & (MAY_BE_RC1|MAY_BE_RCN)); - } else { - var_info = MAY_BE_ARRAY | (var_info & (MAY_BE_ARRAY_OF_ANY|MAY_BE_ARRAY_OF_REF|MAY_BE_ARRAY_KEY_ANY|MAY_BE_RC1|MAY_BE_RCN)); - } - - *var_info_ptr = var_info; - } - - return 1; -} - -static bool zend_jit_may_reuse_reg(const zend_op *opline, const zend_ssa_op *ssa_op, zend_ssa *ssa, int def_var, int use_var) -{ - if ((ssa->var_info[def_var].type & ~MAY_BE_GUARD) != (ssa->var_info[use_var].type & ~MAY_BE_GUARD)) { - return 0; - } - - switch (opline->opcode) { - case ZEND_QM_ASSIGN: - case ZEND_SEND_VAR: - case ZEND_ASSIGN: - case ZEND_PRE_INC: - case ZEND_PRE_DEC: - case ZEND_POST_INC: - case ZEND_POST_DEC: - return 1; - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - case ZEND_SL: - case ZEND_SR: - if (def_var == ssa_op->result_def && - use_var == ssa_op->op1_use) { - return 1; - } - break; - default: - break; - } - return 0; -} - -static bool zend_jit_opline_supports_reg(const zend_op_array *op_array, zend_ssa *ssa, const zend_op *opline, const zend_ssa_op *ssa_op, zend_jit_trace_rec *trace) -{ - uint32_t op1_info, op2_info; - - switch (opline->opcode) { - case ZEND_SEND_VAR: - case ZEND_SEND_VAL: - case ZEND_SEND_VAL_EX: - return (opline->op2_type != IS_CONST); - case ZEND_QM_ASSIGN: - case ZEND_IS_SMALLER: - case ZEND_IS_SMALLER_OR_EQUAL: - case ZEND_IS_EQUAL: - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_IS_NOT_IDENTICAL: - case ZEND_CASE: - return 1; - case ZEND_RETURN: - return (op_array->type != ZEND_EVAL_CODE && op_array->function_name); - case ZEND_ASSIGN: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - return - opline->op1_type == IS_CV && - !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_RESOURCE|MAY_BE_OBJECT|MAY_BE_REF)) && - !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))); - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - (MAY_BE_LONG|MAY_BE_DOUBLE))); - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - case ZEND_SL: - case ZEND_SR: - case ZEND_MOD: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - return !((op1_info | op2_info) & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG)); - case ZEND_PRE_INC: - case ZEND_PRE_DEC: - case ZEND_POST_INC: - case ZEND_POST_DEC: - op1_info = OP1_INFO(); - op2_info = OP1_DEF_INFO(); - return opline->op1_type == IS_CV - && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF) - MAY_BE_LONG)) - && (op2_info & MAY_BE_LONG); - case ZEND_STRLEN: - op1_info = OP1_INFO(); - return (opline->op1_type & (IS_CV|IS_CONST)) - && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_STRING; - case ZEND_COUNT: - op1_info = OP1_INFO(); - return (opline->op1_type & (IS_CV|IS_CONST)) - && (op1_info & (MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)) == MAY_BE_ARRAY; - case ZEND_JMPZ: - case ZEND_JMPNZ: - if (JIT_G(trigger) != ZEND_JIT_ON_HOT_TRACE) { - if (!ssa->cfg.map) { - return 0; - } - if (opline > op_array->opcodes + ssa->cfg.blocks[ssa->cfg.map[opline-op_array->opcodes]].start && - ((opline-1)->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ)) != 0) { - return 0; - } - } - ZEND_FALLTHROUGH; - case ZEND_BOOL: - case ZEND_BOOL_NOT: - case ZEND_JMPZ_EX: - case ZEND_JMPNZ_EX: - return 1; - case ZEND_FETCH_CONSTANT: - return 1; - case ZEND_FETCH_DIM_R: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (trace - && trace->op1_type != IS_UNKNOWN - && (trace->op1_type & ~(IS_TRACE_REFERENCE|IS_TRACE_INDIRECT|IS_TRACE_PACKED)) == IS_ARRAY) { - op1_info &= ~((MAY_BE_ANY|MAY_BE_UNDEF) - MAY_BE_ARRAY); - } - return ((op1_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_ARRAY) && - (!(opline->op1_type & (IS_TMP_VAR|IS_VAR)) || !(op1_info & MAY_BE_RC1)) && - (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_LONG) || - (((op2_info & (MAY_BE_ANY|MAY_BE_UNDEF)) == MAY_BE_STRING) && - (!(opline->op2_type & (IS_TMP_VAR|IS_VAR)) || !(op2_info & MAY_BE_RC1)))); - } - return 0; -} - -static bool zend_jit_var_supports_reg(zend_ssa *ssa, int var) -{ - if (ssa->vars[var].no_val) { - /* we don't need the value */ - return 0; - } - - if (!(JIT_G(opt_flags) & ZEND_JIT_REG_ALLOC_GLOBAL)) { - /* Disable global register allocation, - * register allocation for SSA variables connected through Phi functions - */ - if (ssa->vars[var].definition_phi) { - return 0; - } - if (ssa->vars[var].phi_use_chain) { - zend_ssa_phi *phi = ssa->vars[var].phi_use_chain; - do { - if (!ssa->vars[phi->ssa_var].no_val) { - return 0; - } - phi = zend_ssa_next_use_phi(ssa, var, phi); - } while (phi); - } - } - - if (((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_DOUBLE) && - ((ssa->var_info[var].type & (MAY_BE_ANY|MAY_BE_UNDEF|MAY_BE_REF)) != MAY_BE_LONG)) { - /* bad type */ - return 0; - } - - return 1; -} - -static bool zend_jit_may_be_in_reg(const zend_op_array *op_array, zend_ssa *ssa, int var) -{ - if (!zend_jit_var_supports_reg(ssa, var)) { - return 0; - } - - if (ssa->vars[var].definition >= 0) { - uint32_t def = ssa->vars[var].definition; - if (!zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + def, ssa->ops + def, NULL)) { - return 0; - } - } - - if (ssa->vars[var].use_chain >= 0) { - int use = ssa->vars[var].use_chain; - - do { - if (!zend_ssa_is_no_val_use(op_array->opcodes + use, ssa->ops + use, var) && - !zend_jit_opline_supports_reg(op_array, ssa, op_array->opcodes + use, ssa->ops + use, NULL)) { - return 0; - } - use = zend_ssa_next_use(ssa->ops, var, use); - } while (use >= 0); - } - - return 1; -} - -static zend_regset zend_jit_get_def_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, bool last_use) -{ - uint32_t op1_info, op2_info; - - switch (opline->opcode) { - case ZEND_FETCH_DIM_R: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (((opline->op1_type & (IS_TMP_VAR|IS_VAR)) && - (op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE))) || - ((opline->op2_type & (IS_TMP_VAR|IS_VAR)) && - (op2_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE)))) { - return ZEND_REGSET(ZREG_FCARG1); - } - break; - default: - break; - } - - return ZEND_REGSET_EMPTY; -} - -static zend_regset zend_jit_get_scratch_regset(const zend_op *opline, const zend_ssa_op *ssa_op, const zend_op_array *op_array, zend_ssa *ssa, int current_var, bool last_use) -{ - uint32_t op1_info, op2_info, res_info; - zend_regset regset = ZEND_REGSET_SCRATCH; - - switch (opline->opcode) { - case ZEND_NOP: - case ZEND_OP_DATA: - case ZEND_JMP: - case ZEND_RETURN: - regset = ZEND_REGSET_EMPTY; - break; - case ZEND_QM_ASSIGN: - if (ssa_op->op1_def == current_var || - ssa_op->result_def == current_var) { - regset = ZEND_REGSET_EMPTY; - break; - } - /* break missing intentionally */ - case ZEND_SEND_VAL: - case ZEND_SEND_VAL_EX: - if (opline->op2_type == IS_CONST) { - break; - } - if (ssa_op->op1_use == current_var) { - regset = ZEND_REGSET(ZREG_REG0); - break; - } - op1_info = OP1_INFO(); - if (!(op1_info & MAY_BE_UNDEF)) { - if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) { - regset = ZEND_REGSET(ZREG_FPR0); - } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) { - regset = ZEND_REGSET(ZREG_REG0); - } else { - regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2)); - } - } - break; - case ZEND_SEND_VAR: - if (opline->op2_type == IS_CONST) { - break; - } - if (ssa_op->op1_use == current_var || - ssa_op->op1_def == current_var) { - regset = ZEND_REGSET_EMPTY; - break; - } - op1_info = OP1_INFO(); - if (!(op1_info & MAY_BE_UNDEF)) { - if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) { - regset = ZEND_REGSET(ZREG_FPR0); - } else if ((op1_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) { - } else { - regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2)); - if (op1_info & MAY_BE_REF) { - ZEND_REGSET_INCL(regset, ZREG_REG1); - } - } - } - break; - case ZEND_ASSIGN: - if (ssa_op->op2_use == current_var || - ssa_op->op2_def == current_var || - ssa_op->op1_def == current_var || - ssa_op->result_def == current_var) { - regset = ZEND_REGSET_EMPTY; - break; - } - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (opline->op1_type == IS_CV - && !(op2_info & MAY_BE_UNDEF) - && !(op1_info & (MAY_BE_STRING|MAY_BE_ARRAY|MAY_BE_OBJECT|MAY_BE_RESOURCE|MAY_BE_REF))) { - if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_DOUBLE) { - regset = ZEND_REGSET(ZREG_FPR0); - } else if ((op2_info & (MAY_BE_ANY|MAY_BE_REF)) == MAY_BE_LONG) { - regset = ZEND_REGSET(ZREG_REG0); - } else { - regset = ZEND_REGSET_UNION(ZEND_REGSET(ZREG_REG0), ZEND_REGSET(ZREG_REG2)); - } - } - break; - case ZEND_PRE_INC: - case ZEND_PRE_DEC: - case ZEND_POST_INC: - case ZEND_POST_DEC: - if (ssa_op->op1_use == current_var || - ssa_op->op1_def == current_var || - ssa_op->result_def == current_var) { - regset = ZEND_REGSET_EMPTY; - break; - } - op1_info = OP1_INFO(); - if (opline->op1_type == IS_CV - && (op1_info & MAY_BE_LONG) - && !(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) { - regset = ZEND_REGSET_EMPTY; - if (op1_info & MAY_BE_DOUBLE) { - regset = ZEND_REGSET(ZREG_FPR0); - } - if (opline->result_type != IS_UNUSED && (op1_info & MAY_BE_LONG)) { - ZEND_REGSET_INCL(regset, ZREG_REG1); - } - } - break; - case ZEND_ADD: - case ZEND_SUB: - case ZEND_MUL: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) && - !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) { - - regset = ZEND_REGSET_EMPTY; - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG)) { - if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !last_use)) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - res_info = RES_INFO(); - if (res_info & MAY_BE_DOUBLE) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - ZEND_REGSET_INCL(regset, ZREG_FPR0); - ZEND_REGSET_INCL(regset, ZREG_FPR1); - } else if (res_info & MAY_BE_GUARD) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - } - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) { - if (ssa_op->result_def != current_var) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - } - if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) { - if (zend_is_commutative(opline->opcode)) { - if (ssa_op->result_def != current_var) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - } else { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !last_use)) { - ZEND_REGSET_INCL(regset, ZREG_FPR1); - } - } - } - if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) { - if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !last_use) && - (!zend_is_commutative(opline->opcode) || ssa_op->op2_use != current_var || !last_use)) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - } - } - break; - case ZEND_BW_OR: - case ZEND_BW_AND: - case ZEND_BW_XOR: - case ZEND_SL: - case ZEND_SR: - case ZEND_MOD: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG)) && - !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-MAY_BE_LONG))) { - regset = ZEND_REGSET_EMPTY; - if (ssa_op->result_def != current_var && - (ssa_op->op1_use != current_var || !last_use)) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - } - break; - case ZEND_IS_SMALLER: - case ZEND_IS_SMALLER_OR_EQUAL: - case ZEND_IS_EQUAL: - case ZEND_IS_NOT_EQUAL: - case ZEND_IS_IDENTICAL: - case ZEND_IS_NOT_IDENTICAL: - case ZEND_CASE: - op1_info = OP1_INFO(); - op2_info = OP2_INFO(); - if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE))) && - !(op2_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_LONG|MAY_BE_DOUBLE)))) { - regset = ZEND_REGSET_EMPTY; - if (!(opline->result_type & (IS_SMART_BRANCH_JMPZ|IS_SMART_BRANCH_JMPNZ))) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_LONG) && - opline->op1_type != IS_CONST && opline->op2_type != IS_CONST) { - if (ssa_op->op1_use != current_var && - ssa_op->op2_use != current_var) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - } - if ((op1_info & MAY_BE_LONG) && (op2_info & MAY_BE_DOUBLE)) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_LONG)) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - if ((op1_info & MAY_BE_DOUBLE) && (op2_info & MAY_BE_DOUBLE)) { - if (ssa_op->op1_use != current_var && - ssa_op->op2_use != current_var) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - } - } - break; - case ZEND_BOOL: - case ZEND_BOOL_NOT: - case ZEND_JMPZ: - case ZEND_JMPNZ: - case ZEND_JMPZ_EX: - case ZEND_JMPNZ_EX: - op1_info = OP1_INFO(); - if (!(op1_info & ((MAY_BE_ANY|MAY_BE_REF|MAY_BE_UNDEF)-(MAY_BE_NULL|MAY_BE_FALSE|MAY_BE_TRUE|MAY_BE_LONG|MAY_BE_DOUBLE)))) { - regset = ZEND_REGSET_EMPTY; - if (op1_info & MAY_BE_DOUBLE) { - ZEND_REGSET_INCL(regset, ZREG_FPR0); - } - if (opline->opcode == ZEND_BOOL || - opline->opcode == ZEND_BOOL_NOT || - opline->opcode == ZEND_JMPZ_EX || - opline->opcode == ZEND_JMPNZ_EX) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - } - } - break; - case ZEND_DO_UCALL: - case ZEND_DO_FCALL: - case ZEND_DO_FCALL_BY_NAME: - case ZEND_INCLUDE_OR_EVAL: - case ZEND_GENERATOR_CREATE: - case ZEND_YIELD: - case ZEND_YIELD_FROM: - regset = ZEND_REGSET_UNION(ZEND_REGSET_GP, ZEND_REGSET_FP); - break; - default: - break; - } - - if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE) { - if (ssa_op == ssa->ops - && JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].op == ZEND_JIT_TRACE_INIT_CALL - && (JIT_G(current_trace)[ZEND_JIT_TRACE_START_REC_SIZE].info & ZEND_JIT_TRACE_FAKE_INIT_CALL)) { - ZEND_REGSET_INCL(regset, ZREG_REG0); - ZEND_REGSET_INCL(regset, ZREG_REG1); - } - } - - return regset; -} - -static size_t dasm_venners_size = 0; -void **dasm_labels_veneers = NULL; - -static int zend_jit_add_veneer(dasm_State *Dst, void *buffer, uint32_t ins, int *b, uint32_t *cp, ptrdiff_t offset) -{ - void *veneer; - ptrdiff_t na; - int n, m; - - /* try to reuse veneers for global labels */ - if ((ins >> 16) == DASM_REL_LG - && *(b-1) < 0 - && dasm_labels_veneers[-*(b-1)]) { - - veneer = dasm_labels_veneers[-*(b-1)]; - na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4; - n = (int)na; - - /* check if we can jump to veneer */ - if ((ptrdiff_t)n != na) { - /* pass */ - } else if (!(ins & 0xf800)) { /* B, BL */ - if ((n & 3) == 0 && ((n+0x08000000) >> 28) == 0) { - return n; - } - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - if ((n & 3) == 0 && ((n+0x00100000) >> 21) == 0) { - return n; - } - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - /* pass */ - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - /* pass */ - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - if ((n & 3) == 0 && ((n+0x00008000) >> 16) == 0) { - return n; - } - } - } else if (JIT_G(trigger) == ZEND_JIT_ON_HOT_TRACE - && (ins >> 16) == DASM_REL_A) { - ptrdiff_t addr = (((ptrdiff_t)(*(b-1))) << 32) | (unsigned int)(*(b-2)); - - if ((void*)addr >= dasm_buf && (void*)addr < dasm_end) { - uint32_t exit_point = zend_jit_trace_find_exit_point((void*)addr); - zend_jit_trace_info *t = zend_jit_get_current_trace_info(); - - if (exit_point != (uint32_t)-1) { - /* Use exit points table */ - - ZEND_ASSERT(exit_point < t->exit_count); - - veneer = (char*)buffer + dasm_getpclabel(&Dst, 1) - (t->exit_count - exit_point) * 4; - na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4; - n = (int)na; - - /* check if we can jump to veneer */ - if ((ptrdiff_t)n != na) { - ZEND_ASSERT(0); - return 0; - } else if (!(ins & 0xf800)) { /* B, BL */ - if ((n & 3) != 0 || ((n+0x08000000) >> 28) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - if ((n & 3) != 0 || ((n+0x00100000) >> 21) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - ZEND_ASSERT(0); - return 0; - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - ZEND_ASSERT(0); - return 0; - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - if ((n & 3) != 0 || ((n+0x00008000) >> 16) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else { - ZEND_ASSERT(0); - return 0; - } - return n; - } - } - } - - veneer = (char*)buffer + (Dst->codesize + dasm_venners_size); - - if (veneer > dasm_end) { - return 0; /* jit_buffer_size overflow */ - } - - na = (ptrdiff_t)veneer - (ptrdiff_t)cp + 4; - n = (int)na; - - /* check if we can jump to veneer */ - if ((ptrdiff_t)n != na) { - ZEND_ASSERT(0); - return 0; - } else if (!(ins & 0xf800)) { /* B, BL */ - if ((n & 3) != 0 || ((n+0x08000000) >> 28) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else if ((ins & 0x800)) { /* B.cond, CBZ, CBNZ, LDR* literal */ - if ((n & 3) != 0 || ((n+0x00100000) >> 21) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else if ((ins & 0x3000) == 0x2000) { /* ADR */ - ZEND_ASSERT(0); - return 0; - } else if ((ins & 0x3000) == 0x3000) { /* ADRP */ - ZEND_ASSERT(0); - return 0; - } else if ((ins & 0x1000)) { /* TBZ, TBNZ */ - if ((n & 3) != 0 || ((n+0x00008000) >> 16) != 0) { - ZEND_ASSERT(0); - return 0; - } - } else if ((ins & 0x8000)) { /* absolute */ - ZEND_ASSERT(0); - return 0; - } else { - ZEND_ASSERT(0); - return 0; - } - - // TODO: support for long veneers (above 128MB) ??? - - /* check if we can use B to jump from veneer */ - na = (ptrdiff_t)cp + offset - (ptrdiff_t)veneer - 4; - m = (int)na; - if ((ptrdiff_t)m != na) { - ZEND_ASSERT(0); - return 0; - } else if ((m & 3) != 0 || ((m+0x08000000) >> 28) != 0) { - ZEND_ASSERT(0); - return 0; - } - - /* generate B instruction */ - *(uint32_t*)veneer = 0x14000000 | ((m >> 2) & 0x03ffffff); - dasm_venners_size += 4; - - if ((ins >> 16) == DASM_REL_LG - && *(b-1) < 0) { - /* reuse this veneer for the future jumps to global label */ - dasm_labels_veneers[-*(b-1)] = veneer; - /* Dst->globals[*(b-1)] = veneer; */ - -#ifdef HAVE_DISASM - if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM) { - const char *name = zend_jit_disasm_find_symbol((ptrdiff_t)cp + offset - 4, (int64_t *)(&offset)); - - if (name && !offset) { - if (strstr(name, "@veneer") == NULL) { - char *new_name; - - zend_spprintf(&new_name, 0, "%s@veneer", name); - zend_jit_disasm_add_symbol(new_name, (uint64_t)(uintptr_t)veneer, 4); - efree(new_name); - } else { - zend_jit_disasm_add_symbol(name, (uint64_t)(uintptr_t)veneer, 4); - } - } - } -#endif - } - - return n; -} - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * indent-tabs-mode: t - * End: - */ diff --git a/ext/opcache/jit/zend_jit_arm64.h b/ext/opcache/jit/zend_jit_arm64.h deleted file mode 100644 index 1924875f1be4b..0000000000000 --- a/ext/opcache/jit/zend_jit_arm64.h +++ /dev/null @@ -1,157 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Hao Sun | - +----------------------------------------------------------------------+ -*/ - -#ifndef HAVE_JIT_ARM64_H -#define HAVE_JIT_ARM64_H - -typedef enum _zend_reg { - ZREG_NONE = -1, - - ZREG_X0, - ZREG_X1, - ZREG_X2, - ZREG_X3, - ZREG_X4, - ZREG_X5, - ZREG_X6, - ZREG_X7, - ZREG_X8, - ZREG_X9, - ZREG_X10, - ZREG_X11, - ZREG_X12, - ZREG_X13, - ZREG_X14, - ZREG_X15, - ZREG_X16, - ZREG_X17, - ZREG_X18, - ZREG_X19, - ZREG_X20, - ZREG_X21, - ZREG_X22, - ZREG_X23, - ZREG_X24, - ZREG_X25, - ZREG_X26, - ZREG_X27, - ZREG_X28, - ZREG_X29, - ZREG_X30, - ZREG_X31, - - ZREG_V0, - ZREG_V1, - ZREG_V2, - ZREG_V3, - ZREG_V4, - ZREG_V5, - ZREG_V6, - ZREG_V7, - ZREG_V8, - ZREG_V9, - ZREG_V10, - ZREG_V11, - ZREG_V12, - ZREG_V13, - ZREG_V14, - ZREG_V15, - ZREG_V16, - ZREG_V17, - ZREG_V18, - ZREG_V19, - ZREG_V20, - ZREG_V21, - ZREG_V22, - ZREG_V23, - ZREG_V24, - ZREG_V25, - ZREG_V26, - ZREG_V27, - ZREG_V28, - ZREG_V29, - ZREG_V30, - ZREG_V31, - - ZREG_NUM, - - ZREG_THIS, /* used for delayed FETCH_THIS deoptimization */ - - /* pseudo constants used by deoptimizer */ - ZREG_LONG_MIN_MINUS_1, - ZREG_LONG_MIN, - ZREG_LONG_MAX, - ZREG_LONG_MAX_PLUS_1, - ZREG_NULL, - - ZREG_ZVAL_TRY_ADDREF, - ZREG_ZVAL_COPY_GPR0, -} zend_reg; - -typedef struct _zend_jit_registers_buf { - uint64_t gpr[32]; /* general purpose integer register */ - double fpr[32]; /* floating point registers */ -} zend_jit_registers_buf; - -#define ZREG_RSP ZREG_X31 -#define ZREG_RLR ZREG_X30 -#define ZREG_RFP ZREG_X29 -#define ZREG_RPR ZREG_X18 - -#define ZREG_FP ZREG_X27 -#define ZREG_IP ZREG_X28 -#define ZREG_RX ZREG_IP - -#define ZREG_REG0 ZREG_X8 -#define ZREG_REG1 ZREG_X9 -#define ZREG_REG2 ZREG_X10 - -#define ZREG_FPR0 ZREG_V0 -#define ZREG_FPR1 ZREG_V1 - -#define ZREG_TMP1 ZREG_X15 -#define ZREG_TMP2 ZREG_X16 -#define ZREG_TMP3 ZREG_X17 -#define ZREG_FPTMP ZREG_V16 - -#define ZREG_COPY ZREG_REG0 -#define ZREG_FIRST_FPR ZREG_V0 - -typedef uint64_t zend_regset; - -#define ZEND_REGSET_64BIT 1 - -# define ZEND_REGSET_FIXED \ - (ZEND_REGSET(ZREG_RSP) | ZEND_REGSET(ZREG_RLR) | ZEND_REGSET(ZREG_RFP) | \ - ZEND_REGSET(ZREG_RPR) | ZEND_REGSET(ZREG_FP) | ZEND_REGSET(ZREG_IP) | \ - ZEND_REGSET_INTERVAL(ZREG_TMP1, ZREG_TMP3) | ZEND_REGSET(ZREG_FPTMP)) -# define ZEND_REGSET_GP \ - ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_X0, ZREG_X30), ZEND_REGSET_FIXED) -# define ZEND_REGSET_FP \ - ZEND_REGSET_DIFFERENCE(ZEND_REGSET_INTERVAL(ZREG_V0, ZREG_V31), ZEND_REGSET_FIXED) -# define ZEND_REGSET_SCRATCH \ - (ZEND_REGSET_INTERVAL(ZREG_X0, ZREG_X17) | ZEND_REGSET_INTERVAL(ZREG_V0, ZREG_V7) | \ - ZEND_REGSET_INTERVAL(ZREG_V16, ZREG_V31)) -# define ZEND_REGSET_PRESERVED \ - (ZEND_REGSET_INTERVAL(ZREG_X19, ZREG_X28) | ZEND_REGSET_INTERVAL(ZREG_V8, ZREG_V15)) - -#define ZEND_REGSET_LOW_PRIORITY \ - (ZEND_REGSET(ZREG_REG0) | ZEND_REGSET(ZREG_REG1) | ZEND_REGSET(ZREG_FPR0) | ZEND_REGSET(ZREG_FPR1)) - -#endif /* ZEND_JIT_ARM64_H */ diff --git a/ext/opcache/jit/zend_jit_disasm.c b/ext/opcache/jit/zend_jit_disasm.c deleted file mode 100644 index 41b75979c515d..0000000000000 --- a/ext/opcache/jit/zend_jit_disasm.c +++ /dev/null @@ -1,781 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Xinchen Hui | - | Hao Sun | - +----------------------------------------------------------------------+ -*/ - - -#ifdef HAVE_CAPSTONE -# define HAVE_DISASM 1 -# include -# define HAVE_CAPSTONE_ITER 1 -#elif ZEND_JIT_TARGET_X86 -# define HAVE_DISASM 1 -# define DISASM_INTEL_SYNTAX 0 - -# include "jit/libudis86/itab.c" -# include "jit/libudis86/decode.c" -# include "jit/libudis86/syn.c" -# if DISASM_INTEL_SYNTAX -# include "jit/libudis86/syn-intel.c" -# else -# include "jit/libudis86/syn-att.c" -# endif -# include "jit/libudis86/udis86.c" -#endif /* HAVE_CAPSTONE */ - -#ifdef HAVE_DISASM - -static void zend_jit_disasm_add_symbol(const char *name, - uint64_t addr, - uint64_t size); - -#ifndef _WIN32 -# include "jit/zend_elf.c" -#endif - -#include "zend_sort.h" - -#ifndef _GNU_SOURCE -# define _GNU_SOURCE -#endif - -#ifndef _WIN32 -#include -#endif - -struct _sym_node { - uint64_t addr; - uint64_t end; - struct _sym_node *parent; - struct _sym_node *child[2]; - unsigned char info; - char name[1]; -}; - -static void zend_syms_rotateleft(zend_sym_node *p) { - zend_sym_node *r = p->child[1]; - p->child[1] = r->child[0]; - if (r->child[0]) { - r->child[0]->parent = p; - } - r->parent = p->parent; - if (p->parent == NULL) { - JIT_G(symbols) = r; - } else if (p->parent->child[0] == p) { - p->parent->child[0] = r; - } else { - p->parent->child[1] = r; - } - r->child[0] = p; - p->parent = r; -} - -static void zend_syms_rotateright(zend_sym_node *p) { - zend_sym_node *l = p->child[0]; - p->child[0] = l->child[1]; - if (l->child[1]) { - l->child[1]->parent = p; - } - l->parent = p->parent; - if (p->parent == NULL) { - JIT_G(symbols) = l; - } else if (p->parent->child[1] == p) { - p->parent->child[1] = l; - } else { - p->parent->child[0] = l; - } - l->child[1] = p; - p->parent = l; -} - -static void zend_jit_disasm_add_symbol(const char *name, - uint64_t addr, - uint64_t size) -{ - zend_sym_node *sym; - size_t len = strlen(name); - - sym = malloc(sizeof(zend_sym_node) + len + 1); - if (!sym) { - return; - } - sym->addr = addr; - sym->end = (addr + size - 1); - memcpy((char*)&sym->name, name, len + 1); - sym->parent = sym->child[0] = sym->child[1] = NULL; - sym->info = 1; - if (JIT_G(symbols)) { - zend_sym_node *node = JIT_G(symbols); - - /* insert it into rbtree */ - do { - if (sym->addr > node->addr) { - ZEND_ASSERT(sym->addr > (node->end)); - if (node->child[1]) { - node = node->child[1]; - } else { - node->child[1] = sym; - sym->parent = node; - break; - } - } else if (sym->addr < node->addr) { - if (node->child[0]) { - node = node->child[0]; - } else { - node->child[0] = sym; - sym->parent = node; - break; - } - } else { - ZEND_ASSERT(sym->addr == node->addr); - if (strcmp(name, node->name) == 0 && sym->end < node->end) { - /* reduce size of the existing symbol */ - node->end = sym->end; - } - free(sym); - return; - } - } while (1); - - /* fix rbtree after instering */ - while (sym && sym != JIT_G(symbols) && sym->parent->info == 1) { - if (sym->parent == sym->parent->parent->child[0]) { - node = sym->parent->parent->child[1]; - if (node && node->info == 1) { - sym->parent->info = 0; - node->info = 0; - sym->parent->parent->info = 1; - sym = sym->parent->parent; - } else { - if (sym == sym->parent->child[1]) { - sym = sym->parent; - zend_syms_rotateleft(sym); - } - sym->parent->info = 0; - sym->parent->parent->info = 1; - zend_syms_rotateright(sym->parent->parent); - } - } else { - node = sym->parent->parent->child[0]; - if (node && node->info == 1) { - sym->parent->info = 0; - node->info = 0; - sym->parent->parent->info = 1; - sym = sym->parent->parent; - } else { - if (sym == sym->parent->child[0]) { - sym = sym->parent; - zend_syms_rotateright(sym); - } - sym->parent->info = 0; - sym->parent->parent->info = 1; - zend_syms_rotateleft(sym->parent->parent); - } - } - } - } else { - JIT_G(symbols) = sym; - } - JIT_G(symbols)->info = 0; -} - -static void zend_jit_disasm_destroy_symbols(zend_sym_node *n) { - if (n) { - if (n->child[0]) { - zend_jit_disasm_destroy_symbols(n->child[0]); - } - if (n->child[1]) { - zend_jit_disasm_destroy_symbols(n->child[1]); - } - free(n); - } -} - -static const char* zend_jit_disasm_find_symbol(uint64_t addr, - int64_t *offset) { - zend_sym_node *node = JIT_G(symbols); - while (node) { - if (addr < node->addr) { - node = node->child[0]; - } else if (addr > node->end) { - node = node->child[1]; - } else { - *offset = addr - node->addr; - return node->name; - } - } - return NULL; -} - -#ifdef HAVE_CAPSTONE -static uint64_t zend_jit_disasm_branch_target(csh cs, const cs_insn *insn) -{ - unsigned int i; - -#if ZEND_JIT_TARGET_X86 - if (cs_insn_group(cs, insn, X86_GRP_JUMP)) { - for (i = 0; i < insn->detail->x86.op_count; i++) { - if (insn->detail->x86.operands[i].type == X86_OP_IMM) { - return insn->detail->x86.operands[i].imm; - } - } - } -#elif ZEND_JIT_TARGET_ARM64 - if (cs_insn_group(cs, insn, ARM64_GRP_JUMP) - || insn->id == ARM64_INS_BL - || insn->id == ARM64_INS_ADR) { - for (i = 0; i < insn->detail->arm64.op_count; i++) { - if (insn->detail->arm64.operands[i].type == ARM64_OP_IMM) - return insn->detail->arm64.operands[i].imm; - } - } -#endif - - return 0; -} -#endif - -static const char* zend_jit_disasm_resolver( -#ifndef HAVE_CAPSTONE - struct ud *ud, -#endif - uint64_t addr, - int64_t *offset) -{ -#ifndef _WIN32 -# ifndef HAVE_CAPSTONE - ((void)ud); -# endif - const char *name; - void *a = (void*)(uintptr_t)(addr); - Dl_info info; - - name = zend_jit_disasm_find_symbol(addr, offset); - if (name) { - return name; - } - - if (dladdr(a, &info) - && info.dli_sname != NULL - && info.dli_saddr == a) { - return info.dli_sname; - } -#else - const char *name; - name = zend_jit_disasm_find_symbol(addr, offset); - if (name) { - return name; - } -#endif - - return NULL; -} - -static int zend_jit_cmp_labels(Bucket *b1, Bucket *b2) -{ - return ((b1->h > b2->h) > 0) ? 1 : -1; -} - -static int zend_jit_disasm(const char *name, - const char *filename, - const zend_op_array *op_array, - zend_cfg *cfg, - const void *start, - size_t size) -{ - const void *end = (void *)((char *)start + size); - zval zv, *z; - zend_long n, m; - HashTable labels; - uint64_t addr; - int b; -#ifdef HAVE_CAPSTONE - csh cs; - cs_insn *insn; -# ifdef HAVE_CAPSTONE_ITER - const uint8_t *cs_code; - size_t cs_size; - uint64_t cs_addr; -# else - size_t count, i; -# endif - const char *sym; - int64_t offset = 0; - char *p, *q, *r; -#else - struct ud ud; - const struct ud_operand *op; -#endif - -#ifdef HAVE_CAPSTONE -# if ZEND_JIT_TARGET_X86 -# if defined(__x86_64__) || defined(_WIN64) - if (cs_open(CS_ARCH_X86, CS_MODE_64, &cs) != CS_ERR_OK) - return 0; -# else - if (cs_open(CS_ARCH_X86, CS_MODE_32, &cs) != CS_ERR_OK) - return 0; -# endif - cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON); -# if DISASM_INTEL_SYNTAX - cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_INTEL); -# else - cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); -# endif -# elif ZEND_JIT_TARGET_ARM64 - if (cs_open(CS_ARCH_ARM64, CS_MODE_ARM, &cs) != CS_ERR_OK) - return 0; - cs_option(cs, CS_OPT_DETAIL, CS_OPT_ON); - cs_option(cs, CS_OPT_SYNTAX, CS_OPT_SYNTAX_ATT); -# endif -#else - ud_init(&ud); -# if defined(__x86_64__) || defined(_WIN64) - ud_set_mode(&ud, 64); -# else - ud_set_mode(&ud, 32); -# endif -# if DISASM_INTEL_SYNTAX - ud_set_syntax(&ud, UD_SYN_INTEL); -# else - ud_set_syntax(&ud, UD_SYN_ATT); -# endif - ud_set_sym_resolver(&ud, zend_jit_disasm_resolver); -#endif /* HAVE_CAPSTONE */ - - if (name) { - fprintf(stderr, "%s: ; (%s)\n", name, filename ? filename : "unknown"); - } - -#ifndef HAVE_CAPSTONE - ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start); - ud_set_pc(&ud, (uint64_t)(uintptr_t)start); -#endif - - zend_hash_init(&labels, 8, NULL, NULL, 0); - if (op_array && cfg) { - ZVAL_FALSE(&zv); - for (b = 0; b < cfg->blocks_count; b++) { - if (cfg->blocks[b].flags & (ZEND_BB_ENTRY|ZEND_BB_RECV_ENTRY)) { - addr = (uint64_t)(uintptr_t)op_array->opcodes[cfg->blocks[b].start].handler; - if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) { - zend_hash_index_add(&labels, addr, &zv); - } - } - } - } -#ifdef HAVE_CAPSTONE - ZVAL_TRUE(&zv); -# ifdef HAVE_CAPSTONE_ITER - cs_code = start; - cs_size = (uint8_t*)end - (uint8_t*)start; - cs_addr = (uint64_t)(uintptr_t)cs_code; - insn = cs_malloc(cs); - while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) { - if ((addr = zend_jit_disasm_branch_target(cs, insn))) { -# else - count = cs_disasm(cs, start, (uint8_t*)end - (uint8_t*)start, (uintptr_t)start, 0, &insn); - for (i = 0; i < count; i++) { - if ((addr = zend_jit_disasm_branch_target(cs, &(insn[i])))) { -# endif - if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) { - zend_hash_index_add(&labels, addr, &zv); - } - } - } -#else - ZVAL_TRUE(&zv); - while (ud_disassemble(&ud)) { - op = ud_insn_opr(&ud, 0); - if (op && op->type == UD_OP_JIMM) { - addr = ud_syn_rel_target(&ud, (struct ud_operand*)op); - if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) { - zend_hash_index_add(&labels, addr, &zv); - } - } - } -#endif - - zend_hash_sort(&labels, zend_jit_cmp_labels, 0); - - /* label numbering */ - n = 0; m = 0; - ZEND_HASH_MAP_FOREACH_VAL(&labels, z) { - if (Z_TYPE_P(z) == IS_FALSE) { - m--; - ZVAL_LONG(z, m); - } else { - n++; - ZVAL_LONG(z, n); - } - } ZEND_HASH_FOREACH_END(); - -#ifdef HAVE_CAPSTONE -# ifdef HAVE_CAPSTONE_ITER - cs_code = start; - cs_size = (uint8_t*)end - (uint8_t*)start; - cs_addr = (uint64_t)(uintptr_t)cs_code; - while (cs_disasm_iter(cs, &cs_code, &cs_size, &cs_addr, insn)) { - z = zend_hash_index_find(&labels, insn->address); -# else - for (i = 0; i < count; i++) { - z = zend_hash_index_find(&labels, insn[i].address); -# endif - if (z) { - if (Z_LVAL_P(z) < 0) { - fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z)); - } else { - fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z)); - } - } - -# ifdef HAVE_CAPSTONE_ITER - if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) { - fprintf(stderr, " %" PRIx64 ":", insn->address); - } - fprintf(stderr, "\t%s ", insn->mnemonic); - p = insn->op_str; -# else - if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) { - fprintf(stderr, " %" PRIx64 ":", insn[i].address); - } - fprintf(stderr, "\t%s ", insn[i].mnemonic); - p = insn[i].op_str; -# endif - /* Try to replace the target addresses with a symbols */ - while ((q = strchr(p, 'x')) != NULL) { - if (p != q && *(q-1) == '0') { - r = q + 1; - addr = 0; - while (1) { - if (*r >= '0' && *r <= '9') { - addr = addr * 16 + (*r - '0'); - } else if (*r >= 'A' && *r <= 'F') { - addr = addr * 16 + (*r - 'A' + 10); - } else if (*r >= 'a' && *r <= 'f') { - addr = addr * 16 + (*r - 'a' + 10); - } else { - break; - } - r++; - } - if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) { - if ((z = zend_hash_index_find(&labels, addr))) { - if (Z_LVAL_P(z) < 0) { - fwrite(p, 1, q - p - 1, stderr); - fprintf(stderr, ".ENTRY" ZEND_LONG_FMT, -Z_LVAL_P(z)); - } else { - fwrite(p, 1, q - p - 1, stderr); - fprintf(stderr, ".L" ZEND_LONG_FMT, Z_LVAL_P(z)); - } - } else { - fwrite(p, 1, r - p, stderr); - } - } else if ((sym = zend_jit_disasm_resolver(addr, &offset))) { - fwrite(p, 1, q - p - 1, stderr); - fputs(sym, stderr); - if (offset != 0) { - if (offset > 0) { - fprintf(stderr, "+%" PRIx64, offset); - } else { - fprintf(stderr, "-%" PRIx64, offset); - } - } - } else { - fwrite(p, 1, r - p, stderr); - } - p = r; - } else { - fwrite(p, 1, q - p + 1, stderr); - p = q + 1; - } - } - fprintf(stderr, "%s\n", p); - } -# ifdef HAVE_CAPSTONE_ITER - cs_free(insn, 1); -# else - cs_free(insn, count); -# endif -#else - ud_set_input_buffer(&ud, (uint8_t*)start, (uint8_t*)end - (uint8_t*)start); - ud_set_pc(&ud, (uint64_t)(uintptr_t)start); - - while (ud_disassemble(&ud)) { - addr = ud_insn_off(&ud); - z = zend_hash_index_find(&labels, addr); - if (z) { - if (Z_LVAL_P(z) < 0) { - fprintf(stderr, ".ENTRY" ZEND_LONG_FMT ":\n", -Z_LVAL_P(z)); - } else { - fprintf(stderr, ".L" ZEND_LONG_FMT ":\n", Z_LVAL_P(z)); - } - } - op = ud_insn_opr(&ud, 0); - if (op && op->type == UD_OP_JIMM) { - addr = ud_syn_rel_target(&ud, (struct ud_operand*)op); - if (addr >= (uint64_t)(uintptr_t)start && addr < (uint64_t)(uintptr_t)end) { - z = zend_hash_index_find(&labels, addr); - if (z) { - const char *str = ud_insn_asm(&ud); - int len; - - len = 0; - while (str[len] != 0 && str[len] != ' ' && str[len] != '\t') { - len++; - } - if (str[len] != 0) { - while (str[len] == ' ' || str[len] == '\t') { - len++; - } - if (Z_LVAL_P(z) < 0) { - fprintf(stderr, "\t%.*s.ENTRY" ZEND_LONG_FMT "\n", len, str, -Z_LVAL_P(z)); - } else { - fprintf(stderr, "\t%.*s.L" ZEND_LONG_FMT "\n", len, str, Z_LVAL_P(z)); - } - continue; - } - } - } - } - if (JIT_G(debug) & ZEND_JIT_DEBUG_ASM_ADDR) { - fprintf(stderr, " %" PRIx64 ":", ud_insn_off(&ud)); - } - fprintf(stderr, "\t%s\n", ud_insn_asm(&ud)); - } -#endif - fprintf(stderr, "\n"); - - zend_hash_destroy(&labels); - -#ifdef HAVE_CAPSTONE - cs_close(&cs); -#endif - - return 1; -} - -static int zend_jit_disasm_init(void) -{ -#ifndef ZTS -#define REGISTER_EG(n) \ - zend_jit_disasm_add_symbol("EG("#n")", \ - (uint64_t)(uintptr_t)&executor_globals.n, sizeof(executor_globals.n)) - REGISTER_EG(uninitialized_zval); - REGISTER_EG(exception); - REGISTER_EG(vm_interrupt); - REGISTER_EG(exception_op); - REGISTER_EG(timed_out); - REGISTER_EG(current_execute_data); - REGISTER_EG(vm_stack_top); - REGISTER_EG(vm_stack_end); - REGISTER_EG(symbol_table); - REGISTER_EG(jit_trace_num); -#undef REGISTER_EG -#define REGISTER_CG(n) \ - zend_jit_disasm_add_symbol("CG("#n")", \ - (uint64_t)(uintptr_t)&compiler_globals.n, sizeof(compiler_globals.n)) - REGISTER_CG(map_ptr_base); -#undef REGISTER_CG -#endif - - /* Register JIT helper functions */ -#define REGISTER_HELPER(n) \ - zend_jit_disasm_add_symbol(#n, \ - (uint64_t)(uintptr_t)n, sizeof(void*)); - REGISTER_HELPER(memcmp); - REGISTER_HELPER(zend_jit_init_func_run_time_cache_helper); - REGISTER_HELPER(zend_jit_find_func_helper); - REGISTER_HELPER(zend_jit_find_ns_func_helper); - REGISTER_HELPER(zend_jit_find_method_helper); - REGISTER_HELPER(zend_jit_find_method_tmp_helper); - REGISTER_HELPER(zend_jit_push_static_metod_call_frame); - REGISTER_HELPER(zend_jit_push_static_metod_call_frame_tmp); - REGISTER_HELPER(zend_jit_invalid_method_call); - REGISTER_HELPER(zend_jit_invalid_method_call_tmp); - REGISTER_HELPER(zend_jit_unref_helper); - REGISTER_HELPER(zend_jit_extend_stack_helper); - REGISTER_HELPER(zend_jit_int_extend_stack_helper); - REGISTER_HELPER(zend_jit_leave_nested_func_helper); - REGISTER_HELPER(zend_jit_leave_top_func_helper); - REGISTER_HELPER(zend_jit_leave_func_helper); - REGISTER_HELPER(zend_jit_symtable_find); - REGISTER_HELPER(zend_jit_hash_index_lookup_rw_no_packed); - REGISTER_HELPER(zend_jit_hash_index_lookup_rw); - REGISTER_HELPER(zend_jit_hash_lookup_rw); - REGISTER_HELPER(zend_jit_symtable_lookup_rw); - REGISTER_HELPER(zend_jit_symtable_lookup_w); - REGISTER_HELPER(zend_jit_undefined_op_helper); - REGISTER_HELPER(zend_jit_fetch_dim_r_helper); - REGISTER_HELPER(zend_jit_fetch_dim_is_helper); - REGISTER_HELPER(zend_jit_fetch_dim_isset_helper); - REGISTER_HELPER(zend_jit_fetch_dim_str_offset_r_helper); - REGISTER_HELPER(zend_jit_fetch_dim_str_r_helper); - REGISTER_HELPER(zend_jit_fetch_dim_str_is_helper); - REGISTER_HELPER(zend_jit_fetch_dim_obj_r_helper); - REGISTER_HELPER(zend_jit_fetch_dim_obj_is_helper); - REGISTER_HELPER(zend_jit_fetch_dim_rw_helper); - REGISTER_HELPER(zend_jit_fetch_dim_w_helper); - REGISTER_HELPER(zend_jit_fetch_dim_obj_rw_helper); - REGISTER_HELPER(zend_jit_fetch_dim_obj_w_helper); -// REGISTER_HELPER(zend_jit_fetch_dim_obj_unset_helper); - REGISTER_HELPER(zend_jit_assign_dim_helper); - REGISTER_HELPER(zend_jit_assign_dim_op_helper); - REGISTER_HELPER(zend_jit_fast_assign_concat_helper); - REGISTER_HELPER(zend_jit_fast_concat_helper); - REGISTER_HELPER(zend_jit_fast_concat_tmp_helper); - REGISTER_HELPER(zend_jit_isset_dim_helper); - REGISTER_HELPER(zend_jit_free_call_frame); - REGISTER_HELPER(zend_jit_fetch_global_helper); - REGISTER_HELPER(zend_jit_verify_arg_slow); - REGISTER_HELPER(zend_jit_verify_return_slow); - REGISTER_HELPER(zend_jit_fetch_obj_r_slow); - REGISTER_HELPER(zend_jit_fetch_obj_r_dynamic); - REGISTER_HELPER(zend_jit_fetch_obj_is_slow); - REGISTER_HELPER(zend_jit_fetch_obj_is_dynamic); - REGISTER_HELPER(zend_jit_fetch_obj_w_slow); - REGISTER_HELPER(zend_jit_check_array_promotion); - REGISTER_HELPER(zend_jit_create_typed_ref); - REGISTER_HELPER(zend_jit_extract_helper); - REGISTER_HELPER(zend_jit_vm_stack_free_args_helper); - REGISTER_HELPER(zend_jit_copy_extra_args_helper); - REGISTER_HELPER(zend_jit_deprecated_helper); - REGISTER_HELPER(zend_jit_assign_const_to_typed_ref); - REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref); - REGISTER_HELPER(zend_jit_assign_var_to_typed_ref); - REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref); - REGISTER_HELPER(zend_jit_assign_const_to_typed_ref2); - REGISTER_HELPER(zend_jit_assign_tmp_to_typed_ref2); - REGISTER_HELPER(zend_jit_assign_var_to_typed_ref2); - REGISTER_HELPER(zend_jit_assign_cv_to_typed_ref2); - REGISTER_HELPER(zend_jit_pre_inc_typed_ref); - REGISTER_HELPER(zend_jit_pre_dec_typed_ref); - REGISTER_HELPER(zend_jit_post_inc_typed_ref); - REGISTER_HELPER(zend_jit_post_dec_typed_ref); - REGISTER_HELPER(zend_jit_assign_op_to_typed_ref); - REGISTER_HELPER(zend_jit_assign_op_to_typed_ref_tmp); - REGISTER_HELPER(zend_jit_only_vars_by_reference); - REGISTER_HELPER(zend_jit_invalid_array_access); - REGISTER_HELPER(zend_jit_invalid_property_read); - REGISTER_HELPER(zend_jit_invalid_property_write); - REGISTER_HELPER(zend_jit_invalid_property_incdec); - REGISTER_HELPER(zend_jit_invalid_property_assign); - REGISTER_HELPER(zend_jit_invalid_property_assign_op); - REGISTER_HELPER(zend_jit_prepare_assign_dim_ref); - REGISTER_HELPER(zend_jit_pre_inc); - REGISTER_HELPER(zend_jit_pre_dec); - REGISTER_HELPER(zend_runtime_jit); - REGISTER_HELPER(zend_jit_hot_func); - REGISTER_HELPER(zend_jit_check_constant); - REGISTER_HELPER(zend_jit_get_constant); - REGISTER_HELPER(zend_jit_array_free); - REGISTER_HELPER(zend_jit_zval_array_dup); - REGISTER_HELPER(zend_jit_add_arrays_helper); - REGISTER_HELPER(zend_jit_assign_obj_helper); - REGISTER_HELPER(zend_jit_assign_obj_op_helper); - REGISTER_HELPER(zend_jit_assign_to_typed_prop); - REGISTER_HELPER(zend_jit_assign_op_to_typed_prop); - REGISTER_HELPER(zend_jit_inc_typed_prop); - REGISTER_HELPER(zend_jit_dec_typed_prop); - REGISTER_HELPER(zend_jit_pre_inc_typed_prop); - REGISTER_HELPER(zend_jit_pre_dec_typed_prop); - REGISTER_HELPER(zend_jit_post_inc_typed_prop); - REGISTER_HELPER(zend_jit_post_dec_typed_prop); - REGISTER_HELPER(zend_jit_pre_inc_obj_helper); - REGISTER_HELPER(zend_jit_pre_dec_obj_helper); - REGISTER_HELPER(zend_jit_post_inc_obj_helper); - REGISTER_HELPER(zend_jit_post_dec_obj_helper); - REGISTER_HELPER(zend_jit_rope_end); - REGISTER_HELPER(zend_jit_free_trampoline_helper); - REGISTER_HELPER(zend_jit_exception_in_interrupt_handler_helper); -#undef REGISTER_HELPER - -#ifndef _WIN32 - zend_elf_load_symbols(); -#endif - - if (zend_vm_kind() == ZEND_VM_KIND_HYBRID) { - zend_op opline; - - memset(&opline, 0, sizeof(opline)); - - opline.opcode = ZEND_DO_UCALL; - opline.result_type = IS_UNUSED; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_DO_UCALL; - opline.result_type = IS_VAR; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_UCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_DO_FCALL_BY_NAME; - opline.result_type = IS_UNUSED; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_DO_FCALL_BY_NAME; - opline.result_type = IS_VAR; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_FCALL_BY_NAME_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_DO_FCALL; - opline.result_type = IS_UNUSED; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_UNUSED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_DO_FCALL; - opline.result_type = IS_VAR; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_DO_FCALL_SPEC_RETVAL_USED_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_RETURN; - opline.op1_type = IS_CONST; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CONST_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_RETURN; - opline.op1_type = IS_TMP_VAR; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_TMP_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_RETURN; - opline.op1_type = IS_VAR; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_VAR_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - opline.opcode = ZEND_RETURN; - opline.op1_type = IS_CV; - zend_vm_set_opcode_handler(&opline); - zend_jit_disasm_add_symbol("ZEND_RETURN_SPEC_CV_LABEL", (uint64_t)(uintptr_t)opline.handler, sizeof(void*)); - - zend_jit_disasm_add_symbol("ZEND_HYBRID_HALT_LABEL", (uint64_t)(uintptr_t)zend_jit_halt_op->handler, sizeof(void*)); - } - - return 1; -} - -static void zend_jit_disasm_shutdown(void) -{ - if (JIT_G(symbols)) { - zend_jit_disasm_destroy_symbols(JIT_G(symbols)); - JIT_G(symbols) = NULL; - } -} - -#endif /* HAVE_DISASM */ diff --git a/ext/opcache/jit/zend_jit_gdb.c b/ext/opcache/jit/zend_jit_gdb.c deleted file mode 100644 index 39169108a8f5e..0000000000000 --- a/ext/opcache/jit/zend_jit_gdb.c +++ /dev/null @@ -1,522 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Xinchen Hui | - +----------------------------------------------------------------------+ - | Based on Mike Pall's implementation of GDB interface for LuaJIT. | - | LuaJIT -- a Just-In-Time Compiler for Lua. http://luajit.org/ | - +----------------------------------------------------------------------+ -*/ - - -#define HAVE_GDB - -#include "zend_jit_gdb.h" -#include "zend_elf.h" -#include "zend_gdb.h" - -/* DWARF definitions. */ -#define DW_CIE_VERSION 1 - -/* CFA (Canonical frame address) */ -enum { - DW_CFA_nop = 0x0, - DW_CFA_offset_extended = 0x5, - DW_CFA_def_cfa = 0xc, - DW_CFA_def_cfa_offset = 0xe, - DW_CFA_offset_extended_sf = 0x11, - DW_CFA_advance_loc = 0x40, - DW_CFA_offset = 0x80 -}; - -enum { - DW_EH_PE_udata4 = 0x03, - DW_EH_PE_textrel = 0x20 -}; - -enum { - DW_TAG_compile_unit = 0x11 -}; - -enum { - DW_children_no = 0, - DW_children_yes = 1 -}; - -enum { - DW_AT_name = 0x03, - DW_AT_stmt_list = 0x10, - DW_AT_low_pc = 0x11, - DW_AT_high_pc = 0x12 -}; - -enum { - DW_FORM_addr = 0x01, - DW_FORM_data4 = 0x06, - DW_FORM_string = 0x08 -}; - -enum { - DW_LNS_extended_op = 0, - DW_LNS_copy = 1, - DW_LNS_advance_pc = 2, - DW_LNS_advance_line = 3 -}; - -enum { - DW_LNE_end_sequence = 1, - DW_LNE_set_address = 2 -}; - -enum { -#if defined(__i386__) - DW_REG_AX, DW_REG_CX, DW_REG_DX, DW_REG_BX, - DW_REG_SP, DW_REG_BP, DW_REG_SI, DW_REG_DI, - DW_REG_RA, -#elif defined(__x86_64__) - /* Yes, the order is strange, but correct. */ - DW_REG_AX, DW_REG_DX, DW_REG_CX, DW_REG_BX, - DW_REG_SI, DW_REG_DI, DW_REG_BP, DW_REG_SP, - DW_REG_8, DW_REG_9, DW_REG_10, DW_REG_11, - DW_REG_12, DW_REG_13, DW_REG_14, DW_REG_15, - DW_REG_RA, -#elif defined(__aarch64__) - DW_REG_SP = 31, - DW_REG_RA = 30, - DW_REG_X29 = 29, -#else -#error "Unsupported target architecture" -#endif -}; - -enum { - GDBJIT_SECT_NULL, - GDBJIT_SECT_text, - GDBJIT_SECT_eh_frame, - GDBJIT_SECT_shstrtab, - GDBJIT_SECT_strtab, - GDBJIT_SECT_symtab, - GDBJIT_SECT_debug_info, - GDBJIT_SECT_debug_abbrev, - GDBJIT_SECT_debug_line, - GDBJIT_SECT__MAX -}; - -enum { - GDBJIT_SYM_UNDEF, - GDBJIT_SYM_FILE, - GDBJIT_SYM_FUNC, - GDBJIT_SYM__MAX -}; - -typedef struct _zend_gdbjit_obj { - zend_elf_header hdr; - zend_elf_sectheader sect[GDBJIT_SECT__MAX]; - zend_elf_symbol sym[GDBJIT_SYM__MAX]; - uint8_t space[4096]; -} zend_gdbjit_obj; - -static const zend_elf_header zend_elfhdr_template = { - .emagic = { 0x7f, 'E', 'L', 'F' }, -#ifdef ELF64 - .eclass = 2, -#else - .eclass = 1, -#endif -#ifdef WORDS_BIGENDIAN - .eendian = 2, -#else - .eendian = 1, -#endif - .eversion = 1, -#if defined(Linux) - .eosabi = 0, /* Nope, it's not 3. ??? */ -#elif defined(__FreeBSD__) - .eosabi = 9, -#elif defined(__OpenBSD__) - .eosabi = 12, -#elif defined(__NetBSD__) - .eosabi = 2, -#elif defined(__DragonFly__) - .eosabi = 0, -#elif (defined(__sun__) && defined(__svr4__)) - .eosabi = 6, -#else - .eosabi = 0, -#endif - .eabiversion = 0, - .epad = { 0, 0, 0, 0, 0, 0, 0 }, - .type = 1, -#if defined(__i386__) - .machine = 3, -#elif defined(__x86_64__) - .machine = 62, -#elif defined(__aarch64__) - .machine = 183, -#else -# error "Unsupported target architecture" -#endif - .version = 1, - .entry = 0, - .phofs = 0, - .shofs = offsetof(zend_gdbjit_obj, sect), - .flags = 0, - .ehsize = sizeof(zend_elf_header), - .phentsize = 0, - .phnum = 0, - .shentsize = sizeof(zend_elf_sectheader), - .shnum = GDBJIT_SECT__MAX, - .shstridx = GDBJIT_SECT_shstrtab -}; - -/* Context for generating the ELF object for the GDB JIT API. */ -typedef struct _zend_gdbjit_ctx { - uint8_t *p; /* Pointer to next address in obj.space. */ - uint8_t *startp; /* Pointer to start address in obj.space. */ - uintptr_t mcaddr; /* Machine code address. */ - uint32_t szmcode; /* Size of machine code. */ - int32_t lineno; /* Starting line number. */ - const char *name; /* JIT function name */ - const char *filename; /* Starting file name. */ - size_t objsize; /* Final size of ELF object. */ - zend_gdbjit_obj obj; /* In-memory ELF object. */ -} zend_gdbjit_ctx; - -/* Add a zero-terminated string */ -static uint32_t zend_gdbjit_strz(zend_gdbjit_ctx *ctx, const char *str) -{ - uint8_t *p = ctx->p; - uint32_t ofs = (uint32_t)(p - ctx->startp); - do { - *p++ = (uint8_t)*str; - } while (*str++); - ctx->p = p; - return ofs; -} - -/* Add a ULEB128 value */ -static void zend_gdbjit_uleb128(zend_gdbjit_ctx *ctx, uint32_t v) -{ - uint8_t *p = ctx->p; - for (; v >= 0x80; v >>= 7) - *p++ = (uint8_t)((v & 0x7f) | 0x80); - *p++ = (uint8_t)v; - ctx->p = p; -} - -/* Add a SLEB128 value */ -static void zend_gdbjit_sleb128(zend_gdbjit_ctx *ctx, int32_t v) -{ - uint8_t *p = ctx->p; - for (; (uint32_t)(v+0x40) >= 0x80; v >>= 7) - *p++ = (uint8_t)((v & 0x7f) | 0x80); - *p++ = (uint8_t)(v & 0x7f); - ctx->p = p; -} - -static void zend_gdbjit_secthdr(zend_gdbjit_ctx *ctx) -{ - zend_elf_sectheader *sect; - - *ctx->p++ = '\0'; - -#define SECTDEF(id, tp, al) \ - sect = &ctx->obj.sect[GDBJIT_SECT_##id]; \ - sect->name = zend_gdbjit_strz(ctx, "." #id); \ - sect->type = ELFSECT_TYPE_##tp; \ - sect->align = (al) - - SECTDEF(text, NOBITS, 16); - sect->flags = ELFSECT_FLAGS_ALLOC|ELFSECT_FLAGS_EXEC; - sect->addr = ctx->mcaddr; - sect->ofs = 0; - sect->size = ctx->szmcode; - - SECTDEF(eh_frame, PROGBITS, sizeof(uintptr_t)); - sect->flags = ELFSECT_FLAGS_ALLOC; - - SECTDEF(shstrtab, STRTAB, 1); - SECTDEF(strtab, STRTAB, 1); - - SECTDEF(symtab, SYMTAB, sizeof(uintptr_t)); - sect->ofs = offsetof(zend_gdbjit_obj, sym); - sect->size = sizeof(ctx->obj.sym); - sect->link = GDBJIT_SECT_strtab; - sect->entsize = sizeof(zend_elf_symbol); - sect->info = GDBJIT_SYM_FUNC; - - SECTDEF(debug_info, PROGBITS, 1); - SECTDEF(debug_abbrev, PROGBITS, 1); - SECTDEF(debug_line, PROGBITS, 1); - -#undef SECTDEF -} - -static void zend_gdbjit_symtab(zend_gdbjit_ctx *ctx) -{ - zend_elf_symbol *sym; - - *ctx->p++ = '\0'; - - sym = &ctx->obj.sym[GDBJIT_SYM_FILE]; - sym->name = zend_gdbjit_strz(ctx, "JIT code"); - sym->sectidx = ELFSECT_IDX_ABS; - sym->info = ELFSYM_INFO(ELFSYM_BIND_LOCAL, ELFSYM_TYPE_FILE); - - sym = &ctx->obj.sym[GDBJIT_SYM_FUNC]; - sym->name = zend_gdbjit_strz(ctx, ctx->name); - sym->sectidx = GDBJIT_SECT_text; - sym->value = 0; - sym->size = ctx->szmcode; - sym->info = ELFSYM_INFO(ELFSYM_BIND_GLOBAL, ELFSYM_TYPE_FUNC); -} - -typedef ZEND_SET_ALIGNED(1, uint16_t unaligned_uint16_t); -typedef ZEND_SET_ALIGNED(1, uint32_t unaligned_uint32_t); -typedef ZEND_SET_ALIGNED(1, uintptr_t unaligned_uintptr_t); - -#define SECTALIGN(p, a) \ - ((p) = (uint8_t *)(((uintptr_t)(p) + ((a)-1)) & ~(uintptr_t)((a)-1))) - -/* Shortcuts to generate DWARF structures. */ -#define DB(x) (*p++ = (x)) -#define DI8(x) (*(int8_t *)p = (x), p++) -#define DU16(x) (*(unaligned_uint16_t *)p = (x), p += 2) -#define DU32(x) (*(unaligned_uint32_t *)p = (x), p += 4) -#define DADDR(x) (*(unaligned_uintptr_t *)p = (x), p += sizeof(uintptr_t)) -#define DUV(x) (ctx->p = p, zend_gdbjit_uleb128(ctx, (x)), p = ctx->p) -#define DSV(x) (ctx->p = p, zend_gdbjit_sleb128(ctx, (x)), p = ctx->p) -#define DSTR(str) (ctx->p = p, zend_gdbjit_strz(ctx, (str)), p = ctx->p) -#define DALIGNNOP(s) while ((uintptr_t)p & ((s)-1)) *p++ = DW_CFA_nop -#define DSECT(name, stmt) \ - { unaligned_uint32_t *szp_##name = (uint32_t *)p; p += 4; stmt \ - *szp_##name = (uint32_t)((p-(uint8_t *)szp_##name)-4); } - -static void zend_gdbjit_ehframe(zend_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment) -{ - uint8_t *p = ctx->p; - uint8_t *framep = p; - - /* DWARF EH CIE (Common Information Entry) */ - DSECT(CIE, - DU32(0); /* CIE ID. */ - DB(DW_CIE_VERSION); /* Version */ - DSTR("zR"); /* Augmentation String. */ - DUV(1); /* Code alignment factor. */ - DSV(-(int32_t)sizeof(uintptr_t)); /* Data alignment factor. */ - DB(DW_REG_RA); /* Return address register. */ - DB(1); DB(DW_EH_PE_textrel|DW_EH_PE_udata4); /* Augmentation data. */ -#if defined(__x86_64__) || defined(i386) - DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(sizeof(uintptr_t)); - DB(DW_CFA_offset|DW_REG_RA); DUV(1); -#elif defined(__aarch64__) - DB(DW_CFA_def_cfa); DUV(DW_REG_SP); DUV(0); -#endif - DALIGNNOP(sizeof(uintptr_t)); - ) - - /* DWARF EH FDE (Frame Description Entry). */ - DSECT(FDE, - DU32((uint32_t)(p-framep)); /* Offset to CIE Pointer. */ - DU32(0); /* Machine code offset relative to .text. */ - DU32(ctx->szmcode); /* Machine code length. */ - DB(0); /* Augmentation data. */ - DB(DW_CFA_def_cfa_offset); DUV(sp_offset); -#if defined(__aarch64__) - if (sp_offset) { - if (sp_adjustment && sp_adjustment < sp_offset) { - DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t)); - DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1); - } else { - DB(DW_CFA_offset|DW_REG_X29); DUV(sp_offset / sizeof(uintptr_t)); - DB(DW_CFA_offset|DW_REG_RA); DUV((sp_offset / sizeof(uintptr_t)) - 1); - } - } -#endif - if (sp_adjustment && sp_adjustment > sp_offset) { - DB(DW_CFA_advance_loc|1); DB(DW_CFA_def_cfa_offset); DUV(sp_adjustment); -#if defined(__aarch64__) - if (!sp_offset) { - DB(DW_CFA_offset|DW_REG_X29); DUV(sp_adjustment / sizeof(uintptr_t)); - DB(DW_CFA_offset|DW_REG_RA); DUV((sp_adjustment / sizeof(uintptr_t)) - 1); - } -#endif - } - DALIGNNOP(sizeof(uintptr_t)); - ) - - ctx->p = p; -} - -static void zend_gdbjit_debuginfo(zend_gdbjit_ctx *ctx) -{ - uint8_t *p = ctx->p; - - DSECT(info, - DU16(2); /* DWARF version. */ - DU32(0); /* Abbrev offset. */ - DB(sizeof(uintptr_t)); /* Pointer size. */ - - DUV(1); /* Abbrev #1: DW_TAG_compile_unit. */ - DSTR(ctx->filename); /* DW_AT_name. */ - DADDR(ctx->mcaddr); /* DW_AT_low_pc. */ - DADDR(ctx->mcaddr + ctx->szmcode); /* DW_AT_high_pc. */ - DU32(0); /* DW_AT_stmt_list. */ - ); - - ctx->p = p; -} - -static void zend_gdbjit_debugabbrev(zend_gdbjit_ctx *ctx) -{ - uint8_t *p = ctx->p; - - /* Abbrev #1: DW_TAG_compile_unit. */ - DUV(1); - DUV(DW_TAG_compile_unit); - DB(DW_children_no); - DUV(DW_AT_name); - DUV(DW_FORM_string); - DUV(DW_AT_low_pc); - DUV(DW_FORM_addr); - DUV(DW_AT_high_pc); - DUV(DW_FORM_addr); - DUV(DW_AT_stmt_list); - DUV(DW_FORM_data4); - DB(0); - DB(0); - - ctx->p = p; -} - -#define DLNE(op, s) (DB(DW_LNS_extended_op), DUV(1+(s)), DB((op))) - -static void zend_gdbjit_debugline(zend_gdbjit_ctx *ctx) -{ - uint8_t *p = ctx->p; - - DSECT(line, - DU16(2); /* DWARF version. */ - DSECT(header, - DB(1); /* Minimum instruction length. */ - DB(1); /* is_stmt. */ - DI8(0); /* Line base for special opcodes. */ - DB(2); /* Line range for special opcodes. */ - DB(3+1); /* Opcode base at DW_LNS_advance_line+1. */ - DB(0); DB(1); DB(1); /* Standard opcode lengths. */ - /* Directory table. */ - DB(0); - /* File name table. */ - DSTR(ctx->filename); DUV(0); DUV(0); DUV(0); - DB(0); - ); - DLNE(DW_LNE_set_address, sizeof(uintptr_t)); - DADDR(ctx->mcaddr); - if (ctx->lineno) (DB(DW_LNS_advance_line), DSV(ctx->lineno-1)); - DB(DW_LNS_copy); - DB(DW_LNS_advance_pc); DUV(ctx->szmcode); - DLNE(DW_LNE_end_sequence, 0); - ); - - ctx->p = p; -} - - -#undef DLNE - -/* Undef shortcuts. */ -#undef DB -#undef DI8 -#undef DU16 -#undef DU32 -#undef DADDR -#undef DUV -#undef DSV -#undef DSTR -#undef DALIGNNOP -#undef DSECT - -typedef void (*zend_gdbjit_initf) (zend_gdbjit_ctx *ctx); - -static void zend_gdbjit_initsect(zend_gdbjit_ctx *ctx, int sect) -{ - ctx->startp = ctx->p; - ctx->obj.sect[sect].ofs = (uintptr_t)((char *)ctx->p - (char *)&ctx->obj); -} - -static void zend_gdbjit_initsect_done(zend_gdbjit_ctx *ctx, int sect) -{ - ctx->obj.sect[sect].size = (uintptr_t)(ctx->p - ctx->startp); -} - -static void zend_gdbjit_buildobj(zend_gdbjit_ctx *ctx, uint32_t sp_offset, uint32_t sp_adjustment) -{ - zend_gdbjit_obj *obj = &ctx->obj; - - /* Fill in ELF header and clear structures. */ - memcpy(&obj->hdr, &zend_elfhdr_template, sizeof(zend_elf_header)); - memset(&obj->sect, 0, sizeof(zend_elf_sectheader) * GDBJIT_SECT__MAX); - memset(&obj->sym, 0, sizeof(zend_elf_symbol) * GDBJIT_SYM__MAX); - - /* Initialize sections. */ - ctx->p = obj->space; - zend_gdbjit_initsect(ctx, GDBJIT_SECT_shstrtab); zend_gdbjit_secthdr(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_shstrtab); - zend_gdbjit_initsect(ctx, GDBJIT_SECT_strtab); zend_gdbjit_symtab(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_strtab); - zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_info); zend_gdbjit_debuginfo(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_info); - zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_abbrev); zend_gdbjit_debugabbrev(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_abbrev); - zend_gdbjit_initsect(ctx, GDBJIT_SECT_debug_line); zend_gdbjit_debugline(ctx); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_debug_line); - SECTALIGN(ctx->p, sizeof(uintptr_t)); - zend_gdbjit_initsect(ctx, GDBJIT_SECT_eh_frame); zend_gdbjit_ehframe(ctx, sp_offset, sp_adjustment); zend_gdbjit_initsect_done(ctx, GDBJIT_SECT_eh_frame); - ctx->objsize = (size_t)((char *)ctx->p - (char *)obj); - - ZEND_ASSERT(ctx->objsize < sizeof(zend_gdbjit_obj)); -} - -int zend_jit_gdb_register(const char *name, - const zend_op_array *op_array, - const void *start, - size_t size, - uint32_t sp_offset, - uint32_t sp_adjustment) -{ - zend_gdbjit_ctx ctx; - - ctx.mcaddr = (uintptr_t)start; - ctx.szmcode = (uint32_t)size; - ctx.name = name; - ctx.filename = op_array ? ZSTR_VAL(op_array->filename) : "unknown"; - ctx.lineno = op_array ? op_array->line_start : 0; - - zend_gdbjit_buildobj(&ctx, sp_offset, sp_adjustment); - - return zend_gdb_register_code(&ctx.obj, ctx.objsize); -} - -int zend_jit_gdb_unregister(void) -{ - zend_gdb_unregister_all(); - return 1; -} - -void zend_jit_gdb_init(void) -{ -#if 0 - /* This might enable registration of all JIT-ed code, but unfortunately, - * in case of many functions, this takes enormous time. */ - if (zend_gdb_present()) { - JIT_G(debug) |= ZEND_JIT_DEBUG_GDB; - } -#endif -} diff --git a/ext/opcache/jit/zend_jit_gdb.h b/ext/opcache/jit/zend_jit_gdb.h deleted file mode 100644 index a8fc98dff86bb..0000000000000 --- a/ext/opcache/jit/zend_jit_gdb.h +++ /dev/null @@ -1,37 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - | Xinchen Hui | - +----------------------------------------------------------------------+ -*/ - -#ifndef HAVE_ZEND_JIT_GDB_H -#define HAVE_ZEND_JIT_GDB_H - -#include "zend_compile.h" - -#define HAVE_GDB - -int zend_jit_gdb_register(const char *name, - const zend_op_array *op_array, - const void *start, - size_t size, - uint32_t sp_offset, - uint32_t sp_adjustment); - -int zend_jit_gdb_unregister(void); -void zend_jit_gdb_init(void); - -#endif /* HAVE_ZEND_JIT_GDB_H */ diff --git a/ext/opcache/jit/zend_jit_internal.h b/ext/opcache/jit/zend_jit_internal.h index 77df230b8315a..977cec9cc9386 100644 --- a/ext/opcache/jit/zend_jit_internal.h +++ b/ext/opcache/jit/zend_jit_internal.h @@ -21,97 +21,6 @@ #ifndef ZEND_JIT_INTERNAL_H #define ZEND_JIT_INTERNAL_H -#ifndef ZEND_JIT_IR - -#include "zend_bitset.h" - -/* Register Set */ -#define ZEND_REGSET_EMPTY 0 - -#define ZEND_REGSET_IS_EMPTY(regset) \ - (regset == ZEND_REGSET_EMPTY) - -#define ZEND_REGSET_IS_SINGLETON(regset) \ - (regset && !(regset & (regset - 1))) - -#if (!ZEND_REGSET_64BIT) -#define ZEND_REGSET(reg) \ - (1u << (reg)) -#else -#define ZEND_REGSET(reg) \ - (1ull << (reg)) -#endif - -#if (!ZEND_REGSET_64BIT) -#define ZEND_REGSET_INTERVAL(reg1, reg2) \ - (((1u << ((reg2) - (reg1) + 1)) - 1) << (reg1)) -#else -#define ZEND_REGSET_INTERVAL(reg1, reg2) \ - (((1ull << ((reg2) - (reg1) + 1)) - 1) << (reg1)) -#endif - -#define ZEND_REGSET_IN(regset, reg) \ - (((regset) & ZEND_REGSET(reg)) != 0) - -#define ZEND_REGSET_INCL(regset, reg) \ - (regset) |= ZEND_REGSET(reg) - -#define ZEND_REGSET_EXCL(regset, reg) \ - (regset) &= ~ZEND_REGSET(reg) - -#define ZEND_REGSET_UNION(set1, set2) \ - ((set1) | (set2)) - -#define ZEND_REGSET_INTERSECTION(set1, set2) \ - ((set1) & (set2)) - -#define ZEND_REGSET_DIFFERENCE(set1, set2) \ - ((set1) & ~(set2)) - -#if !defined(_WIN32) -# if (!ZEND_REGSET_64BIT) -# define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctz(set)) -# define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clz(set)^31)) -# else -# define ZEND_REGSET_FIRST(set) ((zend_reg)__builtin_ctzll(set)) -# define ZEND_REGSET_LAST(set) ((zend_reg)(__builtin_clzll(set)^63)) -# endif -#else -# include -uint32_t __inline __zend_jit_ctz(uint32_t value) { - DWORD trailing_zero = 0; - if (_BitScanForward(&trailing_zero, value)) { - return trailing_zero; - } - return 32; -} -uint32_t __inline __zend_jit_clz(uint32_t value) { - DWORD leading_zero = 0; - if (_BitScanReverse(&leading_zero, value)) { - return 31 - leading_zero; - } - return 32; -} -# define ZEND_REGSET_FIRST(set) ((zend_reg)__zend_jit_ctz(set)) -# define ZEND_REGSET_LAST(set) ((zend_reg)(__zend_jit_clz(set)^31)) -#endif - -#define ZEND_REGSET_FOREACH(set, reg) \ - do { \ - zend_regset _tmp = (set); \ - while (!ZEND_REGSET_IS_EMPTY(_tmp)) { \ - zend_reg _reg = ZEND_REGSET_FIRST(_tmp); \ - ZEND_REGSET_EXCL(_tmp, _reg); \ - reg = _reg; \ - -#define ZEND_REGSET_FOREACH_END() \ - } \ - } while (0) - -/* Register Names */ -extern const char *zend_reg_name[]; -#endif /* ZEND_JIT_IR */ - /* Address Encoding */ typedef uintptr_t zend_jit_addr; @@ -140,58 +49,6 @@ typedef uintptr_t zend_jit_addr; #define Z_OFFSET(addr) ((uint32_t)((addr)>>_ZEND_ADDR_OFFSET_SHIFT)) #define Z_REG(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_SHIFT) & _ZEND_ADDR_REG_MASK)) -#ifndef ZEND_JIT_IR - -#define _ZEND_ADDR_REG_STORE_BIT 8 -#define _ZEND_ADDR_REG_LOAD_BIT 9 -#define _ZEND_ADDR_REG_LAST_USE_BIT 10 - -#define Z_STORE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_STORE_BIT) & 1)) -#define Z_LOAD(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LOAD_BIT) & 1)) -#define Z_LAST_USE(addr) ((zend_reg)(((addr)>>_ZEND_ADDR_REG_LAST_USE_BIT) & 1)) - -#define OP_REG_EX(reg, store, load, last_use) \ - ((reg) | \ - ((store) ? (1 << (_ZEND_ADDR_REG_STORE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \ - ((load) ? (1 << (_ZEND_ADDR_REG_LOAD_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) | \ - ((last_use) ? (1 << (_ZEND_ADDR_REG_LAST_USE_BIT-_ZEND_ADDR_REG_SHIFT)) : 0) \ - ) - -#define OP_REG(ssa_op, op) \ - (ra && ssa_op->op >= 0 && ra[ssa_op->op] ? \ - OP_REG_EX(ra[ssa_op->op]->reg, \ - (ra[ssa_op->op]->flags & ZREG_STORE), \ - (ra[ssa_op->op]->flags & ZREG_LOAD), \ - zend_ival_is_last_use(ra[ssa_op->op], ssa_op - ssa->ops) \ - ) : ZREG_NONE) - -static zend_always_inline zend_jit_addr _zend_jit_decode_op(uint8_t op_type, znode_op op, const zend_op *opline, zend_reg reg) -{ - if (op_type == IS_CONST) { -#if ZEND_USE_ABS_CONST_ADDR - return ZEND_ADDR_CONST_ZVAL(op.zv); -#else - return ZEND_ADDR_CONST_ZVAL(RT_CONSTANT(opline, op)); -#endif - } else { - ZEND_ASSERT(op_type & (IS_CV|IS_TMP_VAR|IS_VAR)); - if (reg != ZREG_NONE) { - return ZEND_ADDR_REG(reg); - } else { - return ZEND_ADDR_MEM_ZVAL(ZREG_FP, op.var); - } - } -} - -#define OP_ADDR(opline, type, op) \ - _zend_jit_decode_op((opline)->type, (opline)->op, opline, ZREG_NONE) - -#define OP_REG_ADDR(opline, type, _op, _ssa_op) \ - _zend_jit_decode_op((opline)->type, (opline)->_op, opline, \ - OP_REG(ssa_op, _ssa_op)) - -#else /* ZEND_JIT_IR */ - #define ZEND_ADDR_REF_ZVAL(ref) \ ((((zend_jit_addr)(uintptr_t)(ref)) << _ZEND_ADDR_REG_SHIFT) | \ IS_REF_ZVAL) @@ -225,8 +82,6 @@ static zend_always_inline zend_jit_addr _zend_jit_decode_op(uint8_t op_type, zno ZEND_ADDR_REG(ssa_op->_ssa_op) : \ OP_ADDR(opline, type, op)) -#endif /* ZEND_JIT_IR */ - #define OP1_ADDR() \ OP_ADDR(opline, op1_type, op1) #define OP2_ADDR() \ @@ -258,15 +113,10 @@ static zend_always_inline bool zend_jit_same_addr(zend_jit_addr addr1, zend_jit_ { if (addr1 == addr2) { return 1; -#ifndef ZEND_JIT_IR - } else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) { - return Z_REG(addr1) == Z_REG(addr2); -#else } else if (Z_MODE(addr1) == IS_REG && Z_MODE(addr2) == IS_REG) { return Z_SSA_VAR(addr1) == Z_SSA_VAR(addr2); } else if (Z_MODE(addr1) == IS_REF_ZVAL && Z_MODE(addr2) == IS_REF_ZVAL) { return Z_IR_REF(addr1) == Z_IR_REF(addr2); -#endif } return 0; } @@ -569,36 +419,12 @@ typedef struct _zend_jit_trace_exit_info { uint32_t flags; /* set of ZEND_JIT_EXIT_... */ uint32_t stack_size; uint32_t stack_offset; -#ifdef ZEND_JIT_IR int32_t poly_func_ref; int32_t poly_this_ref; int8_t poly_func_reg; int8_t poly_this_reg; -#endif } zend_jit_trace_exit_info; -#ifndef ZEND_JIT_IR -typedef union _zend_jit_trace_stack { - int32_t ssa_var; - uint32_t info; - struct { - uint8_t type; /* variable type (for type inference) */ - uint8_t mem_type; /* stack slot type (for eliminate dead type store) */ - int8_t reg; - uint8_t flags; - }; -} zend_jit_trace_stack; - -#define STACK_VAR(_stack, _slot) \ - (_stack)[_slot].ssa_var -#define SET_STACK_VAR(_stack, _slot, _ssa_var) do { \ - (_stack)[_slot].ssa_var = _ssa_var; \ - } while (0) - -#define CLEAR_STACK_REF(_stack, _slot) - -#else /* ZEND_JIT_IR */ - typedef struct _zend_jit_trace_stack { union { uint32_t info; @@ -633,8 +459,6 @@ typedef struct _zend_jit_trace_stack { (_stack)[_slot].flags = _flags; \ } while (0) -#endif /* ZEND_JIT_IR */ - #define STACK_INFO(_stack, _slot) \ (_stack)[_slot].info #define STACK_TYPE(_stack, _slot) \ @@ -675,12 +499,10 @@ typedef struct _zend_jit_trace_stack { #define ZEND_JIT_TRACE_LOOP (1<<1) #define ZEND_JIT_TRACE_USES_INITIAL_IP (1<<2) -#ifdef ZEND_JIT_IR typedef union _zend_jit_exit_const { int64_t i; double d; } zend_jit_exit_const; -#endif typedef struct _zend_jit_trace_info { uint32_t id; /* trace id */ @@ -701,10 +523,8 @@ typedef struct _zend_jit_trace_info { zend_jit_trace_exit_info *exit_info; /* info about side exits */ zend_jit_trace_stack *stack_map; //uint32_t loop_offset; -#ifdef ZEND_JIT_IR uint32_t consts_count; /* number of side exits */ zend_jit_exit_const *constants; -#endif } zend_jit_trace_info; struct _zend_jit_trace_stack_frame { @@ -823,9 +643,6 @@ ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_ret_trace_helper(ZEND_OPCODE_HAND ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL zend_jit_loop_trace_helper(ZEND_OPCODE_HANDLER_ARGS); int ZEND_FASTCALL zend_jit_trace_hot_root(zend_execute_data *execute_data, const zend_op *opline); -#ifndef ZEND_JIT_IR -int ZEND_FASTCALL zend_jit_trace_exit(uint32_t exit_num, zend_jit_registers_buf *regs); -#endif zend_jit_trace_stop ZEND_FASTCALL zend_jit_trace_execute(zend_execute_data *execute_data, const zend_op *opline, zend_jit_trace_rec *trace_buffer, uint8_t start, uint32_t is_megamorphc); static zend_always_inline const zend_op* zend_jit_trace_get_exit_opline(zend_jit_trace_rec *trace, const zend_op *opline, bool *exit_if_true) @@ -910,14 +727,6 @@ static zend_always_inline bool zend_long_is_power_of_two(zend_long x) return (x > 0) && !(x & (x - 1)); } -#ifndef ZEND_JIT_IR -static zend_always_inline uint32_t zend_long_floor_log2(zend_long x) -{ - ZEND_ASSERT(zend_long_is_power_of_two(x)); - return zend_ulong_ntz(x); -} -#endif - /* from http://aggregate.org/MAGIC/ */ static zend_always_inline uint32_t ones32(uint32_t x) { diff --git a/ext/opcache/jit/zend_jit_perf_dump.c b/ext/opcache/jit/zend_jit_perf_dump.c deleted file mode 100644 index beebf9369c30e..0000000000000 --- a/ext/opcache/jit/zend_jit_perf_dump.c +++ /dev/null @@ -1,327 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | Zend JIT | - +----------------------------------------------------------------------+ - | Copyright (c) The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | https://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Authors: Dmitry Stogov | - +----------------------------------------------------------------------+ -*/ - -#define HAVE_PERFTOOLS 1 - -#include -#include -#include -#include -#include -#include -#include - -#if !defined(HAVE_OS_SIGNPOST_H) -#if defined(__linux__) -#include -#elif defined(__darwin__) -# include -#elif defined(__FreeBSD__) -# include -# include -#elif defined(__NetBSD__) -# include -#elif defined(__DragonFly__) -# include -# include -#elif defined(__sun) -// avoiding thread.h inclusion as it conflicts with vtunes types. -extern unsigned int thr_self(void); -#elif defined(__HAIKU__) -#include -#endif - -#include "zend_elf.h" -#include "zend_mmap.h" - -/* - * 1) Profile using perf-.map - * - * perf record php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x10 bench.php - * perf report - * - * 2) Profile using jit-.dump - * - * perf record -k 1 php -d opcache.huge_code_pages=0 -d opcache.jit_debug=0x20 bench.php - * perf inject -j -i perf.data -o perf.data.jitted - * perf report -i perf.data.jitted - * - */ - - -#define ZEND_PERF_JITDUMP_HEADER_MAGIC 0x4A695444 -#define ZEND_PERF_JITDUMP_HEADER_VERSION 1 - -#define ZEND_PERF_JITDUMP_RECORD_LOAD 0 -#define ZEND_PERF_JITDUMP_RECORD_MOVE 1 -#define ZEND_PERF_JITDUMP_RECORD_DEBUG_INFO 2 -#define ZEND_PERF_JITDUMP_RECORD_CLOSE 3 -#define ZEND_PERF_JITDUMP_UNWINDING_UNFO 4 - -#define ALIGN8(size) (((size) + 7) & ~7) -#define PADDING8(size) (ALIGN8(size) - (size)) - -typedef struct zend_perf_jitdump_header { - uint32_t magic; - uint32_t version; - uint32_t size; - uint32_t elf_mach_target; - uint32_t reserved; - uint32_t process_id; - uint64_t time_stamp; - uint64_t flags; -} zend_perf_jitdump_header; - -typedef struct _zend_perf_jitdump_record { - uint32_t event; - uint32_t size; - uint64_t time_stamp; -} zend_perf_jitdump_record; - -typedef struct _zend_perf_jitdump_load_record { - zend_perf_jitdump_record hdr; - uint32_t process_id; - uint32_t thread_id; - uint64_t vma; - uint64_t code_address; - uint64_t code_size; - uint64_t code_id; -} zend_perf_jitdump_load_record; - -static int jitdump_fd = -1; -static void *jitdump_mem = MAP_FAILED; - -static uint64_t zend_perf_timestamp(void) -{ - struct timespec ts; - - if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0) { - return 0; - } - return ((uint64_t)ts.tv_sec * 1000000000) + ts.tv_nsec; -} - -static void zend_jit_perf_jitdump_open(void) -{ - char filename[64]; - int fd, ret; - zend_elf_header elf_hdr; - zend_perf_jitdump_header jit_hdr; - - sprintf(filename, "/tmp/jit-%d.dump", getpid()); - if (!zend_perf_timestamp()) { - return; - } - -#if defined(__linux__) - fd = open("/proc/self/exe", O_RDONLY); -#elif defined(__NetBSD__) - fd = open("/proc/curproc/exe", O_RDONLY); -#elif defined(__FreeBSD__) || defined(__DragonFly__) - char path[PATH_MAX]; - size_t pathlen = sizeof(path); - int mib[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1}; - if (sysctl(mib, 4, path, &pathlen, NULL, 0) == -1) { - return; - } - fd = open(path, O_RDONLY); -#elif defined(__sun) - fd = open("/proc/self/path/a.out", O_RDONLY); -#elif defined(__HAIKU__) - char path[PATH_MAX]; - if (find_path(B_APP_IMAGE_SYMBOL, B_FIND_PATH_IMAGE_PATH, - NULL, path, sizeof(path)) != B_OK) { - return; - } - - fd = open(path, O_RDONLY); -#else - fd = -1; -#endif - if (fd < 0) { - return; - } - - ret = read(fd, &elf_hdr, sizeof(elf_hdr)); - close(fd); - - if (ret != sizeof(elf_hdr) || - elf_hdr.emagic[0] != 0x7f || - elf_hdr.emagic[1] != 'E' || - elf_hdr.emagic[2] != 'L' || - elf_hdr.emagic[3] != 'F') { - return; - } - - jitdump_fd = open(filename, O_CREAT | O_TRUNC | O_RDWR, 0666); - if (jitdump_fd < 0) { - return; - } - - const size_t page_size = sysconf(_SC_PAGESIZE); - jitdump_mem = mmap(NULL, - page_size, - PROT_READ|PROT_EXEC, - MAP_PRIVATE, jitdump_fd, 0); - - if (jitdump_mem == MAP_FAILED) { - close(jitdump_fd); - jitdump_fd = -1; - return; - } - - zend_mmap_set_name(jitdump_mem, page_size, "zend_jitdump"); - - memset(&jit_hdr, 0, sizeof(jit_hdr)); - jit_hdr.magic = ZEND_PERF_JITDUMP_HEADER_MAGIC; - jit_hdr.version = ZEND_PERF_JITDUMP_HEADER_VERSION; - jit_hdr.size = sizeof(jit_hdr); - jit_hdr.elf_mach_target = elf_hdr.machine; - jit_hdr.process_id = getpid(); - jit_hdr.time_stamp = zend_perf_timestamp(); - jit_hdr.flags = 0; - zend_quiet_write(jitdump_fd, &jit_hdr, sizeof(jit_hdr)); -} - -static void zend_jit_perf_jitdump_close(void) -{ - if (jitdump_fd >= 0) { - zend_perf_jitdump_record rec; - - rec.event = ZEND_PERF_JITDUMP_RECORD_CLOSE; - rec.size = sizeof(rec); - rec.time_stamp = zend_perf_timestamp(); - zend_quiet_write(jitdump_fd, &rec, sizeof(rec)); - close(jitdump_fd); - - if (jitdump_mem != MAP_FAILED) { - munmap(jitdump_mem, sysconf(_SC_PAGESIZE)); - } - } -} - -static void zend_jit_perf_jitdump_register(const char *name, void *start, size_t size) -{ - if (jitdump_fd >= 0) { - static uint64_t id = 1; - zend_perf_jitdump_load_record rec; - size_t len = strlen(name); - uint32_t thread_id = 0; -#if defined(__linux__) - thread_id = syscall(SYS_gettid); -#elif defined(__darwin__) - uint64_t thread_id_u64; - pthread_threadid_np(NULL, &thread_id_u64); - thread_id = (uint32_t) thread_id_u64; -#elif defined(__FreeBSD__) - long tid; - thr_self(&tid); - thread_id = (uint32_t)tid; -#elif defined(__OpenBSD__) - thread_id = getthrid(); -#elif defined(__NetBSD__) - thread_id = _lwp_self(); -#elif defined(__DragonFly__) - thread_id = lwp_gettid(); -#elif defined(__sun) - thread_id = thr_self(); -#endif - - memset(&rec, 0, sizeof(rec)); - rec.hdr.event = ZEND_PERF_JITDUMP_RECORD_LOAD; - rec.hdr.size = sizeof(rec) + len + 1 + size; - rec.hdr.time_stamp = zend_perf_timestamp(); - rec.process_id = getpid(); - rec.thread_id = thread_id; - rec.vma = (uint64_t)(uintptr_t)start; - rec.code_address = (uint64_t)(uintptr_t)start; - rec.code_size = (uint64_t)size; - rec.code_id = id++; - - zend_quiet_write(jitdump_fd, &rec, sizeof(rec)); - zend_quiet_write(jitdump_fd, name, len + 1); - zend_quiet_write(jitdump_fd, start, size); - } -} - -static void zend_jit_perf_map_register(const char *name, void *start, size_t size) -{ - static FILE *fp = NULL; - - if (!fp) { - char filename[64]; - - sprintf(filename, "/tmp/perf-%d.map", getpid()); - fp = fopen(filename, "w"); - if (!fp) { - return; - } - setlinebuf(fp); - } - fprintf(fp, "%zx %zx %s\n", (size_t)(uintptr_t)start, size, name); -} -#else -#include -#include - -/* - * 1) To generate an Instrument tracing data: - * xcrun xctrace record --template