diff options
author | 2020-06-12 11:55:10 +0700 | |
---|---|---|
committer | 2020-06-12 11:55:10 +0700 | |
commit | 19214dd8e6528e056166a37b441568a9a264b086 (patch) | |
tree | 7403411d6d536153d1df6d8923f7594ace8b9a4f | |
parent | 7b6dbd7a1442d6a77f3b410966fdc41769e417b5 (diff) |
asmjist: sync with upstream (nw)
123 files changed, 14230 insertions, 11024 deletions
diff --git a/3rdparty/asmjit/.travis.yml b/3rdparty/asmjit/.travis.yml index b64f9eb3a86..0d541e6c10d 100644 --- a/3rdparty/asmjit/.travis.yml +++ b/3rdparty/asmjit/.travis.yml @@ -12,6 +12,13 @@ dist: bionic matrix: include: + - name: "Source Code Check" + env: BUILD_MATRIX="SOURCE_CODE_CHECK=1" + os: linux + language: node_js + node_js: + - node + - name: "Linux Clang Default [64-bit] [DBG]" env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=clang-9 && CXX=clang++-9" os: linux @@ -57,8 +64,8 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" packages: [clang++-9] - - name: "Linux Clang Default [64-bit] [REL] [NoBuilder]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_BUILDER=1" + - name: "Linux Clang Default [64-bit] [REL] [NoDeprecated]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_DEPRECATED=1" os: linux addons: apt: @@ -66,8 +73,8 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" packages: [clang++-9] - - name: "Linux Clang Default [64-bit] [REL] [NoCompiler]" - env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_COMPILER=1" + - name: "Linux Clang Default [64-bit] [REL] [NoIntrinsics]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_INTRINSICS=1" os: linux addons: apt: @@ -84,6 +91,24 @@ matrix: - sourceline: "ppa:ubuntu-toolchain-r/test" packages: [clang++-9] + - name: "Linux Clang Default [64-bit] [REL] [NoBuilder]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_BUILDER=1" + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] + + - name: "Linux Clang Default [64-bit] [REL] [NoCompiler]" + env: BUILD_MATRIX="BUILD_TYPE=Release && CC=clang-9 && CXX=clang++-9" EXTRA_OPTIONS="-DASMJIT_NO_COMPILER=1" + os: linux + addons: + apt: + sources: + - sourceline: "ppa:ubuntu-toolchain-r/test" + packages: [clang++-9] + - name: "Linux GCC 4.8 [32-bit] [DBG]" env: BUILD_MATRIX="BUILD_TYPE=Debug && CC=gcc-4.8 && CXX=g++-4.8" CXXFLAGS=-m32 LDFLAGS=-m32 os: linux @@ -268,36 +293,51 @@ before_install: - eval "$BUILD_MATRIX" before_script: - - mkdir build - - cd build - | - if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then - cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 ${EXTRA_OPTIONS} - else - cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 ${EXTRA_OPTIONS} -DCMAKE_PREFIX_PATH="${MINGW_PATH}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" + if [ -z $SOURCE_CODE_CHECK ]; then + mkdir build + cd build + if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then + cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 ${EXTRA_OPTIONS} + else + cmake .. -G"${BUILD_TOOLCHAIN}" -DASMJIT_TEST=1 ${EXTRA_OPTIONS} -DCMAKE_PREFIX_PATH="${MINGW_PATH}" -DCMAKE_BUILD_TYPE="${BUILD_TYPE}" + fi + cd .. fi - - cd .. script: - - cd build - | - if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then - cmake --build . --config ${BUILD_TYPE} -- -nologo -v:minimal - cd ${BUILD_TYPE} + if [ -z $SOURCE_CODE_CHECK ]; then + cd build + if [[ "$BUILD_TOOLCHAIN" =~ ^Visual\ Studio ]]; then + cmake --build . --config ${BUILD_TYPE} -- -nologo -v:minimal || exit 1 + cd ${BUILD_TYPE} + else + cmake --build . || exit 1 + fi + echo "" + echo "=== Starting Tests ===" + echo "" + if [ "$USE_VALGRIND" = "1" ]; then + RUN_CMD="valgrind --leak-check=full --show-reachable=yes --track-origins=yes" + fi + eval "$RUN_CMD ./asmjit_test_unit --quick" || exit 1 + echo "" + eval "$RUN_CMD ./asmjit_test_opcode > /dev/null" || exit 1 + echo "" + eval "$RUN_CMD ./asmjit_test_x86_asm" || exit 1 + echo "" + eval "$RUN_CMD ./asmjit_test_x86_sections" || exit 1 + if [ -f ./asmjit_test_x86_instinfo ]; then + echo "" + eval "$RUN_CMD ./asmjit_test_x86_instinfo" || exit 1 + fi + if [ -f ./asmjit_test_x86_cc ]; then + echo "" + eval "$RUN_CMD ./asmjit_test_x86_cc" || exit 1 + fi else - cmake --build . - fi - - - | - if [ "$USE_VALGRIND" = "1" ]; then - RUN_CMD="valgrind --leak-check=full --show-reachable=yes --track-origins=yes" - fi - - - eval "$RUN_CMD ./asmjit_test_unit --quick" - - eval "$RUN_CMD ./asmjit_test_opcode > /dev/null" - - eval "$RUN_CMD ./asmjit_test_x86_asm" - - eval "$RUN_CMD ./asmjit_test_x86_sections" - - | - if [ -f ./asmjit_test_x86_cc ]; then - eval "$RUN_CMD ./asmjit_test_x86_cc" + cd tools + ./enumgen.sh --verify || exit 1 + cd .. fi diff --git a/3rdparty/asmjit/CMakeLists.txt b/3rdparty/asmjit/CMakeLists.txt index 7b6c90b7179..e033c3ff663 100644 --- a/3rdparty/asmjit/CMakeLists.txt +++ b/3rdparty/asmjit/CMakeLists.txt @@ -1,7 +1,14 @@ cmake_minimum_required(VERSION 3.5 FATAL_ERROR) cmake_policy(PUSH) -cmake_policy(SET CMP0063 NEW) # Honor visibility properties. + +if(POLICY CMP0063) + cmake_policy(SET CMP0063 NEW) # Honor visibility properties. +endif() + +if(POLICY CMP0092) + cmake_policy(SET CMP0092 NEW) # Don't add -W3 warning level by default. +endif() include(CheckCXXCompilerFlag) @@ -62,9 +69,9 @@ set(ASMJIT_DIR "${CMAKE_CURRENT_LIST_DIR}" CACHE PATH "Location of 'asmji set(ASMJIT_TEST ${ASMJIT_TEST} CACHE BOOL "Build 'asmjit' test applications") set(ASMJIT_EMBED ${ASMJIT_EMBED} CACHE BOOL "Embed 'asmjit' library (no targets)") set(ASMJIT_STATIC ${ASMJIT_STATIC} CACHE BOOL "Build 'asmjit' library as static") -set(ASMJIT_SANITIZE ${ASMJIT_SANITIZE} CACHE BOOL "Build with C/C++ sanitizers enabled") +set(ASMJIT_SANITIZE ${ASMJIT_SANITIZE} CACHE STRING "Build with sanitizers: 'address', 'undefined', etc...") set(ASMJIT_BUILD_X86 ${ASMJIT_BUILD_X86} CACHE BOOL "Build X86 backends (X86 and X86_64)") -set(ASMJIT_BUILD_ARM ${ASMJIT_BUILD_ARM} CACHE BOOL "Build ARM backends") +set(ASMJIT_BUILD_ARM ${ASMJIT_BUILD_ARM} CACHE BOOL "Build ARM backends (ARM/Trumb and AArch64") # ============================================================================= # [AsmJit - Project] @@ -167,14 +174,13 @@ set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used b set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers. set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers. -# TODO: Backward compatibility. +# We will have to keep this most likely forever as some users may still be using it. set(ASMJIT_INCLUDE_DIR "${ASMJIT_INCLUDE_DIRS}") if (NOT ASMJIT_NO_CUSTOM_FLAGS) if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") list(APPEND ASMJIT_PRIVATE_CFLAGS -MP # [+] Multi-Process Compilation. - -GR- # [-] Runtime type information. -GF # [+] Eliminate duplicate strings. -Zc:inline # [+] Remove unreferenced COMDAT. -Zc:strictStrings # [+] Strict const qualification of string literals. @@ -189,7 +195,7 @@ if (NOT ASMJIT_NO_CUSTOM_FLAGS) -O2 # [+] Favor speed over size. -Oi) # [+] Generate intrinsic functions. elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang)$") - list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra) + list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion) list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno) list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) @@ -197,8 +203,10 @@ if (NOT ASMJIT_NO_CUSTOM_FLAGS) -fno-threadsafe-statics -fno-semantic-interposition) + # The following flags can save few bytes in the resulting binary. asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL - -fmerge-all-constants) + -fmerge-all-constants # Merge all constants even if it violates ISO C++. + -fno-enforce-eh-specs) # Don't enforce termination if noexcept function throws. endif() endif() @@ -248,6 +256,7 @@ foreach(build_option ASMJIT_STATIC ASMJIT_BUILD_X86 #ASMJIT_BUILD_ARM ASMJIT_BUILD_A64 + ASMJIT_NO_DEPRECATED ASMJIT_NO_JIT ASMJIT_NO_LOGGING ASMJIT_NO_BUILDER @@ -289,6 +298,7 @@ set(ASMJIT_SRC_LIST asmjit/core/builder.h asmjit/core/callconv.cpp asmjit/core/callconv.h + asmjit/core/codebuffer.h asmjit/core/codebufferwriter_p.h asmjit/core/codeholder.cpp asmjit/core/codeholder.h @@ -301,7 +311,15 @@ set(ASMJIT_SRC_LIST asmjit/core/datatypes.h asmjit/core/emitter.cpp asmjit/core/emitter.h + asmjit/core/emitterutils.cpp + asmjit/core/emitterutils_p.h + asmjit/core/environment.cpp + asmjit/core/environment.h + asmjit/core/errorhandler.cpp + asmjit/core/errorhandler.h asmjit/core/features.h + asmjit/core/formatter.cpp + asmjit/core/formatter.h asmjit/core/func.cpp asmjit/core/func.h asmjit/core/globals.cpp @@ -312,8 +330,8 @@ set(ASMJIT_SRC_LIST asmjit/core/jitallocator.h asmjit/core/jitruntime.cpp asmjit/core/jitruntime.h - asmjit/core/logging.cpp - asmjit/core/logging.h + asmjit/core/logger.cpp + asmjit/core/logger.h asmjit/core/misc_p.h asmjit/core/operand.cpp asmjit/core/operand.h @@ -353,6 +371,8 @@ set(ASMJIT_SRC_LIST asmjit/core/zonevector.h asmjit/x86.h + asmjit/x86/x86archdata.cpp + asmjit/x86/x86archdata_p.h asmjit/x86/x86assembler.cpp asmjit/x86/x86assembler.h asmjit/x86/x86builder.cpp @@ -364,6 +384,8 @@ set(ASMJIT_SRC_LIST asmjit/x86/x86emitter.h asmjit/x86/x86features.cpp asmjit/x86/x86features.h + asmjit/x86/x86formatter.cpp + asmjit/x86/x86formatter_p.h asmjit/x86/x86globals.h asmjit/x86/x86internal.cpp asmjit/x86/x86internal_p.h @@ -372,8 +394,6 @@ set(ASMJIT_SRC_LIST asmjit/x86/x86instdb_p.h asmjit/x86/x86instapi.cpp asmjit/x86/x86instapi_p.h - asmjit/x86/x86logging.cpp - asmjit/x86/x86logging_p.h asmjit/x86/x86operand.cpp asmjit/x86/x86operand.h asmjit/x86/x86rapass.cpp @@ -473,11 +493,27 @@ if (NOT ASMJIT_EMBED) CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) endforeach() + if (NOT ASMJIT_NO_INTROSPECTION) + asmjit_add_target(asmjit_test_x86_instinfo TEST + SOURCES test/asmjit_test_x86_instinfo.cpp + LIBRARIES AsmJit::AsmJit + CFLAGS ${ASMJIT_PRIVATE_CFLAGS} + CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} + CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) + endif() + if (NOT (ASMJIT_NO_BUILDER OR ASMJIT_NO_COMPILER)) + # Vectorcall tests and XMM tests require at least SSE2 (required in 32-bit mode). + set(sse2_flags "") + if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_SIMULATE_ID}" STREQUAL "xMSVC") + asmjit_detect_cflags(sse2_flags "-arch:SSE2") + else() + asmjit_detect_cflags(sse2_flags "-msse2") + endif() asmjit_add_target(asmjit_test_x86_cc TEST SOURCES test/asmjit_test_x86_cc.cpp LIBRARIES AsmJit::AsmJit - CFLAGS ${ASMJIT_PRIVATE_CFLAGS} + CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${sse2_flags} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) endif() diff --git a/3rdparty/asmjit/README.md b/3rdparty/asmjit/README.md index 24c726bd30a..abe51bb2169 100644 --- a/3rdparty/asmjit/README.md +++ b/3rdparty/asmjit/README.md @@ -1,140 +1,33 @@ AsmJit ------ -Machine code generation for C++. +AsmJit is a lightweight library for machine code generation written in C++ language. + * [Official Home Page (asmjit.com)](https://asmjit.com) * [Official Repository (asmjit/asmjit)](https://github.com/asmjit/asmjit) - * [Official Blog (asmbits)](https://asmbits.blogspot.com/ncr) - * [Official Chat (gitter)](https://gitter.im/asmjit/asmjit) - * [Permissive ZLIB license](./LICENSE.md) + * [Public Chat Channel](https://gitter.im/asmjit/asmjit) + * [Zlib License](./LICENSE.md) +See [asmjit.com](https://asmjit.com) page for more details, examples, and documentation. -Introduction ------------- +Documentation +------------- -AsmJit is a complete JIT and AOT assembler for C++ language. It can generate native code for x86 and x64 architectures and supports the whole x86/x64 instruction set - from legacy MMX to the newest AVX512. It has a type-safe API that allows C++ compiler to do semantic checks at compile-time even before the assembled code is generated and/or executed. + * [Documentation Index](https://asmjit.com/doc/index.html) + * [Build Instructions](https://asmjit.com/doc/group__asmjit__build.html) -AsmJit, as the name implies, started as a project that provided JIT code-generation and execution. However, AsmJit evolved and it now contains features that are far beyond the scope of a simple JIT compilation. To keep the library small and lightweight the functionality not strictly related to JIT is provided by a sister project called [asmtk](https://github.com/asmjit/asmtk). +Breaking Changes +---------------- +Breaking the API is sometimes inevitable, what to do? -Minimal Example ---------------- - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef int (*Func)(void); - -int main(int argc, char* argv[]) { - JitRuntime rt; // Runtime specialized for JIT code execution. - - CodeHolder code; // Holds code and relocation information. - code.init(rt.codeInfo()); // Initialize to the same arch as JIT runtime. - - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - a.mov(x86::eax, 1); // Move one to 'eax' register. - a.ret(); // Return from function. - // ----> x86::Assembler is no longer needed from here and can be destroyed <---- - - Func fn; - Error err = rt.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - int result = fn(); // Execute the generated code. - printf("%d\n", result); // Print the resulting "1". - - // All classes use RAII, all resources will be released before `main()` returns, - // the generated function can be, however, released explicitly if you intend to - // reuse or keep the runtime alive, which you should in a production-ready code. - rt.release(fn); - - return 0; -} -``` - - -AsmJit Summary --------------- - - * Complete x86/x64 instruction set - MMX, SSE+, BMI+, ADX, TBM, XOP, AVX+, FMA+, and AVX512+. - * Different emitters providing various abstraction levels (Assembler, Builder, Compiler). - * Support for sections for separating code and data. - * Built-in CPU vendor and features detection. - * Advanced logging, formatting, and error handling. - * JIT memory allocator - interface similar to malloc/free for JIT code-generation and execution. - * Lightweight and easily embeddable - ~300kB compiled with all built-in features. - * Modular design - unneeded features can be disabled at compile-time to make the library smaller. - * Zero dependencies - no external libraries, no STL/RTTI - easy to embed and/or link statically. - * Doesn't use exceptions internally, but allows to attach a "throwable" error handler of your choice. - - -Advanced Features ------------------ - - * AsmJit contains a highly compressed instruction database: - * Instruction names - allows to convert instruction id to its name and vice versa. - * Instruction metadata - access (read|write) of all operand combinations of all instructions. - * Instruction signatures - allows to strictly validate if an instruction (with all its operands) is valid. - * AsmJit allows to precisely control how instructions are encoded if there are multiple variations. - * AsmJit is highly dynamic, constructing operands at runtime is a common practice. - * Multiple emitters with the same interface - emit machine code directly or to a representation that can be post-processed. - - -Important ---------- - -Breaking the official API is sometimes inevitable, what to do? - * See asmjit tests, they always compile and provide an implementation of a lot of use-cases: + * See [Breaking Changes Guide](https://asmjit.com/doc/group__asmjit__breaking__changes.html), which is now part of AsmJit documentation. + * See asmjit tests, they always compile and provide implementation of many use-cases: * [asmjit_test_x86_asm.cpp](./test/asmjit_test_x86_asm.cpp) - Tests that demonstrate the purpose of emitters. * [asmjit_test_x86_cc.cpp](./test/asmjit_test_x86_cc.cpp) - A lot of tests targeting Compiler infrastructure. * [asmjit_test_x86_sections.cpp](./test/asmjit_test_x86_sections.cpp) - Multiple sections test. * Visit our [Official Chat](https://gitter.im/asmjit/asmjit) if you need a quick help. - -TODO ----- - - * [ ] Add support for user external buffers in CodeHolder. - - -Supported Environments ----------------------- - -### C++ Compilers: - - * Requirements: - * AsmJit won't build without C++11 enabled. If you use older GCC or Clang you would have to enable at least c++11 through compiler flags. - * Tested: - * **Clang** - tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang versions having C++11 support are probably fine, but are not regularly tested). - * **GNU** - tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is officially supported. - * **MINGW** - tested by Travis-CI - Use the latest version, if possible. - * **MSVC** - tested by Travis-CI - VS2017+ is officially supported, VS2015 is reported to work. - * Untested: - * **Intel** - no maintainers and no CI environment to regularly test this compiler. - * Other c++ compilers would require basic support in [core/build.h](./src/asmjit/core/build.h). - -### Operating Systems: - - * Tested: - * **Linux** - tested by Travis-CI - any distribution is generally supported. - * **OSX** - tested by Travis-CI - any version is supported. - * **Windows** - tested by Travis-CI - Windows 7+ is officially supported. - * Untested: - * **BSDs** - no maintainers, no CI environment to regularly test these OSes. - * **Haiku** - not regularly tested, but reported to work. - * Other operating systems would require some testing and support in [core/build.h](./src/asmjit/core/build.h), [core/osutils.cpp](./src/asmjit/core/osutils.cpp), and [core/virtmem.cpp](./src/asmjit/core/virtmem.cpp). - -### Backends: - - * **X86** - tested by both Travis-CI - both 32-bit and 64-bit backends are fully functional. - * **ARM** - work-in-progress (not public at the moment). - - Project Organization -------------------- @@ -145,1809 +38,22 @@ Project Organization * **arm** - ARM specific API, used only by ARM and AArch64 backends. * **x86** - X86 specific API, used only by X86 and X64 backends. * **test** - Unit and integration tests (don't embed in your project). - * **tools** - Tools used for configuring, documenting and generating data files. - - -Configuring & Feature Selection -------------------------------- - -AsmJit is designed to be easy embeddable in any project. However, it depends on some compile-time macros that can be used to build a specific version of AsmJit that includes or excludes certain features. A typical way of building AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to just include AsmJit source code in your project and just build it. The easiest way to include AsmJit in your project is to just include **src** directory in your project and to define `ASMJIT_STATIC`. AsmJit can be just updated from time to time without any changes to this integration process. Do not embed AsmJit's [/test](./test) files in such case as these are used for testing. - -### Build Type: - - * `ASMJIT_BUILD_DEBUG` - Define to always turn debugging on (regardless of compile-time options detected). - * `ASMJIT_BUILD_RELEASE` - Define to always turn debugging off (regardless of compile-time options detected). - -By default none of these is defined, AsmJit detects build-type based on compile-time macros and supports most IDE and compiler settings out of box. By default AsmJit switches to release mode when `NDEBUG` is defined. - -### Build Mode: - - * `ASMJIT_STATIC` - Define to build AsmJit statically - either as a static library or as a part of another project. No symbols are exported in such case. - -By default AsmJit build is configured to be built as a shared library, this means `ASMJIT_STATIC` must be explicitly enabled if you want to compile AsmJit statically. - -### Build Backends: - - * `ASMJIT_BUILD_ARM` - Build ARM backends (not ready, work-in-progress). - * `ASMJIT_BUILD_X86` - Build X86 backends (X86 and X86_64). - * `ASMJIT_BUILD_HOST` - Build only the host backend (default). - -If none of `ASMJIT_BUILD_...` is defined AsmJit bails to `ASMJIT_BUILD_HOST`, which will detect the target architecture at compile-time. Each backend automatically supports 32-bit and 64-bit targets, so for example AsmJit with X86 support can generate both 32-bit and 64-bit code. - -### Disabling Features: - - * `ASMJIT_NO_BUILDER` - Disables both `Builder` and `Compiler` emitters (only `Assembler` will be available). Ideal for users that don't use `Builder` concept and want to have AsmJit a bit smaller. - * `ASMJIT_NO_COMPILER` - Disables `Compiler` emitter. For users that use `Builder`, but not `Compiler`. - * `ASMJIT_NO_JIT` - Disables JIT execution engine, which includes `JitUtils`, `JitAllocator`, and `JitRuntime`. - * `ASMJIT_NO_LOGGING` - Disables logging (`Logger` and all classes that inherit it) and instruction formatting. - * `ASMJIT_NO_TEXT` - Disables everything that uses text-representation and that causes certain strings to be stored in the resulting binary. For example when this flag is set all instruction and error names (and related APIs) will not be available. This flag has to be disabled together with `ASMJIT_NO_LOGGING`. This option is suitable for deployment builds or builds that don't want to reveal the use of AsmJit. - * `ASMJIT_NO_INST_API` - Disables instruction query features, strict validation, read/write information, and all additional data and APIs that can output information about instructions. - -NOTE: Please don't disable any features if you plan to build AsmJit as a shared library that will be used by multiple projects that you don't control (for example asmjit in a Linux distribution). The possibility to disable certain features exists mainly for customized builds of AsmJit. - - -Using AsmJit ------------- - -AsmJit library uses one global namespace called `asmjit` that provides the whole functionality. Architecture specific code is prefixed by the architecture name and architecture specific registers and operand builders have their own namespace. For example API targeting both X86 and X64 architectures is prefixed with `X86` and registers & operand builders are accessible through `x86` namespace. This design is very different from the initial version of AsmJit and it seems now as the most convenient one. - -### CodeHolder & Emitters - -AsmJit provides two classes that are used together for code generation: - - * `CodeHolder` - Provides functionality to hold generated code and stores all necessary information about code sections, labels, symbols, and possible relocations. - * `BaseEmitter` - Provides functionality to emit code into `CodeHolder`. `BaseEmitter` is abstract and provides just basic building blocks that are then implemented by `BaseAssembler`, `BaseBuilder`, `BaseCompiler`, and their architecture-specific implementations like `x86::Assembler`, `x86::Builder`, and `x86::Compiler`. - -Code emitters: - - * `[Base]Assembler` - Emitter designed to emit machine code directly into a `CodeBuffer` held by `CodeHolder`. - * `[Base]Builder` - Emitter designed to emit code into a representation that can be processed afterwards. It stores the whole code in a double linked list consisting of nodes (`BaseNode` and all derived classes). There are nodes that represent instructions (`InstNode`), labels (`LabelNode`), and other building blocks (`AlignNode`, `DataNode`, ...). Some nodes are used as markers (`SentinelNode` and comments (`CommentNode`). - * `[Base]Compiler` - High-level code emitter that uses virtual registers and contains high-level function building features. Compiler extends `[Base]Builder` functionality and introduces new nodes like `FuncNode`, `FuncRetNode`, and `FuncCallNode`. Compiler is the simplest way to start with AsmJit as it abstracts lots of details required to generate a function that can be called from a C/C++ language. - -### Targets and JitRuntime - -AsmJit's `Target` class is an interface that provides basic target abstraction. At the moment only one implementation called `JitRuntime` is provided, which as the name suggests provides JIT code target and execution runtime. `JitRuntime` provides all the necessary functionality to implement a simple JIT functionality with basic memory management. It only provides `add()` and `release()` functions that are used to either add code to the runtime or release it. The `JitRuntime` doesn't do any decisions on when the code should be released. Once you add new code into it you must decide when that code is no longer needed and should be released. - -### Instructions & Operands - -Instructions specify operations performed by the CPU, and operands specify the operation's input(s) and output(s). Each AsmJit's instruction has it's own unique id (`Inst::Id` for example) and platform specific code emitters always provide a type safe intrinsic (or multiple overloads) to emit such instruction. There are two ways of emitting an instruction: - - * Using `BaseEmitter::inst(operands...)` - A type-safe way provided by platform specific emitters - for example `x86::Assembler` provides `x86::Assembler::mov(x86::Gp, x86::Gp)`. - * Using `BaseEmitter::emit(instId, operands...)` - Allows to emit an instruction in a dynamic way - you just need to know instruction's id and provide its operands. - -AsmJit's operands all inherit from a base class called `Operand` and then specialize its type to: - - * **None** (not used or uninitialized operand). - * **Register** (`BaseReg`) - Describes either physical or virtual register. Physical registers have id that matches the target's machine id directly whereas virtual registers must be allocated into physical registers by a register allocator pass. Register operand provides: - * **Register Type** - Unique id that describes each possible register provided by the target architecture - for example X86 backend provides `x86::Reg::RegType`, which defines all variations of general purpose registers (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K, MM, BND, XMM, YMM, and ZMM. - * **Register Group** - Groups multiple register types under a single group - for example all general-purpose registers (of all sizes) on X86 are `x86::Reg::kGroupGp`, all SIMD registers (XMM, YMM, ZMM) are `x86::Reg::kGroupVec`, etc. - * **Register Size** - Contains the size of the register in bytes. If the size depends on the mode (32-bit vs 64-bit) then generally the higher size is used (for example RIP register has size 8 by default). - * **Register ID** - Contains physical or virtual id of the register. - * Each architecture provides its own register that adds a architecture-specific API to `BaseReg`. - * **Memory Address** (`BaseMem`) - Used to reference a memory location. Memory operand provides: - * **Base Register** - A base register type and id (physical or virtual). - * **Index Register** - An index register type and id (physical or virtual). - * **Offset** - Displacement or absolute address to be referenced (32-bit if base register is used and 64-bit if base register is not used). - * **Flags** that can describe various architecture dependent information (like scale and segment-override on X86). - * Each architecture provides its own register that adds a architecture-specific API to `BaseMem`. - * **Immediate Value** (`Imm`) - Immediate values are usually part of instructions (encoded within the instruction itself) or data. - * **Label** - used to reference a location in code or data. Labels must be created by the `BaseEmitter` or by `CodeHolder`. Each label has its unique id per `CodeHolder` instance. - -AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them at run-time. Operands are small (always 16 bytes per `Operand`) and should be always copied (by value) if you intend to store them (don't create operands by using `new` keyword, it's not recommended). Operands are safe to be `memcpy()`ed and `memset()`ed if you need to work with arrays of operands. - -Small example of manipulating and using operands: - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -x86::Gp dstRegByValue() { return x86::ecx; } - -void usingOperandsExample(x86::Assembler& a) { - // Create some operands. - x86::Gp dst = dstRegByValue(); // Get `ecx` register returned by a function. - x86::Gp src = x86::rax; // Get `rax` register directly from the provided `x86` namespace. - x86::Gp idx = x86::gpq(10); // Construct `r10` dynamically. - x86::Mem m = x86::ptr(src, idx); // Construct [src + idx] memory address - referencing [rax + r10]. - - // Examine `m`: - m.indexType(); // Returns `x86::Reg::kTypeGpq`. - m.indexId(); // Returns 10 (`r10`). - - // Reconstruct `idx` stored in mem: - x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId()); - idx == idx_2; // True, `idx` and idx_2` are identical. - - Operand op = m; // Possible. - op.isMem(); // True (can be casted to BaseMem or architecture-specific Mem). - - m == op; // True, `op` is just a copy of `m`. - static_cast<BaseMem&>(op).addOffset(1); // Static cast is fine and valid here. - op.as<BaseMem>().addOffset(1); // However, using `as<T>()` to cast to a derived type is preferred. - m == op; // False, `op` now points to [rax + r10 + 1], which is not [rax + r10]. - - // Emitting 'mov' - a.mov(dst, m); // Type-safe way. - a.mov(dst, op); // Not possible, `mov` doesn't provide `mov(x86::Gp, Operand)` overload. - - a.emit(x86::Inst::kIdMov, dst, m); // Type-unsafe, but possible. - a.emit(x86::Inst::kIdMov, dst, op); // Also possible, `emit()` is typeless and can be used with raw `Operand`s. -} -``` - -Some operands have to be created explicitly by `BaseEmitter`. For example labels must be created by `newLabel()` before they are used. - -### Assembler Example - -`x86::Assembler` is a code emitter that emits machine code into a CodeBuffer directly. It's capable of targeting both 32-bit and 64-bit instruction sets and it's possible to target both instruction sets within the same code-base. The following example shows how to generate a function that works in both 32-bit and 64-bit modes, and how to use JitRuntime, `CodeHolder`, and `x86::Assembler` together. - -The example handles 3 calling conventions manually just to show how it could be done, however, AsmJit contains utilities that can be used to create function prologs and epilogs automatically, but these concepts will be explained later. - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef int (*SumFunc)(const int* arr, size_t count); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Create a runtime specialized for JIT. - CodeHolder code; // Create a CodeHolder. - - code.init(jit.codeInfo()); // Initialize it to be compatible with `jit`. - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions: - // 32-BIT - passed all arguments by stack. - // WIN64 - passes first 4 arguments by RCX, RDX, R8, and R9. - // UNIX64 - passes first 6 arguments by RDI, RSI, RCX, RDX, R8, and R9. - x86::Gp arr, cnt; - x86::Gp sum = x86::eax; // Use EAX as 'sum' as it's a return register. - - if (ASMJIT_ARCH_BITS == 64) { - #if defined(_WIN32) - arr = x86::rcx; // First argument (array ptr). - cnt = x86::rdx; // Second argument (number of elements) - #else - arr = x86::rdi; // First argument (array ptr). - cnt = x86::rsi; // Second argument (number of elements) - #endif - } - else { - arr = x86::edx; // Use EDX to hold the array pointer. - cnt = x86::ecx; // Use ECX to hold the counter. - a.mov(arr, x86::ptr(x86::esp, 4)); // Fetch first argument from [ESP + 4]. - a.mov(cnt, x86::ptr(x86::esp, 8)); // Fetch second argument from [ESP + 8]. - } - - Label Loop = a.newLabel(); // To construct the loop, we need some labels. - Label Exit = a.newLabel(); - - a.xor_(sum, sum); // Clear 'sum' register (shorter than 'mov'). - a.test(cnt, cnt); // Border case: - a.jz(Exit); // If 'cnt' is zero jump to 'Exit' now. - - a.bind(Loop); // Start of a loop iteration. - a.add(sum, x86::dword_ptr(arr)); // Add int at [arr] to 'sum'. - a.add(arr, 4); // Increment 'arr' pointer. - a.dec(cnt); // Decrease 'cnt'. - a.jnz(Loop); // If not zero jump to 'Loop'. - - a.bind(Exit); // Exit to handle the border case. - a.ret(); // Return from function ('sum' == 'eax'). - // ----> x86::Assembler is no longer needed from here and can be destroyed <---- - - SumFunc fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - static const int array[6] = { 4, 8, 15, 16, 23, 42 }; - - int result = fn(array, 6); // Execute the generated code. - printf("%d\n", result); // Print sum of array (108). - - jit.release(fn); // Remove the function from the runtime. - return 0; -} -``` - -The example should be self-explanatory. It shows how to work with labels, how to use operands, and how to emit instructions that can use different registers based on runtime selection. It implements 32-bit CDECL, WIN64, and SysV64 caling conventions and will work on most X86 environments. - -### More About Memory Addresses - -X86 provides a complex memory addressing model that allows to encode addresses having a BASE register, INDEX register with a possible scale (left shift), and displacement (called offset in AsmJit). Memory address can also specify memory segment (segment-override in X86 terminology) and some instructions (gather / scatter) require INDEX to be a VECTOR register instead of a general-purpose register. AsmJit allows to encode and work with all forms of addresses mentioned and implemented by X86. It also allows to construct a 64-bit memory address, which is only allowed in one form of 'mov' instruction. - -```c++ -#include <asmjit/asmjit.h> - -// Memory operand construction is provided by x86 namespace. -using namespace asmjit; -using namespace asmjit::x86; // Easier to access x86 regs. - -// BASE + OFFSET. -x86::Mem a = ptr(rax); // a = [rax] -x86::Mem b = ptr(rax, 15) // b = [rax + 15] - -// BASE + INDEX << SHIFT - Shift is in BITS as used by X86! -x86::Mem c = ptr(rax, rbx) // c = [rax + rbx] -x86::Mem d = ptr(rax, rbx, 2) // d = [rax + rbx << 2] -x86::Mem e = ptr(rax, rbx, 2, 15) // e = [rax + rbx << 2 + 15] - -// BASE + VM (Vector Index) (encoded as MOD+VSIB). -x86::Mem f = ptr(rax, xmm1) // f = [rax + xmm1] -x86::Mem g = ptr(rax, xmm1, 2) // g = [rax + xmm1 << 2] -x86::Mem h = ptr(rax, xmm1, 2, 15) // h = [rax + xmm1 << 2 + 15] - -// WITHOUT BASE: -uint64_t ADDR = (uint64_t)0x1234; -x86::Mem i = ptr(ADDR); // i = [0x1234] -x86::Mem j = ptr(ADDR, rbx); // j = [0x1234 + rbx] -x86::Mem k = ptr(ADDR, rbx, 2); // k = [0x1234 + rbx << 2] - -// LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit). -Label L = ...; -x86::Mem m = ptr(L); // m = [L] -x86::Mem n = ptr(L, rbx); // n = [L + rbx] -x86::Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2] -x86::Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15] - -// RIP - 64-bit only (RIP can't use INDEX). -x86::Mem q = ptr(rip, 24); // q = [rip + 24] -``` - -Memory operands can optionally contain memory size. This is required by instructions where the memory size cannot be deduced from other operands, like `inc` and `dec`: - -```c++ -x86::Mem a = x86::dword_ptr(rax, rbx); // dword ptr [rax + rbx]. -x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1); // qword ptr [rdx + rsi << 0 + 1]. -``` - -Memory operands provide API that can be used to work with them: - -```c++ -x86::Mem mem = x86::dword_ptr(rax, 12); // dword ptr [rax + 12]. - -mem.hasBase(); // true. -mem.hasIndex(); // false. -mem.size(); // 4. -mem.offset(); // 12. - -mem.setSize(0); // Sets the size to 0 (makes it sizeless). -mem.addOffset(-1); // Adds -1 to the offset and makes it 11. -mem.setOffset(0); // Sets the offset to 0. -mem.setBase(rcx); // Changes BASE to RCX. -mem.setIndex(rax); // Changes INDEX to RAX. -mem.hasIndex(); // true. - -// ... -``` - -Making changes to memory operand is very comfortable when emitting loads and stores: - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -x86::Assembler a(...); // Your initialized x86::Assembler. -x86::Mem m = x86::ptr(eax); // Construct [eax] memory operand. - -// One way of emitting bunch of loads is to use `mem.adjusted()`. It returns -// a new memory operand and keeps the source operand unchanged. -a.movaps(x86::xmm0, m); // No adjustment needed to load [eax]. -a.movaps(x86::xmm1, m.adjusted(16)); // Loads from [eax + 16]. -a.movaps(x86::xmm2, m.adjusted(32)); // Loads from [eax + 32]. -a.movaps(x86::xmm3, m.adjusted(48)); // Loads from [eax + 48]. - -// ... do something with xmm0-3 ... - -// Another way of adjusting memory is to change the operand in-place. If you -// want to keep the original operand you can simply clone it. -x86::Mem mx = m.clone(); -a.movaps(mx, x86::xmm0); mx.addOffset(16);// Stores to [eax] (and adds 16 to mx). -a.movaps(mx, x86::xmm1); mx.addOffset(16);// Stores to [eax + 16] (and adds 16 to mx). -a.movaps(mx, x86::xmm2); mx.addOffset(16);// Stores to [eax + 32] (and adds 16 to mx). -a.movaps(mx, x86::xmm3); // Stores to [eax + 48]. -``` - -You can explore the possibilities by taking a look at: - - * [core/operand.h](./src/asmjit/core/operand.h) - * [x86/x86operand.h](./src/asmjit/x86/x86operand.h). - -### More About CodeInfo - -In the first complete example the `CodeInfo` is retrieved from `JitRuntime`. It's logical as `JitRuntime` will always return a `CodeInfo` that is compatible with the runtime environment. For example if your application runs in 64-bit mode the `CodeInfo` will use `ArchInfo::kIdX64` architecture in contrast to `ArchInfo::kIdX86`, which will be used in 32-bit mode. AsmJit also allows to setup `CodeInfo` manually, and to select a different architecture when needed. So let's do something else this time, let's always generate a 32-bit code and print it's binary representation. To do that, we create our own `CodeInfo` and initialize it to `ArchInfo::kIdX86` architecture. CodeInfo will populate all basic fields just based on the architecture we provide, so it's super-easy: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -int main(int argc, char* argv[]) { - using namespace asmjit::x86; // Easier access to x86/x64 registers. - - CodeHolder code; // Create a CodeHolder. - code.init(CodeInfo(ArchInfo::kIdX86));// Initialize it for a 32-bit X86 target. - - // Generate a 32-bit function that sums 4 floats and looks like: - // void func(float* dst, const float* a, const float* b) - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer. - a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer. - a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer. - - a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0. - a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1. - a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0. - a.movups(ptr(eax), xmm0); // Store the result to [eax]. - a.ret(); // Return from function. - - // We have no Runtime this time, it's on us what we do with the code. - // CodeHolder stores code in `Section`, which provides some basic properties - // and CodeBuffer structure. We are interested in section's CodeBuffer only. - // - // NOTE: The first section is always '.text', so it's safe to just use 0 index. - // Get it by using either `code.sectionById(0)` or `code.textSection()`. - CodeBuffer& buffer = code.sectionById(0)->buffer(); - - // Print the machine-code generated or do something more interesting with it? - // 8B4424048B4C24048B5424040F28010F58010F2900C3 - for (size_t i = 0; i < buffer.length; i++) - printf("%02X", buffer.data[i]); - - return 0; -} -``` - -### Explicit Code Relocation - -CodeInfo contains much more information than just the target architecture. It can be configured to specify a base-address (or a virtual base-address in a linker terminology), which could be static (useful when you know the location of the target's machine code) or dynamic. AsmJit assumes dynamic base-address by default and relocates the code held by `CodeHolder` to a user-provided address on-demand. To be able to relocate to a user-provided address it needs to store some information about relocations, which is represented by `RelocEntry`. Relocation entries are only required if you call external functions from the generated code that cannot be encoded by using a 32-bit displacement (X64 architecture doesn't provide an encodable 64-bit displacement). - -There is also a concept called `LabelLink` - label links are lightweight structs that don't have any identifier and are stored per label in a single-linked list. Label links represent either unbound yet used labels (that are valid in cases in which label was not bound but was already referenced by an instruction) and links that cross-sections (only relevant to code that uses multiple sections). Since crossing sections is something that cannot be resolved immediately these links persist until offsets of these sections are assigned and `CodeHolder::resolveUnresolvedLinks()` is called. It's an error if you end up with code that has unresolved label links after flattening. You can verify it by calling `CodeHolder::hasUnresolvedLinks()` and `CodeHolder::unresolvedLinkCount()`. - -AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects its alignment. Use `CodeHolder::flatten()` to do that. After the sections are flattened their offsets and virtual-sizes were adjusted to respect section's buffer size and alignment. You must call `CodeHolder::resolveUnresolvedLinks()` before relocating the code held by it. You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to base) by your own algorithm. In that case you don't have to call `CodeHolder::flatten()`, but you must still call `CodeHolder::resolveUnresolvedLinks()`. - -Next example shows how to use a built-in virtual memory allocator `JitAllocator` instead of using `JitRuntime` (just in case you want to use your own memory management) and how to relocate the generated code into your own memory block - you can use your own virtual memory allocator if you prefer that, but that's OS specific and it's already provided by AsmJit, so we will use what AsmJit offers instead of going deep into OS specific APIs. - -The following code is similar to the previous one, but implements a function working in both 32-bit and 64-bit environments: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); - -int main(int argc, char* argv[]) { - CodeHolder code; // Create a CodeHolder. - code.init(CodeInfo(ArchInfo::kIdHost)); // Initialize it for the host architecture. - - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - // Generate a function runnable in both 32-bit and 64-bit architectures: - bool isX86 = ASMJIT_ARCH_X86 == 32; - - // Signature: 'void func(int* dst, const int* a, const int* b)'. - x86::Gp dst; - x86::Gp src_a; - x86::Gp src_b; - - // Handle the difference between 32-bit and 64-bit calling convention. - // (arguments passed through stack vs. arguments passed by registers). - if (isX86) { - dst = x86::eax; - src_a = x86::ecx; - src_b = x86::edx; - a.mov(dst , x86::dword_ptr(x86::esp, 4)); // Load the destination pointer. - a.mov(src_a, x86::dword_ptr(x86::esp, 8)); // Load the first source pointer. - a.mov(src_b, x86::dword_ptr(x86::esp, 12)); // Load the second source pointer. - } - else { - #if defined(_WIN32) - dst = x86::rcx; // First argument (destination pointer). - src_a = x86::rdx; // Second argument (source 'a' pointer). - src_b = x86::r8; // Third argument (source 'b' pointer). - #else - dst = x86::rdi; // First argument (destination pointer). - src_a = x86::rsi; // Second argument (source 'a' pointer). - src_b = x86::rdx; // Third argument (source 'b' pointer). - #endif - } - - a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. - a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. - a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0. - a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst]. - a.ret(); // Return from function. - - // Even when we didn't use multiple sections AsmJit could insert one section - // called '.addrtab' (address table section), which would be filled by data - // required by relocations (absolute jumps and calls). You can omit this code - // if you are 100% sure your code doesn't contain multiple sections and - // such relocations. You can use `CodeHolder::hasAddressTable()` to verify - // whether the address table section does exist. - code.flatten(); - code.resolveUnresolvedLinks(); - - // After the code was generated it can be relocated manually to any memory - // location, however, we need to know it's size before we perform memory - // allocation. `CodeHolder::codeSize()` returns the worst estimated code - // size in case that relocations are not possible without trampolines (in - // that case some extra code at the end of the current code buffer is - // generated during relocation). - size_t estimatedSize = code.codeSize(); - - // Instead of rolling up our own memory allocator we can use the one AsmJit - // provides. It's decoupled so you don't need to use `JitRuntime` for that. - JitAllocator allocator; - - // Allocate an executable virtual memory and handle a possible failure. - void* p = allocator.alloc(estimatedSize); - if (!p) return 0; - - // Now relocate the code to the address provided by the memory allocator. - // Please note that this DOESN'T COPY anything to `p`. This function will - // store the address in CodeInfo and use relocation entries to patch the - // existing code in all sections to respect the base address provided. - code.relocateToBase((uint64_t)p); - - // This is purely optional. There are cases in which the relocation can - // omit unneeded data, which would shrink the size of address table. If - // that happened the `codeSize` returned after `relocateToBase()` would - // be smaller than the originally `estimatedSize`. - size_t codeSize = code.codeSize(); - - // This will copy code from all sections to `p`. Iterating over all - // sections and calling `memcpy()` would work as well, however, this - // function supports additional options that can be used to also zero - // pad sections' virtual size, etc. - // - // With some additional features, copyFlattenData() does roughly this: - // for (Section* section : code.sections()) - // memcpy((uint8_t*)p + section->offset(), - // section->data(), - // section->bufferSize()); - code.copyFlattenedData(p, codeSize, CodeHolder::kCopyWithPadding); - - // Execute the generated function. - int inA[4] = { 4, 3, 2, 1 }; - int inB[4] = { 1, 5, 2, 8 }; - int out[4]; - - // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc. - ptr_as_func<SumIntsFunc>(p)(out, inA, inB); - - // Prints {5 8 4 9} - printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); - - // Release 'p' is it's no longer needed. It will be destroyed with 'vm' - // instance anyway, but it's a good practice to release it explicitly - // when you know that the function will not be needed anymore. - allocator.release(p); - - return 0; -} -``` - -If you know your base-address in advance (before code generation) you can use `CodeInfo::setBaseAddress()` to setup its initial value. In that case Assembler will know the absolute position of each instruction and would be able to use it during instruction encoding and prevent relocations in case the instruction is encodable. The following example shows how to configure the base address: - -```c++ -// Configure CodeInfo with base address. -CodeInfo ci(...); -ci.setBaseAddress(uint64_t(0x1234)); - -// Then initialize CodeHolder with it. -CodeHolder code; -code.init(ci); -``` - -### Using Native Registers - zax, zbx, zcx, ... - -AsmJit's X86 code emitters always provide functions to construct machine-size registers depending on the target. This feature is for people that want to write code targeting both 32-bit and 64-bit at the same time. In AsmJit terminology these registers are named **zax**, **zcx**, **zdx**, **zbx**, **zsp**, **zbp**, **zsi**, and **zdi** (they are defined in this exact order by X86). They are accessible through `x86::Assembler`, `x86::Builder`, and `x86::Compiler`. The following example illustrates how to use this feature: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -typedef int (*Func)(void); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Create a runtime specialized for JIT. - CodeHolder code; // Create a CodeHolder. - - code.init(jit.codeInfo()); // Initialize it to be compatible with `jit`. - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - // Let's get these registers from x86::Assembler. - x86::Gp zbp = a.zbp(); - x86::Gp zsp = a.zsp(); - - int stackSize = 32; - - // Function prolog. - a.push(zbp); - a.mov(zbp, zsp); - a.sub(zsp, stackSize); - - // ... emit some code (this just sets return value to zero) ... - a.xor_(x86::eax, x86::eax); - - // Function epilog and return. - a.mov(zsp, zbp); - a.pop(zbp); - a.ret(); - - // To make the example complete let's call it. - Func fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - - int result = fn(); // Execute the generated code. - printf("%d\n", result); // Print the resulting "0". - - jit.release(fn); // Remove the function from the runtime. - return 0; -} -``` - -The example just returns `0`, but the function generated contains a standard prolog and epilog sequence and the function itself reserves 32 bytes of local stack. The advantage is clear - a single code-base can handle multiple targets easily. If you want to create a register of native size dynamically by specifying its id it's also possible: - -```c++ -void example(x86::Assembler& a) { - x86::Gp zax = a.gpz(x86::Gp::kIdAx); - x86::Gp zbx = a.gpz(x86::Gp::kIdBx); - x86::Gp zcx = a.gpz(x86::Gp::kIdCx); - x86::Gp zdx = a.gpz(x86::Gp::kIdDx); - - // You can also change register's id easily. - x86::Gp zsp = zax; - zsp.setId(4); // or x86::Gp::kIdSp. -} -``` - -Cloning existing registers and chaning their IDs is fine in AsmJit; and this technique is used internally in many places. - -### Using Assembler as Code-Patcher - -This is an advanced topic that is sometimes unavoidable. AsmJit by default appends machine-code it generates into a `CodeBuffer`, however, it also allows to set the offset in `CodeBuffer` explicitly and to overwrite its content. This technique is extremely dangerous for asm beginners as X86 instructions have variable length (see below), so you should in general only patch code to change instruction's offset or some basic other details you didn't know about the first time you emitted it. A typical scenario that requires code-patching is when you start emitting function and you don't know how much stack you want to reserve for it. - -Before we go further it's important to introduce instruction options, because they can help with code-patching (and not only patching, but that will be explained in AVX-512 section): - - * Many general-purpose instructions (especially arithmetic ones) on X86 have multiple encodings - in AsmJit this is usually called 'short form' and 'long form'. - * AsmJit always tries to use 'short form' as it makes the resulting machine-code smaller, which is always good - this decision is used by majority of assemblers out there. - * AsmJit allows to override the default decision by using `short_()` and `long_()` instruction options to force short or long form, respectively. The most useful is `long_()` as it basically forces AsmJit to always emit the long form. The `short_()` is not that useful as it's automatic (except jumps to non-bound labels). Note the underscore after each function name as it avoids collision with built-in C++ types. - -To illustrate what short form and long form means in binary let's assume we want to emit `add esp, 16` instruction, which has two possible binary encodings: - - * `83C410` - This is a short form aka `short add esp, 16` - You can see opcode byte (0x8C), MOD/RM byte (0xC4) and an 8-bit immediate value representing `16`. - * `81C410000000` - This is a long form aka `long add esp, 16` - You can see a different opcode byte (0x81), the same Mod/RM byte (0xC4) and a 32-bit immediate in little-endian representing `16`. - -If you generate an instruction in a short form and then patch it in a long form or vice-versa then something really bad will happen when you try to execute such code. The following example illustrates how to patch the code properly (it just extends the previous example): - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -typedef int (*Func)(void); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Create a runtime specialized for JIT. - CodeHolder code; // Create a CodeHolder. - - code.init(jit.codeInfo()); // Initialize it to be compatible with `jit`. - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - // Let's get these registers from x86::Assembler. - x86::Gp zbp = a.zbp(); - x86::Gp zsp = a.zsp(); - - // Function prolog. - a.push(zbp); - a.mov(zbp, zsp); - - // This is where we are gonna patch the code later, so let's get the offset - // (the current location) from the beginning of the code-buffer. - size_t patchOffset = a.offset(); - // Let's just emit 'sub zsp, 0' for now, but don't forget to use LONG form. - a.long_().sub(zsp, 0); - - // ... emit some code (this just sets return value to zero) ... - a.xor_(x86::eax, x86::eax); - - // Function epilog and return. - a.mov(zsp, zbp); - a.pop(zbp); - a.ret(); - - // Now we know how much stack size we want to reserve. I have chosen 128 - // bytes on purpose as it's encodable only in long form that we have used. - - int stackSize = 128; // Number of bytes to reserve on the stack. - a.setOffset(patchOffset); // Move the current cursor to `patchOffset`. - a.long_().sub(zsp, stackSize); // Patch the code; don't forget to use LONG form. - - // Now the code is ready to be called - Func fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - - int result = fn(); // Execute the generated code. - printf("%d\n", result); // Print the resulting "0". - - jit.release(fn); // Remove the function from the runtime. - return 0; -} -``` - -If you run the example it would just work. As an experiment you can try removing `long_()` form to see what happens when wrong code is generated. - -### Code Patching and REX Prefix - -In 64-bit mode there is one more thing to worry about when patching code - REX prefix. It's a single byte prefix designed to address registers with ids from 9 to 15 and to override the default width of operation from 32 to 64 bits. AsmJit, like other assemblers, only emits REX prefix when it's necessary. If the patched code only changes the immediate value as shown in the previous example then there is nothing to worry about as it doesn't change the logic behind emitting REX prefix, however, if the patched code changes register id or overrides the operation width then it's important to take care of REX prefix as well. - -AsmJit contains another instruction option that controls (forces) REX prefix - `rex()`. If you use it the instruction emitted will always use REX prefix even when it's encodable without it. The following list contains some instructions and their binary representations to illustrate when it's emitted: - - * `__83C410` - `add esp, 16` - 32-bit operation in 64-bit mode doesn't require REX prefix. - * `4083C410` - `rex add esp, 16` - 32-bit operation in 64-bit mode with forced REX prefix (0x40). - * `4883C410` - `add rsp, 16` - 64-bit operation in 64-bit mode requires REX prefix (0x48). - * `4183C410` - `add r12d, 16` - 32-bit operation in 64-bit mode using R12D requires REX prefix (0x41). - * `4983C410` - `add r12, 16` - 64-bit operation in 64-bit mode using R12 requires REX prefix (0x49). - -### Generic Function API - -So far all examples shown above handled creating function prologs and epilogs manually. While it's possible to do it that way it's much better to automate such process as function calling conventions vary across architectures and also across operating systems. - -AsmJit contains a functionality that can be used to define function signatures and to calculate automatically optimal function frame that can be used directly by a prolog and epilog inserter. This feature was exclusive to AsmJit's Compiler for a very long time, but was abstracted out and is now available for all users regardless of BaseEmitter they use. The design of handling functions prologs and epilogs allows generally two use cases: - - * Calculate function frame before the function is generated - this is the only way if you use pure `Assembler` emitter and shown in the next example. - * Calculate function frame after the function is generated - this way is generally used by `Builder` and `Compiler` emitters(will be described together with `x86::Compiler`). - -The following concepts are used to describe and create functions in AsmJit: - - * `Type` - Type is an 8-bit value that describes a platform independent type as we know from C/C++. It provides abstractions for most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, `double`, and all possible vector types to match ISAs up to AVX512. `Type::Id` was introduced originally to be used with the Compiler infrastucture, but is now used by `FuncSignature` as well. - - * `CallConv` - Describes a calling convention - this class contains instructions to assign registers and stack addresses to function arguments and return value(s), but doesn't specify any function signature. Calling conventions are architecture and OS dependent. - - * `FuncSignature` - Describes a function signature, for example `int func(int, int)`. `FuncSignature` contains a function calling convention id, return value type, and function arguments. The signature itself is platform independent and uses `Type::Id` to describe types of function arguments and its return value(s). - - * `FuncDetail` - Architecture and ABI dependent information that describes `CallConv` and expanded `FuncSignature`. Each function argument and return value is represented as `FuncValue` that contains the original `Type::Id` enriched by additional information that specifies if the value is passed/returned by register (and which register) or by stack. Each value also contains some other metadata that provide additional information required to handle it properly (for example if a vector value is passed indirectly by a pointer as required by WIN64 calling convention, etc...). - - * `FuncFrame` - Contains information about the function frame that can be used by prolog/epilog inserter (PEI). Holds call stack size size and alignment, local stack size and alignment, and various attributes that describe how prolog and epilog should be constructed. `FuncFrame` doesn't know anything about function's arguments or return values, it hold only information necessary to create a valid and ABI conforming function prologs and epilogs. - - * `FuncArgsAssignment` - A helper class that can be used to reassign function arguments into user specified registers. It's architecture and ABI dependent mapping from function arguments described by CallConv and FuncDetail into registers specified by the user. - -It's a lot of concepts where each represents one step in the function frame calculation. In addition, the whole machinery can also be used to create function calls, instead of function prologs and epilogs. The next example shows how AsmJit can be used to create functions for both 32-bit and 64-bit targets and various calling conventions: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Create JIT Runtime. - CodeHolder code; // Create a CodeHolder. - - code.init(jit.codeInfo()); // Initialize it to match `jit`. - x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. - - // Decide which registers will be mapped to function arguments. Try changing - // registers of `dst`, `src_a`, and `src_b` and see what happens in function's - // prolog and epilog. - x86::Gp dst = a.zax(); - x86::Gp src_a = a.zcx(); - x86::Gp src_b = a.zdx(); - - X86::Xmm vec0 = x86::xmm0; - X86::Xmm vec1 = x86::xmm1; - - // Create and initialize `FuncDetail` and `FuncFrame`. - FuncDetail func; - func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); - - FuncFrame frame; - frame.init(func); - - // Make XMM0 and XMM1 dirty; `kGroupVec` describes XMM|YMM|ZMM registers. - frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); - - // Alternatively, if you don't want to use register masks you can pass `BaseReg` - // to `addDirtyRegs()`. The following code would add both `xmm0` and `xmm1`. - frame.addDirtyRegs(x86::xmm0, x86::xmm1); - - FuncArgsAssignment args(&func); // Create arguments assignment context. - args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. - args.updateFrameInfo(frame); // Reflect our args in FuncFrame. - frame.finalize(); // Finalize the FuncFrame (updates it). - - a.emitProlog(frame); // Emit function prolog. - a.emitArgsAssignment(frame, args); // Assign arguments to registers. - a.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. - a.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. - a.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. - a.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. - a.emitEpilog(frame); // Emit function epilog and return. - - SumIntsFunc fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error case. - - // Execute the generated function. - int inA[4] = { 4, 3, 2, 1 }; - int inB[4] = { 1, 5, 2, 8 }; - int out[4]; - fn(out, inA, inB); - - // Prints {5 8 4 9} - printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); - - jit.release(fn); // Remove the function from the runtime. - return 0; -} -``` - - -Builder Interface ------------------ - -Both `Builder` and `Compiler` are emitters that emit everything to a representation that allows further processing. The code stored in such representation is completely safe to be patched, simplified, reordered, obfuscated, removed, injected, analyzed, and 'think-of-anything-else'. Each instruction, label, directive, etc... is stored in `BaseNode` (or derived class like `InstNode` or `LabelNode`) and contains all the information required to pass it later to the `Assembler`. - -There is a huge difference between `Builder` and `Compiler`: - - * `Builder` (low-level): - * Maximum compatibility with `Assembler`, easy to switch from `Assembler` to `Builder` and vice versa. - * Doesn't generate machine code directly, allows to serialize to `Assembler` when the whole code is ready to be encoded. - - * `Compiler` (high-level): - * Virtual registers - allows to use unlimited number of virtual registers which are allocated into physical registers by a built-in register allocator. - * Function nodes - allows to create functions by specifying their signatures and assigning virtual registers to function arguments and return value(s). - * Function calls - allows to call other functions within the generated code by using the same interface that is used to create functions. - -There are multiple node types used by both `Builder` and `Compiler`: - - * Basic nodes: - * `BaseNode` - Base class for all nodes. - * `InstNode` - Instruction node. - * `AlignNode` - Alignment directive (.align). - * `LabelNode` - Label (location where to bound it). - - * Data nodes: - * `DataNode` - Data embedded into the code. - * `ConstPoolNode` - Constant pool data. - * `LabelDataNode` - Label address embedded as data. - - * Informative nodes: - * `CommentNode` - Contains a comment string, doesn't affect code generation. - * `SentinelNode` - A marker that can be used to remember certain position, doesn't affect code generation. - - * Compiler-only nodes: - * `FuncNode` - Start of a function. - * `FuncRetNode` - Return from a function. - * `FuncCallNode` - Function call. - -### Using Builder - -The Builder interface was designed to be used as an `Assembler` replacement in case that post-processing of the generated code is required. The code can be modified during or after code generation. The post processing can be done manually or through `Pass` (Code-Builder Pass) object. Builder stores the emitted code as a double-linked list, which allows O(1) insertion and removal. - -The code representation used by `Builder` is compatible with everything AsmJit provides. Each instruction is stored as `InstNode`, which contains instruction id, options, and operands. Each instruction emitted will create a new `InstNode` instance and add it to the current cursor in the double-linked list of nodes. Since the instruction stream used by `Builder` can be manipulated, we can rewrite the **SumInts** example into the following: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); - -// Small helper function to print the current content of `cb`. -static void dumpCode(BaseBuilder& cb, const char* phase) { - StringBuilder sb; - cb.dump(sb); - printf("%s:\n%s\n", phase, sb.data()); -} - -int main(int argc, char* argv[]) { - JitRuntime jit; // Create JIT Runtime. - CodeHolder code; // Create a CodeHolder. - - code.init(jit.codeInfo()); // Initialize it to match `jit`. - x86::Builder cb(&code); // Create and attach x86::Builder to `code`. - - // Decide which registers will be mapped to function arguments. Try changing - // registers of `dst`, `src_a`, and `src_b` and see what happens in function's - // prolog and epilog. - x86::Gp dst = cb.zax(); - x86::Gp src_a = cb.zcx(); - x86::Gp src_b = cb.zdx(); - - X86::Xmm vec0 = x86::xmm0; - X86::Xmm vec1 = x86::xmm1; - - // Create and initialize `FuncDetail`. - FuncDetail func; - func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); - - // Remember prolog insertion point. - BaseNode* prologInsertionPoint = cb.cursor(); + * **tools** - Tools used for configuring, documenting, and generating files. - // Emit function body: - cb.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. - cb.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. - cb.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. - cb.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. - - // Remember epilog insertion point. - BaseNode* epilogInsertionPoint = cb.cursor(); - - // Let's see what we have now. - dumpCode(cb, "Raw Function"); - - // Now, after we emitted the function body, we can insert the prolog, arguments - // allocation, and epilog. This is not possible with using pure x86::Assembler. - FuncFrame frame; - frame.init(func); - - // Make XMM0 and XMM1 dirty; `kGroupVec` describes XMM|YMM|ZMM registers. - frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); - - FuncArgsAssignment args(&func); // Create arguments assignment context. - args.assignAll(dst, src_a, src_b); // Assign our registers to arguments. - args.updateFrame(frame); // Reflect our args in FuncFrame. - frame.finalize(); // Finalize the FuncFrame (updates it). - - // Insert function prolog and allocate arguments to registers. - cb.setCursor(prologInsertionPoint); - cb.emitProlog(frame); - cb.emitArgsAssignment(frame, args); - - // Insert function epilog. - cb.setCursor(epilogInsertionPoint); - cb.emitEpilog(frame); - - // Let's see how the function's prolog and epilog looks. - dumpCode(cb, "Prolog & Epilog"); - - // IMPORTANT: Builder requires `finalize()` to be called to serialize the code - // to the Assembler (it automatically creates one if not attached). - cb.finalize(); - - SumIntsFunc fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error case. - - // Execute the generated function. - int inA[4] = { 4, 3, 2, 1 }; - int inB[4] = { 1, 5, 2, 8 }; - int out[4]; - fn(out, inA, inB); - - // Prints {5 8 4 9} - printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); - - jit.release(fn); // Remove the function from the runtime. - return 0; -} -``` - -When the example is executed it should output the following (this one using AMD64-SystemV ABI): - -``` -Raw Function: -movdqu xmm0, [rcx] -movdqu xmm1, [rdx] -paddd xmm0, xmm1 -movdqu [rax], xmm0 - -Prolog & Epilog: -mov rax, rdi -mov rcx, rsi -movdqu xmm0, [rcx] -movdqu xmm1, [rdx] -paddd xmm0, xmm1 -movdqu [rax], xmm0 -ret - -{5 8 4 9} -``` - -The number of use-cases of **x86::Builder** is not limited and highly depends on your creativity and experience. The previous example can be easily improved to collect all dirty registers inside the function programmatically and to pass them to `frame.setDirtyRegs()`: - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -// NOTE: This function doesn't cover all possible constructs. It ignores -// instructions that write to implicit registers that are not part of the -// operand list. It also counts read-only registers. Real implementation -// would be a bit more complicated, but still relatively easy to implement. -static void collectDirtyRegs(const BaseNode* first, const BaseNode* last, uint32_t regMask[BaseReg::kGroupVirt]) { - const BaseNode* node = first; - while (node) { - if (node->actsAsInst()) { - const InstNode* inst = node->as<InstNode>(); - const Operand* opArray = inst->operands(); - - for (uint32_t i = 0, opCount = inst->opCount(); i < opCount; i++) { - const Operand& op = opArray[i]; - if (op.isReg()) { - const x86::Reg& reg = op.as<x86::Reg>(); - if (reg.group() < BaseReg::kGroupVirt) - regMask[reg.group()] |= 1u << reg.id(); - } - } - } - - if (node == last) break; - node = node->next(); - n} - -static void setDirtyRegsOfFuncFrame(const x86::Builder& cb, FuncFrame& frame) { - uint32_t regMask[BaseReg::kGroupVirt] = { 0 }; - collectDirtyRegs(cb.firstNode(), cb.lastNode(), regMask); - - // X86/X64 ABIs only require to save GP/XMM registers: - frame.setDirtyRegs(x86::Reg::kGroupGp , regMask[x86::Reg::kGroupGp ]); - frame.setDirtyRegs(x86::Reg::kGroupVec, regMask[x86::Reg::kGroupVec]); -} -``` - -### Using x86::Assembler or x86::Builder through X86::Emitter - -Even when **Assembler** and **Builder** provide the same interface as defined by **BaseEmitter** their platform dependent variants (**x86::Assembler** and **x86::Builder**, respective) cannot be interchanged or casted to each other by using C++'s `static_cast<>`. The main reason is the inheritance graph of these classes is different and cast-incompatible, as illustrated in the following graph: - -``` - +--------------+ +=========================+ - +----------------------->| x86::Emitter |<--+--# x86::EmitterImplicitT<> #<--+ - | +--------------+ | +=========================+ | - | (abstract) | (mixin) | - | +--------------+ +~~~~~~~~~~~~~~+ | | - +-->| BaseAssembler|---->|x86::Assembler|<--+ | - | +--------------+ +~~~~~~~~~~~~~~+ | | - | (abstract) (final) | | -+===============+ | +--------------+ +~~~~~~~~~~~~~~+ | | -# BaseEmitter #--+-->| BaseBuilder |--+->| x86::Builder |<--+ | -+===============+ +--------------+ | +~~~~~~~~~~~~~~+ | - (abstract) (abstract) | (final) | - +---------------------+ | - | | - | +--------------+ +~~~~~~~~~~~~~~+ +=========================+ | - +-->| BaseCompiler |---->| x86::Compiler|<-----# x86::EmitterExplicitT<> #---+ - +--------------+ +~~~~~~~~~~~~~~+ +=========================+ - (abstract) (final) (mixin) -``` - -The graph basically shows that it's not possible to cast `x86::Assembler` to `x86::Builder` and vice versa. However, since both `x86::Assembler` and `x86::Builder` share the same interface defined by both `BaseEmitter` and `x86::EmmiterImplicitT` a class called `x86::Emitter` was introduced to make it possible to write a function that can emit to both `x86::Assembler` and `x86::Builder`. Note that `x86::Emitter` cannot be created, it's abstract and has private constructors and destructors; it was only designed to be casted to and used as an interface. - -Each X86 emitter implements a member function called `as<x86::Emitter>()`, which casts the instance to the `x86::Emitter`, as illustrated on the next example: - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -static void emitSomething(x86::Emitter* e) { - e->mov(x86::eax, x86::ebx); -} - -static void assemble(CodeHolder& code, bool useAsm) { - if (useAsm) { - x86::Assembler a(&code); - emitSomething(a.as<x86::Emitter>()); - } - else { - x86::Builder cb(&code); - emitSomething(cb.as<x86::Emitter>()); - - // IMPORTANT: Builder requires `finalize()` to be called to serialize the - // code to the Assembler (it automatically creates one if not attached). - cb.finalize(); - } -} -``` - -The example above shows how to create a function that can emit code to either **x86::Assembler** or **x86::Builder** through **x86::Emitter**, which provides emitter-neutral functionality. **x86::Emitter**, however, doesn't provide any emitter **x86::Assembler** or **x86::Builder** specific functionality like **setCursor()**. - - -Compiler Interface ------------------- - -**Compiler** is a high-level code emitter that provides virtual registers and automatically handles function calling conventions. It's still architecture dependent, but makes the code generation much easier by offering a built-in register allocator and function builder. Functions are essential; the first-step to generate some code is to define the signature of the function you want to generate (before generating the function body). Function arguments and return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same way. - -**Compiler** also makes the use of passes (introduced by **Builder**) and automatically adds an architecture-dependent register allocator pass to the list of passes when attached to **CodeHolder**. - -### Compiler Basics - -The first **Compiler** example shows how to generate a function that simply returns an integer value. It's an analogy to the very first example: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef int (*Func)(void); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Runtime specialized for JIT code execution. - CodeHolder code; // Holds code and relocation information. - - code.init(jit.codeInfo()); // Initialize to the same arch as JIT runtime. - x86::Compiler cc(&code); // Create and attach x86::Compiler to `code`. - - cc.addFunc(FuncSignatureT<int>()); // Begin a function of `int fn(void)` signature. - - x86::Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register. - cc.mov(vReg, 1); // Move one to our virtual register `vReg`. - cc.ret(vReg); // Return `vReg` from the function. - - cc.endFunc(); // End of the function body. - cc.finalize(); // Translate and assemble the whole `cc` content. - // ----> x86::Compiler is no longer needed from here and can be destroyed <---- - - Func fn; - Error err = jit.add(&fn, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - int result = fn(); // Execute the generated code. - printf("%d\n", result); // Print the resulting "1". - - jit.release(fn); // RAII, but let's make it explicit. - return 0; -} -``` - -The **addFunc()** and **endFunc()** methods define the body of the function. Both functions must be called per function, but the body doesn't have to be generated in sequence. An example of generating two functions will be shown later. The next example shows more complicated code that contain a loop and generates a **memcpy32()** function: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Runtime specialized for JIT code execution. - CodeHolder code; // Holds code and relocation information. - - code.init(jit.codeInfo()); // Initialize to the same arch as JIT runtime. - x86::Compiler cc(&code); // Create and attach x86::Compiler to `code`. - - cc.addFunc( // Begin the function of the following signature: - FuncSignatureT<void, // Return value - void (no return value). - uint32_t*, // 1st argument - uint32_t* (machine reg-size). - const uint32_t*, // 2nd argument - uint32_t* (machine reg-size). - size_t>()); // 3rd argument - size_t (machine reg-size). - - Label L_Loop = cc.newLabel(); // Start of the loop. - Label L_Exit = cc.newLabel(); // Used to exit early. - - x86::Gp dst = cc.newIntPtr("dst"); // Create `dst` register (destination pointer). - x86::Gp src = cc.newIntPtr("src"); // Create `src` register (source pointer). - x86::Gp cnt = cc.newUIntPtr("cnt"); // Create `cnt` register (loop counter). - - cc.setArg(0, dst); // Assign `dst` argument. - cc.setArg(1, src); // Assign `src` argument. - cc.setArg(2, cnt); // Assign `cnt` argument. - - cc.test(cnt, cnt); // Early exit if length is zero. - cc.jz(L_Exit); - - cc.bind(L_Loop); // Bind the beginning of the loop here. - - x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes). - cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address. - cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address. - - cc.add(src, 4); // Increment `src`. - cc.add(dst, 4); // Increment `dst`. - - cc.dec(cnt); // Loop until `cnt` is non-zero. - cc.jnz(L_Loop); - - cc.bind(L_Exit); // Label used by early exit. - cc.endFunc(); // End of the function body. - - cc.finalize(); // Translate and assemble the whole `cc` content. - // ----> x86::Compiler is no longer needed from here and can be destroyed <---- - - MemCpy32 memcpy32; - Error err = jit.add(&memcpy32, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - // Test the generated code. - uint32_t input[6] = { 1, 2, 3, 5, 8, 13 }; - uint32_t output[6]; - memcpy32(output, input, 6); - - for (uint32_t i = 0; i < 6; i++) - printf("%d\n", output[i]); - - jit.release(memcpy32); // RAII, but let's make it explicit. - return 0; -} -``` - -### Recursive Functions - -It's possible to create more functions by using the same `x86::Compiler` instance and make links between them. In such case it's important to keep the pointer to the `FuncNode` node. The first example creates a simple Fibonacci function that calls itself recursively: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef uint32_t (*Fibonacci)(uint32_t x); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Runtime specialized for JIT code execution. - CodeHolder code; // Holds code and relocation information. - - code.init(jit.codeInfo()); // Initialize to the same arch as JIT runtime. - x86::Compiler cc(&code); // Create and attach x86::Compiler to `code`. - - FuncNode* func = cc.addFunc( // Begin of the Fibonacci function, `addFunc()` - FuncSignatureT<int, int>()); // Returns a pointer to the `FuncNode` node. - - Label L_Exit = cc.newLabel() // Exit label. - x86::Gp x = cc.newU32(); // Function `x` argument. - x86::Gp y = cc.newU32(); // Temporary. - - cc.setArg(0, x); - - cc.cmp(x, 3); // Return `x` if less than 3. - cc.jb(L_Exit); - - cc.mov(y, x); // Make copy of the original `x`. - cc.dec(x); // Decrease `x`. - - FuncCallNode* call = cc.call( // Function call: - func->label(), // Function address or Label. - FuncSignatureT<int, int>()); // Function signature. - - call->setArg(0, x); // Assign `x` as the first argument and - call->setRet(0, x); // assign `x` as a return value as well. - - cc.add(x, y); // Combine the return value with `y`. - - cc.bind(L_Exit); - cc.ret(x); // Return `x`. - cc.endFunc(); // End of the function body. - - cc.finalize(); // Translate and assemble the whole `cc` content. - // ----> x86::Compiler is no longer needed from here and can be destroyed <---- - - Fibonacci fib; - Error err = jit.add(&fib, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - printf("Fib(%u) -> %u\n", 8, fib(8)); // Test the generated code. - - jit.release(fib); // RAII, but let's make it explicit. - return 0; -} -``` - -### Stack Management - -**Compiler** manages function's stack-frame, which is used by the register allocator to spill virtual registers. It also provides an interface to allocate user-defined block of the stack, which can be used as a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values. - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -// Signature of the generated function. -typedef int (*Func)(void); - -int main(int argc, char* argv[]) { - JitRuntime jit; // Runtime specialized for JIT code execution. - CodeHolder code; // Holds code and relocation information. - - code.init(jit.codeInfo()); // Initialize to the same arch as JIT runtime. - x86::Compiler cc(&code); // Create and attach x86::Compiler to `code`. - - cc.addFunc(FuncSignatureT<int>()); // Create a function that returns 'int'. - - x86::Gp p = cc.newIntPtr("p"); - x86::Gp i = cc.newIntPtr("i"); - - x86::Mem stack = cc.newStack(256, 4); // Allocate 256 bytes on the stack aligned to 4 bytes. - x86::Mem stackIdx(stack); // Copy of `stack` with `i` added. - stackIdx.setIndex(i); // stackIdx <- stack[i]. - stackIdx.setSize(1); // stackIdx <- byte ptr stack[i]. - - // Load a stack address to `p`. This step is purely optional and shows - // that `lea` is useful to load a memory operands address (even absolute) - // to a general purpose register. - cc.lea(p, stack); - - // Clear `i` (`xor` as it's C++ keyword, hence `xor_` is used instead). - cc.xor_(i, i); - - Label L1 = cc.newLabel(); - Label L2 = cc.newLabel(); - - cc.bind(L1); // First loop, fill the stack. - cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i). - - cc.inc(i); // i++; - cc.cmp(i, 256); // if (i < 256) - cc.jb(L1); // goto L1; - - // Second loop, sum all bytes stored in `stack`. - x86::Gp sum = cc.newI32("sum"); - x86::Gp val = cc.newI32("val"); - - cc.xor_(i, i); - cc.xor_(sum, sum); - - cc.bind(L2); - - cc.movzx(val, stackIdx); // val = uint32_t(stack[i]); - cc.add(sum, val); // sum += val; - - cc.inc(i); // i++; - cc.cmp(i, 256); // if (i < 256) - cc.jb(L2); // goto L2; - - cc.ret(sum); // Return the `sum` of all values. - cc.endFunc(); // End of the function body. - - cc.finalize(); // Translate and assemble the whole `cc` content. - // ----> x86::Compiler is no longer needed from here and can be destroyed <---- - - Func func; - Error err = jit.add(&func, &code); // Add the generated code to the runtime. - if (err) return 1; // Handle a possible error returned by AsmJit. - // ----> CodeHolder is no longer needed from here and can be destroyed <---- - - printf("Func() -> %d\n", func()); // Test the generated code. - - jit.release(func); // RAII, but let's make it explicit. - return 0; -} -``` - -### Constant Pool - -**Compiler** provides two constant pools for a general purpose code generation - local and global. Local constant pool is related to a single **FuncNode** node and is generally flushed after the function body, and global constant pool is flushed at the end of the generated code by **Compiler::finalize()**. - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -static void exampleUseOfConstPool(x86::Compiler& cc) { - cc.addFunc(FuncSignatureT<int>()); - - x86::Gp v0 = cc.newGpd("v0"); - x86::Gp v1 = cc.newGpd("v1"); - - x86::Mem c0 = cc.newInt32Const(ConstPool::kScopeLocal, 200); - x86::Mem c1 = cc.newInt32Const(ConstPool::kScopeLocal, 33); - - cc.mov(v0, c0); - cc.mov(v1, c1); - cc.add(v0, v1); - - cc.ret(v0); - cc.endFunc(); -} -``` - -### Jump Tables - -**Compiler** supports `jmp` instruction with reg/mem operand, which is a commonly used pattern to implement indirect jumps within a function, for example to implement `switch()` statement in a programming languages. By default AsmJit assumes that every basic block can be a possible jump target as it's unable to deduce targets from instruction's operands. This is a very pessimistic default that should be avoided if possible as it's costly and very unfriendly to liveness analysis and register allocation. So instead of relying on such pessimistic default, use **JumpAnnotation** to annotate indirect jumps: - -```c++ -#include <asmjit/asmjit.h> - -using namespace asmjit; - -static void exampleUseOfIndirectJump(x86::Compiler& cc) { - cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost)); - - // Function arguments - x86::Xmm a = cc.newXmmSs("a"); - x86::Xmm b = cc.newXmmSs("b"); - x86::Gp op = cc.newUInt32("op"); - - x86::Gp target = cc.newIntPtr("target"); - x86::Gp offset = cc.newIntPtr("offset"); - - Label L_Table = cc.newLabel(); - Label L_Add = cc.newLabel(); - Label L_Sub = cc.newLabel(); - Label L_Mul = cc.newLabel(); - Label L_Div = cc.newLabel(); - Label L_End = cc.newLabel(); - - cc.setArg(0, a); - cc.setArg(1, b); - cc.setArg(2, op); - - // Jump annotation is a building block that allows to annotate all - // possible targets where `jmp()` can jump. It then drives the CFG - // contruction and liveness analysis, which impacts register allocation. - JumpAnnotation* annotation = cc.newJumpAnnotation(); - annotation->addLabel(L_Add); - annotation->addLabel(L_Sub); - annotation->addLabel(L_Mul); - annotation->addLabel(L_Div); - - // Most likely not the common indirect jump approach, but it - // doesn't really matter how final address is calculated. The - // most important path using JumpAnnotation with `jmp()`. - cc.lea(offset, x86::ptr(L_Table)); - if (cc.is64Bit()) - cc.movsxd(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); - else - cc.mov(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); - cc.add(target, offset); - cc.jmp(target, annotation); - - // Acts like a switch() statement in C. - cc.bind(L_Add); - cc.addss(a, b); - cc.jmp(L_End); - - cc.bind(L_Sub); - cc.subss(a, b); - cc.jmp(L_End); - - cc.bind(L_Mul); - cc.mulss(a, b); - cc.jmp(L_End); - - cc.bind(L_Div); - cc.divss(a, b); - - cc.bind(L_End); - cc.ret(a); - - cc.endFunc(); - - // Relative int32_t offsets of `L_XXX - L_Table`. - cc.bind(L_Table); - cc.embedLabelDelta(L_Add, L_Table, 4); - cc.embedLabelDelta(L_Sub, L_Table, 4); - cc.embedLabelDelta(L_Mul, L_Table, 4); - cc.embedLabelDelta(L_Div, L_Table, 4); -} -``` - - -Advanced Features ------------------ - -### Logging - -The initial phase of any project that generates machine code is not always smooth. Failure cases are common especially at the beginning of the project and AsmJit provides a logging functionality to address this issue. AsmJit does already a good job with function overloading to prevent from emitting semantically incorrect instructions, but it can't prevent from emitting machine code that is semantically correct, but doesn't work when it's executed. Logging has always been an important part of AsmJit's infrastructure and looking at logs can sometimes reveal code generation issues quickly. - -AsmJit provides API for logging and formatting: - * `Logger` - A logger that you can pass to `CodeHolder` and all emitters that inherit `BaseEmitter`. - * `FormatOptions` - Formatting options that can change how instructions and operands are formatted. - -AsmJit's `Logger` serves the following purposes: - * Provides a basic foundation for logging. - * Abstract class leaving the implementation (destination) on users. Two backends are built-in for simplicity: - * `FileLogger` implements logging into a standard `std::FILE` stream. - * `StringLogger` stores the logged text in `StringBuilder` instance. - -AsmJit's `FormatOptions` provides the following to customize the formatting of instructions and operands: - * Flags: - * `FormatOptions::kFlagMachineCode` - Show a machine code of each encoded instruction. - * `FormatOptions::kFlagExplainConsts` - Show a text explanation of some immediate values that are used as predicates. - * `FormatOptions::kFlagHexImms` - Use hexadecimal notation to output immediates. - * `FormatOptions::kFlagHexOffsets` - Use hexadecimal notation to output offsets. - * `FormatOptions::kFlagRegCasts` - Show casts between various register types (compiler). - * `FormatOptions::kFlagPositions` - Show positions associated with nodes (compiler). - * Indentation: - * `FormatOptions::kIndentationCode` - Indentation of instructions and directives. - * `FormatOptions::kIndentationLabel` - Indentation of labels. - * `FormatOptions::kIndentationComment` - Indentation of whole-line comments. - -**Logger** is typically attached to **CodeHolder** and all attached code emitters automatically use it: - -```c++ -#include <asmjit/asmjit.h> -#include <stdio.h> - -using namespace asmjit; - -int main(int argc, char* argv[]) { - JitRuntime jit; // Runtime specialized for JIT code execution. - FileLogger logger(stdout); // Logger should always survive the CodeHolder. - - CodeHolder code; // Holds code and relocation information. - code.init(jit.codeInfo()); // Initialize to the same arch as JIT runtime. - code.setLogger(&logger); // Attach the `logger` to `code` holder. - - // ... code as usual, everything you emit will be logged to `stdout` ... - - return 0; -} -``` - -### Error Handling - -AsmJit uses error codes to represent and return errors. Every function where error can occur returns **Error**. Exceptions are never thrown by AsmJit even in extreme conditions like out-of-memory. Errors should never be ignored, however, checking errors after each asmjit API call would simply overcomplicate the whole code generation experience. To make life simpler AsmJit provides **ErrorHandler**, which provides **handleError()** function: - - `virtual bool handleError(Error err, const char* message, BaseEmitter* origin) = 0;` - -That can be overridden by AsmJit users and do the following: - - * 1. Record the error and continue (the way how the error is user-implemented). - * 2. Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal to throw an exception from the error handler. - * 3. Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts `Assembler` and `Compiler` to a consistent state before calling the `handleError()` so `longjmp()` can be used without issues to cancel the code-generation if an error occurred. This method can be used if exception handling in your project is turned off and you still want some comfort. In most cases it should be safe as AsmJit uses Zone memory and the ownership of memory it allocates always ends with the instance that allocated it. If using this approach please never jump outside the life-time of **CodeHolder** and **BaseEmitter**. - -**ErrorHandler** can be attached to **CodeHolder** and/or **BaseEmitter** (which has a priority). The first example uses error handler that just prints the error, but lets AsmJit continue: - -```c++ -// Error handling #1: -#include <asmjit/asmjit.h> - -#include <stdio.h> - -// Error handler that just prints the error and lets AsmJit ignore it. -class SimpleErrorHandler : public asmjit::ErrorHandler { -public: - inline SimpleErrorHandler() : lastError(kErrorOk) {} - - void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { - this->err = err; - fprintf(stderr, "ERROR: %s\n", message); - } - - Error err; -}; - -int main(int argc, char* argv[]) { - using namespace asmjit; - - JitRuntime jit; - SimpleErrorHandler eh; - - CodeHolder code; - code.init(jit.codeInfo()); - code.setErrorHandler(&eh); - - // Try to emit instruction that doesn't exist. - x86::Assembler a(&code); - a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); - - if (eh.err) { - // Assembler failed! - } - - return 0; -} -``` - -If error happens during instruction emitting / encoding the assembler behaves transactionally - the output buffer won't advance if encoding failed, thus either a fully encoded instruction or nothing is emitted. The error handling shown above is useful, but it's still not the best way of dealing with errors in AsmJit. The following example shows how to use exception handling to handle errors in a more C++ way: - -```c++ -// Error handling #2: -#include <asmjit/asmjit.h> - -#include <exception> -#include <string> -#include <stdio.h> - -// Error handler that throws a user-defined `AsmJitException`. -class AsmJitException : public std::exception { -public: - AsmJitException(asmjit::Error err, const char* message) noexcept - : err(err), - message(message) {} - - const char* what() const noexcept override { return message.c_str(); } - - asmjit::Error err; - std::string message; -}; - -class ThrowableErrorHandler : public asmjit::ErrorHandler { -public: - // Throw is possible, functions that use ErrorHandler are never 'noexcept'. - void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { - throw AsmJitException(err, message); - } -}; - -int main(int argc, char* argv[]) { - using namespace asmjit; - - JitRuntime jit; - ThrowableErrorHandler eh; - - CodeHolder code; - code.init(jit.codeInfo()); - code.setErrorHandler(&eh); - - x86::Assembler a(&code); - - // Try to emit instruction that doesn't exist. - try { - a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); - } - catch (const AsmJitException& ex) { - printf("EXCEPTION THROWN: %s\n", ex.what()); - } - - return 0; -} -``` - -If C++ exceptions are not what you like or your project turns off them completely there is still a way of reducing the error handling to a minimum by using a standard `setjmp/longjmp` approach. AsmJit is exception-safe and cleans up everything before calling the **ErrorHandler**, so any approach is safe. You can simply jump from the error handler without causing any side-effects or memory leaks. The following example demonstrates how it could be done: - -```c++ -// Error handling #3: -#include <asmjit/asmjit.h> - -#include <setjmp.h> -#include <stdio.h> - -class LongJmpErrorHandler : public asmjit::ErrorHandler { -public: - inline LongJmpErrorHandler() : err(asmjit::kErrorOk) {} - - void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { - this->err = err; - longjmp(state, 1); - } - - jmp_buf state; - asmjit::Error err; -}; - -int main(int argc, char* argv[]) { - using namespace asmjit; - - JitRuntime jit; - LongJmpErrorHandler eh; - - CodeHolder code; - code.init(jit.codeInfo()); - code.setErrorHandler(&eh); - - x86::Assembler a(&code); - - if (!setjmp(eh.state)) { - // Try to emit instruction that doesn't exist. - a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); - } - else { - Error err = eh.err; - printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::errorAsString(err)); - } - - return 0; -} -``` - -### Code Injection - -Both `Builder` and `Compiler` emitters store their nodes in a double-linked list, which makes it easy to manipulate that list during the code generation or after. Each node is always emitted next to the current `cursor` and the cursor is changed to that newly emitted node. The cursor can be explicitly retrieved and changed by `cursor()` and `setCursor()`, respectively. - -The following example shows how to inject code at the beginning of the function by implementing an `XmmConstInjector` helper class. - -```c++ -``` - -### TODO - -...More documentation... - - - -Other Topics ------------- - -This section provides quick answers to some recurring questions and topics. - -### Instruction Validation - -AsmJit by default prefers performance when it comes to instruction encoding. The Assembler implementation would only validate operands that must be validated to select a proper encoding of the instruction. This means that by default it would accept instructions that do not really exist like `mov rax, ebx`. This is great in release mode as it makes the assembler faster, however, it's not that great for development as it allows to silently pass even when the instruction's operands are incorrect. To fix this Asmjit contains a feature called **Strict Validation**, which allows to validate each instruction before the Assembler tries to encode it. This feature can also be used without an Assembler instance through `BaseInst::validate()` API. - -Emitter options are configured through CodeHolder: - -```c++ -CodeHolder code; - -// Enables strict instruction validation for all emitters attached to `code`. -code.addEmitterOptions(BaseEmitter::kOptionStrictValidation); - -// Use either ErrorHandler attached to CodeHolder or Error code returned by -// the Assembler. -x86::Assembler a(&code); -Error err = a.emit(x86::Inst::kIdMov, x86::eax, x86::al); -if (err) { /* failed */ } -``` - -### Label Offsets and Links - -When you use a label that is not yet bound the Assembler would create a `LabelLink`, which is then added to CodeHolder's `LabelEntry`. These links are also created for labels that are bound but reference some location in a different section. Firstly, here are some functions that can be used to check some basics: - -```c++ -CodeHolder code = ...; -Label L = ...; - -// Returns whether the Label `L` is bound. -bool bound = code.isLabelBound(L or L.id()); - -// Returns true if the code contains either referenced, but unbound labels, -// or cross-section label links that are not resolved yet. -bool value = code.hasUnresolvedLinks(); // Boolean answer. -size_t count = code.unresolvedLinkCount(); // Count of links. -``` - -Please note that there is not API to return a count of unbound labels as this is completely unimportant from CodeHolder's perspective. If a label is not used then it doesn't matter whether it's bound or not, only used labels matter. After a Label is bound you can query it's offset relative to the start of the section where it was bound: - -```c++ -CodeHolder code = ...; -Label L = ...; - -// After you are done you can check the offset. The offset provided -// is relative to the start of the section, see below for alternative. -// If the given label is not bound then the offset returned will be zero. -uint64_t offset = code.labelOffset(L or L.id()); - -// If you use multiple sections and want the offset relative to the base. -// NOTE: This function expects that the section has already an offset and -// the label-link was resolved (if this is not true you will still get an -// offset relative to the start of the section). -uint64_t offset = code.labelOffsetFromBase(L or L.id()); -``` - -### Sections - -Sections is a relatively new feature that allows to create multiple sections. It's supported by Assembler, Builder, and Compiler. Please note that using multiple sections is advanced and requires more understanding about how AsmJit works. There is a test-case [asmjit_test_x86_sections.cpp](./test/asmjit_test_x86_sections.cpp) that shows how sections can be used. - -```c++ -CodeHolder code = ...; - -// Text section is always provided as the first section. -Section* text = code.textSection(); // or code.sectionById(0); - -// To create another section use `code.newSection()`. -Section* data; -Error err = code.newSection(&data, - ".data", // Section name - SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX). - 0, // Section flags, see Section::Flags. - 8); // Section alignment, must be power of 2. - -// When you switch sections in Assembler, Builder, or Compiler the cursor -// will always move to the end of that section. When you create an Assembler -// the cursor would be placed at the end of the first (.text) section, which -// is initially empty. -x86::Assembler a(&code); -Label L_Data = a.newLabel(); - -a.mov(x86::eax, x86::ebx); // Emits in .text section. - -a.section(data); // Switches to the end of .data section. -a.bind(L_Data); // Binds label in this .data section -a.db(0x01); // Emits byte in .data section. - -a.section(text); // Switches to the end of .text section. -a.add(x86::ebx, x86::eax); // Emits in .text section. - -// References a label bound in .data section in .text section. This -// would create a LabelLink even when the L_Data is already bound, -// because the reference crosses sections. See below... -a.lea(x86::rsi, x86::ptr(L_Data)); -``` - -The last line in the example above shows that a LabelLink would be created even for bound labels that cross sections. In this case a referenced label was bound in another section, which means that the link couldn't be resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't plan to flatten them manually) then there is an API for that. - -```c++ -// ... (continuing the previous example) ... -CodeHolder code = ...; - -// Suppose we have some code that contains multiple sections and -// we would like to flatten them by using AsmJit's built-in API: -Error err = code.flatten(); -if (err) { /* Error handling is necessary. */ } - -// After flattening all sections would contain assigned offsets -// relative to base. Offsets are 64-bit unsigned integers so we -// cast them to `size_t` for simplicity. On 32-bit targets it's -// guaranteed that the offset cannot be greater than `2^32 - 1`. -printf("Data section offset %zu", size_t(data->offset())); - -// The flattening doesn't resolve unresolved label links, this -// has to be done manually as flattening can be done separately. -err = code.resolveUnresolvedLinks(); -if (err) { /* Error handling is necessary. */ } - -if (code.hasUnresolvedLinks()) { - // This would mean either unbound label or some other issue. - printf("FAILED: UnresoledLinkCount=%zu\n", code.unresovedLinkCount()); -} -``` - -### Using AsmJit Data Structures - -AsmJit stores its data in data structures allocated by `ZoneAllocator`. It's a fast allocator that allows AsmJit to allocate a lot of small data structures fast and without `malloc()` overhead. The most common data structure that you will probably inspect is `ZoneVector<T>`. It's like C++'s `std::vector`. but the implementation doesn't use exceptions and uses the mentioned `ZoneAllocator` for performance reasons. You don't have to worry about allocations as you should not need to add items to data structures that are managed by `CodeHolder` or advanced emitters like Builder/Compiler. - -APIs that return `ZoneVector`: - -```c++ -CodeHolder code = ...; - -// Contains all emitters attached to CodeHolder. -const ZoneVector<BaseEmitter*>& emitters = code.emitters(); - -// Contains all sections managed by CodeHolder. -const ZoneVector<Section*>& sections = code.sections(); - -// Contains all LabelEntry records associated with created Labels. -const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries(); - -// Contains all RelocEntry records that describe relocations. -const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries(); -``` - -AsmJit's `ZoneVector<T>` has overloaded array access operator to make it possible accessing its elements through operator[]. Some standard functions like `empty()`, `size()`, and `data()` are provided as well. Vectors are also iterable through range-based for loop: - -```c++ -CodeHolder code = ...; - -for (LabelEntry* le : code.labelEntries()) { - printf("Label #%u {Bound=%s Offset=%llu}", - le->id(), - le->isBound() ? "true" : "false", - (unsigned long long)le->offset()); -} -``` - - -Support -------- - -AsmJit is an open-source library released under a permissive ZLIB license, which makes it possible to use it freely in any open-source or commercial product. Free support is available through issues and gitter channel, which is very active. Commercial support is currently individual and can be negotiated on demand. It includes consultation, priority bug fixing, review of code that uses AsmJit, porting code to the latest AsmJit, and implementation of new AsmJit features. - -If you use AsmJit in a non-commercial project and would like to appreciate the library in the form of a donation you are welcome to support us. Donations are anonymous unless the donor lets us know otherwise. The order and format of listed donors is not guaranteed and may change in the future. Additionally, donations should be considered as an appreciation of past work and not used to gain special privileges in terms of future development. AsmJit authors reserve the right to remove a donor from the list in extreme cases of disruptive behavior against other community members. Diversity of opinions and constructive criticism will always be welcome in the AsmJit community. - -Donation Addresses: +TODO +---- - * BTC: 14dEp5h8jYSxgXB9vcjE8eh78uweD76o7W - * ETH: 0xd4f0b9424cF31DF5a5359D029CF3A65c500a581E - * Please contact us if you would like to donate through a different channel or to use a different crypto-currency. Wire transfers and SEPA payments are both possible. + * [ ] Core: + * [ ] Add support for user external buffers in CodeHolder. + * [ ] Ports: + * [ ] ARM/Thumb/AArch64 support. -Donors: +Donors +------ * [ZehMatt](https://github.com/ZehMatt) - Authors & Maintainers --------------------- diff --git a/3rdparty/asmjit/src/asmjit.natvis b/3rdparty/asmjit/src/asmjit.natvis index 18a083c6c12..b73d8487276 100644 --- a/3rdparty/asmjit/src/asmjit.natvis +++ b/3rdparty/asmjit/src/asmjit.natvis @@ -35,25 +35,25 @@ </Type> <Type Name="asmjit::Operand_"> - <Intrinsic Name="opType" Expression="(unsigned int)(_signature & 0x7)"/> - <Intrinsic Name="opSize" Expression="(_signature >> 24) & 0xFF"/> + <Intrinsic Name="opType" Expression="(unsigned int)(_signature & 0x7)" /> + <Intrinsic Name="opSize" Expression="(_signature >> 24) & 0xFF" /> - <Intrinsic Name="regType" Expression="(_signature >> 3) & 0x1F"/> - <Intrinsic Name="regGroup" Expression="(_signature >> 8) & 0xF"/> + <Intrinsic Name="regType" Expression="(_signature >> 3) & 0x1F" /> + <Intrinsic Name="regGroup" Expression="(_signature >> 8) & 0xF" /> - <Intrinsic Name="memBaseType" Expression="(_signature >> 3) & 0x1F"/> - <Intrinsic Name="memIndexType" Expression="(_signature >> 8) & 0x1F"/> - <Intrinsic Name="memAddrType" Expression="(_signature >> 13) & 0x3"/> - <Intrinsic Name="memRegHome" Expression="(_signature >> 15) & 0x1"/> + <Intrinsic Name="memBaseType" Expression="(_signature >> 3) & 0x1F" /> + <Intrinsic Name="memIndexType" Expression="(_signature >> 8) & 0x1F" /> + <Intrinsic Name="memAddrType" Expression="(_signature >> 13) & 0x3" /> + <Intrinsic Name="memRegHome" Expression="(_signature >> 15) & 0x1" /> - <Intrinsic Name="memBaseId" Expression="_baseId"/> - <Intrinsic Name="memIndexId" Expression="_data[0]"/> + <Intrinsic Name="memBaseId" Expression="_baseId" /> + <Intrinsic Name="memIndexId" Expression="_data[0]" /> - <Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])"/> - <Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])"/> - <Intrinsic Name="memOffset" Expression="memBaseType() != 0 ? memOffset32b() : memOffset64b()"/> + <Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])" /> + <Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])" /> + <Intrinsic Name="memOffset" Expression="memBaseType() != 0 ? memOffset32b() : memOffset64b()" /> - <Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]"/> + <Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]" /> <DisplayString Condition="opType() == 0">[None]</DisplayString> <DisplayString Condition="opType() == 1">[Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}</DisplayString> @@ -80,4 +80,122 @@ <Item Name="_data[ImmLo]" Condition="opType() == 3">_data[1]</Item> </Expand> </Type> + + <Type Name="asmjit::FuncValue"> + <Intrinsic Name="isReg" Expression="(_data & asmjit::FuncValue::kFlagIsReg) != 0" /> + <Intrinsic Name="isStack" Expression="(_data & asmjit::FuncValue::kFlagIsStack) != 0" /> + <Intrinsic Name="isIndirect" Expression="(_data & asmjit::FuncValue::kFlagIsIndirect) != 0" /> + <Intrinsic Name="isDone" Expression="(_data & asmjit::FuncValue::kFlagIsDone) != 0" /> + + <Intrinsic Name="typeId" Expression="((_data & asmjit::FuncValue::kTypeIdMask) >> asmjit::FuncValue::kTypeIdShift)" /> + <Intrinsic Name="regId" Expression="((_data & asmjit::FuncValue::kRegIdMask) >> asmjit::FuncValue::kRegIdShift)" /> + <Intrinsic Name="regType" Expression="((_data & asmjit::FuncValue::kRegTypeMask) >> asmjit::FuncValue::kRegTypeShift)" /> + <Intrinsic Name="stackOffset" Expression="((_data & asmjit::FuncValue::kStackOffsetMask) >> asmjit::FuncValue::kStackOffsetShift)" /> + + <DisplayString Condition="isReg()">[RegValue {{ regType={regType()} indirect={isIndirect()} done={isDone()} }}]</DisplayString> + <DisplayString Condition="isStack()">[StackValue {{ indirect={isIndirect()} done={isDone()} }}]</DisplayString> + <DisplayString Condition="!isReg() && !isStack()">[Unknown]</DisplayString> + + <Expand HideRawView="true"> + <Item Name="data">_data</Item> + <Item Name="typeId">(asmjit::Type::Id)(typeId())</Item> + <Item Name="regType" Condition="isReg()">(asmjit::BaseReg::RegType)regType()</Item> + <Item Name="regId" Condition="isReg()">regId()</Item> + <Item Name="stackOffset" Condition="isStack()">stackOffset()</Item> + </Expand> + </Type> + + <Type Name="asmjit::BaseNode"> + <Intrinsic Name="nodeType" Expression="_any._nodeType" /> + + <Intrinsic Name="isInst" Expression="nodeType() == asmjit::BaseNode::kNodeInst"></Intrinsic> + <Intrinsic Name="isSection" Expression="nodeType() == asmjit::BaseNode::kNodeSection"></Intrinsic> + <Intrinsic Name="isLabel" Expression="nodeType() == asmjit::BaseNode::kNodeLabel"></Intrinsic> + <Intrinsic Name="isAlign" Expression="nodeType() == asmjit::BaseNode::kNodeAlign"></Intrinsic> + <Intrinsic Name="isEmbedData" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedData"></Intrinsic> + <Intrinsic Name="isEmbedLabel" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabel"></Intrinsic> + <Intrinsic Name="isEmbedLabelDelta" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabelDelta"></Intrinsic> + <Intrinsic Name="isConstPool" Expression="nodeType() == asmjit::BaseNode::kNodeConstPool"></Intrinsic> + <Intrinsic Name="isComment" Expression="nodeType() == asmjit::BaseNode::kNodeComment"></Intrinsic> + <Intrinsic Name="isSentinel" Expression="nodeType() == asmjit::BaseNode::kNodeSentinel"></Intrinsic> + <Intrinsic Name="isJump" Expression="nodeType() == asmjit::BaseNode::kNodeJump"></Intrinsic> + <Intrinsic Name="isFunc" Expression="nodeType() == asmjit::BaseNode::kNodeFunc"></Intrinsic> + <Intrinsic Name="isFuncRet" Expression="nodeType() == asmjit::BaseNode::kNodeFuncRet"></Intrinsic> + <Intrinsic Name="isInvoke" Expression="nodeType() == asmjit::BaseNode::kNodeInvoke"></Intrinsic> + + <Intrinsic Name="actsAsInst" Expression="isInst() || isJump() || isFunc() || isFuncRet() || isInvoke()" /> + <Intrinsic Name="actsAsLabel" Expression="isLabel() || isFunc()" /> + + <DisplayString Condition="isInst()">[InstNode]</DisplayString> + <DisplayString Condition="isSentinel()">[SectionNode]</DisplayString> + <DisplayString Condition="isLabel()">[LabelNode]</DisplayString> + <DisplayString Condition="isAlign()">[AlignNode]</DisplayString> + <DisplayString Condition="isEmbedData()">[EmbedDataNode]</DisplayString> + <DisplayString Condition="isEmbedLabel()">[EmbedLabelNode]</DisplayString> + <DisplayString Condition="isEmbedLabelDelta()">[EmbedLabelDeltaNode]</DisplayString> + <DisplayString Condition="isConstPool()">[ConstPoolNode]</DisplayString> + <DisplayString Condition="isComment()">[CommentNode]</DisplayString> + <DisplayString Condition="isSentinel()">[SentinelNode]</DisplayString> + <DisplayString Condition="isJump()">[JumpNode]</DisplayString> + <DisplayString Condition="isFunc()">[FuncNode]</DisplayString> + <DisplayString Condition="isFuncRet()">[FuncRetNode]</DisplayString> + <DisplayString Condition="isInvoke()">[InvokeNode]</DisplayString> + <DisplayString Condition="nodeType() == 0 || nodeType() > 18">[UnknownNode {nodeType(), d}]</DisplayString> + + <Expand HideRawView="true"> + <Item Name="prev">_prev</Item> + <Item Name="next">_next</Item> + + <Item Name="nodeType">(asmjit::BaseNode::NodeType)_any._nodeType</Item> + <Item Name="nodeFlags">(asmjit::BaseNode::Flags)_any._nodeFlags</Item> + + <Item Name="position">_position</Item> + <Item Name="userData.u64">_userDataU64</Item> + <Item Name="userData.ptr">_userDataPtr</Item> + <Item Name="passData">_passData</Item> + <Item Name="inlineComment">_inlineComment, s8</Item> + + <Item Name="baseInst" Condition="actsAsInst()">((asmjit::InstNode*)this)->_baseInst</Item> + <Item Name="opCount" Condition="actsAsInst()">_inst._opCount</Item> + <Item Name="opCapacity" Condition="actsAsInst()">_inst._opCapacity</Item> + <Item Name="opArray" Condition="actsAsInst()">((asmjit::InstNode*)this)->_opArray, [_inst._opCount]</Item> + + <Item Name="sectionId" Condition="isSection()">((asmjit::SectionNode*)this)->_id</Item> + <Item Name="nextSection" Condition="isSection()">((asmjit::SectionNode*)this)->_nextSection</Item> + + <Item Name="labelId" Condition="isLabel()">((asmjit::LabelNode*)this)->_id</Item> + + <Item Name="alignMode" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignMode</Item> + <Item Name="alignment" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignment</Item> + + <Item Name="typeId" Condition="isEmbedData()">_embed._typeId, d</Item> + <Item Name="typeSize" Condition="isEmbedData()">_embed._typeSize, d</Item> + <Item Name="itemCount" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_itemCount</Item> + <Item Name="repeatCount" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_repeatCount</Item> + <Item Name="inlineData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_inlineData</Item> + <Item Name="externalData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_externalData</Item> + + <Item Name="labelId" Condition="isEmbedLabel()">((asmjit::EmbedLabelNode*)this)->_id</Item> + + <Item Name="labelId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_id</Item> + <Item Name="baseId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_baseId</Item> + <Item Name="dataSize" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_dataSize</Item> + + <Item Name="constPool" Condition="isConstPool()">((asmjit::ConstPoolNode*)this)->_constPool</Item> + + <Item Name="sentinel.sentinelType" Condition="isSentinel()">(asmjit::SentinelNode::SentinelType)_sentinel._sentinelType</Item> + + <Item Name="annotation" Condition="isJump()">((asmjit::JumpNode*)this)->_annotation</Item> + + <Item Name="funcDetail" Condition="isFunc()">((asmjit::FuncNode*)this)->_funcDetail</Item> + <Item Name="frame" Condition="isFunc()">((asmjit::FuncNode*)this)->_frame</Item> + <Item Name="exitNode" Condition="isFunc()">((asmjit::FuncNode*)this)->_exitNode</Item> + <Item Name="end" Condition="isFunc()">((asmjit::FuncNode*)this)->_end</Item> + <Item Name="args" Condition="isFunc()">((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount]</Item> + + <Item Name="funcDetail" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_funcDetail</Item> + <Item Name="rets" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_rets, [((asmjit::InvokeNode*)this)->_funcDetail._retCount]</Item> + <Item Name="args" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount]</Item> + </Expand> + </Type> </AutoVisualizer> diff --git a/3rdparty/asmjit/src/asmjit/asmjit.h b/3rdparty/asmjit/src/asmjit/asmjit.h index e543a633d04..400426c40a7 100644 --- a/3rdparty/asmjit/src/asmjit/asmjit.h +++ b/3rdparty/asmjit/src/asmjit/asmjit.h @@ -24,27 +24,6 @@ #ifndef ASMJIT_ASMJIT_H_INCLUDED #define ASMJIT_ASMJIT_H_INCLUDED -//! \mainpage API Reference -//! -//! AsmJit C++ API reference documentation generated by Doxygen. -//! -//! Introduction provided by the project page at https://github.com/asmjit/asmjit. -//! -//! \section main_groups Groups -//! -//! The documentation is split into the following groups: -//! -//! $$DOCS_GROUP_OVERVIEW$$ -//! -//! \section main_other Other Pages -//! -//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically -//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace - -//! \namespace asmjit -//! -//! Root namespace used by AsmJit. - #include "./core.h" #ifdef ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/core.h b/3rdparty/asmjit/src/asmjit/core.h index f9a56fc51fb..d0fb214d0ce 100644 --- a/3rdparty/asmjit/src/asmjit/core.h +++ b/3rdparty/asmjit/src/asmjit/core.h @@ -24,48 +24,1983 @@ #ifndef ASMJIT_CORE_H_INCLUDED #define ASMJIT_CORE_H_INCLUDED +//! Root namespace used by AsmJit. +namespace asmjit { + +// ============================================================================ +// [Documentation - mainpage] +// ============================================================================ + +//! \mainpage API Reference +//! +//! AsmJit C++ API reference documentation generated by Doxygen. +//! +//! AsmJit library uses one global namespace called \ref asmjit, which provides +//! the whole functionality. Core functionality is within \ref asmjit namespace +//! and architecture specific functionality is always in its own namespace. For +//! example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation. +//! +//! \section main_groups Documentation Groups +//! +//! AsmJit documentation is structured into groups. Groups can be followed in +//! order to learn AsmJit, but knowledge from multiple groups is required to +//! use AsmJit properly: +//! +//! $$DOCS_GROUP_OVERVIEW$$ +//! +//! \note It's important to understand that in order to learn AsmJit all groups +//! are important. Some groups can be omitted if a particular tool is out of +//! interest - for example \ref asmjit_assembler users don't need to know about +//! \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users +//! must know about \ref asmjit_assembler as it also uses operands, labels, and +//! other concepts. Similarly \ref asmjit_compiler users must know how both \ref +//! asmjit_assembler and \ref asmjit_builder tools work. +//! +//! \section where_to_start Where To Start +//! +//! AsmJit \ref asmjit_core provides the following two classes that are essential +//! from the code generation perspective: +//! +//! - \ref CodeHolder provides functionality +//! to temporarily hold the generated code. It stores all the necessary +//! information about the code - code buffers, sections, labels, symbols, +//! and information about relocations. +//! +//! - \ref BaseEmitter provides interface used +//! by emitter implementations. The interface provides basic building blocks +//! that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and +//! \ref BaseCompiler. +//! +//! Code emitters: +//! +//! - \ref asmjit_assembler - provides direct machine code generation. +//! +//! - \ref asmjit_builder - provides intermediate code generation that can +//! be processed before it's serialized to \ref BaseAssembler. +//! +//! - \ref asmjit_compiler - provides high-level code generation with built-in +//! register allocation. +//! +//! - \ref FuncNode - provides insight into how function looks from the Compiler +//! perspective and how it's stored in a node-list. +//! +//! \section main_recommendations Recommendations +//! +//! The following steps are recommended for all AsmJit users: +//! +//! - Make sure that you use \ref Logger, see \ref asmjit_logging. +//! +//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling. +//! +//! - Instruction validation in your debug builds can reveal problems too. +//! AsmJit provides validation at instruction level, that can be enabled +//! by \ref BaseEmitter::addValidationOptions(). +//! +//! See \ref BaseEmitter::ValidationOptions for more details. +//! +//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function +//! if you have a problem with AsmJit returning errors during instruction +//! encoding or register allocation. Having an active breakpoint there can +//! help to reveal the origin of the error, to inspect variables and other +//! conditions that caused to it. +//! +//! The reason for using \ref Logger and \ref ErrorHandler is that they provide +//! a very useful information about what's happening inside emitters. In many +//! cases the information provided by these two is crucial to quickly fix issues +//! that happen during development (for example wrong instruction, address, or +//! register used). In addition, output from \ref Logger is always necessary +//! when filling bug reports. In other words, using logging and proper error +//! handling can save a lot of time during the development. +//! +//! \section main_other Other Pages +//! +//! - <a href="annotated.html">Class List</a> - List of classes sorted alphabetically +//! - <a href="namespaceasmjit.html">AsmJit Namespace</a> - List of symbols provided by `asmjit` namespace + +// ============================================================================ +// [Documentation - asmjit_build] +// ============================================================================ + +//! \defgroup asmjit_build Build Instructions +//! \brief Build instructions, supported environments, and feature selection. +//! +//! ### Overview +//! +//! AsmJit is designed to be easy embeddable in any project. However, it depends +//! on some compile-time definitions that can be used to enable or disable +//! features to decrease the resulting binary size. A typical way of building +//! AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to +//! just include AsmJit source code in your project and to just build it. The +//! easiest way to include AsmJit in your project is to just include **src** +//! directory in your project and to define \ref ASMJIT_STATIC. AsmJit can be +//! just updated from time to time without any changes to this integration +//! process. Do not embed AsmJit's `test` files in such case as these are used +//! exclusively for testing. +//! +//! ### Supported C++ Compilers +//! +//! - Requirements: +//! +//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang +//! you would have to enable at least C++11 standard through compiler flags. +//! +//! - Tested: +//! +//! - **Clang** - Tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is +//! officially supported (older Clang versions having C++11 support are +//! probably fine, but are not regularly tested). +//! +//! - **GNU** - Tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is +//! officially supported. +//! +//! - **MINGW** - Tested by Travis-CI - Use the latest version, if possible. +//! +//! - **MSVC** - Tested by Travis-CI - VS2017+ is officially supported, VS2015 +//! is reported to work. +//! +//! - Untested: +//! +//! - **Intel** - No maintainers and no CI environment to regularly test +//! this compiler. +//! +//! - **Other** C++ compilers would require basic support in +//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h). +//! +//! ### Supported Operating Systems and Platforms +//! +//! - Tested: +//! +//! - **Linux** - Tested by Travis-CI (any distribution is generally supported). +//! +//! - **OSX** - Tested by Travis-CI (any version is supported). +//! +//! - **Windows** - Tested by Travis-CI - (Windows 7+ is officially supported). +//! +//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit +//! cannot generate WASM code, but can be used to generate X86/X64 code +//! within a browser, for example. +//! +//! - Untested: +//! +//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, +//! but they should work out of box. +//! +//! - **Haiku** - Not regularly tested, but reported to work. +//! +//! - **Other** operating systems would require some testing and support in +//! the following files: +//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h) +//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp) +//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp) +//! +//! ### Supported Backends / Architectures +//! +//! - **X86** - Both 32-bit and 64-bit backends tested by Travis-CI. +//! - **ARM** - Work-in-progress (not public at the moment). +//! +//! ### Static Builds and Embedding +//! +//! These definitions can be used to enable static library build. Embed is used +//! when AsmJit's source code is embedded directly in another project, implies +//! static build as well. +//! +//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC. +//! - \ref ASMJIT_STATIC - Enable static-library build. +//! +//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in +//! all compilation units that use AsmJit, otherwise AsmJit would use dynamic +//! library imports in \ref ASMJIT_API decorator. The recommendation is to +//! define this macro across the whole project that uses AsmJit this way. +//! +//! ### Build Configuration +//! +//! These definitions control whether asserts are active or not. By default +//! AsmJit would autodetect build configuration from existing pre-processor +//! definitions, but this behavior can be overridden, for example to enable +//! debug asserts in release configuration. +//! +//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, +//! asserts will be enabled in this case. +//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, +//! asserts will be disabled in this case. +//! +//! \note There is usually no need to override the build configuration. AsmJit +//! detects the build configuration by checking whether `NDEBUG` is defined and +//! automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides +//! were not used. We only recommend using build configuration overrides in +//! special situations, like using AsmJit in release configuration with asserts +//! enabled for whatever reason. +//! +//! ### AsmJit Backends +//! +//! AsmJit currently supports only X86/X64 backend, but the plan is to add more +//! backends in the future. By default AsmJit builds only the host backend, which +//! is autodetected at compile-time, but this can be overridden. +//! +//! - \ref ASMJIT_BUILD_X86 - Always build X86 backend (X86 and X86_64). +//! - \ref ASMJIT_BUILD_ARM - Always build ARM backend (ARM and AArch64). +//! - \ref ASMJIT_BUILD_HOST - Always build the host backend, implied by default. +//! +//! ### Features Selection +//! +//! AsmJit builds by defaults all supported features, which includes all emitters, +//! logging, instruction validation and introspection, and JIT memory allocation. +//! Features can be disabled at compile time by using `ASMJIT_NO_...` definitions. +//! +//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time +//! so it won't be available and the compilation will fail if there is +//! attempt to use such API. This includes deprecated classes, namespaces, +//! enumerations, and functions. +//! +//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality +//! completely. This implies \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! cannot be used without \ref asmjit_builder. +//! +//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality +//! completely. +//! +//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime. +//! +//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter. +//! +//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string +//! representation of AsmJit constants, should be used together with +//! \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the +//! ability to quiry instruction names, register names, etc... +//! +//! - \ref ASMJIT_NO_VALIDATION - Disables validation API. +//! +//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, +//! must be used together with \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler +//! requires introspection for its liveness analysis and register allocation. +//! +//! \note It's not recommended to disable features if you plan to build AsmJit +//! as a shared library that will be used by multiple projects that you don't +//! control how AsmJit was built (for example AsmJit in a Linux distribution). +//! The possibility to disable certain features exists mainly for customized +//! AsmJit builds. + +// ============================================================================ +// [Documentation - asmjit_breaking_changes] +// ============================================================================ + +//! \defgroup asmjit_breaking_changes Breaking Changes +//! \brief Documentation of breaking changes +//! +//! ### Overview +//! +//! AsmJit is a live project that is being actively developed. Deprecating the +//! existing API in favor of a new one is preferred, but it's not always +//! possible if the changes are significant. AsmJit authors prefer to do +//! accumulated breaking changes at once instead of breaking the API often. +//! This page documents deprecated and removed APIs and should serve as a how-to +//! guide for people that want to port existing code to work with the newest AsmJit. +//! +//! ### Tips +//! +//! Useful tips before you start: +//! +//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if +//! you need a quick help. +//! +//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that +//! you are not using deprecated functionality at all. Deprecated functions +//! are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes it's not +//! possible to decorate everything like classes, which are used by deprecated +//! functions as well, because some compilers would warn about that. If your +//! project compiles fine with `ASMJIT_NO_DEPRECATED` it's not using anything, +//! which was deprecated. +//! +//! ### Changes committed at 2020-05-30 +//! +//! AsmJit has been cleaned up significantly, many todo items have been fixed +//! and many functions and classes have been redesigned, some in an incompatible +//! way. +//! +//! Core changes: +//! +//! - \ref Imm operand has now only \ref Imm::value() and \ref Imm::valueAs() +//! functions that return its value content, and \ref Imm::setValue() function +//! that sets the content. Functions like `setI8()`, `setU8()` were deprecated. +//! +//! Old functions were deprecated, but code using them should still compile. +//! +//! - `ArchInfo` has been replaced with \ref Environment. Environment provides +//! more details about the architecture, but drops some properties that +//! were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can +//! be replaced with `registerSize()` getter, which returns a native register +//! size of the architecture the environment uses. However, `gpCount()` was +//! removed - at the moment \ref ArchRegs can be used to access such properties. +//! +//! Some other functions were renamed, like `ArchInfo::isX86Family()` is +//! now \ref Environment::isFamilyX86(), etc. The reason for changing the +//! order was support for more propertries and all the accessors now +//! start with the type of the property, like \ref Environment::isPlatformWindows(). +//! +//! This function causes many other classes to provide `environment()` getter +//! instead of `archInfo()` getter. In addition, AsmJit now uses `arch()` to +//! get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was renamed +//! to `Environment::kArchXXX`. +//! +//! Some functions were deprecated, some removed... +//! +//! - `CodeInfo` has been removed in favor of \ref Environment. If you used +//! `CodeInfo` to set architecture and base address, this is now possible +//! with \ref Environment and setting base address explicitly by \ref +//! CodeHolder::init() - the first argument is \ref Environment, and the +//! second argument is base address, which defaults to \ref +//! Globals::kNoBaseAddress. +//! +//! CodeInfo class was deprecated, but the code using it should still +//! compile with warnings. +//! +//! - \ref CallConv has been updated to offer a more unified way of representing +//! calling conventions - many calling conventions were abstracted to follow +//! standard naming like \ref CallConv::kIdCDecl or \ref CallConv::kIdStdCall. +//! +//! This change means that other APIs like \ref FuncDetail::init() now +//! require both, calling convention and target \ref Environment. +//! +//! - `Logging` namespace has been renamed to \ref Formatter, which now +//! provides general functionality for formatting in AsmJit. +//! +//! Logging namespace should still work, but its use is deprecated. +//! Unfortunately this will be without deprecation warnings, so please +//! make sure you don't use it. +//! +//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should +//! no longer be used. There is no replacement, AsmJit users should simply +//! create their own structures if they need them or use the new repeated +//! embed API in emitters, see \ref BaseEmitter::embedDataArray(). +//! +//! Emitter changes: +//! +//! - \ref BaseEmitter::emit() function signature has been changed to accept +//! 3 operands by reference and the rest 3 operands as a continuous array. +//! This change is purely cosmetic and shouldn't affect users as emit() +//! has many overloads that dispatch to the right function. +//! +//! - \ref x86::Emitter (Assembler, Builder, Compiler) deprecates embed +//! utilities like `dint8()`, `duint8()`, `duint16()`, `dxmm()`, etc... +//! in favor of a new and more powerful \ref BaseEmitter::embedDataArray(). +//! This function also allows emitting repeated values and/or patterns, +//! which is used by helpers \ref BaseEmitter::embedUInt8(), and others... +//! +//! - Validation is now available through \ref BaseEmitter::ValidationOptions, +//! which can be enabled/disabled through \ref BaseEmitter::addValidationOptions() +//! and \ref BaseEmitter::clearValidationOptions(), respectively. Validation +//! options now separate between encoding and Builder/Compiler so it's possible +//! to choose the granularity required. +//! +//! Builder changes: +//! +//! - Internal functions for creating nodes were redesigned. They now accept +//! a pointer to the node created as a first parameter. These changes should +//! not affect AsmJit users as these functions were used internally. +//! +//! Compiler changes: +//! +//! - `FuncCallNode` has been renamed to \ref InvokeNode. Additionally, function +//! calls should now use \ref x86::Compiler::invoke() instead of `call()`. +//! The reason behind this is to remove the confusion between a `call` +//! instruction and AsmJit's `call()` intrinsic, which is now `invoke()`. +//! +//! - Creating new nodes also changed. Now the preferred way of invoking a +//! function is to call \ref x86::Compiler::invoke() where the first +//! argument is `InvokeNode**`. The function now returns an error and would +//! call \ref ErrorHandler in case of a failure. Error handling was +//! unspecified in the past - the function was marked noexcept, but called +//! error handler, which could throw. +//! +//! The reason behind this change is to make the API consistent with other +//! changes and to also make it possible to inspect the possible error. In +//! the previous API it returned a new node or `nullptr` in case of error, +//! which the user couldn't inspect unless there was an attached \ref +//! ErrorHandler. +//! +//! Samples: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! // The basic setup of JitRuntime and CodeHolder changed, use environment() +//! // instead of codeInfo(). +//! void basicSetup() { +//! JitRuntime rt; +//! CodeHolder code(rt.environment()); +//! } +//! +//! // Calling a function (Compiler) changed - use invoke() instead of call(). +//! void functionInvocation(x86::Compiler& cc) { +//! InvokeNode* invokeNode; +//! cc.invoke(&invokeNode, targetOperand, FuncSignatureT<...>(...)); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_core] +// ============================================================================ + //! \defgroup asmjit_core Core -//! \brief Core API. +//! \brief Globals, code storage, and emitter interface. //! -//! API that provides classes and functions not specific to any architecture. +//! ### Overview +//! +//! AsmJit library uses \ref CodeHolder to hold code during code generation and +//! emitters inheriting from \ref BaseEmitter to emit code. CodeHolder uses +//! containers to manage its data: +//! +//! - \ref Section - stores information about a code or data section. +//! - \ref CodeBuffer - stores actual code or data, part of \ref Section. +//! - \ref LabelEntry - stores information about a label - its name, offset, +//! section where it belongs to, and other bits. +//! - \ref LabelLink - stores information about yet unbound label, which was +//! already used by the assembler. +//! - \ref RelocEntry - stores information about a relocation. +//! - \ref AddressTableEntry - stores information about an address, which was +//! used in a jump or call. Such address may need relocation. +//! +//! To generate code you would need to instantiate at least the following classes: +//! +//! - \ref CodeHolder - to hold code during code generation. +//! - \ref BaseEmitter - to emit code into \ref CodeHolder. +//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated +//! code in executable memory. \ref Target can be customized by inheriting from +//! it. +//! +//! There are also other core classes that are important: +//! +//! - \ref Environment - describes where the code will run. Environment brings +//! the concept of target triples or tuples into AsmJit, which means that users +//! can specify target architecture, platform, and ABI. +//! - \ref Type - encapsulates lightweight type functionality that can be used +//! to describe primitive and vector types. Types are used by higher level +//! utilities, for example by \ref asmjit_function and \ref asmjit_compiler. +//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information +//! and features described by \ref BaseFeatures. +//! +//! AsmJit also provides global constants: +//! +//! - \ref Globals - namespace that provides global constants. +//! - \ref ByteOrder - byte-order constants and functionality. +//! +//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### CodeHolder & Emitters +//! +//! The example below shows how the mentioned classes interact to generate X86 code: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! a.mov(x86::eax, 1); // Move one to eax register. +//! a.ret(); // Return from function. +//! // ===== x86::Assembler is no longer needed from here and can be destroyed ===== +//! +//! Func fn; // Holds address to the generated function. +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ===== CodeHolder is no longer needed from here and can be destroyed ===== +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "1". +//! +//! // All classes use RAII, all resources will be released before `main()` returns, +//! // the generated function can be, however, released explicitly if you intend to +//! // reuse or keep the runtime alive, which you should in a production-ready code. +//! rt.release(fn); +//! +//! return 0; +//! } +//! ``` +//! +//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the +//! following emitters that offer various levels of abstraction: +//! +//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer. +//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list. +//! - \ref asmjit_compiler - High-level emitter that provides register allocation. +//! +//! ### Targets and JitRuntime +//! +//! AsmJit's \ref Target is an interface that provides basic target abstraction. +//! At the moment AsmJit provides only one implementation called \ref JitRuntime, +//! which as the name suggests provides JIT code target and execution runtime. +//! \ref JitRuntime provides all the necessary stuff to implement a simple JIT +//! compiler with basic memory management. It only provides \ref JitRuntime::add() +//! and \ref JitRuntime::release() functions that are used to either add code +//! to the runtime or release it. \ref JitRuntime doesn't do any decisions on +//! when the code should be released, the decision is up to the developer. +//! +//! See more at \ref asmjit_virtual_memory group. +//! +//! ### More About Environment +//! +//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. +//! It's logical as \ref JitRuntime always returns an \ref Environment that is +//! compatible with the host. For example if your application runs in 64-bit mode +//! the \ref Environment returned will use \ref Environment::kArchX64 architecture +//! in contrast to \ref Environment::kArchX86, which will be used in 32-bit mode on +//! any X86 platform. +//! +//! AsmJit allows to setup the \ref Environment manually and to select a different +//! architecture and ABI when necessary. So let's do something else this time, let's +//! always generate a 32-bit code and print its binary representation. To do that, we +//! can create our own \ref Environment and initialize it to \ref Environment::kArchX86. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit::x86; +//! +//! // Create a custom environment initialized to 32-bit X86 architecture. +//! Environment env; +//! env.setArch(Environment::kArchX86); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with custom environment. +//! +//! // Generate a 32-bit function that sums 4 floats and looks like: +//! // void func(float* dst, const float* a, const float* b) +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! a.mov(eax, dword_ptr(esp, 4)); // Load the destination pointer. +//! a.mov(ecx, dword_ptr(esp, 8)); // Load the first source pointer. +//! a.mov(edx, dword_ptr(esp, 12)); // Load the second source pointer. +//! +//! a.movups(xmm0, ptr(ecx)); // Load 4 floats from [ecx] to XMM0. +//! a.movups(xmm1, ptr(edx)); // Load 4 floats from [edx] to XMM1. +//! a.addps(xmm0, xmm1); // Add 4 floats in XMM1 to XMM0. +//! a.movups(ptr(eax), xmm0); // Store the result to [eax]. +//! a.ret(); // Return from function. +//! +//! // We have no Runtime this time, it's on us what we do with the code. +//! // CodeHolder stores code in Section, which provides some basic properties +//! // and CodeBuffer structure. We are interested in section's CodeBuffer. +//! // +//! // NOTE: The first section is always '.text', it can be retrieved by +//! // code.sectionById(0) or simply by code.textSection(). +//! CodeBuffer& buffer = code.textSection()->buffer(); +//! +//! // Print the machine-code generated or do something else with it... +//! // 8B4424048B4C24048B5424040F28010F58010F2900C3 +//! for (size_t i = 0; i < buffer.length; i++) +//! printf("%02X", buffer.data[i]); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Explicit Code Relocation +//! +//! In addition to \ref Environment, \ref CodeHolder can be configured to +//! specify a base-address (or a virtual base-address in a linker terminology), +//! which could be static (useful when you know the location where the target's +//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by +//! default and relocates the code held by \ref CodeHolder to a user provided +//! address on-demand. To be able to relocate to a user provided address it needs +//! to store some information about relocations, which is represented by \ref +//! RelocEntry. Relocation entries are only required if you call external functions +//! from the generated code that cannot be encoded by using a 32-bit displacement +//! (64-bit displacements are not provided by aby supported architecture). +//! +//! There is also a concept called \ref LabelLink - label link is a lightweight +//! data structure that doesn't have any identifier and is stored in \ref LabelEntry +//! as a single-linked list. Label link represents either unbound yet used label +//! and cross-sections links (only relevant to code that uses multiple sections). +//! Since crossing sections is something that cannot be resolved immediately these +//! links persist until offsets of these sections are assigned and until +//! \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end +//! up with code that has unresolved label links after flattening. You can verify +//! it by calling \ref CodeHolder::hasUnresolvedLinks(), which inspects the value +//! returned by \ref CodeHolder::unresolvedLinkCount(). +//! +//! AsmJit can flatten code that uses multiple sections by assigning each section +//! an incrementing offset that respects its alignment. Use \ref CodeHolder::flatten() +//! to do that. After the sections are flattened their offsets and virtual-sizes +//! are adjusted to respect each section's buffer size and alignment. The \ref +//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating +//! the code held by \ref CodeHolder. You can also flatten your code manually by +//! iterating over all sections and calculating their offsets (relative to base) +//! by your own algorithm. In that case \ref CodeHolder::flatten() should not be +//! called, however, \ref CodeHolder::resolveUnresolvedLinks() should be. +//! +//! The example below shows how to use a built-in virtual memory allocator +//! \ref JitAllocator instead of using \ref JitRuntime (just in case you want +//! to use your own memory management) and how to relocate the generated code +//! into your own memory block - you can use your own virtual memory allocator +//! if you prefer that, but that's OS specific and not covered by the documentation. +//! +//! The following code is similar to the previous one, but implements a function +//! working in both 32-bit and 64-bit environments: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! int main() { +//! // Create a custom environment that matches the current host environment. +//! Environment env = hostEnvironment(); +//! +//! CodeHolder code; // Create a CodeHolder. +//! code.init(env); // Initialize CodeHolder with environment. +//! +//! x86::Assembler a(&code); // Create and attach x86::Assembler to `code`. +//! +//! // Signature: 'void func(int* dst, const int* a, const int* b)'. +//! x86::Gp dst; +//! x86::Gp src_a; +//! x86::Gp src_b; +//! +//! // Handle the difference between 32-bit and 64-bit calling conventions +//! // (arguments passed through stack vs. arguments passed by registers). +//! if (env.is32Bit()) { +//! dst = x86::eax; +//! src_a = x86::ecx; +//! src_b = x86::edx; +//! a.mov(dst , x86::dword_ptr(x86::esp, 4)); +//! a.mov(src_a, x86::dword_ptr(x86::esp, 8)); +//! a.mov(src_b, x86::dword_ptr(x86::esp, 12)); +//! } +//! else { +//! if (env.isPlatformWindows()) { +//! dst = x86::rcx; // First argument (destination pointer). +//! src_a = x86::rdx; // Second argument (source 'a' pointer). +//! src_b = x86::r8; // Third argument (source 'b' pointer). +//! } +//! else { +//! dst = x86::rdi; // First argument (destination pointer). +//! src_a = x86::rsi; // Second argument (source 'a' pointer). +//! src_b = x86::rdx; // Third argument (source 'b' pointer). +//! } +//! } +//! +//! a.movdqu(x86::xmm0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. +//! a.movdqu(x86::xmm1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. +//! a.paddd(x86::xmm0, x86::xmm1); // Add 4 ints in XMM1 to XMM0. +//! a.movdqu(x86::ptr(dst), x86::xmm0); // Store the result to [dst]. +//! a.ret(); // Return from function. +//! +//! // Even when we didn't use multiple sections AsmJit could insert one section +//! // called '.addrtab' (address table section), which would be filled by data +//! // required by relocations (absolute jumps and calls). You can omit this code +//! // if you are 100% sure your code doesn't contain multiple sections and +//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify +//! // whether the address table section does exist. +//! code.flatten(); +//! code.resolveUnresolvedLinks(); +//! +//! // After the code was generated it can be relocated manually to any memory +//! // location, however, we need to know it's size before we perform memory +//! // allocation. `CodeHolder::codeSize()` returns the worst estimated code +//! // size in case that relocations are not possible without trampolines (in +//! // that case some extra code at the end of the current code buffer is +//! // generated during relocation). +//! size_t estimatedSize = code.codeSize(); +//! +//! // Instead of rolling up our own memory allocator we can use the one AsmJit +//! // provides. It's decoupled so you don't need to use `JitRuntime` for that. +//! JitAllocator allocator; +//! +//! // Allocate an executable virtual memory and handle a possible failure. +//! void* p = allocator.alloc(estimatedSize); +//! if (!p) +//! return 0; +//! +//! // Now relocate the code to the address provided by the memory allocator. +//! // Please note that this DOESN'T COPY anything to `p`. This function will +//! // store the address in CodeHolder and use relocation entries to patch the +//! // existing code in all sections to respect the base address provided. +//! code.relocateToBase((uint64_t)p); +//! +//! // This is purely optional. There are cases in which the relocation can omit +//! // unneeded data, which would shrink the size of address table. If that +//! // happened the codeSize returned after relocateToBase() would be smaller +//! // than the originally `estimatedSize`. +//! size_t codeSize = code.codeSize(); +//! +//! // This will copy code from all sections to `p`. Iterating over all sections +//! // and calling `memcpy()` would work as well, however, this function supports +//! // additional options that can be used to also zero pad sections' virtual +//! // size, etc. +//! // +//! // With some additional features, copyFlattenData() does roughly this: +//! // for (Section* section : code.sections()) +//! // memcpy((uint8_t*)p + section->offset(), +//! // section->data(), +//! // section->bufferSize()); +//! code.copyFlattenedData(p, codeSize, CodeHolder::kCopyPadSectionBuffer); +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! +//! // This code uses AsmJit's ptr_as_func<> to cast between void* and SumIntsFunc. +//! ptr_as_func<SumIntsFunc>(p)(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! // Release 'p' is it's no longer needed. It will be destroyed with 'vm' +//! // instance anyway, but it's a good practice to release it explicitly +//! // when you know that the function will not be needed anymore. +//! allocator.release(p); +//! +//! return 0; +//! } +//! ``` +//! +//! If you know the base-address in advance (before the code generation) it can +//! be passed as a second argument to \ref CodeHolder::init(). In that case the +//! Assembler will know the absolute position of each instruction and would be +//! able to use it during instruction encoding to prevent relocations where +//! possible. The following example shows how to configure the base address: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! void initializeCodeHolder(CodeHolder& code) { +//! Environment env = hostEnvironment(); +//! uint64_t baseAddress = uint64_t(0x1234); +//! +//! // initialize CodeHolder with environment and custom base address. +//! code.init(env, baseAddress); +//! } +//! ``` +//! +//! ### Label Offsets and Links +//! +//! When a label that is not yet bound is used by the Assembler, it creates a +//! \ref LabelLink, which is then added to a \ref LabelEntry. These links are +//! also created if a label is used in a different section than in which it +//! was bound. Let's examine some functions that can be used to check whether +//! there are any unresolved links. +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! void labelLinksExample(CodeHolder& code, const Label& label) { +//! // Tests whether the `label` is bound. +//! bool isBound = code.isLabelBound(label); +//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound"); +//! +//! // Returns true if the code contains either referenced, but unbound +//! // labels, or cross-section label links that are not resolved yet. +//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer. +//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links. +//! +//! printf("Number of unresolved links: %zu\n", nUnresolved); +//! } +//! ``` +//! +//! There is no function that would return the number of unbound labels as this +//! is completely unimportant from CodeHolder's perspective. If a label is not +//! used then it doesn't matter whether it's bound or not, only actually used +//! labels matter. After a Label is bound it's possible to query its offset +//! offset relative to the start of the section where it was bound: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! void labelOffsetExample(CodeHolder& code, const Label& label) { +//! // Label offset is known after it's bound. The offset provided is relative +//! // to the start of the section, see below for alternative. If the given +//! // label is not bound the offset returned will be zero. It's recommended +//! // to always check whether the label is bound before using its offset. +//! uint64_t sectionOffset = code.labelOffset(label); +//! printf("Label offset relative to section: %llu\n", (unsigned long long)sectionOffset); +//! +//! // If you use multiple sections and want the offset relative to the base. +//! // NOTE: This function expects that the section has already an offset and +//! // the label-link was resolved (if this is not true you will still get an +//! // offset relative to the start of the section). +//! uint64_t baseOffset = code.labelOffsetFromBase(label); +//! printf("Label offset relative to base: %llu\n", (unsigned long long)baseOffset); +//! } +//! ``` +//! +//! ### Sections +//! +//! AsmJit allows to create multiple sections within the same \ref CodeHolder. +//! A test-case [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp) +//! can be used as a reference point although the following example should +//! also provide a useful insight: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! void sectionsExample(CodeHolder& code) { +//! // Text section is always provided as the first section. +//! Section* text = code.textSection(); // or code.sectionById(0); +//! +//! // To create another section use CodeHolder::newSection(). +//! Section* data; +//! Error err = code.newSection(&data, +//! ".data", // Section name +//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX). +//! 0, // Section flags, see Section::Flags. +//! 8); // Section alignment, must be power of 2. +//! +//! // When you switch sections in Assembler, Builder, or Compiler the cursor +//! // will always move to the end of that section. When you create an Assembler +//! // the cursor would be placed at the end of the first (.text) section, which +//! // is initially empty. +//! x86::Assembler a(&code); +//! Label L_Data = a.newLabel(); +//! +//! a.mov(x86::eax, x86::ebx); // Emits in .text section. +//! +//! a.section(data); // Switches to the end of .data section. +//! a.bind(L_Data); // Binds label in this .data section +//! a.db(0x01); // Emits byte in .data section. +//! +//! a.section(text); // Switches to the end of .text section. +//! a.add(x86::ebx, x86::eax); // Emits in .text section. +//! +//! // References a label in .text section, which was bound in .data section. +//! // This would create a LabelLink even when the L_Data is already bound, +//! // because the reference crosses sections. See below... +//! a.lea(x86::rsi, x86::ptr(L_Data)); +//! } +//! ``` +//! +//! The last line in the example above shows that a LabelLink would be created +//! even for bound labels that cross sections. In this case a referenced label +//! was bound in another section, which means that the link couldn't be resolved +//! at that moment. If your code uses sections, but you wish AsmJit to flatten +//! these sections (you don't plan to flatten them manually) then there is an +//! API for that. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! // ... (continuing the previous example) ... +//! void sectionsExampleContinued(CodeHolder& code) { +//! // Suppose we have some code that contains multiple sections and +//! // we would like to flatten it by using AsmJit's built-in API: +//! Error err = code.flatten(); +//! if (err) { +//! // There are many reasons it can fail, so always handle a possible error. +//! printf("Failed to flatten the code: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! // After flattening all sections would contain assigned offsets +//! // relative to base. Offsets are 64-bit unsigned integers so we +//! // cast them to `size_t` for simplicity. On 32-bit targets it's +//! // guaranteed that the offset cannot be greater than `2^32 - 1`. +//! printf("Data section offset %zu", size_t(data->offset())); +//! +//! // The flattening doesn't resolve unresolved label links, this +//! // has to be done manually as flattening can be done separately. +//! err = code.resolveUnresolvedLinks(); +//! if (err) { +//! // This is the kind of error that should always be handled... +//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err)); +//! exit(1); +//! } +//! +//! if (code.hasUnresolvedLinks()) { +//! // This would mean either unbound label or some other issue. +//! printf("The code has %zu unbound labels\n", code.unresovedLinkCount()); +//! exit(1); +//! } +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_assembler] +// ============================================================================ + +//! \defgroup asmjit_assembler Assembler +//! \brief Assembler interface and operands. +//! +//! ### Overview +//! +//! AsmJit's Assembler is used to emit machine code directly into a \ref +//! CodeBuffer. In general, code generation with assembler requires the knowledge +//! of the following: +//! +//! - \ref BaseAssembler and architecture-specific assemblers: +//! - \ref x86::Assembler - Assembler specific to X86 architecture +//! - \ref Operand and its variations: +//! - \ref BaseReg - Base class for a register operand, inherited by: +//! - \ref x86::Reg - Register operand specific to X86 architecture. +//! - \ref BaseMem - Base class for a memory operand, inherited by: +//! - \ref x86::Mem - Memory operand specific to X86 architecture. +//! - \ref Imm - Immediate (value) operand. +//! - \ref Label - Label operand. +//! +//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot +//! be used to generate code. +//! +//! ### Operand Basics +//! +//! Let's start with operands. \ref Operand is a data structure that defines a +//! data layout of any operand. It can be inherited, but any class inheriting +//! it cannot add any members to it, only the existing layout can be reused. +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per \ref Operand) and can be copied and passed by value. Please never +//! allocate individual operands dynamically by using a `new` keyword - it would +//! work, but then you would have to be responsible for deleting such operands. +//! In AsmJit operands are always part of some other data structures like \ref +//! InstNode, which is part of \ref asmjit_builder tool. +//! +//! Operands contain only identifiers, but not pointers to any code-generation data. +//! For example \ref Label operand only provides label identifier, but not a pointer +//! to \ref LabelEntry structure. In AsmJit such IDs are used to link stuff together +//! without having to deal with pointers. +//! +//! AsmJit's operands all inherit from a base class called \ref Operand. Operands +//! have the following properties that are commonly accessible by getters and setters: +//! +//! - \ref Operand - Base operand, which only provides accessors that are common +//! to all operand types. +//! - \ref BaseReg - Describes either physical or virtual register. Physical +//! registers have id that matches the target's machine id directly whereas +//! virtual registers must be allocated into physical registers by a register +//! allocator pass. Register operand provides: +//! - Register Type - Unique id that describes each possible register provided +//! by the target architecture - for example X86 backend provides \ref +//! x86::Reg::RegType, which defines all variations of general purpose registers +//! (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K, +//! MM, BND, XMM, YMM, and ZMM. +//! - Register Group - Groups multiple register types under a single group - for +//! example all general-purpose registers (of all sizes) on X86 are part of +//! \ref x86::Reg::kGroupGp and all SIMD registers (XMM, YMM, ZMM) are part +//! of \ref x86::Reg::kGroupVec. +//! - Register Size - Contains the size of the register in bytes. If the size +//! depends on the mode (32-bit vs 64-bit) then generally the higher size is +//! used (for example RIP register has size 8 by default). +//! - Register Id - Contains physical or virtual id of the register. +//! - \ref BaseMem - Used to reference a memory location. Memory operand provides: +//! - Base Register - A base register type and id (physical or virtual). +//! - Index Register - An index register type and id (physical or virtual). +//! - Offset - Displacement or absolute address to be referenced (32-bit if base +//! register is used and 64-bit if base register is not used). +//! - Flags that can describe various architecture dependent information (like +//! scale and segment-override on X86). +//! - \ref Imm - Immediate values are usually part of instructions (encoded within +//! the instruction itself) or data. +//! - \ref Label - used to reference a location in code or data. Labels must be +//! created by the \ref BaseEmitter or by \ref CodeHolder. Each label has its +//! unique id per \ref CodeHolder instance. +//! +//! ### Operand Manipulation +//! +//! AsmJit allows to construct operands dynamically, to store them, and to query +//! a complete information about them at run-time. Operands are small (always 16 +//! bytes per `Operand`) and should be always copied (by value) if you intend to +//! store them (don't create operands by using `new` keyword, it's not recommended). +//! Operands are safe to be passed to `memcpy()` and `memset()`, which becomes +//! handy when working with arrays of operands. If you set all members of an \ref +//! Operand to zero the operand would become NONE operand, which is the same as a +//! default constructed Operand. +//! +//! The example below illustrates how operands can be used and modified even +//! without using any other code generation classes. The example uses X86 +//! architecture-specific operands. +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! // Registers can be copied, it's a common practice. +//! x86::Gp dstRegByValue() { return x86::ecx; } +//! +//! void usingOperandsExample(x86::Assembler& a) { +//! // Gets `ecx` register returned by a function. +//! x86::Gp dst = dstRegByValue(); +//! // Gets `rax` register directly from the provided `x86` namespace. +//! x86::Gp src = x86::rax; +//! // Constructs `r10` dynamically. +//! x86::Gp idx = x86::gpq(10); +//! // Constructs [src + idx] memory address - referencing [rax + r10]. +//! x86::Mem m = x86::ptr(src, idx); +//! +//! // Examine `m`: Returns `x86::Reg::kTypeGpq`. +//! m.indexType(); +//! // Examine `m`: Returns 10 (`r10`). +//! m.indexId(); +//! +//! // Reconstruct `idx` stored in mem: +//! x86::Gp idx_2 = x86::Gp::fromTypeAndId(m.indexType(), m.indexId()); +//! +//! // True, `idx` and idx_2` are identical. +//! idx == idx_2; +//! +//! // Possible - op will still be the same as `m`. +//! Operand op = m; +//! // True (can be casted to BaseMem or architecture-specific Mem). +//! op.isMem(); +//! +//! // True, `op` is just a copy of `m`. +//! m == op; +//! +//! // Static cast is fine and valid here. +//! static_cast<BaseMem&>(op).addOffset(1); +//! // However, using `as<T>()` to cast to a derived type is preferred. +//! op.as<BaseMem>().addOffset(1); +//! // False, `op` now points to [rax + r10 + 2], which is not [rax + r10]. +//! m == op; +//! +//! // Emitting 'mov' - type safe way. +//! a.mov(dst, m); +//! // Not possible, `mov` doesn't provide mov(x86::Gp, Operand) overload. +//! a.mov(dst, op); +//! +//! // Type-unsafe, but possible. +//! a.emit(x86::Inst::kIdMov, dst, m); +//! // Also possible, `emit()` is typeless and can be used with raw Operand. +//! a.emit(x86::Inst::kIdMov, dst, op); +//! } +//! ``` +//! +//! Some operands have to be created explicitly by emitters. For example labels +//! must be created by \ref BaseEmitter::newLabel(), which creates a label entry +//! and returns a \ref Label operand with the id that refers to it. Such label +//! then can be used by emitters. +//! +//! ### Memory Operands +//! +//! Some architectures like X86 provide a complex memory addressing model that +//! allows to encode addresses having a BASE register, INDEX register with a +//! possible scale (left shift), and displacement (called offset in AsmJit). +//! Memory address on X86 can also specify memory segment (segment-override in +//! X86 terminology) and some instructions (gather / scatter) require INDEX to +//! be a \ref x86::Vec register instead of a general-purpose register. +//! +//! AsmJit allows to encode and work with all forms of addresses mentioned and +//! implemented by X86. In addition, it also allows to construct absolute 64-bit +//! memory address operands, which is only allowed in one form of 'mov' instruction. +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // Makes it easier to access x86 stuff... +//! using namespace asmjit::x86; +//! +//! // BASE + OFFSET. +//! Mem a = ptr(rax); // a = [rax] +//! Mem b = ptr(rax, 15); // b = [rax + 15] +//! +//! // BASE + INDEX << SHIFT - Shift is in BITS as used by X86! +//! Mem c = ptr(rax, rbx); // c = [rax + rbx] +//! Mem d = ptr(rax, rbx, 2); // d = [rax + rbx << 2] +//! Mem e = ptr(rax, rbx, 2, 15); // e = [rax + rbx << 2 + 15] +//! +//! // BASE + VM (Vector Index) (encoded as MOD+VSIB). +//! Mem f = ptr(rax, xmm1); // f = [rax + xmm1] +//! Mem g = ptr(rax, xmm1, 2); // g = [rax + xmm1 << 2] +//! Mem h = ptr(rax, xmm1, 2, 15); // h = [rax + xmm1 << 2 + 15] +//! +//! // Absolute adddress: +//! uint64_t addr = (uint64_t)0x1234; +//! Mem i = ptr(addr); // i = [0x1234] +//! Mem j = ptr(addr, rbx); // j = [0x1234 + rbx] +//! Mem k = ptr(addr, rbx, 2); // k = [0x1234 + rbx << 2] +//! +//! // LABEL - Will be encoded as RIP (64-bit) or absolute address (32-bit). +//! Label L = ...; +//! Mem m = ptr(L); // m = [L] +//! Mem n = ptr(L, rbx); // n = [L + rbx] +//! Mem o = ptr(L, rbx, 2); // o = [L + rbx << 2] +//! Mem p = ptr(L, rbx, 2, 15); // p = [L + rbx << 2 + 15] +//! +//! // RIP - 64-bit only (RIP can't use INDEX). +//! Mem q = ptr(rip, 24); // q = [rip + 24] +//! } +//! ``` +//! +//! Memory operands can optionally contain memory size. This is required by +//! instructions where the memory size cannot be deduced from other operands, +//! like `inc` and `dec` on X86: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + rbx]. +//! x86::Mem a = x86::dword_ptr(rax, rbx); +//! +//! // The same as: qword ptr [rdx + rsi << 0 + 1]. +//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1); +//! } +//! ``` +//! +//! Memory operands provide API that can be used to access its properties: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem() { +//! // The same as: dword ptr [rax + 12]. +//! x86::Mem mem = x86::dword_ptr(rax, 12); +//! +//! mem.hasBase(); // true. +//! mem.hasIndex(); // false. +//! mem.size(); // 4. +//! mem.offset(); // 12. +//! +//! mem.setSize(0); // Sets the size to 0 (makes it sizeless). +//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11. +//! mem.setOffset(0); // Sets the offset to 0. +//! mem.setBase(rcx); // Changes BASE to RCX. +//! mem.setIndex(rax); // Changes INDEX to RAX. +//! mem.hasIndex(); // true. +//! } +//! // ... +//! ``` +//! +//! Making changes to memory operand is very comfortable when emitting loads +//! and stores: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void testX86Mem(CodeHolder& code) { +//! x86::Assembler a(code); // Your initialized x86::Assembler. +//! x86::Mem mSrc = x86::ptr(eax); // Construct [eax] memory operand. +//! +//! // One way of emitting bunch of loads is to use `mem.adjusted()`, which +//! // returns a new memory operand and keeps the source operand unchanged. +//! a.movaps(x86::xmm0, mSrc); // No adjustment needed to load [eax]. +//! a.movaps(x86::xmm1, mSrc.adjusted(16)); // Loads from [eax + 16]. +//! a.movaps(x86::xmm2, mSrc.adjusted(32)); // Loads from [eax + 32]. +//! a.movaps(x86::xmm3, mSrc.adjusted(48)); // Loads from [eax + 48]. +//! +//! // ... do something with xmm0-3 ... +//! +//! // Another way of adjusting memory is to change the operand in-place. +//! // If you want to keep the original operand you can simply clone it. +//! x86::Mem mDst = mSrc.clone(); // Clone mSrc. +//! +//! a.movaps(mDst, x86::xmm0); // Stores xmm0 to [eax]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm1); // Stores to [eax + 16] . +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm2); // Stores to [eax + 32]. +//! mDst.addOffset(16); // Adds 16 to `mDst`. +//! +//! a.movaps(mDst, x86::xmm3); // Stores to [eax + 48]. +//! } +//! ``` +//! +//! ### Assembler Examples +//! +//! - \ref x86::Assembler provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_builder] +// ============================================================================ //! \defgroup asmjit_builder Builder -//! \brief Builder API. +//! \brief Builder interface, nodes, and passes. +//! +//! ### Overview +//! +//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters +//! that emit into a representation that allows further processing. The code +//! stored in such representation is completely safe to be patched, simplified, +//! reordered, obfuscated, removed, injected, analyzed, or processed some other +//! way. Each instruction, label, directive, or other building block is stored +//! as \ref BaseNode (or derived class like \ref InstNode or \ref LabelNode) +//! and contains all the information necessary to pass that node later to the +//! assembler. +//! +//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. +//! It was designed to provide a maximum compatibility with the existing \ref +//! BaseAssembler emitter so users can move from assembler to builder when needed, +//! for example to implement post-processing, which is not possible with Assembler. +//! +//! ### Builder Nodes +//! +//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate +//! representation based on nodes, however, it allows to serialize to \ref BaseAssembler +//! when the code is ready to be encoded. //! -//! Both Builder and Compiler are emitters that emit everything to a representation -//! that allows further processing. The code stored in such representation is -//! completely safe to be patched, simplified, reordered, obfuscated, removed, -//! injected, analyzed, or processed some other way. Each instruction, label, -//! directive, or other building block is stored as \ref BaseNode (or derived -//! class like \ref InstNode or \ref LabelNode) and contains all the information -//! necessary to pass that node later to the Assembler. +//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler : +//! +//! - Basic nodes: +//! - \ref BaseNode - Base class for all nodes. +//! - \ref InstNode - Represents an instruction node. +//! - \ref AlignNode - Represents an alignment directive (.align). +//! - \ref LabelNode - Represents a location where to bound a \ref Label. +//! +//! - Data nodes: +//! - \ref EmbedDataNode - Represents data. +//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data. +//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels +//! embedded in data. +//! - \ref ConstPoolNode - Represents a constant pool data embedded as data. +//! +//! - Informative nodes: +//! - \ref CommentNode - Represents a comment string, doesn't affect code +//! generation. +//! - \ref SentinelNode - A marker that can be used to remember certain +//! position in code or data, doesn't affect code generation. Used by +//! \ref FuncNode to mark the end of a function. +//! +//! - Other nodes are provided by \ref asmjit_compiler infrastructure. +//! +//! ### Builder Examples +//! +//! - \ref x86::Builder provides many X86/X64 examples. + +// ============================================================================ +// [Documentation - asmjit_compiler] +// ============================================================================ //! \defgroup asmjit_compiler Compiler -//! \brief Compiler API. +//! \brief Compiler interface. +//! +//! ### Overview +//! +//! \ref BaseCompiler is a high-level interface built on top of \ref BaseBuilder +//! interface, which provides register allocation and support for defining and +//! invoking functions. At the moment it's the easiest way of generating code +//! in AsmJit as most architecture and OS specifics is properly abstracted and +//! handled by AsmJit automatically. However, abstractions also mean restrictions, +//! which means that \ref BaseCompiler has more limitations that \ref BaseAssembler +//! or \ref BaseBuilder. +//! +//! Since \ref BaseCompiler provides register allocation it also establishes the +//! concept of functions - a function in Compiler sense is a unit in which virtual +//! registers are allocated into physical registers by the register allocator. +//! In addition, it enables to use such virtual registers in function invocations. +//! +//! \ref BaseCompiler automatically handles function calling conventions. It's +//! still architecture dependent, but makes the code generation much easies. +//! Functions are essential; the first-step to generate some code is to define a +//! signature of the function to be generated (before generating the function body +//! itself). Function arguments and return value(s) are handled by assigning +//! virtual registers to them. Similarly, function calls are handled the same way. +//! +//! ### Compiler Nodes +//! +//! \ref BaseCompiler adds some nodes that are required for function generation +//! and invocation: +//! +//! - \ref FuncNode - Represents a function definition. +//! - \ref FuncRetNode - Represents a function return. +//! - \ref InvokeNode - Represents a function invocation. +//! +//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically +//! adds an architecture-dependent register allocator pass to the list of passes +//! when attached to \ref CodeHolder. +//! +//! ### Compiler Examples +//! +//! - \ref x86::Compiler provides many X86/X64 examples. +//! +//! ### Compiler Tips +//! +//! Users of AsmJit have done mistakes in the past, this section should provide +//! some useful tips for beginners: +//! +//! - Virtual registers in compiler are bound to a single function. At the +//! moment the implementation doesn't care whether a single virtual register +//! is used in multiple functions, but it sees it as two independent virtual +//! registers in that case. This means that virtual registers cannot be used +//! to implement global variables. Global variables are basically memory +//! addresses which functions can read from and write to, and they have to +//! be implemented in the same way. +//! +//! - Compiler provides a useful debugging functionality, which can be turned +//! on through \ref FormatOptions::Flags. Use \ref Logger::addFlags() to +//! turn on additional logging features when using Compiler. + +// ============================================================================ +// [Documentation - asmjit_function] +// ============================================================================ + +//! \defgroup asmjit_function Function +//! \brief Function definitions. +//! +//! ### Overview +//! +//! AsmJit provides functionality that can be used to define function signatures +//! and to calculate automatically optimal function frame that can be used directly +//! by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler +//! for a very long time, but was abstracted out and is now available for all users +//! regardless of the emitter they use. The following use cases are possible: +//! +//! - Calculate function frame before the function is generated - this is the +//! only way available to \ref BaseAssembler users and it will be described +//! in this section. +//! +//! - Calculate function frame after the function is generated - this way is +//! generally used by \ref BaseBuilder and \ref BaseCompiler emitters and +//! this way is generally described in \ref asmjit_compiler section. +//! +//! The following concepts are used to describe and create functions in AsmJit: +//! +//! - \ref Type::Id - Type-id is an 8-bit value that describes a platform +//! independent type as we know from C/C++. It provides abstractions for +//! most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, +//! `double`, and all possible vector types to match ISAs up to AVX512. +//! \ref Type::Id was introduced originally for \ref asmjit_compiler, but +//! it's now used by \ref FuncSignature as well. +//! +//! - \ref CallConv - Describes a calling convention - this class contains +//! instructions to assign registers and stack addresses to function +//! arguments and return value(s), but doesn't specify any function +//! signature itself. Calling conventions are architecture and OS dependent. +//! +//! - \ref FuncSignature - Describes a function signature, for example +//! `int func(int, int)`. FuncSignature contains a function calling convention +//! id, return value type, and function arguments. The signature itself is +//! platform independent and uses \ref Type::Id to describe types of function +//! arguments and function return value(s). +//! +//! - \ref FuncDetail - Architecture and ABI dependent information that describes +//! \ref CallConv and expanded \ref FuncSignature. Each function argument and +//! return value is represented as \ref FuncValue that contains the original +//! \ref Type::Id enriched with additional information that specifies whether +//! the value is passed or returned by register (and which register) or by +//! stack. Each value also contains some other metadata that provide additional +//! information required to handle it properly (for example whether a vector is +//! passed indirectly by a pointer as required by WIN64 calling convention). +//! +//! - \ref FuncFrame - Contains information about the function frame that can +//! be used by prolog/epilog inserter (PEI). Holds call stack size size and +//! alignment, local stack size and alignment, and various attributes that +//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't +//! know anything about function's arguments or return values, it hold only +//! information necessary to create a valid and ABI conforming function prologs +//! and epilogs. +//! +//! - \ref FuncArgsAssignment - A helper class that can be used to reassign +//! function arguments into user specified registers. It's architecture and +//! ABI dependent mapping from function arguments described by \ref CallConv +//! and \ref FuncDetail into registers specified by the user. +//! +//! It's a lot of concepts where each represents one step in a function frame +//! calculation. It can be used to create function prologs, epilogs, and also +//! to calculate information necessary to perform function calls. + +// ============================================================================ +// [Documentation - asmjit_logging] +// ============================================================================ + +//! \defgroup asmjit_logging Logging +//! \brief Logging and formatting. +//! +//! ### Overview +//! +//! The initial phase of a project that generates machine code is not always smooth. +//! Failure cases are common not just at the beginning phase, but also during the +//! development or refactoring. AsmJit provides logging functionality to address +//! this issue. AsmJit does already a good job with function overloading to prevent +//! from emitting unencodable instructions, but it can't prevent from emitting machine +//! code that is correct at instruction level, but doesn't work when it's executed as +//! a whole. Logging has always been an important part of AsmJit's infrastructure and +//! looking at logs can sometimes reveal code generation issues quickly. +//! +//! AsmJit provides API for logging and formatting: +//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters +//! that inherit from \ref BaseEmitter. +//! - \ref FormatOptions - Formatting options that can change how instructions and +//! operands are formatted. +//! - \ref Formatter - A namespace that provides functions that can format input +//! data like \ref Operand, \ref BaseReg, \ref Label, and \ref BaseNode into +//! \ref String. +//! +//! AsmJit's \ref Logger serves the following purposes: +//! - Provides a basic foundation for logging. +//! - Abstract class leaving the implementation on users. The following built-in +//! inplementations are provided for simplicty: +//! - \ref FileLogger implements logging into a standard `FILE` stream. +//! - \ref StringLogger serializes all logs into a \ref String instance. +//! +//! AsmJit's \ref FormatOptions provides the following to customize the formatting of +//! instructions and operands through: +//! - \ref FormatOptions::Flags +//! - \ref FormatOptions::IndentationType +//! +//! ### Logging +//! +//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it +//! to all attached emitters automatically. The example below illustrates how to +//! use \ref FileLogger that outputs to standard output: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! FileLogger logger(stdout); // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, everything emitted will be logged to `stdout` ... +//! return 0; +//! } +//! ``` +//! +//! If output to FILE stream is not desired it's possible to use \ref StringLogger, +//! which concatenates everything into a multi-line string: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! #include <utility> +//! +//! using namespace asmjit; +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! StringLogger logger; // Logger should always survive CodeHolder. +//! +//! CodeHolder code; // Holds code and relocation information. +//! code.init(rt.environment()); // Initialize to the same arch as JIT runtime. +//! code.setLogger(&logger); // Attach the `logger` to `code` holder. +//! +//! // ... code as usual, logging will be concatenated to logger string ... +//! +//! // You can either use the string from StringLogger directly or you can +//! // move it. Logger::data() returns its content as null terminated char[]. +//! printf("Logger content: %s\n", logger.data()); +//! +//! // It can be moved into your own string like this: +//! String content = std::move(logger.content()); +//! printf("The same content: %s\n", content.data()); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Formatting +//! +//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref +//! Logger. Formatting is public and can be used by AsmJit users as well. The +//! most important thing to know regarding formatting is that \ref Formatter +//! always appends to the output string, so it can be used to build complex +//! strings without having to concatenate intermediate strings. +//! +//! The first example illustrates how to format operands: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! void logOperand(uint32_t arch, const Operand_& op) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; //! -//! Compiler tool is built on top of a \ref asmjit_builder API and adds register -//! allocation and support for defining and calling functions into it. At the -//! moment it's the easiest way to generate some code as most architecture and -//! OS specific stuff is properly abstracted, however, abstractions also mean -//! that not everything is possible with the Compiler. +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! StringTmp<128> sb; +//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! log(arch, rax); // Prints 'rax'. +//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`. +//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`. +//! log(arch, imm(42)); // Prints '42'. +//! } +//! ``` +//! +//! Next example illustrates how to format whole instructions: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! #include <utility> +//! +//! using namespace asmjit; +//! +//! template<typename... Args> +//! void logInstruction(uint32_t arch, const BaseInst& inst, Args&&... args) { +//! // The emitter is optional (named labels and virtual registers need it). +//! BaseEmitter* emitter = nullptr; +//! +//! // No flags by default. +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // The formatter expects operands in an array. +//! Operand_ operands { std::forward<Args>(args)... }; +//! +//! StringTmp<128> sb; +//! Formatter::formatInstruction( +//! sb, formatFlags, emitter, arch, inst, operands, sizeof...(args)); +//! printf("%s\n", sb.data()); +//! } +//! +//! void formattingExample() { +//! using namespace x86; +//! +//! // Architecture is not part of operand, it must be passed explicitly. +//! // Format flags. We pass it explicitly also to 'logOperand' to make +//! // compatible with what AsmJit normally does. +//! uint32_t arch = Environment::kArchX64; +//! +//! // Prints 'mov rax, rcx'. +//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx); +//! +//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdVaddpd), +//! zmm0, zmm1, ptr(rax)._1toN()); +//! +//! // BaseInst abstracts instruction id, instruction options, and extraReg. +//! // Prints 'lock add [rax], rcx'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionLock), +//! x86::ptr(rax), rcx); +//! +//! // Similarly an extra register (like AVX-512 selector) can be used. +//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'. +//! logInstruction(arch, +//! BaseInst(Inst::kIdAdd, Inst::kOptionZMask, k2), +//! zmm0, zmm1, ptr(rax)); +//! } +//! ``` +//! +//! And finally, the example below illustrates how to use a built-in function +//! to format the content of \ref BaseBuilder, which consists of nodes: +//! +//! ``` +//! #include <asmjit/core.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! void formattingExample(BaseBuilder* builder) { +//! uint32_t formatFlags = FormatOptions::kNoFlags; +//! +//! // This also shows how temporary strings can be used. +//! StringTmp<512> sb; +//! +//! // FormatNodeList requires the String for output, formatting flags, which +//! // were zero (no extra flags), and the builder instance, which we have +//! // provided. An overloaded version also exists, which accepts begin and +//! // and end nodes, which can be used to only format a range of nodes. +//! Formatter::formatNodeList(sb, formatFlags, builder); +//! +//! // You can do whatever else with the string, it's always null terminated, +//! // so it can be passed to C functions like printf(). +//! printf("%s\n", sb.data()); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_error_handling] +// ============================================================================ + +//! \defgroup asmjit_error_handling Error Handling +//! \brief Error handling. +//! +//! ### Overview +//! +//! AsmJit uses error codes to represent and return errors. Every function that +//! can fail returns an \ref Error code. Exceptions are never thrown by AsmJit +//! itself even in extreme conditions like out-of-memory, but it's possible to +//! override \ref ErrorHandler::handleError() to throw, in that case no error +//! will be returned and exception will be thrown instead. All functions where +//! this can happen are not marked `noexcept`. +//! +//! Errors should never be ignored, however, checking errors after each AsmJit +//! API call would simply overcomplicate the whole code generation experience. +//! \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows +//! to customize how errors can be handled: +//! +//! - Record the error and continue (the way how the error is user-implemented). +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref +//! ErrorHandler::handleError(), so `longjmp()` can be used without issues to +//! cancel the code-generation if an error occurred. This method can be used if +//! exception handling in your project is turned off and you still want some +//! comfort. In most cases it should be safe as AsmJit uses \ref Zone memory +//! and the ownership of memory it allocates always ends with the instance that +//! allocated it. If using this approach please never jump outside the life-time +//! of \ref CodeHolder and \ref BaseEmitter. +//! +//! ### Using ErrorHandler +//! +//! An example of attaching \ref ErrorHandler to \ref CodeHolder. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // A simple error handler implementation, extend according to your needs. +//! class MyErrorHandler : public ErrorHandler { +//! public: +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! printf("AsmJit error: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! +//! MyErrorHandler myErrorHandler; +//! CodeHolder code; +//! +//! code.init(rt.environment()); +//! code.setErrorHandler(&myErrorHandler); +//! +//! x86::Assembler a(&code); +//! // ... code generation ... +//! +//! return 0; +//! } +//! ``` +//! +//! Useful classes in error handling group: +//! +//! - See \ref DebugUtils that provides utilities useful for debugging. +//! - See \ref Error that lists error codes that AsmJit uses. +//! - See \ref ErrorHandler for more details about error handling. -//! \defgroup asmjit_func Function -//! \brief Function API. +// ============================================================================ +// [Documentation - asmjit_instruction_db] +// ============================================================================ -//! \defgroup asmjit_jit JIT -//! \brief JIT API and Virtual Memory Management. +//! \defgroup asmjit_instruction_db Instruction DB +//! \brief Instruction database (introspection, read/write, validation, ...). +//! +//! ### Overview +//! +//! AsmJit provides a public instruction database that can be used to query +//! information about a complete instruction. The instruction database requires +//! the knowledge of the following: +//! +//! - \ref BaseInst - Base instruction that contains instruction id, options, +//! and a possible extra-register that represents either REP prefix counter +//! or AVX-512 selector (mask). +//! - \ref Operand - Represents operands of an instruction. +//! +//! Each instruction can be then queried for the following information: +//! +//! - \ref InstRWInfo - Read/write information of instruction and its oprands. +//! - \ref OpRWInfo - Read/write information of a single operand, part of +//! \ref InstRWInfo data structure. +//! - \ref BaseFeatures - CPU features required to execute the instruction. +//! +//! In addition to query functionality AsmJit is also able to validate whether +//! an instruction and its operands are valid. This is useful for making sure +//! that what user tries to emit is correct and it can be also used by other +//! projects that parse user input, like AsmTK project. +//! +//! ### Query API +//! +//! The instruction query API is provided by \ref InstAPI namespace. The +//! following queries are possible: +//! +//! - \ref InstAPI::queryRWInfo() - queries read/write information of the +//! given instruction and its operands. Includes also CPU flags read/written. +//! +//! - \ref InstAPI::queryFeatures() - queries CPU features that are required +//! to execute the given instruction. A full instruction with operands must +//! be given as some architectures like X86 may require different features +//! for the same instruction based on its operands. +//! +//! - <a href="https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_instinfo.cpp">asmjit_test_x86_instinfo.cpp</a> +//! can be also used as a reference about accessing instruction information. +//! +//! ### Validation API +//! +//! The instruction validation API is provided by \ref InstAPI namespace in the +//! similar fashion like the Query API, however, validation can also be turned +//! on at \ref BaseEmitter level. The following is possible: +//! +//! - \ref InstAPI::validate() - low-level instruction validation function +//! that is used internally by emitters if strict validation is enabled. +//! +//! - \ref BaseEmitter::addValidationOptions() - can be used to enable +//! validation at emitter level, see \ref BaseEmitter::ValidationOptions. -//! \defgroup asmjit_zone Zone -//! \brief Zone allocator and zone allocated containers. -//! \defgroup asmjit_support Support -//! \brief Support API. +// ============================================================================ +// [Documentation - asmjit_virtual_memory] +// ============================================================================ + +//! \defgroup asmjit_virtual_memory Virtual Memory +//! \brief Virtual memory management. +//! +//! ### Overview +//! +//! AsmJit's virtual memory management is divided into two main categories: +//! +//! - Low level API that provides cross-platform abstractions for virtual +//! memory allocation. Implemented in \ref VirtMem namespace. +//! - High level API that makes it very easy to store generated code for +//! execution. See \ref JitRuntime, which is used by many examples for its +//! simplicity and easy integration with \ref CodeHolder. There is also +//! \ref JitAllocator, which lays somewhere between RAW memory allocation +//! and \ref JitRuntime. + +// ============================================================================ +// [Documentation - asmjit_zone_memory] +// ============================================================================ + +//! \defgroup asmjit_zone Zone Memory +//! \brief Zone memory allocator and containers. +//! +//! ### Overview +//! +//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate +//! most of the data it uses. It's a fast allocator that allows AsmJit to allocate +//! a lot of small data structures fast and without `malloc()` overhead. Since +//! code generators and all related classes are usually short-lived this approach +//! decreases memory usage and fragmentation as arena-based allocators always +//! allocate larger blocks of memory, which are then split into smaller chunks. +//! +//! Another advantage of zone memory allocation is that since the whole library +//! uses this strategy it's very easy to deallocate everything that a particular +//! instance is holding by simply releasing the memory the allocator holds. This +//! improves destruction time of such objects as there is no destruction at all. +//! Long-lived objects just reset its data in destructor or in their reset() +//! member function for a future reuse. For this purpose all containers in AsmJit +//! are also zone allocated. +//! +//! ### Zone Allocation +//! +//! - \ref Zone - Incremental zone memory allocator with minimum features. It +//! can only allocate memory without the possibility to return it back to +//! the allocator. +//! +//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. +//! If the allocation requests fit the static storage allocated then there +//! will be no dynamic memory allocation during the lifetime of \ref ZoneTmp, +//! otherwise it would act as \ref Zone with one preallocated block on the +//! stack. +//! +//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability +//! of returning memory to the allocator. Such memory is stored in a pool for +//! later reuse. +//! +//! ### Zone Allocated Containers +//! +//! - \ref ZoneString - Zone allocated string. +//! - \ref ZoneHash - Zone allocated hash table. +//! - \ref ZoneTree - Zone allocated red-black tree. +//! - \ref ZoneList - Zone allocated double-linked list. +//! - \ref ZoneStack - Zone allocated stack. +//! - \ref ZoneVector - Zone allocated vector. +//! - \ref ZoneBitVector - Zone allocated vector of bits. +//! +//! ### Using Zone Allocated Containers +//! +//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very +//! similar to `std::vector`, but the implementation doesn't use exceptions and +//! uses the mentioned \ref ZoneAllocator for performance reasons. You don't have +//! to worry about allocations as you should not need to add items to AsmJit's +//! data structures directly as there should be API for all required operations. +//! +//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! // Contains all emitters attached to CodeHolder. +//! const ZoneVector<BaseEmitter*>& emitters = code.emitters(); +//! +//! // Contains all section entries managed by CodeHolder. +//! const ZoneVector<Section*>& sections = code.sections(); +//! +//! // Contains all label entries managed by CodeHolder. +//! const ZoneVector<LabelEntry*>& labelEntries = code.labelEntries(); +//! +//! // Contains all relocation entries managed by CodeHolder. +//! const ZoneVector<RelocEntry*>& relocEntries = code.relocEntries(); +//! } +//! ``` +//! +//! \ref ZoneVector has overloaded array access operator to make it possible +//! to access its elements through operator[]. Some standard functions like +//! \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() +//! are provided as well. Vectors are also iterable through a range-based for loop: +//! +//! ``` +//! using namespace asmjit; +//! +//! void example(CodeHolder& code) { +//! for (LabelEntry* le : code.labelEntries()) { +//! printf("Label #%u {Bound=%s Offset=%llu}", +//! le->id(), +//! le->isBound() ? "true" : "false", +//! (unsigned long long)le->offset()); +//! } +//! } +//! ``` +//! +//! ### Design Considerations +//! +//! Zone-allocated containers do not store the allocator within the container. +//! This decision was made to reduce the footprint of such containers as AsmJit +//! tooling, especially Compiler's register allocation, may use many instances +//! of such containers to perform code analysis and register allocation. +//! +//! For example to append an item into a \ref ZoneVector it's required to pass +//! the allocator as the first argument, so it can be used in case that the +//! vector needs a reallocation. Such function also returns an error, which +//! must be propagated to the caller. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector<int> vector; +//! +//! // Unfortunately, allocator must be provided to all functions that mutate +//! // the vector. However, AsmJit users should never need to do this as all +//! // manipulation should be done through public API, which takes care of +//! // that. +//! for (int i = 0; i < 100; i++) { +//! ASMJIT_PROPAGATE(vector.append(allocator, i)); +//! } +//! +//! // By default vector's destructor doesn't release anything as it knows +//! // that its content is zone allocated. However, \ref ZoneVector::release +//! // can be used to explicitly release the vector data to the allocator if +//! // necessary +//! vector.release(allocator); +//! } +//! ``` +//! +//! Containers like \ref ZoneVector also provide a functionality to reserve a +//! certain number of items before any items are added to it. This approach is +//! used internally in most places as it allows to prepare space for data that +//! will be added to some container before the data itself was created. +//! +//! ``` +//! using namespace asmjit +//! +//! Error example(ZoneAllocator* allocator) { +//! ZoneVector<int> vector; +//! +//! ASMJIT_PROPAGATE(vector.willGrow(100)); +//! for (int i = 0; i < 100; i++) { +//! // Cannot fail. +//! vector.appendUnsafe(allocator, i); +//! } +//! +//! vector.release(allocator); +//! } +//! ``` + +// ============================================================================ +// [Documentation - asmjit_utilities] +// ============================================================================ + +//! \defgroup asmjit_utilities Utilities +//! \brief Utility classes and functions. +//! +//! ### Overview +//! +//! AsmJit uses and provides utility classes and functions, that can be used +//! with AsmJit. The functionality can be divided into the following topics: +//! +//! ### String Functionality +//! +//! - \ref String - AsmJit's string container, which is used internally +//! and which doesn't use exceptions and has a stable layout, which is +//! not dependent on C++ standard library. +//! - \ref StringTmp - String that can have base storage allocated on +//! stack. The amount of storage on stack can be specified as a template +//! parameter. +//! - \ref FixedString - Fixed string container limited up to N characters. +//! +//! ### Code Generation Utilities +//! +//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also +//! available to users that may find use of it. +//! +//! ### Support Functionality Used by AsmJit +//! +//! - \ref Support namespace provides many other utility functions and +//! classes that are used by AsmJit, and made public. + +// ============================================================================ +// [Documentation - asmjit_<arch> backends] +// ============================================================================ + +//! \defgroup asmjit_x86 X86 Backend +//! \brief X86/X64 backend. + +// ============================================================================ +// [Documentation - asmjit_ra] +// ============================================================================ //! \cond INTERNAL //! \defgroup asmjit_ra RA //! \brief Register allocator internals. //! \endcond +} // {asmjit} + +// ============================================================================ +// [Core Headers] +// ============================================================================ + #include "./core/globals.h" #include "./core/arch.h" @@ -78,12 +2013,15 @@ #include "./core/cpuinfo.h" #include "./core/datatypes.h" #include "./core/emitter.h" +#include "./core/environment.h" +#include "./core/errorhandler.h" #include "./core/features.h" +#include "./core/formatter.h" #include "./core/func.h" #include "./core/inst.h" #include "./core/jitallocator.h" #include "./core/jitruntime.h" -#include "./core/logging.h" +#include "./core/logger.h" #include "./core/operand.h" #include "./core/osutils.h" #include "./core/string.h" @@ -99,4 +2037,23 @@ #include "./core/zonestring.h" #include "./core/zonevector.h" +// ============================================================================ +// [Deprecated] +// ============================================================================ + +#ifndef ASMJIT_NO_DEPRECATED +namespace asmjit { + +#ifndef ASMJIT_NO_COMPILER +ASMJIT_DEPRECATED("Use InvokeNode instead of FuncCallNode") +typedef InvokeNode FuncCallNode; +#endif // !ASMJIT_NO_COMPILER + +#ifndef ASMJIT_NO_LOGGING +namespace Logging { using namespace Formatter; } +#endif //! ASMJIT_NO_LOGGING + +} // {asmjit} +#endif // !ASMJIT_NO_DEPRECATED + #endif // ASMJIT_CORE_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/api-build_p.h b/3rdparty/asmjit/src/asmjit/core/api-build_p.h index 714107c204d..db37ca77e93 100644 --- a/3rdparty/asmjit/src/asmjit/core/api-build_p.h +++ b/3rdparty/asmjit/src/asmjit/core/api-build_p.h @@ -53,7 +53,7 @@ #include "./api-config.h" -#if !defined(ASMJIT_BUILD_DEBUG) && ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 4, 0) +#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__) #define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os"))) #define ASMJIT_FAVOR_SPEED __attribute__((__optimize__("O3"))) #elif ASMJIT_CXX_HAS_ATTRIBUTE(__minsize__, 0) diff --git a/3rdparty/asmjit/src/asmjit/core/api-config.h b/3rdparty/asmjit/src/asmjit/core/api-config.h index de5985a066a..1388da49618 100644 --- a/3rdparty/asmjit/src/asmjit/core/api-config.h +++ b/3rdparty/asmjit/src/asmjit/core/api-config.h @@ -28,78 +28,90 @@ // [asmjit::Version] // ============================================================================ -#define ASMJIT_LIBRARY_VERSION 0x010200 /* 1.2.0 */ +//! \addtogroup asmjit_core +//! \{ + +//! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format. +#define ASMJIT_LIBRARY_VERSION 0x010400 /* 1.4.0 */ + +//! \} // ============================================================================ -// [asmjit::Options] +// [asmjit::Build - Documentation] // ============================================================================ -// AsmJit Static Builds and Embedding -// ---------------------------------- -// -// These definitions can be used to enable static library build. Embed is used -// when AsmJit's source code is embedded directly in another project, implies -// static build as well. -// -// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_BUILD_STATIC). -#define ASMJIT_STATIC // Enable static-library build. +// NOTE: Doxygen cannot document macros that are not defined, that's why we have +// to define them and then undefine them, so it won't use the macros with its +// own preprocessor. +#ifdef _DOXYGEN +namespace asmjit { -// AsmJit Build Mode -// ----------------- -// -// These definitions control the build mode and tracing support. The build mode -// should be auto-detected at compile time, but it's possible to override it in -// case that the auto-detection fails. -// -// Tracing is a feature that is never compiled by default and it's only used to -// debug AsmJit itself. -// -// #define ASMJIT_BUILD_DEBUG // Always use debug-mode (ASMJIT_ASSERT enabled). -// #define ASMJIT_BUILD_RELEASE // Always use release-mode (ASMJIT_ASSERT disabled). +//! \addtogroup asmjit_build +//! \{ -// AsmJit Build Backends -// --------------------- -// -// These definitions control which backends to compile. If none of these is -// defined AsmJit will use host architecture by default (for JIT code generation). -// -// #define ASMJIT_BUILD_X86 // Enable X86 targets (X86 and X86_64). -// #define ASMJIT_BUILD_ARM // Enable ARM targets (ARM and AArch64). -// #define ASMJIT_BUILD_HOST // Enable targets based on target arch (default). +//! Asmjit is embedded, implies \ref ASMJIT_STATIC. +#define ASMJIT_EMBED -// AsmJit Build Options -// -------------------- -// -// Flags can be defined to disable standard features. These are handy especially -// when building AsmJit statically and some features are not needed or unwanted -// (like BaseCompiler). -// -// AsmJit features are enabled by default. -// #define ASMJIT_NO_BUILDER // Disable Builder (completely). -// #define ASMJIT_NO_COMPILER // Disable Compiler (completely). -// #define ASMJIT_NO_JIT // Disable JIT memory manager and JitRuntime. -// #define ASMJIT_NO_LOGGING // Disable logging and formatting (completely). -// #define ASMJIT_NO_TEXT // Disable everything that contains text -// // representation (instructions, errors, ...). -// #define ASMJIT_NO_VALIDATION // Disable validation API and options. -// #define ASMJIT_NO_INTROSPECTION // Disable API related to instruction database. -// // (validation, cpu features, rw-info, etc). +//! Enables static-library build. +#define ASMJIT_STATIC -// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER. -#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER) - #define ASMJIT_NO_COMPILER -#endif +//! Defined when AsmJit's build configuration is 'Debug'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_DEBUG -// Prevent compile-time errors caused by misconfiguration. -#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING) - #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined." - #undef ASMJIT_NO_TEXT -#endif +//! Defined when AsmJit's build configuration is 'Release'. +//! +//! \note Can be defined explicitly to bypass autodetection. +#define ASMJIT_BUILD_RELEASE -#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER) - #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined") - #undef ASMJIT_NO_INTROSPECTION -#endif +//! Defined to build X86/X64 backend. +#define ASMJIT_BUILD_X86 + +//! Defined to build ARM/AArch64 backend. +#define ASMJIT_BUILD_ARM + +//! Defined to build host backend autodetected at compile-time. +#define ASMJIT_BUILD_HOST + +//! Disables deprecated API at compile time. +#define ASMJIT_NO_DEPRECATED + +//! Disables \ref asmjit_builder functionality completely. +#define ASMJIT_NO_BUILDER + +//! Disables \ref asmjit_compiler functionality completely. +#define ASMJIT_NO_COMPILER + +//! Disables JIT memory management and \ref JitRuntime. +#define ASMJIT_NO_JIT + +//! Disables \ref Logger and \ref Formatter. +#define ASMJIT_NO_LOGGING + +//! Disables everything that contains text. +#define ASMJIT_NO_TEXT + +//! Disables instruction validation API. +#define ASMJIT_NO_VALIDATION + +//! Disables instruction introspection API. +#define ASMJIT_NO_INTROSPECTION + +// Avoid doxygen preprocessor using feature-selection definitions. +#undef ASMJIT_NO_DEPRECATED +#undef ASMJIT_NO_BUILDER +#undef ASMJIT_NO_COMPILER +#undef ASMJIT_NO_JIT +#undef ASMJIT_NO_LOGGING +#undef ASMJIT_NO_TEXT +#undef ASMJIT_NO_VALIDATION +#undef ASMJIT_NO_INTROSPECTION + +//! \} + +} // {asmjit} +#endif // _DOXYGEN // ============================================================================ // [asmjit::Dependencies] @@ -122,23 +134,45 @@ #include <pthread.h> #endif + +// ============================================================================ +// [asmjit::Options] +// ============================================================================ + +// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER. +#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER) + #define ASMJIT_NO_COMPILER +#endif + +// Prevent compile-time errors caused by misconfiguration. +#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING) + #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined." + #undef ASMJIT_NO_TEXT +#endif + +#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER) + #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined") + #undef ASMJIT_NO_INTROSPECTION +#endif + // ============================================================================ // [asmjit::Build - Globals - Deprecated] // ============================================================================ -// DEPRECATED: Will be removed in the future. -#if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC) - #if defined(ASMJIT_BUILD_EMBED) - #pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'") - #endif - #if defined(ASMJIT_BUILD_STATIC) - #pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'") - #endif +#ifndef ASMJIT_NO_DEPRECATED + #if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC) + #if defined(ASMJIT_BUILD_EMBED) + #pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'") + #endif + #if defined(ASMJIT_BUILD_STATIC) + #pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'") + #endif - #if !defined(ASMJIT_STATIC) - #define ASMJIT_STATIC + #if !defined(ASMJIT_STATIC) + #define ASMJIT_STATIC + #endif #endif -#endif +#endif // !ASMJIT_NO_DEPRECATED // ============================================================================ // [asmjit::Build - Globals - Build Mode] @@ -181,7 +215,7 @@ #define ASMJIT_ARCH_MIPS 0 #endif -#define ASMJIT_ARCH_BITS (ASMJIT_ARCH_X86 | ASMJIT_ARCH_ARM | ASMJIT_ARCH_MIPS) +#define ASMJIT_ARCH_BITS (ASMJIT_ARCH_X86 | ASMJIT_ARCH_ARM | ASMJIT_ARCH_MIPS) #if ASMJIT_ARCH_BITS == 0 #undef ASMJIT_ARCH_BITS #if defined (__LP64__) || defined(_LP64) @@ -221,11 +255,8 @@ // [asmjit::Build - Globals - C++ Compiler and Features Detection] // ============================================================================ -#define ASMJIT_CXX_CLANG 0 #define ASMJIT_CXX_GNU 0 -#define ASMJIT_CXX_INTEL 0 -#define ASMJIT_CXX_MSC 0 -#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR, PATCH) ((MAJOR) * 10000000 + (MINOR) * 100000 + (PATCH)) +#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR)) // Intel Compiler [pretends to be GNU or MSC, so it must be checked first]: // - https://software.intel.com/en-us/articles/c0x-features-supported-by-intel-c-compiler @@ -233,9 +264,6 @@ // - https://software.intel.com/en-us/articles/c17-features-supported-by-intel-c-compiler #if defined(__INTEL_COMPILER) - #undef ASMJIT_CXX_INTEL - #define ASMJIT_CXX_INTEL ASMJIT_CXX_MAKE_VER(__INTEL_COMPILER / 100, (__INTEL_COMPILER / 10) % 10, __INTEL_COMPILER % 10) - // MSC Compiler: // - https://msdn.microsoft.com/en-us/library/hh567368.aspx // @@ -247,72 +275,26 @@ // - 19.10.0 == VS2017 #elif defined(_MSC_VER) && defined(_MSC_FULL_VER) - #undef ASMJIT_CXX_MSC - #if _MSC_VER == _MSC_FULL_VER / 10000 - #define ASMJIT_CXX_MSC ASMJIT_CXX_MAKE_VER(_MSC_VER / 100, _MSC_VER % 100, _MSC_FULL_VER % 10000) - #else - #define ASMJIT_CXX_MSC ASMJIT_CXX_MAKE_VER(_MSC_VER / 100, (_MSC_FULL_VER / 100000) % 100, _MSC_FULL_VER % 100000) - #endif - // Clang Compiler [Pretends to be GNU, so it must be checked before]: // - https://clang.llvm.org/cxx_status.html #elif defined(__clang_major__) && defined(__clang_minor__) && defined(__clang_patchlevel__) - #undef ASMJIT_CXX_CLANG - #define ASMJIT_CXX_CLANG ASMJIT_CXX_MAKE_VER(__clang_major__, __clang_minor__, __clang_patchlevel__) - // GNU Compiler: // - https://gcc.gnu.org/projects/cxx-status.html #elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) #undef ASMJIT_CXX_GNU - #define ASMJIT_CXX_GNU ASMJIT_CXX_MAKE_VER(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) + #define ASMJIT_CXX_GNU ASMJIT_CXX_MAKE_VER(__GNUC__, __GNUC_MINOR__) #endif // Compiler features detection macros. -#if ASMJIT_CXX_CLANG && defined(__has_builtin) - #define ASMJIT_CXX_HAS_BUILTIN(NAME, CHECK) (__has_builtin(NAME)) -#else - #define ASMJIT_CXX_HAS_BUILTIN(NAME, CHECK) (!(!(CHECK))) -#endif - -#if ASMJIT_CXX_CLANG && defined(__has_extension) - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (__has_extension(NAME)) -#elif ASMJIT_CXX_CLANG && defined(__has_feature) - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (__has_feature(NAME)) -#else - #define ASMJIT_CXX_HAS_FEATURE(NAME, CHECK) (!(!(CHECK))) -#endif - -#if ASMJIT_CXX_CLANG && defined(__has_attribute) +#if defined(__clang__) && defined(__has_attribute) #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (__has_attribute(NAME)) #else #define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK))) #endif -#if ASMJIT_CXX_CLANG && defined(__has_cpp_attribute) - #define ASMJIT_CXX_HAS_CPP_ATTRIBUTE(NAME, CHECK) (__has_cpp_attribute(NAME)) -#else - #define ASMJIT_CXX_HAS_CPP_ATTRIBUTE(NAME, CHECK) (!(!(CHECK))) -#endif - -// Compiler features by vendor. -#if defined(_MSC_VER) && !defined(_NATIVE_WCHAR_T_DEFINED) - #define ASMJIT_CXX_HAS_NATIVE_WCHAR_T 0 -#else - #define ASMJIT_CXX_HAS_NATIVE_WCHAR_T 1 -#endif - -#if ASMJIT_CXX_HAS_FEATURE(cxx_unicode_literals, ( \ - (ASMJIT_CXX_INTEL >= ASMJIT_CXX_MAKE_VER(14, 0, 0)) || \ - (ASMJIT_CXX_MSC >= ASMJIT_CXX_MAKE_VER(19, 0, 0)) || \ - (ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4 , 5, 0) && __cplusplus >= 201103L) )) - #define ASMJIT_CXX_HAS_UNICODE_LITERALS 1 -#else - #define ASMJIT_CXX_HAS_UNICODE_LITERALS 0 -#endif - // ============================================================================ // [asmjit::Build - Globals - API Decorators & Language Extensions] // ============================================================================ @@ -394,6 +376,15 @@ #define ASMJIT_REGPARM(N) #endif +#if ASMJIT_ARCH_X86 && defined(_WIN32) && defined(_MSC_VER) + #define ASMJIT_VECTORCALL __vectorcall +#elif ASMJIT_ARCH_X86 && defined(_WIN32) + #define ASMJIT_VECTORCALL __attribute__((__vectorcall__)) +#else + #define ASMJIT_VECTORCALL +#endif + + // Type alignment (not allowed by C++11 'alignas' keyword). #if defined(__GNUC__) #define ASMJIT_ALIGN_TYPE(TYPE, N) __attribute__((__aligned__(N))) TYPE @@ -403,13 +394,22 @@ #define ASMJIT_ALIGN_TYPE(TYPE, N) TYPE #endif +//! \def ASMJIT_MAY_ALIAS +//! +//! Expands to `__attribute__((__may_alias__))` if supported. #if defined(__GNUC__) #define ASMJIT_MAY_ALIAS __attribute__((__may_alias__)) #else #define ASMJIT_MAY_ALIAS #endif -// Annotations. +//! \def ASMJIT_LIKELY(...) +//! +//! Condition is likely to be taken (mostly error handling and edge cases). + +//! \def ASMJIT_UNLIKELY(...) +//! +//! Condition is unlikely to be taken (mostly error handling and edge cases). #if defined(__GNUC__) #define ASMJIT_LIKELY(...) __builtin_expect(!!(__VA_ARGS__), 1) #define ASMJIT_UNLIKELY(...) __builtin_expect(!!(__VA_ARGS__), 0) @@ -418,29 +418,42 @@ #define ASMJIT_UNLIKELY(...) (__VA_ARGS__) #endif +//! \def ASMJIT_FALLTHROUGH +//! +//! Portable [[fallthrough]] attribute. #if defined(__clang__) && __cplusplus >= 201103L #define ASMJIT_FALLTHROUGH [[clang::fallthrough]] -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(7, 0, 0) +#elif defined(__GNUC__) && __GNUC__ >= 7 #define ASMJIT_FALLTHROUGH __attribute__((__fallthrough__)) #else #define ASMJIT_FALLTHROUGH ((void)0) /* fallthrough */ #endif +//! \def ASMJIT_DEPRECATED +//! +//! Marks function, class, struct, enum, or anything else as deprecated. +#if defined(__GNUC__) + #define ASMJIT_DEPRECATED(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #if defined(__clang__) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) __attribute__((__deprecated__(MESSAGE))) + #else + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ + #endif +#elif defined(_MSC_VER) + #define ASMJIT_DEPRECATED(MESSAGE) __declspec(deprecated(MESSAGE)) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) /* not usable if a deprecated function uses it */ +#else + #define ASMJIT_DEPRECATED(MESSAGE) + #define ASMJIT_DEPRECATED_STRUCT(MESSAGE) +#endif + // Utilities. #define ASMJIT_OFFSET_OF(STRUCT, MEMBER) ((int)(intptr_t)((const char*)&((const STRUCT*)0x100)->MEMBER) - 0x100) #define ASMJIT_ARRAY_SIZE(X) uint32_t(sizeof(X) / sizeof(X[0])) -#if ASMJIT_CXX_HAS_ATTRIBUTE(attribute_deprecated_with_message, ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 5, 0)) - #define ASMJIT_DEPRECATED(DECL, MESSAGE) DECL __attribute__((__deprecated__(MESSAGE))) -#elif ASMJIT_CXX_MSC - #define ASMJIT_DEPRECATED(DECL, MESSAGE) __declspec(deprecated(MESSAGE)) DECL -#else - #define ASMJIT_DEPRECATED(DECL, MESSAGE) DECL -#endif - #if ASMJIT_CXX_HAS_ATTRIBUTE(no_sanitize, 0) #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize__("undefined"))) -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 9, 0) +#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 9) #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF __attribute__((__no_sanitize_undefined__)) #else #define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF @@ -459,8 +472,7 @@ #define ASMJIT_END_NAMESPACE \ _Pragma("clang diagnostic pop") \ } -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(4, 0, 0) && \ - ASMJIT_CXX_GNU < ASMJIT_CXX_MAKE_VER(5, 0, 0) +#elif defined(__GNUC__) && __GNUC__ == 4 #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ _Pragma("GCC diagnostic push") \ @@ -468,7 +480,7 @@ #define ASMJIT_END_NAMESPACE \ _Pragma("GCC diagnostic pop") \ } -#elif ASMJIT_CXX_GNU >= ASMJIT_CXX_MAKE_VER(8, 0, 0) +#elif defined(__GNUC__) && __GNUC__ >= 8 #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ _Pragma("GCC diagnostic push") \ @@ -480,8 +492,8 @@ #define ASMJIT_BEGIN_NAMESPACE \ namespace asmjit { \ __pragma(warning(push)) \ - __pragma(warning(disable: 4127)) /* conditional expression is constant*/\ - __pragma(warning(disable: 4201)) /* nameless struct/union */ + __pragma(warning(disable: 4127)) /* conditional expression is const */ \ + __pragma(warning(disable: 4201)) /* nameless struct/union */ #define ASMJIT_END_NAMESPACE \ __pragma(warning(pop)) \ } @@ -521,13 +533,8 @@ // [asmjit::Build - Globals - Cleanup] // ============================================================================ -// Try to cleanup things not used in other public headers. -#ifndef ASMJIT_EXPORTS - #undef ASMJIT_CXX_CLANG - #undef ASMJIT_CXX_GNU - #undef ASMJIT_CXX_INTEL - #undef ASMJIT_CXX_MSC - #undef ASMJIT_CXX_MAKE_VER -#endif +// Cleanup definitions that are only used within this header file. +#undef ASMJIT_CXX_GNU +#undef ASMJIT_CXX_MAKE_VER #endif // ASMJIT_CORE_API_CONFIG_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/arch.cpp b/3rdparty/asmjit/src/asmjit/core/arch.cpp index 97fca9d5c47..7200897b0a0 100644 --- a/3rdparty/asmjit/src/asmjit/core/arch.cpp +++ b/3rdparty/asmjit/src/asmjit/core/arch.cpp @@ -23,151 +23,34 @@ #include "../core/api-build_p.h" #include "../core/arch.h" -#include "../core/support.h" -#include "../core/type.h" #ifdef ASMJIT_BUILD_X86 - #include "../x86/x86operand.h" + #include "../x86/x86archdata_p.h" #endif #ifdef ASMJIT_BUILD_ARM - #include "../arm/armoperand.h" + #include "../arm/armarchdata_p.h" #endif ASMJIT_BEGIN_NAMESPACE // ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -// NOTE: Keep `const constexpr` otherwise MSC would not compile this code correctly. -static const constexpr uint32_t archInfoTable[] = { - // <--------------------+---------------------+-------------------+-------+ - // | Type | SubType | GPInfo| - // <--------------------+---------------------+-------------------+-------+ - Support::bytepack32_4x8(ArchInfo::kIdNone , ArchInfo::kSubIdNone, 0, 0), - Support::bytepack32_4x8(ArchInfo::kIdX86 , ArchInfo::kSubIdNone, 4, 8), - Support::bytepack32_4x8(ArchInfo::kIdX64 , ArchInfo::kSubIdNone, 8, 16), - Support::bytepack32_4x8(ArchInfo::kIdA32 , ArchInfo::kSubIdNone, 4, 16), - Support::bytepack32_4x8(ArchInfo::kIdA64 , ArchInfo::kSubIdNone, 8, 32) -}; - -ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t id, uint32_t subId) noexcept { - uint32_t index = id < ASMJIT_ARRAY_SIZE(archInfoTable) ? id : uint32_t(0); - - // Make sure the `archInfoTable` array is correctly indexed. - _signature = archInfoTable[index]; - ASMJIT_ASSERT(_id == index); - - // Even if the architecture is not known we setup its id and sub-id, - // however, such architecture is not really useful. - _id = uint8_t(id); - _subId = uint8_t(subId); -} - -// ============================================================================ // [asmjit::ArchUtils] // ============================================================================ -ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archId, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept { - uint32_t typeId = typeIdInOut; - - // Zero the signature so it's clear in case that typeId is not invalid. - regInfo._signature = 0; +ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept { + // Zero the output in case the input is invalid. + *typeIdOut = 0; + regInfoOut->reset(); - // TODO: Move to X86 backend. #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) { - // Passed RegType instead of TypeId? - if (typeId <= BaseReg::kTypeMax) - typeId = x86::opData.archRegs.regTypeToTypeId[typeId]; - - if (ASMJIT_UNLIKELY(!Type::isValid(typeId))) - return DebugUtils::errored(kErrorInvalidTypeId); - - // First normalize architecture dependent types. - if (Type::isAbstract(typeId)) { - if (typeId == Type::kIdIntPtr) - typeId = (archId == ArchInfo::kIdX86) ? Type::kIdI32 : Type::kIdI64; - else - typeId = (archId == ArchInfo::kIdX86) ? Type::kIdU32 : Type::kIdU64; - } - - // Type size helps to construct all groupss of registers. If the size is zero - // then the TypeId is invalid. - uint32_t size = Type::sizeOf(typeId); - if (ASMJIT_UNLIKELY(!size)) - return DebugUtils::errored(kErrorInvalidTypeId); - - if (ASMJIT_UNLIKELY(typeId == Type::kIdF80)) - return DebugUtils::errored(kErrorInvalidUseOfF80); - - uint32_t regType = 0; - - switch (typeId) { - case Type::kIdI8: - case Type::kIdU8: - regType = x86::Reg::kTypeGpbLo; - break; - - case Type::kIdI16: - case Type::kIdU16: - regType = x86::Reg::kTypeGpw; - break; - - case Type::kIdI32: - case Type::kIdU32: - regType = x86::Reg::kTypeGpd; - break; - - case Type::kIdI64: - case Type::kIdU64: - if (archId == ArchInfo::kIdX86) - return DebugUtils::errored(kErrorInvalidUseOfGpq); - - regType = x86::Reg::kTypeGpq; - break; - - // F32 and F64 are always promoted to use vector registers. - case Type::kIdF32: - typeId = Type::kIdF32x1; - regType = x86::Reg::kTypeXmm; - break; - - case Type::kIdF64: - typeId = Type::kIdF64x1; - regType = x86::Reg::kTypeXmm; - break; - - // Mask registers {k}. - case Type::kIdMask8: - case Type::kIdMask16: - case Type::kIdMask32: - case Type::kIdMask64: - regType = x86::Reg::kTypeKReg; - break; - - // MMX registers. - case Type::kIdMmx32: - case Type::kIdMmx64: - regType = x86::Reg::kTypeMm; - break; - - // XMM|YMM|ZMM registers. - default: - if (size <= 16) - regType = x86::Reg::kTypeXmm; - else if (size == 32) - regType = x86::Reg::kTypeYmm; - else - regType = x86::Reg::kTypeZmm; - break; - } + if (Environment::isFamilyX86(arch)) + return x86::ArchInternal::typeIdToRegInfo(arch, typeId, typeIdOut, regInfoOut); +#endif - typeIdInOut = typeId; - regInfo._signature = x86::opData.archRegs.regInfo[regType].signature(); - return kErrorOk; - } +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::ArchInternal::typeIdToRegInfo(arch, typeId, typeIdOut, regInfoOut); #endif return DebugUtils::errored(kErrorInvalidArch); diff --git a/3rdparty/asmjit/src/asmjit/core/arch.h b/3rdparty/asmjit/src/asmjit/core/arch.h index b0a27fd9cd5..4991a3330d3 100644 --- a/3rdparty/asmjit/src/asmjit/core/arch.h +++ b/3rdparty/asmjit/src/asmjit/core/arch.h @@ -24,7 +24,7 @@ #ifndef ASMJIT_CORE_ARCH_H_INCLUDED #define ASMJIT_CORE_ARCH_H_INCLUDED -#include "../core/globals.h" +#include "../core/environment.h" #include "../core/operand.h" ASMJIT_BEGIN_NAMESPACE @@ -33,153 +33,10 @@ ASMJIT_BEGIN_NAMESPACE //! \{ // ============================================================================ -// [asmjit::ArchInfo] -// ============================================================================ - -class ArchInfo { -public: - union { - struct { - //! Architecture id. - uint8_t _id; - //! Architecture sub-id. - uint8_t _subId; - //! Default size of a general purpose register. - uint8_t _gpSize; - //! Count of all general purpose registers. - uint8_t _gpCount; - }; - //! Architecture signature (32-bit int). - uint32_t _signature; - }; - - //! Architecture id. - enum Id : uint32_t { - kIdNone = 0, //!< No/Unknown architecture. - - // X86 architectures. - kIdX86 = 1, //!< X86 architecture (32-bit). - kIdX64 = 2, //!< X64 architecture (64-bit) (AMD64). - - // ARM architectures. - kIdA32 = 3, //!< ARM 32-bit architecture (AArch32/ARM/THUMB). - kIdA64 = 4, //!< ARM 64-bit architecture (AArch64). - - //! Architecture detected at compile-time (architecture of the host). - kIdHost = ASMJIT_ARCH_X86 == 32 ? kIdX86 : - ASMJIT_ARCH_X86 == 64 ? kIdX64 : - ASMJIT_ARCH_ARM == 32 ? kIdA32 : - ASMJIT_ARCH_ARM == 64 ? kIdA64 : kIdNone - }; - - //! Architecture sub-type or execution mode. - enum SubType : uint32_t { - kSubIdNone = 0, //!< Default mode (or no specific mode). - - // X86 sub-types. - kSubIdX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions). - kSubIdX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions). - kSubIdX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs). - kSubIdX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions). - - // ARM sub-types. - kSubIdA32_Thumb = 8, //!< THUMB|THUMBv2 sub-type (only ARM in 32-bit mode). - -#if (ASMJIT_ARCH_X86) && defined(__AVX512VL__) - kSubIdHost = kSubIdX86_AVX512VL -#elif (ASMJIT_ARCH_X86) && defined(__AVX512F__) - kSubIdHost = kSubIdX86_AVX512 -#elif (ASMJIT_ARCH_X86) && defined(__AVX2__) - kSubIdHost = kSubIdX86_AVX2 -#elif (ASMJIT_ARCH_X86) && defined(__AVX__) - kSubIdHost = kSubIdX86_AVX -#elif (ASMJIT_ARCH_ARM == 32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__)) - kSubIdHost = kSubIdA32_Thumb -#else - kSubIdHost = 0 -#endif - }; - - //! \name Construction & Destruction - //! \{ - - inline ArchInfo() noexcept : _signature(0) {} - inline ArchInfo(const ArchInfo& other) noexcept : _signature(other._signature) {} - inline explicit ArchInfo(uint32_t type, uint32_t subType = kSubIdNone) noexcept { init(type, subType); } - inline explicit ArchInfo(Globals::NoInit_) noexcept {} - - inline static ArchInfo host() noexcept { return ArchInfo(kIdHost, kSubIdHost); } - - inline bool isInitialized() const noexcept { return _id != kIdNone; } - - ASMJIT_API void init(uint32_t type, uint32_t subType = kSubIdNone) noexcept; - inline void reset() noexcept { _signature = 0; } - - //! \} - - //! \name Overloaded Operators - //! \{ - - inline ArchInfo& operator=(const ArchInfo& other) noexcept = default; - - inline bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; } - inline bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; } - - //! \} - - //! \name Accessors - //! \{ - - //! Returns the architecture id, see `Id`. - inline uint32_t archId() const noexcept { return _id; } - - //! Returns the architecture sub-id, see `SubType`. - //! - //! X86 & X64 - //! --------- - //! - //! Architecture subtype describe the highest instruction-set level that can - //! be used. - //! - //! A32 & A64 - //! --------- - //! - //! Architecture mode means the instruction encoding to be used when generating - //! machine code, thus mode can be used to force generation of THUMB and THUMBv2 - //! encoding or regular ARM encoding. - inline uint32_t archSubId() const noexcept { return _subId; } - - //! Tests whether this architecture is 32-bit. - inline bool is32Bit() const noexcept { return _gpSize == 4; } - //! Tests whether this architecture is 64-bit. - inline bool is64Bit() const noexcept { return _gpSize == 8; } - - //! Tests whether this architecture is X86, X64. - inline bool isX86Family() const noexcept { return isX86Family(_id); } - //! Tests whether this architecture is ARM32 or ARM64. - inline bool isArmFamily() const noexcept { return isArmFamily(_id); } - - //! Returns the native size of a general-purpose register. - inline uint32_t gpSize() const noexcept { return _gpSize; } - //! Returns number of general-purpose registers. - inline uint32_t gpCount() const noexcept { return _gpCount; } - - //! \} - - //! \name Static Functions - //! \{ - - static inline bool isX86Family(uint32_t archId) noexcept { return archId >= kIdX86 && archId <= kIdX64; } - static inline bool isArmFamily(uint32_t archId) noexcept { return archId >= kIdA32 && archId <= kIdA64; } - - //! \} -}; - -// ============================================================================ // [asmjit::ArchRegs] // ============================================================================ -//! Information about all architecture registers. +//! Information about registers of a CPU architecture. struct ArchRegs { //! Register information and signatures indexed by `BaseReg::RegType`. RegInfo regInfo[BaseReg::kTypeMax + 1]; @@ -193,9 +50,12 @@ struct ArchRegs { // [asmjit::ArchUtils] // ============================================================================ -struct ArchUtils { - ASMJIT_API static Error typeIdToRegInfo(uint32_t archId, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept; -}; +//! Architecture utilities. +namespace ArchUtils { + +ASMJIT_API Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfo) noexcept; + +} // {ArchUtils} //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/assembler.cpp b/3rdparty/asmjit/src/asmjit/core/assembler.cpp index 35c39ab6089..2eea9cbae94 100644 --- a/3rdparty/asmjit/src/asmjit/core/assembler.cpp +++ b/3rdparty/asmjit/src/asmjit/core/assembler.cpp @@ -25,7 +25,9 @@ #include "../core/assembler.h" #include "../core/codebufferwriter_p.h" #include "../core/constpool.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -39,9 +41,7 @@ BaseAssembler::BaseAssembler() noexcept _section(nullptr), _bufferData(nullptr), _bufferEnd(nullptr), - _bufferPtr(nullptr), - _op4(), - _op5() {} + _bufferPtr(nullptr) {} BaseAssembler::~BaseAssembler() noexcept {} // ============================================================================ @@ -50,7 +50,7 @@ BaseAssembler::~BaseAssembler() noexcept {} Error BaseAssembler::setOffset(size_t offset) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); size_t size = Support::max<size_t>(_section->bufferSize(), this->offset()); if (ASMJIT_UNLIKELY(offset > size)) @@ -61,25 +61,6 @@ Error BaseAssembler::setOffset(size_t offset) { } // ============================================================================ -// [asmjit::BaseAssembler - Logging] -// ============================================================================ - -#ifndef ASMJIT_NO_LOGGING -static void BaseAssembler_logLabel(BaseAssembler* self, const Label& label) noexcept { - Logger* logger = self->_code->_logger; - - StringTmp<512> sb; - size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : std::numeric_limits<size_t>::max(); - - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel)); - Logging::formatLabel(sb, logger->flags(), self, label.id()); - sb.appendChar(':'); - Logging::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment); - logger->log(sb.data(), sb.size()); -} -#endif - -// ============================================================================ // [asmjit::BaseAssembler - Section Management] // ============================================================================ @@ -100,8 +81,8 @@ Error BaseAssembler::section(Section* section) { return reportError(DebugUtils::errored(kErrorInvalidSection)); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - _code->_logger->logf(".section %s {#%u}\n", section->name(), section->id()); + if (_logger) + _logger->logf(".section %s {#%u}\n", section->name(), section->id()); #endif BaseAssembler_initSection(this, section); @@ -119,7 +100,8 @@ Label BaseAssembler::newLabel() { Error err = _code->newLabelEntry(&le); if (ASMJIT_UNLIKELY(err)) reportError(err); - labelId = le->id(); + else + labelId = le->id(); } return Label(labelId); } @@ -131,20 +113,21 @@ Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, uint32_t t Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId); if (ASMJIT_UNLIKELY(err)) reportError(err); - labelId = le->id(); + else + labelId = le->id(); } return Label(labelId); } Error BaseAssembler::bind(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); Error err = _code->bindLabel(label, _section->id(), offset()); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - BaseAssembler_logLabel(this, label); + if (_logger) + EmitterUtils::logLabelBound(this, label); #endif resetInlineComment(); @@ -155,165 +138,112 @@ Error BaseAssembler::bind(const Label& label) { } // ============================================================================ -// [asmjit::BaseAssembler - Emit (Low-Level)] +// [asmjit::BaseAssembler - Embed] // ============================================================================ -Error BaseAssembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { - _op4 = o4; - _op5 = o5; - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, o0, o1, o2, o3); -} - -Error BaseAssembler::_emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { - const Operand_* o0 = &operands[0]; - const Operand_* o1 = &operands[1]; - const Operand_* o2 = &operands[2]; - const Operand_* o3 = &operands[3]; - - switch (count) { - case 0: o0 = &Globals::none; ASMJIT_FALLTHROUGH; - case 1: o1 = &Globals::none; ASMJIT_FALLTHROUGH; - case 2: o2 = &Globals::none; ASMJIT_FALLTHROUGH; - case 3: o3 = &Globals::none; ASMJIT_FALLTHROUGH; - case 4: - return _emit(instId, *o0, *o1, *o2, *o3); - - case 5: - _op4 = operands[4]; - _op5.reset(); - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, *o0, *o1, *o2, *o3); - - case 6: - _op4 = operands[4]; - _op5 = operands[5]; - _instOptions |= BaseInst::kOptionOp4Op5Used; - return _emit(instId, *o0, *o1, *o2, *o3); - - default: - return DebugUtils::errored(kErrorInvalidArgument); - } -} - #ifndef ASMJIT_NO_LOGGING -void BaseAssembler::_emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) { +struct DataSizeByPower { + char str[4]; +}; - Logger* logger = _code->logger(); - ASMJIT_ASSERT(logger != nullptr); - ASMJIT_ASSERT(options & BaseEmitter::kOptionLoggingEnabled); +static const DataSizeByPower dataSizeByPowerTable[] = { + { "db" }, + { "dw" }, + { "dd" }, + { "dq" } +}; +#endif - StringTmp<256> sb; - uint32_t flags = logger->flags(); +Error BaseAssembler::embed(const void* data, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); - uint8_t* beforeCursor = _bufferPtr; - intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + if (dataSize == 0) + return kErrorOk; - Operand_ operands[Globals::kMaxOpCount]; - operands[0].copyFrom(o0); - operands[1].copyFrom(o1); - operands[2].copyFrom(o2); - operands[3].copyFrom(o3); + CodeBufferWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); - if (options & BaseInst::kOptionOp4Op5Used) { - operands[4].copyFrom(_op4); - operands[5].copyFrom(_op5); - } - else { - operands[4].reset(); - operands[5].reset(); - } + writer.emitData(data, dataSize); - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); - Logging::formatInstruction(sb, flags, this, archId(), BaseInst(instId, options, _extraReg), operands, Globals::kMaxOpCount); +#ifndef ASMJIT_NO_LOGGING + if (_logger) + _logger->logBinary(data, dataSize); +#endif - if ((flags & FormatOptions::kFlagMachineCode) != 0) - Logging::formatLine(sb, _bufferPtr, size_t(emittedSize), relSize, immSize, inlineComment()); - else - Logging::formatLine(sb, nullptr, std::numeric_limits<size_t>::max(), 0, 0, inlineComment()); - logger->log(sb); + writer.done(this); + return kErrorOk; } -Error BaseAssembler::_emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { +Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount) { + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); - StringTmp<256> sb; - sb.appendString(DebugUtils::errorAsString(err)); - sb.appendString(": "); + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); - Operand_ operands[Globals::kMaxOpCount]; - operands[0].copyFrom(o0); - operands[1].copyFrom(o1); - operands[2].copyFrom(o2); - operands[3].copyFrom(o3); + if (itemCcount == 0 || repeatCount == 0) + return kErrorOk; - if (options & BaseInst::kOptionOp4Op5Used) { - operands[4].copyFrom(_op4); - operands[5].copyFrom(_op5); - } - else { - operands[4].reset(); - operands[5].reset(); - } + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; - Logging::formatInstruction(sb, 0, this, archId(), BaseInst(instId, options, _extraReg), operands, Globals::kMaxOpCount); + size_t dataSize = Support::mulOverflow(itemCcount, size_t(typeSize), &of); + size_t totalSize = Support::mulOverflow(dataSize, repeatCount, &of); - if (inlineComment()) { - sb.appendString(" ; "); - sb.appendString(inlineComment()); - } + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); - resetInstOptions(); - resetExtraReg(); - resetInlineComment(); - return reportError(err, sb.data()); -} + CodeBufferWriter writer(this); + ASMJIT_PROPAGATE(writer.ensureSpace(this, totalSize)); + +#ifndef ASMJIT_NO_LOGGING + const uint8_t* start = writer.cursor(); #endif -// ============================================================================ -// [asmjit::BaseAssembler - Embed] -// ============================================================================ + for (size_t i = 0; i < repeatCount; i++) { + writer.emitData(data, dataSize); + } #ifndef ASMJIT_NO_LOGGING -struct DataSizeByPower { - char str[4]; -}; - -static const DataSizeByPower dataSizeByPowerTable[] = { - { "db" }, - { "dw" }, - { "dd" }, - { "dq" } -}; + if (_logger) + _logger->logBinary(start, totalSize); #endif -Error BaseAssembler::embed(const void* data, uint32_t dataSize) { + writer.done(this); + return kErrorOk; +} + +Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); - if (dataSize == 0) - return DebugUtils::errored(kErrorInvalidArgument); + if (ASMJIT_UNLIKELY(!isLabelValid(label))) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + size_t size = pool.size(); CodeBufferWriter writer(this); - ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); + ASMJIT_PROPAGATE(writer.ensureSpace(this, size)); - writer.emitData(data, dataSize); + pool.fill(writer.cursor()); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) - _code->_logger->logBinary(data, dataSize); + if (_logger) + _logger->logBinary(writer.cursor(), size); #endif + writer.advance(size); writer.done(this); + return kErrorOk; } Error BaseAssembler::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); ASMJIT_ASSERT(_code != nullptr); RelocEntry* re; @@ -322,30 +252,22 @@ Error BaseAssembler::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!le)) return reportError(DebugUtils::errored(kErrorInvalidLabel)); - uint32_t dataSize = gpSize(); + uint32_t dataSize = registerSize(); ASMJIT_ASSERT(dataSize <= 8); CodeBufferWriter writer(this); ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) { + if (_logger) { StringTmp<256> sb; - sb.appendFormat(".%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str); - Logging::formatLabel(sb, 0, this, label.id()); - sb.appendChar('\n'); - _code->_logger->log(sb); + sb.appendFormat("%s ", dataSizeByPowerTable[Support::ctz(dataSize)].str); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append('\n'); + _logger->log(sb); } #endif - // TODO: Does it make sense to calculate the address here if everything is known? - /* - if (_code->hasBaseAddress() && currentSection() == _code->textSection() && le->isBound()) { - uint64_t addr = _code->baseAddress() + _code->textSection()->offset() + le->offset(); - writer.emitValueLE(addr, dataSize); - } - */ - Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, dataSize); if (ASMJIT_UNLIKELY(err)) return reportError(err); @@ -371,9 +293,9 @@ Error BaseAssembler::embedLabel(const Label& label) { return kErrorOk; } -Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) { +Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); LabelEntry* labelEntry = _code->labelEntry(label); LabelEntry* baseEntry = _code->labelEntry(base); @@ -382,7 +304,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint return reportError(DebugUtils::errored(kErrorInvalidLabel)); if (dataSize == 0) - dataSize = gpSize(); + dataSize = registerSize(); if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) return reportError(DebugUtils::errored(kErrorInvalidOperandSize)); @@ -391,14 +313,14 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint ASMJIT_PROPAGATE(writer.ensureSpace(this, dataSize)); #ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) { + if (_logger) { StringTmp<256> sb; sb.appendFormat(".%s (", dataSizeByPowerTable[Support::ctz(dataSize)].str); - Logging::formatLabel(sb, 0, this, label.id()); - sb.appendString(" - "); - Logging::formatLabel(sb, 0, this, base.id()); - sb.appendString(")\n"); - _code->_logger->log(sb); + Formatter::formatLabel(sb, 0, this, label.id()); + sb.append(" - "); + Formatter::formatLabel(sb, 0, this, base.id()); + sb.append(")\n"); + _logger->log(sb); } #endif @@ -409,7 +331,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint } else { RelocEntry* re; - Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression, dataSize); + Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression, uint32_t(dataSize)); if (ASMJIT_UNLIKELY(err)) return reportError(err); @@ -433,46 +355,18 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, uint return kErrorOk; } -Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) { - if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); - - if (ASMJIT_UNLIKELY(!isLabelValid(label))) - return DebugUtils::errored(kErrorInvalidLabel); - - ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); - ASMJIT_PROPAGATE(bind(label)); - - size_t size = pool.size(); - CodeBufferWriter writer(this); - ASMJIT_PROPAGATE(writer.ensureSpace(this, size)); - - pool.fill(writer.cursor()); - -#ifndef ASMJIT_NO_LOGGING - if (ASMJIT_UNLIKELY(hasEmitterOption(kOptionLoggingEnabled))) - _code->_logger->logBinary(writer.cursor(), size); -#endif - - writer.advance(size); - writer.done(this); - - return kErrorOk; -} - // ============================================================================ // [asmjit::BaseAssembler - Comment] // ============================================================================ Error BaseAssembler::comment(const char* data, size_t size) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) { - Logger* logger = _code->logger(); - logger->log(data, size); - logger->log("\n", 1); + if (_logger) { + _logger->log(data, size); + _logger->log("\n", 1); return kErrorOk; } #else @@ -492,10 +386,6 @@ Error BaseAssembler::onAttach(CodeHolder* code) noexcept { // Attach to the end of the .text section. BaseAssembler_initSection(this, code->_sections[0]); - // And reset everything that is used temporarily. - _op4.reset(); - _op5.reset(); - return kErrorOk; } @@ -504,10 +394,6 @@ Error BaseAssembler::onDetach(CodeHolder* code) noexcept { _bufferData = nullptr; _bufferEnd = nullptr; _bufferPtr = nullptr; - - _op4.reset(); - _op5.reset(); - return Base::onDetach(code); } diff --git a/3rdparty/asmjit/src/asmjit/core/assembler.h b/3rdparty/asmjit/src/asmjit/core/assembler.h index fd2c1c33c28..966dabb06e0 100644 --- a/3rdparty/asmjit/src/asmjit/core/assembler.h +++ b/3rdparty/asmjit/src/asmjit/core/assembler.h @@ -31,14 +31,23 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ // [asmjit::BaseAssembler] // ============================================================================ -//! Base encoder (assembler). +//! Base assembler. +//! +//! This is a base class that provides interface used by architecture specific +//! assembler implementations. Assembler doesn't hold any data, instead it's +//! attached to \ref CodeHolder, which provides all the data that Assembler +//! needs and which can be altered by it. +//! +//! Check out architecture specific assemblers for more details and examples: +//! +//! - \ref x86::Assembler - X86/X64 assembler implementation. class ASMJIT_VIRTAPI BaseAssembler : public BaseEmitter { public: ASMJIT_NONCOPYABLE(BaseAssembler) @@ -52,10 +61,6 @@ public: uint8_t* _bufferEnd; //! Pointer in the CodeBuffer of the current section. uint8_t* _bufferPtr; - //! 5th operand data, used only temporarily. - Operand_ _op4; - //! 6th operand data, used only temporarily. - Operand_ _op5; //! \name Construction & Destruction //! \{ @@ -77,10 +82,11 @@ public: //! Returns the current position in the CodeBuffer. inline size_t offset() const noexcept { return (size_t)(_bufferPtr - _bufferData); } + //! Sets the current position in the CodeBuffer to `offset`. //! - //! \note The `offset` cannot be outside of the buffer size (even if it's - //! within buffer's capacity). + //! \note The `offset` cannot be greater than buffer size even if it's + //! within the buffer's capacity. ASMJIT_API Error setOffset(size_t offset); //! Returns the start of the CodeBuffer in the current section. @@ -95,6 +101,7 @@ public: //! \name Section Management //! \{ + //! Returns the current section. inline Section* currentSection() const noexcept { return _section; } ASMJIT_API Error section(Section* section) override; @@ -110,47 +117,16 @@ public: //! \} - //! \cond INTERNAL - //! \name Emit - //! \{ - - using BaseEmitter::_emit; - - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; - ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t count) override; - -protected: -#ifndef ASMJIT_NO_LOGGING - void _emitLog( - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, - uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); - - Error _emitFailed( - Error err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); -#else - inline Error _emitFailed( - uint32_t err, - uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - - DebugUtils::unused(instId, options, o0, o1, o2, o3); - resetInstOptions(); - resetInlineComment(); - return reportError(err); - } -#endif -public: - //! \} - //! \endcond - //! \name Embed //! \{ - ASMJIT_API Error embed(const void* data, uint32_t dataSize) override; - ASMJIT_API Error embedLabel(const Label& label) override; - ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) override; + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCcount, size_t repeatCount = 1) override; ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API Error embedLabel(const Label& label) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) override; + //! \} //! \name Comment diff --git a/3rdparty/asmjit/src/asmjit/core/builder.cpp b/3rdparty/asmjit/src/asmjit/core/builder.cpp index 35d7127481c..97780c767a4 100644 --- a/3rdparty/asmjit/src/asmjit/core/builder.cpp +++ b/3rdparty/asmjit/src/asmjit/core/builder.cpp @@ -25,7 +25,10 @@ #ifndef ASMJIT_NO_BUILDER #include "../core/builder.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -41,13 +44,23 @@ class PostponedErrorHandler : public ErrorHandler { public: void handleError(Error err, const char* message, BaseEmitter* origin) override { DebugUtils::unused(err, origin); - _message.assignString(message); + _message.assign(message); } StringTmp<128> _message; }; // ============================================================================ +// [asmjit::BaseBuilder - Utilities] +// ============================================================================ + +static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept { + for (Pass* pass : self->_passes) + pass->~Pass(); + self->_passes.reset(); +} + +// ============================================================================ // [asmjit::BaseBuilder - Construction / Destruction] // ============================================================================ @@ -63,132 +76,101 @@ BaseBuilder::BaseBuilder() noexcept _firstNode(nullptr), _lastNode(nullptr), _nodeFlags(0) {} -BaseBuilder::~BaseBuilder() noexcept {} + +BaseBuilder::~BaseBuilder() noexcept { + BaseBuilder_deletePasses(this); +} // ============================================================================ // [asmjit::BaseBuilder - Node Management] // ============================================================================ -LabelNode* BaseBuilder::newLabelNode() noexcept { - LabelNode* node = newNodeT<LabelNode>(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; -} +Error BaseBuilder::_newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount) { + uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); -AlignNode* BaseBuilder::newAlignNode(uint32_t alignMode, uint32_t alignment) noexcept { - return newNodeT<AlignNode>(alignMode, alignment); + InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); + if (ASMJIT_UNLIKELY(!node)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + + *out = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); + return kErrorOk; } -EmbedDataNode* BaseBuilder::newEmbedDataNode(const void* data, uint32_t size) noexcept { - if (size > EmbedDataNode::kInlineBufferSize) { - void* cloned = _dataZone.alloc(size); - if (ASMJIT_UNLIKELY(!cloned)) - return nullptr; - if (data) - memcpy(cloned, data, size); - data = cloned; - } +Error BaseBuilder::_newLabelNode(LabelNode** out) { + *out = nullptr; - return newNodeT<EmbedDataNode>(const_cast<void*>(data), size); + ASMJIT_PROPAGATE(_newNodeT<LabelNode>(out)); + return registerLabelNode(*out); } -ConstPoolNode* BaseBuilder::newConstPoolNode() noexcept { - ConstPoolNode* node = newNodeT<ConstPoolNode>(); - if (!node || registerLabelNode(node) != kErrorOk) - return nullptr; - return node; +Error BaseBuilder::_newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment) { + *out = nullptr; + return _newNodeT<AlignNode>(out, alignMode, alignment); } -CommentNode* BaseBuilder::newCommentNode(const char* data, size_t size) noexcept { - if (data) { - if (size == SIZE_MAX) - size = strlen(data); +Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) { + *out = nullptr; - if (size > 0) { - data = static_cast<char*>(_dataZone.dup(data, size, true)); - if (!data) return nullptr; - } - } + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize()); + uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta); - return newNodeT<CommentNode>(data); -} + if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId))) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0) noexcept { - uint32_t opCount = 1; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + uint32_t typeSize = Type::sizeOf(finalTypeId); + Support::FastUInt8 of = 0; - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; + size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of); + if (ASMJIT_UNLIKELY(of)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->resetOps(opCount, opCapacity); - return node; -} + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node)); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1) noexcept { - uint32_t opCount = 2; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + node->_embed._typeId = uint8_t(typeId); + node->_embed._typeSize = uint8_t(typeSize); + node->_itemCount = itemCount; + node->_repeatCount = repeatCount; - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; + uint8_t* dstData = node->_inlineData; + if (dataSize > EmbedDataNode::kInlineBufferSize) { + dstData = static_cast<uint8_t*>(_dataZone.alloc(dataSize, 8)); + if (ASMJIT_UNLIKELY(!dstData)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + node->_externalData = dstData; + } - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->resetOps(opCount, opCapacity); - return node; -} + if (data) + memcpy(dstData, data, dataSize); -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept { - uint32_t opCount = 3; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + *out = node; + return kErrorOk; +} - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; +Error BaseBuilder::_newConstPoolNode(ConstPoolNode** out) { + *out = nullptr; - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->resetOps(opCount, opCapacity); - return node; + ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out)); + return registerLabelNode(*out); } -InstNode* BaseBuilder::newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept { - uint32_t opCount = 4; - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); - - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; +Error BaseBuilder::_newCommentNode(CommentNode** out, const char* data, size_t size) { + *out = nullptr; - node = new(node) InstNode(this, instId, instOptions, opCount, opCapacity); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->setOp(3, o3); - node->resetOps(opCount, opCapacity); - return node; -} + if (data) { + if (size == SIZE_MAX) + size = strlen(data); -InstNode* BaseBuilder::newInstNodeRaw(uint32_t instId, uint32_t instOptions, uint32_t opCount) noexcept { - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); + if (size > 0) { + data = static_cast<char*>(_dataZone.dup(data, size, true)); + if (ASMJIT_UNLIKELY(!data)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + } + } - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - if (ASMJIT_UNLIKELY(!node)) - return nullptr; - return new(node) InstNode(this, instId, instOptions, opCount, opCapacity); + return _newNodeT<CommentNode>(out, data); } BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept { @@ -368,34 +350,42 @@ BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept { // [asmjit::BaseBuilder - Section] // ============================================================================ -Error BaseBuilder::sectionNodeOf(SectionNode** pOut, uint32_t sectionId) noexcept { +Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) { + *out = nullptr; + if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); if (ASMJIT_UNLIKELY(!_code->isSectionValid(sectionId))) - return DebugUtils::errored(kErrorInvalidSection); + return reportError(DebugUtils::errored(kErrorInvalidSection)); - if (sectionId >= _sectionNodes.size()) - ASMJIT_PROPAGATE(_sectionNodes.resize(&_allocator, sectionId + 1)); + if (sectionId >= _sectionNodes.size()) { + Error err = _sectionNodes.reserve(&_allocator, sectionId + 1); + if (ASMJIT_UNLIKELY(err != kErrorOk)) + return reportError(err); + } + + SectionNode* node = nullptr; + if (sectionId < _sectionNodes.size()) + node = _sectionNodes[sectionId]; - SectionNode* node = _sectionNodes[sectionId]; if (!node) { - node = newNodeT<SectionNode>(sectionId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + ASMJIT_PROPAGATE(_newNodeT<SectionNode>(&node, sectionId)); + + // We have already reserved enough space, this cannot fail now. + if (sectionId >= _sectionNodes.size()) + _sectionNodes.resize(&_allocator, sectionId + 1); + _sectionNodes[sectionId] = node; } - *pOut = node; + *out = node; return kErrorOk; } Error BaseBuilder::section(Section* section) { SectionNode* node; - Error err = sectionNodeOf(&node, section->id()); - - if (ASMJIT_UNLIKELY(err)) - return reportError(err); + ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id())); if (!node->isActive()) { // Insert the section at the end if it was not part of the code. @@ -444,7 +434,9 @@ void BaseBuilder::updateSectionLinks() noexcept { // [asmjit::BaseBuilder - Labels] // ============================================================================ -Error BaseBuilder::labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept { +Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) { + *out = nullptr; + if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); @@ -457,22 +449,18 @@ Error BaseBuilder::labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept { LabelNode* node = _labelNodes[index]; if (!node) { - node = newNodeT<LabelNode>(labelId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + ASMJIT_PROPAGATE(_newNodeT<LabelNode>(&node, labelId)); _labelNodes[index] = node; } - *pOut = node; + *out = node; return kErrorOk; } -Error BaseBuilder::registerLabelNode(LabelNode* node) noexcept { +Error BaseBuilder::registerLabelNode(LabelNode* node) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - // Don't call `reportError()` from here, we are noexcept and we are called - // by `newLabelNode()` and `newFuncNode()`, which are noexcept as well. LabelEntry* le; ASMJIT_PROPAGATE(_code->newLabelEntry(&le)); uint32_t labelId = le->id(); @@ -482,68 +470,58 @@ Error BaseBuilder::registerLabelNode(LabelNode* node) noexcept { ASMJIT_PROPAGATE(_labelNodes.resize(&_allocator, labelId + 1)); _labelNodes[labelId] = node; - node->_id = labelId; + node->_labelId = labelId; return kErrorOk; } -static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) noexcept { +static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) { ASMJIT_ASSERT(self->_labelNodes.size() < labelId + 1); - LabelNode* node = self->newNodeT<LabelNode>(labelId); - if (ASMJIT_UNLIKELY(!node)) - return DebugUtils::errored(kErrorOutOfMemory); + uint32_t growBy = labelId - self->_labelNodes.size(); + Error err = self->_labelNodes.willGrow(&self->_allocator, growBy); + + if (ASMJIT_UNLIKELY(err)) + return self->reportError(err); + + LabelNode* node; + ASMJIT_PROPAGATE(self->_newNodeT<LabelNode>(&node, labelId)); - ASMJIT_PROPAGATE(self->_labelNodes.resize(&self->_allocator, labelId + 1)); + self->_labelNodes.resize(&self->_allocator, labelId + 1); self->_labelNodes[labelId] = node; - node->_id = labelId; + node->_labelId = labelId; return kErrorOk; } Label BaseBuilder::newLabel() { uint32_t labelId = Globals::kInvalidId; - if (_code) { - LabelEntry* le; - Error err = _code->newLabelEntry(&le); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - } - else { - err = BaseBuilder_newLabelInternal(this, le->id()); - if (ASMJIT_UNLIKELY(err)) - reportError(err); - else - labelId = le->id(); - } + LabelEntry* le; + + if (_code && + _code->newLabelEntry(&le) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); } + return Label(labelId); } Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) { uint32_t labelId = Globals::kInvalidId; - if (_code) { - LabelEntry* le; - Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - } - else { - err = BaseBuilder_newLabelInternal(this, le->id()); - if (ASMJIT_UNLIKELY(err)) - reportError(err); - else - labelId = le->id(); - } + LabelEntry* le; + + if (_code && + _code->newNamedLabelEntry(&le, name, nameSize, type, parentId) == kErrorOk && + BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) { + labelId = le->id(); } + return Label(labelId); } Error BaseBuilder::bind(const Label& label) { LabelNode* node; - Error err = labelNodeOf(&node, label); - - if (ASMJIT_UNLIKELY(err)) - return reportError(err); + ASMJIT_PROPAGATE(labelNodeOf(&node, label)); addNode(node); return kErrorOk; @@ -610,7 +588,6 @@ Error BaseBuilder::runPasses() { if (_passes.empty()) return kErrorOk; - Logger* logger = code()->logger(); ErrorHandler* prev = errorHandler(); PostponedErrorHandler postponed; @@ -619,8 +596,9 @@ Error BaseBuilder::runPasses() { for (Pass* pass : _passes) { _passZone.reset(); - err = pass->run(&_passZone, logger); - if (err) break; + err = pass->run(&_passZone, _logger); + if (err) + break; } _passZone.reset(); setErrorHandler(prev); @@ -635,104 +613,21 @@ Error BaseBuilder::runPasses() { // [asmjit::BaseBuilder - Emit] // ============================================================================ -Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { - uint32_t opCount = 4; - - if (o3.isNone()) { - opCount = 3; - if (o2.isNone()) { - opCount = 2; - if (o1.isNone()) { - opCount = 1; - if (o0.isNone()) - opCount = 0; - } - } - } +Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt); + uint32_t options = instOptions() | forcedInstOptions(); - uint32_t options = instOptions() | globalInstOptions(); if (options & BaseInst::kOptionReserved) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); #ifndef ASMJIT_NO_VALIDATION // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { - Operand_ opArray[4]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount); - if (ASMJIT_UNLIKELY(err)) { - resetInstOptions(); - resetExtraReg(); - resetInlineComment(); - return reportError(err); - } - } -#endif - - // Clear options that should never be part of `InstNode`. - options &= ~BaseInst::kOptionReserved; - } - - uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= 4); - - InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); - const char* comment = inlineComment(); - - resetInstOptions(); - resetInlineComment(); - - if (ASMJIT_UNLIKELY(!node)) { - resetExtraReg(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } - - node = new(node) InstNode(this, instId, options, opCount, opCapacity); - node->setExtraReg(extraReg()); - node->setOp(0, o0); - node->setOp(1, o1); - node->setOp(2, o2); - node->setOp(3, o3); - node->resetOps(4, opCapacity); - - if (comment) - node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); - - addNode(node); - resetExtraReg(); - return kErrorOk; -} - -Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { - uint32_t opCount = Globals::kMaxOpCount; - if (o5.isNone()) { - opCount = 5; - if (o4.isNone()) - return _emit(instId, o0, o1, o2, o3); - } - - uint32_t options = instOptions() | globalInstOptions(); - if (ASMJIT_UNLIKELY(options & BaseInst::kOptionReserved)) { - if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); - -#ifndef ASMJIT_NO_VALIDATION - // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { + if (hasValidationOption(kValidationOptionIntermediate)) { Operand_ opArray[Globals::kMaxOpCount]; - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - opArray[4].copyFrom(o4); - opArray[5].copyFrom(o5); - - Error err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, opCount); + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Error err = InstAPI::validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount); if (ASMJIT_UNLIKELY(err)) { resetInstOptions(); resetExtraReg(); @@ -747,7 +642,7 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1 } uint32_t opCapacity = InstNode::capacityOfOpCount(opCount); - ASMJIT_ASSERT(opCapacity >= opCount); + ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity); InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity)); const char* comment = inlineComment(); @@ -765,11 +660,9 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1 node->setOp(0, o0); node->setOp(1, o1); node->setOp(2, o2); - node->setOp(3, o3); - node->setOp(4, o4); - - if (opCapacity > 5) - node->setOp(5, o5); + for (uint32_t i = 3; i < opCount; i++) + node->setOp(i, opExt[i - 3]); + node->resetOpRange(opCount, opCapacity); if (comment) node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); @@ -787,9 +680,8 @@ Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - AlignNode* node = newAlignNode(alignMode, alignment); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + AlignNode* node; + ASMJIT_PROPAGATE(_newAlignNode(&node, alignMode, alignment)); addNode(node); return kErrorOk; @@ -799,57 +691,71 @@ Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) { // [asmjit::BaseBuilder - Embed] // ============================================================================ -Error BaseBuilder::embed(const void* data, uint32_t dataSize) { +Error BaseBuilder::embed(const void* data, size_t dataSize) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedDataNode* node = newEmbedDataNode(data, dataSize); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, data, dataSize)); addNode(node); return kErrorOk; } -Error BaseBuilder::embedLabel(const Label& label) { +Error BaseBuilder::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t itemRepeat) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedLabelNode* node = newNodeT<EmbedLabelNode>(label.id()); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat)); addNode(node); return kErrorOk; } -Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) { +Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - EmbedLabelDeltaNode* node = newNodeT<EmbedLabelDeltaNode>(label.id(), base.id(), dataSize); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + if (!isLabelValid(label)) + return reportError(DebugUtils::errored(kErrorInvalidLabel)); + ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); + ASMJIT_PROPAGATE(bind(label)); + + EmbedDataNode* node; + ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, nullptr, pool.size())); + + pool.fill(node->data()); addNode(node); return kErrorOk; } -Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) { +Error BaseBuilder::embedLabel(const Label& label) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - if (!isLabelValid(label)) - return reportError(DebugUtils::errored(kErrorInvalidLabel)); - ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment()))); - ASMJIT_PROPAGATE(bind(label)); + EmbedLabelNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedLabelNode>(&node, label.id())); - EmbedDataNode* node = newEmbedDataNode(nullptr, uint32_t(pool.size())); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + addNode(node); + return kErrorOk; +} + +Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) { + if (ASMJIT_UNLIKELY(!_code)) + return DebugUtils::errored(kErrorNotInitialized); + + // If dataSize is zero it means that the size is the same as target register + // width, however, if it's provided we really want to validate whether it's + // within the possible range. + if (dataSize && (!Support::isPowerOf2(dataSize) || dataSize > 8)) + return reportError(DebugUtils::errored(kErrorInvalidArgument)); + + EmbedLabelDeltaNode* node; + ASMJIT_PROPAGATE(_newNodeT<EmbedLabelDeltaNode>(&node, label.id(), base.id(), uint32_t(dataSize))); - pool.fill(node->data()); addNode(node); return kErrorOk; } @@ -862,9 +768,8 @@ Error BaseBuilder::comment(const char* data, size_t size) { if (ASMJIT_UNLIKELY(!_code)) return DebugUtils::errored(kErrorNotInitialized); - CommentNode* node = newCommentNode(data, size); - if (ASMJIT_UNLIKELY(!node)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); + CommentNode* node; + ASMJIT_PROPAGATE(_newCommentNode(&node, data, size)); addNode(node); return kErrorOk; @@ -878,12 +783,38 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { Error err = kErrorOk; BaseNode* node_ = _firstNode; + Operand_ opArray[Globals::kMaxOpCount]; + do { dst->setInlineComment(node_->inlineComment()); if (node_->isInst()) { InstNode* node = node_->as<InstNode>(); - err = dst->emitInst(node->baseInst(), node->operands(), node->opCount()); + + // NOTE: Inlined to remove one additional call per instruction. + dst->setInstOptions(node->instOptions()); + dst->setExtraReg(node->extraReg()); + + const Operand_* op = node->operands(); + const Operand_* opExt = EmitterUtils::noExt; + + uint32_t opCount = node->opCount(); + if (opCount > 3) { + uint32_t i = 4; + opArray[3] = op[3]; + + while (i < opCount) { + opArray[i].copyFrom(op[i]); + i++; + } + while (i < Globals::kMaxOpCount) { + opArray[i].reset(); + i++; + } + opExt = opArray + 3; + } + + err = dst->_emit(node->id(), op[0], op[1], op[2], opExt); } else if (node_->isLabel()) { if (node_->isConstPool()) { @@ -901,7 +832,7 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { } else if (node_->isEmbedData()) { EmbedDataNode* node = node_->as<EmbedDataNode>(); - err = dst->embed(node->data(), node->size()); + err = dst->embedDataArray(node->typeId(), node->data(), node->itemCount(), node->repeatCount()); } else if (node_->isEmbedLabel()) { EmbedLabelNode* node = node_->as<EmbedLabelNode>(); @@ -928,23 +859,6 @@ Error BaseBuilder::serialize(BaseEmitter* dst) { } // ============================================================================ -// [asmjit::BaseBuilder - Logging] -// ============================================================================ - -#ifndef ASMJIT_NO_LOGGING -Error BaseBuilder::dump(String& sb, uint32_t flags) const noexcept { - BaseNode* node = _firstNode; - while (node) { - ASMJIT_PROPAGATE(Logging::formatNode(sb, flags, this, node)); - sb.appendChar('\n'); - node = node->next(); - } - - return kErrorOk; -} -#endif - -// ============================================================================ // [asmjit::BaseBuilder - Events] // ============================================================================ @@ -962,7 +876,6 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept { return err; } - _cursor = initialSection; _firstNode = initialSection; _lastNode = initialSection; @@ -972,7 +885,7 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept { } Error BaseBuilder::onDetach(CodeHolder* code) noexcept { - _passes.reset(); + BaseBuilder_deletePasses(this); _sectionNodes.reset(); _labelNodes.reset(); diff --git a/3rdparty/asmjit/src/asmjit/core/builder.h b/3rdparty/asmjit/src/asmjit/core/builder.h index c6d359995fc..ba99267dafa 100644 --- a/3rdparty/asmjit/src/asmjit/core/builder.h +++ b/3rdparty/asmjit/src/asmjit/core/builder.h @@ -30,10 +30,12 @@ #include "../core/assembler.h" #include "../core/codeholder.h" #include "../core/constpool.h" +#include "../core/formatter.h" #include "../core/inst.h" #include "../core/operand.h" #include "../core/string.h" #include "../core/support.h" +#include "../core/type.h" #include "../core/zone.h" #include "../core/zonevector.h" @@ -68,6 +70,18 @@ class JumpAnnotation; // [asmjit::BaseBuilder] // ============================================================================ +//! Builder interface. +//! +//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler +//! replacement in case pre-processing or post-processing of the generated code +//! is required. The code can be modified during or after code generation. Pre +//! or post processing can be done manually or through a \ref Pass object. \ref +//! BaseBuilder stores the emitted code as a double-linked list of nodes, which +//! allows O(1) insertion and removal during processing. +//! +//! Check out architecture specific builders for more details and examples: +//! +//! - \ref x86::Builder - X86/X64 builder implementation. class ASMJIT_VIRTAPI BaseBuilder : public BaseEmitter { public: ASMJIT_NONCOPYABLE(BaseBuilder) @@ -127,33 +141,26 @@ public: //! \remarks The pointer returned (if non-null) is owned by the Builder or //! Compiler. When the Builder/Compiler is destroyed it destroys all nodes //! it created so no manual memory management is required. - template<typename T> - inline T* newNodeT() noexcept { - return _allocator.newT<T>(this); - } - - //! \overload template<typename T, typename... Args> - inline T* newNodeT(Args&&... args) noexcept { - return _allocator.newT<T>(this, std::forward<Args>(args)...); + inline Error _newNodeT(T** out, Args&&... args) { + *out = _allocator.newT<T>(this, std::forward<Args>(args)...); + if (ASMJIT_UNLIKELY(!*out)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + return kErrorOk; } - //! Creates a new `LabelNode`. - ASMJIT_API LabelNode* newLabelNode() noexcept; - //! Creates a new `AlignNode`. - ASMJIT_API AlignNode* newAlignNode(uint32_t alignMode, uint32_t alignment) noexcept; - //! Creates a new `EmbedDataNode`. - ASMJIT_API EmbedDataNode* newEmbedDataNode(const void* data, uint32_t size) noexcept; - //! Creates a new `ConstPoolNode`. - ASMJIT_API ConstPoolNode* newConstPoolNode() noexcept; - //! Creates a new `CommentNode`. - ASMJIT_API CommentNode* newCommentNode(const char* data, size_t size) noexcept; - - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2) noexcept; - ASMJIT_API InstNode* newInstNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) noexcept; - ASMJIT_API InstNode* newInstNodeRaw(uint32_t instId, uint32_t instOptions, uint32_t opCount) noexcept; + //! Creates a new \ref InstNode. + ASMJIT_API Error _newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount); + //! Creates a new \ref LabelNode. + ASMJIT_API Error _newLabelNode(LabelNode** out); + //! Creates a new \ref AlignNode. + ASMJIT_API Error _newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment); + //! Creates a new \ref EmbedDataNode. + ASMJIT_API Error _newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1); + //! Creates a new \ref ConstPoolNode. + ASMJIT_API Error _newConstPoolNode(ConstPoolNode** out); + //! Creates a new \ref CommentNode. + ASMJIT_API Error _newCommentNode(CommentNode** out, const char* data, size_t size); //! Adds `node` after the current and sets the current node to the given `node`. ASMJIT_API BaseNode* addNode(BaseNode* node) noexcept; @@ -173,7 +180,9 @@ public: //! added they are always added after the cursor and the cursor is changed //! to be that newly added node. Use `setCursor()` to change where new nodes //! are inserted. - inline BaseNode* cursor() const noexcept { return _cursor; } + inline BaseNode* cursor() const noexcept { + return _cursor; + } //! Sets the current node to `node` and return the previous one. ASMJIT_API BaseNode* setCursor(BaseNode* node) noexcept; @@ -182,7 +191,9 @@ public: //! //! Only use this function if you are concerned about performance and want //! this inlined (for example if you set the cursor in a loop, etc...). - inline void _setCursor(BaseNode* node) noexcept { _cursor = node; } + inline void _setCursor(BaseNode* node) noexcept { + _cursor = node; + } //! \} @@ -193,7 +204,9 @@ public: //! //! \note If a section of some id is not associated with the Builder/Compiler //! it would be null, so always check for nulls if you iterate over the vector. - inline const ZoneVector<SectionNode*>& sectionNodes() const noexcept { return _sectionNodes; } + inline const ZoneVector<SectionNode*>& sectionNodes() const noexcept { + return _sectionNodes; + } //! Tests whether the `SectionNode` of the given `sectionId` was registered. inline bool hasRegisteredSectionNode(uint32_t sectionId) const noexcept { @@ -205,7 +218,7 @@ public: //! \remarks This function will either get the existing `SectionNode` or create //! it in case it wasn't created before. You can check whether a section has a //! registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`. - ASMJIT_API Error sectionNodeOf(SectionNode** pOut, uint32_t sectionId) noexcept; + ASMJIT_API Error sectionNodeOf(SectionNode** out, uint32_t sectionId); ASMJIT_API Error section(Section* section) override; @@ -221,7 +234,7 @@ public: //! \name Label Management //! \{ - //! Returns a vector of LabelNode nodes. + //! Returns a vector of \ref LabelNode nodes. //! //! \note If a label of some id is not associated with the Builder/Compiler //! it would be null, so always check for nulls if you iterate over the vector. @@ -237,24 +250,24 @@ public: return hasRegisteredLabelNode(label.id()); } - //! Gets or creates a `LabelNode` that matches the given `labelId`. + //! Gets or creates a \ref LabelNode that matches the given `labelId`. //! //! \remarks This function will either get the existing `LabelNode` or create //! it in case it wasn't created before. You can check whether a label has a - //! registered `LabelNode` by using `BaseBuilder::hasRegisteredLabelNode()`. - ASMJIT_API Error labelNodeOf(LabelNode** pOut, uint32_t labelId) noexcept; + //! registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode(). + ASMJIT_API Error labelNodeOf(LabelNode** out, uint32_t labelId); //! \overload - inline Error labelNodeOf(LabelNode** pOut, const Label& label) noexcept { - return labelNodeOf(pOut, label.id()); + inline Error labelNodeOf(LabelNode** out, const Label& label) { + return labelNodeOf(out, label.id()); } - //! Registers this label node [Internal]. + //! Registers this \ref LabelNode (internal). //! //! This function is used internally to register a newly created `LabelNode` - //! with this instance of Builder/Compiler. Use `labelNodeOf()` functions to - //! get back `LabelNode` from a label or its identifier. - ASMJIT_API Error registerLabelNode(LabelNode* node) noexcept; + //! with this instance of Builder/Compiler. Use \ref labelNodeOf() functions + //! to get back \ref LabelNode from a label or its identifier. + ASMJIT_API Error registerLabelNode(LabelNode* node); ASMJIT_API Label newLabel() override; ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override; @@ -284,12 +297,14 @@ public: inline T* newPassT(Args&&... args) noexcept { return _codeZone.newT<T>(std::forward<Args>(args)...); } template<typename T> - inline Error addPassT() noexcept { return addPass(newPassT<T>()); } + inline Error addPassT() { return addPass(newPassT<T>()); } template<typename T, typename... Args> - inline Error addPassT(Args&&... args) noexcept { return addPass(newPassT<T, Args...>(std::forward<Args>(args)...)); } + inline Error addPassT(Args&&... args) { return addPass(newPassT<T, Args...>(std::forward<Args>(args)...)); } //! Returns `Pass` by name. + //! + //! If the pass having the given `name` doesn't exist `nullptr` is returned. ASMJIT_API Pass* passByName(const char* name) const noexcept; //! Adds `pass` to the list of passes. ASMJIT_API Error addPass(Pass* pass) noexcept; @@ -304,8 +319,7 @@ public: //! \name Emit //! \{ - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override; + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override; //! \} @@ -319,11 +333,13 @@ public: //! \name Embed //! \{ - ASMJIT_API Error embed(const void* data, uint32_t dataSize) override; - ASMJIT_API Error embedLabel(const Label& label) override; - ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) override; + ASMJIT_API Error embed(const void* data, size_t dataSize) override; + ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t count, size_t repeat = 1) override; ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override; + ASMJIT_API Error embedLabel(const Label& label) override; + ASMJIT_API Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) override; + //! \} //! \name Comment @@ -345,15 +361,6 @@ public: //! \} - //! \name Logging - //! \{ - -#ifndef ASMJIT_NO_LOGGING - ASMJIT_API Error dump(String& sb, uint32_t flags = 0) const noexcept; -#endif - - //! \} - //! \name Events //! \{ @@ -361,6 +368,15 @@ public: ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; //! \} + +#ifndef ASMJIT_NO_DEPRECATED +#ifndef ASMJIT_NO_LOGGING + ASMJIT_DEPRECATED("Use Formatter::formatNodeList(sb, formatFlags, builder)") + inline Error dump(String& sb, uint32_t formatFlags = 0) const noexcept { + return Formatter::formatNodeList(sb, formatFlags, this); + } +#endif // !ASMJIT_NO_LOGGING +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -369,11 +385,11 @@ public: //! Base node. //! -//! Every node represents a building-block used by `BaseBuilder`. It can be -//! instruction, data, label, comment, directive, or any other high-level +//! Every node represents a building-block used by \ref BaseBuilder. It can +//! be instruction, data, label, comment, directive, or any other high-level //! representation that can be transformed to the building blocks mentioned. -//! Every class that inherits `BaseBuilder` can define its own nodes that it -//! can lower to basic nodes. +//! Every class that inherits \ref BaseBuilder can define its own high-level +//! nodes that can be later lowered to basic nodes like instructions. class BaseNode { public: ASMJIT_NONCOPYABLE(BaseNode) @@ -385,7 +401,7 @@ public: //! Next node. BaseNode* _next; }; - //! Links (previous and next nodes). + //! Links (an alternative view to previous and next nodes). BaseNode* _links[2]; }; @@ -401,6 +417,7 @@ public: uint8_t _reserved1; }; + //! Data used by \ref InstNode. struct InstData { //! Node type, see \ref NodeType. uint8_t _nodeType; @@ -412,6 +429,19 @@ public: uint8_t _opCapacity; }; + //! Data used by \ref EmbedDataNode. + struct EmbedData { + //! Node type, see \ref NodeType. + uint8_t _nodeType; + //! Node flags, see \ref Flags. + uint8_t _nodeFlags; + //! Type id, see \ref Type::Id. + uint8_t _typeId; + //! Size of `_typeId`. + uint8_t _typeSize; + }; + + //! Data used by \ref SentinelNode. struct SentinelData { //! Node type, see \ref NodeType. uint8_t _nodeType; @@ -423,9 +453,15 @@ public: uint8_t _reserved1; }; + //! Data that can have different meaning dependning on \ref NodeType. union { + //! Data useful by any node type. AnyData _any; + //! Data specific to \ref InstNode. InstData _inst; + //! Data specific to \ref EmbedDataNode. + EmbedData _embed; + //! Data specific to \ref SentinelNode. SentinelData _sentinel; }; @@ -434,7 +470,9 @@ public: //! Value reserved for AsmJit users never touched by AsmJit itself. union { + //! User data as 64-bit integer. uint64_t _userDataU64; + //! User data as pointer. void* _userDataPtr; }; @@ -451,54 +489,66 @@ public: // [BaseBuilder] - //! Node is `InstNode` or `InstExNode`. + //! Node is \ref InstNode or \ref InstExNode. kNodeInst = 1, - //! Node is `SectionNode`. + //! Node is \ref SectionNode. kNodeSection = 2, - //! Node is `LabelNode`. + //! Node is \ref LabelNode. kNodeLabel = 3, - //! Node is `AlignNode`. + //! Node is \ref AlignNode. kNodeAlign = 4, - //! Node is `EmbedDataNode`. + //! Node is \ref EmbedDataNode. kNodeEmbedData = 5, - //! Node is `EmbedLabelNode`. + //! Node is \ref EmbedLabelNode. kNodeEmbedLabel = 6, - //! Node is `EmbedLabelDeltaNode`. + //! Node is \ref EmbedLabelDeltaNode. kNodeEmbedLabelDelta = 7, - //! Node is `ConstPoolNode`. + //! Node is \ref ConstPoolNode. kNodeConstPool = 8, - //! Node is `CommentNode`. + //! Node is \ref CommentNode. kNodeComment = 9, - //! Node is `SentinelNode`. + //! Node is \ref SentinelNode. kNodeSentinel = 10, // [BaseCompiler] - //! Node is `JumpNode` (acts as InstNode). + //! Node is \ref JumpNode (acts as InstNode). kNodeJump = 15, - //! Node is `FuncNode` (acts as LabelNode). + //! Node is \ref FuncNode (acts as LabelNode). kNodeFunc = 16, - //! Node is `FuncRetNode` (acts as InstNode). + //! Node is \ref FuncRetNode (acts as InstNode). kNodeFuncRet = 17, - //! Node is `FuncCallNode` (acts as InstNode). - kNodeFuncCall = 18, + //! Node is \ref InvokeNode (acts as InstNode). + kNodeInvoke = 18, // [UserDefined] //! First id of a user-defined node. - kNodeUser = 32 + kNodeUser = 32, + +#ifndef ASMJIT_NO_DEPRECATED + kNodeFuncCall = kNodeInvoke +#endif // !ASMJIT_NO_DEPRECATED }; //! Node flags, specify what the node is and/or does. enum Flags : uint32_t { - kFlagIsCode = 0x01u, //!< Node is code that can be executed (instruction, label, align, etc...). - kFlagIsData = 0x02u, //!< Node is data that cannot be executed (data, const-pool, etc...). - kFlagIsInformative = 0x04u, //!< Node is informative, can be removed and ignored. - kFlagIsRemovable = 0x08u, //!< Node can be safely removed if unreachable. - kFlagHasNoEffect = 0x10u, //!< Node does nothing when executed (label, align, explicit nop). - kFlagActsAsInst = 0x20u, //!< Node is an instruction or acts as it. - kFlagActsAsLabel = 0x40u, //!< Node is a label or acts as it. - kFlagIsActive = 0x80u //!< Node is active (part of the code). + //! Node is code that can be executed (instruction, label, align, etc...). + kFlagIsCode = 0x01u, + //! Node is data that cannot be executed (data, const-pool, etc...). + kFlagIsData = 0x02u, + //! Node is informative, can be removed and ignored. + kFlagIsInformative = 0x04u, + //! Node can be safely removed if unreachable. + kFlagIsRemovable = 0x08u, + //! Node does nothing when executed (label, align, explicit nop). + kFlagHasNoEffect = 0x10u, + //! Node is an instruction or acts as it. + kFlagActsAsInst = 0x20u, + //! Node is a label or acts as it. + kFlagActsAsLabel = 0x40u, + //! Node is active (part of the code). + kFlagIsActive = 0x80u }; //! \name Construction & Destruction @@ -572,8 +622,13 @@ public: inline bool isFunc() const noexcept { return type() == kNodeFunc; } //! Tests whether this node is `FuncRetNode`. inline bool isFuncRet() const noexcept { return type() == kNodeFuncRet; } - //! Tests whether this node is `FuncCallNode`. - inline bool isFuncCall() const noexcept { return type() == kNodeFuncCall; } + //! Tests whether this node is `InvokeNode`. + inline bool isInvoke() const noexcept { return type() == kNodeInvoke; } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use isInvoke") + inline bool isFuncCall() const noexcept { return isInvoke(); } +#endif // !ASMJIT_NO_DEPRECATED //! Returns the node flags, see \ref Flags. inline uint32_t flags() const noexcept { return _any._nodeFlags; } @@ -697,12 +752,13 @@ public: _inst._opCount = uint8_t(opCount); } + //! \cond INTERNAL //! Reset all built-in operands, including `extraReg`. inline void _resetOps() noexcept { _baseInst.resetExtraReg(); - for (uint32_t i = 0, count = opCapacity(); i < count; i++) - _opArray[i].reset(); + resetOpRange(0, opCapacity()); } + //! \endcond //! \} @@ -739,12 +795,12 @@ public: //! Resets extra register operand. inline void resetExtraReg() noexcept { _baseInst.resetExtraReg(); } - //! Returns operands count. + //! Returns operand count. inline uint32_t opCount() const noexcept { return _inst._opCount; } - //! Returns operands capacity. + //! Returns operand capacity. inline uint32_t opCapacity() const noexcept { return _inst._opCapacity; } - //! Sets operands count. + //! Sets operand count. inline void setOpCount(uint32_t opCount) noexcept { _inst._opCount = uint8_t(opCount); } //! Returns operands array. @@ -752,27 +808,32 @@ public: //! Returns operands array (const). inline const Operand* operands() const noexcept { return (const Operand*)_opArray; } - inline Operand& opType(uint32_t index) noexcept { + //! Returns operand at the given `index`. + inline Operand& op(uint32_t index) noexcept { ASMJIT_ASSERT(index < opCapacity()); return _opArray[index].as<Operand>(); } - inline const Operand& opType(uint32_t index) const noexcept { + //! Returns operand at the given `index` (const). + inline const Operand& op(uint32_t index) const noexcept { ASMJIT_ASSERT(index < opCapacity()); return _opArray[index].as<Operand>(); } + //! Sets operand at the given `index` to `op`. inline void setOp(uint32_t index, const Operand_& op) noexcept { ASMJIT_ASSERT(index < opCapacity()); _opArray[index].copyFrom(op); } + //! Resets operand at the given `index` to none. inline void resetOp(uint32_t index) noexcept { ASMJIT_ASSERT(index < opCapacity()); _opArray[index].reset(); } - inline void resetOps(uint32_t start, uint32_t end) noexcept { + //! Resets operands at `[start, end)` range. + inline void resetOpRange(uint32_t start, uint32_t end) noexcept { for (uint32_t i = start; i < end; i++) _opArray[i].reset(); } @@ -816,6 +877,7 @@ public: //! \name Rewriting //! \{ + //! \cond INTERNAL inline uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; } inline const uint32_t* _getRewriteArray() const noexcept { return &_baseInst._extraReg._id; } @@ -833,12 +895,14 @@ public: uint32_t* array = _getRewriteArray(); array[index] = id; } + //! \endcond //! \} //! \name Static Functions //! \{ + //! \cond INTERNAL static inline uint32_t capacityOfOpCount(uint32_t opCount) noexcept { return opCount <= kBaseOpCapacity ? kBaseOpCapacity : Globals::kMaxOpCount; } @@ -847,6 +911,7 @@ public: size_t base = sizeof(InstNode) - kBaseOpCapacity * sizeof(Operand); return base + opCapacity * sizeof(Operand); } + //! \endcond //! \} }; @@ -855,7 +920,7 @@ public: // [asmjit::InstExNode] // ============================================================================ -//! Instruction node with maximum number of operands.. +//! Instruction node with maximum number of operands. //! //! This node is created automatically by Builder/Compiler in case that the //! required number of operands exceeds the default capacity of `InstNode`. @@ -925,27 +990,33 @@ class LabelNode : public BaseNode { public: ASMJIT_NONCOPYABLE(LabelNode) - uint32_t _id; + //! Label identifier. + uint32_t _labelId; //! \name Construction & Destruction //! \{ //! Creates a new `LabelNode` instance. - inline LabelNode(BaseBuilder* cb, uint32_t id = 0) noexcept + inline LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept : BaseNode(cb, kNodeLabel, kFlagHasNoEffect | kFlagActsAsLabel), - _id(id) {} + _labelId(labelId) {} //! \} //! \name Accessors //! \{ + //! Returns \ref Label representation of the \ref LabelNode. + inline Label label() const noexcept { return Label(_labelId); } //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } + inline uint32_t labelId() const noexcept { return _labelId; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1005,37 +1076,28 @@ public: ASMJIT_NONCOPYABLE(EmbedDataNode) enum : uint32_t { - kInlineBufferSize = uint32_t(64 - sizeof(BaseNode) - 4) + kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2) }; + size_t _itemCount; + size_t _repeatCount; + union { - struct { - //! Embedded data buffer. - uint8_t _buf[kInlineBufferSize]; - //! Size of the data. - uint32_t _size; - }; - struct { - //! Pointer to external data. - uint8_t* _externalPtr; - }; + uint8_t* _externalData; + uint8_t _inlineData[kInlineBufferSize]; }; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedDataNode` instance. - inline EmbedDataNode(BaseBuilder* cb, void* data, uint32_t size) noexcept - : BaseNode(cb, kNodeEmbedData, kFlagIsData) { - - if (size <= kInlineBufferSize) { - if (data) - memcpy(_buf, data, size); - } - else { - _externalPtr = static_cast<uint8_t*>(data); - } - _size = size; + inline EmbedDataNode(BaseBuilder* cb) noexcept + : BaseNode(cb, kNodeEmbedData, kFlagIsData), + _itemCount(0), + _repeatCount(0) { + _embed._typeId = uint8_t(Type::kIdU8), + _embed._typeSize = uint8_t(1); + memset(_inlineData, 0, kInlineBufferSize); } //! \} @@ -1043,10 +1105,32 @@ public: //! \name Accessors //! \{ - //! Returns pointer to the data. - inline uint8_t* data() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_buf) : _externalPtr; } - //! Returns size of the data. - inline uint32_t size() const noexcept { return _size; } + //! Returns \ref Type::Id of the data. + inline uint32_t typeId() const noexcept { return _embed._typeId; } + //! Returns the size of a single data element. + inline uint32_t typeSize() const noexcept { return _embed._typeSize; } + + //! Returns a pointer to the data casted to `uint8_t`. + inline uint8_t* data() const noexcept { + return dataSize() <= kInlineBufferSize ? const_cast<uint8_t*>(_inlineData) : _externalData; + } + + //! Returns a pointer to the data casted to `T`. + template<typename T> + inline T* dataAs() const noexcept { return reinterpret_cast<T*>(data()); } + + //! Returns the number of (typed) items in the array. + inline size_t itemCount() const noexcept { return _itemCount; } + + //! Returns how many times the data is repeated (default 1). + //! + //! Repeated data is useful when defining constants for SIMD, for example. + inline size_t repeatCount() const noexcept { return _repeatCount; } + + //! Returns the size of the data, not considering the number of times it repeats. + //! + //! \note The returned value is the same as `typeSize() * itemCount()`. + inline size_t dataSize() const noexcept { return typeSize() * _itemCount; } //! \} }; @@ -1060,32 +1144,37 @@ class EmbedLabelNode : public BaseNode { public: ASMJIT_NONCOPYABLE(EmbedLabelNode) - uint32_t _id; + uint32_t _labelId; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedLabelNode` instance. - inline EmbedLabelNode(BaseBuilder* cb, uint32_t id = 0) noexcept + inline EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept : BaseNode(cb, kNodeEmbedLabel, kFlagIsData), - _id(id) {} + _labelId(labelId) {} //! \} //! \name Accessors //! \{ + //! Returns the label to embed as \ref Label operand. + inline Label label() const noexcept { return Label(_labelId); } //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Sets the label id (use with caution, improper use can break a lot of things). - inline void setId(uint32_t id) noexcept { _id = id; } + inline uint32_t labelId() const noexcept { return _labelId; } - //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } //! Sets the label id from `label` operand. - inline void setLabel(const Label& label) noexcept { setId(label.id()); } + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id (use with caution, improper use can break a lot of things). + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1097,18 +1186,18 @@ class EmbedLabelDeltaNode : public BaseNode { public: ASMJIT_NONCOPYABLE(EmbedLabelDeltaNode) - uint32_t _id; - uint32_t _baseId; + uint32_t _labelId; + uint32_t _baseLabelId; uint32_t _dataSize; //! \name Construction & Destruction //! \{ //! Creates a new `EmbedLabelDeltaNode` instance. - inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t id = 0, uint32_t baseId = 0, uint32_t dataSize = 0) noexcept + inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept : BaseNode(cb, kNodeEmbedLabelDelta, kFlagIsData), - _id(id), - _baseId(baseId), + _labelId(labelId), + _baseLabelId(baseLabelId), _dataSize(dataSize) {} //! \} @@ -1116,28 +1205,46 @@ public: //! \name Accessors //! \{ - //! Returns the id of the label. - inline uint32_t id() const noexcept { return _id; } - //! Sets the label id. - inline void setId(uint32_t id) noexcept { _id = id; } //! Returns the label as `Label` operand. - inline Label label() const noexcept { return Label(_id); } + inline Label label() const noexcept { return Label(_labelId); } + //! Returns the id of the label. + inline uint32_t labelId() const noexcept { return _labelId; } + //! Sets the label id from `label` operand. - inline void setLabel(const Label& label) noexcept { setId(label.id()); } + inline void setLabel(const Label& label) noexcept { setLabelId(label.id()); } + //! Sets the label id. + inline void setLabelId(uint32_t labelId) noexcept { _labelId = labelId; } - //! Returns the id of the base label. - inline uint32_t baseId() const noexcept { return _baseId; } - //! Sets the base label id. - inline void setBaseId(uint32_t baseId) noexcept { _baseId = baseId; } //! Returns the base label as `Label` operand. - inline Label baseLabel() const noexcept { return Label(_baseId); } + inline Label baseLabel() const noexcept { return Label(_baseLabelId); } + //! Returns the id of the base label. + inline uint32_t baseLabelId() const noexcept { return _baseLabelId; } + //! Sets the base label id from `label` operand. - inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseId(baseLabel.id()); } + inline void setBaseLabel(const Label& baseLabel) noexcept { setBaseLabelId(baseLabel.id()); } + //! Sets the base label id. + inline void setBaseLabelId(uint32_t baseLabelId) noexcept { _baseLabelId = baseLabelId; } + //! Returns the size of the embedded label address. inline uint32_t dataSize() const noexcept { return _dataSize; } + //! Sets the size of the embedded label address. inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use labelId() instead") + inline uint32_t id() const noexcept { return labelId(); } + + ASMJIT_DEPRECATED("Use setLabelId() instead") + inline void setId(uint32_t id) noexcept { setLabelId(id); } + + ASMJIT_DEPRECATED("Use baseLabelId() instead") + inline uint32_t baseId() const noexcept { return baseLabelId(); } + + ASMJIT_DEPRECATED("Use setBaseLabelId() instead") + inline void setBaseId(uint32_t id) noexcept { setBaseLabelId(id); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -1229,7 +1336,9 @@ public: //! Type of the sentinel (purery informative purpose). enum SentinelType : uint32_t { + //! Type of the sentinel is not known. kSentinelUnknown = 0u, + //! This is a sentinel used at the end of \ref FuncNode. kSentinelFuncEnd = 1u }; @@ -1248,8 +1357,15 @@ public: //! \name Accessors //! \{ - inline uint32_t sentinelType() const noexcept { return _sentinel._sentinelType; } - inline void setSentinelType(uint32_t type) noexcept { _sentinel._sentinelType = uint8_t(type); } + //! Returns the type of the sentinel. + inline uint32_t sentinelType() const noexcept { + return _sentinel._sentinelType; + } + + //! Sets the type of the sentinel. + inline void setSentinelType(uint32_t type) noexcept { + _sentinel._sentinelType = uint8_t(type); + } //! \} }; @@ -1280,7 +1396,9 @@ public: //! \name Accessors //! \{ + //! Returns \ref BaseBuilder associated with the pass. inline const BaseBuilder* cb() const noexcept { return _cb; } + //! Returns the name of the pass. inline const char* name() const noexcept { return _name; } //! \} @@ -1292,7 +1410,7 @@ public: //! //! This is the only function that is called by the `BaseBuilder` to process //! the code. It passes `zone`, which will be reset after the `run()` finishes. - virtual Error run(Zone* zone, Logger* logger) noexcept = 0; + virtual Error run(Zone* zone, Logger* logger) = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/callconv.cpp b/3rdparty/asmjit/src/asmjit/core/callconv.cpp index 5d915d0e38d..722dbcdb238 100644 --- a/3rdparty/asmjit/src/asmjit/core/callconv.cpp +++ b/3rdparty/asmjit/src/asmjit/core/callconv.cpp @@ -40,17 +40,17 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::CallConv - Init / Reset] // ============================================================================ -ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId) noexcept { +ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId, const Environment& environment) noexcept { reset(); #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) - return x86::CallConvInternal::init(*this, ccId); + if (environment.isFamilyX86()) + return x86::CallConvInternal::init(*this, ccId, environment); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) - return arm::CallConvInternal::init(*this, ccId); + if (environment.isFamilyARM()) + return arm::CallConvInternal::init(*this, ccIdv, environment); #endif return DebugUtils::errored(kErrorInvalidArgument); diff --git a/3rdparty/asmjit/src/asmjit/core/callconv.h b/3rdparty/asmjit/src/asmjit/core/callconv.h index f3dc385dfec..6e75540c545 100644 --- a/3rdparty/asmjit/src/asmjit/core/callconv.h +++ b/3rdparty/asmjit/src/asmjit/core/callconv.h @@ -30,7 +30,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_func +//! \addtogroup asmjit_function //! \{ // ============================================================================ @@ -46,8 +46,8 @@ ASMJIT_BEGIN_NAMESPACE struct CallConv { //! Calling convention id, see `Id`. uint8_t _id; - //! Architecture id (see `ArchInfo::Id`). - uint8_t _archId; + //! Architecture identifier, see \ref Environment::Arch. + uint8_t _arch; //! Register assignment strategy. uint8_t _strategy; //! Flags. @@ -78,179 +78,117 @@ struct CallConv { uint32_t packed[(kMaxRegArgsPerGroup + 3) / 4]; }; - //! Passed registers' order, per group. + //! Passed registers' order, per register group. RegOrder _passedOrder[BaseReg::kGroupVirt]; //! Calling convention id. + //! + //! Calling conventions can be divided into the following groups: + //! + //! - Universal - calling conventions are applicable to any target. They + //! will be converted to a target dependent calling convention at runtime + //! by \ref init(). The purpose of these conventions is to make using + //! functions less target dependent and closer to how they are declared + //! in C and C++. + //! + //! - Target specific - calling conventions that are used by a particular + //! architecture and ABI. For example Windows 64-bit calling convention + //! and AMD64 SystemV calling convention. enum Id : uint32_t { //! None or invalid (can't be used). kIdNone = 0, // ------------------------------------------------------------------------ - // [Universal] + // [Universal Calling Conventions] // ------------------------------------------------------------------------ - // TODO: To make this possible we need to know target ARCH and ABI. - - /* - - // Universal calling conventions are applicable to any target and are - // converted to target dependent conventions at runtime. The purpose of - // these conventions is to make using functions less target dependent. - + //! Standard function call or explicit `__cdecl` where it can be specified. + //! + //! This is a universal convention, which is used to initialize specific + //! calling connventions based on architecture, platform, and its ABI. kIdCDecl = 1, + + //! `__stdcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention \ref kIdCDecl + //! will be used instead. kIdStdCall = 2, + + //! `__fastcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86. If used + //! on environment that doesn't support this calling convention \ref kIdCDecl + //! will be used instead. kIdFastCall = 3, + //! `__vectorcall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit and 64-bit + //! X86 architecture on Windows platform. If used on environment that doesn't + //! support this calling convention \ref kIdCDecl will be used instead. + kIdVectorCall = 4, + + //! `__thiscall` on targets that support this calling convention. + //! + //! \note This calling convention is only supported on 32-bit X86 Windows + //! platform. If used on environment that doesn't support this calling + //! convention \ref kIdCDecl will be used instead. + kIdThisCall = 5, + + //! `__attribute__((regparm(1)))` convention (GCC and Clang). + kIdRegParm1 = 6, + //! `__attribute__((regparm(2)))` convention (GCC and Clang). + kIdRegParm2 = 7, + //! `__attribute__((regparm(3)))` convention (GCC and Clang). + kIdRegParm3 = 8, + + //! Soft-float calling convention (ARM). + //! + //! Floating point arguments are passed via general purpose registers. + kIdSoftFloat = 9, + + //! Hard-float calling convention (ARM). + //! + //! Floating point arguments are passed via SIMD registers. + kIdHardFloat = 10, + //! AsmJit specific calling convention designed for calling functions //! inside a multimedia code that don't use many registers internally, //! but are long enough to be called and not inlined. These functions are //! usually used to calculate trigonometric functions, logarithms, etc... - kIdLightCall2 = 10, - kIdLightCall3 = 11, - kIdLightCall4 = 12, - */ - - // ------------------------------------------------------------------------ - // [X86] - // ------------------------------------------------------------------------ - - //! X86 `__cdecl` calling convention (used by C runtime and libraries). - kIdX86CDecl = 16, - //! X86 `__stdcall` calling convention (used mostly by WinAPI). - kIdX86StdCall = 17, - //! X86 `__thiscall` calling convention (MSVC/Intel). - kIdX86MsThisCall = 18, - //! X86 `__fastcall` convention (MSVC/Intel). - kIdX86MsFastCall = 19, - //! X86 `__fastcall` convention (GCC and Clang). - kIdX86GccFastCall = 20, - //! X86 `regparm(1)` convention (GCC and Clang). - kIdX86GccRegParm1 = 21, - //! X86 `regparm(2)` convention (GCC and Clang). - kIdX86GccRegParm2 = 22, - //! X86 `regparm(3)` convention (GCC and Clang). - kIdX86GccRegParm3 = 23, - - kIdX86LightCall2 = 29, - kIdX86LightCall3 = 30, - kIdX86LightCall4 = 31, - - //! X64 calling convention - WIN64-ABI. - kIdX86Win64 = 32, - //! X64 calling convention - SystemV / AMD64-ABI. - kIdX86SysV64 = 33, - - kIdX64LightCall2 = 45, - kIdX64LightCall3 = 46, - kIdX64LightCall4 = 47, - - // ------------------------------------------------------------------------ - // [ARM] - // ------------------------------------------------------------------------ - - //! Legacy calling convention, floating point arguments are passed via GP registers. - kIdArm32SoftFP = 48, - //! Modern calling convention, uses VFP registers to pass floating point arguments. - kIdArm32HardFP = 49, + kIdLightCall2 = 16, + kIdLightCall3 = 17, + kIdLightCall4 = 18, // ------------------------------------------------------------------------ - // [Internal] + // [ABI-Specific Calling Conventions] // ------------------------------------------------------------------------ - //! \cond INTERNAL - - _kIdX86Start = 16, - _kIdX86End = 31, - - _kIdX64Start = 32, - _kIdX64End = 47, - - _kIdArmStart = 48, - _kIdArmEnd = 49, - - //! \endcond + kIdX64SystemV = 32, + kIdX64Windows = 33, // ------------------------------------------------------------------------ // [Host] // ------------------------------------------------------------------------ -#if defined(ASMJIT_DOCGEN) - - //! Default calling convention based on the current C++ compiler's settings. - //! - //! \note This should be always the same as `kIdHostCDecl`, but some - //! compilers allow to override the default calling convention. Overriding - //! is not detected at the moment. - kIdHost = DETECTED_AT_COMPILE_TIME, - - //! Default CDECL calling convention based on the current C++ compiler's settings. - kIdHostCDecl = DETECTED_AT_COMPILE_TIME, - - //! Default STDCALL calling convention based on the current C++ compiler's settings. - //! - //! \note If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostStdCall = DETECTED_AT_COMPILE_TIME, - - //! Compatibility for `__fastcall` calling convention. - //! - //! \note If not defined by the host then it's the same as `kIdHostCDecl`. - kIdHostFastCall = DETECTED_AT_COMPILE_TIME - -#elif ASMJIT_ARCH_X86 == 32 - - kIdHost = kIdX86CDecl, - kIdHostCDecl = kIdX86CDecl, - kIdHostStdCall = kIdX86StdCall, - -# if defined(_MSC_VER) - kIdHostFastCall = kIdX86MsFastCall, -# elif defined(__GNUC__) - kIdHostFastCall = kIdX86GccFastCall, -# else - kIdHostFastCall = kIdHost, -# endif - - kIdHostLightCall2 = kIdX86LightCall2, - kIdHostLightCall3 = kIdX86LightCall3, - kIdHostLightCall4 = kIdX86LightCall4 - -#elif ASMJIT_ARCH_X86 == 64 - -# if defined(_WIN32) - kIdHost = kIdX86Win64, -# else - kIdHost = kIdX86SysV64, -# endif - - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost, // Doesn't exist, redirected to host. - - kIdHostLightCall2 = kIdX64LightCall2, - kIdHostLightCall3 = kIdX64LightCall3, - kIdHostLightCall4 = kIdX64LightCall4 - -#elif ASMJIT_ARCH_ARM == 32 - -# if defined(__SOFTFP__) - kIdHost = kIdArm32SoftFP, -# else - kIdHost = kIdArm32HardFP, -# endif - // These don't exist on ARM. - kIdHostCDecl = kIdHost, // Doesn't exist, redirected to host. - kIdHostStdCall = kIdHost, // Doesn't exist, redirected to host. - kIdHostFastCall = kIdHost // Doesn't exist, redirected to host. - + kIdHost = +#if ASMJIT_ARCH_ARM == 32 && defined(__SOFTFP__) + kIdSoftFloat +#elif ASMJIT_ARCH_ARM == 32 && !defined(__SOFTFP__) + kIdHardFloat #else - - kIdHost = kIdNone, - kIdHostCDecl = kIdHost, - kIdHostStdCall = kIdHost, - kIdHostFastCall = kIdHost - + kIdCDecl #endif + +#ifndef ASMJIT_NO_DEPRECATE + , kIdHostCDecl = kIdCDecl + , kIdHostStdCall = kIdStdCall + , kIdHostFastCall = kIdFastCall + , kIdHostLightCall2 = kIdLightCall2 + , kIdHostLightCall3 = kIdLightCall3 + , kIdHostLightCall4 = kIdLightCall4 +#endif // !ASMJIT_NO_DEPRECATE }; //! Strategy used to assign registers to function arguments. @@ -262,23 +200,50 @@ struct CallConv { //! as defined by WIN64 calling convention - it applies to 64-bit calling //! conventions only. enum Strategy : uint32_t { - kStrategyDefault = 0, //!< Default register assignment strategy. - kStrategyWin64 = 1 //!< WIN64 specific register assignment strategy. + //! Default register assignment strategy. + kStrategyDefault = 0, + //! Windows 64-bit ABI register assignment strategy. + kStrategyX64Windows = 1, + //! Windows 64-bit __vectorcall register assignment strategy. + kStrategyX64VectorCall = 2, + + //! Number of assignment strategies. + kStrategyCount = 3 }; //! Calling convention flags. enum Flags : uint32_t { - kFlagCalleePopsStack = 0x01, //!< Callee is responsible for cleaning up the stack. - kFlagPassFloatsByVec = 0x02, //!< Pass F32 and F64 arguments by VEC128 register. - kFlagVectorCall = 0x04, //!< This is a '__vectorcall' calling convention. - kFlagIndirectVecArgs = 0x08 //!< Pass vector arguments indirectly (as a pointer). + //! Callee is responsible for cleaning up the stack. + kFlagCalleePopsStack = 0x01u, + //! Pass vector arguments indirectly (as a pointer). + kFlagIndirectVecArgs = 0x02u, + //! Pass F32 and F64 arguments by VEC128 register. + kFlagPassFloatsByVec = 0x04u, + //! Pass MMX and vector arguments by stack if the function has variable arguments. + kFlagPassVecByStackIfVA = 0x08u, + //! MMX registers are passed and returned via GP registers. + kFlagPassMmxByGp = 0x10u, + //! MMX registers are passed and returned via XMM registers. + kFlagPassMmxByXmm = 0x20u, + //! Calling convention can be used with variable arguments. + kFlagVarArgCompatible = 0x80u }; //! \name Construction & Destruction //! \{ - ASMJIT_API Error init(uint32_t ccId) noexcept; + //! Initializes this calling convention to the given `ccId` based on the + //! `environment`. + //! + //! See \ref Id and \ref Environment for more details. + ASMJIT_API Error init(uint32_t ccId, const Environment& environment) noexcept; + //! Resets this CallConv struct into a defined state. + //! + //! It's recommended to reset the \ref CallConv struct in case you would + //! like create a custom calling convention as it prevents from using an + //! uninitialized data (CallConv doesn't have a constructor that would + //! initialize it, it's just a struct). inline void reset() noexcept { memset(this, 0, sizeof(*this)); memset(_passedOrder, 0xFF, sizeof(_passedOrder)); @@ -295,9 +260,9 @@ struct CallConv { inline void setId(uint32_t id) noexcept { _id = uint8_t(id); } //! Returns the calling function architecture id. - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } //! Sets the calling function architecture id. - inline void setArchType(uint32_t archId) noexcept { _archId = uint8_t(archId); } + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } //! Returns the strategy used to assign registers to arguments, see `Strategy`. inline uint32_t strategy() const noexcept { return _strategy; } @@ -337,11 +302,13 @@ struct CallConv { //! implement custom calling conventions that guarantee higher stack alignment. inline void setNaturalStackAlignment(uint32_t value) noexcept { _naturalStackAlignment = uint8_t(value); } + //! Returns the order of passed registers of the given `group`, see \ref BaseReg::RegGroup. inline const uint8_t* passedOrder(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _passedOrder[group].id; } + //! Returns the mask of passed registers of the given `group`, see \ref BaseReg::RegGroup. inline uint32_t passedRegs(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _passedRegs[group]; @@ -356,6 +323,7 @@ struct CallConv { _passedOrder[group].packed[3] = p3; } + //! Resets the order and mask of passed registers. inline void setPassedToNone(uint32_t group) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); @@ -363,6 +331,7 @@ struct CallConv { _passedRegs[group] = 0u; } + //! Sets the order and mask of passed registers. inline void setPassedOrder(uint32_t group, uint32_t a0, uint32_t a1 = 0xFF, uint32_t a2 = 0xFF, uint32_t a3 = 0xFF, uint32_t a4 = 0xFF, uint32_t a5 = 0xFF, uint32_t a6 = 0xFF, uint32_t a7 = 0xFF) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); @@ -383,25 +352,19 @@ struct CallConv { (a7 != 0xFF ? 1u << a7 : 0u) ; } + //! Returns preserved register mask of the given `group`, see \ref BaseReg::RegGroup. inline uint32_t preservedRegs(uint32_t group) const noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); return _preservedRegs[group]; } + //! Sets preserved register mask of the given `group`, see \ref BaseReg::RegGroup. inline void setPreservedRegs(uint32_t group, uint32_t regs) noexcept { ASMJIT_ASSERT(group < BaseReg::kGroupVirt); _preservedRegs[group] = regs; } //! \} - - //! \name Static Functions - //! \{ - - static inline bool isX86Family(uint32_t ccId) noexcept { return ccId >= _kIdX86Start && ccId <= _kIdX64End; } - static inline bool isArmFamily(uint32_t ccId) noexcept { return ccId >= _kIdArmStart && ccId <= _kIdArmEnd; } - - //! \} }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/codebuffer.h b/3rdparty/asmjit/src/asmjit/core/codebuffer.h new file mode 100644 index 00000000000..76c86b1f631 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/codebuffer.h @@ -0,0 +1,126 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED +#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::CodeBuffer] +// ============================================================================ + +//! Code or data buffer. +struct CodeBuffer { + //! The content of the buffer (data). + uint8_t* _data; + //! Number of bytes of `data` used. + size_t _size; + //! Buffer capacity (in bytes). + size_t _capacity; + //! Buffer flags. + uint32_t _flags; + + //! Code buffer flags. + enum Flags : uint32_t { + //! Buffer is external (not allocated by asmjit). + kFlagIsExternal = 0x00000001u, + //! Buffer is fixed (cannot be reallocated). + kFlagIsFixed = 0x00000002u + }; + + //! \name Overloaded Operators + //! \{ + + //! Returns a referebce to the byte at the given `index`. + inline uint8_t& operator[](size_t index) noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + //! \overload + inline const uint8_t& operator[](size_t index) const noexcept { + ASMJIT_ASSERT(index < _size); + return _data[index]; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns code buffer flags, see \ref Flags. + inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the code buffer has the given `flag` set. + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + + //! Tests whether this code buffer has a fixed size. + //! + //! Fixed size means that the code buffer is fixed and cannot grow. + inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); } + + //! Tests whether the data in this code buffer is external. + //! + //! External data can only be provided by users, it's never used by AsmJit. + inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); } + + //! Tests whether the data in this code buffer is allocated (non-null). + inline bool isAllocated() const noexcept { return _data != nullptr; } + + //! Tests whether the code buffer is empty. + inline bool empty() const noexcept { return !_size; } + + //! Returns the size of the data. + inline size_t size() const noexcept { return _size; } + //! Returns the capacity of the data. + inline size_t capacity() const noexcept { return _capacity; } + + //! Returns the pointer to the data the buffer references. + inline uint8_t* data() noexcept { return _data; } + //! \overload + inline const uint8_t* data() const noexcept { return _data; } + + //! \} + + //! \name Iterators + //! \{ + + inline uint8_t* begin() noexcept { return _data; } + inline const uint8_t* begin() const noexcept { return _data; } + + inline uint8_t* end() noexcept { return _data + _size; } + inline const uint8_t* end() const noexcept { return _data + _size; } + + //! \} +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_CODEBUFFER_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h b/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h index ee7521153a3..75ee04748f4 100644 --- a/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h +++ b/3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h @@ -25,12 +25,13 @@ #define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED #include "../core/assembler.h" +#include "../core/codebuffer.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE //! \cond INTERNAL -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/codeholder.cpp b/3rdparty/asmjit/src/asmjit/core/codeholder.cpp index 93c9a99df88..8711e382ce4 100644 --- a/3rdparty/asmjit/src/asmjit/core/codeholder.cpp +++ b/3rdparty/asmjit/src/asmjit/core/codeholder.cpp @@ -23,7 +23,7 @@ #include "../core/api-build_p.h" #include "../core/assembler.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE @@ -78,13 +78,6 @@ public: }; // ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -ErrorHandler::ErrorHandler() noexcept {} -ErrorHandler::~ErrorHandler() noexcept {} - -// ============================================================================ // [asmjit::CodeHolder - Utilities] // ============================================================================ @@ -97,8 +90,8 @@ static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noe self->detach(emitters[--i]); // Reset everything into its construction state. - self->_codeInfo.reset(); - self->_emitterOptions = 0; + self->_environment.reset(); + self->_baseAddress = Globals::kNoBaseAddress; self->_logger = nullptr; self->_errorHandler = nullptr; @@ -129,20 +122,10 @@ static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noe self->_zone.reset(resetPolicy); } -static void CodeHolder_modifyEmitterOptions(CodeHolder* self, uint32_t clear, uint32_t add) noexcept { - uint32_t oldOpt = self->_emitterOptions; - uint32_t newOpt = (oldOpt & ~clear) | add; - - if (oldOpt == newOpt) - return; - - // Modify emitter options of `CodeHolder` itself. - self->_emitterOptions = newOpt; - - // Modify emitter options of all attached emitters. +static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept { + // Notify all attached emitters about a settings update. for (BaseEmitter* emitter : self->emitters()) { - emitter->_emitterOptions = (emitter->_emitterOptions & ~clear) | add; - emitter->onUpdateGlobalInstOptions(); + emitter->onSettingsUpdated(); } } @@ -151,8 +134,8 @@ static void CodeHolder_modifyEmitterOptions(CodeHolder* self, uint32_t clear, ui // ============================================================================ CodeHolder::CodeHolder() noexcept - : _codeInfo(), - _emitterOptions(0), + : _environment(), + _baseAddress(Globals::kNoBaseAddress), _logger(nullptr), _errorHandler(nullptr), _zone(16384 - Zone::kBlockOverhead), @@ -177,7 +160,7 @@ inline void CodeHolder_setSectionDefaultName( section->_name.u32[1] = Support::bytepack32_4x8(uint8_t(c4), uint8_t(c5), uint8_t(c6), uint8_t(c7)); } -Error CodeHolder::init(const CodeInfo& info) noexcept { +Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noexcept { // Cannot reinitialize if it's locked or there is one or more emitter attached. if (isInitialized()) return DebugUtils::errored(kErrorAlreadyInitialized); @@ -185,7 +168,7 @@ Error CodeHolder::init(const CodeInfo& info) noexcept { // If we are just initializing there should be no emitters attached. ASMJIT_ASSERT(_emitters.empty()); - // Create the default section and insert it to the `_sections` array. + // Create a default section and insert it to the `_sections` array. Error err = _sections.willGrow(&_allocator); if (err == kErrorOk) { Section* section = _allocator.allocZeroedT<Section>(); @@ -204,7 +187,8 @@ Error CodeHolder::init(const CodeInfo& info) noexcept { return err; } else { - _codeInfo = info; + _environment = environment; + _baseAddress = baseAddress; return kErrorOk; } } @@ -271,34 +255,28 @@ Error CodeHolder::detach(BaseEmitter* emitter) noexcept { } // ============================================================================ -// [asmjit::CodeHolder - Emitter Options] -// ============================================================================ - -static constexpr uint32_t kEmitterOptionsFilter = ~uint32_t(BaseEmitter::kOptionLoggingEnabled); - -void CodeHolder::addEmitterOptions(uint32_t options) noexcept { - CodeHolder_modifyEmitterOptions(this, 0, options & kEmitterOptionsFilter); -} - -void CodeHolder::clearEmitterOptions(uint32_t options) noexcept { - CodeHolder_modifyEmitterOptions(this, options & kEmitterOptionsFilter, 0); -} - -// ============================================================================ -// [asmjit::CodeHolder - Logging & Error Handling] +// [asmjit::CodeHolder - Logging] // ============================================================================ void CodeHolder::setLogger(Logger* logger) noexcept { #ifndef ASMJIT_NO_LOGGING _logger = logger; - uint32_t option = !logger ? uint32_t(0) : uint32_t(BaseEmitter::kOptionLoggingEnabled); - CodeHolder_modifyEmitterOptions(this, BaseEmitter::kOptionLoggingEnabled, option); + CodeHolder_onSettingsUpdated(this); #else DebugUtils::unused(logger); #endif } // ============================================================================ +// [asmjit::CodeHolder - Error Handling] +// ============================================================================ + +void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept { + _errorHandler = errorHandler; + CodeHolder_onSettingsUpdated(this); +} + +// ============================================================================ // [asmjit::CodeHolder - Code Buffer] // ============================================================================ @@ -440,7 +418,7 @@ Section* CodeHolder::ensureAddressTableSection() noexcept { if (_addressTableSection) return _addressTableSection; - newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _codeInfo.gpSize()); + newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize()); return _addressTableSection; } @@ -458,7 +436,7 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept { return DebugUtils::errored(kErrorOutOfMemory); _addressTableEntries.insert(entry); - section->_virtualSize += _codeInfo.gpSize(); + section->_virtualSize += _environment.registerSize(); return kErrorOk; } @@ -470,20 +448,24 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept { //! Only used to lookup a label from `_namedLabels`. class LabelByName { public: - inline LabelByName(const char* key, size_t keySize, uint32_t hashCode) noexcept + inline LabelByName(const char* key, size_t keySize, uint32_t hashCode, uint32_t parentId) noexcept : _key(key), _keySize(uint32_t(keySize)), - _hashCode(hashCode) {} + _hashCode(hashCode), + _parentId(parentId) {} inline uint32_t hashCode() const noexcept { return _hashCode; } inline bool matches(const LabelEntry* entry) const noexcept { - return entry->nameSize() == _keySize && ::memcmp(entry->name(), _key, _keySize) == 0; + return entry->nameSize() == _keySize && + entry->parentId() == _parentId && + ::memcmp(entry->name(), _key, _keySize) == 0; } const char* _key; uint32_t _keySize; uint32_t _hashCode; + uint32_t _parentId; }; // Returns a hash of `name` and fixes `nameSize` if it's `SIZE_MAX`. @@ -539,7 +521,7 @@ LabelLink* CodeHolder::newLabelLink(LabelEntry* le, uint32_t sectionId, size_t o } Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept { - *entryOut = 0; + *entryOut = nullptr; uint32_t labelId = _labelEntries.size(); if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId)) @@ -561,7 +543,7 @@ Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept { } Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId) noexcept { - *entryOut = 0; + *entryOut = nullptr; uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); if (ASMJIT_UNLIKELY(nameSize == 0)) @@ -580,7 +562,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si case Label::kTypeGlobal: if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId)) - return DebugUtils::errored(kErrorNonLocalLabelCantHaveParent); + return DebugUtils::errored(kErrorNonLocalLabelCannotHaveParent); break; @@ -591,7 +573,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si // Don't allow to insert duplicates. Local labels allow duplicates that have // different id, this is already accomplished by having a different hashes // between the same label names having different parent labels. - LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode)); + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); if (ASMJIT_UNLIKELY(le)) return DebugUtils::errored(kErrorLabelAlreadyDefined); @@ -610,7 +592,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si le->_hashCode = hashCode; le->_setId(labelId); le->_type = uint8_t(type); - le->_parentId = Globals::kInvalidId; + le->_parentId = parentId; le->_offset = 0; ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize)); @@ -622,13 +604,14 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si } uint32_t CodeHolder::labelIdByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { - // TODO: Finalize - parent id is not used here? - DebugUtils::unused(parentId); - uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize); - if (ASMJIT_UNLIKELY(!nameSize)) return 0; + if (ASMJIT_UNLIKELY(!nameSize)) + return 0; + + if (parentId != Globals::kInvalidId) + hashCode ^= parentId; - LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode)); + LabelEntry* le = _namedLabels.get(LabelByName(name, nameSize, hashCode, parentId)); return le ? le->id() : uint32_t(Globals::kInvalidId); } @@ -906,7 +889,6 @@ size_t CodeHolder::codeSize() const noexcept { } } - // TODO: Not nice, maybe changing `codeSize()` to return `uint64_t` instead? if ((sizeof(uint64_t) > sizeof(size_t) && offset > SIZE_MAX) || of) return SIZE_MAX; @@ -918,8 +900,8 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { if (ASMJIT_UNLIKELY(baseAddress == Globals::kNoBaseAddress)) return DebugUtils::errored(kErrorInvalidArgument); - _codeInfo.setBaseAddress(baseAddress); - uint32_t gpSize = _codeInfo.gpSize(); + _baseAddress = baseAddress; + uint32_t addressSize = _environment.registerSize(); Section* addressTableSection = _addressTableSection; uint32_t addressTableEntryCount = 0; @@ -980,7 +962,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { case RelocEntry::kTypeAbsToRel: { value -= baseAddress + sectionOffset + sourceOffset + regionSize; - if (gpSize > 4 && !Support::isInt32(int64_t(value))) + if (addressSize > 4 && !Support::isInt32(int64_t(value))) return DebugUtils::errored(kErrorRelocOffsetOutOfRange); break; } @@ -1003,7 +985,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { if (!atEntry->hasAssignedSlot()) atEntry->_slot = addressTableEntryCount++; - size_t atEntryIndex = size_t(atEntry->slot()) * gpSize; + size_t atEntryIndex = size_t(atEntry->slot()) * addressSize; uint64_t addrSrc = sectionOffset + sourceOffset + regionSize; uint64_t addrDst = addressTableSection->offset() + uint64_t(atEntryIndex); @@ -1064,7 +1046,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { // Fixup the virtual size of the address table if it's the last section. if (_sections.last() == addressTableSection) { - size_t addressTableSize = addressTableEntryCount * gpSize; + size_t addressTableSize = addressTableEntryCount * addressSize; addressTableSection->_buffer._size = addressTableSize; addressTableSection->_virtualSize = addressTableSize; } @@ -1072,7 +1054,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept { return kErrorOk; } -Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t options) noexcept { +Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions) noexcept { if (ASMJIT_UNLIKELY(!isSectionValid(sectionId))) return DebugUtils::errored(kErrorInvalidSection); @@ -1084,7 +1066,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, memcpy(dst, section->data(), bufferSize); - if (bufferSize < dstSize && (options & kCopyWithPadding)) { + if (bufferSize < dstSize && (copyOptions & kCopyPadSectionBuffer)) { size_t paddingSize = dstSize - bufferSize; memset(static_cast<uint8_t*>(dst) + bufferSize, 0, paddingSize); } @@ -1092,7 +1074,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, return kErrorOk; } -Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) noexcept { +Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept { size_t end = 0; for (Section* section : _sections) { if (section->offset() > dstSize) @@ -1108,7 +1090,7 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) size_t paddingSize = 0; memcpy(dstTarget, section->data(), bufferSize); - if ((options & kCopyWithPadding) && bufferSize < section->virtualSize()) { + if ((copyOptions & kCopyPadSectionBuffer) && bufferSize < section->virtualSize()) { paddingSize = Support::min<size_t>(dstSize - offset, size_t(section->virtualSize())) - bufferSize; memset(dstTarget + bufferSize, 0, paddingSize); } @@ -1116,8 +1098,9 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t options) end = Support::max(end, offset + bufferSize + paddingSize); } - // TODO: `end` is not used atm, we need an option to also pad anything beyond - // the code in case that the destination was much larger (for example page-size). + if (end < dstSize && (copyOptions & kCopyPadTargetBuffer)) { + memset(static_cast<uint8_t*>(dst) + end, 0, dstSize - end); + } return kErrorOk; } diff --git a/3rdparty/asmjit/src/asmjit/core/codeholder.h b/3rdparty/asmjit/src/asmjit/core/codeholder.h index 5f6a21d6241..9b3466dbb58 100644 --- a/3rdparty/asmjit/src/asmjit/core/codeholder.h +++ b/3rdparty/asmjit/src/asmjit/core/codeholder.h @@ -25,7 +25,9 @@ #define ASMJIT_CORE_CODEHOLDER_H_INCLUDED #include "../core/arch.h" +#include "../core/codebuffer.h" #include "../core/datatypes.h" +#include "../core/errorhandler.h" #include "../core/operand.h" #include "../core/string.h" #include "../core/support.h" @@ -56,126 +58,14 @@ class Logger; //! Align mode. enum AlignMode : uint32_t { - kAlignCode = 0, //!< Align executable code. - kAlignData = 1, //!< Align non-executable code. - kAlignZero = 2, //!< Align by a sequence of zeros. - kAlignCount = 3 //!< Count of alignment modes. -}; - -// ============================================================================ -// [asmjit::ErrorHandler] -// ============================================================================ - -//! Error handler can be used to override the default behavior of error handling -//! available to all classes that inherit `BaseEmitter`. -//! -//! Override `ErrorHandler::handleError()` to implement your own error handler. -class ASMJIT_VIRTAPI ErrorHandler { -public: - ASMJIT_BASE_CLASS(ErrorHandler) - - // -------------------------------------------------------------------------- - // [Construction / Destruction] - // -------------------------------------------------------------------------- - - //! Creates a new `ErrorHandler` instance. - ASMJIT_API ErrorHandler() noexcept; - //! Destroys the `ErrorHandler` instance. - ASMJIT_API virtual ~ErrorHandler() noexcept; - - // -------------------------------------------------------------------------- - // [Handle Error] - // -------------------------------------------------------------------------- - - //! Error handler (must be reimplemented). - //! - //! Error handler is called after an error happened and before it's propagated - //! to the caller. There are multiple ways how the error handler can be used: - //! - //! 1. User-based error handling without throwing exception or using C's - //! `longjmp()`. This is for users that don't use exceptions and want - //! customized error handling. - //! - //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely - //! exception-safe, but you can throw exception from your error handler if - //! this way is the preferred way of handling errors in your project. - //! - //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts - //! `BaseEmitter` to a consistent state before calling `handleError()` - //! so `longjmp()` can be used without any issues to cancel the code - //! generation if an error occurred. There is no difference between - //! exceptions and `longjmp()` from AsmJit's perspective, however, - //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you - //! would leak memory. - virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; -}; - -// ============================================================================ -// [asmjit::CodeBuffer] -// ============================================================================ - -//! Code or data buffer. -struct CodeBuffer { - //! The content of the buffer (data). - uint8_t* _data; - //! Number of bytes of `data` used. - size_t _size; - //! Buffer capacity (in bytes). - size_t _capacity; - //! Buffer flags. - uint32_t _flags; - - enum Flags : uint32_t { - //! Buffer is external (not allocated by asmjit). - kFlagIsExternal = 0x00000001u, - //! Buffer is fixed (cannot be reallocated). - kFlagIsFixed = 0x00000002u - }; - - //! \name Overloaded Operators - //! \{ - - inline uint8_t& operator[](size_t index) noexcept { - ASMJIT_ASSERT(index < _size); - return _data[index]; - } - - inline const uint8_t& operator[](size_t index) const noexcept { - ASMJIT_ASSERT(index < _size); - return _data[index]; - } - - //! \} - - //! \name Accessors - //! \{ - - inline uint32_t flags() const noexcept { return _flags; } - inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - - inline bool isAllocated() const noexcept { return _data != nullptr; } - inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); } - inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); } - - inline uint8_t* data() noexcept { return _data; } - inline const uint8_t* data() const noexcept { return _data; } - - inline bool empty() const noexcept { return !_size; } - inline size_t size() const noexcept { return _size; } - inline size_t capacity() const noexcept { return _capacity; } - - //! \} - - //! \name Iterators - //! \{ - - inline uint8_t* begin() noexcept { return _data; } - inline const uint8_t* begin() const noexcept { return _data; } - - inline uint8_t* end() noexcept { return _data + _size; } - inline const uint8_t* end() const noexcept { return _data + _size; } - - //! \} + //! Align executable code. + kAlignCode = 0, + //! Align non-executable code. + kAlignData = 1, + //! Align by a sequence of zeros. + kAlignZero = 2, + //! Count of alignment modes. + kAlignCount = 3 }; // ============================================================================ @@ -204,31 +94,48 @@ public: //! Section flags. enum Flags : uint32_t { - kFlagExec = 0x00000001u, //!< Executable (.text sections). - kFlagConst = 0x00000002u, //!< Read-only (.text and .data sections). - kFlagZero = 0x00000004u, //!< Zero initialized by the loader (BSS). - kFlagInfo = 0x00000008u, //!< Info / comment flag. - kFlagImplicit = 0x80000000u //!< Section created implicitly and can be deleted by `Target`. + //! Executable (.text sections). + kFlagExec = 0x00000001u, + //! Read-only (.text and .data sections). + kFlagConst = 0x00000002u, + //! Zero initialized by the loader (BSS). + kFlagZero = 0x00000004u, + //! Info / comment flag. + kFlagInfo = 0x00000008u, + //! Section created implicitly and can be deleted by \ref Target. + kFlagImplicit = 0x80000000u }; //! \name Accessors //! \{ + //! Returns the section id. inline uint32_t id() const noexcept { return _id; } + //! Returns the section name, as a null terminated string. inline const char* name() const noexcept { return _name.str; } + //! Returns the section data. inline uint8_t* data() noexcept { return _buffer.data(); } + //! \overload inline const uint8_t* data() const noexcept { return _buffer.data(); } + //! Returns the section flags, see \ref Flags. inline uint32_t flags() const noexcept { return _flags; } + //! Tests whether the section has the given `flag`. inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Adds `flags` to the section flags. inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from the section flags. inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + //! Returns the minimum section alignment inline uint32_t alignment() const noexcept { return _alignment; } + //! Sets the minimum section alignment inline void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; } + //! Returns the section offset, relative to base. inline uint64_t offset() const noexcept { return _offset; } + //! Set the section offset. inline void setOffset(uint64_t offset) noexcept { _offset = offset; } //! Returns the virtual size of the section. @@ -277,46 +184,73 @@ struct LabelLink { // [asmjit::Expression] // ============================================================================ +//! Expression node that can reference constants, labels, and another expressions. struct Expression { + //! Operation type. enum OpType : uint8_t { + //! Addition. kOpAdd = 0, + //! Subtraction. kOpSub = 1, + //! Multiplication kOpMul = 2, + //! Logical left shift. kOpSll = 3, + //! Logical right shift. kOpSrl = 4, + //! Arithmetic right shift. kOpSra = 5 }; + //! Type of \ref Value. enum ValueType : uint8_t { + //! No value or invalid. kValueNone = 0, + //! Value is 64-bit unsigned integer (constant). kValueConstant = 1, + //! Value is \ref LabelEntry, which references a \ref Label. kValueLabel = 2, + //! Value is \ref Expression kValueExpression = 3 }; + //! Expression value. union Value { + //! Constant. uint64_t constant; + //! Pointer to another expression. Expression* expression; + //! Poitner to \ref LabelEntry. LabelEntry* label; }; + //! Operation type. uint8_t opType; + //! Value types of \ref value. uint8_t valueType[2]; + //! Reserved for future use, should be initialized to zero. uint8_t reserved[5]; + //! Expression left and right values. Value value[2]; + //! Resets the whole expression. + //! + //! Changes both values to \ref kValueNone. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! Sets the value type at `index` to \ref kValueConstant and its content to `constant`. inline void setValueAsConstant(size_t index, uint64_t constant) noexcept { valueType[index] = kValueConstant; value[index].constant = constant; } - inline void setValueAsLabel(size_t index, LabelEntry* label) noexcept { + //! Sets the value type at `index` to \ref kValueLabel and its content to `labelEntry`. + inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept { valueType[index] = kValueLabel; - value[index].label = label; + value[index].label = labelEntry; } + //! Sets the value type at `index` to \ref kValueExpression and its content to `expression`. inline void setValueAsExpression(size_t index, Expression* expression) noexcept { valueType[index] = kValueLabel; value[index].expression = expression; @@ -510,11 +444,14 @@ struct RelocEntry { // [asmjit::AddressTableEntry] // ============================================================================ +//! Entry in an address table. class AddressTableEntry : public ZoneTreeNodeT<AddressTableEntry> { public: ASMJIT_NONCOPYABLE(AddressTableEntry) + //! Address. uint64_t _address; + //! Slot. uint32_t _slot; //! \name Construction & Destruction @@ -547,22 +484,24 @@ public: // [asmjit::CodeHolder] // ============================================================================ -//! Contains basic information about the target architecture plus its settings, -//! and holds code & data (including sections, labels, and relocation information). -//! CodeHolder can store both binary and intermediate representation of assembly, -//! which can be generated by `BaseAssembler` and/or `BaseBuilder`. +//! Contains basic information about the target architecture and its options. +//! +//! In addition, it holds assembled code & data (including sections, labels, and +//! relocation information). `CodeHolder` can store both binary and intermediate +//! representation of assembly, which can be generated by \ref BaseAssembler, +//! \ref BaseBuilder, and \ref BaseCompiler //! -//! \note `CodeHolder` has ability to attach an `ErrorHandler`, however, the -//! error handler is not triggered by `CodeHolder` itself, it's only used by -//! emitters attached to `CodeHolder`. +//! \note `CodeHolder` has an ability to attach an \ref ErrorHandler, however, +//! the error handler is not triggered by `CodeHolder` itself, it's instead +//! propagated to all emitters that attach to it. class CodeHolder { public: ASMJIT_NONCOPYABLE(CodeHolder) - //! Basic information about the code (architecture and other info). - CodeInfo _codeInfo; - //! Emitter options, propagated to all emitters when changed. - uint32_t _emitterOptions; + //! Environment information. + Environment _environment; + //! Base address or \ref Globals::kNoBaseAddress. + uint64_t _baseAddress; //! Attached `Logger`, used by all consumers. Logger* _logger; @@ -574,7 +513,7 @@ public: //! Zone allocator, used to manage internal containers. ZoneAllocator _allocator; - //! Attached code emitters. + //! Attached emitters. ZoneVector<BaseEmitter*> _emitters; //! Section entries. ZoneVector<Section*> _sections; @@ -592,6 +531,25 @@ public: //! Address table entries. ZoneTree<AddressTableEntry> _addressTableEntries; + //! Options that can be used with \ref copySectionData() and \ref copyFlattenedData(). + enum CopyOptions : uint32_t { + //! If virtual size of a section is greater than the size of its \ref CodeBuffer + //! then all bytes between the buffer size and virtual size will be zeroed. + //! If this option is not set then those bytes would be left as is, which + //! means that if the user didn't initialize them they would have a previous + //! content, which may be unwanted. + kCopyPadSectionBuffer = 0x00000001u, + +#ifndef ASMJIT_NO_DEPRECATED + kCopyWithPadding = kCopyPadSectionBuffer, +#endif // !ASMJIT_NO_DEPRECATED + + //! Zeroes the target buffer if the flattened data is less than the destination + //! size. This option works only with \ref copyFlattenedData() as it processes + //! multiple sections. It is ignored by \ref copySectionData(). + kCopyPadTargetBuffer = 0x00000002u + }; + //! \name Construction & Destruction //! \{ @@ -600,10 +558,13 @@ public: //! Destroys the CodeHolder. ASMJIT_API ~CodeHolder() noexcept; - inline bool isInitialized() const noexcept { return _codeInfo.isInitialized(); } + //! Tests whether the `CodeHolder` has been initialized. + //! + //! Emitters can be only attached to initialized `CodeHolder` instances. + inline bool isInitialized() const noexcept { return _environment.isInitialized(); } - //! Initializes CodeHolder to hold code described by `codeInfo`. - ASMJIT_API Error init(const CodeInfo& info) noexcept; + //! Initializes CodeHolder to hold code described by code `info`. + ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept; //! Detaches all code-generators attached and resets the `CodeHolder`. ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept; @@ -622,65 +583,62 @@ public: //! \name Allocators //! \{ + //! Returns the allocator that the `CodeHolder` uses. + //! + //! \note This should be only used for AsmJit's purposes. Code holder uses + //! arena allocator to allocate everything, so anything allocated through + //! this allocator will be invalidated by \ref CodeHolder::reset() or by + //! CodeHolder's destructor. inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); } //! \} - //! \name Code Emitter + //! \name Code & Architecture //! \{ - inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; } + //! Returns the target environment information, see \ref Environment. + inline const Environment& environment() const noexcept { return _environment; } - //! Returns global emitter options, internally propagated to all attached emitters. - inline uint32_t emitterOptions() const noexcept { return _emitterOptions; } + //! Returns the target architecture. + inline uint32_t arch() const noexcept { return environment().arch(); } + //! Returns the target sub-architecture. + inline uint32_t subArch() const noexcept { return environment().subArch(); } - //! Enables the given global emitter `options` and propagates the resulting - //! options to all attached emitters. - ASMJIT_API void addEmitterOptions(uint32_t options) noexcept; - - //! Disables the given global emitter `options` and propagates the resulting - //! options to all attached emitters. - ASMJIT_API void clearEmitterOptions(uint32_t options) noexcept; + //! Tests whether a static base-address is set. + inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + //! Returns a static base-address or \ref Globals::kNoBaseAddress, if not set. + inline uint64_t baseAddress() const noexcept { return _baseAddress; } //! \} - //! \name Code & Architecture + //! \name Emitters //! \{ - //! Returns the target architecture information, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _codeInfo.archInfo(); } - //! Returns the target code information, see `CodeInfo`. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } - - //! Returns the target architecture id. - inline uint32_t archId() const noexcept { return archInfo().archId(); } - //! Returns the target architecture sub-id. - inline uint32_t archSubId() const noexcept { return archInfo().archSubId(); } - - //! Tests whether a static base-address is set. - inline bool hasBaseAddress() const noexcept { return _codeInfo.hasBaseAddress(); } - //! Returns a static base-address (uint64_t). - inline uint64_t baseAddress() const noexcept { return _codeInfo.baseAddress(); } + //! Returns a vector of attached emitters. + inline const ZoneVector<BaseEmitter*>& emitters() const noexcept { return _emitters; } //! \} - //! \name Logging & Error Handling + //! \name Logging //! \{ - //! Returns the attached logger. + //! Returns the attached logger, see \ref Logger. inline Logger* logger() const noexcept { return _logger; } //! Attaches a `logger` to CodeHolder and propagates it to all attached emitters. ASMJIT_API void setLogger(Logger* logger) noexcept; //! Resets the logger to none. inline void resetLogger() noexcept { setLogger(nullptr); } - //! Tests whether the global error handler is attached. + //! \name Error Handling + //! \{ + + //! Tests whether the CodeHolder has an attached error handler, see \ref ErrorHandler. inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } - //! Returns the global error handler. + //! Returns the attached error handler. inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } - //! Sets the global error handler. - inline void setErrorHandler(ErrorHandler* handler) noexcept { _errorHandler = handler; } - //! Resets the global error handler to none. + //! Attach an error handler to this `CodeHolder`. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + //! Resets the error handler to none. inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } //! \} @@ -688,7 +646,16 @@ public: //! \name Code Buffer //! \{ + //! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept; + + //! Reserves the size of `cb` to at least `n` bytes. + //! + //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the + //! behavior of the function is undefined. ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept; //! \} @@ -719,7 +686,7 @@ public: //! Returns '.text' section (section that commonly represents code). //! - //! \note Text section is always the first section in `CodeHolder::sections()` array. + //! \note Text section is always the first section in \ref CodeHolder::sections() array. inline Section* textSection() const noexcept { return _sections[0]; } //! Tests whether '.addrtab' section exists. @@ -729,6 +696,8 @@ public: //! //! This section is used exclusively by AsmJit to store absolute 64-bit //! addresses that cannot be encoded in instructions like 'jmp' or 'call'. + //! + //! \note This section is created on demand, the returned pointer can be null. inline Section* addressTableSection() const noexcept { return _addressTableSection; } //! Ensures that '.addrtab' section exists (creates it if it doesn't) and @@ -825,18 +794,38 @@ public: //! Returns `Error`, does not report error to `ErrorHandler`. ASMJIT_API Error newLabelEntry(LabelEntry** entryOut) noexcept; - //! Creates a new named label label-type `type`. + //! Creates a new named \ref LabelEntry of the given label `type`. //! - //! Returns `Error`, does not report a possible error to `ErrorHandler`. + //! \param entryOut Where to store the created \ref LabelEntry. + //! \param name The name of the label. + //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is + //! a null terminated string, which means that the `CodeHolder` will + //! use `strlen()` to determine the length. + //! \param type The type of the label to create, see \ref Label::LabelType. + //! \param parentId Parent id of a local label, otherwise it must be + //! \ref Globals::kInvalidId. + //! + //! \retval Always returns \ref Error, does not report a possible error to + //! the attached \ref ErrorHandler. + //! + //! AsmJit has a support for local labels (\ref Label::kTypeLocal) which + //! require a parent label id (parentId). The names of local labels can + //! conflict with names of other local labels that have a different parent. ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId = Globals::kInvalidId) noexcept; - //! Returns a label id by name. - ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; - + //! Returns a label by name. + //! + //! If the named label doesn't a default constructed \ref Label is returned, + //! which has its id set to \ref Globals::kInvalidId. inline Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept { return Label(labelIdByName(name, nameSize, parentId)); } + //! Returns a label id by name. + //! + //! If the named label doesn't exist \ref Globals::kInvalidId is returned. + ASMJIT_API uint32_t labelIdByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept; + //! Tests whether there are any unresolved label links. inline bool hasUnresolvedLinks() const noexcept { return _unresolvedLinkCount != 0; } //! Returns the number of label links, which are unresolved. @@ -903,24 +892,34 @@ public: //! \note This should never be called more than once. ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept; - //! Options that can be used with \ref copySectionData(). - enum CopyOptions : uint32_t { - //! If virtual size of the section is larger than the size of its buffer - //! then all bytes between buffer size and virtual size will be zeroed. - kCopyWithPadding = 0x1 - }; - //! Copies a single section into `dst`. - ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t options = 0) noexcept; + ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions = 0) noexcept; //! Copies all sections into `dst`. //! //! This should only be used if the data was flattened and there are no gaps //! between the sections. The `dstSize` is always checked and the copy will //! never write anything outside the provided buffer. - ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t options = 0) noexcept; + ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions = 0) noexcept; //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use 'CodeHolder::init(const Environment& environment, uint64_t baseAddress)' instead") + inline Error init(const CodeInfo& codeInfo) noexcept { return init(codeInfo._environment, codeInfo._baseAddress); } + + ASMJIT_DEPRECATED("Use nevironment() instead") + inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment, _baseAddress); } + + ASMJIT_DEPRECATED("Use BaseEmitter::encodingOptions() - this function always returns zero") + inline uint32_t emitterOptions() const noexcept { return 0; } + + ASMJIT_DEPRECATED("Use BaseEmitter::addEncodingOptions() - this function does nothing") + inline void addEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } + + ASMJIT_DEPRECATED("Use BaseEmitter::clearEncodingOptions() - this function does nothing") + inline void clearEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); } +#endif // !ASMJIT_NO_DEPRECATED }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/compiler.cpp b/3rdparty/asmjit/src/asmjit/core/compiler.cpp index 13dbf54300a..28bc93f29f2 100644 --- a/3rdparty/asmjit/src/asmjit/core/compiler.cpp +++ b/3rdparty/asmjit/src/asmjit/core/compiler.cpp @@ -27,7 +27,7 @@ #include "../core/assembler.h" #include "../core/compiler.h" #include "../core/cpuinfo.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/rapass_p.h" #include "../core/rastack_p.h" #include "../core/support.h" @@ -40,12 +40,12 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ class GlobalConstPoolPass : public Pass { - ASMJIT_NONCOPYABLE(GlobalConstPoolPass) typedef Pass Base; + ASMJIT_NONCOPYABLE(GlobalConstPoolPass) GlobalConstPoolPass() noexcept : Pass("GlobalConstPoolPass") {} - Error run(Zone* zone, Logger* logger) noexcept override { + Error run(Zone* zone, Logger* logger) override { DebugUtils::unused(zone, logger); // Flush the global constant pool. @@ -54,15 +54,16 @@ class GlobalConstPoolPass : public Pass { compiler->addAfter(compiler->_globalConstPool, compiler->lastNode()); compiler->_globalConstPool = nullptr; } + return kErrorOk; } }; // ============================================================================ -// [asmjit::FuncCallNode - Arg / Ret] +// [asmjit::InvokeNode - Arg / Ret] // ============================================================================ -bool FuncCallNode::_setArg(uint32_t i, const Operand_& op) noexcept { +bool InvokeNode::_setArg(uint32_t i, const Operand_& op) noexcept { if ((i & ~kFuncArgHi) >= _funcDetail.argCount()) return false; @@ -70,7 +71,7 @@ bool FuncCallNode::_setArg(uint32_t i, const Operand_& op) noexcept { return true; } -bool FuncCallNode::_setRet(uint32_t i, const Operand_& op) noexcept { +bool InvokeNode::_setRet(uint32_t i, const Operand_& op) noexcept { if (i >= 2) return false; @@ -90,72 +91,81 @@ BaseCompiler::BaseCompiler() noexcept _localConstPool(nullptr), _globalConstPool(nullptr) { - _type = kTypeCompiler; + _emitterType = uint8_t(kTypeCompiler); + _validationFlags = uint8_t(InstAPI::kValidationFlagVirtRegs); } BaseCompiler::~BaseCompiler() noexcept {} // ============================================================================ -// [asmjit::BaseCompiler - Function API] +// [asmjit::BaseCompiler - Function Management] // ============================================================================ -FuncNode* BaseCompiler::newFunc(const FuncSignature& sign) noexcept { - Error err; - - FuncNode* func = newNodeT<FuncNode>(); - if (ASMJIT_UNLIKELY(!func)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } +Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature) { + *out = nullptr; - err = registerLabelNode(func); - if (ASMJIT_UNLIKELY(err)) { - // TODO: Calls reportError, maybe rethink noexcept? - reportError(err); - return nullptr; - } - - // Create helper nodes. - func->_exitNode = newLabelNode(); - func->_end = newNodeT<SentinelNode>(SentinelNode::kSentinelFuncEnd); - - if (ASMJIT_UNLIKELY(!func->_exitNode || !func->_end)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } + // Create FuncNode together with all the required surrounding nodes. + FuncNode* funcNode; + ASMJIT_PROPAGATE(_newNodeT<FuncNode>(&funcNode)); + ASMJIT_PROPAGATE(_newLabelNode(&funcNode->_exitNode)); + ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelNode::kSentinelFuncEnd)); - // Initialize the function info. - err = func->detail().init(sign); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } + // Initialize the function's detail info. + Error err = funcNode->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); // If the Target guarantees greater stack alignment than required by the // calling convention then override it as we can prevent having to perform // dynamic stack alignment - if (func->_funcDetail._callConv.naturalStackAlignment() < _codeInfo.stackAlignment()) - func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.stackAlignment()); + uint32_t environmentStackAlignment = _environment.stackAlignment(); + + if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment) + funcNode->_funcDetail._callConv.setNaturalStackAlignment(environmentStackAlignment); // Initialize the function frame. - err = func->_frame.init(func->_funcDetail); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } + err = funcNode->_frame.init(funcNode->_funcDetail); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); // Allocate space for function arguments. - func->_args = nullptr; - if (func->argCount() != 0) { - func->_args = _allocator.allocT<VirtReg*>(func->argCount() * sizeof(VirtReg*)); - if (ASMJIT_UNLIKELY(!func->_args)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - memset(func->_args, 0, func->argCount() * sizeof(VirtReg*)); + funcNode->_args = nullptr; + if (funcNode->argCount() != 0) { + funcNode->_args = _allocator.allocT<VirtReg*>(funcNode->argCount() * sizeof(VirtReg*)); + if (ASMJIT_UNLIKELY(!funcNode->_args)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(funcNode->_args, 0, funcNode->argCount() * sizeof(VirtReg*)); } - return func; + ASMJIT_PROPAGATE(registerLabelNode(funcNode)); + + *out = funcNode; + return kErrorOk; +} + +Error BaseCompiler::_addFuncNode(FuncNode** out, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newFuncNode(out, signature)); + addFunc(*out); + return kErrorOk; +} + +Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u; + FuncRetNode* node; + + ASMJIT_PROPAGATE(_newNodeT<FuncRetNode>(&node)); + node->setOpCount(opCount); + node->setOp(0, o0); + node->setOp(1, o1); + node->resetOpRange(2, node->opCapacity()); + + *out = node; + return kErrorOk; +} + +Error BaseCompiler::_addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) { + ASMJIT_PROPAGATE(_newRetNode(out, o0, o1)); + addNode(*out); + return kErrorOk; } FuncNode* BaseCompiler::addFunc(FuncNode* func) { @@ -165,25 +175,15 @@ FuncNode* BaseCompiler::addFunc(FuncNode* func) { addNode(func); // Function node. BaseNode* prev = cursor(); // {CURSOR}. addNode(func->exitNode()); // Function exit label. - addNode(func->endNode()); // Function end marker. + addNode(func->endNode()); // Function end sentinel. _setCursor(prev); return func; } -FuncNode* BaseCompiler::addFunc(const FuncSignature& sign) { - FuncNode* func = newFunc(sign); - - if (!func) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - return addFunc(func); -} - Error BaseCompiler::endFunc() { FuncNode* func = _func; + if (ASMJIT_UNLIKELY(!func)) return reportError(DebugUtils::errored(kErrorInvalidState)); @@ -199,6 +199,7 @@ Error BaseCompiler::endFunc() { SentinelNode* end = func->endNode(); setCursor(end); + return kErrorOk; } @@ -217,71 +218,43 @@ Error BaseCompiler::setArg(uint32_t argIndex, const BaseReg& r) { return kErrorOk; } -FuncRetNode* BaseCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept { - FuncRetNode* node = newNodeT<FuncRetNode>(); - if (!node) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } - - node->setOp(0, o0); - node->setOp(1, o1); - node->setOpCount(!o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u); - - return node; -} - -FuncRetNode* BaseCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept { - FuncRetNode* node = newRet(o0, o1); - if (!node) return nullptr; - return addNode(node)->as<FuncRetNode>(); -} - // ============================================================================ -// [asmjit::BaseCompiler - Call] +// [asmjit::BaseCompiler - Function Invocation] // ============================================================================ -FuncCallNode* BaseCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - FuncCallNode* node = newNodeT<FuncCallNode>(instId, 0u); - if (ASMJIT_UNLIKELY(!node)) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; - } +Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, 0u)); node->setOpCount(1); node->setOp(0, o0); - node->resetOp(1); - node->resetOp(2); - node->resetOp(3); + node->resetOpRange(1, node->opCapacity()); - Error err = node->detail().init(sign); - if (ASMJIT_UNLIKELY(err)) { - reportError(err); - return nullptr; - } - - // If there are no arguments skip the allocation. - uint32_t nArgs = sign.argCount(); - if (!nArgs) return node; + Error err = node->detail().init(signature, environment()); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - node->_args = static_cast<Operand*>(_allocator.alloc(nArgs * sizeof(Operand))); - if (!node->_args) { - reportError(DebugUtils::errored(kErrorOutOfMemory)); - return nullptr; + // Skip the allocation if there are no arguments. + uint32_t argCount = signature.argCount(); + if (argCount) { + node->_args = static_cast<Operand*>(_allocator.alloc(argCount * sizeof(Operand))); + if (!node->_args) + reportError(DebugUtils::errored(kErrorOutOfMemory)); + memset(node->_args, 0, argCount * sizeof(Operand)); } - memset(node->_args, 0, nArgs * sizeof(Operand)); - return node; + *out = node; + return kErrorOk; } -FuncCallNode* BaseCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept { - FuncCallNode* node = newCall(instId, o0, sign); - if (!node) return nullptr; - return addNode(node)->as<FuncCallNode>(); +Error BaseCompiler::_addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + ASMJIT_PROPAGATE(_newInvokeNode(out, instId, o0, signature)); + addNode(*out); + return kErrorOk; } // ============================================================================ -// [asmjit::BaseCompiler - Vars] +// [asmjit::BaseCompiler - Virtual Registers] // ============================================================================ static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) { @@ -294,16 +267,19 @@ static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) { vReg->_name.setData(&self->_dataZone, buf, unsigned(size)); } -VirtReg* BaseCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept { +Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name) { + *out = nullptr; uint32_t index = _vRegArray.size(); + if (ASMJIT_UNLIKELY(index >= uint32_t(Operand::kVirtIdCount))) - return nullptr; + return reportError(DebugUtils::errored(kErrorTooManyVirtRegs)); - if (_vRegArray.willGrow(&_allocator) != kErrorOk) - return nullptr; + if (ASMJIT_UNLIKELY(_vRegArray.willGrow(&_allocator) != kErrorOk)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); VirtReg* vReg = _vRegZone.allocZeroedT<VirtReg>(); - if (ASMJIT_UNLIKELY(!vReg)) return nullptr; + if (ASMJIT_UNLIKELY(!vReg)) + return reportError(DebugUtils::errored(kErrorOutOfMemory)); uint32_t size = Type::sizeOf(typeId); uint32_t alignment = Support::min<uint32_t>(size, 64); @@ -320,26 +296,28 @@ VirtReg* BaseCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const cha #endif _vRegArray.appendUnsafe(vReg); - return vReg; + *out = vReg; + + return kErrorOk; } -Error BaseCompiler::_newReg(BaseReg& out, uint32_t typeId, const char* name) { +Error BaseCompiler::_newReg(BaseReg* out, uint32_t typeId, const char* name) { + out->reset(); + RegInfo regInfo; + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); - Error err = ArchUtils::typeIdToRegInfo(archId(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return reportError(err); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - VirtReg* vReg = newVirtReg(typeId, regInfo.signature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); - out._initReg(regInfo.signature(), vReg->id()); + out->_initReg(regInfo.signature(), vReg->id()); return kErrorOk; } -Error BaseCompiler::_newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...) { +Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...) { va_list ap; StringTmp<256> sb; @@ -350,7 +328,9 @@ Error BaseCompiler::_newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, . return _newReg(out, typeId, sb.data()); } -Error BaseCompiler::_newReg(BaseReg& out, const BaseReg& ref, const char* name) { +Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) { + out->reset(); + RegInfo regInfo; uint32_t typeId; @@ -412,20 +392,18 @@ Error BaseCompiler::_newReg(BaseReg& out, const BaseReg& ref, const char* name) typeId = ref.type(); } - Error err = ArchUtils::typeIdToRegInfo(archId(), typeId, regInfo); - if (ASMJIT_UNLIKELY(err)) return reportError(err); + Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info); + if (ASMJIT_UNLIKELY(err)) + return reportError(err); - VirtReg* vReg = newVirtReg(typeId, regInfo.signature(), name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name)); - out._initReg(regInfo.signature(), vReg->id()); + out->_initReg(regInfo.signature(), vReg->id()); return kErrorOk; } -Error BaseCompiler::_newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...) { +Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...) { va_list ap; StringTmp<256> sb; @@ -436,7 +414,9 @@ Error BaseCompiler::_newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt return _newReg(out, ref, sb.data()); } -Error BaseCompiler::_newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name) { +Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) { + out->reset(); + if (size == 0) return reportError(DebugUtils::errored(kErrorInvalidArgument)); @@ -449,22 +429,19 @@ Error BaseCompiler::_newStack(BaseMem& out, uint32_t size, uint32_t alignment, c if (alignment > 64) alignment = 64; - VirtReg* vReg = newVirtReg(0, 0, name); - if (ASMJIT_UNLIKELY(!vReg)) { - out.reset(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + VirtReg* vReg; + ASMJIT_PROPAGATE(newVirtReg(&vReg, 0, 0, name)); vReg->_virtSize = size; vReg->_isStack = true; vReg->_alignment = uint8_t(alignment); // Set the memory operand to GPD/GPQ and its id to VirtReg. - out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag }); + *out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag }); return kErrorOk; } -Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) noexcept { +Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment) { if (!isVirtIdValid(virtId)) return DebugUtils::errored(kErrorInvalidVirtId); @@ -493,8 +470,10 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new return kErrorOk; } -Error BaseCompiler::_newConst(BaseMem& out, uint32_t scope, const void* data, size_t size) { +Error BaseCompiler::_newConst(BaseMem* out, uint32_t scope, const void* data, size_t size) { + out->reset(); ConstPoolNode** pPool; + if (scope == ConstPool::kScopeLocal) pPool = &_localConstPool; else if (scope == ConstPool::kScopeGlobal) @@ -502,29 +481,26 @@ Error BaseCompiler::_newConst(BaseMem& out, uint32_t scope, const void* data, si else return reportError(DebugUtils::errored(kErrorInvalidArgument)); - ConstPoolNode* pool = *pPool; - if (!pool) { - pool = newConstPoolNode(); - if (ASMJIT_UNLIKELY(!pool)) - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - *pPool = pool; - } + if (!*pPool) + ASMJIT_PROPAGATE(_newConstPoolNode(pPool)); + ConstPoolNode* pool = *pPool; size_t off; Error err = pool->add(data, size, off); if (ASMJIT_UNLIKELY(err)) return reportError(err); - out = BaseMem(BaseMem::Decomposed { + *out = BaseMem(BaseMem::Decomposed { Label::kLabelTag, // Base type. - pool->id(), // Base id. + pool->labelId(), // Base id. 0, // Index type. 0, // Index id. int32_t(off), // Offset. uint32_t(size), // Size. 0 // Flags. }); + return kErrorOk; } @@ -553,38 +529,38 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) { // [asmjit::BaseCompiler - Jump Annotations] // ============================================================================ -JumpNode* BaseCompiler::newJumpNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) noexcept { - uint32_t opCount = 1; +Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) { JumpNode* node = _allocator.allocT<JumpNode>(); + uint32_t opCount = 1; + if (ASMJIT_UNLIKELY(!node)) - return nullptr; + return reportError(DebugUtils::errored(kErrorOutOfMemory)); node = new(node) JumpNode(this, instId, instOptions, opCount, annotation); node->setOp(0, o0); - node->resetOps(opCount, JumpNode::kBaseOpCapacity); - return node; + node->resetOpRange(opCount, JumpNode::kBaseOpCapacity); + + *out = node; + return kErrorOk; } Error BaseCompiler::emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation) { - uint32_t options = instOptions() | globalInstOptions(); + uint32_t options = instOptions() | forcedInstOptions(); + RegOnly extra = extraReg(); const char* comment = inlineComment(); - JumpNode* node = newJumpNode(instId, options, o0, annotation); - resetInstOptions(); resetInlineComment(); + resetExtraReg(); - if (ASMJIT_UNLIKELY(!node)) { - resetExtraReg(); - return reportError(DebugUtils::errored(kErrorOutOfMemory)); - } + JumpNode* node; + ASMJIT_PROPAGATE(newJumpNode(&node, instId, options, o0, annotation)); - node->setExtraReg(extraReg()); + node->setExtraReg(extra); if (comment) node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true))); addNode(node); - resetExtraReg(); return kErrorOk; } @@ -644,7 +620,7 @@ FuncPass::FuncPass(const char* name) noexcept // [asmjit::FuncPass - Run] // ============================================================================ -Error FuncPass::run(Zone* zone, Logger* logger) noexcept { +Error FuncPass::run(Zone* zone, Logger* logger) { BaseNode* node = cb()->firstNode(); if (!node) return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/core/compiler.h b/3rdparty/asmjit/src/asmjit/core/compiler.h index 32b2a8bb271..71f89ec701e 100644 --- a/3rdparty/asmjit/src/asmjit/core/compiler.h +++ b/3rdparty/asmjit/src/asmjit/core/compiler.h @@ -51,7 +51,7 @@ class JumpAnnotation; class JumpNode; class FuncNode; class FuncRetNode; -class FuncCallNode; +class InvokeNode; //! \addtogroup asmjit_compiler //! \{ @@ -60,7 +60,7 @@ class FuncCallNode; // [asmjit::VirtReg] // ============================================================================ -//! Virtual register data (BaseCompiler). +//! Virtual register data, managed by \ref BaseCompiler. class VirtReg { public: ASMJIT_NONCOPYABLE(VirtReg) @@ -192,14 +192,18 @@ public: //! primarily designed for merging multiple parts of code into a function //! without worrying about registers and function calling conventions. //! -//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit -//! code at the same time. +//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and +//! 64-bit code generation within a single code base. //! //! BaseCompiler is based on BaseBuilder and contains all the features it //! provides. It means that the code it stores can be modified (removed, added, //! injected) and analyzed. When the code is finalized the compiler can emit //! the code into an Assembler to translate the abstract representation into a //! machine code. +//! +//! Check out architecture specific compilers for more details and examples: +//! +//! - \ref x86::Compiler - X86/X64 compiler implementation. class ASMJIT_VIRTAPI BaseCompiler : public BaseBuilder { public: ASMJIT_NONCOPYABLE(BaseCompiler) @@ -229,38 +233,80 @@ public: //! \} - //! \name Function API + //! \name Function Management //! \{ //! Returns the current function. inline FuncNode* func() const noexcept { return _func; } - //! Creates a new `FuncNode`. - ASMJIT_API FuncNode* newFunc(const FuncSignature& sign) noexcept; - //! Adds a function `node` to the stream. + //! Creates a new \ref FuncNode. + ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature); + //! Creates a new \ref FuncNode adds it to the compiler. + ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature); + + //! Creates a new \ref FuncRetNode. + ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + //! Creates a new \ref FuncRetNode and adds it to the compiler. + ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1); + + //! Creates a new \ref FuncNode with the given `signature` and returns it. + inline FuncNode* newFunc(const FuncSignature& signature) { + FuncNode* node; + _newFuncNode(&node, signature); + return node; + } + + //! Creates a new \ref FuncNode with the given `signature`, adds it to the + //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it. + inline FuncNode* addFunc(const FuncSignature& signature) { + FuncNode* node; + _addFuncNode(&node, signature); + return node; + } + + //! Adds a function `node` to the instruction stream. ASMJIT_API FuncNode* addFunc(FuncNode* func); - //! Adds a new function. - ASMJIT_API FuncNode* addFunc(const FuncSignature& sign); //! Emits a sentinel that marks the end of the current function. ASMJIT_API Error endFunc(); //! Sets a function argument at `argIndex` to `reg`. ASMJIT_API Error setArg(uint32_t argIndex, const BaseReg& reg); - //! Creates a new `FuncRetNode`. - ASMJIT_API FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) noexcept; - //! Adds a new `FuncRetNode`. - ASMJIT_API FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) noexcept; + inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _newRetNode(&node, o0, o1); + return node; + } + + inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) { + FuncRetNode* node; + _addRetNode(&node, o0, o1); + return node; + } //! \} - //! \name Function Calls + //! \name Function Invocation //! \{ - //! Creates a new `FuncCallNode`. - ASMJIT_API FuncCallNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; - //! Adds a new `FuncCallNode`. - ASMJIT_API FuncCallNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept; + //! Creates a new \ref InvokeNode. + ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + //! Creates a new \ref InvokeNode and adds it to Compiler. + ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature); + + //! Creates a new `InvokeNode`. + inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _newInvokeNode(&node, instId, o0, signature); + return node; + } + + //! Adds a new `InvokeNode`. + inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) { + InvokeNode* node; + _addInvokeNode(&node, instId, o0, signature); + return node; + } //! \} @@ -268,13 +314,27 @@ public: //! \{ //! Creates a new virtual register representing the given `typeId` and `signature`. - ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept; + //! + //! \note This function is public, but it's not generally recommended to be used + //! by AsmJit users, use architecture-specific `newReg()` functionality instead + //! or functions like \ref _newReg() and \ref _newRegFmt(). + ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name); - ASMJIT_API Error _newReg(BaseReg& out, uint32_t typeId, const char* name = nullptr); - ASMJIT_API Error _newRegFmt(BaseReg& out, uint32_t typeId, const char* fmt, ...); + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + ASMJIT_API Error _newReg(BaseReg* out, uint32_t typeId, const char* name = nullptr); - ASMJIT_API Error _newReg(BaseReg& out, const BaseReg& ref, const char* name = nullptr); - ASMJIT_API Error _newRegFmt(BaseReg& out, const BaseReg& ref, const char* fmt, ...); + //! Creates a new virtual register of the given `typeId` and stores it to `out` operand. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr); + + //! Creates a new virtual register compatible with the provided reference register `ref`. + //! + //! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments. + ASMJIT_API Error _newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...); //! Tests whether the given `id` is a valid virtual register id. inline bool isVirtIdValid(uint32_t id) const noexcept { @@ -286,14 +346,20 @@ public: return isVirtIdValid(reg.id()); } - //! Returns `VirtReg` associated with the given `id`. + //! Returns \ref VirtReg associated with the given `id`. inline VirtReg* virtRegById(uint32_t id) const noexcept { ASMJIT_ASSERT(isVirtIdValid(id)); return _vRegArray[Operand::virtIdToIndex(id)]; } - //! Returns `VirtReg` associated with the given `reg`. + + //! Returns \ref VirtReg associated with the given `reg`. inline VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); } - //! Returns `VirtReg` associated with the given `index`. + + //! Returns \ref VirtReg associated with the given virtual register `index`. + //! + //! \note This is not the same as virtual register id. The conversion between + //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref + //! Operand_::indexToVirtId() functions. inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; } //! Returns an array of all virtual registers managed by the Compiler. @@ -302,13 +368,16 @@ public: //! \name Stack //! \{ - ASMJIT_API Error _newStack(BaseMem& out, uint32_t size, uint32_t alignment, const char* name = nullptr); + //! Creates a new stack of the given `size` and `alignment` and stores it to `out`. + //! + //! \note `name` can be used to give the stack a name, for debugging purposes. + ASMJIT_API Error _newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name = nullptr); //! Updates the stack size of a stack created by `_newStack()` by its `virtId`. - ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0) noexcept; + ASMJIT_API Error setStackSize(uint32_t virtId, uint32_t newSize, uint32_t newAlignment = 0); //! Updates the stack size of a stack created by `_newStack()`. - inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) noexcept { + inline Error setStackSize(const BaseMem& mem, uint32_t newSize, uint32_t newAlignment = 0) { return setStackSize(mem.id(), newSize, newAlignment); } @@ -317,7 +386,11 @@ public: //! \name Constants //! \{ - ASMJIT_API Error _newConst(BaseMem& out, uint32_t scope, const void* data, size_t size); + //! Creates a new constant of the given `scope` (see \ref ConstPool::Scope). + //! + //! This function adds a constant of the given `size` to the built-in \ref + //! ConstPool and stores the reference to that constant to the `out` operand. + ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size); //! \} @@ -325,8 +398,6 @@ public: //! \{ //! Rename the given virtual register `reg` to a formatted string `fmt`. - //! - //! \note Only new name will appear in the logger. ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...); //! \} @@ -338,7 +409,7 @@ public: return _jumpAnnotations; } - ASMJIT_API JumpNode* newJumpNode(uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation) noexcept; + ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation); ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation); //! Returns a new `JumpAnnotation` instance, which can be used to aggregate @@ -348,9 +419,12 @@ public: //! \} - // TODO: These should be removed - inline void alloc(BaseReg& reg) { DebugUtils::unused(reg); } - inline void spill(BaseReg& reg) { DebugUtils::unused(reg); } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future") + inline void alloc(BaseReg&) {} + ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future") + inline void spill(BaseReg&) {} +#endif // !ASMJIT_NO_DEPRECATED //! \name Events //! \{ @@ -365,26 +439,44 @@ public: // [asmjit::JumpAnnotation] // ============================================================================ +//! Jump annotation used to annotate jumps. +//! +//! \ref BaseCompiler allows to emit jumps where the target is either register +//! or memory operand. Such jumps cannot be trivially inspected, so instead of +//! doing heuristics AsmJit allows to annotate such jumps with possible targets. +//! Register allocator then use the annotation to construct control-flow, which +//! is then used by liveness analysis and other tools to prepare ground for +//! register allocation. class JumpAnnotation { public: ASMJIT_NONCOPYABLE(JumpAnnotation) + //! Compiler that owns this JumpAnnotation. BaseCompiler* _compiler; + //! Annotation identifier. uint32_t _annotationId; + //! Vector of label identifiers, see \ref labelIds(). ZoneVector<uint32_t> _labelIds; inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept : _compiler(compiler), _annotationId(annotationId) {} + //! Returns the compiler that owns this JumpAnnotation. inline BaseCompiler* compiler() const noexcept { return _compiler; } + //! Returns the annotation id. inline uint32_t annotationId() const noexcept { return _annotationId; } + //! Returns a vector of label identifiers that lists all targets of the jump. const ZoneVector<uint32_t>& labelIds() const noexcept { return _labelIds; } + //! Tests whether the given `label` is a target of this JumpAnnotation. inline bool hasLabel(const Label& label) const noexcept { return hasLabelId(label.id()); } + //! Tests whether the given `labelId` is a target of this JumpAnnotation. inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); } + //! Adds the `label` to the list of targets of this JumpAnnotation. inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); } + //! Adds the `labelId` to the list of targets of this JumpAnnotation. inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); } }; @@ -418,8 +510,11 @@ public: //! \name Accessors //! \{ + //! Tests whether this JumpNode has associated a \ref JumpAnnotation. inline bool hasAnnotation() const noexcept { return _annotation != nullptr; } + //! Returns the \ref JumpAnnotation associated with this jump, or `nullptr`. inline JumpAnnotation* annotation() const noexcept { return _annotation; } + //! Sets the \ref JumpAnnotation associated with this jump to `annotation`. inline void setAnnotation(JumpAnnotation* annotation) noexcept { _annotation = annotation; } //! \} @@ -429,7 +524,51 @@ public: // [asmjit::FuncNode] // ============================================================================ -//! Function entry (BaseCompiler). +//! Function node represents a function used by \ref BaseCompiler. +//! +//! A function is composed of the following: +//! +//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. +//! To get the entry, simply use \ref FuncNode::label(), which is the same +//! as \ref LabelNode::label(). +//! +//! - Function exit, which is represented by \ref FuncNode::exitNode(). A +//! helper function \ref FuncNode::exitLabel() exists and returns an exit +//! label instead of node. +//! +//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of +//! a function - there should be no code that belongs to the function after +//! this node, but the Compiler doesn't enforce that at the moment. +//! +//! - Function detail, see \ref FuncNode::detail(). +//! +//! - Function frame, see \ref FuncNode::frame(). +//! +//! - Function arguments mapped to virtual registers, see \ref FuncNode::args(). +//! +//! In a node list, the function and its body looks like the following: +//! +//! \code{.unparsed} +//! [...] - Anything before the function. +//! +//! [FuncNode] - Entry point of the function, acts as a label as well. +//! <Prolog> - Prolog inserted by the register allocator. +//! {...} - Function body - user code basically. +//! [ExitLabel] - Exit label +//! <Epilog> - Epilog inserted by the register allocator. +//! <Return> - Return inserted by the register allocator. +//! {...} - Can contain data or user code (error handling, special cases, ...). +//! [FuncEnd] - End sentinel +//! +//! [...] - Anything after the function. +//! \endcode +//! +//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it +//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the +//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called +//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel +//! as a marker after additional code or data can be placed, and it's a common +//! practice. class FuncNode : public LabelNode { public: ASMJIT_NONCOPYABLE(FuncNode) @@ -438,7 +577,7 @@ public: FuncDetail _funcDetail; //! Function frame. FuncFrame _frame; - //! Function exit (label). + //! Function exit label. LabelNode* _exitNode; //! Function end (sentinel). SentinelNode* _end; @@ -510,7 +649,9 @@ public: _args[i] = nullptr; } + //! Returns function attributes. inline uint32_t attributes() const noexcept { return _frame.attributes(); } + //! Adds `attrs` to the function attributes. inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); } //! \} @@ -520,7 +661,7 @@ public: // [asmjit::FuncRetNode] // ============================================================================ -//! Function return (BaseCompiler). +//! Function return, used by \ref BaseCompiler. class FuncRetNode : public InstNode { public: ASMJIT_NONCOPYABLE(FuncRetNode) @@ -537,13 +678,13 @@ public: }; // ============================================================================ -// [asmjit::FuncCallNode] +// [asmjit::InvokeNode] // ============================================================================ -//! Function call (BaseCompiler). -class FuncCallNode : public InstNode { +//! Function invocation, used by \ref BaseCompiler. +class InvokeNode : public InstNode { public: - ASMJIT_NONCOPYABLE(FuncCallNode) + ASMJIT_NONCOPYABLE(InvokeNode) //! Function detail. FuncDetail _funcDetail; @@ -555,12 +696,12 @@ public: //! \name Construction & Destruction //! \{ - //! Creates a new `FuncCallNode` instance. - inline FuncCallNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept + //! Creates a new `InvokeNode` instance. + inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept : InstNode(cb, instId, options, kBaseOpCapacity), _funcDetail(), _args(nullptr) { - setType(kNodeFuncCall); + setType(kNodeInvoke); _resetOps(); _rets[0].reset(); _rets[1].reset(); @@ -573,8 +714,8 @@ public: //! \{ //! Sets the function signature. - inline Error setSignature(const FuncSignature& sign) noexcept { - return _funcDetail.init(sign); + inline Error init(const FuncSignature& signature, const Environment& environment) noexcept { + return _funcDetail.init(signature, environment); } //! Returns the function detail. @@ -634,6 +775,7 @@ public: // [asmjit::FuncPass] // ============================================================================ +//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction(). class ASMJIT_VIRTAPI FuncPass : public Pass { public: ASMJIT_NONCOPYABLE(FuncPass) @@ -658,10 +800,10 @@ public: //! \{ //! Calls `runOnFunction()` on each `FuncNode` node found. - ASMJIT_API Error run(Zone* zone, Logger* logger) noexcept override; + ASMJIT_API Error run(Zone* zone, Logger* logger) override; //! Called once per `FuncNode`. - virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept = 0; + virtual Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/constpool.h b/3rdparty/asmjit/src/asmjit/core/constpool.h index 259615fcaa8..d9ac58952a8 100644 --- a/3rdparty/asmjit/src/asmjit/core/constpool.h +++ b/3rdparty/asmjit/src/asmjit/core/constpool.h @@ -30,7 +30,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ @@ -65,9 +65,12 @@ public: //! Zone-allocated const-pool gap created by two differently aligned constants. struct Gap { - Gap* _next; //!< Pointer to the next gap - size_t _offset; //!< Offset of the gap. - size_t _size; //!< Remaining bytes of the gap (basically a gap size). + //! Pointer to the next gap + Gap* _next; + //! Offset of the gap. + size_t _offset; + //! Remaining bytes of the gap (basically a gap size). + size_t _size; }; //! Zone-allocated const-pool node. @@ -75,6 +78,11 @@ public: public: ASMJIT_NONCOPYABLE(Node) + //! If this constant is shared with another. + uint32_t _shared : 1; + //! Data offset from the beginning of the pool. + uint32_t _offset; + inline Node(size_t offset, bool shared) noexcept : ZoneTreeNodeT<Node>(), _shared(shared), @@ -83,14 +91,13 @@ public: inline void* data() const noexcept { return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1); } - - uint32_t _shared : 1; //!< If this constant is shared with another. - uint32_t _offset; //!< Data offset from the beginning of the pool. }; //! Data comparer used internally. class Compare { public: + size_t _dataSize; + inline Compare(size_t dataSize) noexcept : _dataSize(dataSize) {} @@ -101,12 +108,17 @@ public: inline int operator()(const Node& a, const void* data) const noexcept { return ::memcmp(a.data(), data, _dataSize); } - - size_t _dataSize; }; //! Zone-allocated const-pool tree. struct Tree { + //! RB tree. + ZoneTree<Node> _tree; + //! Size of the tree (number of nodes). + size_t _size; + //! Size of the data. + size_t _dataSize; + inline explicit Tree(size_t dataSize = 0) noexcept : _tree(), _size(0), @@ -177,13 +189,6 @@ public: memcpy(node->data(), data, size); return node; } - - //! RB tree. - ZoneTree<Node> _tree; - //! Size of the tree (number of nodes). - size_t _size; - //! Size of the data. - size_t _dataSize; }; //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/core/cpuinfo.h b/3rdparty/asmjit/src/asmjit/core/cpuinfo.h index d2defb90ed6..ee2c9e5514a 100644 --- a/3rdparty/asmjit/src/asmjit/core/cpuinfo.h +++ b/3rdparty/asmjit/src/asmjit/core/cpuinfo.h @@ -31,7 +31,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_core //! \{ // ============================================================================ @@ -41,8 +41,12 @@ ASMJIT_BEGIN_NAMESPACE //! CPU information. class CpuInfo { public: - //! CPU architecture information. - ArchInfo _archInfo; + //! Architecture. + uint8_t _arch; + //! Sub-architecture. + uint8_t _subArch; + //! Reserved for future use. + uint16_t _reserved; //! CPU family ID. uint32_t _familyId; //! CPU model ID. @@ -74,15 +78,15 @@ public: inline CpuInfo(const CpuInfo& other) noexcept = default; inline explicit CpuInfo(Globals::NoInit_) noexcept - : _archInfo(Globals::NoInit), - _features(Globals::NoInit) {}; + : _features(Globals::NoInit) {}; //! Returns the host CPU information. ASMJIT_API static const CpuInfo& host() noexcept; - //! Initializes CpuInfo to the given architecture, see `ArchInfo`. - inline void initArch(uint32_t archId, uint32_t archMode = 0) noexcept { - _archInfo.init(archId, archMode); + //! Initializes CpuInfo to the given architecture, see \ref Environment. + inline void initArch(uint32_t arch, uint32_t subArch = 0u) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); } inline void reset() noexcept { memset(this, 0, sizeof(*this)); } @@ -99,12 +103,10 @@ public: //! \name Accessors //! \{ - //! Returns the CPU architecture information. - inline const ArchInfo& archInfo() const noexcept { return _archInfo; } - //! Returns the CPU architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _archInfo.archId(); } - //! Returns the CPU architecture sub-id, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _archInfo.archSubId(); } + //! Returns the CPU architecture id, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the CPU architecture sub-id, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } //! Returns the CPU family ID. inline uint32_t familyId() const noexcept { return _familyId; } diff --git a/3rdparty/asmjit/src/asmjit/core/datatypes.h b/3rdparty/asmjit/src/asmjit/core/datatypes.h index bee4572294c..2f6cc1e5b42 100644 --- a/3rdparty/asmjit/src/asmjit/core/datatypes.h +++ b/3rdparty/asmjit/src/asmjit/core/datatypes.h @@ -26,17 +26,16 @@ #include "../core/globals.h" -ASMJIT_BEGIN_NAMESPACE +#ifndef ASMJIT_NO_DEPRECATED -//! \addtogroup asmjit_support -//! \{ +ASMJIT_BEGIN_NAMESPACE // ============================================================================ // [asmjit::Data64] // ============================================================================ //! 64-bit data useful for creating SIMD constants. -union Data64 { +union ASMJIT_DEPRECATED_STRUCT("Data64 is deprecated and will be removed in the future") Data64 { //! Array of eight 8-bit signed integers. int8_t sb[8]; //! Array of eight 8-bit unsigned integers. @@ -303,7 +302,7 @@ union Data64 { // ============================================================================ //! 128-bit data useful for creating SIMD constants. -union Data128 { +union ASMJIT_DEPRECATED_STRUCT("Data128 is deprecated and will be removed in the future") Data128 { //! Array of sixteen 8-bit signed integers. int8_t sb[16]; //! Array of sixteen 8-bit unsigned integers. @@ -648,7 +647,7 @@ union Data128 { // ============================================================================ //! 256-bit data useful for creating SIMD constants. -union Data256 { +union ASMJIT_DEPRECATED_STRUCT("Data256 is deprecated and will be removed in the future") Data256 { //! Array of thirty two 8-bit signed integers. int8_t sb[32]; //! Array of thirty two 8-bit unsigned integers. @@ -1066,8 +1065,7 @@ union Data256 { //! \} }; -//! \} - ASMJIT_END_NAMESPACE +#endif // !ASMJIT_NO_DEPRECATED #endif // ASMJIT_CORE_DATATYPES_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/emitter.cpp b/3rdparty/asmjit/src/asmjit/core/emitter.cpp index ebf8c179008..b6ecc3d3cca 100644 --- a/3rdparty/asmjit/src/asmjit/core/emitter.cpp +++ b/3rdparty/asmjit/src/asmjit/core/emitter.cpp @@ -22,7 +22,9 @@ // 3. This notice may not be removed or altered from any source distribution. #include "../core/api-build_p.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/errorhandler.h" +#include "../core/logger.h" #include "../core/support.h" #ifdef ASMJIT_BUILD_X86 @@ -41,94 +43,212 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::BaseEmitter - Construction / Destruction] // ============================================================================ -BaseEmitter::BaseEmitter(uint32_t type) noexcept - : _type(uint8_t(type)), - _reserved(0), - _flags(0), - _emitterOptions(0), +BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept + : _emitterType(uint8_t(emitterType)), + _emitterFlags(0), + _validationFlags(0), + _validationOptions(0), + _encodingOptions(0), + _forcedInstOptions(BaseInst::kOptionReserved), + _privateData(0), _code(nullptr), + _logger(nullptr), _errorHandler(nullptr), - _codeInfo(), + _environment(), _gpRegInfo(), - _privateData(0), _instOptions(0), - _globalInstOptions(BaseInst::kOptionReserved), _extraReg(), _inlineComment(nullptr) {} BaseEmitter::~BaseEmitter() noexcept { if (_code) { - _addFlags(kFlagDestroyed); + _addEmitterFlags(kFlagDestroyed); _code->detach(this); } } // ============================================================================ -// [asmjit::BaseEmitter - Code-Generation] +// [asmjit::BaseEmitter - Finalize] // ============================================================================ -Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { - const Operand_* op = operands; - const Operand& none_ = Globals::none; - - switch (count) { - case 0: return _emit(instId, none_, none_, none_, none_); - case 1: return _emit(instId, op[0], none_, none_, none_); - case 2: return _emit(instId, op[0], op[1], none_, none_); - case 3: return _emit(instId, op[0], op[1], op[2], none_); - case 4: return _emit(instId, op[0], op[1], op[2], op[3]); - case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], none_); - case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]); - default: return DebugUtils::errored(kErrorInvalidArgument); - } +Error BaseEmitter::finalize() { + // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. + return kErrorOk; } // ============================================================================ -// [asmjit::BaseEmitter - Finalize] +// [asmjit::BaseEmitter - Internals] // ============================================================================ -Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { - return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); +static constexpr uint32_t kEmitterPreservedFlags = + BaseEmitter::kFlagOwnLogger | + BaseEmitter::kFlagOwnErrorHandler ; + +static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept { + bool hasLogger = self->_logger != nullptr; + bool hasValidationOptions; + + if (self->emitterType() == BaseEmitter::kTypeAssembler) + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler); + else + hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate); + + self->_forcedInstOptions &= ~BaseInst::kOptionReserved; + if (hasLogger || hasValidationOptions) + self->_forcedInstOptions |= BaseInst::kOptionReserved; } // ============================================================================ -// [asmjit::BaseEmitter - Finalize] +// [asmjit::BaseEmitter - Validation Options] // ============================================================================ -Error BaseEmitter::finalize() { - // Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`. - return kErrorOk; +void BaseEmitter::addValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +void BaseEmitter::clearValidationOptions(uint32_t options) noexcept { + _validationOptions = uint8_t(_validationOptions | options); + BaseEmitter_updateForcedOptions(this); +} + +// ============================================================================ +// [asmjit::BaseEmitter - Logging] +// ============================================================================ + +void BaseEmitter::setLogger(Logger* logger) noexcept { +#ifndef ASMJIT_NO_LOGGING + if (logger) { + _logger = logger; + _addEmitterFlags(kFlagOwnLogger); + } + else { + _logger = nullptr; + _clearEmitterFlags(kFlagOwnLogger); + if (_code) + _logger = _code->logger(); + } + BaseEmitter_updateForcedOptions(this); +#else + DebugUtils::unused(logger); +#endif } // ============================================================================ // [asmjit::BaseEmitter - Error Handling] // ============================================================================ -Error BaseEmitter::reportError(Error err, const char* message) { - ErrorHandler* handler = errorHandler(); - if (!handler) { - if (code()) - handler = code()->errorHandler(); +void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept { + if (errorHandler) { + _errorHandler = errorHandler; + _addEmitterFlags(kFlagOwnErrorHandler); } + else { + _errorHandler = nullptr; + _clearEmitterFlags(kFlagOwnErrorHandler); + if (_code) + _errorHandler = _code->errorHandler(); + } +} - if (handler) { +Error BaseEmitter::reportError(Error err, const char* message) { + ErrorHandler* eh = _errorHandler; + if (eh) { if (!message) message = DebugUtils::errorAsString(err); - handler->handleError(err, message, this); + eh->handleError(err, message, this); } - return err; } // ============================================================================ -// [asmjit::BaseEmitter - Label Management] +// [asmjit::BaseEmitter - Labels] // ============================================================================ +Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept { + return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId)); +} + bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept { return _code && labelId < _code->labelCount(); } // ============================================================================ +// [asmjit::BaseEmitter - Emit (Low-Level)] +// ============================================================================ + +using EmitterUtils::noExt; + +Error BaseEmitter::_emitI(uint32_t instId) { + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) { + return _emit(instId, o0, noExt[1], noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) { + return _emit(instId, o0, o1, noExt[2], noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) { + return _emit(instId, o0, o1, o2, noExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { + Operand_ opExt[3] = { o3 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) { + Operand_ opExt[3] = { o3, o4 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) { + Operand_ opExt[3] = { o3, o4, o5 }; + return _emit(instId, o0, o1, o2, opExt); +} + +Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + const Operand_* op = operands; + + Operand_ opExt[3]; + + switch (opCount) { + case 0: + return _emit(instId, noExt[0], noExt[1], noExt[2], noExt); + + case 1: + return _emit(instId, op[0], noExt[1], noExt[2], noExt); + + case 2: + return _emit(instId, op[0], op[1], noExt[2], noExt); + + case 3: + return _emit(instId, op[0], op[1], op[2], noExt); + + case 4: + opExt[0] = op[3]; + opExt[1].reset(); + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 5: + opExt[0] = op[3]; + opExt[1] = op[4]; + opExt[2].reset(); + return _emit(instId, op[0], op[1], op[2], opExt); + + case 6: + return _emit(instId, op[0], op[1], op[2], op + 3); + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } +} + +// ============================================================================ // [asmjit::BaseEmitter - Emit (High-Level)] // ============================================================================ @@ -137,12 +257,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) { return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitProlog(as<x86::Emitter>(), frame); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitProlog(as<arm::Emitter>(), frame); #endif @@ -154,12 +274,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitEpilog(const FuncFrame& frame) { return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitEpilog(as<x86::Emitter>(), frame); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitEpilog(as<arm::Emitter>(), frame); #endif @@ -171,12 +291,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame, return DebugUtils::errored(kErrorNotInitialized); #ifdef ASMJIT_BUILD_X86 - if (archInfo().isX86Family()) + if (environment().isFamilyX86()) return x86::X86Internal::emitArgsAssignment(as<x86::Emitter>(), frame, args); #endif #ifdef ASMJIT_BUILD_ARM - if (archInfo().isArmFamily()) + if (environment().isFamilyARM()) return arm::ArmInternal::emitArgsAssignment(as<arm::Emitter>(), frame, args); #endif @@ -192,17 +312,11 @@ Error BaseEmitter::commentf(const char* fmt, ...) { return DebugUtils::errored(kErrorNotInitialized); #ifndef ASMJIT_NO_LOGGING - StringTmp<1024> sb; - va_list ap; va_start(ap, fmt); - Error err = sb.appendVFormat(fmt, ap); + Error err = commentv(fmt, ap); va_end(ap); - - if (ASMJIT_UNLIKELY(err)) - return err; - - return comment(sb.data(), sb.size()); + return err; #else DebugUtils::unused(fmt); return kErrorOk; @@ -215,8 +329,8 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) { #ifndef ASMJIT_NO_LOGGING StringTmp<1024> sb; - Error err = sb.appendVFormat(fmt, ap); + if (ASMJIT_UNLIKELY(err)) return err; @@ -233,40 +347,46 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) { Error BaseEmitter::onAttach(CodeHolder* code) noexcept { _code = code; - _codeInfo = code->codeInfo(); - _emitterOptions = code->emitterOptions(); + _environment = code->environment(); - onUpdateGlobalInstOptions(); + onSettingsUpdated(); return kErrorOk; } Error BaseEmitter::onDetach(CodeHolder* code) noexcept { DebugUtils::unused(code); - _flags = 0; - _emitterOptions = 0; - _errorHandler = nullptr; + _clearEmitterFlags(~kEmitterPreservedFlags); + _forcedInstOptions = BaseInst::kOptionReserved; + _privateData = 0; + + if (!hasOwnLogger()) + _logger = nullptr; + + if (!hasOwnErrorHandler()) + _errorHandler = nullptr; - _codeInfo.reset(); + _environment.reset(); _gpRegInfo.reset(); - _privateData = 0; _instOptions = 0; - _globalInstOptions = BaseInst::kOptionReserved; _extraReg.reset(); _inlineComment = nullptr; return kErrorOk; } -void BaseEmitter::onUpdateGlobalInstOptions() noexcept { - constexpr uint32_t kCriticalEmitterOptions = - kOptionLoggingEnabled | - kOptionStrictValidation ; +void BaseEmitter::onSettingsUpdated() noexcept { + // Only called when attached to CodeHolder by CodeHolder. + ASMJIT_ASSERT(_code != nullptr); + + if (!hasOwnLogger()) + _logger = _code->logger(); + + if (!hasOwnErrorHandler()) + _errorHandler = _code->errorHandler(); - _globalInstOptions &= ~BaseInst::kOptionReserved; - if ((_emitterOptions & kCriticalEmitterOptions) != 0) - _globalInstOptions |= BaseInst::kOptionReserved; + BaseEmitter_updateForcedOptions(this); } ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/emitter.h b/3rdparty/asmjit/src/asmjit/core/emitter.h index 585558457bd..cfdb6951488 100644 --- a/3rdparty/asmjit/src/asmjit/core/emitter.h +++ b/3rdparty/asmjit/src/asmjit/core/emitter.h @@ -25,9 +25,10 @@ #define ASMJIT_CORE_EMITTER_H_INCLUDED #include "../core/arch.h" +#include "../core/codeholder.h" #include "../core/inst.h" #include "../core/operand.h" -#include "../core/codeholder.h" +#include "../core/type.h" ASMJIT_BEGIN_NAMESPACE @@ -52,31 +53,40 @@ class ASMJIT_VIRTAPI BaseEmitter { public: ASMJIT_BASE_CLASS(BaseEmitter) - //! See `EmitterType`. - uint8_t _type; - //! Reserved for future use. - uint8_t _reserved; - //! See \ref BaseEmitter::Flags. - uint16_t _flags; - //! Emitter options, always in sync with CodeHolder. - uint32_t _emitterOptions; + //! See \ref EmitterType. + uint8_t _emitterType; + //! See \ref BaseEmitter::EmitterFlags. + uint8_t _emitterFlags; + //! Validation flags in case validation is used, see \ref InstAPI::ValidationFlags. + //! + //! \note Validation flags are specific to the emitter and they are setup at + //! construction time and then never changed. + uint8_t _validationFlags; + //! Validation options, see \ref ValidationOptions. + uint8_t _validationOptions; + + //! Encoding options, see \ref EncodingOptions. + uint32_t _encodingOptions; - //! CodeHolder the BaseEmitter is attached to. + //! Forced instruction options, combined with \ref _instOptions by \ref emit(). + uint32_t _forcedInstOptions; + //! Internal private data used freely by any emitter. + uint32_t _privateData; + + //! CodeHolder the emitter is attached to. CodeHolder* _code; - //! Attached `ErrorHandler`. + //! Attached \ref Logger. + Logger* _logger; + //! Attached \ref ErrorHandler. ErrorHandler* _errorHandler; - //! Basic information about the code (matches CodeHolder::_codeInfo). - CodeInfo _codeInfo; + //! Describes the target environment, matches \ref CodeHolder::environment(). + Environment _environment; //! Native GP register signature and signature related information. RegInfo _gpRegInfo; - //! Internal private data used freely by any emitter. - uint32_t _privateData; //! Next instruction options (affects the next instruction). uint32_t _instOptions; - //! Global Instruction options (combined with `_instOptions` by `emit...()`). - uint32_t _globalInstOptions; //! Extra register (op-mask {k} on AVX-512) (affects the next instruction). RegOnly _extraReg; //! Inline comment of the next instruction (affects the next instruction). @@ -86,41 +96,34 @@ public: enum EmitterType : uint32_t { //! Unknown or uninitialized. kTypeNone = 0, - //! Emitter inherits from `BaseAssembler`. + //! Emitter inherits from \ref BaseAssembler. kTypeAssembler = 1, - //! Emitter inherits from `BaseBuilder`. + //! Emitter inherits from \ref BaseBuilder. kTypeBuilder = 2, - //! Emitter inherits from `BaseCompiler`. + //! Emitter inherits from \ref BaseCompiler. kTypeCompiler = 3, + //! Count of emitter types. kTypeCount = 4 }; //! Emitter flags. - enum Flags : uint32_t { + enum EmitterFlags : uint32_t { + //! The emitter has its own \ref Logger (not propagated from \ref CodeHolder). + kFlagOwnLogger = 0x10u, + //! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder). + kFlagOwnErrorHandler = 0x20u, //! The emitter was finalized. - kFlagFinalized = 0x4000u, + kFlagFinalized = 0x40u, //! The emitter was destroyed. - kFlagDestroyed = 0x8000u + kFlagDestroyed = 0x80u }; - //! Emitter options. - enum Options : uint32_t { - //! Logging is enabled, `BaseEmitter::logger()` must return a valid logger. - //! This option is set automatically by the emitter if the logger is present. - //! User code should never alter this value. - //! - //! Default `false`. - kOptionLoggingEnabled = 0x00000001u, - - //! Stricly validate each instruction before it's emitted. - //! - //! Default `false`. - kOptionStrictValidation = 0x00000002u, - + //! Encoding options. + enum EncodingOptions : uint32_t { //! Emit instructions that are optimized for size, if possible. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -130,11 +133,11 @@ public: //! by taking advantage of implicit zero extension. For example instruction //! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` //! and `and r32, imm` when the immediate constant is lesser than `2^31`. - kOptionOptimizedForSize = 0x00000004u, + kEncodingOptionOptimizeForSize = 0x00000001u, //! Emit optimized code-alignment sequences. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -144,11 +147,11 @@ public: //! more optimized align sequences for 2-11 bytes that may execute faster //! on certain CPUs. If this feature is enabled AsmJit will generate //! specialized sequences for alignment between 2 to 11 bytes. - kOptionOptimizedAlign = 0x00000008u, + kEncodingOptionOptimizedAlign = 0x00000002u, //! Emit jump-prediction hints. //! - //! Default `false`. + //! Default: false. //! //! X86 Specific //! ------------ @@ -163,14 +166,56 @@ public: //! This feature is disabled by default, because the only processor that //! used to take into consideration prediction hints was P4. Newer processors //! implement heuristics for branch prediction and ignore static hints. This - //! means that this feature can be used for annotation purposes. - kOptionPredictedJumps = 0x00000010u + //! means that this feature can be only used for annotation purposes. + kEncodingOptionPredictedJumps = 0x00000010u + }; + +#ifndef ASMJIT_NO_DEPRECATED + enum EmitterOptions : uint32_t { + kOptionOptimizedForSize = kEncodingOptionOptimizeForSize, + kOptionOptimizedAlign = kEncodingOptionOptimizedAlign, + kOptionPredictedJumps = kEncodingOptionPredictedJumps + }; +#endif + + //! Validation options are used to tell emitters to perform strict validation + //! of instructions passed to \ref emit(). + //! + //! \ref BaseAssembler implementation perform by default only basic checks + //! that are necessary to identify all variations of an instruction so the + //! correct encoding can be selected. This is fine for production-ready code + //! as the assembler doesn't have to perform checks that would slow it down. + //! However, sometimes these checks are beneficial especially when the project + //! that uses AsmJit is in a development phase, in which mistakes happen often. + //! To make the experience of using AsmJit seamless it offers validation + //! features that can be controlled by `ValidationOptions`. + enum ValidationOptions : uint32_t { + //! Perform strict validation in \ref BaseAssembler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before it's encoded + //! into a binary representation. This flag is only relevant for \ref + //! BaseAssembler implementations, but can be set in any other emitter type, + //! in that case if that emitter needs to create an assembler on its own, + //! for the purpose of \ref finalize() it would propagate this flag to such + //! assembler so all instructions passed to it are explicitly validated. + //! + //! Default: false. + kValidationOptionAssembler = 0x00000001u, + + //! Perform strict validation in \ref BaseBuilder::emit() and \ref + //! BaseCompiler::emit() implementations. + //! + //! This flag ensures that each instruction is checked before an \ref + //! InstNode representing the instruction is created by Builder or Compiler. + //! + //! Default: false. + kValidationOptionIntermediate = 0x00000002u }; //! \name Construction & Destruction //! \{ - ASMJIT_API explicit BaseEmitter(uint32_t type) noexcept; + ASMJIT_API explicit BaseEmitter(uint32_t emitterType) noexcept; ASMJIT_API virtual ~BaseEmitter() noexcept; //! \} @@ -190,28 +235,28 @@ public: //! \{ //! Returns the type of this emitter, see `EmitterType`. - inline uint32_t emitterType() const noexcept { return _type; } + inline uint32_t emitterType() const noexcept { return _emitterType; } //! Returns emitter flags , see `Flags`. - inline uint32_t emitterFlags() const noexcept { return _flags; } + inline uint32_t emitterFlags() const noexcept { return _emitterFlags; } //! Tests whether the emitter inherits from `BaseAssembler`. - inline bool isAssembler() const noexcept { return _type == kTypeAssembler; } + inline bool isAssembler() const noexcept { return _emitterType == kTypeAssembler; } //! Tests whether the emitter inherits from `BaseBuilder`. //! //! \note Both Builder and Compiler emitters would return `true`. - inline bool isBuilder() const noexcept { return _type >= kTypeBuilder; } + inline bool isBuilder() const noexcept { return _emitterType >= kTypeBuilder; } //! Tests whether the emitter inherits from `BaseCompiler`. - inline bool isCompiler() const noexcept { return _type == kTypeCompiler; } + inline bool isCompiler() const noexcept { return _emitterType == kTypeCompiler; } //! Tests whether the emitter has the given `flag` enabled. - inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + inline bool hasEmitterFlag(uint32_t flag) const noexcept { return (_emitterFlags & flag) != 0; } //! Tests whether the emitter is finalized. - inline bool isFinalized() const noexcept { return hasFlag(kFlagFinalized); } + inline bool isFinalized() const noexcept { return hasEmitterFlag(kFlagFinalized); } //! Tests whether the emitter is destroyed (only used during destruction). - inline bool isDestroyed() const noexcept { return hasFlag(kFlagDestroyed); } + inline bool isDestroyed() const noexcept { return hasEmitterFlag(kFlagDestroyed); } - inline void _addFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags | flags); } - inline void _clearFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags & ~flags); } + inline void _addEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags | flags); } + inline void _clearEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags & ~flags); } //! \} @@ -220,90 +265,187 @@ public: //! Returns the CodeHolder this emitter is attached to. inline CodeHolder* code() const noexcept { return _code; } - //! Returns an information about the code, see `CodeInfo`. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } - //! Returns an information about the architecture, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _codeInfo.archInfo(); } + + //! Returns the target environment, see \ref Environment. + //! + //! The returned \ref Environment reference matches \ref CodeHolder::environment(). + inline const Environment& environment() const noexcept { return _environment; } //! Tests whether the target architecture is 32-bit. - inline bool is32Bit() const noexcept { return archInfo().is32Bit(); } + inline bool is32Bit() const noexcept { return environment().is32Bit(); } //! Tests whether the target architecture is 64-bit. - inline bool is64Bit() const noexcept { return archInfo().is64Bit(); } + inline bool is64Bit() const noexcept { return environment().is64Bit(); } //! Returns the target architecture type. - inline uint32_t archId() const noexcept { return archInfo().archId(); } + inline uint32_t arch() const noexcept { return environment().arch(); } //! Returns the target architecture sub-type. - inline uint32_t archSubId() const noexcept { return archInfo().archSubId(); } + inline uint32_t subArch() const noexcept { return environment().subArch(); } + //! Returns the target architecture's GP register size (4 or 8 bytes). - inline uint32_t gpSize() const noexcept { return archInfo().gpSize(); } - //! Returns the number of target GP registers. - inline uint32_t gpCount() const noexcept { return archInfo().gpCount(); } + inline uint32_t registerSize() const noexcept { return environment().registerSize(); } //! \} //! \name Initialization & Finalization //! \{ - //! Tests whether the BaseEmitter is initialized (i.e. attached to the `CodeHolder`). + //! Tests whether the emitter is initialized (i.e. attached to \ref CodeHolder). inline bool isInitialized() const noexcept { return _code != nullptr; } + //! Finalizes this emitter. + //! + //! Materializes the content of the emitter by serializing it to the attached + //! \ref CodeHolder through an architecture specific \ref BaseAssembler. This + //! function won't do anything if the emitter inherits from \ref BaseAssembler + //! as assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. + //! However, if this is an emitter that inherits from \ref BaseBuilder or \ref + //! BaseCompiler then these emitters need the materialization phase as they + //! store their content in a representation not visible to \ref CodeHolder. ASMJIT_API virtual Error finalize(); //! \} - //! \name Emitter Options + //! \name Logging //! \{ - //! Tests whether the `option` is present in emitter options. - inline bool hasEmitterOption(uint32_t option) const noexcept { return (_emitterOptions & option) != 0; } - //! Returns the emitter options. - inline uint32_t emitterOptions() const noexcept { return _emitterOptions; } + //! Tests whether the emitter has a logger. + inline bool hasLogger() const noexcept { return _logger != nullptr; } - // TODO: Deprecate and remove, CodeHolder::addEmitterOptions() is the way. - inline void addEmitterOptions(uint32_t options) noexcept { - _emitterOptions |= options; - onUpdateGlobalInstOptions(); - } + //! Tests whether the emitter has its own logger. + //! + //! Own logger means that it overrides the possible logger that may be used + //! by \ref CodeHolder this emitter is attached to. + inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(kFlagOwnLogger); } - inline void clearEmitterOptions(uint32_t options) noexcept { - _emitterOptions &= ~options; - onUpdateGlobalInstOptions(); - } + //! Returns the logger this emitter uses. + //! + //! The returned logger is either the emitter's own logger or it's logger + //! used by \ref CodeHolder this emitter is attached to. + inline Logger* logger() const noexcept { return _logger; } + + //! Sets or resets the logger of the emitter. + //! + //! If the `logger` argument is non-null then the logger will be considered + //! emitter's own logger, see \ref hasOwnLogger() for more details. If the + //! given `logger` is null then the emitter will automatically use logger + //! that is attached to the \ref CodeHolder this emitter is attached to. + ASMJIT_API void setLogger(Logger* logger) noexcept; - //! Returns the global instruction options. + //! Resets the logger of this emitter. //! - //! Default instruction options are merged with instruction options before the - //! instruction is encoded. These options have some bits reserved that are used - //! for error handling, logging, and strict validation. Other options are globals that - //! affect each instruction, for example if VEX3 is set globally, it will all - //! instructions, even those that don't have such option set. - inline uint32_t globalInstOptions() const noexcept { return _globalInstOptions; } + //! The emitter will bail to using a logger attached to \ref CodeHolder this + //! emitter is attached to, or no logger at all if \ref CodeHolder doesn't + //! have one. + inline void resetLogger() noexcept { return setLogger(nullptr); } //! \} //! \name Error Handling //! \{ - //! Tests whether the local error handler is attached. + //! Tests whether the emitter has an error handler attached. inline bool hasErrorHandler() const noexcept { return _errorHandler != nullptr; } - //! Returns the local error handler. + + //! Tests whether the emitter has its own error handler. + //! + //! Own error handler means that it overrides the possible error handler that + //! may be used by \ref CodeHolder this emitter is attached to. + inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(kFlagOwnErrorHandler); } + + //! Returns the error handler this emitter uses. + //! + //! The returned error handler is either the emitter's own error handler or + //! it's error handler used by \ref CodeHolder this emitter is attached to. inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; } - //! Sets the local error handler. - inline void setErrorHandler(ErrorHandler* handler) noexcept { _errorHandler = handler; } - //! Resets the local error handler (does nothing if not attached). + + //! Sets or resets the error handler of the emitter. + ASMJIT_API void setErrorHandler(ErrorHandler* errorHandler) noexcept; + + //! Resets the error handler. inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); } //! Handles the given error in the following way: - //! 1. Gets either Emitter's (preferred) or CodeHolder's ErrorHandler. - //! 2. If exists, calls `ErrorHandler::handleError(error, message, this)`. - //! 3. Returns the given `err` if ErrorHandler haven't thrown. + //! 1. If the emitter has \ref ErrorHandler attached, it calls its + //! \ref ErrorHandler::handleError() member function first, and + //! then returns the error. The `handleError()` function may throw. + //! 2. if the emitter doesn't have \ref ErrorHandler, the error is + //! simply returned. ASMJIT_API Error reportError(Error err, const char* message = nullptr); //! \} + //! \name Encoding Options + //! \{ + + //! Returns encoding options, see \ref EncodingOptions. + inline uint32_t encodingOptions() const noexcept { return _encodingOptions; } + //! Tests whether the encoding `option` is set. + inline bool hasEncodingOption(uint32_t option) const noexcept { return (_encodingOptions & option) != 0; } + + //! Enables the given encoding `options`, see \ref EncodingOptions. + inline void addEncodingOptions(uint32_t options) noexcept { _encodingOptions |= options; } + //! Disables the given encoding `options`, see \ref EncodingOptions. + inline void clearEncodingOptions(uint32_t options) noexcept { _encodingOptions &= ~options; } + + //! \} + + //! \name Validation Options + //! \{ + + //! Returns the emitter's validation options, see \ref ValidationOptions. + inline uint32_t validationOptions() const noexcept { + return _validationOptions; + } + + //! Tests whether the given `option` is present in validation options. + inline bool hasValidationOption(uint32_t option) const noexcept { + return (_validationOptions & option) != 0; + } + + //! Activates the given validation `options`, see \ref ValidationOptions. + //! + //! This function is used to activate explicit validation options that will + //! be then used by all emitter implementations. There are in general two + //! possibilities: + //! + //! - Architecture specific assembler is used. In this case a + //! \ref kValidationOptionAssembler can be used to turn on explicit + //! validation that will be used before an instruction is emitted. + //! This means that internally an extra step will be performed to + //! make sure that the instruction is correct. This is needed, because + //! by default assemblers prefer speed over strictness. + //! + //! This option should be used in debug builds as it's pretty expensive. + //! + //! - Architecture specific builder or compiler is used. In this case + //! the user can turn on \ref kValidationOptionIntermediate option + //! that adds explicit validation step before the Builder or Compiler + //! creates an \ref InstNode to represent an emitted instruction. Error + //! will be returned if the instruction is ill-formed. In addition, + //! also \ref kValidationOptionAssembler can be used, which would not be + //! consumed by Builder / Compiler directly, but it would be propagated + //! to an architecture specific \ref BaseAssembler implementation it + //! creates during \ref BaseEmitter::finalize(). + ASMJIT_API void addValidationOptions(uint32_t options) noexcept; + + //! Deactivates the given validation `options`. + //! + //! See \ref addValidationOptions() and \ref ValidationOptions for more details. + ASMJIT_API void clearValidationOptions(uint32_t options) noexcept; + + //! \} + //! \name Instruction Options //! \{ + //! Returns forced instruction options. + //! + //! Forced instruction options are merged with next instruction options before + //! the instruction is encoded. These options have some bits reserved that are + //! used by error handling, logging, and instruction validation purposes. Other + //! options are globals that affect each instruction. + inline uint32_t forcedInstOptions() const noexcept { return _forcedInstOptions; } + //! Returns options of the next instruction. inline uint32_t instOptions() const noexcept { return _instOptions; } //! Returns options of the next instruction. @@ -377,100 +519,49 @@ public: // NOTE: These `emit()` helpers are designed to address a code-bloat generated // by C++ compilers to call a function having many arguments. Each parameter to - // `_emit()` requires some code to pass it, which means that if we default to 4 - // operand parameters in `_emit()` and instId the C++ compiler would have to - // generate a virtual function call having 5 parameters, which is quite a lot. - // Since by default asm instructions have 2 to 3 operands it's better to - // introduce helpers that pass those and fill out the remaining operands. - - #define OP const Operand_& - #define NONE Globals::none - - //! Emits an instruction. - ASMJIT_NOINLINE Error emit(uint32_t instId) { return _emit(instId, NONE, NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0) { return _emit(instId, o0, NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, NONE); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, NONE); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); } - - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), NONE); } + // `_emit()` requires some code to pass it, which means that if we default to + // 5 arguments in `_emit()` and instId the C++ compiler would have to generate + // a virtual function call having 5 parameters and additional `this` argument, + // which is quite a lot. Since by default most instructions have 2 to 3 operands + // it's better to introduce helpers that pass from 0 to 6 operands that help to + // reduce the size of emit(...) function call. + + //! Emits an instruction (internal). + ASMJIT_API Error _emitI(uint32_t instId); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } - - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), NONE, NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), NONE, NONE); } - //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), NONE); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4); //! \overload - ASMJIT_NOINLINE Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); } + ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5); - //! \overload - inline Error emit(uint32_t instId, unsigned int o0) { return emit(instId, int64_t(o0)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, unsigned int o1) { return emit(instId, o0, int64_t(o1)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, unsigned int o2) { return emit(instId, o0, o1, int64_t(o2)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, unsigned int o3) { return emit(instId, o0, o1, o2, int64_t(o3)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, unsigned int o4) { return emit(instId, o0, o1, o2, o3, int64_t(o4)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, unsigned int o5) { return emit(instId, o0, o1, o2, o3, o4, int64_t(o5)); } - - //! \overload - inline Error emit(uint32_t instId, uint64_t o0) { return emit(instId, int64_t(o0)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, uint64_t o1) { return emit(instId, o0, int64_t(o1)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, uint64_t o2) { return emit(instId, o0, o1, int64_t(o2)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, uint64_t o3) { return emit(instId, o0, o1, o2, int64_t(o3)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, uint64_t o4) { return emit(instId, o0, o1, o2, o3, int64_t(o4)); } - //! \overload - inline Error emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, uint64_t o5) { return emit(instId, o0, o1, o2, o3, o4, int64_t(o5)); } - - #undef NONE - #undef OP + //! Emits an instruction `instId` with the given `operands`. + template<typename... Args> + ASMJIT_INLINE Error emit(uint32_t instId, Args&&... operands) { + return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...); + } - inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t count) { return _emitOpArray(instId, operands, count); } + inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) { + return _emitOpArray(instId, operands, opCount); + } - inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t count) { + inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) { setInstOptions(inst.options()); setExtraReg(inst.extraReg()); - return _emitOpArray(inst.id(), operands, count); + return _emitOpArray(inst.id(), operands, opCount); } //! \cond INTERNAL - //! Emits instruction having max 4 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0; - //! Emits instruction having max 6 operands. - virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0; + //! Emits an instruction - all 6 operands must be defined. + virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0; //! Emits instruction having operands stored in array. - virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t count); + virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount); //! \endcond //! \} @@ -478,19 +569,19 @@ public: //! \name Emit Utilities //! \{ - ASMJIT_API Error emitProlog(const FuncFrame& layout); - ASMJIT_API Error emitEpilog(const FuncFrame& layout); - ASMJIT_API Error emitArgsAssignment(const FuncFrame& layout, const FuncArgsAssignment& args); + ASMJIT_API Error emitProlog(const FuncFrame& frame); + ASMJIT_API Error emitEpilog(const FuncFrame& frame); + ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args); //! \} //! \name Align //! \{ - //! Aligns the current CodeBuffer to the `alignment` specified. + //! Aligns the current CodeBuffer position to the `alignment` specified. //! //! The sequence that is used to fill the gap between the aligned location - //! and the current location depends on the align `mode`, see `AlignMode`. + //! and the current location depends on the align `mode`, see \ref AlignMode. virtual Error align(uint32_t alignMode, uint32_t alignment) = 0; //! \} @@ -498,16 +589,38 @@ public: //! \name Embed //! \{ - //! Embeds raw data into the CodeBuffer. - virtual Error embed(const void* data, uint32_t dataSize) = 0; - - //! Embeds an absolute label address as data (4 or 8 bytes). - virtual Error embedLabel(const Label& label) = 0; + //! Embeds raw data into the \ref CodeBuffer. + virtual Error embed(const void* data, size_t dataSize) = 0; - //! Embeds a delta (distance) between the `label` and `base` calculating it - //! as `label - base`. This function was designed to make it easier to embed - //! lookup tables where each index is a relative distance of two labels. - virtual Error embedLabelDelta(const Label& label, const Label& base, uint32_t dataSize) = 0; + //! Embeds a typed data array. + //! + //! This is the most flexible function for embedding data as it allows to: + //! - Assign a `typeId` to the data, so the emitter knows the type of + //! items stored in `data`. Binary data should use \ref Type::kIdU8. + //! - Repeat the given data `repeatCount` times, so the data can be used + //! as a fill pattern for example, or as a pattern used by SIMD instructions. + virtual Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0; + + //! Embeds int8_t `value` repeated by `repeatCount`. + inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI8, &value, 1, repeatCount); } + //! Embeds uint8_t `value` repeated by `repeatCount`. + inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU8, &value, 1, repeatCount); } + //! Embeds int16_t `value` repeated by `repeatCount`. + inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI16, &value, 1, repeatCount); } + //! Embeds uint16_t `value` repeated by `repeatCount`. + inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU16, &value, 1, repeatCount); } + //! Embeds int32_t `value` repeated by `repeatCount`. + inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI32, &value, 1, repeatCount); } + //! Embeds uint32_t `value` repeated by `repeatCount`. + inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU32, &value, 1, repeatCount); } + //! Embeds int64_t `value` repeated by `repeatCount`. + inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI64, &value, 1, repeatCount); } + //! Embeds uint64_t `value` repeated by `repeatCount`. + inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU64, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(Type::kIdF32, &value, 1, repeatCount); } + //! Embeds a floating point `value` repeated by `repeatCount`. + inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(Type::IdOfT<double>::kTypeId, &value, 1, repeatCount); } //! Embeds a constant pool at the current offset by performing the following: //! 1. Aligns by using kAlignData to the minimum `pool` alignment. @@ -515,6 +628,14 @@ public: //! 3. Emits ConstPool content. virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0; + //! Embeds an absolute label address as data (4 or 8 bytes). + virtual Error embedLabel(const Label& label) = 0; + + //! Embeds a delta (distance) between the `label` and `base` calculating it + //! as `label - base`. This function was designed to make it easier to embed + //! lookup tables where each index is a relative distance of two labels. + virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize) = 0; + //! \} //! \name Comment @@ -538,13 +659,48 @@ public: //! Called after the emitter was detached from `CodeHolder`. virtual Error onDetach(CodeHolder* code) noexcept = 0; - //! Called to update `_globalInstOptions` based on `_emitterOptions`. + //! Called when \ref CodeHolder has updated an important setting, which + //! involves the following: //! - //! This function should only touch one bit `BaseInst::kOptionReserved`, which - //! is used to handle errors and special-cases in a way that minimizes branching. - ASMJIT_API void onUpdateGlobalInstOptions() noexcept; + //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been + //! called). + //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() + //! has been called). + //! + //! This function ensures that the settings are properly propagated from + //! \ref CodeHolder to the emitter. + //! + //! \note This function is virtual and can be overridden, however, if you + //! do so, always call \ref BaseEmitter::onSettingsUpdated() within your + //! own implementation to ensure that the emitter is in a consisten state. + ASMJIT_API virtual void onSettingsUpdated() noexcept; //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use environment() instead") + inline CodeInfo codeInfo() const noexcept { + return CodeInfo(_environment, _code ? _code->baseAddress() : Globals::kNoBaseAddress); + } + + ASMJIT_DEPRECATED("Use arch() instead") + inline uint32_t archId() const noexcept { return arch(); } + + ASMJIT_DEPRECATED("Use registerSize() instead") + inline uint32_t gpSize() const noexcept { return registerSize(); } + + ASMJIT_DEPRECATED("Use encodingOptions() instead") + inline uint32_t emitterOptions() const noexcept { return encodingOptions(); } + + ASMJIT_DEPRECATED("Use addEncodingOptions() instead") + inline void addEmitterOptions(uint32_t options) noexcept { addEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use clearEncodingOptions() instead") + inline void clearEmitterOptions(uint32_t options) noexcept { clearEncodingOptions(options); } + + ASMJIT_DEPRECATED("Use forcedInstOptions() instead") + inline uint32_t globalInstOptions() const noexcept { return forcedInstOptions(); } +#endif // !ASMJIT_NO_DEPRECATED }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp b/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp new file mode 100644 index 00000000000..1115934e21e --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/emitterutils.cpp @@ -0,0 +1,150 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/assembler.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +#ifndef ASMJIT_NO_LOGGING + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept { + size_t currentSize = sb.size(); + size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0; + + ASMJIT_ASSERT(binSize >= dispSize); + const size_t kNoBinSize = SIZE_MAX; + + if ((binSize != 0 && binSize != kNoBinSize) || commentSize) { + size_t align = kMaxInstLineSize; + char sep = ';'; + + for (size_t i = (binSize == kNoBinSize); i < 2; i++) { + size_t begin = sb.size(); + ASMJIT_PROPAGATE(sb.padEnd(align)); + + if (sep) { + ASMJIT_PROPAGATE(sb.append(sep)); + ASMJIT_PROPAGATE(sb.append(' ')); + } + + // Append binary data or comment. + if (i == 0) { + ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize)); + ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2)); + ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize)); + if (commentSize == 0) break; + } + else { + ASMJIT_PROPAGATE(sb.append(comment, commentSize)); + } + + currentSize += sb.size() - begin; + align += kMaxBinarySize; + sep = '|'; + } + } + + return sb.append('\n'); +} + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept { + Logger* logger = self->logger(); + + StringTmp<512> sb; + size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : SIZE_MAX; + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel)); + Formatter::formatLabel(sb, logger->flags(), self, label.id()); + sb.append(':'); + EmitterUtils::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment); + logger->log(sb.data(), sb.size()); +} + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) { + + Logger* logger = self->logger(); + ASMJIT_ASSERT(logger != nullptr); + + StringTmp<256> sb; + uint32_t flags = logger->flags(); + + uint8_t* beforeCursor = self->bufferPtr(); + intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); + Formatter::formatInstruction(sb, flags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if ((flags & FormatOptions::kFlagMachineCode) != 0) + EmitterUtils::formatLine(sb, self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment()); + else + EmitterUtils::formatLine(sb, nullptr, SIZE_MAX, 0, 0, self->inlineComment()); + logger->log(sb); +} + +Error logInstructionFailed( + BaseAssembler* self, + Error err, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { + + StringTmp<256> sb; + sb.append(DebugUtils::errorAsString(err)); + sb.append(": "); + + Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); + + Formatter::formatInstruction(sb, 0, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount); + + if (self->inlineComment()) { + sb.append(" ; "); + sb.append(self->inlineComment()); + } + + self->resetInstOptions(); + self->resetExtraReg(); + self->resetInlineComment(); + return self->reportError(err, sb.data()); +} + +#endif + +} // {EmitterUtils} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h b/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h new file mode 100644 index 00000000000..7e222d3ad00 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/emitterutils_p.h @@ -0,0 +1,109 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED +#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + +#include "../core/emitter.h" +#include "../core/operand.h" + +ASMJIT_BEGIN_NAMESPACE + +class BaseAssembler; + +//! \cond INTERNAL +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::EmitterUtils] +// ============================================================================ + +namespace EmitterUtils { + +static const Operand_ noExt[3] {}; + +enum kOpIndex { + kOp3 = 0, + kOp4 = 1, + kOp5 = 2 +}; + +static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + uint32_t opCount = 0; + + if (opExt[kOp3].isNone()) { + if (!o0.isNone()) opCount = 1; + if (!o1.isNone()) opCount = 2; + if (!o2.isNone()) opCount = 3; + } + else { + opCount = 4; + if (!opExt[kOp4].isNone()) { + opCount = 5 + uint32_t(!opExt[kOp5].isNone()); + } + } + + return opCount; +} + +static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount], const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept { + dst[0].copyFrom(o0); + dst[1].copyFrom(o1); + dst[2].copyFrom(o2); + dst[3].copyFrom(opExt[kOp3]); + dst[4].copyFrom(opExt[kOp4]); + dst[5].copyFrom(opExt[kOp5]); +} + +#ifndef ASMJIT_NO_LOGGING +enum : uint32_t { + // Has to be big to be able to hold all metadata compiler can assign to a + // single instruction. + kMaxInstLineSize = 44, + kMaxBinarySize = 26 +}; + +Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept; + +void logLabelBound(BaseAssembler* self, const Label& label) noexcept; + +void logInstructionEmitted( + BaseAssembler* self, + uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt, + uint32_t relSize, uint32_t immSize, uint8_t* afterCursor); + +Error logInstructionFailed( + BaseAssembler* self, + Error err, uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt); +#endif + +} + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/environment.cpp b/3rdparty/asmjit/src/asmjit/core/environment.cpp new file mode 100644 index 00000000000..3be2b15a590 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/environment.cpp @@ -0,0 +1,64 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/environment.h" + +ASMJIT_BEGIN_NAMESPACE + +// X86 Target +// ---------- +// +// - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte +// stack alignment. Other operating systems are assumed to have +// 4-byte alignment by default for safety reasons. +// - 64-bit - stack must be aligned to 16 bytes. +// +// ARM Target +// ---------- +// +// - 32-bit - Stack must be aligned to 8 bytes. +// - 64-bit - Stack must be aligned to 16 bytes (hardware requirement). +uint32_t Environment::stackAlignment() const noexcept { + if (is64Bit()) { + // Assume 16-byte alignment on any 64-bit target. + return 16; + } + else { + // The following platforms use 16-byte alignment in 32-bit mode. + if (isPlatformLinux() || + isPlatformBSD() || + isPlatformApple() || + isPlatformHaiku()) { + return 16u; + } + + if (isFamilyARM()) + return 8; + + // Bail to 4-byte alignment if we don't know. + return 4; + } +} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/environment.h b/3rdparty/asmjit/src/asmjit/core/environment.h new file mode 100644 index 00000000000..99b34ec9dbd --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/environment.h @@ -0,0 +1,591 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED +#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED + +#include "../core/globals.h" + +#if defined(__APPLE__) + #include <TargetConditionals.h> +#endif + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_core +//! \{ + +// ============================================================================ +// [asmjit::Environment] +// ============================================================================ + +//! Represents an environment, which is usually related to a \ref Target. +//! +//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is +//! sometimes called "Triple" (historically it used to be 3 only parts) or +//! "Tuple", which is a convention used by Debian Linux. +//! +//! AsmJit doesn't support all possible combinations or architectures and ABIs, +//! however, it models the environment similarly to other compilers for future +//! extensibility. +class Environment { +public: + //! Architecture type, see \ref Arch. + uint8_t _arch; + //! Sub-architecture type, see \ref SubArch. + uint8_t _subArch; + //! Vendor type, see \ref Vendor. + uint8_t _vendor; + //! Platform type, see \ref Platform. + uint8_t _platform; + //! ABI type, see \ref Abi. + uint8_t _abi; + //! Object format, see \ref Format. + uint8_t _format; + //! Reserved for future use, must be zero. + uint16_t _reserved; + + //! Architecture. + enum Arch : uint32_t { + //! Unknown or uninitialized architecture. + kArchUnknown = 0, + + //! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit). + kArch32BitMask = 0x01, + //! Mask used by big-endian architectures. + kArchBigEndianMask = 0x80u, + + //! 32-bit X86 architecture. + kArchX86 = 1, + //! 64-bit X86 architecture also known as X86_64 and AMD64. + kArchX64 = 2, + + //! 32-bit RISC-V architecture. + kArchRISCV32 = 3, + //! 64-bit RISC-V architecture. + kArchRISCV64 = 4, + + //! 32-bit ARM architecture (little endian). + kArchARM = 5, + //! 32-bit ARM architecture (big endian). + kArchARM_BE = kArchARM | kArchBigEndianMask, + //! 64-bit ARM architecture in (little endian). + kArchAArch64 = 6, + //! 64-bit ARM architecture in (big endian). + kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask, + //! 32-bit ARM in Thumb mode (little endian). + kArchThumb = 7, + //! 32-bit ARM in Thumb mode (big endian). + kArchThumb_BE = kArchThumb | kArchBigEndianMask, + + // 8 is not used, even numbers are 64-bit architectures. + + //! 32-bit MIPS architecture in (little endian). + kArchMIPS_LE = 9, + //! 32-bit MIPS architecture in (big endian). + kArchMIPS_BE = kArchMIPS_LE | kArchBigEndianMask, + //! 64-bit MIPS architecture in (little endian). + kArchMIPS64_LE = 10, + //! 64-bit MIPS architecture in (big endian). + kArchMIPS64_BE = kArchMIPS64_LE | kArchBigEndianMask, + + //! Count of architectures. + kArchCount + }; + + //! Sub-architecture. + enum SubArch : uint32_t { + //! Unknown or uninitialized architecture sub-type. + kSubArchUnknown = 0, + + //! Count of sub-architectures. + kSubArchCount + }; + + //! Vendor. + //! + //! \note AsmJit doesn't use vendor information at the moment. It's provided + //! for future use, if required. + enum Vendor : uint32_t { + //! Unknown or uninitialized vendor. + kVendorUnknown = 0, + + //! Count of vendor identifiers. + kVendorCount + }; + + //! Platform / OS. + enum Platform : uint32_t { + //! Unknown or uninitialized platform. + kPlatformUnknown = 0, + + //! Windows OS. + kPlatformWindows, + + //! Other platform, most likely POSIX based. + kPlatformOther, + + //! Linux OS. + kPlatformLinux, + //! GNU/Hurd OS. + kPlatformHurd, + + //! FreeBSD OS. + kPlatformFreeBSD, + //! OpenBSD OS. + kPlatformOpenBSD, + //! NetBSD OS. + kPlatformNetBSD, + //! DragonFly BSD OS. + kPlatformDragonFlyBSD, + + //! Haiku OS. + kPlatformHaiku, + + //! Apple OSX. + kPlatformOSX, + //! Apple iOS. + kPlatformIOS, + //! Apple TVOS. + kPlatformTVOS, + //! Apple WatchOS. + kPlatformWatchOS, + + //! Emscripten platform. + kPlatformEmscripten, + + //! Count of platform identifiers. + kPlatformCount + }; + + //! ABI. + enum Abi : uint32_t { + //! Unknown or uninitialied environment. + kAbiUnknown = 0, + //! Microsoft ABI. + kAbiMSVC, + //! GNU ABI. + kAbiGNU, + //! Android Environment / ABI. + kAbiAndroid, + //! Cygwin ABI. + kAbiCygwin, + + //! Count of known ABI types. + kAbiCount + }; + + //! Object format. + //! + //! \note AsmJit doesn't really use anything except \ref kFormatUnknown and + //! \ref kFormatJIT at the moment. Object file formats are provided for + //! future extensibility and a possibility to generate object files at some + //! point. + enum Format : uint32_t { + //! Unknown or uninitialized object format. + kFormatUnknown = 0, + + //! JIT code generation object, most likely \ref JitRuntime or a custom + //! \ref Target implementation. + kFormatJIT, + + //! Executable and linkable format (ELF). + kFormatELF, + //! Common object file format. + kFormatCOFF, + //! Extended COFF object format. + kFormatXCOFF, + //! Mach object file format. + kFormatMachO, + + //! Count of object format types. + kFormatCount + }; + + //! \name Environment Detection + //! \{ + +#ifdef _DOXYGEN + //! Architecture detected at compile-time (architecture of the host). + static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME; + //! Sub-architecture detected at compile-time (sub-architecture of the host). + static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME; + //! Vendor detected at compile-time (vendor of the host). + static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME; + //! Platform detected at compile-time (platform of the host). + static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME; + //! ABI detected at compile-time (ABI of the host). + static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME; +#else + static constexpr Arch kArchHost = + ASMJIT_ARCH_X86 == 32 ? kArchX86 : + ASMJIT_ARCH_X86 == 64 ? kArchX64 : + + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM : + ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 : + ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE : + + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kArchMIPS_LE : + ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kArchMIPS_BE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kArchMIPS64_LE : + ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kArchMIPS64_BE : + + kArchUnknown; + + static constexpr SubArch kSubArchHost = + kSubArchUnknown; + + static constexpr Vendor kVendorHost = + kVendorUnknown; + + static constexpr Platform kPlatformHost = +#if defined(__EMSCRIPTEN__) + kPlatformEmscripten +#elif defined(_WIN32) + kPlatformWindows +#elif defined(__linux__) + kPlatformLinux +#elif defined(__gnu_hurd__) + kPlatformHurd +#elif defined(__FreeBSD__) + kPlatformFreeBSD +#elif defined(__OpenBSD__) + kPlatformOpenBSD +#elif defined(__NetBSD__) + kPlatformNetBSD +#elif defined(__DragonFly__) + kPlatformDragonFlyBSD +#elif defined(__HAIKU__) + kPlatformHaiku +#elif defined(__APPLE__) && TARGET_OS_OSX + kPlatformOSX +#elif defined(__APPLE__) && TARGET_OS_TV + kPlatformTVOS +#elif defined(__APPLE__) && TARGET_OS_WATCH + kPlatformWatchOS +#elif defined(__APPLE__) && TARGET_OS_IPHONE + kPlatformIOS +#else + kPlatformOther +#endif + ; + + static constexpr Abi kAbiHost = +#if defined(_MSC_VER) + kAbiMSVC +#elif defined(__CYGWIN__) + kAbiCygwin +#elif defined(__MINGW32__) || defined(__GLIBC__) + kAbiGNU +#elif defined(__ANDROID__) + kAbiAndroid +#else + kAbiUnknown +#endif + ; + +#endif + + //! \} + + //! \name Construction / Destruction + //! \{ + + inline Environment() noexcept : + _arch(uint8_t(kArchUnknown)), + _subArch(uint8_t(kSubArchUnknown)), + _vendor(uint8_t(kVendorUnknown)), + _platform(uint8_t(kPlatformUnknown)), + _abi(uint8_t(kAbiUnknown)), + _format(uint8_t(kFormatUnknown)), + _reserved(0) {} + + inline Environment(const Environment& other) noexcept = default; + + inline explicit Environment(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + init(arch, subArch, vendor, platform, abi, format); + } + + //! \} + + //! \name Overloaded Operators + //! \{ + + inline Environment& operator=(const Environment& other) noexcept = default; + + inline bool operator==(const Environment& other) const noexcept { return equals(other); } + inline bool operator!=(const Environment& other) const noexcept { return !equals(other); } + + //! \} + + //! \name Accessors + //! \{ + + //! Tests whether the environment is not set up. + //! + //! Returns true if all members are zero, and thus unknown. + inline bool empty() const noexcept { + // Unfortunately compilers won't optimize fields are checked one by one... + return _packed() == 0; + } + + //! Tests whether the environment is intialized, which means it must have + //! a valid architecture. + inline bool isInitialized() const noexcept { + return _arch != kArchUnknown; + } + + inline uint64_t _packed() const noexcept { + uint64_t x; + memcpy(&x, this, 8); + return x; + } + + //! Resets all members of the environment to zero / unknown. + inline void reset() noexcept { + _arch = uint8_t(kArchUnknown); + _subArch = uint8_t(kSubArchUnknown); + _vendor = uint8_t(kVendorUnknown); + _platform = uint8_t(kPlatformUnknown); + _abi = uint8_t(kAbiUnknown); + _format = uint8_t(kFormatUnknown); + _reserved = 0; + } + + inline bool equals(const Environment& other) const noexcept { + return _packed() == other._packed(); + } + + //! Returns the architecture, see \ref Arch. + inline uint32_t arch() const noexcept { return _arch; } + //! Returns the sub-architecture, see \ref SubArch. + inline uint32_t subArch() const noexcept { return _subArch; } + //! Returns vendor, see \ref Vendor. + inline uint32_t vendor() const noexcept { return _vendor; } + //! Returns target's platform or operating system, see \ref Platform. + inline uint32_t platform() const noexcept { return _platform; } + //! Returns target's ABI, see \ref Abi. + inline uint32_t abi() const noexcept { return _abi; } + //! Returns target's object format, see \ref Format. + inline uint32_t format() const noexcept { return _format; } + + inline void init(uint32_t arch, + uint32_t subArch = kSubArchUnknown, + uint32_t vendor = kVendorUnknown, + uint32_t platform = kPlatformUnknown, + uint32_t abi = kAbiUnknown, + uint32_t format = kFormatUnknown) noexcept { + _arch = uint8_t(arch); + _subArch = uint8_t(subArch); + _vendor = uint8_t(vendor); + _platform = uint8_t(platform); + _abi = uint8_t(abi); + _format = uint8_t(format); + _reserved = 0; + } + + //! Tests whether the architecture is 32-bit. + inline bool is32Bit() const noexcept { return is32Bit(_arch); } + //! Tests whether the architecture is 64-bit. + inline bool is64Bit() const noexcept { return is64Bit(_arch); } + + //! Tests whether the architecture is little endian. + inline bool isLittleEndian() const noexcept { return isLittleEndian(_arch); } + //! Tests whether the architecture is big endian. + inline bool isBigEndian() const noexcept { return isBigEndian(_arch); } + + //! Tests whether this architecture is of X86 family. + inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); } + //! Tests whether this architecture is of ARM family. + inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); } + + //! Tests whether the environment platform is Windows. + inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; } + + //! Tests whether the environment platform is Linux. + inline bool isPlatformLinux() const noexcept { return _platform == kPlatformLinux; } + + //! Tests whether the environment platform is Hurd. + inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; } + + //! Tests whether the environment platform is Haiku. + inline bool isPlatformHaiku() const noexcept { return _platform == kPlatformHaiku; } + + //! Tests whether the environment platform is any BSD. + inline bool isPlatformBSD() const noexcept { + return _platform == kPlatformFreeBSD || + _platform == kPlatformOpenBSD || + _platform == kPlatformNetBSD || + _platform == kPlatformDragonFlyBSD; + } + + //! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS). + inline bool isPlatformApple() const noexcept { + return _platform == kPlatformOSX || + _platform == kPlatformIOS || + _platform == kPlatformTVOS || + _platform == kPlatformWatchOS; + } + + //! Tests whether the ABI is MSVC. + inline bool isAbiMSVC() const noexcept { return _abi == kAbiMSVC; } + //! Tests whether the ABI is GNU. + inline bool isAbiGNU() const noexcept { return _abi == kAbiGNU; } + + //! Returns a calculated stack alignment for this environment. + ASMJIT_API uint32_t stackAlignment() const noexcept; + + //! Returns a native register size of this architecture. + uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); } + + //! Sets the architecture to `arch`. + inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); } + //! Sets the sub-architecture to `subArch`. + inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); } + //! Sets the vendor to `vendor`. + inline void setVendor(uint32_t vendor) noexcept { _vendor = uint8_t(vendor); } + //! Sets the platform to `platform`. + inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); } + //! Sets the ABI to `abi`. + inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); } + //! Sets the object format to `format`. + inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); } + + //! \} + + //! \name Static Utilities + //! \{ + + //! Tests whether the given architecture `arch` is 32-bit. + static inline bool is32Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == kArch32BitMask; + } + + //! Tests whether the given architecture `arch` is 64-bit. + static inline bool is64Bit(uint32_t arch) noexcept { + return (arch & kArch32BitMask) == 0; + } + + //! Tests whether the given architecture `arch` is little endian. + static inline bool isLittleEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == 0; + } + + //! Tests whether the given architecture `arch` is big endian. + static inline bool isBigEndian(uint32_t arch) noexcept { + return (arch & kArchBigEndianMask) == kArchBigEndianMask; + } + + //! Tests whether the given architecture family is X86 or X64. + static inline bool isFamilyX86(uint32_t arch) noexcept { + return arch == kArchX86 || + arch == kArchX64; + } + + //! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit). + static inline bool isFamilyRISCV(uint32_t arch) noexcept { + return arch == kArchRISCV32 || + arch == kArchRISCV64; + } + + //! Tests whether the given architecture family is ARM, Thumb, or AArch64. + static inline bool isFamilyARM(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchARM || + arch == kArchAArch64 || + arch == kArchThumb; + } + + //! Tests whether the given architecture family is MISP or MIPS64. + static inline bool isFamilyMIPS(uint32_t arch) noexcept { + arch &= ~kArchBigEndianMask; + return arch == kArchMIPS_LE || + arch == kArchMIPS64_LE; + } + + //! Returns a native general purpose register size from the given architecture. + static uint32_t registerSizeFromArch(uint32_t arch) noexcept { + return is32Bit(arch) ? 4u : 8u; + } + + //! \} +}; + +//! Returns the host environment constructed from preprocessor macros defined +//! by the compiler. +//! +//! The returned environment should precisely match the target host architecture, +//! sub-architecture, platform, and ABI. +static ASMJIT_INLINE Environment hostEnvironment() noexcept { + return Environment(Environment::kArchHost, + Environment::kSubArchHost, + Environment::kVendorHost, + Environment::kPlatformHost, + Environment::kAbiHost, + Environment::kFormatUnknown); +} + +static_assert(sizeof(Environment) == 8, + "Environment must occupy exactly 8 bytes."); + +//! \} + +#ifndef ASMJIT_NO_DEPRECATED +class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment { +public: + inline ArchInfo() noexcept : Environment() {} + + inline ArchInfo(const Environment& other) noexcept : Environment(other) {} + inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept + : Environment(arch, subArch) {} + + enum Id : uint32_t { + kIdNone = Environment::kArchUnknown, + kIdX86 = Environment::kArchX86, + kIdX64 = Environment::kArchX64, + kIdA32 = Environment::kArchARM, + kIdA64 = Environment::kArchAArch64, + kIdHost = Environment::kArchHost + }; + + enum SubType : uint32_t { + kSubIdNone = Environment::kSubArchUnknown + }; + + static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); } +}; +#endif // !ASMJIT_NO_DEPRECATED + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp b/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp new file mode 100644 index 00000000000..8372d75a463 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/errorhandler.cpp @@ -0,0 +1,37 @@ + +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#include "../core/errorhandler.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +ErrorHandler::ErrorHandler() noexcept {} +ErrorHandler::~ErrorHandler() noexcept {} + +ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/errorhandler.h b/3rdparty/asmjit/src/asmjit/core/errorhandler.h new file mode 100644 index 00000000000..2337cd8d841 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/errorhandler.h @@ -0,0 +1,267 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED +#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + +#include "../core/globals.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_error_handling +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; + +// ============================================================================ +// [asmjit::ErrorHandler] +// ============================================================================ + +//! Error handler can be used to override the default behavior of error handling. +//! +//! It's available to all classes that inherit `BaseEmitter`. Override +//! \ref ErrorHandler::handleError() to implement your own error handler. +//! +//! The following use-cases are supported: +//! +//! - Record the error and continue code generation. This is the simplest +//! approach that can be used to at least log possible errors. +//! - Throw an exception. AsmJit doesn't use exceptions and is completely +//! exception-safe, but it's perfectly legal to throw an exception from +//! the error handler. +//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, +//! Builder and Compiler to a consistent state before calling \ref handleError(), +//! so `longjmp()` can be used without issues to cancel the code-generation if +//! an error occurred. This method can be used if exception handling in your +//! project is turned off and you still want some comfort. In most cases it +//! should be safe as AsmJit uses \ref Zone memory and the ownership of memory +//! it allocates always ends with the instance that allocated it. If using this +//! approach please never jump outside the life-time of \ref CodeHolder and +//! \ref BaseEmitter. +//! +//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, +//! which has a priority. The example below uses error handler that just prints +//! the error, but lets AsmJit continue: +//! +//! ``` +//! // Error Handling #1 - Logging and returing Error. +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Error handler that just prints the error and lets AsmJit ignore it. +//! class SimpleErrorHandler : public ErrorHandler { +//! public: +//! Error err; +//! +//! inline SimpleErrorHandler() : err(kErrorOk) {} +//! +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! this->err = err; +//! fprintf(stderr, "ERROR: %s\n", message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! SimpleErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! // Try to emit instruction that doesn't exist. +//! x86::Assembler a(&code); +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! +//! if (eh.err) { +//! // Assembler failed! +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If error happens during instruction emitting / encoding the assembler behaves +//! transactionally - the output buffer won't advance if encoding failed, thus +//! either a fully encoded instruction or nothing is emitted. The error handling +//! shown above is useful, but it's still not the best way of dealing with errors +//! in AsmJit. The following example shows how to use exception handling to handle +//! errors in a more C++ way: +//! +//! ``` +//! // Error Handling #2 - Throwing an exception. +//! #include <asmjit/x86.h> +//! #include <exception> +//! #include <string> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Error handler that throws a user-defined `AsmJitException`. +//! class AsmJitException : public std::exception { +//! public: +//! Error err; +//! std::string message; +//! +//! AsmJitException(Error err, const char* message) noexcept +//! : err(err), +//! message(message) {} +//! +//! const char* what() const noexcept override { return message.c_str(); } +//! }; +//! +//! class ThrowableErrorHandler : public ErrorHandler { +//! public: +//! // Throw is possible, functions that use ErrorHandler are never 'noexcept'. +//! void handleError(Error err, const char* message, BaseEmitter* origin) override { +//! throw AsmJitException(err, message); +//! } +//! }; +//! +//! int main() { +//! JitRuntime rt; +//! ThrowableErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! // Try to emit instruction that doesn't exist. +//! try { +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! catch (const AsmJitException& ex) { +//! printf("EXCEPTION THROWN: %s\n", ex.what()); +//! return 1; +//! } +//! +//! return 0; +//! } +//! ``` +//! +//! If C++ exceptions are not what you like or your project turns off them +//! completely there is still a way of reducing the error handling to a minimum +//! by using a standard setjmp/longjmp approach. AsmJit is exception-safe and +//! cleans up everything before calling the ErrorHandler, so any approach is +//! safe. You can simply jump from the error handler without causing any +//! side-effects or memory leaks. The following example demonstrates how it +//! could be done: +//! +//! ``` +//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed. +//! #include <asmjit/x86.h> +//! #include <setjmp.h> +//! #include <stdio.h> +//! +//! class LongJmpErrorHandler : public asmjit::ErrorHandler { +//! public: +//! inline LongJmpErrorHandler() : err(asmjit::kErrorOk) {} +//! +//! void handleError(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override { +//! this->err = err; +//! longjmp(state, 1); +//! } +//! +//! jmp_buf state; +//! asmjit::Error err; +//! }; +//! +//! int main(int argc, char* argv[]) { +//! using namespace asmjit; +//! +//! JitRuntime rt; +//! LongJmpErrorHandler eh; +//! +//! CodeHolder code; +//! code.init(rt.rt.environment()); +//! code.setErrorHandler(&eh); +//! +//! x86::Assembler a(&code); +//! +//! if (!setjmp(eh.state)) { +//! // Try to emit instruction that doesn't exist. +//! a.emit(x86::Inst::kIdMov, x86::xmm0, x86::xmm1); +//! } +//! else { +//! Error err = eh.err; +//! printf("ASMJIT ERROR: 0x%08X [%s]\n", err, DebugUtils::errorAsString(err)); +//! } +//! +//! return 0; +//! } +//! ``` +class ASMJIT_VIRTAPI ErrorHandler { +public: + ASMJIT_BASE_CLASS(ErrorHandler) + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! Creates a new `ErrorHandler` instance. + ASMJIT_API ErrorHandler() noexcept; + //! Destroys the `ErrorHandler` instance. + ASMJIT_API virtual ~ErrorHandler() noexcept; + + // -------------------------------------------------------------------------- + // [Handle Error] + // -------------------------------------------------------------------------- + + //! Error handler (must be reimplemented). + //! + //! Error handler is called after an error happened and before it's propagated + //! to the caller. There are multiple ways how the error handler can be used: + //! + //! 1. User-based error handling without throwing exception or using C's + //! `longjmp()`. This is for users that don't use exceptions and want + //! customized error handling. + //! + //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely + //! exception-safe, but you can throw exception from your error handler if + //! this way is the preferred way of handling errors in your project. + //! + //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts + //! `BaseEmitter` to a consistent state before calling `handleError()` + //! so `longjmp()` can be used without any issues to cancel the code + //! generation if an error occurred. There is no difference between + //! exceptions and `longjmp()` from AsmJit's perspective, however, + //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you + //! would leak memory. + virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0; +}; + +//! \} + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_ERRORHANDLER_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/features.h b/3rdparty/asmjit/src/asmjit/core/features.h index 193841c76c8..fd28472c91f 100644 --- a/3rdparty/asmjit/src/asmjit/core/features.h +++ b/3rdparty/asmjit/src/asmjit/core/features.h @@ -36,9 +36,15 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::BaseFeatures] // ============================================================================ +//! Base class that provides information about CPU features. +//! +//! Internally each feature is repreesnted by a single bit in an embedded +//! bit-array, however, feature bits are defined by an architecture specific +//! implementations, like \ref x86::Features. class BaseFeatures { public: typedef Support::BitWord BitWord; + typedef Support::BitVectorIterator<BitWord> Iterator; enum : uint32_t { kMaxFeatures = 128, @@ -74,9 +80,11 @@ public: //! \name Cast //! \{ + //! Casts this base class into a derived type `T`. template<typename T> inline T& as() noexcept { return static_cast<T&>(*this); } + //! Casts this base class into a derived type `T` (const). template<typename T> inline const T& as() const noexcept { return static_cast<const T&>(*this); } @@ -85,11 +93,27 @@ public: //! \name Accessors //! \{ - //! Returns all features as `BitWord` array. + inline bool empty() const noexcept { + for (uint32_t i = 0; i < kNumBitWords; i++) + if (_bits[i]) + return false; + return true; + } + + //! Returns all features as array of bitwords (see \ref Support::BitWord). inline BitWord* bits() noexcept { return _bits; } - //! Returns all features as `BitWord` array (const). + //! Returns all features as array of bitwords (const). inline const BitWord* bits() const noexcept { return _bits; } + //! Returns the number of BitWords returned by \ref bits(). + inline size_t bitWordCount() const noexcept { return kNumBitWords; } + + //! Returns \ref Support::BitVectorIterator, that can be used to iterate + //! all features efficiently + inline Iterator iterator() const noexcept { + return Iterator(_bits, kNumBitWords); + } + //! Tests whether the feature `featureId` is present. inline bool has(uint32_t featureId) const noexcept { ASMJIT_ASSERT(featureId < kMaxFeatures); diff --git a/3rdparty/asmjit/src/asmjit/core/formatter.cpp b/3rdparty/asmjit/src/asmjit/core/formatter.cpp new file mode 100644 index 00000000000..404edaf3820 --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/formatter.cpp @@ -0,0 +1,469 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/builder.h" +#include "../core/codeholder.h" +#include "../core/compiler.h" +#include "../core/emitter.h" +#include "../core/formatter.h" +#include "../core/string.h" +#include "../core/support.h" +#include "../core/type.h" + +#ifdef ASMJIT_BUILD_X86 + #include "../x86/x86formatter_p.h" +#endif + +#ifdef ASMJIT_BUILD_ARM + #include "../arm/armformatter_p.h" +#endif + +ASMJIT_BEGIN_NAMESPACE + +#if defined(ASMJIT_NO_COMPILER) +class VirtReg; +#endif + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +namespace Formatter { + +Error formatTypeId(String& sb, uint32_t typeId) noexcept { + if (typeId == Type::kIdVoid) + return sb.append("void"); + + if (!Type::isValid(typeId)) + return sb.append("unknown"); + + const char* typeName = "unknown"; + uint32_t typeSize = Type::sizeOf(typeId); + + uint32_t baseId = Type::baseOf(typeId); + switch (baseId) { + case Type::kIdIntPtr : typeName = "iptr" ; break; + case Type::kIdUIntPtr: typeName = "uptr" ; break; + case Type::kIdI8 : typeName = "i8" ; break; + case Type::kIdU8 : typeName = "u8" ; break; + case Type::kIdI16 : typeName = "i16" ; break; + case Type::kIdU16 : typeName = "u16" ; break; + case Type::kIdI32 : typeName = "i32" ; break; + case Type::kIdU32 : typeName = "u32" ; break; + case Type::kIdI64 : typeName = "i64" ; break; + case Type::kIdU64 : typeName = "u64" ; break; + case Type::kIdF32 : typeName = "f32" ; break; + case Type::kIdF64 : typeName = "f64" ; break; + case Type::kIdF80 : typeName = "f80" ; break; + case Type::kIdMask8 : typeName = "mask8" ; break; + case Type::kIdMask16 : typeName = "mask16"; break; + case Type::kIdMask32 : typeName = "mask32"; break; + case Type::kIdMask64 : typeName = "mask64"; break; + case Type::kIdMmx32 : typeName = "mmx32" ; break; + case Type::kIdMmx64 : typeName = "mmx64" ; break; + } + + uint32_t baseSize = Type::sizeOf(baseId); + if (typeSize > baseSize) { + uint32_t count = typeSize / baseSize; + return sb.appendFormat("%sx%u", typeName, unsigned(count)); + } + else { + return sb.append(typeName); + } +} + +Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatFeature(sb, featureId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatFeature(sb, featureId); +#endif + + return kErrorInvalidArch; +} + +Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept { + + DebugUtils::unused(formatFlags); + + const LabelEntry* le = emitter->code()->labelEntry(labelId); + if (ASMJIT_UNLIKELY(!le)) + return sb.appendFormat("<InvalidLabel:%u>", labelId); + + if (le->hasName()) { + if (le->hasParent()) { + uint32_t parentId = le->parentId(); + const LabelEntry* pe = emitter->code()->labelEntry(parentId); + + if (ASMJIT_UNLIKELY(!pe)) + ASMJIT_PROPAGATE(sb.appendFormat("<InvalidLabel:%u>", labelId)); + else if (ASMJIT_UNLIKELY(!pe->hasName())) + ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId)); + else + ASMJIT_PROPAGATE(sb.append(pe->name())); + + ASMJIT_PROPAGATE(sb.append('.')); + } + return sb.append(le->name()); + } + else { + return sb.appendFormat("L%u", labelId); + } +} + +Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatRegister(sb, formatFlags, emitter, arch, regType, regId); +#endif + + return kErrorInvalidArch; +} + +Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatOperand(sb, formatFlags, emitter, arch, op); +#endif + + return kErrorInvalidArch; +} + +Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept { + +#ifdef ASMJIT_BUILD_X86 + if (Environment::isFamilyX86(arch)) + return x86::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + +#ifdef ASMJIT_BUILD_ARM + if (Environment::isFamilyARM(arch)) + return arm::FormatterInternal::formatInstruction(sb, formatFlags, emitter, arch, inst, operands, opCount); +#endif + + return kErrorInvalidArch; +} + +#ifndef ASMJIT_NO_BUILDER +static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept { + uint32_t typeId = value.typeId(); + ASMJIT_PROPAGATE(formatTypeId(sb, typeId)); + + if (value.isAssigned()) { + ASMJIT_PROPAGATE(sb.append('@')); + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append('[')); + + // NOTE: It should be either reg or stack, but never both. We + // use two IFs on purpose so if the FuncValue is both it would + // show in logs. + if (value.isReg()) { + ASMJIT_PROPAGATE(formatRegister(sb, formatFlags, emitter, emitter->arch(), value.regType(), value.regId())); + } + + if (value.isStack()) { + ASMJIT_PROPAGATE(sb.appendFormat("[%d]", int(value.stackOffset()))); + } + + if (value.isIndirect()) + ASMJIT_PROPAGATE(sb.append(']')); + } + + return kErrorOk; +} + +static Error formatFuncRets( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + if (!fd.hasRet()) + return sb.append("void"); + + for (uint32_t i = 0; i < fd.retCount(); i++) { + if (i) ASMJIT_PROPAGATE(sb.append(", ")); + ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, fd.ret(i))); + +#ifndef ASMJIT_NO_COMPILER + if (vRegs) { + static const char nullRet[] = "<none>"; + ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullRet)); + } +#else + DebugUtils::unused(vRegs); +#endif + } + + return kErrorOk; +} + +static Error formatFuncArgs( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + const FuncDetail& fd, + VirtReg* const* vRegs) noexcept { + + uint32_t count = fd.argCount(); + if (!count) + return sb.append("void"); + + for (uint32_t i = 0; i < count; i++) { + if (i) + ASMJIT_PROPAGATE(sb.append(", ")); + + ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, fd.arg(i))); + +#ifndef ASMJIT_NO_COMPILER + if (vRegs) { + static const char nullArg[] = "<none>"; + ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullArg)); + } +#else + DebugUtils::unused(vRegs); +#endif + } + + return kErrorOk; +} + +Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept { + + if (node->hasPosition() && (formatFlags & FormatOptions::kFlagPositions) != 0) + ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node->position())); + + switch (node->type()) { + case BaseNode::kNodeInst: + case BaseNode::kNodeJump: { + const InstNode* instNode = node->as<InstNode>(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + instNode->baseInst(), instNode->operands(), instNode->opCount())); + break; + } + + case BaseNode::kNodeSection: { + const SectionNode* sectionNode = node->as<SectionNode>(); + if (builder->_code->isSectionValid(sectionNode->id())) { + const Section* section = builder->_code->sectionById(sectionNode->id()); + ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name())); + } + break; + } + + case BaseNode::kNodeLabel: { + const LabelNode* labelNode = node->as<LabelNode>(); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, labelNode->labelId())); + ASMJIT_PROPAGATE(sb.append(":")); + break; + } + + case BaseNode::kNodeAlign: { + const AlignNode* alignNode = node->as<AlignNode>(); + ASMJIT_PROPAGATE( + sb.appendFormat("align %u (%s)", + alignNode->alignment(), + alignNode->alignMode() == kAlignCode ? "code" : "data")); + break; + } + + case BaseNode::kNodeEmbedData: { + const EmbedDataNode* embedNode = node->as<EmbedDataNode>(); + ASMJIT_PROPAGATE(sb.append("embed ")); + if (embedNode->repeatCount() != 1) + ASMJIT_PROPAGATE(sb.appendFormat("[repeat=%zu] ", size_t(embedNode->repeatCount()))); + ASMJIT_PROPAGATE(sb.appendFormat("%u bytes", embedNode->dataSize())); + break; + } + + case BaseNode::kNodeEmbedLabel: { + const EmbedLabelNode* embedNode = node->as<EmbedLabelNode>(); + ASMJIT_PROPAGATE(sb.append(".label ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + break; + } + + case BaseNode::kNodeEmbedLabelDelta: { + const EmbedLabelDeltaNode* embedNode = node->as<EmbedLabelDeltaNode>(); + ASMJIT_PROPAGATE(sb.append(".label (")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId())); + ASMJIT_PROPAGATE(sb.append(" - ")); + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->baseLabelId())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeComment: { + const CommentNode* commentNode = node->as<CommentNode>(); + ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment())); + break; + } + + case BaseNode::kNodeSentinel: { + const SentinelNode* sentinelNode = node->as<SentinelNode>(); + const char* sentinelName = nullptr; + + switch (sentinelNode->sentinelType()) { + case SentinelNode::kSentinelFuncEnd: + sentinelName = "[FuncEnd]"; + break; + + default: + sentinelName = "[Sentinel]"; + break; + } + + ASMJIT_PROPAGATE(sb.append(sentinelName)); + break; + } + +#ifndef ASMJIT_NO_COMPILER + case BaseNode::kNodeFunc: { + const FuncNode* funcNode = node->as<FuncNode>(); + + ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, funcNode->labelId())); + ASMJIT_PROPAGATE(sb.append(": ")); + + ASMJIT_PROPAGATE(formatFuncRets(sb, formatFlags, builder, funcNode->detail(), nullptr)); + ASMJIT_PROPAGATE(sb.append(" Func(")); + ASMJIT_PROPAGATE(formatFuncArgs(sb, formatFlags, builder, funcNode->detail(), funcNode->args())); + ASMJIT_PROPAGATE(sb.append(")")); + break; + } + + case BaseNode::kNodeFuncRet: { + const FuncRetNode* retNode = node->as<FuncRetNode>(); + ASMJIT_PROPAGATE(sb.append("[FuncRet]")); + + for (uint32_t i = 0; i < 2; i++) { + const Operand_& op = retNode->_opArray[i]; + if (!op.isNone()) { + ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", ")); + ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, builder, builder->arch(), op)); + } + } + break; + } + + case BaseNode::kNodeInvoke: { + const InvokeNode* invokeNode = node->as<InvokeNode>(); + ASMJIT_PROPAGATE( + formatInstruction(sb, formatFlags, builder, + builder->arch(), + invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount())); + break; + } +#endif + + default: { + ASMJIT_PROPAGATE(sb.appendFormat("[UserNode:%u]", node->type())); + break; + } + } + + return kErrorOk; +} + + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept { + + return formatNodeList(sb, formatFlags, builder, builder->firstNode(), nullptr); +} + +Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept { + + const BaseNode* node = begin; + while (node != end) { + ASMJIT_PROPAGATE(formatNode(sb, formatFlags, builder, node)); + ASMJIT_PROPAGATE(sb.append('\n')); + node = node->next(); + } + return kErrorOk; +} +#endif + +} // {Formatter} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/3rdparty/asmjit/src/asmjit/core/formatter.h b/3rdparty/asmjit/src/asmjit/core/formatter.h new file mode 100644 index 00000000000..81d1c77ccdf --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/formatter.h @@ -0,0 +1,252 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED +#define ASMJIT_CORE_FORMATTER_H_INCLUDED + +#include "../core/inst.h" +#include "../core/string.h" + +#ifndef ASMJIT_NO_LOGGING + +ASMJIT_BEGIN_NAMESPACE + +//! \addtogroup asmjit_logging +//! \{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +class BaseEmitter; +struct Operand_; + +#ifndef ASMJIT_NO_BUILDER +class BaseBuilder; +class BaseNode; +#endif + +// ============================================================================ +// [asmjit::FormatOptions] +// ============================================================================ + +//! Formatting options used by \ref Logger and \ref Formatter. +class FormatOptions { +public: + //! Format flags, see \ref Flags. + uint32_t _flags; + //! Indentation by type, see \ref IndentationType. + uint8_t _indentation[4]; + + //! Flags can enable a logging feature. + enum Flags : uint32_t { + //! No flags. + kNoFlags = 0u, + + //! Show also binary form of each logged instruction (Assembler). + kFlagMachineCode = 0x00000001u, + //! Show a text explanation of some immediate values. + kFlagExplainImms = 0x00000002u, + //! Use hexadecimal notation of immediate values. + kFlagHexImms = 0x00000004u, + //! Use hexadecimal notation of address offsets. + kFlagHexOffsets = 0x00000008u, + //! Show casts between virtual register types (Compiler). + kFlagRegCasts = 0x00000010u, + //! Show positions associated with nodes (Compiler). + kFlagPositions = 0x00000020u, + //! Annotate nodes that are lowered by passes. + kFlagAnnotations = 0x00000040u, + + // TODO: These must go, keep this only for formatting. + //! Show an additional output from passes. + kFlagDebugPasses = 0x00000080u, + //! Show an additional output from RA. + kFlagDebugRA = 0x00000100u + }; + + //! Describes indentation type of code, label, or comment in logger output. + enum IndentationType : uint32_t { + //! Indentation used for instructions and directives. + kIndentationCode = 0u, + //! Indentation used for labels and function nodes. + kIndentationLabel = 1u, + //! Indentation used for comments (not inline comments). + kIndentationComment = 2u, + //! \cond INTERNAL + //! Reserved for future use. + kIndentationReserved = 3u + //! \endcond + }; + + //! \name Construction & Destruction + //! \{ + + //! Creates a default-initialized FormatOptions. + constexpr FormatOptions() noexcept + : _flags(0), + _indentation { 0, 0, 0, 0 } {} + + constexpr FormatOptions(const FormatOptions& other) noexcept = default; + inline FormatOptions& operator=(const FormatOptions& other) noexcept = default; + + //! Resets FormatOptions to its default initialized state. + inline void reset() noexcept { + _flags = 0; + _indentation[0] = 0; + _indentation[1] = 0; + _indentation[2] = 0; + _indentation[3] = 0; + } + + //! \} + + //! \name Accessors + //! \{ + + //! Returns format flags. + constexpr uint32_t flags() const noexcept { return _flags; } + //! Tests whether the given `flag` is set in format flags. + constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + //! Resets all format flags to `flags`. + inline void setFlags(uint32_t flags) noexcept { _flags = flags; } + //! Adds `flags` to format flags. + inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } + //! Removes `flags` from format flags. + inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } + + //! Returns indentation for the given `type`, see \ref IndentationType. + constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; } + //! Sets indentation for the given `type`, see \ref IndentationType. + inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); } + //! Resets indentation for the given `type` to zero. + inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); } + + //! \} +}; + +// ============================================================================ +// [asmjit::Formatter] +// ============================================================================ + +//! Provides formatting functionality to format operands, instructions, and nodes. +namespace Formatter { + +//! Appends a formatted `typeId` to the output string `sb`. +ASMJIT_API Error formatTypeId( + String& sb, + uint32_t typeId) noexcept; + +//! Appends a formatted `featureId` to the output string `sb`. +//! +//! See \ref BaseFeatures. +ASMJIT_API Error formatFeature( + String& sb, + uint32_t arch, + uint32_t featureId) noexcept; + +//! Appends a formatted register to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format virtual registers, +//! which won't be formatted properly if the `emitter` is not provided. +ASMJIT_API Error formatRegister( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept; + +//! Appends a formatted label to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels +//! properly, otherwise the formatted as it is an anonymous label. +ASMJIT_API Error formatLabel( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t labelId) noexcept; + +//! Appends a formatted operand to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatOperand( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept; + +//! Appends a formatted instruction to the output string `sb`. +//! +//! \note Emitter is optional, but it's required to format named labels and +//! virtual registers. See \ref formatRegister() and \ref formatLabel() for +//! more details. +ASMJIT_API Error formatInstruction( + String& sb, + uint32_t formatFlags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept; + +#ifndef ASMJIT_NO_BUILDER +//! Appends a formatted node to the output string `sb`. +//! +//! The `node` must belong to the provided `builder`. +ASMJIT_API Error formatNode( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* node) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! All nodes that are part of the given `builder` will be appended. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder) noexcept; + +//! Appends formatted nodes to the output string `sb`. +//! +//! This function works the same as \ref formatNode(), but appends more nodes +//! to the output string, separating each node with a newline '\n' character. +ASMJIT_API Error formatNodeList( + String& sb, + uint32_t formatFlags, + const BaseBuilder* builder, + const BaseNode* begin, + const BaseNode* end) noexcept; +#endif + +} // {Formatter} + +//! \} + +ASMJIT_END_NAMESPACE + +#endif + +#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/func.cpp b/3rdparty/asmjit/src/asmjit/core/func.cpp index 79eab2e83ad..514ae9db4e1 100644 --- a/3rdparty/asmjit/src/asmjit/core/func.cpp +++ b/3rdparty/asmjit/src/asmjit/core/func.cpp @@ -42,41 +42,41 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::FuncDetail - Init / Reset] // ============================================================================ -ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { - uint32_t ccId = sign.callConv(); - CallConv& cc = _callConv; +ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept { + uint32_t ccId = signature.callConv(); + uint32_t argCount = signature.argCount(); - uint32_t argCount = sign.argCount(); if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs)) return DebugUtils::errored(kErrorInvalidArgument); - ASMJIT_PROPAGATE(cc.init(ccId)); + CallConv& cc = _callConv; + ASMJIT_PROPAGATE(cc.init(ccId, environment)); - uint32_t gpSize = (cc.archId() == ArchInfo::kIdX86) ? 4 : 8; - uint32_t deabstractDelta = Type::deabstractDeltaOfSize(gpSize); + uint32_t registerSize = Environment::registerSizeFromArch(cc.arch()); + uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize); - const uint8_t* args = sign.args(); + const uint8_t* args = signature.args(); for (uint32_t i = 0; i < argCount; i++) { FuncValue& arg = _args[i]; arg.initTypeId(Type::deabstract(args[i], deabstractDelta)); } _argCount = uint8_t(argCount); - _vaIndex = uint8_t(sign.vaIndex()); + _vaIndex = uint8_t(signature.vaIndex()); - uint32_t ret = sign.ret(); + uint32_t ret = signature.ret(); if (ret != Type::kIdVoid) { _rets[0].initTypeId(Type::deabstract(ret, deabstractDelta)); _retCount = 1; } #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) - return x86::X86Internal::initFuncDetail(*this, sign, gpSize); + if (environment.isFamilyX86()) + return x86::X86Internal::initFuncDetail(*this, signature, registerSize); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) - return arm::ArmInternal::initFuncDetail(*this, sign, gpSize); + if (environment.isFamilyARM()) + return arm::ArmInternal::initFuncDetail(*this, signature, registerSize); #endif // We should never bubble here as if `cc.init()` succeeded then there has to @@ -89,15 +89,13 @@ ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& sign) { // ============================================================================ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { - uint32_t ccId = func.callConv().id(); - #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) + if (Environment::isFamilyX86(func.callConv().arch())) return x86::X86Internal::initFuncFrame(*this, func); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) + if (Environment::isFamilyARM(func.callConv().arch())) return arm::ArmInternal::initFuncFrame(*this, func); #endif @@ -106,12 +104,12 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept { ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId())) + if (Environment::isFamilyX86(arch())) return x86::X86Internal::finalizeFuncFrame(*this); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId())) + if (Environment::isFamilyARM(arch())) return arm::ArmInternal::finalizeFuncFrame(*this); #endif @@ -123,18 +121,19 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept { // ============================================================================ ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept { + uint32_t arch = frame.arch(); const FuncDetail* func = funcDetail(); - if (!func) return DebugUtils::errored(kErrorInvalidState); - uint32_t ccId = func->callConv().id(); + if (!func) + return DebugUtils::errored(kErrorInvalidState); #ifdef ASMJIT_BUILD_X86 - if (CallConv::isX86Family(ccId)) + if (Environment::isFamilyX86(arch)) return x86::X86Internal::argsToFuncFrame(*this, frame); #endif #ifdef ASMJIT_BUILD_ARM - if (CallConv::isArmFamily(ccId)) + if (Environment::isFamilyARM(arch)) return arm::ArmInternal::argsToFuncFrame(*this, frame); #endif diff --git a/3rdparty/asmjit/src/asmjit/core/func.h b/3rdparty/asmjit/src/asmjit/core/func.h index 36ebf9bb526..9c45c1f8b3d 100644 --- a/3rdparty/asmjit/src/asmjit/core/func.h +++ b/3rdparty/asmjit/src/asmjit/core/func.h @@ -26,13 +26,14 @@ #include "../core/arch.h" #include "../core/callconv.h" +#include "../core/environment.h" #include "../core/operand.h" #include "../core/type.h" #include "../core/support.h" ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_func +//! \addtogroup asmjit_function //! \{ // ============================================================================ @@ -365,7 +366,7 @@ public: inline FuncDetail(const FuncDetail& other) noexcept = default; //! Initializes this `FuncDetail` to the given signature. - ASMJIT_API Error init(const FuncSignature& sign); + ASMJIT_API Error init(const FuncSignature& signature, const Environment& environment) noexcept; inline void reset() noexcept { memset(this, 0, sizeof(*this)); } //! \} @@ -472,12 +473,13 @@ public: //! frame. The function frame in most cases won't use all of the properties //! illustrated (for example Spill Zone and Red Zone are never used together). //! +//! ``` //! +-----------------------------+ //! | Arguments Passed by Stack | //! +-----------------------------+ //! | Spill Zone | //! +-----------------------------+ <- Stack offset (args) starts from here. -//! | Return Address if Pushed | +//! | Return Address, if Pushed | //! +-----------------------------+ <- Stack pointer (SP) upon entry. //! | Save/Restore Stack. | //! +-----------------------------+-----------------------------+ @@ -487,32 +489,42 @@ public: //! +-----------------------------+-----------------------------+ <- SP after prolog. //! | Red Zone | //! +-----------------------------+ +//! ``` class FuncFrame { public: enum Tag : uint32_t { - kTagInvalidOffset = 0xFFFFFFFFu //!< Tag used to inform that some offset is invalid. + //! Tag used to inform that some offset is invalid. + kTagInvalidOffset = 0xFFFFFFFFu }; //! Attributes are designed in a way that all are initially false, and user //! or FuncFrame finalizer adds them when necessary. enum Attributes : uint32_t { - kAttrHasVarArgs = 0x00000001u, //!< Function has variable number of arguments. - kAttrHasPreservedFP = 0x00000010u, //!< Preserve frame pointer (don't omit FP). - kAttrHasFuncCalls = 0x00000020u, //!< Function calls other functions (is not leaf). - - kAttrX86AvxEnabled = 0x00010000u, //!< Use AVX instead of SSE for all operations (X86). - kAttrX86AvxCleanup = 0x00020000u, //!< Emit VZEROUPPER instruction in epilog (X86). - kAttrX86MmxCleanup = 0x00040000u, //!< Emit EMMS instruction in epilog (X86). - - kAttrAlignedVecSR = 0x40000000u, //!< Function has aligned save/restore of vector registers. - kAttrIsFinalized = 0x80000000u //!< FuncFrame is finalized and can be used by PEI. + //! Function has variable number of arguments. + kAttrHasVarArgs = 0x00000001u, + //! Preserve frame pointer (don't omit FP). + kAttrHasPreservedFP = 0x00000010u, + //! Function calls other functions (is not leaf). + kAttrHasFuncCalls = 0x00000020u, + + //! Use AVX instead of SSE for all operations (X86). + kAttrX86AvxEnabled = 0x00010000u, + //! Emit VZEROUPPER instruction in epilog (X86). + kAttrX86AvxCleanup = 0x00020000u, + //! Emit EMMS instruction in epilog (X86). + kAttrX86MmxCleanup = 0x00040000u, + + //! Function has aligned save/restore of vector registers. + kAttrAlignedVecSR = 0x40000000u, + //! FuncFrame is finalized and can be used by PEI. + kAttrIsFinalized = 0x80000000u }; //! Function attributes. uint32_t _attributes; - //! Architecture ID. - uint8_t _archId; + //! Architecture, see \ref Environment::Arch. + uint8_t _arch; //! SP register ID (to access call stack and local stack). uint8_t _spRegId; //! SA register ID (to access stack arguments). @@ -591,7 +603,7 @@ public: //! \{ //! Returns the target architecture of the function frame. - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } //! Returns function frame attributes, see `Attributes`. inline uint32_t attributes() const noexcept { return _attributes; } @@ -784,10 +796,8 @@ public: } inline void setAllDirty() noexcept { - _dirtyRegs[0] = 0xFFFFFFFFu; - _dirtyRegs[1] = 0xFFFFFFFFu; - _dirtyRegs[2] = 0xFFFFFFFFu; - _dirtyRegs[3] = 0xFFFFFFFFu; + for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_dirtyRegs); i++) + _dirtyRegs[i] = 0xFFFFFFFFu; } inline void setAllDirty(uint32_t group) noexcept { diff --git a/3rdparty/asmjit/src/asmjit/core/globals.cpp b/3rdparty/asmjit/src/asmjit/core/globals.cpp index 426fce8f533..7ec66283e80 100644 --- a/3rdparty/asmjit/src/asmjit/core/globals.cpp +++ b/3rdparty/asmjit/src/asmjit/core/globals.cpp @@ -33,75 +33,88 @@ ASMJIT_BEGIN_NAMESPACE ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept { #ifndef ASMJIT_NO_TEXT - static const char errorMessages[] = + // @EnumStringBegin{"enum": "ErrorCode", "output": "sError", "strip": "kError"}@ + static const char sErrorString[] = "Ok\0" - "Out of memory\0" - "Invalid argument\0" - "Invalid state\0" - "Invalid architecture\0" - "Not initialized\0" - "Already initialized\0" - "Feature not enabled\0" - "Too many handles or file descriptors\0" - "Too large (code or memory request)\0" - "No code generated\0" - "Invalid directive\0" - "Invalid label\0" - "Too many labels\0" - "Label already bound\0" - "Label already defined\0" - "Label name too long\0" - "Invalid label name\0" - "Invalid parent label\0" - "Non-local label can't have parent\0" - "Invalid section\0" - "Too many sections\0" - "Invalid section name\0" - "Too many relocations\0" - "Invalid relocation entry\0" - "Relocation offset out of range\0" - "Invalid assignment\0" - "Invalid instruction\0" - "Invalid register type\0" - "Invalid register group\0" - "Invalid register physical id\0" - "Invalid register virtual id\0" - "Invalid prefix combination\0" - "Invalid lock prefix\0" - "Invalid xacquire prefix\0" - "Invalid xrelease prefix\0" - "Invalid rep prefix\0" - "Invalid rex prefix\0" - "Invalid {...} register \0" - "Invalid use of {k}\0" - "Invalid use of {k}{z}\0" - "Invalid broadcast {1tox}\0" - "Invalid {er} or {sae} option\0" - "Invalid address\0" - "Invalid address index\0" - "Invalid address scale\0" - "Invalid use of 64-bit address or offset\0" - "Invalid use of 64-bit address or offset that requires 32-bit zero-extension\0" - "Invalid displacement\0" - "Invalid segment\0" - "Invalid immediate value\0" - "Invalid operand size\0" - "Ambiguous operand size\0" - "Operand size mismatch\0" - "Invalid option\0" - "Option already defined\0" - "Invalid type-info\0" - "Invalid use of a low 8-bit GPB register\0" - "Invalid use of a 64-bit GPQ register in 32-bit mode\0" - "Invalid use of an 80-bit float\0" - "Not consecutive registers\0" - "No more physical registers\0" - "Overlapped registers\0" - "Overlapping register and arguments base-address register\0" - "Unbound label cannot be evaluated by expression\0" - "Arithmetic overflow during expression evaluation\0" - "Unknown error\0"; - return Support::findPackedString(errorMessages, Support::min<Error>(err, kErrorCount)); + "OutOfMemory\0" + "InvalidArgument\0" + "InvalidState\0" + "InvalidArch\0" + "NotInitialized\0" + "AlreadyInitialized\0" + "FeatureNotEnabled\0" + "TooManyHandles\0" + "TooLarge\0" + "NoCodeGenerated\0" + "InvalidDirective\0" + "InvalidLabel\0" + "TooManyLabels\0" + "LabelAlreadyBound\0" + "LabelAlreadyDefined\0" + "LabelNameTooLong\0" + "InvalidLabelName\0" + "InvalidParentLabel\0" + "NonLocalLabelCannotHaveParent\0" + "InvalidSection\0" + "TooManySections\0" + "InvalidSectionName\0" + "TooManyRelocations\0" + "InvalidRelocEntry\0" + "RelocOffsetOutOfRange\0" + "InvalidAssignment\0" + "InvalidInstruction\0" + "InvalidRegType\0" + "InvalidRegGroup\0" + "InvalidPhysId\0" + "InvalidVirtId\0" + "InvalidPrefixCombination\0" + "InvalidLockPrefix\0" + "InvalidXAcquirePrefix\0" + "InvalidXReleasePrefix\0" + "InvalidRepPrefix\0" + "InvalidRexPrefix\0" + "InvalidExtraReg\0" + "InvalidKMaskUse\0" + "InvalidKZeroUse\0" + "InvalidBroadcast\0" + "InvalidEROrSAE\0" + "InvalidAddress\0" + "InvalidAddressIndex\0" + "InvalidAddressScale\0" + "InvalidAddress64Bit\0" + "InvalidAddress64BitZeroExtension\0" + "InvalidDisplacement\0" + "InvalidSegment\0" + "InvalidImmediate\0" + "InvalidOperandSize\0" + "AmbiguousOperandSize\0" + "OperandSizeMismatch\0" + "InvalidOption\0" + "OptionAlreadyDefined\0" + "InvalidTypeId\0" + "InvalidUseOfGpbHi\0" + "InvalidUseOfGpq\0" + "InvalidUseOfF80\0" + "NotConsecutiveRegs\0" + "IllegalVirtReg\0" + "TooManyVirtRegs\0" + "NoMorePhysRegs\0" + "OverlappedRegs\0" + "OverlappingStackRegWithRegArg\0" + "ExpressionLabelNotBound\0" + "ExpressionOverflow\0" + "<Unknown>\0"; + + static const uint16_t sErrorIndex[] = { + 0, 3, 15, 31, 44, 56, 71, 90, 108, 123, 132, 148, 165, 178, 192, 210, 230, + 247, 264, 283, 313, 328, 344, 363, 382, 400, 422, 440, 459, 474, 490, 504, + 518, 543, 561, 583, 605, 622, 639, 655, 671, 687, 704, 719, 734, 754, 774, + 794, 827, 847, 862, 879, 898, 919, 939, 953, 974, 988, 1006, 1022, 1038, + 1057, 1072, 1088, 1103, 1118, 1148, 1172, 1191 + }; + // @EnumStringEnd@ + + return sErrorString + sErrorIndex[Support::min<Error>(err, kErrorCount)]; #else DebugUtils::unused(err); static const char noMessage[] = ""; diff --git a/3rdparty/asmjit/src/asmjit/core/globals.h b/3rdparty/asmjit/src/asmjit/core/globals.h index 6373b7e8c6a..67a8769a403 100644 --- a/3rdparty/asmjit/src/asmjit/core/globals.h +++ b/3rdparty/asmjit/src/asmjit/core/globals.h @@ -33,7 +33,7 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ //! \cond INTERNAL -//! \addtogroup Support +//! \addtogroup asmjit_utilities //! \{ namespace Support { //! Cast designed to cast between function and void* pointers. @@ -88,9 +88,9 @@ constexpr uint32_t kAllocAlignment = 8; //! Aggressive growing strategy threshold. constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16; -//! Maximum height of RB-Tree is: +//! Maximum depth of RB-Tree is: //! -//! `2 * log2(n + 1)`. +//! `2 * log2(n + 1)` //! //! Size of RB node is at least two pointers (without data), //! so a theoretical architecture limit would be: @@ -104,7 +104,7 @@ constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1; //! Maximum number of operands per a single instruction. constexpr uint32_t kMaxOpCount = 6; -// TODO: Use this one. +//! Maximum arguments of a function supported by the Compiler / Function API. constexpr uint32_t kMaxFuncArgs = 16; //! Maximum number of physical registers AsmJit can use per register group. @@ -169,14 +169,45 @@ static const constexpr NoInit_ NoInit {}; } // {Globals} // ============================================================================ +// [asmjit::ByteOrder] +// ============================================================================ + +//! Byte order. +namespace ByteOrder { + enum : uint32_t { + kLE = 0, + kBE = 1, + kNative = ASMJIT_ARCH_LE ? kLE : kBE, + kSwapped = ASMJIT_ARCH_LE ? kBE : kLE + }; +} + +// ============================================================================ +// [asmjit::ptr_as_func / func_as_ptr] +// ============================================================================ + +template<typename Func> +static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); } + +template<typename Func> +static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl<void*, Func>(func); } + +//! \} + +// ============================================================================ // [asmjit::Error] // ============================================================================ +//! \addtogroup asmjit_error_handling +//! \{ + //! AsmJit error type (uint32_t). typedef uint32_t Error; //! AsmJit error codes. enum ErrorCode : uint32_t { + // @EnumValuesBegin{"enum": "ErrorCode"}@ + //! No error (success). kErrorOk = 0, @@ -211,16 +242,16 @@ enum ErrorCode : uint32_t { //! No code generated. //! - //! Returned by runtime if the `CodeHolder` contains no code. + //! Returned by runtime if the \ref CodeHolder contains no code. kErrorNoCodeGenerated, //! Invalid directive. kErrorInvalidDirective, //! Attempt to use uninitialized label. kErrorInvalidLabel, - //! Label index overflow - a single `Assembler` instance can hold almost - //! 2^32 (4 billion) labels. If there is an attempt to create more labels - //! then this error is returned. + //! Label index overflow - a single \ref BaseAssembler instance can hold + //! almost 2^32 (4 billion) labels. If there is an attempt to create more + //! labels then this error is returned. kErrorTooManyLabels, //! Label is already bound. kErrorLabelAlreadyBound, @@ -230,10 +261,10 @@ enum ErrorCode : uint32_t { kErrorLabelNameTooLong, //! Label must always be local if it's anonymous (without a name). kErrorInvalidLabelName, - //! Parent id passed to `CodeHolder::newNamedLabelId()` was invalid. + //! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was invalid. kErrorInvalidParentLabel, //! Parent id specified for a non-local (global) label. - kErrorNonLocalLabelCantHaveParent, + kErrorNonLocalLabelCannotHaveParent, //! Invalid section. kErrorInvalidSection, @@ -257,9 +288,9 @@ enum ErrorCode : uint32_t { kErrorInvalidRegType, //! Invalid register group. kErrorInvalidRegGroup, - //! Invalid register's physical id. + //! Invalid physical register id. kErrorInvalidPhysId, - //! Invalid register's virtual id. + //! Invalid virtual register id. kErrorInvalidVirtId, //! Invalid prefix combination. kErrorInvalidPrefixCombination, @@ -319,11 +350,17 @@ enum ErrorCode : uint32_t { kErrorInvalidUseOfGpbHi, //! Invalid use of a 64-bit GPQ register in 32-bit mode. kErrorInvalidUseOfGpq, - //! Invalid use of an 80-bit float (Type::kIdF80). + //! Invalid use of an 80-bit float (\ref Type::kIdF80). kErrorInvalidUseOfF80, - //! Some registers in the instruction muse be consecutive (some ARM and AVX512 neural-net instructions). + //! Some registers in the instruction muse be consecutive (some ARM and AVX512 + //! neural-net instructions). kErrorNotConsecutiveRegs, + //! Illegal virtual register - reported by instruction validation. + kErrorIllegalVirtReg, + //! AsmJit cannot create more virtual registers. + kErrorTooManyVirtRegs, + //! AsmJit requires a physical register, but no one is available. kErrorNoMorePhysRegs, //! A variable has been assigned more than once to a function argument (BaseCompiler). @@ -336,43 +373,24 @@ enum ErrorCode : uint32_t { //! Arithmetic overflow during expression evaluation. kErrorExpressionOverflow, + // @EnumValuesEnd@ + //! Count of AsmJit error codes. kErrorCount }; // ============================================================================ -// [asmjit::ByteOrder] -// ============================================================================ - -//! Byte order. -namespace ByteOrder { - enum : uint32_t { - kLE = 0, - kBE = 1, - kNative = ASMJIT_ARCH_LE ? kLE : kBE, - kSwapped = ASMJIT_ARCH_LE ? kBE : kLE - }; -} - -// ============================================================================ -// [asmjit::ptr_as_func / func_as_ptr] -// ============================================================================ - -template<typename Func> -static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); } -template<typename Func> -static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl<void*, Func>(func); } - -// ============================================================================ // [asmjit::DebugUtils] // ============================================================================ //! Debugging utilities. namespace DebugUtils { +//! \cond INTERNAL //! Used to silence warnings about unused arguments or variables. template<typename... Args> static ASMJIT_INLINE void unused(Args&&...) noexcept {} +//! \endcond //! Returns the error `err` passed. //! @@ -392,23 +410,35 @@ ASMJIT_API void debugOutput(const char* str) noexcept; //! \param line Line in the source file. //! \param msg Message to display. //! -//! If you have problems with assertions put a breakpoint at assertionFailed() -//! function (asmjit/core/globals.cpp) and check the call stack to locate the -//! failing code. +//! If you have problems with assertion failures a breakpoint can be put +//! at \ref assertionFailed() function (asmjit/core/globals.cpp). A call stack +//! will be available when such assertion failure is triggered. AsmJit always +//! returns errors on failures, assertions are a last resort and usually mean +//! unrecoverable state due to out of range array access or totally invalid +//! arguments like nullptr where a valid pointer should be provided, etc... ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept; +} // {DebugUtils} + +//! \def ASMJIT_ASSERT(...) +//! +//! AsmJit's own assert macro used in AsmJit code-base. #if defined(ASMJIT_BUILD_DEBUG) -#define ASMJIT_ASSERT(EXP) \ +#define ASMJIT_ASSERT(...) \ do { \ - if (ASMJIT_LIKELY(EXP)) \ + if (ASMJIT_LIKELY(__VA_ARGS__)) \ break; \ - ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #EXP); \ + ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \ } while (0) #else -#define ASMJIT_ASSERT(EXP) ((void)0) +#define ASMJIT_ASSERT(...) ((void)0) #endif -//! Used by AsmJit to propagate a possible `Error` produced by `...` to the caller. +//! \def ASMJIT_PROPAGATE(...) +//! +//! Propagates a possible `Error` produced by `...` to the caller by returning +//! the error immediately. Used by AsmJit internally, but kept public for users +//! that want to use the same technique to propagate errors to the caller. #define ASMJIT_PROPAGATE(...) \ do { \ ::asmjit::Error _err = __VA_ARGS__; \ @@ -416,8 +446,6 @@ ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, cons return _err; \ } while (0) -} // {DebugUtils} - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/inst.cpp b/3rdparty/asmjit/src/asmjit/core/inst.cpp index d89c29f1917..a233b9383bf 100644 --- a/3rdparty/asmjit/src/asmjit/core/inst.cpp +++ b/3rdparty/asmjit/src/asmjit/core/inst.cpp @@ -42,29 +42,29 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ #ifndef ASMJIT_NO_TEXT -Error InstAPI::instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept { +Error InstAPI::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::instIdToString(archId, instId, output); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::instIdToString(arch, instId, output); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::instIdToString(archId, instId, output); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::instIdToString(arch, instId, output); #endif return DebugUtils::errored(kErrorInvalidArch); } -uint32_t InstAPI::stringToInstId(uint32_t archId, const char* s, size_t len) noexcept { +uint32_t InstAPI::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::stringToInstId(archId, s, len); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::stringToInstId(arch, s, len); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::stringToInstId(archId, s, len); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::stringToInstId(arch, s, len); #endif return 0; @@ -76,15 +76,15 @@ uint32_t InstAPI::stringToInstId(uint32_t archId, const char* s, size_t len) noe // ============================================================================ #ifndef ASMJIT_NO_VALIDATION -Error InstAPI::validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { +Error InstAPI::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::validate(archId, inst, operands, opCount); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::validate(archId, inst, operands, opCount); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::validate(arch, inst, operands, opCount, validationFlags); #endif return DebugUtils::errored(kErrorInvalidArch); @@ -96,18 +96,18 @@ Error InstAPI::validate(uint32_t archId, const BaseInst& inst, const Operand_* o // ============================================================================ #ifndef ASMJIT_NO_INTROSPECTION -Error InstAPI::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept { - if (ASMJIT_UNLIKELY(opCount > 6)) +Error InstAPI::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { + if (ASMJIT_UNLIKELY(opCount > Globals::kMaxOpCount)) return DebugUtils::errored(kErrorInvalidArgument); #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::queryRWInfo(archId, inst, operands, opCount, out); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::queryRWInfo(archId, inst, operands, opCount, out); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::queryRWInfo(arch, inst, operands, opCount, out); #endif return DebugUtils::errored(kErrorInvalidArch); @@ -119,15 +119,15 @@ Error InstAPI::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_ // ============================================================================ #ifndef ASMJIT_NO_INTROSPECTION -Error InstAPI::queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept { +Error InstAPI::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept { #ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::InstInternal::queryFeatures(archId, inst, operands, opCount, out); + if (Environment::isFamilyX86(arch)) + return x86::InstInternal::queryFeatures(arch, inst, operands, opCount, out); #endif #ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::InstInternal::queryFeatures(archId, inst, operands, opCount, out); + if (Environment::isFamilyARM(arch)) + return arm::InstInternal::queryFeatures(arch, inst, operands, opCount, out); #endif return DebugUtils::errored(kErrorInvalidArch); diff --git a/3rdparty/asmjit/src/asmjit/core/inst.h b/3rdparty/asmjit/src/asmjit/core/inst.h index 91671822043..e34f93c87f1 100644 --- a/3rdparty/asmjit/src/asmjit/core/inst.h +++ b/3rdparty/asmjit/src/asmjit/core/inst.h @@ -31,45 +31,173 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_core +//! \addtogroup asmjit_instruction_db //! \{ // ============================================================================ -// [asmjit::InstInfo] +// [asmjit::BaseInst] // ============================================================================ -// TODO: Finalize instruction info and make more x86::InstDB methods/structs private. +//! Instruction id, options, and extraReg in a single structure. This structure +//! exists mainly to simplify analysis and validation API that requires `BaseInst` +//! and `Operand[]` array. +class BaseInst { +public: + //! Instruction id, see \ref BaseInst::Id or {arch-specific}::Inst::Id. + uint32_t _id; + //! Instruction options, see \ref BaseInst::Options or {arch-specific}::Inst::Options. + uint32_t _options; + //! Extra register used by instruction (either REP register or AVX-512 selector). + RegOnly _extraReg; -/* + enum Id : uint32_t { + //! Invalid or uninitialized instruction id. + kIdNone = 0x00000000u, + //! Abstract instruction (BaseBuilder and BaseCompiler). + kIdAbstract = 0x80000000u + }; + + enum Options : uint32_t { + //! Used internally by emitters for handling errors and rare cases. + kOptionReserved = 0x00000001u, + + //! Prevents following a jump during compilation (BaseCompiler). + kOptionUnfollow = 0x00000010u, -struct InstInfo { - //! Architecture agnostic attributes. - enum Attributes : uint32_t { + //! Overwrite the destination operand(s) (BaseCompiler). + //! + //! Hint that is important for register liveness analysis. It tells the + //! compiler that the destination operand will be overwritten now or by + //! adjacent instructions. BaseCompiler knows when a register is completely + //! overwritten by a single instruction, for example you don't have to + //! mark "movaps" or "pxor x, x", however, if a pair of instructions is + //! used and the first of them doesn't completely overwrite the content + //! of the destination, BaseCompiler fails to mark that register as dead. + //! + //! X86 Specific + //! ------------ + //! + //! - All instructions that always overwrite at least the size of the + //! register the virtual-register uses , for example "mov", "movq", + //! "movaps" don't need the overwrite option to be used - conversion, + //! shuffle, and other miscellaneous instructions included. + //! + //! - All instructions that clear the destination register if all operands + //! are the same, for example "xor x, x", "pcmpeqb x x", etc... + //! + //! - Consecutive instructions that partially overwrite the variable until + //! there is no old content require `BaseCompiler::overwrite()` to be used. + //! Some examples (not always the best use cases thought): + //! + //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa + //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa + //! - `mov al, ?` followed by `and ax, 0xFF` + //! - `mov al, ?` followed by `mov ah, al` + //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` + //! + //! - If allocated variable is used temporarily for scalar operations. For + //! example if you allocate a full vector like `x86::Compiler::newXmm()` + //! and then use that vector for scalar operations you should use + //! `overwrite()` directive: + //! + //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't + //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. + kOptionOverwrite = 0x00000020u, + //! Emit short-form of the instruction. + kOptionShortForm = 0x00000040u, + //! Emit long-form of the instruction. + kOptionLongForm = 0x00000080u, + //! Conditional jump is likely to be taken. + kOptionTaken = 0x00000100u, + //! Conditional jump is unlikely to be taken. + kOptionNotTaken = 0x00000200u }; - //! Instruction attributes. - uint32_t _attributes; + //! Control type. + enum ControlType : uint32_t { + //! No control type (doesn't jump). + kControlNone = 0u, + //! Unconditional jump. + kControlJump = 1u, + //! Conditional jump (branch). + kControlBranch = 2u, + //! Function call. + kControlCall = 3u, + //! Function return. + kControlReturn = 4u + }; - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! \name Construction & Destruction + //! \{ - inline uint32_t attributes() const noexcept { return _attributes; } - inline bool hasAttribute(uint32_t attr) const noexcept { return (_attributes & attr) != 0; } -}; + //! Creates a new BaseInst instance with `id` and `options` set. + //! + //! Default values of `id` and `options` are zero, which means none instruciton. + //! Such instruction is guaranteed to never exist for any architecture supported + //! by AsmJit. + inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept + : _id(id), + _options(options), + _extraReg() {} + + inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept + : _id(id), + _options(options), + _extraReg(extraReg) {} + + inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept + : _id(id), + _options(options), + _extraReg { extraReg.signature(), extraReg.id() } {} + + //! \} -//! Gets attributes of the given instruction. -ASMJIT_API Error queryCommonInfo(uint32_t archId, uint32_t instId, InstInfo& out) noexcept; + //! \name Instruction ID + //! \{ + + //! Returns the instruction id. + inline uint32_t id() const noexcept { return _id; } + //! Sets the instruction id to the given `id`. + inline void setId(uint32_t id) noexcept { _id = id; } + //! Resets the instruction id to zero, see \ref kIdNone. + inline void resetId() noexcept { _id = 0; } + + //! \} -*/ + //! \name Instruction Options + //! \{ + + inline uint32_t options() const noexcept { return _options; } + inline bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; } + inline void setOptions(uint32_t options) noexcept { _options = options; } + inline void addOptions(uint32_t options) noexcept { _options |= options; } + inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } + inline void resetOptions() noexcept { _options = 0; } + + //! \} + + //! \name Extra Register + //! \{ + + inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } + inline RegOnly& extraReg() noexcept { return _extraReg; } + inline const RegOnly& extraReg() const noexcept { return _extraReg; } + inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } + inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } + inline void resetExtraReg() noexcept { _extraReg.reset(); } + + //! \} +}; // ============================================================================ -// [asmjit::InstRWInfo / OpRWInfo] +// [asmjit::OpRWInfo] // ============================================================================ -//! Read/Write information related to a single operand, used by `InstRWInfo`. +//! Read/Write information related to a single operand, used by \ref InstRWInfo. struct OpRWInfo { - //! Read/Write flags, see `OpRWInfo::Flags`. + //! Read/Write flags, see \ref OpRWInfo::Flags. uint32_t _opFlags; //! Physical register index, if required. uint8_t _physId; @@ -87,18 +215,12 @@ struct OpRWInfo { //! Flags describe how the operand is accessed and some additional information. enum Flags : uint32_t { //! Operand is read. - //! - //! \note This flag must be `0x00000001`. kRead = 0x00000001u, //! Operand is written. - //! - //! \note This flag must be `0x00000002`. kWrite = 0x00000002u, //! Operand is both read and written. - //! - //! \note This combination of flags must be `0x00000003`. kRW = 0x00000003u, //! Register operand can be replaced by a memory operand. @@ -107,9 +229,9 @@ struct OpRWInfo { //! The `extendByteMask()` represents a zero extension. kZExt = 0x00000010u, - //! Register operand must use `physId()`. + //! Register operand must use \ref physId(). kRegPhysId = 0x00000100u, - //! Base register of a memory operand must use `physId()`. + //! Base register of a memory operand must use \ref physId(). kMemPhysId = 0x00000200u, //! This memory operand is only used to encode registers and doesn't access memory. @@ -140,6 +262,8 @@ struct OpRWInfo { kMemBasePostModify = 0x00020000u }; + // Don't remove these asserts. Read/Write flags are used extensively + // by Compiler and they must always be compatible with constants below. static_assert(kRead == 0x1, "OpRWInfo::kRead flag must be 0x1"); static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2"); static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4"); @@ -147,7 +271,11 @@ struct OpRWInfo { //! \name Reset //! \{ + //! Resets this operand information to all zeros. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + + //! Resets this operand info (resets all members) and set common information + //! to the given `opFlags`, `regSize`, and possibly `physId`. inline void reset(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept { _opFlags = opFlags; _physId = uint8_t(physId); @@ -169,35 +297,96 @@ struct OpRWInfo { //! \name Operand Flags //! \{ + //! Returns operand flags, see \ref Flags. inline uint32_t opFlags() const noexcept { return _opFlags; } + //! Tests whether operand flags contain the given `flag`. inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; } + //! Adds the given `flags` to operand flags. inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; } + //! Removes the given `flags` from operand flags. inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; } + //! Tests whether this operand is read from. inline bool isRead() const noexcept { return hasOpFlag(kRead); } + //! Tests whether this operand is written to. inline bool isWrite() const noexcept { return hasOpFlag(kWrite); } + //! Tests whether this operand is both read and write. inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; } + //! Tests whether this operand is read only. inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; } + //! Tests whether this operand is write only. inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; } + + //! Tests whether this operand is Reg/Mem + //! + //! Reg/Mem operands can use either register or memory. inline bool isRm() const noexcept { return hasOpFlag(kRegMem); } + + //! Tests whether the operand will be zero extended. inline bool isZExt() const noexcept { return hasOpFlag(kZExt); } //! \} + //! \name Memory Flags + //! \{ + + //! Tests whether this is a fake memory operand, which is only used, because + //! of encoding. Fake memory operands do not access any memory, they are only + //! used to encode registers. + inline bool isMemFake() const noexcept { return hasOpFlag(kMemFake); } + + //! Tests whether the instruction reads from its BASE registers. + inline bool isMemBaseRead() const noexcept { return hasOpFlag(kMemBaseRead); } + //! Tests whether the instruction writes to its BASE registers. + inline bool isMemBaseWrite() const noexcept { return hasOpFlag(kMemBaseWrite); } + //! Tests whether the instruction reads and writes from/to its BASE registers. + inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRW; } + //! Tests whether the instruction only reads from its BASE registers. + inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRead; } + //! Tests whether the instruction only writes to its BASE registers. + inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseWrite; } + + //! Tests whether the instruction modifies the BASE register before it uses + //! it to calculate the target address. + inline bool isMemBasePreModify() const noexcept { return hasOpFlag(kMemBasePreModify); } + //! Tests whether the instruction modifies the BASE register after it uses + //! it to calculate the target address. + inline bool isMemBasePostModify() const noexcept { return hasOpFlag(kMemBasePostModify); } + + //! Tests whether the instruction reads the INDEX registers. + inline bool isMemIndexRead() const noexcept { return hasOpFlag(kMemIndexRead); } + //! Tests whether the instruction writes to its INDEX registers. + inline bool isMemIndexWrite() const noexcept { return hasOpFlag(kMemIndexWrite); } + //! Tests whether the instruction reads and writes from/to its INDEX registers. + inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRW; } + //! Tests whether the instruction only reads from its INDEX registers. + inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRead; } + //! Tests whether the instruction only writes to its INDEX registers. + inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexWrite; } + + //! \} + //! \name Physical Register ID //! \{ + //! Returns a physical id of the register that is fixed for this operand. + //! + //! Returns \ref BaseReg::kIdBad if any register can be used. inline uint32_t physId() const noexcept { return _physId; } + //! Tests whether \ref physId() would return a valid physical register id. inline bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; } + //! Sets physical register id, which would be fixed for this operand. inline void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); } //! \} - //! \name Reg/Mem + //! \name Reg/Mem Information //! \{ + //! Returns Reg/Mem size of the operand. inline uint32_t rmSize() const noexcept { return _rmSize; } + //! Sets Reg/Mem size of the operand. inline void setRmSize(uint32_t rmSize) noexcept { _rmSize = uint8_t(rmSize); } //! \} @@ -205,46 +394,76 @@ struct OpRWInfo { //! \name Read & Write Masks //! \{ + //! Returns read mask. inline uint64_t readByteMask() const noexcept { return _readByteMask; } + //! Returns write mask. inline uint64_t writeByteMask() const noexcept { return _writeByteMask; } + //! Returns extend mask. inline uint64_t extendByteMask() const noexcept { return _extendByteMask; } + //! Sets read mask. inline void setReadByteMask(uint64_t mask) noexcept { _readByteMask = mask; } + //! Sets write mask. inline void setWriteByteMask(uint64_t mask) noexcept { _writeByteMask = mask; } + //! Sets externd mask. inline void setExtendByteMask(uint64_t mask) noexcept { _extendByteMask = mask; } //! \} }; +// ============================================================================ +// [asmjit::InstRWInfo] +// ============================================================================ + //! Read/Write information of an instruction. struct InstRWInfo { - //! Instruction flags. + //! Instruction flags (there are no flags at the moment, this field is reserved). uint32_t _instFlags; - //! Mask of flags read. + //! Mask of CPU flags read. uint32_t _readFlags; - //! Mask of flags written. + //! Mask of CPU flags written. uint32_t _writeFlags; //! Count of operands. uint8_t _opCount; //! CPU feature required for replacing register operand with memory operand. uint8_t _rmFeature; //! Reserved for future use. - uint8_t _reserved[19]; + uint8_t _reserved[18]; //! Read/Write onfo of extra register (rep{} or kz{}). OpRWInfo _extraReg; //! Read/Write info of instruction operands. OpRWInfo _operands[Globals::kMaxOpCount]; + //! \name Commons + //! \{ + + //! Resets this RW information to all zeros. inline void reset() noexcept { memset(this, 0, sizeof(*this)); } + //! \} + + //! \name Instruction Flags + //! + //! \{ + inline uint32_t instFlags() const noexcept { return _instFlags; } inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; } - inline uint32_t opCount() const noexcept { return _opCount; } + //! } + //! \name CPU Flags Read/Write Information + //! \{ + + //! Returns read flags of the instruction. inline uint32_t readFlags() const noexcept { return _readFlags; } + //! Returns write flags of the instruction. inline uint32_t writeFlags() const noexcept { return _writeFlags; } + //! \} + + //! \name Reg/Mem Information + //! \{ + //! Returns the CPU feature required to replace a register operand with memory //! operand. If the returned feature is zero (none) then this instruction //! either doesn't provide memory operand combination or there is no extra @@ -259,166 +478,25 @@ struct InstRWInfo { //! 'reg/mem/imm' combination. inline uint32_t rmFeature() const noexcept { return _rmFeature; } + //! \} + + //! \name Operand Read/Write Information + //! \{ + + //! Returns RW information of extra register operand (extraReg). inline const OpRWInfo& extraReg() const noexcept { return _extraReg; } + + //! Returns RW information of all instruction's operands. inline const OpRWInfo* operands() const noexcept { return _operands; } + //! Returns RW information of the operand at the given `index`. inline const OpRWInfo& operand(size_t index) const noexcept { ASMJIT_ASSERT(index < Globals::kMaxOpCount); return _operands[index]; } -}; - -// ============================================================================ -// [asmjit::BaseInst] -// ============================================================================ - -//! Instruction id, options, and extraReg in a single structure. This structure -//! exists mainly to simplify analysis and validation API that requires `BaseInst` -//! and `Operand[]` array. -class BaseInst { -public: - //! Instruction id. - uint32_t _id; - //! Instruction options. - uint32_t _options; - //! Extra register used by instruction (either REP register or AVX-512 selector). - RegOnly _extraReg; - - enum Id : uint32_t { - //! Invalid or uninitialized instruction id. - kIdNone = 0x00000000u, - //! Abstract instruction (BaseBuilder and BaseCompiler). - kIdAbstract = 0x80000000u - }; - - enum Options : uint32_t { - //! Used internally by emitters for handling errors and rare cases. - kOptionReserved = 0x00000001u, - - //! Used only by Assembler to mark that `_op4` and `_op5` are used (internal). - //! - //! TODO: This should be removed in the future. - kOptionOp4Op5Used = 0x00000002u, - - //! Prevents following a jump during compilation (BaseCompiler). - //! - //! TODO: This should be renamed to kOptionNoReturn. - kOptionUnfollow = 0x00000010u, - - //! Overwrite the destination operand(s) (BaseCompiler). - //! - //! Hint that is important for register liveness analysis. It tells the - //! compiler that the destination operand will be overwritten now or by - //! adjacent instructions. BaseCompiler knows when a register is completely - //! overwritten by a single instruction, for example you don't have to - //! mark "movaps" or "pxor x, x", however, if a pair of instructions is - //! used and the first of them doesn't completely overwrite the content - //! of the destination, BaseCompiler fails to mark that register as dead. - //! - //! X86 Specific - //! ------------ - //! - //! - All instructions that always overwrite at least the size of the - //! register the virtual-register uses , for example "mov", "movq", - //! "movaps" don't need the overwrite option to be used - conversion, - //! shuffle, and other miscellaneous instructions included. - //! - //! - All instructions that clear the destination register if all operands - //! are the same, for example "xor x, x", "pcmpeqb x x", etc... - //! - //! - Consecutive instructions that partially overwrite the variable until - //! there is no old content require `BaseCompiler::overwrite()` to be used. - //! Some examples (not always the best use cases thought): - //! - //! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa - //! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa - //! - `mov al, ?` followed by `and ax, 0xFF` - //! - `mov al, ?` followed by `mov ah, al` - //! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1` - //! - //! - If allocated variable is used temporarily for scalar operations. For - //! example if you allocate a full vector like `x86::Compiler::newXmm()` - //! and then use that vector for scalar operations you should use - //! `overwrite()` directive: - //! - //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't - //! use HI elements, use `compiler.overwrite().sqrtss(x, y)`. - kOptionOverwrite = 0x00000020u, - - //! Emit short-form of the instruction. - kOptionShortForm = 0x00000040u, - //! Emit long-form of the instruction. - kOptionLongForm = 0x00000080u, - - //! Conditional jump is likely to be taken. - kOptionTaken = 0x00000100u, - //! Conditional jump is unlikely to be taken. - kOptionNotTaken = 0x00000200u - }; - - //! Control type. - enum ControlType : uint32_t { - //! No control type (doesn't jump). - kControlNone = 0u, - //! Unconditional jump. - kControlJump = 1u, - //! Conditional jump (branch). - kControlBranch = 2u, - //! Function call. - kControlCall = 3u, - //! Function return. - kControlReturn = 4u - }; - - //! \name Construction & Destruction - //! \{ - inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept - : _id(id), - _options(options), - _extraReg() {} - - inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept - : _id(id), - _options(options), - _extraReg(extraReg) {} - - inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept - : _id(id), - _options(options), - _extraReg { extraReg.signature(), extraReg.id() } {} - - //! \} - - //! \name Instruction ID - //! \{ - - inline uint32_t id() const noexcept { return _id; } - inline void setId(uint32_t id) noexcept { _id = id; } - inline void resetId() noexcept { _id = 0; } - - //! \} - - //! \name Instruction Options - //! \{ - - inline uint32_t options() const noexcept { return _options; } - inline void setOptions(uint32_t options) noexcept { _options = options; } - inline void addOptions(uint32_t options) noexcept { _options |= options; } - inline void clearOptions(uint32_t options) noexcept { _options &= ~options; } - inline void resetOptions() noexcept { _options = 0; } - - //! \} - - //! \name Extra Register - //! \{ - - inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); } - inline RegOnly& extraReg() noexcept { return _extraReg; } - inline const RegOnly& extraReg() const noexcept { return _extraReg; } - inline void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); } - inline void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); } - inline void resetExtraReg() noexcept { _extraReg.reset(); } + //! Returns the number of operands this instruction has. + inline uint32_t opCount() const noexcept { return _opCount; } //! \} }; @@ -430,6 +508,12 @@ public: //! Instruction API. namespace InstAPI { +//! Validation flags that can be used with \ref InstAPI::validate(). +enum ValidationFlags : uint32_t { + //! Allow virtual registers in the instruction. + kValidationFlagVirtRegs = 0x01u +}; + #ifndef ASMJIT_NO_TEXT //! Appends the name of the instruction specified by `instId` and `instOptions` //! into the `output` string. @@ -437,27 +521,29 @@ namespace InstAPI { //! \note Instruction options would only affect instruction prefix & suffix, //! other options would be ignored. If `instOptions` is zero then only raw //! instruction name (without any additional text) will be appended. -ASMJIT_API Error instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept; +ASMJIT_API Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; //! Parses an instruction name in the given string `s`. Length is specified //! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null //! terminated. //! -//! The output is stored in `instId`. -ASMJIT_API uint32_t stringToInstId(uint32_t archId, const char* s, size_t len) noexcept; +//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such +//! instruction exists. +ASMJIT_API uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; #endif // !ASMJIT_NO_TEXT #ifndef ASMJIT_NO_VALIDATION -//! Validates the given instruction. -ASMJIT_API Error validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; +//! Validates the given instruction considering the validation `flags`, see +//! \ref ValidationFlags. +ASMJIT_API Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags = 0) noexcept; #endif // !ASMJIT_NO_VALIDATION #ifndef ASMJIT_NO_INTROSPECTION //! Gets Read/Write information of the given instruction. -ASMJIT_API Error queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept; +ASMJIT_API Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; //! Gets CPU features required by the given instruction. -ASMJIT_API Error queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept; +ASMJIT_API Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; #endif // !ASMJIT_NO_INTROSPECTION } // {InstAPI} diff --git a/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp b/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp index a8ca0c3d75a..b2285113d3d 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp +++ b/3rdparty/asmjit/src/asmjit/core/jitallocator.cpp @@ -26,7 +26,7 @@ #include "../core/arch.h" #include "../core/jitallocator.h" -#include "../core/osutils.h" +#include "../core/osutils_p.h" #include "../core/support.h" #include "../core/virtmem.h" #include "../core/zone.h" @@ -938,7 +938,7 @@ public: // Helper class to verify that JitAllocator doesn't return addresses that overlap. class JitAllocatorWrapper { public: - explicit inline JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept + inline explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept : _zone(1024 * 1024), _heap(&_zone), _allocator(params) {} diff --git a/3rdparty/asmjit/src/asmjit/core/jitallocator.h b/3rdparty/asmjit/src/asmjit/core/jitallocator.h index 111716ed59e..9cd0a1f7b7e 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitallocator.h +++ b/3rdparty/asmjit/src/asmjit/core/jitallocator.h @@ -32,7 +32,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ @@ -132,9 +132,6 @@ public: //! JitAllocator allocator(¶ms); //! ``` struct CreateParams { - // Reset the content of `CreateParams`. - inline void reset() noexcept { memset(this, 0, sizeof(*this)); } - //! Allocator options, see \ref JitAllocator::Options. //! //! No options are used by default. @@ -161,6 +158,9 @@ public: //! //! Only used if \ref kOptionCustomFillPattern is set. uint32_t fillPattern; + + // Reset the content of `CreateParams`. + inline void reset() noexcept { memset(this, 0, sizeof(*this)); } }; //! Creates a `JitAllocator` instance. @@ -221,6 +221,15 @@ public: //! Statistics about `JitAllocator`. struct Statistics { + //! Number of blocks `JitAllocator` maintains. + size_t _blockCount; + //! How many bytes are currently used / allocated. + size_t _usedSize; + //! How many bytes are currently reserved by the allocator. + size_t _reservedSize; + //! Allocation overhead (in bytes) required to maintain all blocks. + size_t _overheadSize; + inline void reset() noexcept { _blockCount = 0; _usedSize = 0; @@ -251,15 +260,6 @@ public: inline double overheadSizeAsPercent() const noexcept { return (double(overheadSize()) / (double(reservedSize()) + 1e-16)) * 100.0; } - - //! Number of blocks `JitAllocator` maintains. - size_t _blockCount; - //! How many bytes are currently used / allocated. - size_t _usedSize; - //! How many bytes are currently reserved by the allocator. - size_t _reservedSize; - //! Allocation overhead (in bytes) required to maintain all blocks. - size_t _overheadSize; }; //! Returns JIT allocator statistics. diff --git a/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp b/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp index 625cc3d2f51..1127c866aad 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp +++ b/3rdparty/asmjit/src/asmjit/core/jitruntime.cpp @@ -43,52 +43,16 @@ static inline void JitRuntime_flushInstructionCache(const void* p, size_t size) #endif } -// X86 Target -// ---------- -// -// - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte -// stack alignment. Other operating systems are assumed to have -// 4-byte alignment by default for safety reasons. -// - 64-bit - stack must be aligned to 16 bytes. -// -// ARM Target -// ---------- -// -// - 32-bit - Stack must be aligned to 8 bytes. -// - 64-bit - Stack must be aligned to 16 bytes (hardware requirement). -static inline uint32_t JitRuntime_detectNaturalStackAlignment() noexcept { -#if ASMJIT_ARCH_BITS == 64 || \ - defined(__APPLE__ ) || \ - defined(__DragonFly__) || \ - defined(__HAIKU__ ) || \ - defined(__FreeBSD__ ) || \ - defined(__NetBSD__ ) || \ - defined(__OpenBSD__ ) || \ - defined(__bsdi__ ) || \ - defined(__linux__ ) - return 16; -#elif ASMJIT_ARCH_ARM - return 8; -#else - return uint32_t(sizeof(uintptr_t)); -#endif -} - // ============================================================================ // [asmjit::JitRuntime - Construction / Destruction] // ============================================================================ JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept : _allocator(params) { - - // Setup target properties. - _targetType = kTargetJit; - _codeInfo._archInfo = CpuInfo::host().archInfo(); - _codeInfo._stackAlignment = uint8_t(JitRuntime_detectNaturalStackAlignment()); - _codeInfo._cdeclCallConv = CallConv::kIdHostCDecl; - _codeInfo._stdCallConv = CallConv::kIdHostStdCall; - _codeInfo._fastCallConv = CallConv::kIdHostFastCall; + _environment = hostEnvironment(); + _environment.setFormat(Environment::kFormatJIT); } + JitRuntime::~JitRuntime() noexcept {} // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/jitruntime.h b/3rdparty/asmjit/src/asmjit/core/jitruntime.h index 97f26e7a6c1..91880e688c0 100644 --- a/3rdparty/asmjit/src/asmjit/core/jitruntime.h +++ b/3rdparty/asmjit/src/asmjit/core/jitruntime.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE class CodeHolder; -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/logger.cpp b/3rdparty/asmjit/src/asmjit/core/logger.cpp new file mode 100644 index 00000000000..22e0b9af08a --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/logger.cpp @@ -0,0 +1,124 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifndef ASMJIT_NO_LOGGING + +#include "../core/logger.h" +#include "../core/string.h" +#include "../core/support.h" + +ASMJIT_BEGIN_NAMESPACE + +// ============================================================================ +// [asmjit::Logger - Construction / Destruction] +// ============================================================================ + +Logger::Logger() noexcept + : _options() {} +Logger::~Logger() noexcept {} + +// ============================================================================ +// [asmjit::Logger - Logging] +// ============================================================================ + +Error Logger::logf(const char* fmt, ...) noexcept { + Error err; + va_list ap; + + va_start(ap, fmt); + err = logv(fmt, ap); + va_end(ap); + + return err; +} + +Error Logger::logv(const char* fmt, va_list ap) noexcept { + StringTmp<2048> sb; + ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap)); + return log(sb); +} + +Error Logger::logBinary(const void* data, size_t size) noexcept { + static const char prefix[] = "db "; + + StringTmp<256> sb; + sb.append(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); + + size_t i = size; + const uint8_t* s = static_cast<const uint8_t*>(data); + + while (i) { + uint32_t n = uint32_t(Support::min<size_t>(i, 16)); + sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1); + sb.appendHex(s, n); + sb.append('\n'); + ASMJIT_PROPAGATE(log(sb)); + s += n; + i -= n; + } + + return kErrorOk; +} + +// ============================================================================ +// [asmjit::FileLogger - Construction / Destruction] +// ============================================================================ + +FileLogger::FileLogger(FILE* file) noexcept + : _file(file) {} +FileLogger::~FileLogger() noexcept {} + +// ============================================================================ +// [asmjit::FileLogger - Logging] +// ============================================================================ + +Error FileLogger::_log(const char* data, size_t size) noexcept { + if (!_file) + return kErrorOk; + + if (size == SIZE_MAX) + size = strlen(data); + + fwrite(data, 1, size, _file); + return kErrorOk; +} + +// ============================================================================ +// [asmjit::StringLogger - Construction / Destruction] +// ============================================================================ + +StringLogger::StringLogger() noexcept {} +StringLogger::~StringLogger() noexcept {} + +// ============================================================================ +// [asmjit::StringLogger - Logging] +// ============================================================================ + +Error StringLogger::_log(const char* data, size_t size) noexcept { + return _content.append(data, size); +} + +ASMJIT_END_NAMESPACE + +#endif diff --git a/3rdparty/asmjit/src/asmjit/core/logging.h b/3rdparty/asmjit/src/asmjit/core/logger.h index 468e3a1ba2b..2840869b476 100644 --- a/3rdparty/asmjit/src/asmjit/core/logging.h +++ b/3rdparty/asmjit/src/asmjit/core/logger.h @@ -26,119 +26,28 @@ #include "../core/inst.h" #include "../core/string.h" - -ASMJIT_BEGIN_NAMESPACE - -//! \addtogroup asmjit_core -//! \{ +#include "../core/formatter.h" #ifndef ASMJIT_NO_LOGGING -// ============================================================================ -// [Forward Declarations] -// ============================================================================ - -class BaseEmitter; -class BaseReg; -class Logger; -struct Operand_; - -#ifndef ASMJIT_NO_BUILDER -class BaseBuilder; -class BaseNode; -#endif - -// ============================================================================ -// [asmjit::FormatOptions] -// ============================================================================ - -class FormatOptions { -public: - uint32_t _flags; - uint8_t _indentation[4]; - - enum Flags : uint32_t { - //! Show also binary form of each logged instruction (assembler). - kFlagMachineCode = 0x00000001u, - //! Show a text explanation of some immediate values. - kFlagExplainImms = 0x00000002u, - //! Use hexadecimal notation of immediate values. - kFlagHexImms = 0x00000004u, - //! Use hexadecimal notation of address offsets. - kFlagHexOffsets = 0x00000008u, - //! Show casts between virtual register types (compiler). - kFlagRegCasts = 0x00000010u, - //! Show positions associated with nodes (compiler). - kFlagPositions = 0x00000020u, - //! Annotate nodes that are lowered by passes. - kFlagAnnotations = 0x00000040u, - - // TODO: These must go, keep this only for formatting. - //! Show an additional output from passes. - kFlagDebugPasses = 0x00000080u, - //! Show an additional output from RA. - kFlagDebugRA = 0x00000100u - }; - - enum IndentationType : uint32_t { - //! Indentation used for instructions and directives. - kIndentationCode = 0u, - //! Indentation used for labels and function nodes. - kIndentationLabel = 1u, - //! Indentation used for comments (not inline comments). - kIndentationComment = 2u, - kIndentationReserved = 3u - }; - - //! \name Construction & Destruction - //! \{ - - constexpr FormatOptions() noexcept - : _flags(0), - _indentation { 0, 0, 0, 0 } {} - - constexpr FormatOptions(const FormatOptions& other) noexcept = default; - inline FormatOptions& operator=(const FormatOptions& other) noexcept = default; - - inline void reset() noexcept { - _flags = 0; - _indentation[0] = 0; - _indentation[1] = 0; - _indentation[2] = 0; - _indentation[3] = 0; - } - - //! \} - - //! \name Accessors - //! \{ - - constexpr uint32_t flags() const noexcept { return _flags; } - constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } - inline void setFlags(uint32_t flags) noexcept { _flags = flags; } - inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } - inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; } - - constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; } - inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); } - inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); } +ASMJIT_BEGIN_NAMESPACE - //! \} -}; +//! \addtogroup asmjit_logging +//! \{ // ============================================================================ // [asmjit::Logger] // ============================================================================ -//! Abstract logging interface and helpers. +//! Logging interface. //! -//! This class can be inherited and reimplemented to fit into your logging -//! subsystem. When reimplementing use `Logger::_log()` method to log into -//! a custom stream. +//! This class can be inherited and reimplemented to fit into your own logging +//! needs. When reimplementing a logger use \ref Logger::_log() method to log +//! customize the output. //! //! There are two `Logger` implementations offered by AsmJit: -//! - `FileLogger` - allows to log into `FILE*`. -//! - `StringLogger` - logs into a `String`. +//! - \ref FileLogger - logs into a `FILE*`. +//! - \ref StringLogger - concatenates all logs into a \ref String. class ASMJIT_VIRTAPI Logger { public: ASMJIT_BASE_CLASS(Logger) @@ -160,17 +69,28 @@ public: //! \name Format Options //! \{ + //! Returns \ref FormatOptions of this logger. inline FormatOptions& options() noexcept { return _options; } + //! \overload inline const FormatOptions& options() const noexcept { return _options; } + //! Returns formatting flags, see \ref FormatOptions::Flags. inline uint32_t flags() const noexcept { return _options.flags(); } + //! Tests whether the logger has the given `flag` enabled. inline bool hasFlag(uint32_t flag) const noexcept { return _options.hasFlag(flag); } + //! Sets formatting flags to `flags`, see \ref FormatOptions::Flags. inline void setFlags(uint32_t flags) noexcept { _options.setFlags(flags); } + //! Enables the given formatting `flags`, see \ref FormatOptions::Flags. inline void addFlags(uint32_t flags) noexcept { _options.addFlags(flags); } + //! Disables the given formatting `flags`, see \ref FormatOptions::Flags. inline void clearFlags(uint32_t flags) noexcept { _options.clearFlags(flags); } + //! Returns indentation of `type`, see \ref FormatOptions::IndentationType. inline uint32_t indentation(uint32_t type) const noexcept { return _options.indentation(type); } + //! Sets indentation of the given indentation `type` to `n` spaces, see \ref + //! FormatOptions::IndentationType. inline void setIndentation(uint32_t type, uint32_t n) noexcept { _options.setIndentation(type, n); } + //! Resets indentation of the given indentation `type` to 0 spaces. inline void resetIndentation(uint32_t type) noexcept { _options.resetIndentation(type); } //! \} @@ -179,6 +99,11 @@ public: //! \{ //! Logs `str` - must be reimplemented. + //! + //! The function can accept either a null terminated string if `size` is + //! `SIZE_MAX` or a non-null terminated string of the given `size`. The + //! function cannot assume that the data is null terminated and must handle + //! non-null terminated inputs. virtual Error _log(const char* data, size_t size) noexcept = 0; //! Logs string `str`, which is either null terminated or having size `size`. @@ -186,15 +111,15 @@ public: //! Logs content of a string `str`. inline Error log(const String& str) noexcept { return _log(str.data(), str.size()); } - //! Formats the message by using `snprintf()` and then sends the result - //! to `log()`. + //! Formats the message by using `snprintf()` and then passes the formatted + //! string to \ref _log(). ASMJIT_API Error logf(const char* fmt, ...) noexcept; - //! Formats the message by using `vsnprintf()` and then sends the result - //! to `log()`. + //! Formats the message by using `vsnprintf()` and then passes the formatted + //! string to \ref _log(). ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept; - //! Logs binary data. + //! Logs binary `data` of the given `size`. ASMJIT_API Error logBinary(const void* data, size_t size) noexcept; //! \} @@ -267,6 +192,13 @@ public: //! \name Logger Data Accessors //! \{ + //! Returns the content of the logger as \ref String. + //! + //! It can be moved, if desired. + inline String& content() noexcept { return _content; } + //! \overload + inline const String& content() const noexcept { return _content; } + //! Returns aggregated logger data as `char*` pointer. //! //! The pointer is owned by `StringLogger`, it can't be modified or freed. @@ -287,69 +219,10 @@ public: ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override; }; -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -struct Logging { - ASMJIT_API static Error formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept; - - ASMJIT_API static Error formatLabel( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t labelId) noexcept; - - ASMJIT_API static Error formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept; - - ASMJIT_API static Error formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; - - ASMJIT_API static Error formatTypeId( - String& sb, - uint32_t typeId) noexcept; - -#ifndef ASMJIT_NO_BUILDER - ASMJIT_API static Error formatNode( - String& sb, - uint32_t flags, - const BaseBuilder* cb, - const BaseNode* node_) noexcept; -#endif - - // Only used by AsmJit internals, not available to users. -#ifdef ASMJIT_EXPORTS - enum { - // Has to be big to be able to hold all metadata compiler can assign to a - // single instruction. - kMaxInstLineSize = 44, - kMaxBinarySize = 26 - }; - - static Error formatLine( - String& sb, - const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept; -#endif -}; -#endif - //! \} ASMJIT_END_NAMESPACE +#endif + #endif // ASMJIT_CORE_LOGGER_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/logging.cpp b/3rdparty/asmjit/src/asmjit/core/logging.cpp deleted file mode 100644 index 7e10af27c2d..00000000000 --- a/3rdparty/asmjit/src/asmjit/core/logging.cpp +++ /dev/null @@ -1,535 +0,0 @@ -// AsmJit - Machine code generation for C++ -// -// * Official AsmJit Home Page: https://asmjit.com -// * Official Github Repository: https://github.com/asmjit/asmjit -// -// Copyright (c) 2008-2020 The AsmJit Authors -// -// This software is provided 'as-is', without any express or implied -// warranty. In no event will the authors be held liable for any damages -// arising from the use of this software. -// -// Permission is granted to anyone to use this software for any purpose, -// including commercial applications, and to alter it and redistribute it -// freely, subject to the following restrictions: -// -// 1. The origin of this software must not be misrepresented; you must not -// claim that you wrote the original software. If you use this software -// in a product, an acknowledgment in the product documentation would be -// appreciated but is not required. -// 2. Altered source versions must be plainly marked as such, and must not be -// misrepresented as being the original software. -// 3. This notice may not be removed or altered from any source distribution. - -#include "../core/api-build_p.h" -#ifndef ASMJIT_NO_LOGGING - -#include "../core/builder.h" -#include "../core/codeholder.h" -#include "../core/compiler.h" -#include "../core/emitter.h" -#include "../core/logging.h" -#include "../core/string.h" -#include "../core/support.h" -#include "../core/type.h" - -#ifdef ASMJIT_BUILD_X86 - #include "../x86/x86logging_p.h" -#endif - -#ifdef ASMJIT_BUILD_ARM - #include "../arm/armlogging_p.h" -#endif - -ASMJIT_BEGIN_NAMESPACE - -#if defined(ASMJIT_NO_COMPILER) -class VirtReg; -#endif - -// ============================================================================ -// [asmjit::Logger - Construction / Destruction] -// ============================================================================ - -Logger::Logger() noexcept - : _options() {} -Logger::~Logger() noexcept {} - -// ============================================================================ -// [asmjit::Logger - Logging] -// ============================================================================ - -Error Logger::logf(const char* fmt, ...) noexcept { - Error err; - va_list ap; - - va_start(ap, fmt); - err = logv(fmt, ap); - va_end(ap); - - return err; -} - -Error Logger::logv(const char* fmt, va_list ap) noexcept { - StringTmp<2048> sb; - ASMJIT_PROPAGATE(sb.appendVFormat(fmt, ap)); - return log(sb); -} - -Error Logger::logBinary(const void* data, size_t size) noexcept { - static const char prefix[] = "db "; - - StringTmp<256> sb; - sb.appendString(prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); - - size_t i = size; - const uint8_t* s = static_cast<const uint8_t*>(data); - - while (i) { - uint32_t n = uint32_t(Support::min<size_t>(i, 16)); - sb.truncate(ASMJIT_ARRAY_SIZE(prefix) - 1); - sb.appendHex(s, n); - sb.appendChar('\n'); - ASMJIT_PROPAGATE(log(sb)); - s += n; - i -= n; - } - - return kErrorOk; -} - -// ============================================================================ -// [asmjit::FileLogger - Construction / Destruction] -// ============================================================================ - -FileLogger::FileLogger(FILE* file) noexcept - : _file(nullptr) { setFile(file); } -FileLogger::~FileLogger() noexcept {} - -// ============================================================================ -// [asmjit::FileLogger - Logging] -// ============================================================================ - -Error FileLogger::_log(const char* data, size_t size) noexcept { - if (!_file) - return kErrorOk; - - if (size == SIZE_MAX) - size = strlen(data); - - fwrite(data, 1, size, _file); - return kErrorOk; -} - -// ============================================================================ -// [asmjit::StringLogger - Construction / Destruction] -// ============================================================================ - -StringLogger::StringLogger() noexcept {} -StringLogger::~StringLogger() noexcept {} - -// ============================================================================ -// [asmjit::StringLogger - Logging] -// ============================================================================ - -Error StringLogger::_log(const char* data, size_t size) noexcept { - return _content.appendString(data, size); -} - -// ============================================================================ -// [asmjit::Logging] -// ============================================================================ - -Error Logging::formatLabel( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t labelId) noexcept { - - DebugUtils::unused(flags); - - const LabelEntry* le = emitter->code()->labelEntry(labelId); - if (ASMJIT_UNLIKELY(!le)) - return sb.appendFormat("InvalidLabel[Id=%u]", labelId); - - if (le->hasName()) { - if (le->hasParent()) { - uint32_t parentId = le->parentId(); - const LabelEntry* pe = emitter->code()->labelEntry(parentId); - - if (ASMJIT_UNLIKELY(!pe)) - ASMJIT_PROPAGATE(sb.appendFormat("InvalidLabel[Id=%u]", labelId)); - else if (ASMJIT_UNLIKELY(!pe->hasName())) - ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId)); - else - ASMJIT_PROPAGATE(sb.appendString(pe->name())); - - ASMJIT_PROPAGATE(sb.appendChar('.')); - } - return sb.appendString(le->name()); - } - else { - return sb.appendFormat("L%u", labelId); - } -} - -Error Logging::formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatRegister(sb, flags, emitter, archId, regType, regId); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatOperand(sb, flags, emitter, archId, op); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatOperand(sb, flags, emitter, archId, op); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { - -#ifdef ASMJIT_BUILD_X86 - if (ArchInfo::isX86Family(archId)) - return x86::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount); -#endif - -#ifdef ASMJIT_BUILD_ARM - if (ArchInfo::isArmFamily(archId)) - return arm::LoggingInternal::formatInstruction(sb, flags, emitter, archId, inst, operands, opCount); -#endif - - return kErrorInvalidArch; -} - -Error Logging::formatTypeId(String& sb, uint32_t typeId) noexcept { - if (typeId == Type::kIdVoid) - return sb.appendString("void"); - - if (!Type::isValid(typeId)) - return sb.appendString("unknown"); - - const char* typeName = "unknown"; - uint32_t typeSize = Type::sizeOf(typeId); - - uint32_t baseId = Type::baseOf(typeId); - switch (baseId) { - case Type::kIdIntPtr : typeName = "iptr" ; break; - case Type::kIdUIntPtr: typeName = "uptr" ; break; - case Type::kIdI8 : typeName = "i8" ; break; - case Type::kIdU8 : typeName = "u8" ; break; - case Type::kIdI16 : typeName = "i16" ; break; - case Type::kIdU16 : typeName = "u16" ; break; - case Type::kIdI32 : typeName = "i32" ; break; - case Type::kIdU32 : typeName = "u32" ; break; - case Type::kIdI64 : typeName = "i64" ; break; - case Type::kIdU64 : typeName = "u64" ; break; - case Type::kIdF32 : typeName = "f32" ; break; - case Type::kIdF64 : typeName = "f64" ; break; - case Type::kIdF80 : typeName = "f80" ; break; - case Type::kIdMask8 : typeName = "mask8" ; break; - case Type::kIdMask16 : typeName = "mask16"; break; - case Type::kIdMask32 : typeName = "mask32"; break; - case Type::kIdMask64 : typeName = "mask64"; break; - case Type::kIdMmx32 : typeName = "mmx32" ; break; - case Type::kIdMmx64 : typeName = "mmx64" ; break; - } - - uint32_t baseSize = Type::sizeOf(baseId); - if (typeSize > baseSize) { - uint32_t count = typeSize / baseSize; - return sb.appendFormat("%sx%u", typeName, unsigned(count)); - } - else { - return sb.appendString(typeName); - } - -} - -#ifndef ASMJIT_NO_BUILDER -static Error formatFuncValue(String& sb, uint32_t flags, const BaseEmitter* emitter, FuncValue value) noexcept { - uint32_t typeId = value.typeId(); - ASMJIT_PROPAGATE(Logging::formatTypeId(sb, typeId)); - - if (value.isReg()) { - ASMJIT_PROPAGATE(sb.appendChar('@')); - ASMJIT_PROPAGATE(Logging::formatRegister(sb, flags, emitter, emitter->archId(), value.regType(), value.regId())); - } - - if (value.isStack()) { - ASMJIT_PROPAGATE(sb.appendFormat("@[%d]", int(value.stackOffset()))); - } - - return kErrorOk; -} - -static Error formatFuncRets( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - if (!fd.hasRet()) - return sb.appendString("void"); - - for (uint32_t i = 0; i < fd.retCount(); i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.ret(i))); - -#ifndef ASMJIT_NO_COMPILER - if (vRegs) { - static const char nullRet[] = "<none>"; - ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullRet)); - } -#else - DebugUtils::unused(vRegs); -#endif - } - - return kErrorOk; -} - -static Error formatFuncArgs( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - const FuncDetail& fd, - VirtReg* const* vRegs) noexcept { - - uint32_t count = fd.argCount(); - if (!count) - return sb.appendString("void"); - - for (uint32_t i = 0; i < count; i++) { - if (i) ASMJIT_PROPAGATE(sb.appendString(", ")); - ASMJIT_PROPAGATE(formatFuncValue(sb, flags, emitter, fd.arg(i))); - -#ifndef ASMJIT_NO_COMPILER - if (vRegs) { - static const char nullArg[] = "<none>"; - ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[i] ? vRegs[i]->name() : nullArg)); - } -#else - DebugUtils::unused(vRegs); -#endif - } - - return kErrorOk; -} - -Error Logging::formatNode( - String& sb, - uint32_t flags, - const BaseBuilder* cb, - const BaseNode* node_) noexcept { - - if (node_->hasPosition() && (flags & FormatOptions::kFlagPositions) != 0) - ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node_->position())); - - switch (node_->type()) { - case BaseNode::kNodeInst: - case BaseNode::kNodeJump: { - const InstNode* node = node_->as<InstNode>(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, flags, cb, - cb->archId(), - node->baseInst(), node->operands(), node->opCount())); - break; - } - - case BaseNode::kNodeSection: { - const SectionNode* node = node_->as<SectionNode>(); - if (cb->_code->isSectionValid(node->id())) { - const Section* section = cb->_code->sectionById(node->id()); - ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name())); - } - break; - } - - case BaseNode::kNodeLabel: { - const LabelNode* node = node_->as<LabelNode>(); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(":")); - break; - } - - case BaseNode::kNodeAlign: { - const AlignNode* node = node_->as<AlignNode>(); - ASMJIT_PROPAGATE( - sb.appendFormat(".align %u (%s)", - node->alignment(), - node->alignMode() == kAlignCode ? "code" : "data")); - break; - } - - case BaseNode::kNodeEmbedData: { - const EmbedDataNode* node = node_->as<EmbedDataNode>(); - ASMJIT_PROPAGATE(sb.appendFormat(".embed (%u bytes)", node->size())); - break; - } - - case BaseNode::kNodeEmbedLabel: { - const EmbedLabelNode* node = node_->as<EmbedLabelNode>(); - ASMJIT_PROPAGATE(sb.appendString(".label ")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - break; - } - - case BaseNode::kNodeEmbedLabelDelta: { - const EmbedLabelDeltaNode* node = node_->as<EmbedLabelDeltaNode>(); - ASMJIT_PROPAGATE(sb.appendString(".label (")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(" - ")); - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->baseId())); - ASMJIT_PROPAGATE(sb.appendString(")")); - break; - } - - case BaseNode::kNodeComment: { - const CommentNode* node = node_->as<CommentNode>(); - ASMJIT_PROPAGATE(sb.appendFormat("; %s", node->inlineComment())); - break; - } - - case BaseNode::kNodeSentinel: { - const SentinelNode* node = node_->as<SentinelNode>(); - const char* sentinelName = nullptr; - - switch (node->sentinelType()) { - case SentinelNode::kSentinelFuncEnd: - sentinelName = "[FuncEnd]"; - break; - - default: - sentinelName = "[Sentinel]"; - break; - } - - ASMJIT_PROPAGATE(sb.appendString(sentinelName)); - break; - } - -#ifndef ASMJIT_NO_COMPILER - case BaseNode::kNodeFunc: { - const FuncNode* node = node_->as<FuncNode>(); - - ASMJIT_PROPAGATE(formatLabel(sb, flags, cb, node->id())); - ASMJIT_PROPAGATE(sb.appendString(": ")); - - ASMJIT_PROPAGATE(formatFuncRets(sb, flags, cb, node->detail(), nullptr)); - ASMJIT_PROPAGATE(sb.appendString(" Func(")); - ASMJIT_PROPAGATE(formatFuncArgs(sb, flags, cb, node->detail(), node->args())); - ASMJIT_PROPAGATE(sb.appendString(")")); - break; - } - - case BaseNode::kNodeFuncRet: { - const FuncRetNode* node = node_->as<FuncRetNode>(); - ASMJIT_PROPAGATE(sb.appendString("[FuncRet]")); - - for (uint32_t i = 0; i < 2; i++) { - const Operand_& op = node->_opArray[i]; - if (!op.isNone()) { - ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", ")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, cb, cb->archId(), op)); - } - } - break; - } - - case BaseNode::kNodeFuncCall: { - const FuncCallNode* node = node_->as<FuncCallNode>(); - ASMJIT_PROPAGATE( - Logging::formatInstruction(sb, flags, cb, - cb->archId(), - node->baseInst(), node->operands(), node->opCount())); - break; - } -#endif - - default: { - ASMJIT_PROPAGATE(sb.appendFormat("[User:%u]", node_->type())); - break; - } - } - - return kErrorOk; -} -#endif - -Error Logging::formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept { - size_t currentSize = sb.size(); - size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0; - - ASMJIT_ASSERT(binSize >= dispSize); - const size_t kNoBinSize = std::numeric_limits<size_t>::max(); - - if ((binSize != 0 && binSize != kNoBinSize) || commentSize) { - size_t align = kMaxInstLineSize; - char sep = ';'; - - for (size_t i = (binSize == kNoBinSize); i < 2; i++) { - size_t begin = sb.size(); - ASMJIT_PROPAGATE(sb.padEnd(align)); - - if (sep) { - ASMJIT_PROPAGATE(sb.appendChar(sep)); - ASMJIT_PROPAGATE(sb.appendChar(' ')); - } - - // Append binary data or comment. - if (i == 0) { - ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize)); - ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2)); - ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize)); - if (commentSize == 0) break; - } - else { - ASMJIT_PROPAGATE(sb.appendString(comment, commentSize)); - } - - currentSize += sb.size() - begin; - align += kMaxBinarySize; - sep = '|'; - } - } - - return sb.appendChar('\n'); -} - -ASMJIT_END_NAMESPACE - -#endif diff --git a/3rdparty/asmjit/src/asmjit/core/misc_p.h b/3rdparty/asmjit/src/asmjit/core/misc_p.h index 916ca9db67c..b1056f473ae 100644 --- a/3rdparty/asmjit/src/asmjit/core/misc_p.h +++ b/3rdparty/asmjit/src/asmjit/core/misc_p.h @@ -29,7 +29,7 @@ ASMJIT_BEGIN_NAMESPACE //! \cond INTERNAL -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ #define ASMJIT_LOOKUP_TABLE_8(T, I) T((I)), T((I+1)), T((I+2)), T((I+3)), T((I+4)), T((I+5)), T((I+6)), T((I+7)) diff --git a/3rdparty/asmjit/src/asmjit/core/operand.cpp b/3rdparty/asmjit/src/asmjit/core/operand.cpp index 9d11f3f6ddc..46bb23a289c 100644 --- a/3rdparty/asmjit/src/asmjit/core/operand.cpp +++ b/3rdparty/asmjit/src/asmjit/core/operand.cpp @@ -126,10 +126,10 @@ UNIT(operand) { INFO("Checking basic functionality of Imm"); Imm immValue(-42); - EXPECT(Imm(-1).i64() == int64_t(-1)); - EXPECT(imm(-1).i64() == int64_t(-1)); - EXPECT(immValue.i64() == int64_t(-42)); - EXPECT(imm(0xFFFFFFFF).i64() == int64_t(0xFFFFFFFF)); + EXPECT(Imm(-1).value() == -1); + EXPECT(imm(-1).value() == -1); + EXPECT(immValue.value() == -42); + EXPECT(imm(0xFFFFFFFF).value() == int64_t(0xFFFFFFFF)); } #endif diff --git a/3rdparty/asmjit/src/asmjit/core/operand.h b/3rdparty/asmjit/src/asmjit/core/operand.h index eee1af4244e..01cc1eaa560 100644 --- a/3rdparty/asmjit/src/asmjit/core/operand.h +++ b/3rdparty/asmjit/src/asmjit/core/operand.h @@ -103,7 +103,7 @@ public: \ constexpr explicit REG(uint32_t rId) noexcept \ : BASE(kSignature, rId) {} -//! \addtogroup asmjit_core +//! \addtogroup asmjit_assembler //! \{ // ============================================================================ @@ -162,6 +162,16 @@ struct Operand_ { }; static_assert(kOpMem == kOpReg + 1, "asmjit::Operand requires `kOpMem` to be `kOpReg+1`."); + //! Label tag. + enum LabelTag { + //! Label tag is used as a sub-type, forming a unique signature across all + //! operand types as 0x1 is never associated with any register type. This + //! means that a memory operand's BASE register can be constructed from + //! virtually any operand (register vs. label) by just assigning its type + //! (register type or label-tag) and operand id. + kLabelTag = 0x1 + }; + // \cond INTERNAL enum SignatureBits : uint32_t { // Operand type (3 least significant bits). @@ -211,7 +221,6 @@ struct Operand_ { }; //! \endcond - //! \cond INTERNAL //! Constants useful for VirtId <-> Index translation. enum VirtIdConstants : uint32_t { //! Minimum valid packed-id. @@ -225,14 +234,12 @@ struct Operand_ { //! Tests whether the given `id` is a valid virtual register id. Since AsmJit //! supports both physical and virtual registers it must be able to distinguish //! between these two. The idea is that physical registers are always limited - //! in size, so virtual identifiers start from `kVirtIdMin` and end at - //! `kVirtIdMax`. + //! in size, so virtual identifiers start from `kVirtIdMin` and end at `kVirtIdMax`. static ASMJIT_INLINE bool isVirtId(uint32_t id) noexcept { return id - kVirtIdMin < uint32_t(kVirtIdCount); } //! Converts a real-id into a packed-id that can be stored in Operand. static ASMJIT_INLINE uint32_t indexToVirtId(uint32_t id) noexcept { return id + kVirtIdMin; } //! Converts a packed-id back to real-id. static ASMJIT_INLINE uint32_t virtIdToIndex(uint32_t id) noexcept { return id - kVirtIdMin; } - //! \endcond //! \name Construction & Destruction //! \{ @@ -245,10 +252,10 @@ struct Operand_ { _data[0] = 0; _data[1] = 0; } + //! \endcond - //! Initializes the operand from `other` (used by operator overloads). + //! Initializes the operand from `other` operand (used by operator overloads). inline void copyFrom(const Operand_& other) noexcept { memcpy(this, &other, sizeof(Operand_)); } - //! \endcond //! Resets the `Operand` to none. //! @@ -290,8 +297,10 @@ struct Operand_ { //! \name Operator Overloads //! \{ - constexpr bool operator==(const Operand_& other) const noexcept { return isEqual(other); } - constexpr bool operator!=(const Operand_& other) const noexcept { return !isEqual(other); } + //! Tests whether this operand is the same as `other`. + constexpr bool operator==(const Operand_& other) const noexcept { return equals(other); } + //! Tests whether this operand is not the same as `other`. + constexpr bool operator!=(const Operand_& other) const noexcept { return !equals(other); } //! \} @@ -395,14 +404,22 @@ struct Operand_ { //! initialized. constexpr uint32_t id() const noexcept { return _baseId; } - //! Tests whether the operand is 100% equal to `other`. - constexpr bool isEqual(const Operand_& other) const noexcept { + //! Tests whether the operand is 100% equal to `other` operand. + //! + //! \note This basically performs a binary comparison, if aby bit is + //! different the operands are not equal. + constexpr bool equals(const Operand_& other) const noexcept { return (_signature == other._signature) & (_baseId == other._baseId ) & (_data[0] == other._data[0] ) & (_data[1] == other._data[1] ) ; } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use equals() instead") + constexpr bool isEqual(const Operand_& other) const noexcept { return equals(other); } +#endif //!ASMJIT_NO_DEPRECATED + //! Tests whether the operand is a register matching `rType`. constexpr bool isReg(uint32_t rType) const noexcept { return (_signature & (kSignatureOpMask | kSignatureRegTypeMask)) == @@ -471,11 +488,6 @@ public: static_assert(sizeof(Operand) == 16, "asmjit::Operand must be exactly 16 bytes long"); -namespace Globals { - //! A default-constructed operand of `Operand_::kOpNone` type. - static constexpr const Operand none; -} - // ============================================================================ // [asmjit::Label] // ============================================================================ @@ -519,16 +531,6 @@ public: kTypeCount = 3 }; - // TODO: Find a better place, find a better name. - enum { - //! Label tag is used as a sub-type, forming a unique signature across all - //! operand types as 0x1 is never associated with any register (reg-type). - //! This means that a memory operand's BASE register can be constructed - //! from virtually any operand (register vs. label) by just assigning its - //! type (reg type or label-tag) and operand id. - kLabelTag = 0x1 - }; - //! \name Construction & Destruction //! \{ @@ -536,7 +538,7 @@ public: constexpr Label() noexcept : Operand(Globals::Init, kOpLabel, Globals::kInvalidId, 0, 0) {} - //! Creates a cloned label operand of `other` . + //! Creates a cloned label operand of `other`. constexpr Label(const Label& other) noexcept : Operand(other) {} @@ -610,7 +612,7 @@ struct BaseRegTraits { //! This information is compatible with operand's signature (32-bit integer) //! and `RegInfo` just provides easy way to access it. struct RegInfo { - inline void reset() noexcept { _signature = 0; } + inline void reset(uint32_t signature = 0) noexcept { _signature = signature; } inline void setSignature(uint32_t signature) noexcept { _signature = signature; } template<uint32_t mask> @@ -628,7 +630,7 @@ struct RegInfo { uint32_t _signature; }; -//! Physical/Virtual register operand. +//! Physical or virtual register operand. class BaseReg : public Operand { public: //! Architecture neutral register types. @@ -638,7 +640,7 @@ public: //! of a memory operand. enum RegType : uint32_t { //! No register - unused, invalid, multiple meanings. - kTypeNone = 0, + kTypeNone = 0, // (1 is used as a LabelTag) @@ -736,15 +738,14 @@ public: //! Tests whether this register is the same as `other`. //! //! This is just an optimization. Registers by default only use the first - //! 8 bytes of the Operand, so this method takes advantage of this knowledge + //! 8 bytes of Operand data, so this method takes advantage of this knowledge //! and only compares these 8 bytes. If both operands were created correctly - //! then `isEqual()` and `isSame()` should give the same answer, however, if - //! some one of the two operand contains a garbage or other metadata in the - //! upper 8 bytes then `isSame()` may return `true` in cases where `isEqual()` + //! both \ref equals() and \ref isSame() should give the same answer, however, + //! if any of these two contains garbage or other metadata in the upper 8 + //! bytes then \ref isSame() may return `true` in cases in which \ref equals() //! returns false. constexpr bool isSame(const BaseReg& other) const noexcept { - return (_signature == other._signature) & - (_baseId == other._baseId ) ; + return (_signature == other._signature) & (_baseId == other._baseId); } //! Tests whether the register is valid (either virtual or physical). @@ -810,6 +811,7 @@ public: //! \name Static Functions //! \{ + //! Tests whether the `op` operand is a general purpose register. static inline bool isGp(const Operand_& op) noexcept { // Check operand type and register group. Not interested in register type and size. const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | @@ -817,7 +819,7 @@ public: return (op.signature() & (kSignatureOpMask | kSignatureRegGroupMask)) == kSgn; } - //! Tests whether the `op` operand is either a low or high 8-bit GPB register. + //! Tests whether the `op` operand is a vector register. static inline bool isVec(const Operand_& op) noexcept { // Check operand type and register group. Not interested in register type and size. const uint32_t kSgn = (kOpReg << kSignatureOpShift ) | @@ -825,7 +827,9 @@ public: return (op.signature() & (kSignatureOpMask | kSignatureRegGroupMask)) == kSgn; } + //! Tests whether the `op` is a general purpose register of the given `rId`. static inline bool isGp(const Operand_& op, uint32_t rId) noexcept { return isGp(op) & (op.id() == rId); } + //! Tests whether the `op` is a vector register of the given `rId`. static inline bool isVec(const Operand_& op, uint32_t rId) noexcept { return isVec(op) & (op.id() == rId); } //! \} @@ -947,10 +951,14 @@ struct RegOnly { //! index shift (scale). class BaseMem : public Operand { public: + //! Address type. enum AddrType : uint32_t { + //! Default address type, Assembler will select the best type when necessary. kAddrTypeDefault = 0, - kAddrTypeAbs = 1, - kAddrTypeRel = 2 + //! Absolute address type. + kAddrTypeAbs = 1, + //! Relative address type. + kAddrTypeRel = 2 }; // Shortcuts. @@ -1028,25 +1036,37 @@ public: //! Clones the memory operand. constexpr BaseMem clone() const noexcept { return BaseMem(*this); } + //! Returns the address type (see \ref AddrType) of the memory operand. + //! + //! By default, address type of newly created memory operands is always \ref kAddrTypeDefault. constexpr uint32_t addrType() const noexcept { return _getSignaturePart<kSignatureMemAddrTypeMask>(); } + //! Sets the address type to `addrType`, see \ref AddrType. inline void setAddrType(uint32_t addrType) noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(addrType); } + //! Resets the address type to \ref kAddrTypeDefault. inline void resetAddrType() noexcept { _setSignaturePart<kSignatureMemAddrTypeMask>(0); } + //! Tests whether the address type is \ref kAddrTypeAbs. constexpr bool isAbs() const noexcept { return addrType() == kAddrTypeAbs; } + //! Sets the address type to \ref kAddrTypeAbs. inline void setAbs() noexcept { setAddrType(kAddrTypeAbs); } + //! Tests whether the address type is \ref kAddrTypeRel. constexpr bool isRel() const noexcept { return addrType() == kAddrTypeRel; } + //! Sets the address type to \ref kAddrTypeRel. inline void setRel() noexcept { setAddrType(kAddrTypeRel); } + //! Tests whether this memory operand is a register home (only used by \ref asmjit_compiler) constexpr bool isRegHome() const noexcept { return _hasSignaturePart<kSignatureMemRegHomeFlag>(); } + //! Mark this memory operand as register home (only used by \ref asmjit_compiler). inline void setRegHome() noexcept { _signature |= kSignatureMemRegHomeFlag; } + //! Marks this operand to not be a register home (only used by \ref asmjit_compiler). inline void clearRegHome() noexcept { _signature &= ~kSignatureMemRegHomeFlag; } //! Tests whether the memory operand has a BASE register or label specified. constexpr bool hasBase() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0; } //! Tests whether the memory operand has an INDEX register specified. constexpr bool hasIndex() const noexcept { return (_signature & kSignatureMemIndexTypeMask) != 0; } - //! Tests whether the memory operand has BASE and INDEX register. + //! Tests whether the memory operand has BASE or INDEX register. constexpr bool hasBaseOrIndex() const noexcept { return (_signature & kSignatureMemBaseIndexMask) != 0; } //! Tests whether the memory operand has BASE and INDEX register. constexpr bool hasBaseAndIndex() const noexcept { return (_signature & kSignatureMemBaseTypeMask) != 0 && (_signature & kSignatureMemIndexTypeMask) != 0; } @@ -1093,6 +1113,7 @@ public: //! Sets the index register to type and id of the given `index` operand. inline void setIndex(const BaseReg& index) noexcept { return _setIndex(index.type(), index.id()); } + //! \cond INTERNAL inline void _setBase(uint32_t rType, uint32_t rId) noexcept { _setSignaturePart<kSignatureMemBaseTypeMask>(rType); _baseId = rId; @@ -1102,6 +1123,7 @@ public: _setSignaturePart<kSignatureMemIndexTypeMask>(rType); _data[kDataMemIndexId] = rId; } + //! \endcond //! Resets the memory operand's BASE register or label. inline void resetBase() noexcept { _setBase(0, 0); } @@ -1159,7 +1181,7 @@ public: //! 64-bit offset. Use it only if you know that there is a BASE register //! and the offset is only 32 bits anyway. - //! Adjusts the offset by a 64-bit `offset`. + //! Adjusts the memory operand offset by a `offset`. inline void addOffset(int64_t offset) noexcept { if (isOffset64Bit()) { int64_t result = offset + int64_t(uint64_t(_data[kDataMemOffsetLo]) | (uint64_t(_baseId) << 32)); @@ -1230,77 +1252,54 @@ public: //! \name Accessors //! \{ - //! Returns immediate value as 8-bit signed integer, possibly cropped. - constexpr int8_t i8() const noexcept { return int8_t(_data[kDataImmValueLo] & 0xFFu); } - //! Returns immediate value as 8-bit unsigned integer, possibly cropped. - constexpr uint8_t u8() const noexcept { return uint8_t(_data[kDataImmValueLo] & 0xFFu); } - //! Returns immediate value as 16-bit signed integer, possibly cropped. - constexpr int16_t i16() const noexcept { return int16_t(_data[kDataImmValueLo] & 0xFFFFu);} - //! Returns immediate value as 16-bit unsigned integer, possibly cropped. - constexpr uint16_t u16() const noexcept { return uint16_t(_data[kDataImmValueLo] & 0xFFFFu);} - //! Returns immediate value as 32-bit signed integer, possibly cropped. - constexpr int32_t i32() const noexcept { return int32_t(_data[kDataImmValueLo]); } - //! Returns low 32-bit signed integer. - constexpr int32_t i32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); } - //! Returns high 32-bit signed integer. - constexpr int32_t i32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); } - //! Returns immediate value as 32-bit unsigned integer, possibly cropped. - constexpr uint32_t u32() const noexcept { return _data[kDataImmValueLo]; } - //! Returns low 32-bit signed integer. - constexpr uint32_t u32Lo() const noexcept { return _data[kDataImmValueLo]; } - //! Returns high 32-bit signed integer. - constexpr uint32_t u32Hi() const noexcept { return _data[kDataImmValueHi]; } - //! Returns immediate value as 64-bit signed integer. - constexpr int64_t i64() const noexcept { return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); } - //! Returns immediate value as 64-bit unsigned integer. - constexpr uint64_t u64() const noexcept { return uint64_t(i64()); } - //! Returns immediate value as `intptr_t`, possibly cropped if size of `intptr_t` is 32 bits. - constexpr intptr_t iptr() const noexcept { return (sizeof(intptr_t) == sizeof(int64_t)) ? intptr_t(i64()) : intptr_t(i32()); } - //! Returns immediate value as `uintptr_t`, possibly cropped if size of `uintptr_t` is 32 bits. - constexpr uintptr_t uptr() const noexcept { return (sizeof(uintptr_t) == sizeof(uint64_t)) ? uintptr_t(u64()) : uintptr_t(u32()); } + //! Returns the immediate value as `int64_t`, which is the internal format Imm uses. + constexpr int64_t value() const noexcept { + return int64_t((uint64_t(_data[kDataImmValueHi]) << 32) | _data[kDataImmValueLo]); + } //! Tests whether the immediate can be casted to 8-bit signed integer. - constexpr bool isInt8() const noexcept { return Support::isInt8(i64()); } + constexpr bool isInt8() const noexcept { return Support::isInt8(value()); } //! Tests whether the immediate can be casted to 8-bit unsigned integer. - constexpr bool isUInt8() const noexcept { return Support::isUInt8(i64()); } + constexpr bool isUInt8() const noexcept { return Support::isUInt8(value()); } //! Tests whether the immediate can be casted to 16-bit signed integer. - constexpr bool isInt16() const noexcept { return Support::isInt16(i64()); } + constexpr bool isInt16() const noexcept { return Support::isInt16(value()); } //! Tests whether the immediate can be casted to 16-bit unsigned integer. - constexpr bool isUInt16() const noexcept { return Support::isUInt16(i64()); } + constexpr bool isUInt16() const noexcept { return Support::isUInt16(value()); } //! Tests whether the immediate can be casted to 32-bit signed integer. - constexpr bool isInt32() const noexcept { return Support::isInt32(i64()); } + constexpr bool isInt32() const noexcept { return Support::isInt32(value()); } //! Tests whether the immediate can be casted to 32-bit unsigned integer. constexpr bool isUInt32() const noexcept { return _data[kDataImmValueHi] == 0; } - //! Sets immediate value to 8-bit signed integer `val`. - inline void setI8(int8_t val) noexcept { setI64(val); } - //! Sets immediate value to 8-bit unsigned integer `val`. - inline void setU8(uint8_t val) noexcept { setU64(val); } - //! Sets immediate value to 16-bit signed integer `val`. - inline void setI16(int16_t val) noexcept { setI64(val); } - //! Sets immediate value to 16-bit unsigned integer `val`. - inline void setU16(uint16_t val) noexcept { setU64(val); } - //! Sets immediate value to 32-bit signed integer `val`. - inline void setI32(int32_t val) noexcept { setI64(val); } - //! Sets immediate value to 32-bit unsigned integer `val`. - inline void setU32(uint32_t val) noexcept { setU64(val); } - //! Sets immediate value to 64-bit signed integer `val`. - inline void setI64(int64_t val) noexcept { - _data[kDataImmValueHi] = uint32_t(uint64_t(val) >> 32); - _data[kDataImmValueLo] = uint32_t(uint64_t(val) & 0xFFFFFFFFu); + //! Returns the immediate value casted to `T`. + //! + //! The value is masked before it's casted to `T` so the returned value is + //! simply the representation of `T` considering the original value's lowest + //! bits. + template<typename T> + constexpr T valueAs() const noexcept { + return T(uint64_t(value()) & Support::allOnes<typename std::make_unsigned<T>::type>()); } - //! Sets immediate value to 64-bit unsigned integer `val`. - inline void setU64(uint64_t val) noexcept { setI64(int64_t(val)); } - //! Sets immediate value to intptr_t `val`. - inline void setIPtr(intptr_t val) noexcept { setI64(val); } - //! Sets immediate value to uintptr_t `val`. - inline void setUPtr(uintptr_t val) noexcept { setU64(val); } - - //! Sets immediate value to `val`. + + //! Returns low 32-bit signed integer. + constexpr int32_t int32Lo() const noexcept { return int32_t(_data[kDataImmValueLo]); } + //! Returns high 32-bit signed integer. + constexpr int32_t int32Hi() const noexcept { return int32_t(_data[kDataImmValueHi]); } + //! Returns low 32-bit signed integer. + constexpr uint32_t uint32Lo() const noexcept { return _data[kDataImmValueLo]; } + //! Returns high 32-bit signed integer. + constexpr uint32_t uint32Hi() const noexcept { return _data[kDataImmValueHi]; } + + //! Sets immediate value to `val`, the value is casted to a signed 64-bit integer. template<typename T> - inline void setValue(T val) noexcept { setI64(int64_t(Support::asNormalized(val))); } + inline void setValue(const T& val) noexcept { + int64_t val64 = int64_t(Support::asNormalized(val)); + _data[kDataImmValueHi] = uint32_t(uint64_t(val64) >> 32); + _data[kDataImmValueLo] = uint32_t(uint64_t(val64) & 0xFFFFFFFFu); + } - inline void setDouble(double d) noexcept { setU64(Support::bitCast<uint64_t>(d)); } + inline void setDouble(double d) noexcept { + setValue(Support::bitCast<uint64_t>(d)); + } //! \} @@ -1310,15 +1309,59 @@ public: //! Clones the immediate operand. constexpr Imm clone() const noexcept { return Imm(*this); } - inline void signExtend8Bits() noexcept { setI64(int64_t(i8())); } - inline void signExtend16Bits() noexcept { setI64(int64_t(i16())); } - inline void signExtend32Bits() noexcept { setI64(int64_t(i32())); } + inline void signExtend8Bits() noexcept { setValue(int64_t(valueAs<int8_t>())); } + inline void signExtend16Bits() noexcept { setValue(int64_t(valueAs<int16_t>())); } + inline void signExtend32Bits() noexcept { setValue(int64_t(valueAs<int32_t>())); } - inline void zeroExtend8Bits() noexcept { setU64(u8()); } - inline void zeroExtend16Bits() noexcept { setU64(u16()); } + inline void zeroExtend8Bits() noexcept { setValue(valueAs<uint8_t>()); } + inline void zeroExtend16Bits() noexcept { setValue(valueAs<uint16_t>()); } inline void zeroExtend32Bits() noexcept { _data[kDataImmValueHi] = 0u; } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use valueAs<int8_t>() instead") + inline int8_t i8() const noexcept { return valueAs<int8_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint8_t>() instead") + inline uint8_t u8() const noexcept { return valueAs<uint8_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<int16_t>() instead") + inline int16_t i16() const noexcept { return valueAs<int16_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint16_t>() instead") + inline uint16_t u16() const noexcept { return valueAs<uint16_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<int32_t>() instead") + inline int32_t i32() const noexcept { return valueAs<int32_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uint32_t>() instead") + inline uint32_t u32() const noexcept { return valueAs<uint32_t>(); } + + ASMJIT_DEPRECATED("Use value() instead") + inline int64_t i64() const noexcept { return value(); } + + ASMJIT_DEPRECATED("Use valueAs<uint64_t>() instead") + inline uint64_t u64() const noexcept { return valueAs<uint64_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<intptr_t>() instead") + inline intptr_t iptr() const noexcept { return valueAs<intptr_t>(); } + + ASMJIT_DEPRECATED("Use valueAs<uintptr_t>() instead") + inline uintptr_t uptr() const noexcept { return valueAs<uintptr_t>(); } + + ASMJIT_DEPRECATED("Use int32Lo() instead") + inline int32_t i32Lo() const noexcept { return int32Lo(); } + + ASMJIT_DEPRECATED("Use uint32Lo() instead") + inline uint32_t u32Lo() const noexcept { return uint32Lo(); } + + ASMJIT_DEPRECATED("Use int32Hi() instead") + inline int32_t i32Hi() const noexcept { return int32Hi(); } + + ASMJIT_DEPRECATED("Use uint32Hi() instead") + inline uint32_t u32Hi() const noexcept { return uint32Hi(); } +#endif // !ASMJIT_NO_DEPRECATED }; //! Creates a new immediate operand. @@ -1332,6 +1375,44 @@ static constexpr Imm imm(T val) noexcept { //! \} +// ============================================================================ +// [asmjit::Globals::none] +// ============================================================================ + +namespace Globals { + //! \ingroup asmjit_assembler + //! + //! A default-constructed operand of `Operand_::kOpNone` type. + static constexpr const Operand none; +} + +// ============================================================================ +// [asmjit::Support::ForwardOp] +// ============================================================================ + +//! \cond INTERNAL +namespace Support { + +template<typename T, bool IsIntegral> +struct ForwardOpImpl { + static ASMJIT_INLINE const T& forward(const T& value) noexcept { return value; } +}; + +template<typename T> +struct ForwardOpImpl<T, true> { + static ASMJIT_INLINE Imm forward(const T& value) noexcept { return Imm(value); } +}; + +//! Either forwards operand T or returns a new operand for T if T is a type +//! convertible to operand. At the moment this is only used to convert integers +//! to \ref Imm operands. +template<typename T> +struct ForwardOp : public ForwardOpImpl<T, std::is_integral<typename std::decay<T>::type>::value> {}; + +} + +//! \endcond + ASMJIT_END_NAMESPACE #endif // ASMJIT_CORE_OPERAND_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/core/osutils.h b/3rdparty/asmjit/src/asmjit/core/osutils.h index b9a2df4ad8f..a4691295b20 100644 --- a/3rdparty/asmjit/src/asmjit/core/osutils.h +++ b/3rdparty/asmjit/src/asmjit/core/osutils.h @@ -28,7 +28,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ @@ -50,7 +50,7 @@ namespace OSUtils { //! Lock. //! //! Lock is internal, it cannot be used outside of AsmJit, however, its internal -//! layout is exposed as it's used by some other public classes. +//! layout is exposed as it's used by some other classes, which are public. class Lock { public: ASMJIT_NONCOPYABLE(Lock) @@ -78,60 +78,8 @@ public: inline void lock() noexcept; inline void unlock() noexcept; }; - -#ifdef ASMJIT_EXPORTS -#if defined(_WIN32) - -// Win32 implementation. -static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION"); -static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION"); - -inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } -inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } - -#elif !defined(__EMSCRIPTEN__) - -// PThread implementation. -inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } -inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); } -inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); } -inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); } - -#else - -// Dummy implementation - Emscripten or other unsupported platform. -inline Lock::Lock() noexcept {} -inline Lock::~Lock() noexcept {} -inline void Lock::lock() noexcept {} -inline void Lock::unlock() noexcept {} - -#endif -#endif - //! \endcond -// ============================================================================ -// [asmjit::LockGuard] -// ============================================================================ - -#ifdef ASMJIT_EXPORTS -//! \cond INTERNAL - -//! Scoped lock. -struct LockGuard { - ASMJIT_NONCOPYABLE(LockGuard) - - Lock& _target; - - inline LockGuard(Lock& target) noexcept : _target(target) { _target.lock(); } - inline ~LockGuard() noexcept { _target.unlock(); } -}; - -//! \endcond -#endif - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/osutils_p.h b/3rdparty/asmjit/src/asmjit/core/osutils_p.h new file mode 100644 index 00000000000..31db308bdcf --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/core/osutils_p.h @@ -0,0 +1,94 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_CORE_OSUTILS_P_H_INCLUDED +#define ASMJIT_CORE_OSUTILS_P_H_INCLUDED + +#include "../core/osutils.h" + +ASMJIT_BEGIN_NAMESPACE + +//! \cond INTERNAL +//! \addtogroup asmjit_utilities +//! \{ + +// ============================================================================ +// [asmjit::Lock] +// ============================================================================ + +#if defined(_WIN32) + +// Windows implementation. +static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION"); +static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION"); + +inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } +inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); } + +#elif !defined(__EMSCRIPTEN__) + +// PThread implementation. +#ifdef PTHREAD_MUTEX_INITIALIZER +inline Lock::Lock() noexcept : _handle(PTHREAD_MUTEX_INITIALIZER) {} +#else +inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); } +#endif +inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); } +inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); } +inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); } + +#else + +// Dummy implementation - Emscripten or other unsupported platform. +inline Lock::Lock() noexcept {} +inline Lock::~Lock() noexcept {} +inline void Lock::lock() noexcept {} +inline void Lock::unlock() noexcept {} + +#endif + +// ============================================================================ +// [asmjit::LockGuard] +// ============================================================================ + +//! Scoped lock. +class LockGuard { +public: + ASMJIT_NONCOPYABLE(LockGuard) + + Lock& _target; + + inline LockGuard(Lock& target) noexcept + : _target(target) { _target.lock(); } + inline ~LockGuard() noexcept { _target.unlock(); } +}; + +//! \} +//! \endcond + +ASMJIT_END_NAMESPACE + +#endif // ASMJIT_CORE_OSUTILS_P_H_INCLUDED + diff --git a/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h b/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h index 6f400ad1c3a..50624bf58cd 100644 --- a/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rabuilders_p.h @@ -27,6 +27,7 @@ #include "../core/api-config.h" #ifndef ASMJIT_NO_COMPILER +#include "../core/formatter.h" #include "../core/rapass_p.h" ASMJIT_BEGIN_NAMESPACE @@ -66,7 +67,7 @@ public: static constexpr uint32_t kCodeIndentation = 4; // NOTE: This is a bit hacky. There are some nodes which are processed twice - // (see `onBeforeCall()` and `onBeforeRet()`) as they can insert some nodes + // (see `onBeforeInvoke()` and `onBeforeRet()`) as they can insert some nodes // around them. Since we don't have any flags to mark these we just use their // position that is [at that time] unassigned. static constexpr uint32_t kNodePositionDidOnBefore = 0xFFFFFFFFu; @@ -122,7 +123,7 @@ public: // Instruction | Jump | Invoke | Return // ------------------------------------ - // Handle `InstNode`, `FuncCallNode`, and `FuncRetNode`. All of them + // Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them // share the same interface that provides operands that have read/write // semantics. if (ASMJIT_UNLIKELY(!_curBlock)) { @@ -135,18 +136,18 @@ public: _hasCode = true; - if (node->isFuncCall() || node->isFuncRet()) { + if (node->isInvoke() || node->isFuncRet()) { if (node->position() != kNodePositionDidOnBefore) { // Call and Reg are complicated as they may insert some surrounding // code around them. The simplest approach is to get the previous // node, call the `onBefore()` handlers and then check whether // anything changed and restart if so. By restart we mean that the // current `node` would go back to the first possible inserted node - // by `onBeforeCall()` or `onBeforeRet()`. + // by `onBeforeInvoke()` or `onBeforeRet()`. BaseNode* prev = node->prev(); - if (node->type() == BaseNode::kNodeFuncCall) - ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeCall(node->as<FuncCallNode>())); + if (node->type() == BaseNode::kNodeInvoke) + ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeInvoke(node->as<InvokeNode>())); else ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeRet(node->as<FuncRetNode>())); @@ -159,7 +160,7 @@ public: node->setPosition(kNodePositionDidOnBefore); node = prev->next(); - // `onBeforeCall()` and `onBeforeRet()` can only insert instructions. + // `onBeforeInvoke()` and `onBeforeRet()` can only insert instructions. ASMJIT_ASSERT(node->isInst()); } @@ -179,8 +180,8 @@ public: ib.reset(); ASMJIT_PROPAGATE(static_cast<This*>(this)->onInst(inst, controlType, ib)); - if (node->isFuncCall()) { - ASMJIT_PROPAGATE(static_cast<This*>(this)->onCall(inst->as<FuncCallNode>(), ib)); + if (node->isInvoke()) { + ASMJIT_PROPAGATE(static_cast<This*>(this)->onInvoke(inst->as<InvokeNode>(), ib)); } if (node->isFuncRet()) { @@ -409,7 +410,7 @@ public: logNode(node, kRootIndentation); // Unlikely: Assume that the exit label is reached only once per function. - if (ASMJIT_UNLIKELY(node->as<LabelNode>()->id() == _exitLabelId)) { + if (ASMJIT_UNLIKELY(node->as<LabelNode>()->labelId() == _exitLabelId)) { _curBlock->setLast(node); _curBlock->makeConstructed(_blockRegStats); ASMJIT_PROPAGATE(_pass->addExitBlock(_curBlock)); @@ -492,7 +493,7 @@ public: // Reset everything we may need. _blockRegStats.reset(); - _exitLabelId = func->exitNode()->id(); + _exitLabelId = func->exitNode()->labelId(); // Initially we assume there is no code in the function body. _hasCode = false; @@ -599,11 +600,11 @@ public: _sb.clear(); _sb.appendChars(' ', indentation); if (action) { - _sb.appendString(action); - _sb.appendChar(' '); + _sb.append(action); + _sb.append(' '); } - Logging::formatNode(_sb, _logFlags, cc(), node); - _sb.appendChar('\n'); + Formatter::formatNode(_sb, _logFlags, cc(), node); + _sb.append('\n'); _logger->log(_sb); } #else diff --git a/3rdparty/asmjit/src/asmjit/core/radefs_p.h b/3rdparty/asmjit/src/asmjit/core/radefs_p.h index c63a1a33966..b77ed1bd738 100644 --- a/3rdparty/asmjit/src/asmjit/core/radefs_p.h +++ b/3rdparty/asmjit/src/asmjit/core/radefs_p.h @@ -28,7 +28,7 @@ #ifndef ASMJIT_NO_COMPILER #include "../core/compiler.h" -#include "../core/logging.h" +#include "../core/logger.h" #include "../core/support.h" #include "../core/zone.h" #include "../core/zonevector.h" @@ -984,10 +984,7 @@ public: //! Stack allocation is preferred. kFlagStackPreferred = 0x00000004u, //! Marked for stack argument reassignment. - kFlagStackArgToStack = 0x00000008u, - - // TODO: Used? - kFlagDirtyStats = 0x80000000u + kFlagStackArgToStack = 0x00000008u }; enum ArgIndex : uint32_t { @@ -1004,7 +1001,7 @@ public: _tiedReg(nullptr), _stackSlot(nullptr), _info(vReg->info()), - _flags(kFlagDirtyStats), + _flags(0), _allocatedMask(0), _clobberSurvivalMask(0), _regByteMask(0), diff --git a/3rdparty/asmjit/src/asmjit/core/ralocal.cpp b/3rdparty/asmjit/src/asmjit/core/ralocal.cpp index 98d7d8fd568..88cb86bde18 100644 --- a/3rdparty/asmjit/src/asmjit/core/ralocal.cpp +++ b/3rdparty/asmjit/src/asmjit/core/ralocal.cpp @@ -596,7 +596,7 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept { // DECIDE whether to MOVE or SPILL. if (allocableRegs) { - uint32_t reassignedId = decideOnUnassignment(group, workId, assignedId, allocableRegs); + uint32_t reassignedId = decideOnReassignment(group, workId, assignedId, allocableRegs); if (reassignedId != RAAssignment::kPhysNone) { ASMJIT_PROPAGATE(onMoveReg(group, workId, reassignedId, assignedId)); allocableRegs ^= Support::bitMask(reassignedId); @@ -897,7 +897,7 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co // Additional instructions emitted to switch from the current state to // the `target` state. This means that we have to move these instructions // into an independent code block and patch the jump location. - Operand& targetOp(node->opType(node->opCount() - 1)); + Operand& targetOp = node->op(node->opCount() - 1); if (ASMJIT_UNLIKELY(!targetOp.isLabel())) return DebugUtils::errored(kErrorInvalidState); @@ -970,38 +970,39 @@ Error RALocalAllocator::allocJumpTable(InstNode* node, const RABlocks& targets, // ============================================================================ uint32_t RALocalAllocator::decideOnAssignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { - DebugUtils::unused(group, physId); ASMJIT_ASSERT(allocableRegs != 0); + DebugUtils::unused(group, physId); RAWorkReg* workReg = workRegById(workId); - // HIGHEST PRIORITY: Home register id. + // Prefer home register id, if possible. if (workReg->hasHomeRegId()) { uint32_t homeId = workReg->homeRegId(); if (Support::bitTest(allocableRegs, homeId)) return homeId; } - // HIGH PRIORITY: Register IDs used upon block entries. + // Prefer registers used upon block entries. uint32_t previouslyAssignedRegs = workReg->allocatedMask(); if (allocableRegs & previouslyAssignedRegs) allocableRegs &= previouslyAssignedRegs; - if (Support::isPowerOf2(allocableRegs)) - return Support::ctz(allocableRegs); - - // TODO: This is not finished. return Support::ctz(allocableRegs); } -uint32_t RALocalAllocator::decideOnUnassignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { +uint32_t RALocalAllocator::decideOnReassignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept { ASMJIT_ASSERT(allocableRegs != 0); + DebugUtils::unused(group, physId); - // TODO: - DebugUtils::unused(allocableRegs, group, workId, physId); + RAWorkReg* workReg = workRegById(workId); + + // Prefer allocating back to HomeId, if possible. + if (workReg->hasHomeRegId()) { + if (Support::bitTest(allocableRegs, workReg->homeRegId())) + return workReg->homeRegId(); + } - // if (!_curAssignment.isPhysDirty(group, physId)) { - // } + // TODO: [Register Allocator] This could be improved. // Decided to SPILL. return RAAssignment::kPhysNone; diff --git a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h index 0af595b3cd5..c944aad2bb4 100644 --- a/3rdparty/asmjit/src/asmjit/core/ralocal_p.h +++ b/3rdparty/asmjit/src/asmjit/core/ralocal_p.h @@ -198,12 +198,13 @@ public: //! Decides on register assignment. uint32_t decideOnAssignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; - //! Decides on whether to MOVE or SPILL the given WorkReg. + //! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated + //! in a physical register that have to be used by another WorkReg. //! //! The function must return either `RAAssignment::kPhysNone`, which means that - //! the WorkReg should be spilled, or a valid physical register ID, which means - //! that the register should be moved to that physical register instead. - uint32_t decideOnUnassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; + //! the WorkReg of `workId` should be spilled, or a valid physical register ID, + //! which means that the register should be moved to that physical register instead. + uint32_t decideOnReassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept; //! Decides on best spill given a register mask `spillableRegs` uint32_t decideOnSpillFor(uint32_t group, uint32_t workId, uint32_t spillableRegs, uint32_t* spillWorkId) const noexcept; diff --git a/3rdparty/asmjit/src/asmjit/core/rapass.cpp b/3rdparty/asmjit/src/asmjit/core/rapass.cpp index 1174635d75d..c5b5ce88a16 100644 --- a/3rdparty/asmjit/src/asmjit/core/rapass.cpp +++ b/3rdparty/asmjit/src/asmjit/core/rapass.cpp @@ -24,6 +24,7 @@ #include "../core/api-build_p.h" #ifndef ASMJIT_NO_COMPILER +#include "../core/formatter.h" #include "../core/ralocal_p.h" #include "../core/rapass_p.h" #include "../core/support.h" @@ -161,7 +162,7 @@ static void RAPass_resetVirtRegData(RAPass* self) noexcept { } } -Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept { +Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) { _allocator.reset(zone); #ifndef ASMJIT_NO_LOGGING @@ -194,7 +195,6 @@ Error RAPass::runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept // Must be called regardless of the allocation status. onDone(); - // TODO: I don't like this... // Reset possible connections introduced by the register allocator. RAPass_resetVirtRegData(this); @@ -472,7 +472,7 @@ Error RAPass::buildViews() noexcept { if (block->hasSuccessors()) { sb.appendFormat(" #%u -> {", block->blockId()); _dumpBlockIds(sb, block->successors()); - sb.appendString("}\n"); + sb.append("}\n"); } else { sb.appendFormat(" #%u -> {Exit}\n", block->blockId()); @@ -1133,11 +1133,11 @@ static void RAPass_dumpSpans(String& sb, uint32_t index, const LiveRegSpans& liv for (uint32_t i = 0; i < liveSpans.size(); i++) { const LiveRegSpan& liveSpan = liveSpans[i]; - if (i) sb.appendString(", "); + if (i) sb.append(", "); sb.appendFormat("[%u:%u@%u]", liveSpan.a, liveSpan.b, liveSpan.id); } - sb.appendChar('\n'); + sb.append('\n'); } #endif @@ -1296,10 +1296,10 @@ ASMJIT_FAVOR_SPEED Error RAPass::binPack(uint32_t group) noexcept { sb.appendFormat(" Unassigned (%u): ", count); for (i = 0; i < numWorkRegs; i++) { RAWorkReg* workReg = workRegs[i]; - if (i) sb.appendString(", "); - sb.appendString(workReg->name()); + if (i) sb.append(", "); + sb.append(workReg->name()); } - sb.appendChar('\n'); + sb.append('\n'); logger->log(sb); }); } @@ -1380,8 +1380,8 @@ Error RAPass::runLocalAllocator() noexcept { } ASMJIT_PROPAGATE(lra.allocInst(inst)); - if (inst->type() == BaseNode::kNodeFuncCall) - ASMJIT_PROPAGATE(onEmitPreCall(inst->as<FuncCallNode>())); + if (inst->type() == BaseNode::kNodeInvoke) + ASMJIT_PROPAGATE(onEmitPreCall(inst->as<InvokeNode>())); else ASMJIT_PROPAGATE(lra.spillAfterAllocation(inst)); } @@ -1595,7 +1595,7 @@ Error RAPass::useTemporaryMem(BaseMem& out, uint32_t size, uint32_t alignment) n ASMJIT_ASSERT(alignment <= 64); if (_temporaryMem.isNone()) { - ASMJIT_PROPAGATE(cc()->_newStack(_temporaryMem.as<BaseMem>(), size, alignment)); + ASMJIT_PROPAGATE(cc()->_newStack(&_temporaryMem.as<BaseMem>(), size, alignment)); } else { ASMJIT_ASSERT(_temporaryMem.as<BaseMem>().isRegHome()); @@ -1852,27 +1852,31 @@ static void RAPass_dumpRAInst(RAPass* pass, String& sb, const RAInst* raInst) no for (uint32_t i = 0; i < tiedCount; i++) { const RATiedReg& tiedReg = tiedRegs[i]; - if (i != 0) sb.appendChar(' '); + if (i != 0) + sb.append(' '); sb.appendFormat("%s{", pass->workRegById(tiedReg.workId())->name()); - sb.appendChar(tiedReg.isReadWrite() ? 'X' : - tiedReg.isRead() ? 'R' : - tiedReg.isWrite() ? 'W' : '?'); + sb.append(tiedReg.isReadWrite() ? 'X' : + tiedReg.isRead() ? 'R' : + tiedReg.isWrite() ? 'W' : '?'); if (tiedReg.hasUseId()) sb.appendFormat("|Use=%u", tiedReg.useId()); else if (tiedReg.isUse()) - sb.appendString("|Use"); + sb.append("|Use"); if (tiedReg.hasOutId()) sb.appendFormat("|Out=%u", tiedReg.outId()); else if (tiedReg.isOut()) - sb.appendString("|Out"); + sb.append("|Out"); + + if (tiedReg.isLast()) + sb.append("|Last"); - if (tiedReg.isLast()) sb.appendString("|Last"); - if (tiedReg.isKill()) sb.appendString("|Kill"); + if (tiedReg.isKill()) + sb.append("|Kill"); - sb.appendString("}"); + sb.append("}"); } } @@ -1887,13 +1891,13 @@ ASMJIT_FAVOR_SIZE Error RAPass::annotateCode() noexcept { BaseNode* last = block->last(); for (;;) { sb.clear(); - Logging::formatNode(sb, loggerFlags, cc(), node); + Formatter::formatNode(sb, loggerFlags, cc(), node); if ((loggerFlags & FormatOptions::kFlagDebugRA) != 0 && node->isInst() && node->hasPassData()) { const RAInst* raInst = node->passData<RAInst>(); if (raInst->tiedCount() > 0) { sb.padEnd(40); - sb.appendString(" | "); + sb.append(" | "); RAPass_dumpRAInst(this, sb, raInst); } } @@ -1940,15 +1944,15 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpBlockLiveness(String& sb, const RABlock* bl if (!n) sb.appendFormat(" %s [", bitsName); else - sb.appendString(", "); + sb.append(", "); - sb.appendString(wReg->name()); + sb.append(wReg->name()); n++; } } if (n) - sb.appendString("]\n"); + sb.append("]\n"); } return kErrorOk; @@ -1961,10 +1965,10 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpLiveSpans(String& sb) noexcept { for (uint32_t workId = 0; workId < numWorkRegs; workId++) { RAWorkReg* workReg = _workRegs[workId]; - sb.appendString(" "); + sb.append(" "); size_t oldSize = sb.size(); - sb.appendString(workReg->name()); + sb.append(workReg->name()); sb.padEnd(oldSize + maxSize); RALiveStats& stats = workReg->liveStats(); @@ -1973,16 +1977,17 @@ ASMJIT_FAVOR_SIZE Error RAPass::_dumpLiveSpans(String& sb) noexcept { stats.width(), stats.freq(), stats.priority()); - sb.appendString(": "); + sb.append(": "); LiveRegSpans& liveSpans = workReg->liveSpans(); for (uint32_t x = 0; x < liveSpans.size(); x++) { const LiveRegSpan& liveSpan = liveSpans[x]; - if (x) sb.appendString(", "); + if (x) + sb.append(", "); sb.appendFormat("[%u:%u]", liveSpan.a, liveSpan.b); } - sb.appendChar('\n'); + sb.append('\n'); } return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/core/rapass_p.h b/3rdparty/asmjit/src/asmjit/core/rapass_p.h index 5a575ad4bae..df5eb9d7aad 100644 --- a/3rdparty/asmjit/src/asmjit/core/rapass_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rapass_p.h @@ -42,6 +42,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::RABlock] // ============================================================================ +//! Basic block used by register allocator pass. class RABlock { public: ASMJIT_NONCOPYABLE(RABlock) @@ -53,6 +54,7 @@ public: kUnassignedId = 0xFFFFFFFFu }; + //! Basic block flags. enum Flags : uint32_t { //! Block has been constructed from nodes. kFlagIsConstructed = 0x00000001u, @@ -111,9 +113,6 @@ public: //! Block successors. RABlocks _successors; - // TODO: Used? - RABlocks _doms; - enum LiveType : uint32_t { kLiveIn = 0, kLiveOut = 1, @@ -157,7 +156,6 @@ public: _idom(nullptr), _predecessors(), _successors(), - _doms(), _sharedAssignmentId(Globals::kInvalidId), _entryScratchGpRegs(0), _exitScratchGpRegs(0), @@ -470,7 +468,7 @@ public: //! \name Utilities //! \{ - ASMJIT_INLINE Error add(RAWorkReg* workReg, uint32_t flags, uint32_t allocable, uint32_t useId, uint32_t useRewriteMask, uint32_t outId, uint32_t outRewriteMask, uint32_t rmSize = 0) noexcept { + Error add(RAWorkReg* workReg, uint32_t flags, uint32_t allocable, uint32_t useId, uint32_t useRewriteMask, uint32_t outId, uint32_t outRewriteMask, uint32_t rmSize = 0) noexcept { uint32_t group = workReg->group(); RATiedReg* tiedReg = workReg->tiedReg(); @@ -510,7 +508,6 @@ public: if (ASMJIT_UNLIKELY(tiedReg->hasOutId())) return DebugUtils::errored(kErrorOverlappedRegs); tiedReg->setOutId(outId); - // TODO: ? _used[group] |= Support::bitMask(outId); } tiedReg->addRefCount(); @@ -523,7 +520,7 @@ public: } } - ASMJIT_INLINE Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept { + Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept { ASMJIT_ASSERT(useId != BaseReg::kIdBad); uint32_t flags = RATiedReg::kUse | RATiedReg::kRead | RATiedReg::kUseFixed; @@ -563,7 +560,7 @@ public: } } - ASMJIT_INLINE Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept { + Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept { ASMJIT_ASSERT(outId != BaseReg::kIdBad); uint32_t flags = RATiedReg::kOut | RATiedReg::kWrite | RATiedReg::kOutFixed; @@ -761,14 +758,14 @@ public: //! \name Accessors //! \{ - //! Returns `Logger` passed to `runOnFunction()`. + //! Returns \ref Logger passed to \ref runOnFunction(). inline Logger* logger() const noexcept { return _logger; } - //! Returns `Logger` passed to `runOnFunction()` or null if `kOptionDebugPasses` is not set. + //! Returns \ref Logger passed to \ref runOnFunction() or null if `kOptionDebugPasses` is not set. inline Logger* debugLogger() const noexcept { return _debugLogger; } - //! Returns `Zone` passed to `runOnFunction()`. + //! Returns \ref Zone passed to \ref runOnFunction(). inline Zone* zone() const noexcept { return _allocator.zone(); } - //! Returns `ZoneAllocator` used by the register allocator. + //! Returns \ref ZoneAllocator used by the register allocator. inline ZoneAllocator* allocator() const noexcept { return const_cast<ZoneAllocator*>(&_allocator); } inline const ZoneVector<RASharedAssignment>& sharedAssignments() const { return _sharedAssignments; } @@ -800,7 +797,7 @@ public: } //! Runs the register allocator for the given `func`. - Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) noexcept override; + Error runOnFunction(Zone* zone, Logger* logger, FuncNode* func) override; //! Performs all allocation steps sequentially, called by `runOnFunction()`. Error onPerformAllSteps() noexcept; @@ -810,11 +807,11 @@ public: //! \name Events //! \{ - //! Called by `runOnFunction()` before the register allocation to initialize + //! Called by \ref runOnFunction() before the register allocation to initialize //! architecture-specific data and constraints. virtual void onInit() noexcept = 0; - //! Called by `runOnFunction()` after register allocation to clean everything + //! Called by \ref runOnFunction(` after register allocation to clean everything //! up. Called even if the register allocation failed. virtual void onDone() noexcept = 0; @@ -1009,7 +1006,7 @@ public: //! \{ //! Returns a native size of the general-purpose register of the target architecture. - inline uint32_t gpSize() const noexcept { return _sp.size(); } + inline uint32_t registerSize() const noexcept { return _sp.size(); } inline uint32_t availableRegCount(uint32_t group) const noexcept { return _availableRegCount[group]; } inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _workRegs[workId]; } @@ -1049,9 +1046,11 @@ public: inline RAStackSlot* getOrCreateStackSlot(RAWorkReg* workReg) noexcept { RAStackSlot* slot = workReg->stackSlot(); - if (slot) return slot; - slot = _stackAllocator.newSlot(_sp.id(), workReg->virtReg()->virtSize(), workReg->virtReg()->alignment(), 0); + if (slot) + return slot; + + slot = _stackAllocator.newSlot(_sp.id(), workReg->virtReg()->virtSize(), workReg->virtReg()->alignment(), RAStackSlot::kFlagRegHome); workReg->_stackSlot = slot; workReg->markStackUsed(); return slot; @@ -1166,7 +1165,7 @@ public: virtual Error onEmitSave(uint32_t workId, uint32_t srcPhysId) noexcept = 0; virtual Error onEmitJump(const Label& label) noexcept = 0; - virtual Error onEmitPreCall(FuncCallNode* call) noexcept = 0; + virtual Error onEmitPreCall(InvokeNode* invokeNode) noexcept = 0; //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/rastack.cpp b/3rdparty/asmjit/src/asmjit/core/rastack.cpp index 342b7ce7c9e..b886279a5f3 100644 --- a/3rdparty/asmjit/src/asmjit/core/rastack.cpp +++ b/3rdparty/asmjit/src/asmjit/core/rastack.cpp @@ -43,11 +43,9 @@ RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32 slot->_baseRegId = uint8_t(baseRegId); slot->_alignment = uint8_t(Support::max<uint32_t>(alignment, 1)); - slot->_reserved[0] = 0; - slot->_reserved[1] = 0; + slot->_flags = uint16_t(flags); slot->_useCount = 0; slot->_size = size; - slot->_flags = flags; slot->_weight = 0; slot->_offset = 0; @@ -92,7 +90,7 @@ Error RAStackAllocator::calculateStackFrame() noexcept { uint32_t alignment = slot->alignment(); ASMJIT_ASSERT(alignment > 0); - uint32_t power = Support::ctz(alignment); + uint32_t power = Support::min<uint32_t>(Support::ctz(alignment), 6); uint64_t weight; if (slot->isRegHome()) @@ -128,7 +126,8 @@ Error RAStackAllocator::calculateStackFrame() noexcept { ZoneVector<RAStackGap> gaps[kSizeCount - 1]; for (RAStackSlot* slot : _slots) { - if (slot->isStackArg()) continue; + if (slot->isStackArg()) + continue; uint32_t slotAlignment = slot->alignment(); uint32_t alignedOffset = Support::alignUp(offset, slotAlignment); diff --git a/3rdparty/asmjit/src/asmjit/core/rastack_p.h b/3rdparty/asmjit/src/asmjit/core/rastack_p.h index d45f7aa8896..33d4e1d15e8 100644 --- a/3rdparty/asmjit/src/asmjit/core/rastack_p.h +++ b/3rdparty/asmjit/src/asmjit/core/rastack_p.h @@ -41,10 +41,14 @@ ASMJIT_BEGIN_NAMESPACE //! Stack slot. struct RAStackSlot { + //! Stack slot flags. + //! + //! TODO: kFlagStackArg is not used by the current implementation, do we need to keep it? enum Flags : uint32_t { - // TODO: kFlagRegHome is apparently not used, but isRegHome() is. - kFlagRegHome = 0x00000001u, //!< Stack slot is register home slot. - kFlagStackArg = 0x00000002u //!< Stack slot position matches argument passed via stack. + //! Stack slot is register home slot. + kFlagRegHome = 0x0001u, + //! Stack slot position matches argument passed via stack. + kFlagStackArg = 0x0002u }; enum ArgIndex : uint32_t { @@ -56,17 +60,15 @@ struct RAStackSlot { //! Minimum alignment required by the slot. uint8_t _alignment; //! Reserved for future use. - uint8_t _reserved[2]; + uint16_t _flags; //! Size of memory required by the slot. uint32_t _size; - //! Slot flags. - uint32_t _flags; //! Usage counter (one unit equals one memory access). uint32_t _useCount; - //! Weight of the slot (calculated by `calculateStackFrame()`). + //! Weight of the slot, calculated by \ref RAStackAllocator::calculateStackFrame(). uint32_t _weight; - //! Stack offset (calculated by `calculateStackFrame()`). + //! Stack offset, calculated by \ref RAStackAllocator::calculateStackFrame(). int32_t _offset; //! \name Accessors @@ -79,9 +81,11 @@ struct RAStackSlot { inline uint32_t alignment() const noexcept { return _alignment; } inline uint32_t flags() const noexcept { return _flags; } - inline void addFlags(uint32_t flags) noexcept { _flags |= flags; } - inline bool isRegHome() const noexcept { return (_flags & kFlagRegHome) != 0; } - inline bool isStackArg() const noexcept { return (_flags & kFlagStackArg) != 0; } + inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; } + inline void addFlags(uint32_t flags) noexcept { _flags = uint16_t(_flags | flags); } + + inline bool isRegHome() const noexcept { return hasFlag(kFlagRegHome); } + inline bool isStackArg() const noexcept { return hasFlag(kFlagStackArg); } inline uint32_t useCount() const noexcept { return _useCount; } inline void addUseCount(uint32_t n = 1) noexcept { _useCount += n; } diff --git a/3rdparty/asmjit/src/asmjit/core/string.cpp b/3rdparty/asmjit/src/asmjit/core/string.cpp index 564a566f042..e059884c844 100644 --- a/3rdparty/asmjit/src/asmjit/core/string.cpp +++ b/3rdparty/asmjit/src/asmjit/core/string.cpp @@ -34,7 +34,7 @@ ASMJIT_BEGIN_NAMESPACE static const char String_baseN[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; constexpr size_t kMinAllocSize = 64; -constexpr size_t kMaxAllocSize = std::numeric_limits<size_t>::max() - Globals::kGrowThreshold; +constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold; // ============================================================================ // [asmjit::String] @@ -150,7 +150,7 @@ char* String::prepare(uint32_t op, size_t size) noexcept { } } -Error String::assignString(const char* data, size_t size) noexcept { +Error String::assign(const char* data, size_t size) noexcept { char* dst = nullptr; // Null terminated string without `size` specified. @@ -222,7 +222,8 @@ Error String::_opString(uint32_t op, const char* str, size_t size) noexcept { return kErrorOk; char* p = prepare(op, size); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); memcpy(p, str, size); return kErrorOk; @@ -230,7 +231,8 @@ Error String::_opString(uint32_t op, const char* str, size_t size) noexcept { Error String::_opChar(uint32_t op, char c) noexcept { char* p = prepare(op, 1); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); *p = c; return kErrorOk; @@ -241,7 +243,8 @@ Error String::_opChars(uint32_t op, char c, size_t n) noexcept { return kErrorOk; char* p = prepare(op, n); - if (!p) return DebugUtils::errored(kErrorOutOfMemory); + if (!p) + return DebugUtils::errored(kErrorOutOfMemory); memset(p, c, n); return kErrorOk; @@ -349,7 +352,7 @@ Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) return kErrorOk; if (separator) { - if (ASMJIT_UNLIKELY(size >= std::numeric_limits<size_t>::max() / 3)) + if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 3)) return DebugUtils::errored(kErrorOutOfMemory); dst = prepare(op, size * 3 - 1); @@ -369,7 +372,7 @@ Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) } } else { - if (ASMJIT_UNLIKELY(size >= std::numeric_limits<size_t>::max() / 2)) + if (ASMJIT_UNLIKELY(size >= SIZE_MAX / 2)) return DebugUtils::errored(kErrorOutOfMemory); dst = prepare(op, size * 2); @@ -404,6 +407,9 @@ Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { int fmtResult; size_t outputSize; + va_list apCopy; + va_copy(apCopy, ap); + if (remainingCapacity >= 128) { fmtResult = vsnprintf(data() + startAt, remainingCapacity, fmt, ap); outputSize = size_t(fmtResult); @@ -428,7 +434,7 @@ Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept { if (ASMJIT_UNLIKELY(!p)) return DebugUtils::errored(kErrorOutOfMemory); - fmtResult = vsnprintf(p, outputSize + 1, fmt, ap); + fmtResult = vsnprintf(p, outputSize + 1, fmt, apCopy); ASMJIT_ASSERT(size_t(fmtResult) == outputSize); return kErrorOk; @@ -483,7 +489,7 @@ UNIT(core_string) { EXPECT(s.isLarge() == false); EXPECT(s.isExternal() == false); - EXPECT(s.assignChar('a') == kErrorOk); + EXPECT(s.assign('a') == kErrorOk); EXPECT(s.size() == 1); EXPECT(s.capacity() == String::kSSOCapacity); EXPECT(s.data()[0] == 'a'); @@ -502,7 +508,7 @@ UNIT(core_string) { EXPECT(s.eq("bbbb") == true); EXPECT(s.eq("bbbb", 4) == true); - EXPECT(s.assignString("abc") == kErrorOk); + EXPECT(s.assign("abc") == kErrorOk); EXPECT(s.size() == 3); EXPECT(s.capacity() == String::kSSOCapacity); EXPECT(s.data()[0] == 'a'); @@ -513,7 +519,7 @@ UNIT(core_string) { EXPECT(s.eq("abc", 3) == true); const char* large = "Large string that will not fit into SSO buffer"; - EXPECT(s.assignString(large) == kErrorOk); + EXPECT(s.assign(large) == kErrorOk); EXPECT(s.isLarge() == true); EXPECT(s.size() == strlen(large)); EXPECT(s.capacity() > String::kSSOCapacity); @@ -522,7 +528,7 @@ UNIT(core_string) { const char* additional = " (additional content)"; EXPECT(s.isLarge() == true); - EXPECT(s.appendString(additional) == kErrorOk); + EXPECT(s.append(additional) == kErrorOk); EXPECT(s.size() == strlen(large) + strlen(additional)); EXPECT(s.clear() == kErrorOk); diff --git a/3rdparty/asmjit/src/asmjit/core/string.h b/3rdparty/asmjit/src/asmjit/core/string.h index 22108f21f8b..4c490d87b1d 100644 --- a/3rdparty/asmjit/src/asmjit/core/string.h +++ b/3rdparty/asmjit/src/asmjit/core/string.h @@ -29,10 +29,34 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ // ============================================================================ +// [asmjit::FixedString] +// ============================================================================ + +//! A fixed string - only useful for strings that would never exceed `N - 1` +//! characters; always null-terminated. +template<size_t N> +union FixedString { + enum : uint32_t { + kNumU32 = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t)) + }; + + char str[kNumU32 * sizeof(uint32_t)]; + uint32_t u32[kNumU32]; + + //! \name Utilities + //! \{ + + inline bool eq(const char* other) const noexcept { + return strcmp(str, other) == 0; + } + + //! \} +}; +// ============================================================================ // [asmjit::String] // ============================================================================ @@ -60,8 +84,10 @@ public: //! String operation. enum Op : uint32_t { - kOpAssign = 0, - kOpAppend = 1 + //! Assignment - a new content replaces the current one. + kOpAssign = 0, + //! Append - a new content is appended to the string. + kOpAppend = 1 }; //! String format flags. @@ -114,12 +140,13 @@ public: //! \name Construction & Destruction //! \{ + //! Creates a default-initialized string if zero length. inline String() noexcept : _small {} {} + //! Creates a string that takes ownership of the content of the `other` string. inline String(String&& other) noexcept { - for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_raw.uptr); i++) - _raw.uptr[i] = other._raw.uptr[i]; + _raw = other._raw; other._resetInternal(); } @@ -135,6 +162,12 @@ public: //! \name Overloaded Operators //! \{ + inline String& operator=(String&& other) noexcept { + swap(other); + other.reset(); + return *this; + } + inline bool operator==(const char* other) const noexcept { return eq(other); } inline bool operator!=(const char* other) const noexcept { return !eq(other); } @@ -149,13 +182,21 @@ public: inline bool isLarge() const noexcept { return _type >= kTypeLarge; } inline bool isExternal() const noexcept { return _type == kTypeExternal; } + //! Tests whether the string is empty. inline bool empty() const noexcept { return size() == 0; } + //! Returns the size of the string. inline size_t size() const noexcept { return isLarge() ? size_t(_large.size) : size_t(_type); } + //! Returns the capacity of the string. inline size_t capacity() const noexcept { return isLarge() ? _large.capacity : size_t(kSSOCapacity); } + //! Returns the data of the string. inline char* data() noexcept { return isLarge() ? _large.data : _small.data; } + //! \overload inline const char* data() const noexcept { return isLarge() ? _large.data : _small.data; } + inline char* start() noexcept { return data(); } + inline const char* start() const noexcept { return data(); } + inline char* end() noexcept { return data() + size(); } inline const char* end() const noexcept { return data() + size(); } @@ -164,102 +205,120 @@ public: //! \name String Operations //! \{ - //! Clear the content of the string. + //! Swaps the content of this string with `other`. + inline void swap(String& other) noexcept { + std::swap(_raw, other._raw); + } + + //! Clears the content of the string. ASMJIT_API Error clear() noexcept; ASMJIT_API char* prepare(uint32_t op, size_t size) noexcept; ASMJIT_API Error _opString(uint32_t op, const char* str, size_t size = SIZE_MAX) noexcept; - ASMJIT_API Error _opFormat(uint32_t op, const char* fmt, ...) noexcept; - ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; ASMJIT_API Error _opChar(uint32_t op, char c) noexcept; ASMJIT_API Error _opChars(uint32_t op, char c, size_t n) noexcept; ASMJIT_API Error _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept; ASMJIT_API Error _opHex(uint32_t op, const void* data, size_t size, char separator = '\0') noexcept; + ASMJIT_API Error _opFormat(uint32_t op, const char* fmt, ...) noexcept; + ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept; - //! Replace the string content to a string specified by `data` and `size`. If - //! `size` is `SIZE_MAX` then it's considered null-terminated and its length - //! will be obtained through `strlen()`. - ASMJIT_API Error assignString(const char* data, size_t size = SIZE_MAX) noexcept; - - //! Replace the current content by a formatted string `fmt`. - template<typename... Args> - inline Error assignFormat(const char* fmt, Args&&... args) noexcept { - return _opFormat(kOpAssign, fmt, std::forward<Args>(args)...); - } + //! Replaces the current of the string with `data` of the given `size`. + //! + //! Null terminated strings can set `size` to `SIZE_MAX`. + ASMJIT_API Error assign(const char* data, size_t size = SIZE_MAX) noexcept; - //! Replace the current content by a formatted string `fmt` (va_list version). - inline Error assignVFormat(const char* fmt, va_list ap) noexcept { - return _opVFormat(kOpAssign, fmt, ap); + //! Replaces the current of the string with `other` string. + inline Error assign(const String& other) noexcept { + return assign(other.data(), other.size()); } - //! Replace the current content by a single `c` character. - inline Error assignChar(char c) noexcept { + //! Replaces the current of the string by a single `c` character. + inline Error assign(char c) noexcept { return _opChar(kOpAssign, c); } - //! Replace the current content by `c` character `n` times. + //! Replaces the current of the string by a `c` character, repeated `n` times. inline Error assignChars(char c, size_t n) noexcept { return _opChars(kOpAssign, c, n); } - //! Replace the current content by a formatted integer `i` (signed). + //! Replaces the current of the string by a formatted integer `i` (signed). inline Error assignInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAssign, uint64_t(i), base, width, flags | kFormatSigned); } - //! Replace the current content by a formatted integer `i` (unsigned). + //! Replaces the current of the string by a formatted integer `i` (unsigned). inline Error assignUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAssign, i, base, width, flags); } - //! Replace the current content by the given `data` converted to a HEX string. + //! Replaces the current of the string by the given `data` converted to a HEX string. inline Error assignHex(const void* data, size_t size, char separator = '\0') noexcept { return _opHex(kOpAssign, data, size, separator); } - //! Append string `str` of size `size` (or possibly null terminated). - inline Error appendString(const char* str, size_t size = SIZE_MAX) noexcept { - return _opString(kOpAppend, str, size); + //! Replaces the current of the string by a formatted string `fmt`. + template<typename... Args> + inline Error assignFormat(const char* fmt, Args&&... args) noexcept { + return _opFormat(kOpAssign, fmt, std::forward<Args>(args)...); } - template<typename... Args> - inline Error appendFormat(const char* fmt, Args&&... args) noexcept { - return _opFormat(kOpAppend, fmt, std::forward<Args>(args)...); + //! Replaces the current of the string by a formatted string `fmt` (va_list version). + inline Error assignVFormat(const char* fmt, va_list ap) noexcept { + return _opVFormat(kOpAssign, fmt, ap); } - //! Append a formatted string `fmt` (va_list version). - inline Error appendVFormat(const char* fmt, va_list ap) noexcept { - return _opVFormat(kOpAppend, fmt, ap); + //! Appends `str` having the given size `size` to the string. + //! + //! Null terminated strings can set `size` to `SIZE_MAX`. + inline Error append(const char* str, size_t size = SIZE_MAX) noexcept { + return _opString(kOpAppend, str, size); + } + + //! Appends `other` string to this string. + inline Error append(const String& other) noexcept { + return append(other.data(), other.size()); } - //! Append a single `c` character. - inline Error appendChar(char c) noexcept { + //! Appends a single `c` character. + inline Error append(char c) noexcept { return _opChar(kOpAppend, c); } - //! Append `c` character `n` times. + //! Appends `c` character repeated `n` times. inline Error appendChars(char c, size_t n) noexcept { return _opChars(kOpAppend, c, n); } - ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept; - - //! Append `i`. + //! Appends a formatted integer `i` (signed). inline Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAppend, uint64_t(i), base, width, flags | kFormatSigned); } - //! Append `i`. + //! Appends a formatted integer `i` (unsigned). inline Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept { return _opNumber(kOpAppend, i, base, width, flags); } - //! Append the given `data` converted to a HEX string. + //! Appends the given `data` converted to a HEX string. inline Error appendHex(const void* data, size_t size, char separator = '\0') noexcept { return _opHex(kOpAppend, data, size, separator); } + //! Appends a formatted string `fmt` with `args`. + template<typename... Args> + inline Error appendFormat(const char* fmt, Args&&... args) noexcept { + return _opFormat(kOpAppend, fmt, std::forward<Args>(args)...); + } + + //! Appends a formatted string `fmt` (va_list version). + inline Error appendVFormat(const char* fmt, va_list ap) noexcept { + return _opVFormat(kOpAppend, fmt, ap); + } + + ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept; + //! Truncate the string length into `newSize`. ASMJIT_API Error truncate(size_t newSize) noexcept; @@ -288,6 +347,20 @@ public: } //! \} + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use assign() instead of assignString()") + inline Error assignString(const char* data, size_t size = SIZE_MAX) noexcept { return assign(data, size); } + + ASMJIT_DEPRECATED("Use assign() instead of assignChar()") + inline Error assignChar(char c) noexcept { return assign(c); } + + ASMJIT_DEPRECATED("Use append() instead of appendString()") + inline Error appendString(const char* data, size_t size = SIZE_MAX) noexcept { return append(data, size); } + + ASMJIT_DEPRECATED("Use append() instead of appendChar()") + inline Error appendChar(char c) noexcept { return append(c); } +#endif // !ASMJIT_NO_DEPRECATED }; // ============================================================================ @@ -320,31 +393,6 @@ public: //! \} }; -// ============================================================================ -// [asmjit::FixedString] -// ============================================================================ - -//! A fixed string - only useful for strings that would never exceed `N - 1` -//! characters; always null-terminated. -template<size_t N> -union FixedString { - enum : uint32_t { - kNumU32 = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t)) - }; - - char str[kNumU32 * sizeof(uint32_t)]; - uint32_t u32[kNumU32]; - - //! \name Utilities - //! \{ - - inline bool eq(const char* other) const noexcept { - return strcmp(str, other) == 0; - } - - //! \} -}; - //! \} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/support.cpp b/3rdparty/asmjit/src/asmjit/core/support.cpp index 6b7e0854d81..a99477dc9fe 100644 --- a/3rdparty/asmjit/src/asmjit/core/support.cpp +++ b/3rdparty/asmjit/src/asmjit/core/support.cpp @@ -100,7 +100,7 @@ static void testBitUtils() noexcept { EXPECT(Support::bitTest((1 << i), i) == true, "Support::bitTest(%X, %u) should return true", (1 << i), i); } - INFO("Support::lsbMask()"); + INFO("Support::lsbMask<uint32_t>()"); for (i = 0; i < 32; i++) { uint32_t expectedBits = 0; for (uint32_t b = 0; b < i; b++) @@ -108,6 +108,14 @@ static void testBitUtils() noexcept { EXPECT(Support::lsbMask<uint32_t>(i) == expectedBits); } + INFO("Support::lsbMask<uint64_t>()"); + for (i = 0; i < 64; i++) { + uint64_t expectedBits = 0; + for (uint32_t b = 0; b < i; b++) + expectedBits |= uint64_t(1) << b; + EXPECT(Support::lsbMask<uint64_t>(i) == expectedBits); + } + INFO("Support::popcnt()"); for (i = 0; i < 32; i++) EXPECT(Support::popcnt((uint32_t(1) << i)) == 1); for (i = 0; i < 64; i++) EXPECT(Support::popcnt((uint64_t(1) << i)) == 1); diff --git a/3rdparty/asmjit/src/asmjit/core/support.h b/3rdparty/asmjit/src/asmjit/core/support.h index 0f49b78f0af..9e2bee477cb 100644 --- a/3rdparty/asmjit/src/asmjit/core/support.h +++ b/3rdparty/asmjit/src/asmjit/core/support.h @@ -32,7 +32,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_support +//! \addtogroup asmjit_utilities //! \{ //! Contains support classes and functions that may be used by AsmJit source @@ -69,28 +69,35 @@ namespace Internal { template<> struct AlignedInt<uint64_t, 4> { typedef uint64_t ASMJIT_ALIGN_TYPE(T, 4); }; template<> struct AlignedInt<uint64_t, 8> { typedef uint64_t T; }; - // IntBySize - Make an int-type by size (signed or unsigned) that is the + // StdInt - Make an int-type by size (signed or unsigned) that is the // same as types defined by <stdint.h>. // Int32Or64 - Make an int-type that has at least 32 bits: [u]int[32|64]_t. - template<size_t SIZE, int IS_SIGNED> - struct IntBySize {}; // Fail if not specialized. + template<size_t Size, unsigned Unsigned> + struct StdInt {}; // Fail if not specialized. - template<> struct IntBySize<1, 0> { typedef uint8_t Type; }; - template<> struct IntBySize<1, 1> { typedef int8_t Type; }; - template<> struct IntBySize<2, 0> { typedef uint16_t Type; }; - template<> struct IntBySize<2, 1> { typedef int16_t Type; }; - template<> struct IntBySize<4, 0> { typedef uint32_t Type; }; - template<> struct IntBySize<4, 1> { typedef int32_t Type; }; - template<> struct IntBySize<8, 0> { typedef uint64_t Type; }; - template<> struct IntBySize<8, 1> { typedef int64_t Type; }; + template<> struct StdInt<1, 0> { typedef int8_t Type; }; + template<> struct StdInt<1, 1> { typedef uint8_t Type; }; + template<> struct StdInt<2, 0> { typedef int16_t Type; }; + template<> struct StdInt<2, 1> { typedef uint16_t Type; }; + template<> struct StdInt<4, 0> { typedef int32_t Type; }; + template<> struct StdInt<4, 1> { typedef uint32_t Type; }; + template<> struct StdInt<8, 0> { typedef int64_t Type; }; + template<> struct StdInt<8, 1> { typedef uint64_t Type; }; - template<typename T, int IS_SIGNED = std::is_signed<T>::value> - struct Int32Or64 : public IntBySize<sizeof(T) <= 4 ? size_t(4) : sizeof(T), IS_SIGNED> {}; + template<typename T, int Unsigned = std::is_unsigned<T>::value> + struct Int32Or64 : public StdInt<sizeof(T) <= 4 ? size_t(4) : sizeof(T), Unsigned> {}; } //! \endcond // ============================================================================ +// [asmjit::Support - Basic Traits] +// ============================================================================ + +template<typename T> +static constexpr bool isUnsigned() noexcept { return std::is_unsigned<T>::value; } + +// ============================================================================ // [asmjit::Support - FastUInt8] // ============================================================================ @@ -101,20 +108,32 @@ typedef unsigned int FastUInt8; #endif // ============================================================================ -// [asmjit::Support - IntBySize / Int32Or64] +// [asmjit::Support - asInt / asUInt / asNormalized] // ============================================================================ //! Casts an integer `x` to either `int32_t` or `int64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T, 1>::Type asInt(T x) noexcept { return (typename Internal::Int32Or64<T, 1>::Type)x; } +static constexpr typename Internal::Int32Or64<T, 0>::Type asInt(const T& x) noexcept { + return (typename Internal::Int32Or64<T, 0>::Type)x; +} //! Casts an integer `x` to either `uint32_t` or `uint64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T, 0>::Type asUInt(T x) noexcept { return (typename Internal::Int32Or64<T, 0>::Type)x; } +static constexpr typename Internal::Int32Or64<T, 1>::Type asUInt(const T& x) noexcept { + return (typename Internal::Int32Or64<T, 1>::Type)x; +} //! Casts an integer `x` to either `int32_t`, uint32_t`, `int64_t`, or `uint64_t` depending on `T`. template<typename T> -static constexpr typename Internal::Int32Or64<T>::Type asNormalized(T x) noexcept { return (typename Internal::Int32Or64<T>::Type)x; } +static constexpr typename Internal::Int32Or64<T>::Type asNormalized(const T& x) noexcept { + return (typename Internal::Int32Or64<T>::Type)x; +} + +//! Casts an integer `x` to the same type as defined by `<stdint.h>`. +template<typename T> +static constexpr typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type asStdInt(const T& x) noexcept { + return (typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type)x; +} // ============================================================================ // [asmjit::Support - BitCast] @@ -142,7 +161,7 @@ static inline Dst bitCast(const Src& x) noexcept { return Internal::BitCastUnion // ============================================================================ //! Storage used to store a pack of bits (should by compatible with a machine word). -typedef Internal::IntBySize<sizeof(uintptr_t), 0>::Type BitWord; +typedef Internal::StdInt<sizeof(uintptr_t), 1>::Type BitWord; template<typename T> static constexpr uint32_t bitSizeOf() noexcept { return uint32_t(sizeof(T) * 8u); } @@ -194,14 +213,14 @@ static constexpr T blsi(T x) noexcept { //! Generate a trailing bit-mask that has `n` least significant (trailing) bits set. template<typename T, typename CountT> -static constexpr T lsbMask(CountT n) noexcept { +static constexpr T lsbMask(const CountT& n) noexcept { typedef typename std::make_unsigned<T>::type U; return (sizeof(U) < sizeof(uintptr_t)) + // Prevent undefined behavior by using a larger type than T. ? T(U((uintptr_t(1) << n) - uintptr_t(1))) - // Shifting more bits than the type provides is UNDEFINED BEHAVIOR. - // In such case we trash the result by ORing it with a mask that has - // all bits set and discards the UNDEFINED RESULT of the shift. - : T(((U(1) << n) - U(1u)) | neg(U(n >= CountT(bitSizeOf<T>())))); + // Prevent undefined behavior by performing `n & (nBits - 1)` so it's always within the range. + : shr(sar(neg(T(n)), bitSizeOf<T>() - 1u), + neg(T(n)) & CountT(bitSizeOf<T>() - 1u)); } //! Tests whether the given value `x` has `n`th bit set. @@ -398,30 +417,113 @@ static constexpr T max(const T& a, const T& b, Args&&... args) noexcept { return //! \cond namespace Internal { template<typename T> - static ASMJIT_INLINE T addOverflowImpl(T x, T y, FastUInt8* of) noexcept { + ASMJIT_INLINE T addOverflowFallback(T x, T y, FastUInt8* of) noexcept { typedef typename std::make_unsigned<T>::type U; U result = U(x) + U(y); - *of = FastUInt8(*of | FastUInt8(std::is_unsigned<T>::value ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0)); + *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0)); return T(result); } template<typename T> - static ASMJIT_INLINE T subOverflowImpl(T x, T y, FastUInt8* of) noexcept { + ASMJIT_INLINE T subOverflowFallback(T x, T y, FastUInt8* of) noexcept { typedef typename std::make_unsigned<T>::type U; U result = U(x) - U(y); - *of = FastUInt8(*of | FastUInt8(std::is_unsigned<T>::value ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0)); + *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0)); return T(result); } -} + + template<typename T> + ASMJIT_INLINE T mulOverflowFallback(T x, T y, FastUInt8* of) noexcept { + typedef typename Internal::StdInt<sizeof(T) * 2, isUnsigned<T>()>::Type I; + typedef typename std::make_unsigned<I>::type U; + + U mask = allOnes<U>(); + if (std::is_signed<T>::value) { + U prod = U(I(x)) * U(I(y)); + *of = FastUInt8(*of | FastUInt8(I(prod) < I(std::numeric_limits<T>::lowest()) || I(prod) > I(std::numeric_limits<T>::max()))); + return T(I(prod & mask)); + } + else { + U prod = U(x) * U(y); + *of = FastUInt8(*of | FastUInt8((prod & ~mask) != 0)); + return T(prod & mask); + } + } + + template<> + ASMJIT_INLINE int64_t mulOverflowFallback(int64_t x, int64_t y, FastUInt8* of) noexcept { + int64_t result = int64_t(uint64_t(x) * uint64_t(y)); + *of = FastUInt8(*of | FastUInt8(x && (result / x != y))); + return result; + } + + template<> + ASMJIT_INLINE uint64_t mulOverflowFallback(uint64_t x, uint64_t y, FastUInt8* of) noexcept { + uint64_t result = x * y; + *of = FastUInt8(*of | FastUInt8(y != 0 && allOnes<uint64_t>() / y < x)); + return result; + } + + // These can be specialized. + template<typename T> ASMJIT_INLINE T addOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return addOverflowFallback(x, y, of); } + template<typename T> ASMJIT_INLINE T subOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return subOverflowFallback(x, y, of); } + template<typename T> ASMJIT_INLINE T mulOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return mulOverflowFallback(x, y, of); } + + #if defined(__GNUC__) && !defined(ASMJIT_NO_INTRINSICS) + #if defined(__clang__) || __GNUC__ >= 5 + #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, RESULT_T, BUILTIN) \ + template<> \ + ASMJIT_INLINE T FUNC(const T& x, const T& y, FastUInt8* of) noexcept { \ + RESULT_T result; \ + *of = FastUInt8(*of | (BUILTIN((RESULT_T)x, (RESULT_T)y, &result))); \ + return T(result); \ + } + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int32_t , int , __builtin_sadd_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , __builtin_uadd_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int64_t , long long , __builtin_saddll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned long long, __builtin_uaddll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int32_t , int , __builtin_ssub_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , __builtin_usub_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int64_t , long long , __builtin_ssubll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned long long, __builtin_usubll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int32_t , int , __builtin_smul_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint32_t, unsigned int , __builtin_umul_overflow ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int64_t , long long , __builtin_smulll_overflow) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint64_t, unsigned long long, __builtin_umulll_overflow) + #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE + #endif + #endif + + // There is a bug in MSVC that makes these specializations unusable, maybe in the future... + #if defined(_MSC_VER) && 0 + #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, ALT_T, BUILTIN) \ + template<> \ + ASMJIT_INLINE T FUNC(T x, T y, FastUInt8* of) noexcept { \ + ALT_T result; \ + *of = FastUInt8(*of | BUILTIN(0, (ALT_T)x, (ALT_T)y, &result)); \ + return T(result); \ + } + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , _addcarry_u32 ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , _subborrow_u32) + #if ARCH_BITS >= 64 + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned __int64 , _addcarry_u64 ) + ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned __int64 , _subborrow_u64) + #endif + #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE + #endif +} // {Internal} //! \endcond template<typename T> -static ASMJIT_INLINE T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(x, y, of)); } +static ASMJIT_INLINE T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(asStdInt(x), asStdInt(y), of)); } + +template<typename T> +static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(asStdInt(x), asStdInt(y), of)); } template<typename T> -static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(x, y, of)); } +static ASMJIT_INLINE T mulOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::mulOverflowImpl(asStdInt(x), asStdInt(y), of)); } // ============================================================================ // [asmjit::Support - Alignment] @@ -429,7 +531,7 @@ static ASMJIT_INLINE T subOverflow(const T& x, const T& y, FastUInt8* of) noexce template<typename X, typename Y> static constexpr bool isAligned(X base, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return ((U)base % (U)alignment) == 0; } @@ -442,27 +544,27 @@ static constexpr bool isPowerOf2(T x) noexcept { template<typename X, typename Y> static constexpr X alignUp(X x, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return (X)( ((U)x + ((U)(alignment) - 1u)) & ~((U)(alignment) - 1u) ); } template<typename T> static constexpr T alignUpPowerOf2(T x) noexcept { - typedef typename Internal::IntBySize<sizeof(T), 0>::Type U; + typedef typename Internal::StdInt<sizeof(T), 1>::Type U; return (T)(fillTrailingBits(U(x) - 1u) + 1u); } //! Returns either zero or a positive difference between `base` and `base` when //! aligned to `alignment`. template<typename X, typename Y> -static constexpr typename Internal::IntBySize<sizeof(X), 0>::Type alignUpDiff(X base, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; +static constexpr typename Internal::StdInt<sizeof(X), 1>::Type alignUpDiff(X base, Y alignment) noexcept { + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return alignUp(U(base), alignment) - U(base); } template<typename X, typename Y> static constexpr X alignDown(X x, Y alignment) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return (X)( (U)x & ~((U)(alignment) - 1u) ); } @@ -475,7 +577,7 @@ static constexpr X alignDown(X x, Y alignment) noexcept { //! the number of BitWords to represent N bits, for example. template<typename X, typename Y> static constexpr X numGranularized(X base, Y granularity) noexcept { - typedef typename Internal::IntBySize<sizeof(X), 0>::Type U; + typedef typename Internal::StdInt<sizeof(X), 1>::Type U; return X((U(base) + U(granularity) - 1) / U(granularity)); } @@ -620,10 +722,10 @@ static inline uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept { // ============================================================================ template<typename T> -static constexpr T asciiToLower(T c) noexcept { return c ^ (T(c >= T('A') && c <= T('Z')) << 5); } +static constexpr T asciiToLower(T c) noexcept { return T(c ^ T(T(c >= T('A') && c <= T('Z')) << 5)); } template<typename T> -static constexpr T asciiToUpper(T c) noexcept { return c ^ (T(c >= T('a') && c <= T('z')) << 5); } +static constexpr T asciiToUpper(T c) noexcept { return T(c ^ T(T(c >= T('a') && c <= T('z')) << 5)); } static ASMJIT_INLINE size_t strLen(const char* s, size_t maxSize) noexcept { size_t i = 0; @@ -920,6 +1022,7 @@ static inline void writeU64uBE(void* p, uint64_t x) noexcept { writeU64xBE<1>(p, // [asmjit::Support - Operators] // ============================================================================ +//! \cond INTERNAL struct Set { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return y; } }; struct SetNot { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return ~y; } }; struct And { template<typename T> static inline T op(T x, T y) noexcept { return x & y; } }; @@ -931,6 +1034,7 @@ struct Add { template<typename T> static inline T op(T x, T y) noexcept { ret struct Sub { template<typename T> static inline T op(T x, T y) noexcept { return x - y; } }; struct Min { template<typename T> static inline T op(T x, T y) noexcept { return min<T>(x, y); } }; struct Max { template<typename T> static inline T op(T x, T y) noexcept { return max<T>(x, y); } }; +//! \endcond // ============================================================================ // [asmjit::Support - BitWordIterator] @@ -1081,6 +1185,13 @@ static inline size_t bitVectorIndexOf(T* buf, size_t start, bool value) noexcept template<typename T> class BitVectorIterator { public: + const T* _ptr; + size_t _idx; + size_t _end; + T _current; + + ASMJIT_INLINE BitVectorIterator(const BitVectorIterator& other) noexcept = default; + ASMJIT_INLINE BitVectorIterator(const T* data, size_t numBitWords, size_t start = 0) noexcept { init(data, numBitWords, start); } @@ -1126,11 +1237,6 @@ public: ASMJIT_ASSERT(_current != T(0)); return _idx + ctz(_current); } - - const T* _ptr; - size_t _idx; - size_t _end; - T _current; }; // ============================================================================ @@ -1142,6 +1248,12 @@ class BitVectorOpIterator { public: static constexpr uint32_t kTSizeInBits = bitSizeOf<T>(); + const T* _aPtr; + const T* _bPtr; + size_t _idx; + size_t _end; + T _current; + ASMJIT_INLINE BitVectorOpIterator(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept { init(aData, bData, numBitWords, start); } @@ -1184,12 +1296,6 @@ public: _current = bitWord; return n; } - - const T* _aPtr; - const T* _bPtr; - size_t _idx; - size_t _end; - T _current; }; // ============================================================================ @@ -1290,7 +1396,6 @@ namespace Internal { } //! \endcond - //! Quick sort implementation. //! //! The main reason to provide a custom qsort implementation is that we needed diff --git a/3rdparty/asmjit/src/asmjit/core/target.cpp b/3rdparty/asmjit/src/asmjit/core/target.cpp index ad120b443a3..9ce94f32410 100644 --- a/3rdparty/asmjit/src/asmjit/core/target.cpp +++ b/3rdparty/asmjit/src/asmjit/core/target.cpp @@ -31,8 +31,7 @@ ASMJIT_BEGIN_NAMESPACE // ============================================================================ Target::Target() noexcept - : _targetType(kTargetNone), - _codeInfo() {} + : _environment() {} Target::~Target() noexcept {} ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/target.h b/3rdparty/asmjit/src/asmjit/core/target.h index f3da0e5de8e..4d144c64ee2 100644 --- a/3rdparty/asmjit/src/asmjit/core/target.h +++ b/3rdparty/asmjit/src/asmjit/core/target.h @@ -36,20 +36,13 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::CodeInfo] // ============================================================================ +#ifndef ASMJIT_NO_DEPRECATED //! Basic information about a code (or target). It describes its architecture, //! code generation mode (or optimization level), and base address. -class CodeInfo { +class ASMJIT_DEPRECATED_STRUCT("Use Environment instead of CodeInfo") CodeInfo { public: - //!< Architecture information. - ArchInfo _archInfo; - //! Natural stack alignment (ARCH+OS). - uint8_t _stackAlignment; - //! Default CDECL calling convention. - uint8_t _cdeclCallConv; - //! Default STDCALL calling convention. - uint8_t _stdCallConv; - //! Default FASTCALL calling convention. - uint8_t _fastCallConv; + //!< Environment information. + Environment _environment; //! Base address. uint64_t _baseAddress; @@ -57,46 +50,35 @@ public: //! \{ inline CodeInfo() noexcept - : _archInfo(), - _stackAlignment(0), - _cdeclCallConv(CallConv::kIdNone), - _stdCallConv(CallConv::kIdNone), - _fastCallConv(CallConv::kIdNone), + : _environment(), _baseAddress(Globals::kNoBaseAddress) {} - inline explicit CodeInfo(uint32_t archId, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept - : _archInfo(archId, archMode), - _stackAlignment(0), - _cdeclCallConv(CallConv::kIdNone), - _stdCallConv(CallConv::kIdNone), - _fastCallConv(CallConv::kIdNone), + inline explicit CodeInfo(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept + : _environment(arch, subArch), _baseAddress(baseAddress) {} + inline explicit CodeInfo(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept + : _environment(environment), + _baseAddress(baseAddress) {} + + inline CodeInfo(const CodeInfo& other) noexcept { init(other); } inline bool isInitialized() const noexcept { - return _archInfo.archId() != ArchInfo::kIdNone; + return _environment.arch() != Environment::kArchUnknown; } inline void init(const CodeInfo& other) noexcept { *this = other; } - inline void init(uint32_t archId, uint32_t archMode = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { - _archInfo.init(archId, archMode); - _stackAlignment = 0; - _cdeclCallConv = CallConv::kIdNone; - _stdCallConv = CallConv::kIdNone; - _fastCallConv = CallConv::kIdNone; + inline void init(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept { + _environment.init(arch, subArch); _baseAddress = baseAddress; } inline void reset() noexcept { - _archInfo.reset(); - _stackAlignment = 0; - _cdeclCallConv = CallConv::kIdNone; - _stdCallConv = CallConv::kIdNone; - _fastCallConv = CallConv::kIdNone; + _environment.reset(); _baseAddress = Globals::kNoBaseAddress; } @@ -115,39 +97,28 @@ public: //! \name Accessors //! \{ - //! Returns the target architecture information, see `ArchInfo`. - inline const ArchInfo& archInfo() const noexcept { return _archInfo; } + //! Returns the target environment information, see \ref Environment. + inline const Environment& environment() const noexcept { return _environment; } - //! Returns the target architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _archInfo.archId(); } - //! Returns the target architecture sub-type, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _archInfo.archSubId(); } + //! Returns the target architecture, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _environment.arch(); } + //! Returns the target sub-architecture, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _environment.subArch(); } //! Returns the native size of the target's architecture GP register. - inline uint32_t gpSize() const noexcept { return _archInfo.gpSize(); } - //! Returns the number of GP registers of the target's architecture. - inline uint32_t gpCount() const noexcept { return _archInfo.gpCount(); } - - //! Returns a natural stack alignment that must be honored (or 0 if not known). - inline uint32_t stackAlignment() const noexcept { return _stackAlignment; } - //! Sets a natural stack alignment that must be honored. - inline void setStackAlignment(uint32_t sa) noexcept { _stackAlignment = uint8_t(sa); } - - inline uint32_t cdeclCallConv() const noexcept { return _cdeclCallConv; } - inline void setCdeclCallConv(uint32_t cc) noexcept { _cdeclCallConv = uint8_t(cc); } - - inline uint32_t stdCallConv() const noexcept { return _stdCallConv; } - inline void setStdCallConv(uint32_t cc) noexcept { _stdCallConv = uint8_t(cc); } - - inline uint32_t fastCallConv() const noexcept { return _fastCallConv; } - inline void setFastCallConv(uint32_t cc) noexcept { _fastCallConv = uint8_t(cc); } + inline uint32_t gpSize() const noexcept { return _environment.registerSize(); } + //! Tests whether this CodeInfo has a base address set. inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; } + //! Returns the base address or \ref Globals::kNoBaseAddress if it's not set. inline uint64_t baseAddress() const noexcept { return _baseAddress; } + //! Sets base address to `p`. inline void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; } + //! Resets base address (implicitly sets it to \ref Globals::kNoBaseAddress). inline void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; } //! \} }; +#endif // !ASMJIT_NO_DEPRECATED // ============================================================================ // [asmjit::Target] @@ -159,19 +130,8 @@ public: ASMJIT_BASE_CLASS(Target) ASMJIT_NONCOPYABLE(Target) - //! Tartget type, see `TargetType`. - uint8_t _targetType; - //! Reserved for future use. - uint8_t _reserved[7]; - //! Basic information about the Runtime's code. - CodeInfo _codeInfo; - - enum TargetType : uint32_t { - //! Uninitialized target or unknown target type. - kTargetNone = 0, - //! JIT target type, see `JitRuntime`. - kTargetJit = 1 - }; + //! Target environment information. + Environment _environment; //! \name Construction & Destruction //! \{ @@ -190,15 +150,20 @@ public: //! //! CodeInfo can be used to setup a CodeHolder in case you plan to generate a //! code compatible and executable by this Runtime. - inline const CodeInfo& codeInfo() const noexcept { return _codeInfo; } + inline const Environment& environment() const noexcept { return _environment; } + + //! Returns the target architecture, see \ref Environment::Arch. + inline uint32_t arch() const noexcept { return _environment.arch(); } + //! Returns the target sub-architecture, see \ref Environment::SubArch. + inline uint32_t subArch() const noexcept { return _environment.subArch(); } - //! Returns the target architecture id, see `ArchInfo::Id`. - inline uint32_t archId() const noexcept { return _codeInfo.archId(); } - //! Returns the target architecture sub-id, see `ArchInfo::SubId`. - inline uint32_t archSubId() const noexcept { return _codeInfo.archSubId(); } +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use environment() instead") + inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment); } - //! Returns the target type, see `TargetType`. - inline uint32_t targetType() const noexcept { return _targetType; } + ASMJIT_DEPRECATED("Use environment().format() instead") + inline uint32_t targetType() const noexcept { return _environment.format(); } +#endif // !ASMJIT_NO_DEPRECATED //! \} }; diff --git a/3rdparty/asmjit/src/asmjit/core/type.cpp b/3rdparty/asmjit/src/asmjit/core/type.cpp index 67662db5075..97892d9815e 100644 --- a/3rdparty/asmjit/src/asmjit/core/type.cpp +++ b/3rdparty/asmjit/src/asmjit/core/type.cpp @@ -31,14 +31,62 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::Type] // ============================================================================ -const Type::TypeData Type::_typeData = { - #define VALUE(X) Type::BaseOfTypeId<X>::kTypeId +namespace Type { + +template<uint32_t TYPE_ID> +struct BaseOfTypeId { + static constexpr uint32_t kTypeId = + isBase (TYPE_ID) ? TYPE_ID : + isMask8 (TYPE_ID) ? kIdU8 : + isMask16(TYPE_ID) ? kIdU16 : + isMask32(TYPE_ID) ? kIdU32 : + isMask64(TYPE_ID) ? kIdU64 : + isMmx32 (TYPE_ID) ? kIdI32 : + isMmx64 (TYPE_ID) ? kIdI64 : + isVec32 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec32Start : + isVec64 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec64Start : + isVec128(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec128Start : + isVec256(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec256Start : + isVec512(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec512Start : 0; +}; + +template<uint32_t TYPE_ID> +struct SizeOfTypeId { + static constexpr uint32_t kTypeSize = + isInt8 (TYPE_ID) ? 1 : + isUInt8 (TYPE_ID) ? 1 : + isInt16 (TYPE_ID) ? 2 : + isUInt16 (TYPE_ID) ? 2 : + isInt32 (TYPE_ID) ? 4 : + isUInt32 (TYPE_ID) ? 4 : + isInt64 (TYPE_ID) ? 8 : + isUInt64 (TYPE_ID) ? 8 : + isFloat32(TYPE_ID) ? 4 : + isFloat64(TYPE_ID) ? 8 : + isFloat80(TYPE_ID) ? 10 : + isMask8 (TYPE_ID) ? 1 : + isMask16 (TYPE_ID) ? 2 : + isMask32 (TYPE_ID) ? 4 : + isMask64 (TYPE_ID) ? 8 : + isMmx32 (TYPE_ID) ? 4 : + isMmx64 (TYPE_ID) ? 8 : + isVec32 (TYPE_ID) ? 4 : + isVec64 (TYPE_ID) ? 8 : + isVec128 (TYPE_ID) ? 16 : + isVec256 (TYPE_ID) ? 32 : + isVec512 (TYPE_ID) ? 64 : 0; +}; + +const TypeData _typeData = { + #define VALUE(X) BaseOfTypeId<X>::kTypeId { ASMJIT_LOOKUP_TABLE_256(VALUE, 0) }, #undef VALUE - #define VALUE(X) Type::SizeOfTypeId<X>::kTypeSize + #define VALUE(X) SizeOfTypeId<X>::kTypeSize { ASMJIT_LOOKUP_TABLE_256(VALUE, 0) } #undef VALUE }; +} // {Type} + ASMJIT_END_NAMESPACE diff --git a/3rdparty/asmjit/src/asmjit/core/type.h b/3rdparty/asmjit/src/asmjit/core/type.h index 59a17e92625..ef03ecb8360 100644 --- a/3rdparty/asmjit/src/asmjit/core/type.h +++ b/3rdparty/asmjit/src/asmjit/core/type.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::Type] // ============================================================================ -//! Provides minimum type-system that is used by \ref asmjit_func and \ref asmjit_compiler. +//! Provides a minimalist type-system that is used by Asmjit library. namespace Type { //! TypeId. @@ -46,7 +46,7 @@ namespace Type { //! width used) and it's also used by APIs that allow to describe and work with //! function signatures. enum Id : uint32_t { - kIdVoid = 0, + kIdVoid = 0, //!< Void type. _kIdBaseStart = 32, _kIdBaseEnd = 44, @@ -54,38 +54,38 @@ enum Id : uint32_t { _kIdIntStart = 32, _kIdIntEnd = 41, - kIdIntPtr = 32, - kIdUIntPtr = 33, + kIdIntPtr = 32, //!< Abstract signed integer type that has a native size. + kIdUIntPtr = 33, //!< Abstract unsigned integer type that has a native size. - kIdI8 = 34, - kIdU8 = 35, - kIdI16 = 36, - kIdU16 = 37, - kIdI32 = 38, - kIdU32 = 39, - kIdI64 = 40, - kIdU64 = 41, + kIdI8 = 34, //!< 8-bit signed integer type. + kIdU8 = 35, //!< 8-bit unsigned integer type. + kIdI16 = 36, //!< 16-bit signed integer type. + kIdU16 = 37, //!< 16-bit unsigned integer type. + kIdI32 = 38, //!< 32-bit signed integer type. + kIdU32 = 39, //!< 32-bit unsigned integer type. + kIdI64 = 40, //!< 64-bit signed integer type. + kIdU64 = 41, //!< 64-bit unsigned integer type. _kIdFloatStart = 42, _kIdFloatEnd = 44, - kIdF32 = 42, - kIdF64 = 43, - kIdF80 = 44, + kIdF32 = 42, //!< 32-bit floating point type. + kIdF64 = 43, //!< 64-bit floating point type. + kIdF80 = 44, //!< 80-bit floating point type. _kIdMaskStart = 45, _kIdMaskEnd = 48, - kIdMask8 = 45, - kIdMask16 = 46, - kIdMask32 = 47, - kIdMask64 = 48, + kIdMask8 = 45, //!< 8-bit opmask register (K). + kIdMask16 = 46, //!< 16-bit opmask register (K). + kIdMask32 = 47, //!< 32-bit opmask register (K). + kIdMask64 = 48, //!< 64-bit opmask register (K). _kIdMmxStart = 49, _kIdMmxEnd = 50, - kIdMmx32 = 49, - kIdMmx64 = 50, + kIdMmx32 = 49, //!< 64-bit MMX register only used for 32 bits. + kIdMmx64 = 50, //!< 64-bit MMX register. _kIdVec32Start = 51, _kIdVec32End = 60, @@ -206,72 +206,74 @@ static constexpr bool isVec128(uint32_t typeId) noexcept { return typeId >= _kId static constexpr bool isVec256(uint32_t typeId) noexcept { return typeId >= _kIdVec256Start && typeId <= _kIdVec256End; } static constexpr bool isVec512(uint32_t typeId) noexcept { return typeId >= _kIdVec512Start && typeId <= _kIdVec512End; } -//! IdOfT<> template allows to get a TypeId of a C++ `T` type. -template<typename T> struct IdOfT { /* Fail if not specialized. */ }; - //! \cond -template<typename T> struct IdOfT<T*> { - enum : uint32_t { kTypeId = kIdUIntPtr }; +enum TypeCategory : uint32_t { + kTypeCategoryUnknown = 0, + kTypeCategoryEnum = 1, + kTypeCategoryIntegral = 2, + kTypeCategoryFloatingPoint = 3, + kTypeCategoryFunction = 4 }; -template<typename T> struct IdOfT<T&> { - enum : uint32_t { kTypeId = kIdUIntPtr }; -}; +template<typename T, uint32_t Category> +struct IdOfT_ByCategory {}; // Fails if not specialized. template<typename T> -struct IdOfIntT { - static constexpr uint32_t kTypeId = - sizeof(T) == 1 ? (std::is_signed<T>::value ? kIdI8 : kIdU8 ) : - sizeof(T) == 2 ? (std::is_signed<T>::value ? kIdI16 : kIdU16) : - sizeof(T) == 4 ? (std::is_signed<T>::value ? kIdI32 : kIdU32) : - sizeof(T) == 8 ? (std::is_signed<T>::value ? kIdI64 : kIdU64) : kIdVoid; +struct IdOfT_ByCategory<T, kTypeCategoryIntegral> { + enum : uint32_t { + kTypeId = (sizeof(T) == 1 && std::is_signed<T>::value) ? kIdI8 : + (sizeof(T) == 1 && !std::is_signed<T>::value) ? kIdU8 : + (sizeof(T) == 2 && std::is_signed<T>::value) ? kIdI16 : + (sizeof(T) == 2 && !std::is_signed<T>::value) ? kIdU16 : + (sizeof(T) == 4 && std::is_signed<T>::value) ? kIdI32 : + (sizeof(T) == 4 && !std::is_signed<T>::value) ? kIdU32 : + (sizeof(T) == 8 && std::is_signed<T>::value) ? kIdI64 : + (sizeof(T) == 8 && !std::is_signed<T>::value) ? kIdU64 : kIdVoid + }; }; -template<uint32_t TYPE_ID> -struct BaseOfTypeId { - static constexpr uint32_t kTypeId = - isBase (TYPE_ID) ? TYPE_ID : - isMask8 (TYPE_ID) ? kIdU8 : - isMask16(TYPE_ID) ? kIdU16 : - isMask32(TYPE_ID) ? kIdU32 : - isMask64(TYPE_ID) ? kIdU64 : - isMmx32 (TYPE_ID) ? kIdI32 : - isMmx64 (TYPE_ID) ? kIdI64 : - isVec32 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec32Start : - isVec64 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec64Start : - isVec128(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec128Start : - isVec256(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec256Start : - isVec512(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec512Start : 0; +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryFloatingPoint> { + enum : uint32_t { + kTypeId = (sizeof(T) == 4 ) ? kIdF32 : + (sizeof(T) == 8 ) ? kIdF64 : + (sizeof(T) >= 10) ? kIdF80 : kIdVoid + }; }; -template<uint32_t TYPE_ID> -struct SizeOfTypeId { - static constexpr uint32_t kTypeSize = - isInt8 (TYPE_ID) ? 1 : - isUInt8 (TYPE_ID) ? 1 : - isInt16 (TYPE_ID) ? 2 : - isUInt16 (TYPE_ID) ? 2 : - isInt32 (TYPE_ID) ? 4 : - isUInt32 (TYPE_ID) ? 4 : - isInt64 (TYPE_ID) ? 8 : - isUInt64 (TYPE_ID) ? 8 : - isFloat32(TYPE_ID) ? 4 : - isFloat64(TYPE_ID) ? 8 : - isFloat80(TYPE_ID) ? 10 : - isMask8 (TYPE_ID) ? 1 : - isMask16 (TYPE_ID) ? 2 : - isMask32 (TYPE_ID) ? 4 : - isMask64 (TYPE_ID) ? 8 : - isMmx32 (TYPE_ID) ? 4 : - isMmx64 (TYPE_ID) ? 8 : - isVec32 (TYPE_ID) ? 4 : - isVec64 (TYPE_ID) ? 8 : - isVec128 (TYPE_ID) ? 16 : - isVec256 (TYPE_ID) ? 32 : - isVec512 (TYPE_ID) ? 64 : 0; +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryEnum> + : public IdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {}; + +template<typename T> +struct IdOfT_ByCategory<T, kTypeCategoryFunction> { + enum: uint32_t { kTypeId = kIdUIntPtr }; }; //! \endcond +//! IdOfT<> template allows to get a TypeId from a C++ type `T`. +template<typename T> +struct IdOfT +#ifdef _DOXYGEN + //! TypeId of C++ type `T`. + static constexpr uint32_t kTypeId = _TypeIdDeducedAtCompileTime_; +#else + : public IdOfT_ByCategory<T, + std::is_enum<T>::value ? kTypeCategoryEnum : + std::is_integral<T>::value ? kTypeCategoryIntegral : + std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint : + std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown> +#endif +{}; + +//! \cond +template<typename T> +struct IdOfT<T*> { enum : uint32_t { kTypeId = kIdUIntPtr }; }; + +template<typename T> +struct IdOfT<T&> { enum : uint32_t { kTypeId = kIdUIntPtr }; }; +//! \endcond + static inline uint32_t baseOf(uint32_t typeId) noexcept { ASMJIT_ASSERT(typeId <= kIdMax); return _typeData.baseOf[typeId]; @@ -283,14 +285,14 @@ static inline uint32_t sizeOf(uint32_t typeId) noexcept { } //! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId -//! into a type that matches `gpSize` (general-purpose register size). +//! into a type that matches `registerSize` (general-purpose register size). //! If you find such TypeId it's then only about adding the offset to it. //! //! For example: //! //! ``` -//! uint32_t gpSize = '4' or '8'; -//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(gpSize); +//! uint32_t registerSize = '4' or '8'; +//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize); //! //! uint32_t typeId = 'some type-id'; //! @@ -300,8 +302,8 @@ static inline uint32_t sizeOf(uint32_t typeId) noexcept { //! // The same, but by using Type::deabstract() function. //! typeId = Type::deabstract(typeId, deabstractDelta); //! ``` -static constexpr uint32_t deabstractDeltaOfSize(uint32_t gpSize) noexcept { - return gpSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr; +static constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept { + return registerSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr; } static constexpr uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept { @@ -350,45 +352,20 @@ namespace Type { \ }; \ } -ASMJIT_DEFINE_TYPE_ID(bool , IdOfIntT<bool >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(char , IdOfIntT<char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(signed char , IdOfIntT<signed char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned char , IdOfIntT<unsigned char >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(short , IdOfIntT<short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned short , IdOfIntT<unsigned short >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(int , IdOfIntT<int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned int , IdOfIntT<unsigned int >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(long , IdOfIntT<long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long , IdOfIntT<unsigned long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(long long , IdOfIntT<long long >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(unsigned long long, IdOfIntT<unsigned long long>::kTypeId); - -#if ASMJIT_CXX_HAS_NATIVE_WCHAR_T -ASMJIT_DEFINE_TYPE_ID(wchar_t , IdOfIntT<wchar_t >::kTypeId); -#endif - -#if ASMJIT_CXX_HAS_UNICODE_LITERALS -ASMJIT_DEFINE_TYPE_ID(char16_t , IdOfIntT<char16_t >::kTypeId); -ASMJIT_DEFINE_TYPE_ID(char32_t , IdOfIntT<char32_t >::kTypeId); -#endif - -ASMJIT_DEFINE_TYPE_ID(void , kIdVoid); -ASMJIT_DEFINE_TYPE_ID(float , kIdF32); -ASMJIT_DEFINE_TYPE_ID(double , kIdF64); - -ASMJIT_DEFINE_TYPE_ID(Bool , kIdU8); -ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8); -ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8); -ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16); -ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16); -ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32); -ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32); -ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64); -ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64); -ASMJIT_DEFINE_TYPE_ID(IPtr , kIdIntPtr); -ASMJIT_DEFINE_TYPE_ID(UPtr , kIdUIntPtr); -ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32); -ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64); +ASMJIT_DEFINE_TYPE_ID(void, kIdVoid); +ASMJIT_DEFINE_TYPE_ID(Bool, kIdU8); +ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8); +ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8); +ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16); +ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16); +ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32); +ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32); +ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64); +ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64); +ASMJIT_DEFINE_TYPE_ID(IPtr, kIdIntPtr); +ASMJIT_DEFINE_TYPE_ID(UPtr, kIdUIntPtr); +ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32); +ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64); //! \endcond //! \} diff --git a/3rdparty/asmjit/src/asmjit/core/virtmem.cpp b/3rdparty/asmjit/src/asmjit/core/virtmem.cpp index e373cf8d723..0606748ef7f 100644 --- a/3rdparty/asmjit/src/asmjit/core/virtmem.cpp +++ b/3rdparty/asmjit/src/asmjit/core/virtmem.cpp @@ -45,7 +45,7 @@ // Apple recently introduced MAP_JIT flag, which we want to use. #if defined(__APPLE__) #include <TargetConditionals.h> - #if defined(TARGET_OS_OSX) + #if TARGET_OS_OSX #include <sys/utsname.h> #endif // Older SDK doesn't define `MAP_JIT`. @@ -316,10 +316,10 @@ static ASMJIT_INLINE bool VirtMem_isHardened() noexcept { // MAP_JIT flag required to run unsigned JIT code is only supported by kernel // version 10.14+ (Mojave) and IOS. static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept { -#if defined(TARGET_OS_OSX) - static volatile uint32_t globalVersion; +#if TARGET_OS_OSX + static volatile int globalVersion; - uint32_t ver = globalVersion; + int ver = globalVersion; if (!ver) { struct utsname osname; uname(&osname); @@ -333,19 +333,19 @@ static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept { #endif } -static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { +static ASMJIT_INLINE int VirtMem_appleSpecificMMapFlags(uint32_t flags) { // Always use MAP_JIT flag if user asked for it (could be used for testing // on non-hardened processes) and detect whether it must be used when the // process is actually hardened (in that case it doesn't make sense to rely // on user `flags`). bool useMapJit = ((flags & VirtMem::kMMapEnableMapJit) != 0) || VirtMem_isHardened(); if (useMapJit) - return VirtMem_hasMapJitSupport() ? MAP_JIT : 0u; + return VirtMem_hasMapJitSupport() ? int(MAP_JIT) : 0; else return 0; } #else -static ASMJIT_INLINE uint32_t VirtMem_appleSpecificMMapFlags(uint32_t flags) { +static ASMJIT_INLINE int VirtMem_appleSpecificMMapFlags(uint32_t flags) { DebugUtils::unused(flags); return 0; } @@ -406,7 +406,7 @@ static Error VirtMem_openAnonymousMemory(int* fd, bool preferTmpOverDevShm) noex bits = ((bits >> 14) ^ (bits << 6)) + uint64_t(++internalCounter) * 10619863; if (!ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm) { - uniqueName.assignString(VirtMem_getTmpDir()); + uniqueName.assign(VirtMem_getTmpDir()); uniqueName.appendFormat(kShmFormat, (unsigned long long)bits); *fd = open(uniqueName.data(), O_RDWR | O_CREAT | O_EXCL, 0); if (ASMJIT_LIKELY(*fd >= 0)) { diff --git a/3rdparty/asmjit/src/asmjit/core/virtmem.h b/3rdparty/asmjit/src/asmjit/core/virtmem.h index a37005d947e..8d3ee01ee5b 100644 --- a/3rdparty/asmjit/src/asmjit/core/virtmem.h +++ b/3rdparty/asmjit/src/asmjit/core/virtmem.h @@ -31,7 +31,7 @@ ASMJIT_BEGIN_NAMESPACE -//! \addtogroup asmjit_jit +//! \addtogroup asmjit_virtual_memory //! \{ // ============================================================================ diff --git a/3rdparty/asmjit/src/asmjit/core/zone.cpp b/3rdparty/asmjit/src/asmjit/core/zone.cpp index 16de89becec..61f7cec796d 100644 --- a/3rdparty/asmjit/src/asmjit/core/zone.cpp +++ b/3rdparty/asmjit/src/asmjit/core/zone.cpp @@ -144,7 +144,7 @@ void* Zone::_alloc(size_t size, size_t alignment) noexcept { size_t newSize = Support::max(blockSize(), size); // Prevent arithmetic overflow. - if (ASMJIT_UNLIKELY(newSize > std::numeric_limits<size_t>::max() - kBlockSize - blockAlignmentOverhead)) + if (ASMJIT_UNLIKELY(newSize > SIZE_MAX - kBlockSize - blockAlignmentOverhead)) return nullptr; // Allocate new block - we add alignment overhead to `newSize`, which becomes the @@ -200,7 +200,7 @@ void* Zone::dup(const void* data, size_t size, bool nullTerminate) noexcept { if (ASMJIT_UNLIKELY(!data || !size)) return nullptr; - ASMJIT_ASSERT(size != std::numeric_limits<size_t>::max()); + ASMJIT_ASSERT(size != SIZE_MAX); uint8_t* m = allocT<uint8_t>(size + nullTerminate); if (ASMJIT_UNLIKELY(!m)) return nullptr; @@ -318,7 +318,7 @@ void* ZoneAllocator::_alloc(size_t size, size_t& allocatedSize) noexcept { size_t kBlockOverhead = sizeof(DynamicBlock) + sizeof(DynamicBlock*) + kBlockAlignment; // Handle a possible overflow. - if (ASMJIT_UNLIKELY(kBlockOverhead >= std::numeric_limits<size_t>::max() - size)) + if (ASMJIT_UNLIKELY(kBlockOverhead >= SIZE_MAX - size)) return nullptr; void* p = ::malloc(size + kBlockOverhead); diff --git a/3rdparty/asmjit/src/asmjit/core/zone.h b/3rdparty/asmjit/src/asmjit/core/zone.h index c426f785c0c..52e9f125461 100644 --- a/3rdparty/asmjit/src/asmjit/core/zone.h +++ b/3rdparty/asmjit/src/asmjit/core/zone.h @@ -383,15 +383,22 @@ public: // [b2d::ZoneTmp] // ============================================================================ +//! \ref Zone with `N` bytes of a static storage, used for the initial block. +//! +//! Temporary zones are used in cases where it's known that some memory will be +//! required, but in many cases it won't exceed N bytes, so the whole operation +//! can be performed without a dynamic memory allocation. template<size_t N> class ZoneTmp : public Zone { public: ASMJIT_NONCOPYABLE(ZoneTmp<N>) + //! Temporary storage, embedded after \ref Zone. struct Storage { char data[N]; } _storage; + //! Creates a temporary zone. Dynamic block size is specified by `blockSize`. ASMJIT_INLINE explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept : Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {} }; diff --git a/3rdparty/asmjit/src/asmjit/core/zonehash.h b/3rdparty/asmjit/src/asmjit/core/zonehash.h index bdc1da76027..0f1f21f148c 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonehash.h +++ b/3rdparty/asmjit/src/asmjit/core/zonehash.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneHashNode] // ============================================================================ -//! Node used by `ZoneHash<>` template. +//! Node used by \ref ZoneHash template. //! //! You must provide function `bool eq(const Key& key)` in order to make //! `ZoneHash::get()` working. @@ -60,6 +60,7 @@ public: // [asmjit::ZoneHashBase] // ============================================================================ +//! Base class used by \ref ZoneHash template class ZoneHashBase { public: ASMJIT_NONCOPYABLE(ZoneHashBase) diff --git a/3rdparty/asmjit/src/asmjit/core/zonelist.h b/3rdparty/asmjit/src/asmjit/core/zonelist.h index 9d300b03606..bc726deca94 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonelist.h +++ b/3rdparty/asmjit/src/asmjit/core/zonelist.h @@ -35,6 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneListNode] // ============================================================================ +//! Node used by \ref ZoneList template. template<typename NodeT> class ZoneListNode { public: @@ -69,6 +70,7 @@ public: // [asmjit::ZoneList<T>] // ============================================================================ +//! Zone allocated list container that uses nodes of `NodeT` type. template <typename NodeT> class ZoneList { public: diff --git a/3rdparty/asmjit/src/asmjit/core/zonestack.h b/3rdparty/asmjit/src/asmjit/core/zonestack.h index 3c7b5ce0c45..2de6cdc05a7 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonestack.h +++ b/3rdparty/asmjit/src/asmjit/core/zonestack.h @@ -35,7 +35,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneStackBase] // ============================================================================ -//! Base class used by `ZoneStack<T>`. +//! Base class used by \ref ZoneStack. class ZoneStackBase { public: ASMJIT_NONCOPYABLE(ZoneStackBase) diff --git a/3rdparty/asmjit/src/asmjit/core/zonestring.h b/3rdparty/asmjit/src/asmjit/core/zonestring.h index dfb06b4c754..cb25b29ce7d 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonestring.h +++ b/3rdparty/asmjit/src/asmjit/core/zonestring.h @@ -36,6 +36,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneStringBase] // ============================================================================ +//! A helper class used by \ref ZoneString implementation. struct ZoneStringBase { union { struct { @@ -77,11 +78,12 @@ struct ZoneStringBase { // [asmjit::ZoneString<N>] // ============================================================================ -//! Small string is a template that helps to create strings that can be either -//! statically allocated if they are small, or externally allocated in case -//! their size exceeds the limit. The `N` represents the size of the whole -//! `ZoneString` structure, based on that size the maximum size of the internal -//! buffer is determined. +//! A string template that can be zone allocated. +//! +//! Helps with creating strings that can be either statically allocated if they +//! are small, or externally allocated in case their size exceeds the limit. +//! The `N` represents the size of the whole `ZoneString` structure, based on +//! that size the maximum size of the internal buffer is determined. template<size_t N> class ZoneString { public: @@ -105,12 +107,22 @@ public: //! \name Accessors //! \{ - inline const char* data() const noexcept { return _base._size <= kMaxEmbeddedSize ? _base._embedded : _base._external; } + //! Tests whether the string is empty. inline bool empty() const noexcept { return _base._size == 0; } + + //! Returns the string data. + inline const char* data() const noexcept { return _base._size <= kMaxEmbeddedSize ? _base._embedded : _base._external; } + //! Returns the string size. inline uint32_t size() const noexcept { return _base._size; } + //! Tests whether the string is embedded (e.g. no dynamically allocated). inline bool isEmbedded() const noexcept { return _base._size <= kMaxEmbeddedSize; } + //! Copies a new `data` of the given `size` to the string. + //! + //! If the `size` exceeds the internal buffer the given `zone` will be + //! used to duplicate the data, otherwise the internal buffer will be + //! used as a storage. inline Error setData(Zone* zone, const char* data, size_t size) noexcept { return _base.setData(zone, kMaxEmbeddedSize, data, size); } diff --git a/3rdparty/asmjit/src/asmjit/core/zonetree.h b/3rdparty/asmjit/src/asmjit/core/zonetree.h index 6cb88ed499b..1877919d67b 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonetree.h +++ b/3rdparty/asmjit/src/asmjit/core/zonetree.h @@ -99,7 +99,7 @@ public: //! \endcond }; -//! RB-Tree typed to `NodeT`. +//! RB-Tree node casted to `NodeT`. template<typename NodeT> class ZoneTreeNodeT : public ZoneTreeNode { public: diff --git a/3rdparty/asmjit/src/asmjit/core/zonevector.h b/3rdparty/asmjit/src/asmjit/core/zonevector.h index 7ee04ce7807..770543baee1 100644 --- a/3rdparty/asmjit/src/asmjit/core/zonevector.h +++ b/3rdparty/asmjit/src/asmjit/core/zonevector.h @@ -36,9 +36,7 @@ ASMJIT_BEGIN_NAMESPACE // [asmjit::ZoneVectorBase] // ============================================================================ -//! \cond INTERNAL - -//! Base class implementing core `ZoneVector<>` functionality. +//! Base class used by \ref ZoneVector template. class ZoneVectorBase { public: ASMJIT_NONCOPYABLE(ZoneVectorBase) @@ -93,6 +91,7 @@ protected: } //! \} + //! \endcond public: //! \name Accessors @@ -133,8 +132,6 @@ public: //! \} }; -//! \endcond - // ============================================================================ // [asmjit::ZoneVector<T>] // ============================================================================ @@ -180,7 +177,7 @@ public: inline const T* data() const noexcept { return static_cast<const T*>(_data); } //! Returns item at the given index `i` (const). - inline const T& at(uint32_t i) const noexcept { + inline const T& at(size_t i) const noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } @@ -259,6 +256,7 @@ public: return kErrorOk; } + //! Appends `other` vector at the end of this vector. inline Error concat(ZoneAllocator* allocator, const ZoneVector<T>& other) noexcept { uint32_t size = other._size; if (_capacity - _size < size) @@ -338,6 +336,7 @@ public: ::memmove(data, data + 1, size_t(size) * sizeof(T)); } + //! Pops the last element from the vector and returns it. inline T pop() noexcept { ASMJIT_ASSERT(_size > 0); @@ -351,21 +350,33 @@ public: } //! Returns item at index `i`. - inline T& operator[](uint32_t i) noexcept { + inline T& operator[](size_t i) noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } //! Returns item at index `i`. - inline const T& operator[](uint32_t i) const noexcept { + inline const T& operator[](size_t i) const noexcept { ASMJIT_ASSERT(i < _size); return data()[i]; } + //! Returns a reference to the first element of the vector. + //! + //! \note The vector must have at least one element. Attempting to use + //! `first()` on empty vector will trigger an assertion failure in debug + //! builds. inline T& first() noexcept { return operator[](0); } + //! \overload inline const T& first() const noexcept { return operator[](0); } + //! Returns a reference to the last element of the vector. + //! + //! \note The vector must have at least one element. Attempting to use + //! `last()` on empty vector will trigger an assertion failure in debug + //! builds. inline T& last() noexcept { return operator[](_size - 1); } + //! \overload inline const T& last() const noexcept { return operator[](_size - 1); } //! \} @@ -408,6 +419,7 @@ public: // [asmjit::ZoneBitVector] // ============================================================================ +//! Zone-allocated bit vector. class ZoneBitVector { public: typedef Support::BitWord BitWord; @@ -689,7 +701,6 @@ public: }; //! \} - }; //! \} diff --git a/3rdparty/asmjit/src/asmjit/x86.h b/3rdparty/asmjit/src/asmjit/x86.h index 161b3be19fb..3c2224c966a 100644 --- a/3rdparty/asmjit/src/asmjit/x86.h +++ b/3rdparty/asmjit/src/asmjit/x86.h @@ -24,9 +24,83 @@ #ifndef ASMJIT_X86_H_INCLUDED #define ASMJIT_X86_H_INCLUDED -//! \defgroup asmjit_x86 X86 +//! \addtogroup asmjit_x86 //! -//! \brief X86/X64 Backend. +//! ### Namespace +//! +//! - \ref x86 - x86 namespace provides support for X86/X64 code generation. +//! +//! ### Emitters +//! +//! - \ref x86::Assembler - X86/X64 assembler (must read, provides examples). +//! - \ref x86::Builder - X86/X64 builder. +//! - \ref x86::Compiler - X86/X64 compiler. +//! - \ref x86::Emitter - X86/X64 emitter (abstract). +//! +//! ### Supported Instructions +//! +//! - Emitters: +//! - \ref x86::EmitterExplicitT - Provides all instructions that use +//! explicit operands, provides also utility functions. The member +//! functions provided are part of all X86 emitters. +//! - \ref x86::EmitterImplicitT - Provides all instructions that use +//! implicit operands, these cannot be used with \ref x86::Compiler. +//! - Instruction representation: +//! - \ref x86::Inst::Id - instruction identifiers. +//! - \ref x86::Inst::Options - instruction options. +//! +//! ### Register Operands +//! +//! - \ref x86::Reg - Base class for any X86 register. +//! - \ref x86::Gp - General purpose register: +//! - \ref x86::GpbLo - 8-bit low register. +//! - \ref x86::GpbHi - 8-bit high register. +//! - \ref x86::Gpw - 16-bit register. +//! - \ref x86::Gpd - 32-bit register. +//! - \ref x86::Gpq - 64-bit register (X64 only). +//! - \ref x86::Vec - Vector (SIMD) register: +//! - \ref x86::Xmm - 128-bit SIMD register (SSE+). +//! - \ref x86::Ymm - 256-bit SIMD register (AVX+). +//! - \ref x86::Zmm - 512-bit SIMD register (AVX512+). +//! - \ref x86::Mm - 64-bit MMX register. +//! - \ref x86::St - 80-bit FPU register. +//! - \ref x86::KReg - opmask registers (AVX512+). +//! - \ref x86::SReg - segment register. +//! - \ref x86::CReg - control register. +//! - \ref x86::DReg - debug register. +//! - \ref x86::Bnd - bound register (discontinued). +//! - \ref x86::Rip - relative instruction pointer. +//! +//! ### Memory Operands +//! +//! - \ref x86::Mem - X86/X64 memory operand that provides support for all +//! X86 and X64 addressing features, including absolute addresses, index +//! scales, and segment override prefixes. +//! +//! ### Other +//! +//! - \ref x86::Features - X86/X64 CPU features on top of \ref BaseFeatures. +//! +//! ### Status and Control Words +//! +//! - \ref asmjit::x86::FpuWord::Status - FPU status word. +//! - \ref asmjit::x86::FpuWord::Control - FPU control word. +//! +//! ### Predicates +//! +//! - \ref x86::Predicate - namespace that provides X86/X64 predicates. +//! - \ref x86::Predicate::Cmp - `CMP[PD|PS|SD|SS]` predicate (SSE+). +//! - \ref x86::Predicate::PCmpStr - `[V]PCMP[I|E]STR[I|M]` predicate (SSE4.1+). +//! - \ref x86::Predicate::Round - `ROUND[PD|PS|SD|SS]` predicate (SSE+). +//! - \ref x86::Predicate::VCmp - `VCMP[PD|PS|SD|SS]` predicate (AVX+). +//! - \ref x86::Predicate::VFixupImm - `VFIXUPIMM[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VFPClass - `VFPCLASS[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VGetMant - `VGETMANT[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VPCmp - `VPCMP[U][B|W|D|Q]` predicate (AVX512+). +//! - \ref x86::Predicate::VPCom - `VPCOM[U][B|W|D|Q]` predicate (XOP). +//! - \ref x86::Predicate::VRange - `VRANGE[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::Predicate::VReduce - `REDUCE[PD|PS|SD|SS]` predicate (AVX512+). +//! - \ref x86::TLog - namespace that provides `VPTERNLOG[D|Q]` predicate / operations. #include "./core.h" diff --git a/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp b/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp new file mode 100644 index 00000000000..cd928b2534b --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp @@ -0,0 +1,137 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include "../core/api-build_p.h" +#ifdef ASMJIT_BUILD_X86 + +#include "../core/support.h" +#include "../core/type.h" +#include "../x86/x86archdata_p.h" +#include "../x86/x86operand.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(x86) + +// ============================================================================ +// [asmjit::x86::ArchInternal] +// ============================================================================ + +namespace ArchInternal { + +Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept { + // Passed RegType instead of TypeId? + if (typeId <= BaseReg::kTypeMax) + typeId = opData.archRegs.regTypeToTypeId[typeId]; + + if (ASMJIT_UNLIKELY(!Type::isValid(typeId))) + return DebugUtils::errored(kErrorInvalidTypeId); + + // First normalize architecture dependent types. + if (Type::isAbstract(typeId)) { + bool is32Bit = arch == Environment::kArchX86; + if (typeId == Type::kIdIntPtr) + typeId = is32Bit ? Type::kIdI32 : Type::kIdI64; + else + typeId = is32Bit ? Type::kIdU32 : Type::kIdU64; + } + + // Type size helps to construct all groups of registers. + // TypeId is invalid if the size is zero. + uint32_t size = Type::sizeOf(typeId); + if (ASMJIT_UNLIKELY(!size)) + return DebugUtils::errored(kErrorInvalidTypeId); + + if (ASMJIT_UNLIKELY(typeId == Type::kIdF80)) + return DebugUtils::errored(kErrorInvalidUseOfF80); + + uint32_t regType = 0; + + switch (typeId) { + case Type::kIdI8: + case Type::kIdU8: + regType = Reg::kTypeGpbLo; + break; + + case Type::kIdI16: + case Type::kIdU16: + regType = Reg::kTypeGpw; + break; + + case Type::kIdI32: + case Type::kIdU32: + regType = Reg::kTypeGpd; + break; + + case Type::kIdI64: + case Type::kIdU64: + if (arch == Environment::kArchX86) + return DebugUtils::errored(kErrorInvalidUseOfGpq); + + regType = Reg::kTypeGpq; + break; + + // F32 and F64 are always promoted to use vector registers. + case Type::kIdF32: + typeId = Type::kIdF32x1; + regType = Reg::kTypeXmm; + break; + + case Type::kIdF64: + typeId = Type::kIdF64x1; + regType = Reg::kTypeXmm; + break; + + // Mask registers {k}. + case Type::kIdMask8: + case Type::kIdMask16: + case Type::kIdMask32: + case Type::kIdMask64: + regType = Reg::kTypeKReg; + break; + + // MMX registers. + case Type::kIdMmx32: + case Type::kIdMmx64: + regType = Reg::kTypeMm; + break; + + // XMM|YMM|ZMM registers. + default: + if (size <= 16) + regType = Reg::kTypeXmm; + else if (size == 32) + regType = Reg::kTypeYmm; + else + regType = Reg::kTypeZmm; + break; + } + + *typeIdOut = typeId; + regInfoOut->reset(opData.archRegs.regInfo[regType].signature()); + return kErrorOk; +} + +} // {ArchInternal} + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h b/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h new file mode 100644 index 00000000000..e765cb9b02a --- /dev/null +++ b/3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h @@ -0,0 +1,51 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#ifndef ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED +#define ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED + +#include "../core/arch.h" + +ASMJIT_BEGIN_SUB_NAMESPACE(x86) + +//! \cond INTERNAL +//! \addtogroup asmjit_x86 +//! \{ + +// ============================================================================ +// [asmjit::x86::ArchInternal] +// ============================================================================ + +//! X86-specific function API (calling conventions and other utilities). +namespace ArchInternal { + +Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept; + +} // {ArchInternal} + +//! \} +//! \endcond + +ASMJIT_END_SUB_NAMESPACE + +#endif // ASMJIT_X86_X86ARCHDATA_P_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp b/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp index d509926e5f5..879fb2f0151 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp @@ -24,14 +24,17 @@ #include "../core/api-build_p.h" #ifdef ASMJIT_BUILD_X86 +#include "../core/assembler.h" #include "../core/codebufferwriter_p.h" #include "../core/cpuinfo.h" -#include "../core/logging.h" +#include "../core/emitterutils_p.h" +#include "../core/formatter.h" +#include "../core/logger.h" #include "../core/misc_p.h" #include "../core/support.h" #include "../x86/x86assembler.h" #include "../x86/x86instdb_p.h" -#include "../x86/x86logging_p.h" +#include "../x86/x86formatter_p.h" #include "../x86/x86opcode_p.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) @@ -508,7 +511,7 @@ static ASMJIT_INLINE uint32_t x86GetMovAbsAddrType(Assembler* self, X86BufferWri if (addrType == BaseMem::kAddrTypeDefault && !(options & Inst::kOptionModMR)) { if (self->is64Bit()) { - uint64_t baseAddress = self->codeInfo().baseAddress(); + uint64_t baseAddress = self->code()->baseAddress(); if (baseAddress != Globals::kNoBaseAddress && !rmRel.hasSegment()) { uint32_t instructionSize = x86GetMovAbsInstSize64Bit(regSize, options, rmRel); uint64_t virtualOffset = uint64_t(writer.offsetFrom(self->_bufferData)); @@ -545,18 +548,18 @@ Assembler::~Assembler() noexcept {} // [asmjit::x86::Assembler - Emit (Low-Level)] // ============================================================================ -ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) { +ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) { constexpr uint32_t kVSHR_W = Opcode::kW_Shift - 23; constexpr uint32_t kVSHR_PP = Opcode::kPP_Shift - 16; constexpr uint32_t kVSHR_PP_EW = Opcode::kPP_Shift - 16; constexpr uint32_t kRequiresSpecialHandling = - Inst::kOptionReserved | // Logging/Validation/Error. - Inst::kOptionRep | // REP/REPE prefix. - Inst::kOptionRepne | // REPNE prefix. - Inst::kOptionLock | // LOCK prefix. - Inst::kOptionXAcquire | // XACQUIRE prefix. - Inst::kOptionXRelease ; // XRELEASE prefix. + uint32_t(Inst::kOptionReserved) | // Logging/Validation/Error. + uint32_t(Inst::kOptionRep ) | // REP/REPE prefix. + uint32_t(Inst::kOptionRepne ) | // REPNE prefix. + uint32_t(Inst::kOptionLock ) | // LOCK prefix. + uint32_t(Inst::kOptionXAcquire) | // XACQUIRE prefix. + uint32_t(Inst::kOptionXRelease) ; // XRELEASE prefix. Error err; @@ -595,12 +598,12 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c // instruction) are handled by the next branch. options = uint32_t(instId == 0); options |= uint32_t((size_t)(_bufferEnd - writer.cursor()) < 16); - options |= uint32_t(instOptions() | globalInstOptions()); + options |= uint32_t(instOptions() | forcedInstOptions()); // Handle failure and rare cases first. if (ASMJIT_UNLIKELY(options & kRequiresSpecialHandling)) { if (ASMJIT_UNLIKELY(!_code)) - return DebugUtils::errored(kErrorNotInitialized); + return reportError(DebugUtils::errored(kErrorNotInitialized)); // Unknown instruction. if (ASMJIT_UNLIKELY(instId == 0)) @@ -613,25 +616,13 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c #ifndef ASMJIT_NO_VALIDATION // Strict validation. - if (hasEmitterOption(kOptionStrictValidation)) { + if (hasValidationOption(kValidationOptionAssembler)) { Operand_ opArray[Globals::kMaxOpCount]; + EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt); - opArray[0].copyFrom(o0); - opArray[1].copyFrom(o1); - opArray[2].copyFrom(o2); - opArray[3].copyFrom(o3); - - if (options & Inst::kOptionOp4Op5Used) { - opArray[4].copyFrom(_op4); - opArray[5].copyFrom(_op5); - } - else { - opArray[4].reset(); - opArray[5].reset(); - } - - err = InstAPI::validate(archId(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount); - if (ASMJIT_UNLIKELY(err)) goto Failed; + err = InstAPI::validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount); + if (ASMJIT_UNLIKELY(err)) + goto Failed; } #endif @@ -693,7 +684,7 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c if (ASMJIT_UNLIKELY(isign3 != ENC_OPS1(Imm))) goto InvalidInstruction; - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; ASMJIT_FALLTHROUGH; @@ -738,14 +729,14 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c case InstDB::kEncodingX86I_xAX: // Implicit form. if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } // Explicit form. if (isign3 == ENC_OPS2(Reg, Imm) && o0.id() == Gp::kIdAx) { - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } @@ -996,7 +987,7 @@ CaseX86M_GPB_MulDiv: uint32_t size = o0.size(); rbReg = o0.id(); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); if (size == 1) { FIXUP_GPB(o0, rbReg); @@ -1022,8 +1013,7 @@ CaseX86M_GPB_MulDiv: else goto InvalidImmediate; } - else if (canTransformTo32Bit && hasEmitterOption(kOptionOptimizedForSize)) { - // This is a code-size optimization. + else if (canTransformTo32Bit && hasEncodingOption(kEncodingOptionOptimizeForSize)) { size = 4; } @@ -1053,7 +1043,7 @@ CaseX86M_GPB_MulDiv: if (ASMJIT_UNLIKELY(memSize == 0)) goto AmbiguousOperandSize; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(memSize, 4)); // Sign extend so isInt8 returns the right result. @@ -1098,7 +1088,7 @@ CaseX86M_GPB_MulDiv: } // The remaining instructions use the secondary opcode/r. - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; opcode = x86AltOpcodeOf(instInfo); @@ -1175,8 +1165,11 @@ CaseX86M_GPB_MulDiv: } case InstDB::kEncodingX86Cmpxchg8b_16b: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + if (isign3 == ENC_OPS3(Mem, Reg, Reg)) { - if (o3.isReg() && _op4.isReg()) { + if (o3.isReg() && o4.isReg()) { rmRel = &o0; goto EmitX86M; } @@ -1224,8 +1217,8 @@ CaseX86M_GPB_MulDiv: case InstDB::kEncodingX86Enter: if (isign3 == ENC_OPS2(Imm, Imm)) { - uint32_t iw = o0.as<Imm>().u16(); - uint32_t ib = o1.as<Imm>().u8(); + uint32_t iw = o0.as<Imm>().valueAs<uint16_t>(); + uint32_t ib = o1.as<Imm>().valueAs<uint8_t>(); immValue = iw | (ib << 16); immSize = 3; @@ -1239,7 +1232,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (!Support::isInt8(immValue) || (options & Inst::kOptionLongForm)) { @@ -1257,7 +1250,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; // Sign extend so isInt8 returns the right result. @@ -1309,7 +1302,7 @@ CaseX86M_GPB_MulDiv: opcode = 0x6B; opcode.addPrefixBySize(o0.size()); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; // Sign extend so isInt8 returns the right result. @@ -1333,7 +1326,7 @@ CaseX86M_GPB_MulDiv: if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx)) goto InvalidInstruction; - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; opcode = x86AltOpcodeOf(instInfo) + (o0.size() != 1); @@ -1398,18 +1391,16 @@ CaseX86M_GPB_MulDiv: case InstDB::kEncodingX86Int: if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); immSize = 1; goto EmitX86Op; } break; case InstDB::kEncodingX86Jcc: - if (_emitterOptions & kOptionPredictedJumps) { - if (options & Inst::kOptionTaken) - writer.emit8(0x3E); - if (options & Inst::kOptionNotTaken) - writer.emit8(0x2E); + if ((options & (Inst::kOptionTaken | Inst::kOptionNotTaken)) && hasEncodingOption(kEncodingOptionPredictedJumps)) { + uint8_t prefix = (options & Inst::kOptionTaken) ? uint8_t(0x3E) : uint8_t(0x2E); + writer.emit8(prefix); } rmRel = &o0; @@ -1649,16 +1640,16 @@ CaseX86M_GPB_MulDiv: FIXUP_GPB(o0, opReg); opcode = 0xB0; - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); goto EmitX86OpReg; } else { // 64-bit immediate in 64-bit mode is allowed. - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); // Optimize the instruction size by using a 32-bit immediate if possible. if (immSize == 8 && !(options & Inst::kOptionLongForm)) { - if (Support::isUInt32(immValue) && hasEmitterOption(kOptionOptimizedForSize)) { + if (Support::isUInt32(immValue) && hasEncodingOption(kEncodingOptionOptimizeForSize)) { // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ. immSize = 4; } @@ -1690,7 +1681,7 @@ CaseX86M_GPB_MulDiv: opReg = 0; rmRel = &o0; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(memSize, 4)); goto EmitX86M; } @@ -1753,7 +1744,7 @@ CaseX86M_GPB_MulDiv: opcode = x86AltOpcodeOf(instInfo) + (o1.size() != 1); opcode.add66hBySize(o1.size()); - immValue = o0.as<Imm>().u8(); + immValue = o0.as<Imm>().valueAs<uint8_t>(); immSize = 1; goto EmitX86Op; } @@ -1800,7 +1791,7 @@ CaseX86M_GPB_MulDiv: } if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); immSize = 4; if (Support::isInt8(immValue) && !(options & Inst::kOptionLongForm)) @@ -1840,7 +1831,7 @@ CaseX86PushPop_Gp: if (ASMJIT_UNLIKELY(o0.size() == 0)) goto AmbiguousOperandSize; - if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != gpSize())) + if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != registerSize())) goto InvalidInstruction; opcode.add66hBySize(o0.size()); @@ -1857,7 +1848,7 @@ CaseX86PushPop_Gp: } if (isign3 == ENC_OPS1(Imm)) { - immValue = o0.as<Imm>().i64(); + immValue = o0.as<Imm>().value(); if (immValue == 0 && !(options & Inst::kOptionLongForm)) { // 'ret' without immediate, change C2 to C3. opcode.add(1); @@ -1887,7 +1878,7 @@ CaseX86PushPop_Gp: } if (isign3 == ENC_OPS2(Reg, Imm)) { - immValue = o1.as<Imm>().i64() & 0xFF; + immValue = o1.as<Imm>().value() & 0xFF; immSize = 0; if (immValue == 1 && !(options & Inst::kOptionLongForm)) @@ -1915,7 +1906,7 @@ CaseX86PushPop_Gp: goto AmbiguousOperandSize; rmRel = &o0; - immValue = o1.as<Imm>().i64() & 0xFF; + immValue = o1.as<Imm>().value() & 0xFF; immSize = 0; if (immValue == 1 && !(options & Inst::kOptionLongForm)) @@ -1947,7 +1938,7 @@ CaseX86PushPop_Gp: opReg = o1.id(); rbReg = o0.id(); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; goto EmitX86R; } @@ -1957,7 +1948,7 @@ CaseX86PushPop_Gp: opReg = o1.id(); rmRel = &o0; - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; goto EmitX86M; } @@ -2077,11 +2068,11 @@ CaseX86PushPop_Gp: if (o0.size() == 1) { FIXUP_GPB(o0, rbReg); - immValue = o1.as<Imm>().u8(); + immValue = o1.as<Imm>().valueAs<uint8_t>(); immSize = 1; } else { - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4)); } @@ -2102,7 +2093,7 @@ CaseX86PushPop_Gp: opcode.addArithBySize(o0.size()); rmRel = &o0; - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4)); goto EmitX86M; } @@ -2345,7 +2336,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o0.id(); @@ -2358,7 +2349,7 @@ CaseFpuArith_Mem: opcode = x86AltOpcodeOf(instInfo); opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2371,7 +2362,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2382,7 +2373,7 @@ CaseFpuArith_Mem: if (isign3 == ENC_OPS3(Mem, Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o1)); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; opReg = o1.id(); @@ -2621,7 +2612,7 @@ CaseExtRm: opReg = opcode.extractO(); if (isign3 == ENC_OPS2(Reg, Imm)) { - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; rbReg = o0.id(); @@ -2653,7 +2644,7 @@ CaseExtRm: if (isign3 == ENC_OPS2(Reg, Imm)) { opcode.add66hIf(Reg::isXmm(o0)); - immValue = o1.as<Imm>().i64(); + immValue = o1.as<Imm>().value(); immSize = 1; rbReg = o0.id(); @@ -2662,7 +2653,7 @@ CaseExtRm: break; case InstDB::kEncodingExtRmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2679,7 +2670,7 @@ CaseExtRm: break; case InstDB::kEncodingExtRmi_P: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2714,8 +2705,8 @@ CaseExtRm: opcode = x86AltOpcodeOf(instInfo); if (isign3 == ENC_OPS3(Reg, Imm, Imm)) { - immValue = (o1.as<Imm>().u32() ) + - (o2.as<Imm>().u32() << 8) ; + immValue = (uint32_t(o1.as<Imm>().valueAs<uint8_t>()) ) + + (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) << 8) ; immSize = 2; rbReg = opcode.extractO(); @@ -2724,7 +2715,9 @@ CaseExtRm: break; case InstDB::kEncodingExtInsertq: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); + opReg = o0.id(); rbReg = o1.id(); @@ -2735,8 +2728,8 @@ CaseExtRm: opcode = x86AltOpcodeOf(instInfo); if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) { - immValue = (o2.as<Imm>().u32() ) + - (o3.as<Imm>().u32() << 8) ; + immValue = (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) ) + + (uint32_t(o3.as<Imm>().valueAs<uint8_t>()) << 8) ; immSize = 2; goto EmitX86R; } @@ -2869,7 +2862,7 @@ CaseExtRm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexMri: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2934,24 +2927,22 @@ CaseVexRm: break; case InstDB::kEncodingVexRm_T1_4X: { - if (!(options & Inst::kOptionOp4Op5Used)) - goto InvalidInstruction; + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + const Operand_& o5 = opExt[EmitterUtils::kOp5]; - if (Reg::isZmm(o0 ) && Reg::isZmm(o1) && - Reg::isZmm(o2 ) && Reg::isZmm(o3) && - Reg::isZmm(_op4) && _op5.isMem()) { - - // Registers [o1, o2, o3, _op4] must start aligned and must be consecutive. + if (Reg::isZmm(o0) && Reg::isZmm(o1) && Reg::isZmm(o2) && Reg::isZmm(o3) && Reg::isZmm(o4) && o5.isMem()) { + // Registers [o1, o2, o3, o4] must start aligned and must be consecutive. uint32_t i1 = o1.id(); uint32_t i2 = o2.id(); uint32_t i3 = o3.id(); - uint32_t i4 = _op4.id(); + uint32_t i4 = o4.id(); if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3)) goto NotConsecutiveRegs; opReg = o0.id(); - rmRel = &_op5; + rmRel = &o5; goto EmitVexEvexM; } break; @@ -2967,7 +2958,7 @@ CaseVexRm: case InstDB::kEncodingVexRmi: CaseVexRmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -2999,25 +2990,32 @@ CaseVexRvm_R: } break; - case InstDB::kEncodingVexRvm_ZDX_Wx: + case InstDB::kEncodingVexRvm_ZDX_Wx: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; if (ASMJIT_UNLIKELY(!o3.isNone() && !Reg::isGp(o3, Gp::kIdDx))) goto InvalidInstruction; ASMJIT_FALLTHROUGH; + } - case InstDB::kEncodingVexRvm_Wx: + case InstDB::kEncodingVexRvm_Wx: { opcode.addWIf(Reg::isGpq(o0) | (o2.size() == 8)); goto CaseVexRvm; + } - case InstDB::kEncodingVexRvm_Lx: + case InstDB::kEncodingVexRvm_Lx: { opcode |= x86OpcodeLBySize(o0.size() | o1.size()); goto CaseVexRvm; + } - case InstDB::kEncodingVexRvmr_Lx: + case InstDB::kEncodingVexRvmr_Lx: { opcode |= x86OpcodeLBySize(o0.size() | o1.size()); ASMJIT_FALLTHROUGH; + } case InstDB::kEncodingVexRvmr: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); + immValue = o3.id() << 4; immSize = 1; @@ -3040,8 +3038,10 @@ CaseVexRvm_R: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexRvmi: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); - immValue = o3.as<Imm>().i64(); + + immValue = o3.as<Imm>().value(); immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { @@ -3100,8 +3100,10 @@ CaseVexRvm_R: case InstDB::kEncodingVexRmvi: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); - immValue = o3.as<Imm>().i64(); + + immValue = o3.as<Imm>().value(); immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) { @@ -3249,7 +3251,7 @@ CaseVexRvm_R: opcode &= Opcode::kLL_Mask; opcode |= x86AltOpcodeOf(instInfo); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3295,7 +3297,7 @@ CaseVexRvm_R: // The following instructions use the secondary opcode. opcode = x86AltOpcodeOf(instInfo); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3390,7 +3392,7 @@ CaseVexRvm_R: opcode |= x86AltOpcodeOf(instInfo); opReg = opcode.extractO(); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; if (isign3 == ENC_OPS3(Reg, Reg, Imm)) { @@ -3434,7 +3436,7 @@ CaseVexRvm_R: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexVmi: - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 1; CaseVexVmi_AfterImm: @@ -3453,7 +3455,7 @@ CaseVexVmi_AfterImm: case InstDB::kEncodingVexVmi4_Wx: opcode.addWIf(Reg::isGpq(o0) || o1.size() == 8); - immValue = o2.as<Imm>().i64(); + immValue = o2.as<Imm>().value(); immSize = 4; goto CaseVexVmi_AfterImm; @@ -3462,6 +3464,7 @@ CaseVexVmi_AfterImm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingVexRvrmRvmr: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3495,13 +3498,16 @@ CaseVexVmi_AfterImm: } case InstDB::kEncodingVexRvrmiRvmri_Lx: { - if (!(options & Inst::kOptionOp4Op5Used) || !_op4.isImm()) + const Operand_& o3 = opExt[EmitterUtils::kOp3]; + const Operand_& o4 = opExt[EmitterUtils::kOp4]; + + if (ASMJIT_UNLIKELY(!o4.isImm())) goto InvalidInstruction; const uint32_t isign4 = isign3 + (o3.opType() << 9); opcode |= x86OpcodeLBySize(o0.size() | o1.size() | o2.size() | o3.size()); - immValue = _op4.as<Imm>().u8() & 0x0F; + immValue = o4.as<Imm>().valueAs<uint8_t>() & 0x0F; immSize = 1; if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3560,6 +3566,7 @@ CaseVexVmi_AfterImm: ASMJIT_FALLTHROUGH; case InstDB::kEncodingFma4: { + const Operand_& o3 = opExt[EmitterUtils::kOp3]; const uint32_t isign4 = isign3 + (o3.opType() << 9); if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) { @@ -3600,7 +3607,7 @@ CaseVexVmi_AfterImm: // -------------------------------------------------------------------------- EmitX86OpMovAbs: - immSize = FastUInt8(gpSize()); + immSize = FastUInt8(registerSize()); writer.emitSegmentOverride(rmRel->as<Mem>().segmentId()); EmitX86Op: @@ -3805,7 +3812,7 @@ EmitModSib: else { bool isOffsetI32 = rmRel->as<Mem>().offsetHi32() == (relOffset >> 31); bool isOffsetU32 = rmRel->as<Mem>().offsetHi32() == 0; - uint64_t baseAddress = codeInfo().baseAddress(); + uint64_t baseAddress = code()->baseAddress(); // If relative addressing was not explicitly set then we can try to guess. // By guessing we check some properties of the memory operand and try to @@ -4241,7 +4248,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } @@ -4262,7 +4269,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } else { @@ -4276,7 +4283,7 @@ EmitVexEvexR: rbReg &= 0x7; writer.emit8(x86EncodeMod(3, opReg, rbReg)); - writer.emitImmByteOrDWord(immValue, immSize); + writer.emitImmByteOrDWord(uint64_t(immValue), immSize); goto EmitDone; } } @@ -4459,15 +4466,15 @@ EmitJmpCall: } if (rmRel->isImm()) { - uint64_t baseAddress = codeInfo().baseAddress(); - uint64_t jumpAddress = rmRel->as<Imm>().u64(); + uint64_t baseAddress = code()->baseAddress(); + uint64_t jumpAddress = rmRel->as<Imm>().valueAs<uint64_t>(); // If the base-address is known calculate a relative displacement and // check if it fits in 32 bits (which is always true in 32-bit mode). // Emit relative displacement as it was a bound label if all checks are ok. if (baseAddress != Globals::kNoBaseAddress) { uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size; - if (archId() == ArchInfo::kIdX86 || Support::isInt32(int64_t(rel64))) { + if (Environment::is32Bit(arch()) || Support::isInt32(int64_t(rel64))) { rel32 = uint32_t(rel64 & 0xFFFFFFFFu); goto EmitJmpCallRel; } @@ -4492,7 +4499,7 @@ EmitJmpCall: // REX prefix does nothing if not patched, but allows to patch the // instruction to use MOD/M and to point to a memory where the final // 64-bit address is stored. - if (archId() != ArchInfo::kIdX86 && x86IsJmpOrCall(instId)) { + if (Environment::is64Bit(arch()) && x86IsJmpOrCall(instId)) { if (!rex) writer.emit8(kX86ByteRex); @@ -4582,13 +4589,13 @@ EmitRel: EmitDone: if (ASMJIT_UNLIKELY(options & Inst::kOptionReserved)) { #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) - _emitLog(instId, options, o0, o1, o2, o3, relSize, immSize, writer.cursor()); + if (_logger) + EmitterUtils::logInstructionEmitted(this, instId, options, o0, o1, o2, opExt, relSize, immSize, writer.cursor()); #endif } - resetInstOptions(); resetExtraReg(); + resetInstOptions(); resetInlineComment(); writer.done(this); @@ -4625,7 +4632,14 @@ EmitDone: #undef ERROR_HANDLER Failed: - return _emitFailed(err, instId, options, o0, o1, o2, o3); +#ifndef ASMJIT_NO_LOGGING + return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt); +#else + resetExtraReg(); + resetInstOptions(); + resetInlineComment(); + return reportError(err); +#endif } // ============================================================================ @@ -4633,6 +4647,9 @@ Failed: // ============================================================================ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { + if (ASMJIT_UNLIKELY(!_code)) + return reportError(DebugUtils::errored(kErrorNotInitialized)); + if (ASMJIT_UNLIKELY(alignMode >= kAlignCount)) return reportError(DebugUtils::errored(kErrorInvalidArgument)); @@ -4650,7 +4667,7 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { uint8_t pattern = 0x00; switch (alignMode) { case kAlignCode: { - if (hasEmitterOption(kOptionOptimizedAlign)) { + if (hasEncodingOption(kEncodingOptionOptimizedAlign)) { // Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP). enum { kMaxNopSize = 9 }; @@ -4699,12 +4716,11 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { } #ifndef ASMJIT_NO_LOGGING - if (hasEmitterOption(kOptionLoggingEnabled)) { - Logger* logger = _code->logger(); + if (_logger) { StringTmp<128> sb; - sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode)); + sb.appendChars(' ', _logger->indentation(FormatOptions::kIndentationCode)); sb.appendFormat("align %u\n", alignment); - logger->log(sb); + _logger->log(sb); } #endif @@ -4716,22 +4732,22 @@ Error Assembler::align(uint32_t alignMode, uint32_t alignment) { // ============================================================================ Error Assembler::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - if (archId == ArchInfo::kIdX86) { + if (Environment::is32Bit(arch)) { // 32 bit architecture - X86. _gpRegInfo.setSignature(Gpd::kSignature); - _globalInstOptions |= Inst::_kOptionInvalidRex; + _forcedInstOptions |= Inst::_kOptionInvalidRex; _setAddressOverrideMask(kX86MemInfo_67H_X86); } else { // 64 bit architecture - X64. _gpRegInfo.setSignature(Gpq::kSignature); - _globalInstOptions &= ~Inst::_kOptionInvalidRex; + _forcedInstOptions &= ~Inst::_kOptionInvalidRex; _setAddressOverrideMask(kX86MemInfo_67H_X64); } @@ -4739,6 +4755,9 @@ Error Assembler::onAttach(CodeHolder* code) noexcept { } Error Assembler::onDetach(CodeHolder* code) noexcept { + _forcedInstOptions &= ~Inst::_kOptionInvalidRex; + _setAddressOverrideMask(0); + return Base::onDetach(code); } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86assembler.h b/3rdparty/asmjit/src/asmjit/x86/x86assembler.h index 3e3027bab4a..8cd10143b0e 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86assembler.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86assembler.h @@ -37,9 +37,652 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::Assembler] // ============================================================================ -//! Assembler (X86). +//! X86/X64 assembler implementation. //! -//! Emits X86 machine-code into buffers managed by `CodeHolder`. +//! x86::Assembler is a code emitter that emits machine code directly into the +//! \ref CodeBuffer. The assembler is capable of targeting both 32-bit and 64-bit +//! instruction sets, the instruction set can be configured through \ref CodeHolder. +//! +//! ### Basics +//! +//! The following example shows a basic use of `x86::Assembler`, how to generate +//! a function that works in both 32-bit and 64-bit modes, and how to connect +//! \ref JitRuntime, \ref CodeHolder, and `x86::Assembler`. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*SumFunc)(const int* arr, size_t count); +//! +//! int main() { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Decide between 32-bit CDECL, WIN64, and SysV64 calling conventions: +//! // 32-BIT - passed all arguments by stack. +//! // WIN64 - passes first 4 arguments by RCX, RDX, R8, and R9. +//! // UNIX64 - passes first 6 arguments by RDI, RSI, RCX, RDX, R8, and R9. +//! x86::Gp arr, cnt; +//! x86::Gp sum = x86::eax; // Use EAX as 'sum' as it's a return register. +//! +//! if (ASMJIT_ARCH_BITS == 64) { +//! #if defined(_WIN32) +//! arr = x86::rcx; // First argument (array ptr). +//! cnt = x86::rdx; // Second argument (number of elements) +//! #else +//! arr = x86::rdi; // First argument (array ptr). +//! cnt = x86::rsi; // Second argument (number of elements) +//! #endif +//! } +//! else { +//! arr = x86::edx; // Use EDX to hold the array pointer. +//! cnt = x86::ecx; // Use ECX to hold the counter. +//! // Fetch first and second arguments from [ESP + 4] and [ESP + 8]. +//! a.mov(arr, x86::ptr(x86::esp, 4)); +//! a.mov(cnt, x86::ptr(x86::esp, 8)); +//! } +//! +//! Label Loop = a.newLabel(); // To construct the loop, we need some labels. +//! Label Exit = a.newLabel(); +//! +//! a.xor_(sum, sum); // Clear 'sum' register (shorter than 'mov'). +//! a.test(cnt, cnt); // Border case: +//! a.jz(Exit); // If 'cnt' is zero jump to 'Exit' now. +//! +//! a.bind(Loop); // Start of a loop iteration. +//! a.add(sum, x86::dword_ptr(arr)); // Add int at [arr] to 'sum'. +//! a.add(arr, 4); // Increment 'arr' pointer. +//! a.dec(cnt); // Decrease 'cnt'. +//! a.jnz(Loop); // If not zero jump to 'Loop'. +//! +//! a.bind(Exit); // Exit to handle the border case. +//! a.ret(); // Return from function ('sum' == 'eax'). +//! // ----> x86::Assembler is no longer needed from here and can be destroyed <---- +//! +//! SumFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! static const int array[6] = { 4, 8, 15, 16, 23, 42 }; +//! +//! int result = fn(array, 6); // Execute the generated code. +//! printf("%d\n", result); // Print sum of array (108). +//! +//! rt.release(fn); // Explicitly remove the function from the runtime +//! return 0; // Everything successful... +//! } +//! ``` +//! +//! The example should be self-explanatory. It shows how to work with labels, +//! how to use operands, and how to emit instructions that can use different +//! registers based on runtime selection. It implements 32-bit CDECL, WIN64, +//! and SysV64 caling conventions and will work on most X86/X64 environments. +//! +//! Although functions prologs / epilogs can be implemented manually, AsmJit +//! provides utilities that can be used to create function prologs and epilogs +//! automatically, see \ref asmjit_function for more details. +//! +//! ### Instruction Validation +//! +//! Assembler prefers speed over strictness by default. The implementation checks +//! the type of operands and fails if the signature of types is invalid, however, +//! it does only basic checks regarding registers and their groups used in +//! instructions. It's possible to pass operands that don't form any valid +//! signature to the implementation and succeed. This is usually not a problem +//! as Assembler provides typed API so operand types are normally checked by C++ +//! compiler at compile time, however, Assembler is fully dynamic and its \ref +//! emit() function can be called with any instruction id, options, and operands. +//! Moreover, it's also possible to form instructions that will be accepted by +//! the typed API, for example by calling `mov(x86::eax, x86::al)` - the C++ +//! compiler won't see a problem as both EAX and AL are \ref Gp registers. +//! +//! To help with common mistakes AsmJit allows to activate instruction validation. +//! This feature instruments the Assembler to call \ref InstAPI::validate() before +//! it attempts to encode any instruction. +//! +//! The example below illustrates how validation can be turned on: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Enable strict validation. +//! a.addValidationOptions(BaseEmitter::kValidationOptionAssembler); +//! +//! // Try to encode invalid or ill-formed instructions. +//! Error err; +//! +//! // Invalid instruction. +//! err = a.mov(x86::eax, x86::al); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! // Invalid instruction. +//! err = a.emit(x86::Inst::kIdMovss, x86::eax, x86::xmm0); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! // Ambiguous operand size - the pointer requires size. +//! err = a.inc(x86::ptr(x86::rax), 1); +//! printf("Status: %s\n", DebugUtils::errorAsString(err)); +//! +//! return 0; +//! } +//! ``` +//! +//! ### Native Registers +//! +//! All emitters provide functions to construct machine-size registers depending +//! on the target. This feature is for users that want to write code targeting +//! both 32-bit and 64-bit architectures at the same time. In AsmJit terminology +//! such registers have prefix `z`, so for example on X86 architecture the +//! following native registers are provided: +//! +//! - `zax` - mapped to either `eax` or `rax` +//! - `zbx` - mapped to either `ebx` or `rbx` +//! - `zcx` - mapped to either `ecx` or `rcx` +//! - `zdx` - mapped to either `edx` or `rdx` +//! - `zsp` - mapped to either `esp` or `rsp` +//! - `zbp` - mapped to either `ebp` or `rbp` +//! - `zsi` - mapped to either `esi` or `rsi` +//! - `zdi` - mapped to either `edi` or `rdi` +//! +//! They are accessible through \ref x86::Assembler, \ref x86::Builder, and +//! \ref x86::Compiler. The example below illustrates how to use this feature: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef int (*Func)(void); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Let's get these registers from x86::Assembler. +//! x86::Gp zbp = a.zbp(); +//! x86::Gp zsp = a.zsp(); +//! +//! int stackSize = 32; +//! +//! // Function prolog. +//! a.push(zbp); +//! a.mov(zbp, zsp); +//! a.sub(zsp, stackSize); +//! +//! // ... emit some code (this just sets return value to zero) ... +//! a.xor_(x86::eax, x86::eax); +//! +//! // Function epilog and return. +//! a.mov(zsp, zbp); +//! a.pop(zbp); +//! a.ret(); +//! +//! // To make the example complete let's call it. +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "0". +//! +//! rt.release(fn); // Remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! The example just returns `0`, but the function generated contains a standard +//! prolog and epilog sequence and the function itself reserves 32 bytes of local +//! stack. The advantage is clear - a single code-base can handle multiple targets +//! easily. If you want to create a register of native size dynamically by +//! specifying its id it's also possible: +//! +//! ``` +//! void example(x86::Assembler& a) { +//! x86::Gp zax = a.gpz(x86::Gp::kIdAx); +//! x86::Gp zbx = a.gpz(x86::Gp::kIdBx); +//! x86::Gp zcx = a.gpz(x86::Gp::kIdCx); +//! x86::Gp zdx = a.gpz(x86::Gp::kIdDx); +//! +//! // You can also change register's id easily. +//! x86::Gp zsp = zax; +//! zsp.setId(4); // or x86::Gp::kIdSp. +//! } +//! ``` +//! +//! ### Data Embedding +//! +//! x86::Assembler extends the standard \ref BaseAssembler with X86/X64 specific +//! conventions that are often used by assemblers to embed data next to the code. +//! The following functions can be used to embed data: +//! +//! - \ref x86::Assembler::db() - embeds byte (8 bits) (x86 naming). +//! - \ref x86::Assembler::dw() - embeds word (16 bits) (x86 naming). +//! - \ref x86::Assembler::dd() - embeds dword (32 bits) (x86 naming). +//! - \ref x86::Assembler::dq() - embeds qword (64 bits) (x86 naming). +//! +//! - \ref BaseAssembler::embedInt8() - embeds int8_t (portable naming). +//! - \ref BaseAssembler::embedUInt8() - embeds uint8_t (portable naming). +//! - \ref BaseAssembler::embedInt16() - embeds int16_t (portable naming). +//! - \ref BaseAssembler::embedUInt16() - embeds uint16_t (portable naming). +//! - \ref BaseAssembler::embedInt32() - embeds int32_t (portable naming). +//! - \ref BaseAssembler::embedUInt32() - embeds uint32_t (portable naming). +//! - \ref BaseAssembler::embedInt64() - embeds int64_t (portable naming). +//! - \ref BaseAssembler::embedUInt64() - embeds uint64_t (portable naming). +//! - \ref BaseAssembler::embedFloat() - embeds float (portable naming). +//! - \ref BaseAssembler::embedDouble() - embeds double (portable naming). +//! +//! The following example illustrates how embed works: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedData(x86::Assembler& a) { +//! a.db(0xFF); // Embeds 0xFF byte. +//! a.dw(0xFF00); // Embeds 0xFF00 word (little-endian). +//! a.dd(0xFF000000); // Embeds 0xFF000000 dword (little-endian). +//! a.embedFloat(0.4f); // Embeds 0.4f (32-bit float, little-endian). +//! } +//! ``` +//! +//! Sometimes it's required to read the data that is embedded after code, for +//! example. This can be done through \ref Label as shown below: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedData(x86::Assembler& a, const Label& L_Data) { +//! x86::Gp addr = a.zax(); // EAX or RAX. +//! x86::Gp val = x86::edi; // Where to store some value... +//! +//! // Approach 1 - Load the address to register through LEA. This approach +//! // is flexible as the address can be then manipulated, for +//! // example if you have a data array, which would need index. +//! a.lea(addr, L_Data); // Loads the address of the label to EAX or RAX. +//! a.mov(val, dword_ptr(addr)); +//! +//! // Approach 2 - Load the data directly by using L_Data in address. It's +//! // worth noting that this doesn't work with indexes in X64 +//! // mode. It will use absolute address in 32-bit mode and +//! // relative address (RIP) in 64-bit mode. +//! a.mov(val, dword_ptr(L_Data)); +//! } +//! ``` +//! +//! ### Label Embedding +//! +//! It's also possible to embed labels. In general AsmJit provides the following +//! options: +//! +//! - \ref BaseEmitter::embedLabel() - Embeds absolute address of a label. +//! This is target dependent and would embed either 32-bit or 64-bit data +//! that embeds absolute label address. This kind of embedding cannot be +//! used in a position independent code. +//! +//! - \ref BaseEmitter::embedLabelDelta() - Embeds a difference between two +//! labels. The size of the difference can be specified so it's possible to +//! embed 8-bit, 16-bit, 32-bit, and 64-bit difference, which is sufficient +//! for most purposes. +//! +//! The following example demonstrates how to embed labels and their differences: +//! +//! ``` +//! #include <asmjit/x86.h> +//! using namespace asmjit; +//! +//! void embedLabel(x86::Assembler& a, const Label& L_Data) { +//! // [1] Embed L_Data - the size of the data will be dependent on the target. +//! a.embedLabel(L_Data); +//! +//! // [2] Embed a 32-bit difference of two labels. +//! Label L_Here = a.newLabel(); +//! a.bind(L_Here); +//! // Embeds int32_t(L_Data - L_Here). +//! a.embedLabelDelta(L_Data, L_Here, 4); +//! } +//! ``` +//! +//! ### Using FuncFrame and FuncDetail with x86::Assembler +//! +//! The example below demonstrates how \ref FuncFrame and \ref FuncDetail can be +//! used together with \ref x86::Assembler to generate a function that will use +//! platform dependent calling conventions automatically depending on the target: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create JIT Runtime. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Decide which registers will be mapped to function arguments. Try changing +//! // registers of dst, src_a, and src_b and see what happens in function's +//! // prolog and epilog. +//! x86::Gp dst = a.zax(); +//! x86::Gp src_a = a.zcx(); +//! x86::Gp src_b = a.zdx(); +//! +//! X86::Xmm vec0 = x86::xmm0; +//! X86::Xmm vec1 = x86::xmm1; +//! +//! // Create/initialize FuncDetail and FuncFrame. +//! FuncDetail func; +//! func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); +//! +//! FuncFrame frame; +//! frame.init(func); +//! +//! // Make XMM0 and XMM1 dirty - kGroupVec describes XMM|YMM|ZMM registers. +//! frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); +//! +//! // Alternatively, if you don't want to use register masks you can pass BaseReg +//! // to addDirtyRegs(). The following code would add both xmm0 and xmm1. +//! frame.addDirtyRegs(x86::xmm0, x86::xmm1); +//! +//! FuncArgsAssignment args(&func); // Create arguments assignment context. +//! args.assignAll(dst, src_a, src_b);// Assign our registers to arguments. +//! args.updateFrameInfo(frame); // Reflect our args in FuncFrame. +//! frame.finalize(); // Finalize the FuncFrame (updates it). +//! +//! a.emitProlog(frame); // Emit function prolog. +//! a.emitArgsAssignment(frame, args);// Assign arguments to registers. +//! a.movdqu(vec0, x86::ptr(src_a)); // Load 4 ints from [src_a] to XMM0. +//! a.movdqu(vec1, x86::ptr(src_b)); // Load 4 ints from [src_b] to XMM1. +//! a.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. +//! a.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. +//! a.emitEpilog(frame); // Emit function epilog and return. +//! +//! SumIntsFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error case. +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! fn(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! rt.release(fn); +//! return 0; +//! } +//! ``` +//! +//! ### Using x86::Assembler as Code-Patcher +//! +//! This is an advanced topic that is sometimes unavoidable. AsmJit by default +//! appends machine code it generates into a \ref CodeBuffer, however, it also +//! allows to set the offset in \ref CodeBuffer explicitly and to overwrite its +//! content. This technique is extremely dangerous as X86 instructions have +//! variable length (see below), so you should in general only patch code to +//! change instruction's immediate values or some other details not known the +//! at a time the instruction was emitted. A typical scenario that requires +//! code-patching is when you start emitting function and you don't know how +//! much stack you want to reserve for it. +//! +//! Before we go further it's important to introduce instruction options, because +//! they can help with code-patching (and not only patching, but that will be +//! explained in AVX-512 section): +//! +//! - Many general-purpose instructions (especially arithmetic ones) on X86 +//! have multiple encodings - in AsmJit this is usually called 'short form' +//! and 'long form'. +//! - AsmJit always tries to use 'short form' as it makes the resulting +//! machine-code smaller, which is always good - this decision is used +//! by majority of assemblers out there. +//! - AsmJit allows to override the default decision by using `short_()` +//! and `long_()` instruction options to force short or long form, +//! respectively. The most useful is `long_()` as it basically forces +//! AsmJit to always emit the longest form. The `short_()` is not that +//! useful as it's automatic (except jumps to non-bound labels). Note that +//! the underscore after each function name avoids collision with built-in +//! C++ types. +//! +//! To illustrate what short form and long form means in binary let's assume +//! we want to emit "add esp, 16" instruction, which has two possible binary +//! encodings: +//! +//! - `83C410` - This is a short form aka `short add esp, 16` - You can see +//! opcode byte (0x8C), MOD/RM byte (0xC4) and an 8-bit immediate value +//! representing `16`. +//! - `81C410000000` - This is a long form aka `long add esp, 16` - You can +//! see a different opcode byte (0x81), the same Mod/RM byte (0xC4) and a +//! 32-bit immediate in little-endian representing `16`. +//! +//! It should be obvious that patching an existing instruction into an instruction +//! having a different size may create various problems. So it's recommended to be +//! careful and to only patch instructions into instructions having the same size. +//! The example below demonstrates how instruction options can be used to guarantee +//! the size of an instruction by forcing the assembler to use long-form encoding: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef int (*Func)(void); +//! +//! int main(int argc, char* argv[]) { +//! JitRuntime rt; // Create a runtime specialized for JIT. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Assembler a(&code); // Create and attach x86::Assembler to code. +//! +//! // Let's get these registers from x86::Assembler. +//! x86::Gp zbp = a.zbp(); +//! x86::Gp zsp = a.zsp(); +//! +//! // Function prolog. +//! a.push(zbp); +//! a.mov(zbp, zsp); +//! +//! // This is where we are gonna patch the code later, so let's get the offset +//! // (the current location) from the beginning of the code-buffer. +//! size_t patchOffset = a.offset(); +//! // Let's just emit 'sub zsp, 0' for now, but don't forget to use LONG form. +//! a.long_().sub(zsp, 0); +//! +//! // ... emit some code (this just sets return value to zero) ... +//! a.xor_(x86::eax, x86::eax); +//! +//! // Function epilog and return. +//! a.mov(zsp, zbp); +//! a.pop(zbp); +//! a.ret(); +//! +//! // Now we know how much stack size we want to reserve. I have chosen 128 +//! // bytes on purpose as it's encodable only in long form that we have used. +//! +//! int stackSize = 128; // Number of bytes to reserve on the stack. +//! a.setOffset(patchOffset); // Move the current cursor to `patchOffset`. +//! a.long_().sub(zsp, stackSize); // Patch the code; don't forget to use LONG form. +//! +//! // Now the code is ready to be called +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "0". +//! +//! rt.release(fn); // Remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! If you run the example it will just work, because both instructions have +//! the same size. As an experiment you can try removing `long_()` form to +//! see what happens when wrong code is generated. +//! +//! ### Code Patching and REX Prefix +//! +//! In 64-bit mode there is one more thing to worry about when patching code: +//! REX prefix. It's a single byte prefix designed to address registers with +//! ids from 9 to 15 and to override the default width of operation from 32 +//! to 64 bits. AsmJit, like other assemblers, only emits REX prefix when it's +//! necessary. If the patched code only changes the immediate value as shown +//! in the previous example then there is nothing to worry about as it doesn't +//! change the logic behind emitting REX prefix, however, if the patched code +//! changes register id or overrides the operation width then it's important +//! to take care of REX prefix as well. +//! +//! AsmJit contains another instruction option that controls (forces) REX +//! prefix - `rex()`. If you use it the instruction emitted will always use +//! REX prefix even when it's encodable without it. The following list contains +//! some instructions and their binary representations to illustrate when it's +//! emitted: +//! +//! - `__83C410` - `add esp, 16` - 32-bit operation in 64-bit mode doesn't require REX prefix. +//! - `4083C410` - `rex add esp, 16` - 32-bit operation in 64-bit mode with forced REX prefix (0x40). +//! - `4883C410` - `add rsp, 16` - 64-bit operation in 64-bit mode requires REX prefix (0x48). +//! - `4183C410` - `add r12d, 16` - 32-bit operation in 64-bit mode using R12D requires REX prefix (0x41). +//! - `4983C410` - `add r12, 16` - 64-bit operation in 64-bit mode using R12 requires REX prefix (0x49). +//! +//! ### More Prefixes +//! +//! X86 architecture is known for its prefixes. AsmJit supports all prefixes +//! that can affect how the instruction is encoded: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void prefixesExample(x86::Assembler& a) { +//! // Lock prefix for implementing atomics: +//! // lock add dword ptr [dst], 1 +//! a.lock().add(x86::dword_ptr(dst), 1); +//! +//! // Similarly, XAcquire/XRelease prefixes are also available: +//! // xacquire add dword ptr [dst], 1 +//! a.xacquire().add(x86::dword_ptr(dst), 1); +//! +//! // Rep prefix (see also repe/repz and repne/repnz): +//! // rep movs byte ptr [dst], byte ptr [src] +//! a.rep().movs(x86::byte_ptr(dst), x86::byte_ptr(src)); +//! +//! // Forcing REX prefix in 64-bit mode. +//! // rex mov eax, 1 +//! a.rex().mov(x86::eax, 1); +//! +//! // AVX instruction without forced prefix uses the shortest encoding: +//! // vaddpd xmm0, xmm1, xmm2 -> [C5|F1|58|C2] +//! a.vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Forcing VEX3 prefix (AVX): +//! // vex3 vaddpd xmm0, xmm1, xmm2 -> [C4|E1|71|58|C2] +//! a.vex3().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Forcing EVEX prefix (AVX512): +//! // evex vaddpd xmm0, xmm1, xmm2 -> [62|F1|F5|08|58|C2] +//! a.evex().vaddpd(x86::xmm0, x86::xmm1, x86::xmm2); +//! +//! // Some instructions accept prefixes not originally intended to: +//! // rep ret +//! a.rep().ret(); +//! } +//! ``` +//! +//! It's important to understand that prefixes are part of instruction options. +//! When a member function that involves adding a prefix is called the prefix +//! is combined with existing instruction options, which will affect the next +//! instruction generated. +//! +//! ### Generating AVX512 code. +//! +//! x86::Assembler can generate AVX512+ code including the use of opmask +//! registers. Opmask can be specified through \ref x86::Assembler::k() +//! function, which stores it as an extra register, which will be used +//! by the next instruction. AsmJit uses such concept for manipulating +//! instruction options as well. +//! +//! The following AVX512 features are supported: +//! +//! - Opmask selector {k} and zeroing {z}. +//! - Rounding modes {rn|rd|ru|rz} and suppress-all-exceptions {sae} option. +//! - AVX512 broadcasts {1toN}. +//! +//! The following example demonstrates how AVX512 features can be used: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! void generateAVX512Code(x86::Assembler& a) { +//! using namespace x86; +//! +//! // Opmask Selectors +//! // ---------------- +//! // +//! // - Opmask / zeroing is part of the instruction options / extraReg. +//! // - k(reg) is like {kreg} in Intel syntax. +//! // - z() is like {z} in Intel syntax. +//! +//! // vaddpd zmm {k1} {z}, zmm1, zmm2 +//! a.k(k1).z().vaddpd(zmm0, zmm1, zmm2); +//! +//! // Memory Broadcasts +//! // ----------------- +//! // +//! // - Broadcast data is part of memory operand. +//! // - Use x86::Mem::_1toN(), which returns a new x86::Mem operand. +//! +//! // vaddpd zmm0 {k1} {z}, zmm1, [rcx] {1to8} +//! a.k(k1).z().vaddpd(zmm0, zmm1, x86::mem(rcx)._1to8()); +//! +//! // Embedded Rounding & Suppress-All-Exceptoins +//! // ------------------------------------------- +//! // +//! // - Rounding mode and {sae} are part of instruction options. +//! // - Use sae() to enable exception suppression. +//! // - Use rn_sae(), rd_sae(), ru_sae(), and rz_sae() - to enable rounding. +//! // - Embedded rounding implicitly sets {sae} as well, that's why the API +//! // also has sae() suffix, to make it clear. +//! +//! // vcmppd k1, zmm1, zmm2, 0x00 {sae} +//! a.sae().vcmppd(k1, zmm1, zmm2, 0); +//! +//! // vaddpd zmm0, zmm1, zmm2 {rz} +//! a.rz_sae().vaddpd(zmm0, zmm1, zmm2); +//! } +//! ``` class ASMJIT_VIRTAPI Assembler : public BaseAssembler, public EmitterImplicitT<Assembler> { @@ -69,12 +712,10 @@ public: //! \} //! \endcond - //! \cond INTERNAL //! \name Emit //! \{ - using BaseEmitter::_emit; - ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; + ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override; //! \} //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp b/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp index 4e65c7b16b5..b3c0b261a0b 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86builder.cpp @@ -46,6 +46,8 @@ Builder::~Builder() noexcept {} Error Builder::finalize() { ASMJIT_PROPAGATE(runPasses()); Assembler a(_code); + a.addEncodingOptions(encodingOptions()); + a.addValidationOptions(validationOptions()); return serialize(&a); } @@ -54,13 +56,13 @@ Error Builder::finalize() { // ============================================================================ Error Builder::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - _gpRegInfo.setSignature(archId == ArchInfo::kIdX86 ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); + _gpRegInfo.setSignature(Environment::is32Bit(arch) ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); return kErrorOk; } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86builder.h b/3rdparty/asmjit/src/asmjit/x86/x86builder.h index 66e2dfc99d8..256bc9ecbec 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86builder.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86builder.h @@ -40,7 +40,315 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::Builder] // ============================================================================ -//! Architecture-dependent asm-builder (X86). +//! X86/X64 builder implementation. +//! +//! The code representation used by \ref BaseBuilder is compatible with everything +//! AsmJit provides. Each instruction is stored as \ref InstNode, which contains +//! instruction id, options, and operands. Each instruction emitted will create +//! a new \ref InstNode instance and add it to the current cursor in the double-linked +//! list of nodes. Since the instruction stream used by \ref BaseBuilder can be +//! manipulated, we can rewrite the SumInts example from \ref asmjit_assembler +//! into the following: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! typedef void (*SumIntsFunc)(int* dst, const int* a, const int* b); +//! +//! // Small helper function to print the current content of `cb`. +//! static void dumpCode(BaseBuilder& builder, const char* phase) { +//! String sb; +//! builder.dump(sb); +//! printf("%s:\n%s\n", phase, sb.data()); +//! } +//! +//! int main() { +//! JitRuntime rt; // Create JIT Runtime. +//! CodeHolder code; // Create a CodeHolder. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Builder cb(&code); // Create and attach x86::Builder to `code`. +//! +//! // Decide which registers will be mapped to function arguments. Try changing +//! // registers of `dst`, `srcA`, and `srcB` and see what happens in function's +//! // prolog and epilog. +//! x86::Gp dst = cb.zax(); +//! x86::Gp srcA = cb.zcx(); +//! x86::Gp srcB = cb.zdx(); +//! +//! X86::Xmm vec0 = x86::xmm0; +//! X86::Xmm vec1 = x86::xmm1; +//! +//! // Create and initialize `FuncDetail`. +//! FuncDetail func; +//! func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); +//! +//! // Remember prolog insertion point. +//! BaseNode* prologInsertionPoint = cb.cursor(); +//! +//! // Emit function body: +//! cb.movdqu(vec0, x86::ptr(srcA)); // Load 4 ints from [srcA] to XMM0. +//! cb.movdqu(vec1, x86::ptr(srcB)); // Load 4 ints from [srcB] to XMM1. +//! cb.paddd(vec0, vec1); // Add 4 ints in XMM1 to XMM0. +//! cb.movdqu(x86::ptr(dst), vec0); // Store the result to [dst]. +//! +//! // Remember epilog insertion point. +//! BaseNode* epilogInsertionPoint = cb.cursor(); +//! +//! // Let's see what we have now. +//! dumpCode(cb, "Raw Function"); +//! +//! // Now, after we emitted the function body, we can insert the prolog, arguments +//! // allocation, and epilog. This is not possible with using pure x86::Assembler. +//! FuncFrame frame; +//! frame.init(func); +//! +//! // Make XMM0 and XMM1 dirty; `kGroupVec` describes XMM|YMM|ZMM registers. +//! frame.setDirtyRegs(x86::Reg::kGroupVec, IntUtils::mask(0, 1)); +//! +//! FuncArgsAssignment args(&func); // Create arguments assignment context. +//! args.assignAll(dst, srcA, srcB); // Assign our registers to arguments. +//! args.updateFrame(frame); // Reflect our args in FuncFrame. +//! frame.finalize(); // Finalize the FuncFrame (updates it). +//! +//! // Insert function prolog and allocate arguments to registers. +//! cb.setCursor(prologInsertionPoint); +//! cb.emitProlog(frame); +//! cb.emitArgsAssignment(frame, args); +//! +//! // Insert function epilog. +//! cb.setCursor(epilogInsertionPoint); +//! cb.emitEpilog(frame); +//! +//! // Let's see how the function's prolog and epilog looks. +//! dumpCode(cb, "Prolog & Epilog"); +//! +//! // IMPORTANT: Builder requires finalize() to be called to serialize its +//! // code to the Assembler (it automatically creates one if not attached). +//! cb.finalize(); +//! +//! SumIntsFunc fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error case. +//! +//! // Execute the generated function. +//! int inA[4] = { 4, 3, 2, 1 }; +//! int inB[4] = { 1, 5, 2, 8 }; +//! int out[4]; +//! fn(out, inA, inB); +//! +//! // Prints {5 8 4 9} +//! printf("{%d %d %d %d}\n", out[0], out[1], out[2], out[3]); +//! +//! rt.release(fn); // Explicitly remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! When the example is executed it should output the following (this one using +//! AMD64-SystemV ABI): +//! +//! ``` +//! Raw Function: +//! movdqu xmm0, [rcx] +//! movdqu xmm1, [rdx] +//! paddd xmm0, xmm1 +//! movdqu [rax], xmm0 +//! +//! Prolog & Epilog: +//! mov rax, rdi +//! mov rcx, rsi +//! movdqu xmm0, [rcx] +//! movdqu xmm1, [rdx] +//! paddd xmm0, xmm1 +//! movdqu [rax], xmm0 +//! ret +//! +//! {5 8 4 9} +//! ``` +//! +//! The number of use-cases of \ref BaseBuilder is not limited and highly depends +//! on your creativity and experience. The previous example can be easily improved +//! to collect all dirty registers inside the function programmatically and to pass +//! them to \ref FuncFrame::setDirtyRegs(). +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! // NOTE: This function doesn't cover all possible constructs. It ignores +//! // instructions that write to implicit registers that are not part of the +//! // operand list. It also counts read-only registers. Real implementation +//! // would be a bit more complicated, but still relatively easy to implement. +//! static void collectDirtyRegs(const BaseNode* first, +//! const BaseNode* last, +//! uint32_t regMask[BaseReg::kGroupVirt]) { +//! const BaseNode* node = first; +//! while (node) { +//! if (node->actsAsInst()) { +//! const InstNode* inst = node->as<InstNode>(); +//! const Operand* opArray = inst->operands(); +//! +//! for (uint32_t i = 0, opCount = inst->opCount(); i < opCount; i++) { +//! const Operand& op = opArray[i]; +//! if (op.isReg()) { +//! const x86::Reg& reg = op.as<x86::Reg>(); +//! if (reg.group() < BaseReg::kGroupVirt) { +//! regMask[reg.group()] |= 1u << reg.id(); +//! } +//! } +//! } +//! } +//! +//! if (node == last) +//! break; +//! node = node->next(); +//! } +//! } +//! +//! static void setDirtyRegsOfFuncFrame(const x86::Builder& builder, FuncFrame& frame) { +//! uint32_t regMask[BaseReg::kGroupVirt] {}; +//! collectDirtyRegs(builder.firstNode(), builder.lastNode(), regMask); +//! +//! // X86/X64 ABIs only require to save GP/XMM registers: +//! frame.setDirtyRegs(x86::Reg::kGroupGp , regMask[x86::Reg::kGroupGp ]); +//! frame.setDirtyRegs(x86::Reg::kGroupVec, regMask[x86::Reg::kGroupVec]); +//! } +//! ``` +//! +//! ### Casting Between Various Emitters +//! +//! Even when \ref BaseAssembler and \ref BaseBuilder provide the same interface +//! as defined by \ref BaseEmitter their platform dependent variants like \ref +//! x86::Assembler and \ref x86::Builder cannot be interchanged or casted +//! to each other by using a C++ `static_cast<>`. The main reason is the +//! inheritance graph of these classes is different and cast-incompatible, as +//! illustrated below: +//! +//! ``` +//! +--------------+ +=========================+ +//! +----------------------->| x86::Emitter |<--+--# x86::EmitterImplicitT<> #<--+ +//! | +--------------+ | +=========================+ | +//! | (abstract) | (mixin) | +//! | +--------------+ +~~~~~~~~~~~~~~+ | | +//! +-->| BaseAssembler|---->|x86::Assembler|<--+ | +//! | +--------------+ +~~~~~~~~~~~~~~+ | | +//! | (abstract) (final) | | +//! +===============+ | +--------------+ +~~~~~~~~~~~~~~+ | | +//! # BaseEmitter #--+-->| BaseBuilder |--+->| x86::Builder |<--+ | +//! +===============+ +--------------+ | +~~~~~~~~~~~~~~+ | +//! (abstract) (abstract) | (final) | +//! +---------------------+ | +//! | | +//! | +--------------+ +~~~~~~~~~~~~~~+ +=========================+ | +//! +-->| BaseCompiler |---->| x86::Compiler|<-----# x86::EmitterExplicitT<> #---+ +//! +--------------+ +~~~~~~~~~~~~~~+ +=========================+ +//! (abstract) (final) (mixin) +//! ``` +//! +//! The graph basically shows that it's not possible to cast between \ref +//! x86::Assembler and \ref x86::Builder. However, since both share the +//! base interface (\ref BaseEmitter) it's possible to cast them to a class +//! that cannot be instantiated, but defines the same interface - the class +//! is called \ref x86::Emitter and was introduced to make it possible to +//! write a function that can emit to both \ref x86::Assembler and \ref +//! x86::Builder. Note that \ref x86::Emitter cannot be created, it's abstract +//! and has private constructors and destructors; it was only designed to be +//! casted to and used as an interface. +//! +//! Each architecture-specific emitter implements a member function called +//! `as<arch::Emitter>()`, which casts the instance to the architecture +//! specific emitter as illustrated below: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void emitSomething(x86::Emitter* e) { +//! e->mov(x86::eax, x86::ebx); +//! } +//! +//! static void assemble(CodeHolder& code, bool useAsm) { +//! if (useAsm) { +//! x86::Assembler assembler(&code); +//! emitSomething(assembler.as<x86::Emitter>()); +//! } +//! else { +//! x86::Builder builder(&code); +//! emitSomething(builder.as<x86::Emitter>()); +//! +//! // NOTE: Builder requires `finalize()` to be called to serialize its +//! // content to Assembler (it automatically creates one if not attached). +//! builder.finalize(); +//! } +//! } +//! ``` +//! +//! The example above shows how to create a function that can emit code to +//! either \ref x86::Assembler or \ref x86::Builder through \ref x86::Emitter, +//! which provides emitter-neutral functionality. \ref x86::Emitter, however, +//! doesn't provide any emitter-specific functionality like `setCursor()`. +//! +//! ### Code Injection and Manipulation +//! +//! \ref BaseBuilder emitter stores its nodes in a double-linked list, which +//! makes it easy to manipulate that list during the code generation or +//! afterwards. Each node is always emitted next to the current cursor and the +//! cursor is advanced to that newly emitted node. The cursor can be retrieved +//! and changed by \ref BaseBuilder::cursor() and \ref BaseBuilder::setCursor(), +//! respectively. +//! +//! The example below demonstrates how to remember a node and inject something +//! next to it. +//! +//! ``` +//! static void example(x86::Builder& builder) { +//! // Emit something, after it returns the cursor would point at the last +//! // emitted node. +//! builder.mov(x86::rax, x86::rdx); // [1] +//! +//! // We can retrieve the node. +//! BaseNode* node = builder.cursor(); +//! +//! // Change the instruction we just emitted, just for fun... +//! if (node->isInst()) { +//! InstNode* inst = node->as<InstNode>(); +//! // Changes the operands at index [1] to RCX. +//! inst->setOp(1, x86::rcx); +//! } +//! +//! // ------------------------- Generate Some Code ------------------------- +//! builder.add(x86::rax, x86::rdx); // [2] +//! builder.shr(x86::rax, 3); // [3] +//! // ---------------------------------------------------------------------- +//! +//! // Now, we know where our node is, and we can simply change the cursor +//! // and start emitting something after it. The setCursor() function +//! // returns the previous cursor, and it's always a good practice to remember +//! // it, because you never know if you are not already injecting the code +//! // somewhere else... +//! BaseNode* oldCursor = builder.setCursor(node); +//! +//! builder.mul(x86::rax, 8); // [4] +//! +//! // Restore the cursor +//! builder.setCursor(oldCursor); +//! } +//! ``` +//! +//! The function above would actually emit the following: +//! +//! ``` +//! mov rax, rcx ; [1] Patched at the beginning. +//! mul rax, 8 ; [4] Injected. +//! add rax, rdx ; [2] Followed [1] initially. +//! shr rax, 3 ; [3] Follows [2]. +//! ``` class ASMJIT_VIRTAPI Builder : public BaseBuilder, public EmitterImplicitT<Builder> { diff --git a/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp b/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp index 7ec4c55ef0a..e0a3f213dfe 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86callconv.cpp @@ -33,13 +33,19 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::CallConvInternal - Init] // ============================================================================ -static inline void CallConv_initX86Common(CallConv& cc) noexcept { - cc.setNaturalStackAlignment(4); - cc.setArchType(ArchInfo::kIdX86); - cc.setPreservedRegs(Reg::kGroupGp, Support::bitMask(Gp::kIdBx, Gp::kIdSp, Gp::kIdBp, Gp::kIdSi, Gp::kIdDi)); +namespace CallConvInternal { + +static inline bool shouldThreatAsCDeclIn64BitMode(uint32_t ccId) noexcept { + return ccId == CallConv::kIdCDecl || + ccId == CallConv::kIdStdCall || + ccId == CallConv::kIdThisCall || + ccId == CallConv::kIdFastCall || + ccId == CallConv::kIdRegParm1 || + ccId == CallConv::kIdRegParm2 || + ccId == CallConv::kIdRegParm3; } -ASMJIT_FAVOR_SIZE Error CallConvInternal::init(CallConv& cc, uint32_t ccId) noexcept { +ASMJIT_FAVOR_SIZE Error init(CallConv& cc, uint32_t ccId, const Environment& environment) noexcept { constexpr uint32_t kGroupGp = Reg::kGroupGp; constexpr uint32_t kGroupVec = Reg::kGroupVec; constexpr uint32_t kGroupMm = Reg::kGroupMm; @@ -54,110 +60,179 @@ ASMJIT_FAVOR_SIZE Error CallConvInternal::init(CallConv& cc, uint32_t ccId) noex constexpr uint32_t kZsi = Gp::kIdSi; constexpr uint32_t kZdi = Gp::kIdDi; - switch (ccId) { - case CallConv::kIdX86StdCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86MsThisCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - cc.setPassedOrder(kGroupGp, kZcx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86MsFastCall: - case CallConv::kIdX86GccFastCall: - cc.setFlags(CallConv::kFlagCalleePopsStack); - cc.setPassedOrder(kGroupGp, kZcx, kZdx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm1: - cc.setPassedOrder(kGroupGp, kZax); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm2: - cc.setPassedOrder(kGroupGp, kZax, kZdx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86GccRegParm3: - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx); - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86CDecl: - CallConv_initX86Common(cc); - break; - - case CallConv::kIdX86Win64: - cc.setArchType(ArchInfo::kIdX64); - cc.setStrategy(CallConv::kStrategyWin64); - cc.setFlags(CallConv::kFlagPassFloatsByVec | CallConv::kFlagIndirectVecArgs); - cc.setNaturalStackAlignment(16); - cc.setSpillZoneSize(32); - cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3); - cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); - cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); - break; - - case CallConv::kIdX86SysV64: - cc.setArchType(ArchInfo::kIdX64); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setRedZoneSize(128); - cc.setPassedOrder(kGroupGp, kZdi, kZsi, kZdx, kZcx, 8, 9); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, 12, 13, 14, 15)); - break; - - case CallConv::kIdX86LightCall2: - case CallConv::kIdX86LightCall3: - case CallConv::kIdX86LightCall4: { - uint32_t n = (ccId - CallConv::kIdX86LightCall2) + 2; - - cc.setArchType(ArchInfo::kIdX86); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); - cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); - - cc.setPreservedRegs(kGroupGp , Support::lsbMask<uint32_t>(8)); - cc.setPreservedRegs(kGroupVec , Support::lsbMask<uint32_t>(8) & ~Support::lsbMask<uint32_t>(n)); - break; + bool winABI = environment.isPlatformWindows() || environment.isAbiMSVC(); + + cc.setArch(environment.arch()); + + if (environment.is32Bit()) { + bool isStandardCallConv = true; + + cc.setPreservedRegs(Reg::kGroupGp, Support::bitMask(Gp::kIdBx, Gp::kIdSp, Gp::kIdBp, Gp::kIdSi, Gp::kIdDi)); + cc.setNaturalStackAlignment(4); + + switch (ccId) { + case CallConv::kIdCDecl: + break; + + case CallConv::kIdStdCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + break; + + case CallConv::kIdFastCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx, kZdx); + break; + + case CallConv::kIdVectorCall: + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx, kZdx); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5); + break; + + case CallConv::kIdThisCall: + // NOTE: Even MINGW (starting with GCC 4.7.0) now uses __thiscall on MS Windows, + // so we won't bail to any other calling convention if __thiscall was specified. + if (winABI) { + cc.setFlags(CallConv::kFlagCalleePopsStack); + cc.setPassedOrder(kGroupGp, kZcx); + } + else { + ccId = CallConv::kIdCDecl; + } + break; + + case CallConv::kIdRegParm1: + cc.setPassedOrder(kGroupGp, kZax); + break; + + case CallConv::kIdRegParm2: + cc.setPassedOrder(kGroupGp, kZax, kZdx); + break; + + case CallConv::kIdRegParm3: + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx); + break; + + case CallConv::kIdLightCall2: + case CallConv::kIdLightCall3: + case CallConv::kIdLightCall4: { + uint32_t n = (ccId - CallConv::kIdLightCall2) + 2; + + cc.setFlags(CallConv::kFlagPassFloatsByVec); + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); + cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPreservedRegs(kGroupGp, Support::lsbMask<uint32_t>(8)); + cc.setPreservedRegs(kGroupVec, Support::lsbMask<uint32_t>(8) & ~Support::lsbMask<uint32_t>(n)); + + cc.setNaturalStackAlignment(16); + isStandardCallConv = false; + break; + } + + default: + return DebugUtils::errored(kErrorInvalidArgument); } - case CallConv::kIdX64LightCall2: - case CallConv::kIdX64LightCall3: - case CallConv::kIdX64LightCall4: { - uint32_t n = (ccId - CallConv::kIdX64LightCall2) + 2; - - cc.setArchType(ArchInfo::kIdX64); - cc.setFlags(CallConv::kFlagPassFloatsByVec); - cc.setNaturalStackAlignment(16); - cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); - cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); - cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); - - cc.setPreservedRegs(kGroupGp , Support::lsbMask<uint32_t>(16)); - cc.setPreservedRegs(kGroupVec ,~Support::lsbMask<uint32_t>(n)); - break; + if (isStandardCallConv) { + // MMX arguments is something where compiler vendors disagree. For example + // GCC and MSVC would pass first three via registers and the rest via stack, + // however Clang passes all via stack. Returning MMX registers is even more + // fun, where GCC uses MM0, but Clang uses EAX:EDX pair. I'm not sure it's + // something we should be worried about as MMX is deprecated anyway. + cc.setPassedOrder(kGroupMm, 0, 1, 2); + + // Vector arguments (XMM|YMM|ZMM) are passed via registers. However, if the + // function is variadic then they have to be passed via stack. + cc.setPassedOrder(kGroupVec, 0, 1, 2); + + // Functions with variable arguments always use stack for MM and vector + // arguments. + cc.addFlags(CallConv::kFlagPassVecByStackIfVA); } - default: - return DebugUtils::errored(kErrorInvalidArgument); + if (ccId == CallConv::kIdCDecl) { + cc.addFlags(CallConv::kFlagVarArgCompatible); + } + } + else { + // Preprocess the calling convention into a common id as many conventions + // are normally ignored even by C/C++ compilers and treated as `__cdecl`. + if (shouldThreatAsCDeclIn64BitMode(ccId)) + ccId = winABI ? CallConv::kIdX64Windows : CallConv::kIdX64SystemV; + + switch (ccId) { + case CallConv::kIdX64SystemV: { + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagPassMmxByXmm | + CallConv::kFlagVarArgCompatible); + cc.setNaturalStackAlignment(16); + cc.setRedZoneSize(128); + cc.setPassedOrder(kGroupGp, kZdi, kZsi, kZdx, kZcx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdX64Windows: { + cc.setStrategy(CallConv::kStrategyX64Windows); + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagIndirectVecArgs | + CallConv::kFlagPassMmxByGp | + CallConv::kFlagVarArgCompatible); + cc.setNaturalStackAlignment(16); + // Maximum 4 arguments in registers, each adds 8 bytes to the spill zone. + cc.setSpillZoneSize(4 * 8); + cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); + cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdVectorCall: { + cc.setStrategy(CallConv::kStrategyX64VectorCall); + cc.setFlags(CallConv::kFlagPassFloatsByVec | + CallConv::kFlagPassMmxByGp ); + cc.setNaturalStackAlignment(16); + // Maximum 6 arguments in registers, each adds 8 bytes to the spill zone. + cc.setSpillZoneSize(6 * 8); + cc.setPassedOrder(kGroupGp, kZcx, kZdx, 8, 9); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5); + cc.setPreservedRegs(kGroupGp, Support::bitMask(kZbx, kZsp, kZbp, kZsi, kZdi, 12, 13, 14, 15)); + cc.setPreservedRegs(kGroupVec, Support::bitMask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); + break; + } + + case CallConv::kIdLightCall2: + case CallConv::kIdLightCall3: + case CallConv::kIdLightCall4: { + uint32_t n = (ccId - CallConv::kIdLightCall2) + 2; + + cc.setFlags(CallConv::kFlagPassFloatsByVec); + cc.setNaturalStackAlignment(16); + cc.setPassedOrder(kGroupGp, kZax, kZdx, kZcx, kZsi, kZdi); + cc.setPassedOrder(kGroupMm, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupVec, 0, 1, 2, 3, 4, 5, 6, 7); + cc.setPassedOrder(kGroupKReg, 0, 1, 2, 3, 4, 5, 6, 7); + + cc.setPreservedRegs(kGroupGp, Support::lsbMask<uint32_t>(16)); + cc.setPreservedRegs(kGroupVec, ~Support::lsbMask<uint32_t>(n)); + break; + } + + default: + return DebugUtils::errored(kErrorInvalidArgument); + } } cc.setId(ccId); return kErrorOk; } +} // {CallConvInternal} + ASMJIT_END_SUB_NAMESPACE #endif // ASMJIT_BUILD_X86 diff --git a/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h b/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h index 5fc21133cef..1607ea2e385 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86callconv_p.h @@ -38,9 +38,11 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! X86-specific function API (calling conventions and other utilities). namespace CallConvInternal { - //! Initialize `CallConv` structure (X86 specific). - Error init(CallConv& cc, uint32_t ccId) noexcept; -} + +//! Initialize `CallConv` structure (X86 specific). +Error init(CallConv& cc, uint32_t ccId, const Environment& environment) noexcept; + +} // {CallConvInternal} //! \} //! \endcond diff --git a/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp b/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp index 910ed5e7dde..33377e9f98b 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86compiler.cpp @@ -47,20 +47,24 @@ Compiler::~Compiler() noexcept {} Error Compiler::finalize() { ASMJIT_PROPAGATE(runPasses()); Assembler a(_code); + a.addEncodingOptions(encodingOptions()); + a.addValidationOptions(validationOptions()); return serialize(&a); } - // ============================================================================ // [asmjit::x86::Compiler - Events] // ============================================================================ Error Compiler::onAttach(CodeHolder* code) noexcept { - uint32_t archId = code->archId(); - if (!ArchInfo::isX86Family(archId)) + uint32_t arch = code->arch(); + if (!Environment::isFamilyX86(arch)) return DebugUtils::errored(kErrorInvalidArch); ASMJIT_PROPAGATE(Base::onAttach(code)); - _gpRegInfo.setSignature(archId == ArchInfo::kIdX86 ? uint32_t(Gpd::kSignature) : uint32_t(Gpq::kSignature)); + + bool is32Bit = Environment::is32Bit(arch); + _gpRegInfo.setSignature(is32Bit ? uint32_t(Gpd::kSignature) + : uint32_t(Gpq::kSignature)); Error err = addPassT<X86RAPass>(); if (ASMJIT_UNLIKELY(err)) { diff --git a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h index cc7035b2990..4c64b3b6e40 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86compiler.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86compiler.h @@ -41,7 +41,413 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // [asmjit::x86::Compiler] // ============================================================================ -//! Architecture-dependent asm-compiler (X86). +//! X86/X64 compiler implementation. +//! +//! ### Compiler Basics +//! +//! The first \ref x86::Compiler example shows how to generate a function that +//! simply returns an integer value. It's an analogy to the first Assembler example: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc(FuncSignatureT<int>());// Begin a function of `int fn(void)` signature. +//! +//! x86::Gp vReg = cc.newGpd(); // Create a 32-bit general purpose register. +//! cc.mov(vReg, 1); // Move one to our virtual register `vReg`. +//! cc.ret(vReg); // Return `vReg` from the function. +//! +//! cc.endFunc(); // End of the function body. +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Func fn; +//! Error err = rt.add(&fn, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! int result = fn(); // Execute the generated code. +//! printf("%d\n", result); // Print the resulting "1". +//! +//! rt.release(fn); // Explicitly remove the function from the runtime. +//! return 0; +//! } +//! ``` +//! +//! The \ref BaseCompiler::addFunc() and \ref BaseCompiler::endFunc() functions +//! are used to define the function and its end. Both must be called per function, +//! but the body doesn't have to be generated in sequence. An example of generating +//! two functions will be shown later. The next example shows more complicated code +//! that contain a loop and generates a simple memory copy function that uses +//! `uint32_t` items: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef void (*MemCpy32)(uint32_t* dst, const uint32_t* src, size_t count); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc( // Begin the function of the following signature: +//! FuncSignatureT<void, // Return value - void (no return value). +//! uint32_t*, // 1st argument - uint32_t* (machine reg-size). +//! const uint32_t*, // 2nd argument - uint32_t* (machine reg-size). +//! size_t>()); // 3rd argument - size_t (machine reg-size). +//! +//! Label L_Loop = cc.newLabel(); // Start of the loop. +//! Label L_Exit = cc.newLabel(); // Used to exit early. +//! +//! x86::Gp dst = cc.newIntPtr("dst");// Create `dst` register (destination pointer). +//! x86::Gp src = cc.newIntPtr("src");// Create `src` register (source pointer). +//! x86::Gp i = cc.newUIntPtr("i"); // Create `i` register (loop counter). +//! +//! cc.setArg(0, dst); // Assign `dst` argument. +//! cc.setArg(1, src); // Assign `src` argument. +//! cc.setArg(2, i); // Assign `i` argument. +//! +//! cc.test(i, i); // Early exit if length is zero. +//! cc.jz(L_Exit); +//! +//! cc.bind(L_Loop); // Bind the beginning of the loop here. +//! +//! x86::Gp tmp = cc.newInt32("tmp"); // Copy a single dword (4 bytes). +//! cc.mov(tmp, x86::dword_ptr(src)); // Load DWORD from [src] address. +//! cc.mov(x86::dword_ptr(dst), tmp); // Store DWORD to [dst] address. +//! +//! cc.add(src, 4); // Increment `src`. +//! cc.add(dst, 4); // Increment `dst`. +//! +//! cc.dec(i); // Loop until `i` is non-zero. +//! cc.jnz(L_Loop); +//! +//! cc.bind(L_Exit); // Label used by early exit. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! // Add the generated code to the runtime. +//! MemCpy32 memcpy32; +//! Error err = rt.add(&memcpy32, &code); +//! +//! // Handle a possible error returned by AsmJit. +//! if (err) +//! return 1; +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! // Test the generated code. +//! uint32_t input[6] = { 1, 2, 3, 5, 8, 13 }; +//! uint32_t output[6]; +//! memcpy32(output, input, 6); +//! +//! for (uint32_t i = 0; i < 6; i++) +//! printf("%d\n", output[i]); +//! +//! rt.release(memcpy32); +//! return 0; +//! } +//! ``` +//! +//! ### Recursive Functions +//! +//! It's possible to create more functions by using the same \ref x86::Compiler +//! instance and make links between them. In such case it's important to keep +//! the pointer to \ref FuncNode. +//! +//! The example below creates a simple Fibonacci function that calls itself recursively: +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef uint32_t (*Fibonacci)(uint32_t x); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! FuncNode* func = cc.addFunc( // Begin of the Fibonacci function, addFunc() +//! FuncSignatureT<int, int>()); // Returns a pointer to the FuncNode node. +//! +//! Label L_Exit = cc.newLabel() // Exit label. +//! x86::Gp x = cc.newU32(); // Function x argument. +//! x86::Gp y = cc.newU32(); // Temporary. +//! +//! cc.setArg(0, x); +//! +//! cc.cmp(x, 3); // Return x if less than 3. +//! cc.jb(L_Exit); +//! +//! cc.mov(y, x); // Make copy of the original x. +//! cc.dec(x); // Decrease x. +//! +//! InvokeNode* invokeNode; // Function invocation: +//! cc.invoke(&invokeNode, // - InvokeNode (output). +//! func->label(), // - Function address or Label. +//! FuncSignatureT<int, int>()); // - Function signature. +//! +//! invokeNode->setArg(0, x); // Assign x as the first argument. +//! invokeNode->setRet(0, x); // Assign x as a return value as well. +//! +//! cc.add(x, y); // Combine the return value with y. +//! +//! cc.bind(L_Exit); +//! cc.ret(x); // Return x. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Fibonacci fib; +//! Error err = rt.add(&fib, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! // Test the generated code. +//! printf("Fib(%u) -> %u\n", 8, fib(8)); +//! +//! rt.release(fib); +//! return 0; +//! } +//! ``` +//! +//! ### Stack Management +//! +//! Function's stack-frame is managed automatically, which is used by the register allocator to spill virtual registers. It also provides an interface to allocate user-defined block of the stack, which can be used as a temporary storage by the generated function. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values. +//! +//! ``` +//! #include <asmjit/x86.h> +//! #include <stdio.h> +//! +//! using namespace asmjit; +//! +//! // Signature of the generated function. +//! typedef int (*Func)(void); +//! +//! int main() { +//! JitRuntime rt; // Runtime specialized for JIT code execution. +//! CodeHolder code; // Holds code and relocation information. +//! +//! code.init(rt.environment()); // Initialize code to match the JIT environment. +//! x86::Compiler cc(&code); // Create and attach x86::Compiler to code. +//! +//! cc.addFunc(FuncSignatureT<int>());// Create a function that returns int. +//! +//! x86::Gp p = cc.newIntPtr("p"); +//! x86::Gp i = cc.newIntPtr("i"); +//! +//! // Allocate 256 bytes on the stack aligned to 4 bytes. +//! x86::Mem stack = cc.newStack(256, 4); +//! +//! x86::Mem stackIdx(stack); // Copy of stack with i added. +//! stackIdx.setIndex(i); // stackIdx <- stack[i]. +//! stackIdx.setSize(1); // stackIdx <- byte ptr stack[i]. +//! +//! // Load a stack address to `p`. This step is purely optional and shows +//! // that `lea` is useful to load a memory operands address (even absolute) +//! // to a general purpose register. +//! cc.lea(p, stack); +//! +//! // Clear i (xor is a C++ keyword, hence 'xor_' is used instead). +//! cc.xor_(i, i); +//! +//! Label L1 = cc.newLabel(); +//! Label L2 = cc.newLabel(); +//! +//! cc.bind(L1); // First loop, fill the stack. +//! cc.mov(stackIdx, i.r8()); // stack[i] = uint8_t(i). +//! +//! cc.inc(i); // i++; +//! cc.cmp(i, 256); // if (i < 256) +//! cc.jb(L1); // goto L1; +//! +//! // Second loop, sum all bytes stored in `stack`. +//! x86::Gp sum = cc.newI32("sum"); +//! x86::Gp val = cc.newI32("val"); +//! +//! cc.xor_(i, i); +//! cc.xor_(sum, sum); +//! +//! cc.bind(L2); +//! +//! cc.movzx(val, stackIdx); // val = uint32_t(stack[i]); +//! cc.add(sum, val); // sum += val; +//! +//! cc.inc(i); // i++; +//! cc.cmp(i, 256); // if (i < 256) +//! cc.jb(L2); // goto L2; +//! +//! cc.ret(sum); // Return the `sum` of all values. +//! cc.endFunc(); // End of the function body. +//! +//! cc.finalize(); // Translate and assemble the whole 'cc' content. +//! // ----> x86::Compiler is no longer needed from here and can be destroyed <---- +//! +//! Func func; +//! Error err = rt.add(&func, &code); // Add the generated code to the runtime. +//! if (err) return 1; // Handle a possible error returned by AsmJit. +//! // ----> CodeHolder is no longer needed from here and can be destroyed <---- +//! +//! printf("Func() -> %d\n", func()); // Test the generated code. +//! +//! rt.release(func); +//! return 0; +//! } +//! ``` +//! +//! ### Constant Pool +//! +//! Compiler provides two constant pools for a general purpose code generation: +//! +//! - Local constant pool - Part of \ref FuncNode, can be only used by a +//! single function and added after the function epilog sequence (after +//! `ret` instruction). +//! +//! - Global constant pool - Part of \ref BaseCompiler, flushed at the end +//! of the generated code by \ref BaseEmitter::finalize(). +//! +//! The example below illustrates how a built-in constant pool can be used: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void exampleUseOfConstPool(x86::Compiler& cc) { +//! cc.addFunc(FuncSignatureT<int>()); +//! +//! x86::Gp v0 = cc.newGpd("v0"); +//! x86::Gp v1 = cc.newGpd("v1"); +//! +//! x86::Mem c0 = cc.newInt32Const(ConstPool::kScopeLocal, 200); +//! x86::Mem c1 = cc.newInt32Const(ConstPool::kScopeLocal, 33); +//! +//! cc.mov(v0, c0); +//! cc.mov(v1, c1); +//! cc.add(v0, v1); +//! +//! cc.ret(v0); +//! cc.endFunc(); +//! } +//! ``` +//! +//! ### Jump Tables +//! +//! x86::Compiler supports `jmp` instruction with reg/mem operand, which is a +//! commonly used pattern to implement indirect jumps within a function, for +//! example to implement `switch()` statement in a programming languages. By +//! default AsmJit assumes that every basic block can be a possible jump +//! target as it's unable to deduce targets from instruction's operands. This +//! is a very pessimistic default that should be avoided if possible as it's +//! costly and very unfriendly to liveness analysis and register allocation. +//! +//! Instead of relying on such pessimistic default behavior, let's use \ref +//! JumpAnnotation to annotate a jump where all targets are known: +//! +//! ``` +//! #include <asmjit/x86.h> +//! +//! using namespace asmjit; +//! +//! static void exampleUseOfIndirectJump(x86::Compiler& cc) { +//! cc.addFunc(FuncSignatureT<float, float, float, uint32_t>(CallConv::kIdHost)); +//! +//! // Function arguments +//! x86::Xmm a = cc.newXmmSs("a"); +//! x86::Xmm b = cc.newXmmSs("b"); +//! x86::Gp op = cc.newUInt32("op"); +//! +//! x86::Gp target = cc.newIntPtr("target"); +//! x86::Gp offset = cc.newIntPtr("offset"); +//! +//! Label L_Table = cc.newLabel(); +//! Label L_Add = cc.newLabel(); +//! Label L_Sub = cc.newLabel(); +//! Label L_Mul = cc.newLabel(); +//! Label L_Div = cc.newLabel(); +//! Label L_End = cc.newLabel(); +//! +//! cc.setArg(0, a); +//! cc.setArg(1, b); +//! cc.setArg(2, op); +//! +//! // Jump annotation is a building block that allows to annotate all +//! // possible targets where `jmp()` can jump. It then drives the CFG +//! // contruction and liveness analysis, which impacts register allocation. +//! JumpAnnotation* annotation = cc.newJumpAnnotation(); +//! annotation->addLabel(L_Add); +//! annotation->addLabel(L_Sub); +//! annotation->addLabel(L_Mul); +//! annotation->addLabel(L_Div); +//! +//! // Most likely not the common indirect jump approach, but it +//! // doesn't really matter how final address is calculated. The +//! // most important path using JumpAnnotation with `jmp()`. +//! cc.lea(offset, x86::ptr(L_Table)); +//! if (cc.is64Bit()) +//! cc.movsxd(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); +//! else +//! cc.mov(target, x86::dword_ptr(offset, op.cloneAs(offset), 2)); +//! cc.add(target, offset); +//! cc.jmp(target, annotation); +//! +//! // Acts like a switch() statement in C. +//! cc.bind(L_Add); +//! cc.addss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Sub); +//! cc.subss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Mul); +//! cc.mulss(a, b); +//! cc.jmp(L_End); +//! +//! cc.bind(L_Div); +//! cc.divss(a, b); +//! +//! cc.bind(L_End); +//! cc.ret(a); +//! +//! cc.endFunc(); +//! +//! // Relative int32_t offsets of `L_XXX - L_Table`. +//! cc.bind(L_Table); +//! cc.embedLabelDelta(L_Add, L_Table, 4); +//! cc.embedLabelDelta(L_Sub, L_Table, 4); +//! cc.embedLabelDelta(L_Mul, L_Table, 4); +//! cc.embedLabelDelta(L_Div, L_Table, 4); +//! } +//! ``` class ASMJIT_VIRTAPI Compiler : public BaseCompiler, public EmitterExplicitT<Compiler> { @@ -62,18 +468,18 @@ public: #ifndef ASMJIT_NO_LOGGING # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ - _newRegFmt(OUT, PARAM, FORMAT, ARGS) + _newRegFmt(&OUT, PARAM, FORMAT, ARGS) #else # define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ DebugUtils::unused(FORMAT); \ DebugUtils::unused(std::forward<Args>(args)...); \ - _newReg(OUT, PARAM) + _newReg(&OUT, PARAM) #endif #define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \ inline REG FUNC(uint32_t typeId) { \ REG reg(Globals::NoInit); \ - _newReg(reg, typeId); \ + _newReg(®, typeId); \ return reg; \ } \ \ @@ -87,7 +493,7 @@ public: #define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \ inline REG FUNC() { \ REG reg(Globals::NoInit); \ - _newReg(reg, TYPE_ID); \ + _newReg(®, TYPE_ID); \ return reg; \ } \ \ @@ -170,7 +576,7 @@ public: //! Creates a new memory chunk allocated on the current function's stack. inline Mem newStack(uint32_t size, uint32_t alignment, const char* name = nullptr) { Mem m(Globals::NoInit); - _newStack(m, size, alignment, name); + _newStack(&m, size, alignment, name); return m; } @@ -182,7 +588,7 @@ public: //! Put data to a constant-pool and get a memory reference to it. inline Mem newConst(uint32_t scope, const void* data, size_t size) { Mem m(Globals::NoInit); - _newConst(m, scope, data, size); + _newConst(&m, scope, data, size); return m; } @@ -213,12 +619,16 @@ public: //! Put a DP-FP `val` to a constant-pool. inline Mem newDoubleConst(uint32_t scope, double val) noexcept { return newConst(scope, &val, 8); } - //! Put a MMX `val` to a constant-pool. +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("newMmConst() uses a deprecated Data64, use newConst() with your own data instead") inline Mem newMmConst(uint32_t scope, const Data64& val) noexcept { return newConst(scope, &val, 8); } - //! Put a XMM `val` to a constant-pool. + + ASMJIT_DEPRECATED("newXmmConst() uses a deprecated Data128, use newConst() with your own data instead") inline Mem newXmmConst(uint32_t scope, const Data128& val) noexcept { return newConst(scope, &val, 16); } - //! Put a YMM `val` to a constant-pool. + + ASMJIT_DEPRECATED("newYmmConst() uses a deprecated Data256, use newConst() with your own data instead") inline Mem newYmmConst(uint32_t scope, const Data256& val) noexcept { return newConst(scope, &val, 32); } +#endif // !ASMJIT_NO_DEPRECATED //! \} @@ -235,16 +645,37 @@ public: //! \name Function Call & Ret Intrinsics //! \{ - //! Call a function. - inline FuncCallNode* call(const Gp& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + //! Invoke a function call without `target` type enforcement. + inline Error invoke_(InvokeNode** out, const Operand_& target, const FuncSignature& signature) { + return _addInvokeNode(out, Inst::kIdCall, target, signature); + } + + //! Invoke a function call of the given `target` and `signature` and store + //! the added node to `out`. + //! + //! Creates a new \ref InvokeNode, initializes all the necessary members to + //! match the given function `signature`, adds the node to the compiler, and + //! stores its pointer to `out`. The operation is atomic, if anything fails + //! nullptr is stored in `out` and error code is returned. + inline Error invoke(InvokeNode** out, const Gp& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Mem& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Mem& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Label& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Label& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(const Imm& target, const FuncSignature& sign) { return addCall(Inst::kIdCall, target, sign); } + inline Error invoke(InvokeNode** out, const Imm& target, const FuncSignature& signature) { return invoke_(out, target, signature); } //! \overload - inline FuncCallNode* call(uint64_t target, const FuncSignature& sign) { return addCall(Inst::kIdCall, Imm(int64_t(target)), sign); } + inline Error invoke(InvokeNode** out, uint64_t target, const FuncSignature& signature) { return invoke_(out, Imm(int64_t(target)), signature); } + +#ifndef _DOXYGEN + template<typename Target> + ASMJIT_DEPRECATED("Use invoke() instead of call()") + inline InvokeNode* call(const Target& target, const FuncSignature& signature) { + InvokeNode* invokeNode; + invoke(&invokeNode, target, signature); + return invokeNode; + } +#endif //! Return. inline FuncRetNode* ret() { return addRet(Operand(), Operand()); } @@ -260,7 +691,9 @@ public: using EmitterExplicitT<Compiler>::jmp; + //! Adds a jump to the given `target` with the provided jump `annotation`. inline Error jmp(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); } + //! \overload inline Error jmp(const BaseMem& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdJmp, target, annotation); } //! \} diff --git a/3rdparty/asmjit/src/asmjit/x86/x86emitter.h b/3rdparty/asmjit/src/asmjit/x86/x86emitter.h index cfd96a18809..561acdd6000 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86emitter.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86emitter.h @@ -39,10 +39,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_1i(NAME, ID, T0) \ inline Error NAME(const T0& o0) { return _emitter()->emit(Inst::kId##ID, o0); } \ + /** \cond */ \ inline Error NAME(int o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ inline Error NAME(unsigned int o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ inline Error NAME(int64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ - inline Error NAME(uint64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } + inline Error NAME(uint64_t o0) { return _emitter()->emit(Inst::kId##ID, Support::asInt(o0)); } \ + /** \endcond */ #define ASMJIT_INST_1c(NAME, ID, CONV, T0) \ inline Error NAME(uint32_t cc, const T0& o0) { return _emitter()->emit(CONV(cc), o0); } \ @@ -82,10 +84,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_2i(NAME, ID, T0, T1) \ inline Error NAME(const T0& o0, const T1& o1) { return _emitter()->emit(Inst::kId##ID, o0, o1); } \ + /** \cond */ \ inline Error NAME(const T0& o0, int o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ inline Error NAME(const T0& o0, unsigned int o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ inline Error NAME(const T0& o0, int64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ - inline Error NAME(const T0& o0, uint64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } + inline Error NAME(const T0& o0, uint64_t o1) { return _emitter()->emit(Inst::kId##ID, o0, Support::asInt(o1)); } \ + /** \endcond */ #define ASMJIT_INST_2c(NAME, ID, CONV, T0, T1) \ inline Error NAME(uint32_t cc, const T0& o0, const T1& o1) { return _emitter()->emit(CONV(cc), o0, o1); } \ @@ -125,10 +129,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_3i(NAME, ID, T0, T1, T2) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, int o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ inline Error NAME(const T0& o0, const T1& o1, unsigned int o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ inline Error NAME(const T0& o0, const T1& o1, int64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ - inline Error NAME(const T0& o0, const T1& o1, uint64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } + inline Error NAME(const T0& o0, const T1& o1, uint64_t o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, Support::asInt(o2)); } \ + /** \endcond */ #define ASMJIT_INST_3ii(NAME, ID, T0, T1, T2) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2); } \ @@ -139,10 +145,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_4i(NAME, ID, T0, T1, T2, T3) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, int o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, unsigned int o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, int64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ - inline Error NAME(const T0& o0, const T1& o1, const T2& o2, uint64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } + inline Error NAME(const T0& o0, const T1& o1, const T2& o2, uint64_t o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, Support::asInt(o3)); } \ + /** \endcond */ #define ASMJIT_INST_4ii(NAME, ID, T0, T1, T2, T3) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3); } \ @@ -153,10 +161,12 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) #define ASMJIT_INST_5i(NAME, ID, T0, T1, T2, T3, T4) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, const T4& o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, o4); } \ + /** \cond */ \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, int o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, unsigned int o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, int64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ - inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, uint64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } + inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, uint64_t o4) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, Support::asInt(o4)); } \ + /** \endcond */ #define ASMJIT_INST_6x(NAME, ID, T0, T1, T2, T3, T4, T5) \ inline Error NAME(const T0& o0, const T1& o1, const T2& o2, const T3& o3, const T4& o4, const T5& o5) { return _emitter()->emit(Inst::kId##ID, o0, o1, o2, o3, o4, o5); } @@ -244,57 +254,57 @@ struct EmitterExplicitT { //! Creates an `intptr_t` memory operand depending on the current architecture. inline Mem intptr_ptr(const Gp& base, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, const Gp& index, uint32_t shift, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Label& base, const Vec& index, uint32_t shift, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(const Rip& rip, int32_t offset = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(rip, offset, nativeGpSize); } //! \overload inline Mem intptr_ptr(uint64_t base) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, nativeGpSize); } //! \overload inline Mem intptr_ptr(uint64_t base, const Gp& index, uint32_t shift = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, nativeGpSize); } //! \overload inline Mem intptr_ptr_abs(uint64_t base) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, nativeGpSize, BaseMem::kSignatureMemAbs); } //! \overload inline Mem intptr_ptr_abs(uint64_t base, const Gp& index, uint32_t shift = 0) const noexcept { - uint32_t nativeGpSize = _emitter()->gpSize(); + uint32_t nativeGpSize = _emitter()->registerSize(); return Mem(base, index, shift, nativeGpSize, BaseMem::kSignatureMemAbs); } @@ -303,46 +313,55 @@ struct EmitterExplicitT { //! \name Embed //! \{ - //! Adds 8-bit integer data to the CodeBuffer. - inline Error db(uint8_t x) { return _emitter()->embed(&x, 1); } - //! Adds 16-bit integer data to the CodeBuffer. - inline Error dw(uint16_t x) { return _emitter()->embed(&x, 2); } - //! Adds 32-bit integer data to the CodeBuffer. - inline Error dd(uint32_t x) { return _emitter()->embed(&x, 4); } - //! Adds 64-bit integer data to the CodeBuffer. - inline Error dq(uint64_t x) { return _emitter()->embed(&x, 8); } - - //! Adds 8-bit integer data to the CodeBuffer. + //! Embeds 8-bit integer data. + inline Error db(uint8_t x, size_t repeatCount = 1) { return _emitter()->embedUInt8(x, repeatCount); } + //! Embeds 16-bit integer data. + inline Error dw(uint16_t x, size_t repeatCount = 1) { return _emitter()->embedUInt16(x, repeatCount); } + //! Embeds 32-bit integer data. + inline Error dd(uint32_t x, size_t repeatCount = 1) { return _emitter()->embedUInt32(x, repeatCount); } + //! Embeds 64-bit integer data. + inline Error dq(uint64_t x, size_t repeatCount = 1) { return _emitter()->embedUInt64(x, repeatCount); } + +#ifndef ASMJIT_NO_DEPRECATED + ASMJIT_DEPRECATED("Use embedInt8() instead of dint8()") inline Error dint8(int8_t x) { return _emitter()->embed(&x, sizeof(int8_t)); } - //! Adds 8-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt8() instead of duint8()") inline Error duint8(uint8_t x) { return _emitter()->embed(&x, sizeof(uint8_t)); } - //! Adds 16-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt16() instead of dint16()") inline Error dint16(int16_t x) { return _emitter()->embed(&x, sizeof(int16_t)); } - //! Adds 16-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt16() instead of duint16()") inline Error duint16(uint16_t x) { return _emitter()->embed(&x, sizeof(uint16_t)); } - //! Adds 32-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt32() instead of dint32()") inline Error dint32(int32_t x) { return _emitter()->embed(&x, sizeof(int32_t)); } - //! Adds 32-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt32() instead of duint32()") inline Error duint32(uint32_t x) { return _emitter()->embed(&x, sizeof(uint32_t)); } - //! Adds 64-bit integer data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedInt64() instead of dint64()") inline Error dint64(int64_t x) { return _emitter()->embed(&x, sizeof(int64_t)); } - //! Adds 64-bit integer data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedUInt64() instead of duint64()") inline Error duint64(uint64_t x) { return _emitter()->embed(&x, sizeof(uint64_t)); } - //! Adds float data to the CodeBuffer. + ASMJIT_DEPRECATED("Use embedFloat() instead of float()") inline Error dfloat(float x) { return _emitter()->embed(&x, sizeof(float)); } - //! Adds double data to the CodeBuffer. + + ASMJIT_DEPRECATED("Use embedDouble() instead of ddouble()") inline Error ddouble(double x) { return _emitter()->embed(&x, sizeof(double)); } - //! Adds MMX data to the CodeBuffer. - inline Error dmm(const Data64& x) { return _emitter()->embed(&x, sizeof(Data64)); } - //! Adds XMM data to the CodeBuffer. - inline Error dxmm(const Data128& x) { return _emitter()->embed(&x, sizeof(Data128)); } - //! Adds YMM data to the CodeBuffer. - inline Error dymm(const Data256& x) { return _emitter()->embed(&x, sizeof(Data256)); } + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dmm()") + inline Error dmm(const Data64& x) { return _emitter()->embed(&x, 8); } + + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dxmm()") + inline Error dxmm(const Data128& x) { return _emitter()->embed(&x, 16); } + + ASMJIT_DEPRECATED("Use embed[U]IntN() or embed[Float|Double]() instead of dymm()") + inline Error dymm(const Data256& x) { return _emitter()->embed(&x, 32); } +#endif // !ASMJIT_NO_DEPRECATED //! Adds data in a given structure instance to the CodeBuffer. template<typename T> @@ -2025,203 +2044,90 @@ public: ASMJIT_INST_6x(v4fmaddss, V4fmaddss, Xmm, Xmm, Xmm, Xmm, Xmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(v4fnmaddps, V4fnmaddps, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(v4fnmaddss, V4fnmaddss, Xmm, Xmm, Xmm, Xmm, Xmm, Mem) // AVX512_4FMAPS{kz} - ASMJIT_INST_3x(vaddpd, Vaddpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vaddpd, Vaddpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vaddpd, Vaddpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vaddps, Vaddps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vaddps, Vaddps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vaddps, Vaddps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vaddpd, Vaddpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vaddpd, Vaddpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vaddps, Vaddps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vaddps, Vaddps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vaddsd, Vaddsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddsd, Vaddsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddss, Vaddss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vaddss, Vaddss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vaddsubps, Vaddsubps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesdec, Vaesdec, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdec, Vaesdec, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdec, Vaesdec, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesdec, Vaesdec, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesenc, Vaesenc, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesenc, Vaesenc, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesenc, Vaesenc, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenc, Vaesenc, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenc, Vaesenc, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesenc, Vaesenc, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Ymm, Ymm, Ymm) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Ymm, Ymm, Mem) // VAES AVX512_VL - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Zmm, Zmm, Zmm) // VAES - ASMJIT_INST_3x(vaesenclast, Vaesenclast, Zmm, Zmm, Mem) // VAES - ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Mem) // AVX - ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(valignd, Valignd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(valignd, Valignd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(valignd, Valignd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(valignq, Valignq, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(valignq, Valignq, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(valignq, Valignq, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vandnpd, Vandnpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandnpd, Vandnpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandnpd, Vandnpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandnps, Vandnps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandnps, Vandnps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandnps, Vandnps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandpd, Vandpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vandpd, Vandpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandpd, Vandpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vandps, Vandps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vandps, Vandps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vandps, Vandps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vblendmb, Vblendmb, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmb, Vblendmb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmb, Vblendmb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmd, Vblendmd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmd, Vblendmd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmd, Vblendmd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmpd, Vblendmpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmps, Vblendmps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vblendmps, Vblendmps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmps, Vblendmps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vblendmq, Vblendmq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vblendmq, Vblendmq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmq, Vblendmq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vblendmw, Vblendmw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vblendmw, Vblendmw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vblendmw, Vblendmw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vblendpd, Vblendpd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vblendpd, Vblendpd, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vblendps, Vblendps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Ymm, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_4x(vblendvpd, Vblendvpd, Ymm, Ymm, Mem, Ymm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Ymm, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_4x(vblendvps, Vblendvps, Ymm, Ymm, Mem, Ymm) // AVX - ASMJIT_INST_2x(vbroadcastf128, Vbroadcastf128, Ymm, Mem) // AVX - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Ymm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastf32x8, Vbroadcastf32x8, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcastf64x4, Vbroadcastf64x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti128, Vbroadcasti128, Ymm, Mem) // AVX2 - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Xmm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Xmm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti32x8, Vbroadcasti32x8, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Ymm, Xmm) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Ymm, Mem) // AVX512_DQ{kz}-VL - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Zmm, Xmm) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Zmm, Mem) // AVX512_DQ{kz} - ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Ymm, Mem) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Ymm, Xmm) // AVX2 AVX512_F{kz} - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Zmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Zmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vcmpps, Vcmpps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vaddsubpd, Vaddsubpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vaddsubps, Vaddsubps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vaddsubps, Vaddsubps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vaesdec, Vaesdec, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdec, Vaesdec, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesdeclast, Vaesdeclast, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenc, Vaesenc, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenc, Vaesenc, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenclast, Vaesenclast, Vec, Vec, Vec) // AVX+AESNI VAES + ASMJIT_INST_3x(vaesenclast, Vaesenclast, Vec, Vec, Mem) // AVX+AESNI VAES + ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Xmm) // AVX+AESNI + ASMJIT_INST_2x(vaesimc, Vaesimc, Xmm, Mem) // AVX+AESNI + ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Xmm, Imm) // AVX+AESNI + ASMJIT_INST_3i(vaeskeygenassist, Vaeskeygenassist, Xmm, Mem, Imm) // AVX+AESNI + ASMJIT_INST_4i(valignd, Valignd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(valignd, Valignd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(valignq, Valignq, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(valignq, Valignq, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vandnpd, Vandnpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandnpd, Vandnpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandnps, Vandnps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandnps, Vandnps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandpd, Vandpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandpd, Vandpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vandps, Vandps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vandps, Vandps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vblendmb, Vblendmb, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmb, Vblendmb, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmd, Vblendmd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmd, Vblendmd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmpd, Vblendmpd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmpd, Vblendmpd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmps, Vblendmps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmps, Vblendmps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vblendmq, Vblendmq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmq, Vblendmq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vblendmw, Vblendmw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vblendmw, Vblendmw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_4i(vblendpd, Vblendpd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vblendpd, Vblendpd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vblendps, Vblendps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vblendps, Vblendps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4x(vblendvpd, Vblendvpd, Vec, Vec, Vec, Vec) // AVX + ASMJIT_INST_4x(vblendvpd, Vblendvpd, Vec, Vec, Mem, Vec) // AVX + ASMJIT_INST_4x(vblendvps, Vblendvps, Vec, Vec, Vec, Vec) // AVX + ASMJIT_INST_4x(vblendvps, Vblendvps, Vec, Vec, Mem, Vec) // AVX + ASMJIT_INST_2x(vbroadcastf128, Vbroadcastf128, Vec, Mem) // AVX + ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf32x2, Vbroadcastf32x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf32x4, Vbroadcastf32x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastf32x8, Vbroadcastf32x8, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf64x2, Vbroadcastf64x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcastf64x4, Vbroadcastf64x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti128, Vbroadcasti128, Vec, Mem) // AVX2 + ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti32x2, Vbroadcasti32x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti32x4, Vbroadcasti32x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti32x8, Vbroadcasti32x8, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Vec, Vec) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x2, Vbroadcasti64x2, Vec, Mem) // AVX512_DQ{kz} + ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcasti64x4, Vbroadcasti64x4, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastsd, Vbroadcastsd, Vec, Xmm) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vbroadcastss, Vbroadcastss, Vec, Xmm) // AVX2 AVX512_F{kz} + ASMJIT_INST_4i(vcmppd, Vcmppd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vcmppd, Vcmppd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vcmppd, Vcmppd, KReg, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vcmpps, Vcmpps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vcmpps, Vcmpps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vcmpps, Vcmpps, KReg, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vcmpsd, Vcmpsd, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vcmpsd, Vcmpsd, Xmm, Xmm, Mem, Imm) // AVX ASMJIT_INST_4i(vcmpsd, Vcmpsd, KReg, Xmm, Xmm, Imm) // AVX512_F{kz|sae} @@ -2234,121 +2140,46 @@ public: ASMJIT_INST_2x(vcomisd, Vcomisd, Xmm, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcomiss, Vcomiss, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcomiss, Vcomiss, Xmm, Mem) // AVX AVX512_F{sae} - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompressps, Vcompressps, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vcompressps, Vcompressps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Ymm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Zmm, Ymm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Xmm, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Xmm, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Ymm, Ymm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Ymm, Ymm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Zmm, Zmm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Zmm, Zmm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Ymm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Ymm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Xmm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Ymm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Ymm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Xmm, Xmm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Xmm, Mem) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Ymm, Xmm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Ymm, Mem) // F16C AVX512_F{kz}-VL - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Zmm, Ymm) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Zmm, Mem) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Ymm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Zmm, Ymm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Xmm, Xmm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Xmm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Xmm, Ymm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Ymm, Imm) // F16C AVX512_F{kz}-VL - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Ymm, Zmm, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Zmm, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Zmm, Ymm) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Zmm, Mem) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Zmm, Ymm) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Zmm, Mem) // AVX512_DQ{kz|er|b32} - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Xmm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Ymm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Ymm, Mem) // AVX512_DQ{kz|er|b64} + ASMJIT_INST_2x(vcompresspd, Vcompresspd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompresspd, Vcompresspd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompressps, Vcompressps, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcompressps, Vcompressps, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2pd, Vcvtdq2pd, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtdq2ps, Vcvtdq2ps, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Vec, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_3x(vcvtne2ps2bf16, Vcvtne2ps2bf16, Vec, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtneps2bf16, Vcvtneps2bf16, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2dq, Vcvtpd2dq, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2ps, Vcvtpd2ps, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2qq, Vcvtpd2qq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2udq, Vcvtpd2udq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtpd2uqq, Vcvtpd2uqq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Vec, Vec) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtph2ps, Vcvtph2ps, Vec, Mem) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2dq, Vcvtps2dq, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2pd, Vcvtps2pd, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Vec, Vec, Imm) // F16C AVX512_F{kz} + ASMJIT_INST_3i(vcvtps2ph, Vcvtps2ph, Mem, Vec, Imm) // F16C AVX512_F{kz} + ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2qq, Vcvtps2qq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2udq, Vcvtps2udq, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtps2uqq, Vcvtps2uqq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2pd, Vcvtqq2pd, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtqq2ps, Vcvtqq2ps, Vec, Mem) // AVX512_DQ{kz|b64} ASMJIT_INST_2x(vcvtsd2si, Vcvtsd2si, Gp, Xmm) // AVX AVX512_F{er} ASMJIT_INST_2x(vcvtsd2si, Vcvtsd2si, Gp, Mem) // AVX AVX512_F{er} ASMJIT_INST_3x(vcvtsd2ss, Vcvtsd2ss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} @@ -2365,52 +2196,22 @@ public: ASMJIT_INST_2x(vcvtss2si, Vcvtss2si, Gp, Mem) // AVX AVX512_F{er} ASMJIT_INST_2x(vcvtss2usi, Vcvtss2usi, Gp, Xmm) // AVX512_F{er} ASMJIT_INST_2x(vcvtss2usi, Vcvtss2usi, Gp, Mem) // AVX512_F{er} - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Xmm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Ymm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Ymm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Xmm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Ymm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Ymm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Zmm, Zmm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Zmm, Mem) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Zmm, Ymm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Zmm, Mem) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Xmm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Xmm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Ymm, Xmm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Ymm, Mem) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Zmm, Ymm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Zmm, Mem) // AVX512_DQ{kz|sae|b32} + ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2dq, Vcvttpd2dq, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2qq, Vcvttpd2qq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2udq, Vcvttpd2udq, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvttpd2uqq, Vcvttpd2uqq, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2dq, Vcvttps2dq, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2qq, Vcvttps2qq, Vec, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2udq, Vcvttps2udq, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Vec, Vec) // AVX512_DQ{kz|b32} + ASMJIT_INST_2x(vcvttps2uqq, Vcvttps2uqq, Vec, Mem) // AVX512_DQ{kz|b32} ASMJIT_INST_2x(vcvttsd2si, Vcvttsd2si, Gp, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttsd2si, Vcvttsd2si, Gp, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttsd2usi, Vcvttsd2usi, Gp, Xmm) // AVX512_F{sae} @@ -2419,415 +2220,204 @@ public: ASMJIT_INST_2x(vcvttss2si, Vcvttss2si, Gp, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vcvttss2usi, Vcvttss2usi, Gp, Xmm) // AVX512_F{sae} ASMJIT_INST_2x(vcvttss2usi, Vcvttss2usi, Gp, Mem) // AVX512_F{sae} - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Ymm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Zmm, Ymm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Zmm, Mem) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Zmm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Zmm, Mem) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Xmm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Ymm, Zmm) // AVX512_DQ{kz|er|b64} - ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Ymm, Mem) // AVX512_DQ{kz|er|b64} + ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2pd, Vcvtudq2pd, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtudq2ps, Vcvtudq2ps, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2pd, Vcvtuqq2pd, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_2x(vcvtuqq2ps, Vcvtuqq2ps, Vec, Mem) // AVX512_DQ{kz|b64} ASMJIT_INST_3x(vcvtusi2sd, Vcvtusi2sd, Xmm, Xmm, Gp) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2sd, Vcvtusi2sd, Xmm, Xmm, Mem) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2ss, Vcvtusi2ss, Xmm, Xmm, Gp) // AVX512_F{er} ASMJIT_INST_3x(vcvtusi2ss, Vcvtusi2ss, Xmm, Xmm, Mem) // AVX512_F{er} - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Xmm, Xmm, Xmm, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Xmm, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Ymm, Ymm, Ymm, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Ymm, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Zmm, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Zmm, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vdivpd, Vdivpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vdivpd, Vdivpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vdivpd, Vdivpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vdivps, Vdivps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vdivps, Vdivps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vdivps, Vdivps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Vec, Vec, Vec, Imm) // AVX512_BW{kz} + ASMJIT_INST_4i(vdbpsadbw, Vdbpsadbw, Vec, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3x(vdivpd, Vdivpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vdivpd, Vdivpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vdivps, Vdivps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vdivps, Vdivps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vdivsd, Vdivsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivsd, Vdivsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivss, Vdivss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vdivss, Vdivss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Xmm, Xmm, Xmm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Xmm, Xmm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Ymm, Ymm, Ymm) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Ymm, Ymm, Mem) // AVX512_BF16{kz|b32}-VL - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Zmm, Zmm, Zmm) // AVX512_BF16{kz|b32} - ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Zmm, Zmm, Mem) // AVX512_BF16{kz|b32} - ASMJIT_INST_4i(vdppd, Vdppd, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vdppd, Vdppd, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vdpps, Vdpps, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_2x(vexp2pd, Vexp2pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vexp2pd, Vexp2pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vexp2ps, Vexp2ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vexp2ps, Vexp2ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandpd, Vexpandpd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandps, Vexpandps, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vexpandps, Vexpandps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vexpandps, Vexpandps, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf128, Vextractf128, Xmm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vextractf128, Vextractf128, Mem, Ymm, Imm) // AVX - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Xmm, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Xmm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Ymm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Xmm, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Xmm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Ymm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti128, Vextracti128, Xmm, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vextracti128, Vextracti128, Mem, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Xmm, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Ymm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Xmm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Ymm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Xmm, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Ymm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Xmm, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Zmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Ymm, Zmm, Imm) // AVX512_F{kz} - ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Mem, Zmm, Imm) // AVX512_F{kz} + ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Vec, Vec, Vec) // AVX512_BF16{kz|b32} + ASMJIT_INST_3x(vdpbf16ps, Vdpbf16ps, Vec, Vec, Mem) // AVX512_BF16{kz|b32} + ASMJIT_INST_4i(vdppd, Vdppd, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vdppd, Vdppd, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vdpps, Vdpps, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vdpps, Vdpps, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_2x(vexp2pd, Vexp2pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vexp2pd, Vexp2pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vexp2ps, Vexp2ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vexp2ps, Vexp2ps, Vec, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vexpandpd, Vexpandpd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandpd, Vexpandpd, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandps, Vexpandps, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vexpandps, Vexpandps, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf128, Vextractf128, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vextractf128, Vextractf128, Mem, Vec, Imm) // AVX + ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf32x4, Vextractf32x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf32x8, Vextractf32x8, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x2, Vextractf64x2, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextractf64x4, Vextractf64x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti128, Vextracti128, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vextracti128, Vextracti128, Mem, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti32x4, Vextracti32x4, Mem, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti32x8, Vextracti32x8, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x2, Vextracti64x2, Mem, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_3i(vextracti64x4, Vextracti64x4, Mem, Vec, Imm) // AVX512_F{kz} ASMJIT_INST_3i(vextractps, Vextractps, Gp, Xmm, Imm) // AVX AVX512_F ASMJIT_INST_3i(vextractps, Vextractps, Mem, Xmm, Imm) // AVX AVX512_F - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vfixupimmpd, Vfixupimmpd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vfixupimmps, Vfixupimmps, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vfixupimmsd, Vfixupimmsd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmsd, Vfixupimmsd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmss, Vfixupimmss, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vfixupimmss, Vfixupimmss, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd132pd, Vfmadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd132ps, Vfmadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd132sd, Vfmadd132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132sd, Vfmadd132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132ss, Vfmadd132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd132ss, Vfmadd132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd213pd, Vfmadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd213ps, Vfmadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd213sd, Vfmadd213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213sd, Vfmadd213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213ss, Vfmadd213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd213ss, Vfmadd213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd231pd, Vfmadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmadd231ps, Vfmadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmadd231sd, Vfmadd231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231sd, Vfmadd231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231ss, Vfmadd231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmadd231ss, Vfmadd231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub132pd, Vfmaddsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub132ps, Vfmaddsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub213pd, Vfmaddsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub213ps, Vfmaddsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub231pd, Vfmaddsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmaddsub231ps, Vfmaddsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub132pd, Vfmsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub132ps, Vfmsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub132sd, Vfmsub132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132sd, Vfmsub132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132ss, Vfmsub132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub132ss, Vfmsub132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub213pd, Vfmsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub213ps, Vfmsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub213sd, Vfmsub213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213sd, Vfmsub213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213ss, Vfmsub213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub213ss, Vfmsub213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub231pd, Vfmsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsub231ps, Vfmsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfmsub231sd, Vfmsub231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231sd, Vfmsub231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231ss, Vfmsub231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfmsub231ss, Vfmsub231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd132pd, Vfmsubadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd132ps, Vfmsubadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd213pd, Vfmsubadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd213ps, Vfmsubadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd231pd, Vfmsubadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfmsubadd231ps, Vfmsubadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd132pd, Vfnmadd132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd132ps, Vfnmadd132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd132sd, Vfnmadd132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132sd, Vfnmadd132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132ss, Vfnmadd132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd132ss, Vfnmadd132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd213pd, Vfnmadd213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd213ps, Vfnmadd213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd213sd, Vfnmadd213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213sd, Vfnmadd213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213ss, Vfnmadd213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd213ss, Vfnmadd213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd231pd, Vfnmadd231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmadd231ps, Vfnmadd231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmadd231sd, Vfnmadd231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231sd, Vfnmadd231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231ss, Vfnmadd231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmadd231ss, Vfnmadd231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub132pd, Vfnmsub132pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub132ps, Vfnmsub132ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub132sd, Vfnmsub132sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132sd, Vfnmsub132sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132ss, Vfnmsub132ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub132ss, Vfnmsub132ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub213pd, Vfnmsub213pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub213ps, Vfnmsub213ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub213sd, Vfnmsub213sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213sd, Vfnmsub213sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213ss, Vfnmsub213ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub213ss, Vfnmsub213ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Xmm, Xmm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Ymm, Ymm, Ymm) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Ymm, Ymm, Mem) // FMA AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Zmm, Zmm, Zmm) // FMA AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Zmm, Zmm, Mem) // FMA AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Vec, Vec, Vec) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub231pd, Vfnmsub231pd, Vec, Vec, Mem) // FMA AVX512_F{kz|b64} + ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Vec, Vec, Vec) // FMA AVX512_F{kz|b32} + ASMJIT_INST_3x(vfnmsub231ps, Vfnmsub231ps, Vec, Vec, Mem) // FMA AVX512_F{kz|b32} ASMJIT_INST_3x(vfnmsub231sd, Vfnmsub231sd, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231sd, Vfnmsub231sd, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231ss, Vfnmsub231ss, Xmm, Xmm, Xmm) // FMA AVX512_F{kz|er} ASMJIT_INST_3x(vfnmsub231ss, Vfnmsub231ss, Xmm, Xmm, Mem) // FMA AVX512_F{kz|er} - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Xmm, Imm) // AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Mem, Imm) // AVX512_DQ{k|b64} AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Ymm, Imm) // AVX512_DQ{k|b64}-VL - ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Zmm, Imm) // AVX512_DQ{k|b64} - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Xmm, Imm) // AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Mem, Imm) // AVX512_DQ{k|b32} AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Ymm, Imm) // AVX512_DQ{k|b32}-VL - ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Zmm, Imm) // AVX512_DQ{k|b32} + ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Vec, Imm) // AVX512_DQ{k|b64} + ASMJIT_INST_3i(vfpclasspd, Vfpclasspd, KReg, Mem, Imm) // AVX512_DQ{k|b64} + ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Vec, Imm) // AVX512_DQ{k|b32} + ASMJIT_INST_3i(vfpclassps, Vfpclassps, KReg, Mem, Imm) // AVX512_DQ{k|b32} ASMJIT_INST_3i(vfpclasssd, Vfpclasssd, KReg, Xmm, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclasssd, Vfpclasssd, KReg, Mem, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclassss, Vfpclassss, KReg, Xmm, Imm) // AVX512_DQ{k} ASMJIT_INST_3i(vfpclassss, Vfpclassss, KReg, Mem, Imm) // AVX512_DQ{k} - ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vgatherdps, Vgatherdps, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherdps, Vgatherdps, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherdps, Vgatherdps, Zmm, Mem) // AVX512_F{k} + ASMJIT_INST_2x(vgatherdpd, Vgatherdpd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherdpd, Vgatherdpd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgatherdps, Vgatherdps, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherdps, Vgatherdps, Vec, Mem, Vec) // AVX2 ASMJIT_INST_1x(vgatherpf0dpd, Vgatherpf0dpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf0dps, Vgatherpf0dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf0qpd, Vgatherpf0qpd, Mem) // AVX512_PF{k} @@ -2836,249 +2426,121 @@ public: ASMJIT_INST_1x(vgatherpf1dps, Vgatherpf1dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf1qpd, Vgatherpf1qpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vgatherpf1qps, Vgatherpf1qps, Mem) // AVX512_PF{k} - ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vgatherqps, Vgatherqps, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vgatherqps, Vgatherqps, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vgetexppd, Vgetexppd, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_2x(vgetexpps, Vgetexpps, Zmm, Mem) // AVX512_F{kz|sae|b32} + ASMJIT_INST_2x(vgatherqpd, Vgatherqpd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherqpd, Vgatherqpd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgatherqps, Vgatherqps, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vgatherqps, Vgatherqps, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vgetexppd, Vgetexppd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vgetexppd, Vgetexppd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vgetexpps, Vgetexpps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vgetexpps, Vgetexpps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vgetexpsd, Vgetexpsd, Xmm, Xmm, Xmm) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpsd, Vgetexpsd, Xmm, Xmm, Mem) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpss, Vgetexpss, Xmm, Xmm, Xmm) // AVX512_F{kz|sae} ASMJIT_INST_3x(vgetexpss, Vgetexpss, Xmm, Xmm, Mem) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3i(vgetmantps, Vgetmantps, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vgetmantpd, Vgetmantpd, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vgetmantps, Vgetmantps, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vgetmantps, Vgetmantps, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vgetmantsd, Vgetmantsd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantsd, Vgetmantsd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantss, Vgetmantss, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vgetmantss, Vgetmantss, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Xmm,Xmm,Xmm,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Xmm,Xmm,Mem,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Ymm,Ymm,Ymm,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Ymm,Ymm,Mem,Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Zmm,Zmm,Zmm,Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Zmm,Zmm,Mem,Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Xmm, Xmm, Xmm, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Xmm, Xmm, Mem, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Ymm, Ymm, Ymm, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Ymm, Ymm, Mem, Imm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Zmm, Zmm, Zmm, Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Zmm, Zmm, Mem, Imm) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Xmm, Xmm, Xmm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Xmm, Xmm, Mem) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Ymm, Ymm, Ymm) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Ymm, Ymm, Mem) // AVX AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Zmm, Zmm, Zmm) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Zmm, Zmm, Mem) // AVX512_VL{kz} GFNI - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhaddpd, Vhaddpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhaddps, Vhaddps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhsubpd, Vhsubpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Ymm, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vhsubps, Vhsubps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_4i(vinsertf128, Vinsertf128, Ymm, Ymm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vinsertf128, Vinsertf128, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Ymm, Ymm, Xmm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Zmm, Zmm, Xmm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Zmm, Zmm, Ymm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Ymm, Ymm, Xmm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Zmm, Zmm, Xmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Zmm, Zmm, Ymm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti128, Vinserti128, Ymm, Ymm, Xmm, Imm) // AVX2 - ASMJIT_INST_4i(vinserti128, Vinserti128, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Ymm, Ymm, Xmm, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz}-VL - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Zmm, Zmm, Xmm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Zmm, Zmm, Ymm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Ymm, Ymm, Xmm, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz}-VL - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Zmm, Zmm, Xmm, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Zmm, Zmm, Ymm, Imm) // AVX512_F{kz} - ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Vec,Vec,Vec,Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineinvqb, Vgf2p8affineinvqb,Vec,Vec,Mem,Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Vec, Vec, Vec, Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_4i(vgf2p8affineqb, Vgf2p8affineqb, Vec, Vec, Mem, Imm) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Vec, Vec, Vec) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vgf2p8mulb, Vgf2p8mulb, Vec, Vec, Mem) // AVX AVX512_VL{kz} GFNI + ASMJIT_INST_3x(vhaddpd, Vhaddpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhaddpd, Vhaddpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhaddps, Vhaddps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhaddps, Vhaddps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhsubpd, Vhsubpd, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhsubpd, Vhsubpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vhsubps, Vhsubps, Vec, Vec, Vec) // AVX + ASMJIT_INST_3x(vhsubps, Vhsubps, Vec, Vec, Mem) // AVX + ASMJIT_INST_4i(vinsertf128, Vinsertf128, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vinsertf128, Vinsertf128, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf32x4, Vinsertf32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf32x8, Vinsertf32x8, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x2, Vinsertf64x2, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinsertf64x4, Vinsertf64x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti128, Vinserti128, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vinserti128, Vinserti128, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti32x4, Vinserti32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti32x8, Vinserti32x8, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Vec, Vec, Vec, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x2, Vinserti64x2, Vec, Vec, Mem, Imm) // AVX512_DQ{kz} + ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Vec, Vec, Vec, Imm) // AVX512_F{kz} + ASMJIT_INST_4i(vinserti64x4, Vinserti64x4, Vec, Vec, Mem, Imm) // AVX512_F{kz} ASMJIT_INST_4i(vinsertps, Vinsertps, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F ASMJIT_INST_4i(vinsertps, Vinsertps, Xmm, Xmm, Mem, Imm) // AVX AVX512_F - ASMJIT_INST_2x(vlddqu, Vlddqu, Xmm, Mem) // AVX - ASMJIT_INST_2x(vlddqu, Vlddqu, Ymm, Mem) // AVX + ASMJIT_INST_2x(vlddqu, Vlddqu, Vec, Mem) // AVX ASMJIT_INST_1x(vldmxcsr, Vldmxcsr, Mem) // AVX - ASMJIT_INST_3x(vmaskmovdqu, Vmaskmovdqu, Xmm, Xmm, DS_ZDI) // AVX [EXPLICIT] - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Ymm, Ymm) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Ymm, Ymm, Mem) // AVX - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vmaxpd, Vmaxpd, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vmaxps, Vmaxps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmaxps, Vmaxps, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vmaxps, Vmaxps, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vminpd, Vminpd, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vminpd, Vminpd, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3x(vminps, Vminps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vminps, Vminps, Zmm, Zmm, Zmm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vminps, Vminps, Zmm, Zmm, Mem) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovapd, Vmovapd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovapd, Vmovapd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovaps, Vmovaps, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Zmm) // AVX512_F{kz} + ASMJIT_INST_3x(vmaskmovdqu, Vmaskmovdqu, Vec, Vec, DS_ZDI) // AVX [EXPLICIT] + ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Mem, Vec, Vec) // AVX + ASMJIT_INST_3x(vmaskmovpd, Vmaskmovpd, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Mem, Vec, Vec) // AVX + ASMJIT_INST_3x(vmaskmovps, Vmaskmovps, Vec, Vec, Mem) // AVX + ASMJIT_INST_3x(vmaxpd, Vmaxpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmaxpd, Vmaxpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmaxps, Vmaxps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmaxps, Vmaxps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxsd, Vmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vmaxss, Vmaxss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminpd, Vminpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vminpd, Vminpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vminps, Vminps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vminps, Vminps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminsd, Vminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|sae} + ASMJIT_INST_3x(vminss, Vminss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|sae} + ASMJIT_INST_2x(vmovapd, Vmovapd, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovapd, Vmovapd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovapd, Vmovapd, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovaps, Vmovaps, Mem, Vec) // AVX AVX512_F{kz} ASMJIT_INST_2x(vmovd, Vmovd, Gp, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Xmm, Gp) // AVX AVX512_F ASMJIT_INST_2x(vmovd, Vmovd, Xmm, Mem) // AVX AVX512_F - ASMJIT_INST_2x(vmovddup, Vmovddup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovddup, Vmovddup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovddup, Vmovddup, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Xmm, Mem) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Xmm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Ymm, Mem) // AVX - ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Ymm) // AVX - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Xmm, Mem) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Xmm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Ymm, Mem) // AVX - ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Ymm) // AVX - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Zmm) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovddup, Vmovddup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovddup, Vmovddup, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Vec, Vec) // AVX + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Vec, Mem) // AVX + ASMJIT_INST_2x(vmovdqa, Vmovdqa, Mem, Vec) // AVX + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa32, Vmovdqa32, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqa64, Vmovdqa64, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Vec, Vec) // AVX + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Vec, Mem) // AVX + ASMJIT_INST_2x(vmovdqu, Vmovdqu, Mem, Vec) // AVX + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu16, Vmovdqu16, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu32, Vmovdqu32, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu64, Vmovdqu64, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vmovdqu8, Vmovdqu8, Mem, Vec) // AVX512_BW{kz} ASMJIT_INST_3x(vmovhlps, Vmovhlps, Xmm, Xmm, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovhpd, Vmovhpd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_3x(vmovhpd, Vmovhpd, Xmm, Xmm, Mem) // AVX AVX512_F @@ -3089,22 +2551,12 @@ public: ASMJIT_INST_3x(vmovlpd, Vmovlpd, Xmm, Xmm, Mem) // AVX AVX512_F ASMJIT_INST_2x(vmovlps, Vmovlps, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_3x(vmovlps, Vmovlps, Xmm, Xmm, Mem) // AVX AVX512_F - ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Xmm) // AVX - ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Ymm) // AVX - ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Xmm) // AVX - ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Ymm) // AVX - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Zmm) // AVX512_F - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Xmm, Mem) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Ymm, Mem) // AVX2 AVX512_F-VL - ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Zmm, Mem) // AVX512_F - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Zmm) // AVX512_F - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Xmm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Ymm) // AVX AVX512_F-VL - ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Zmm) // AVX512_F + ASMJIT_INST_2x(vmovmskpd, Vmovmskpd, Gp, Vec) // AVX + ASMJIT_INST_2x(vmovmskps, Vmovmskps, Gp, Vec) // AVX + ASMJIT_INST_2x(vmovntdq, Vmovntdq, Mem, Vec) // AVX+ AVX512_F + ASMJIT_INST_2x(vmovntdqa, Vmovntdqa, Vec, Mem) // AVX+ AVX512_F + ASMJIT_INST_2x(vmovntpd, Vmovntpd, Mem, Vec) // AVX AVX512_F + ASMJIT_INST_2x(vmovntps, Vmovntps, Mem, Vec) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Gp, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovq, Vmovq, Xmm, Mem) // AVX AVX512_F @@ -3113,627 +2565,241 @@ public: ASMJIT_INST_2x(vmovsd, Vmovsd, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovsd, Vmovsd, Xmm, Mem) // AVX AVX512_F{kz} ASMJIT_INST_3x(vmovsd, Vmovsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovshdup, Vmovshdup, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovsldup, Vmovsldup, Zmm, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vmovshdup, Vmovshdup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovshdup, Vmovshdup, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovsldup, Vmovsldup, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovsldup, Vmovsldup, Vec, Mem) // AVX AVX512_F{kz} ASMJIT_INST_2x(vmovss, Vmovss, Mem, Xmm) // AVX AVX512_F ASMJIT_INST_2x(vmovss, Vmovss, Xmm, Mem) // AVX AVX512_F{kz} ASMJIT_INST_3x(vmovss, Vmovss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovupd, Vmovupd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Ymm, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Ymm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Ymm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vmovups, Vmovups, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vmovups, Vmovups, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vmulpd, Vmulpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vmulpd, Vmulpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vmulpd, Vmulpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vmulps, Vmulps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vmulps, Vmulps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vmulps, Vmulps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_2x(vmovupd, Vmovupd, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovupd, Vmovupd, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovupd, Vmovupd, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_2x(vmovups, Vmovups, Mem, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Vec, Vec, Vec, Imm) // AVX+ + ASMJIT_INST_4i(vmpsadbw, Vmpsadbw, Vec, Vec, Mem, Imm) // AVX+ + ASMJIT_INST_3x(vmulpd, Vmulpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmulpd, Vmulpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vmulps, Vmulps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vmulps, Vmulps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vmulsd, Vmulsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulsd, Vmulsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulss, Vmulss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vmulss, Vmulss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_3x(vorpd, Vorpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vorpd, Vorpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vorpd, Vorpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vorps, Vorps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vorps, Vorps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vorps, Vorps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vorpd, Vorpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vorpd, Vorpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vorps, Vorps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vorps, Vorps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_6x(vp4dpwssd, Vp4dpwssd, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} ASMJIT_INST_6x(vp4dpwssds, Vp4dpwssds, Zmm, Zmm, Zmm, Zmm, Zmm, Mem) // AVX512_4FMAPS{kz} - ASMJIT_INST_2x(vpabsb, Vpabsb, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsb, Vpabsb, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsb, Vpabsb, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsd, Vpabsd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Ymm, Ymm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsd, Vpabsd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsd, Vpabsd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsq, Vpabsq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpabsq, Vpabsq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsq, Vpabsq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpabsw, Vpabsw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpabsw, Vpabsw, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpabsw, Vpabsw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Zmm, Zmm, Zmm) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackssdw, Vpackssdw, Zmm, Zmm, Mem) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpacksswb, Vpacksswb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz|b32}-VL - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Zmm, Zmm, Zmm) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackusdw, Vpackusdw, Zmm, Zmm, Mem) // AVX512_BW{kz|b32} - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpackuswb, Vpackuswb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddb, Vpaddb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddb, Vpaddb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddb, Vpaddb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddd, Vpaddd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpaddd, Vpaddd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpaddd, Vpaddd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpaddq, Vpaddq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpaddq, Vpaddq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpaddq, Vpaddq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsb, Vpaddsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddsw, Vpaddsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusb, Vpaddusb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddusw, Vpaddusw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddw, Vpaddw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpaddw, Vpaddw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpaddw, Vpaddw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpalignr, Vpalignr, Xmm, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Ymm, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Ymm, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_4i(vpalignr, Vpalignr, Zmm, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_4i(vpalignr, Vpalignr, Zmm, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpand, Vpand, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpand, Vpand, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpand, Vpand, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpand, Vpand, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpandd, Vpandd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandd, Vpandd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandd, Vpandd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandn, Vpandn, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpandn, Vpandn, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpandn, Vpandn, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpandn, Vpandn, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpandnd, Vpandnd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpandnd, Vpandnd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandnd, Vpandnd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpandnq, Vpandnq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandnq, Vpandnq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandnq, Vpandnq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandq, Vpandq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpandq, Vpandq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpandq, Vpandq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpavgb, Vpavgb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Ymm, Ymm, Ymm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Ymm, Ymm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgb, Vpavgb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgb, Vpavgb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgw, Vpavgw, Xmm, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Xmm, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpavgw, Vpavgw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpavgw, Vpavgw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpblendd, Vpblendd, Xmm, Xmm, Xmm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Xmm, Xmm, Mem, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendd, Vpblendd, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Xmm, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Xmm, Xmm, Mem, Xmm) // AVX - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Ymm, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_4x(vpblendvb, Vpblendvb, Ymm, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_4i(vpblendw, Vpblendw, Xmm, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_4i(vpblendw, Vpblendw, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_4i(vpblendw, Vpblendw, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vpblendw, Vpblendw, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Xmm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Ymm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Gp) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Xmm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Ymm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Gp) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Xmm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Ymm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Zmm, KReg) // AVX512_CD - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Xmm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Ymm, KReg) // AVX512_CD-VL - ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Zmm, KReg) // AVX512_CD - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Xmm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Ymm, Gp) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Gp) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Xmm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Ymm, Gp) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Gp) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F-VL - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Xmm, Xmm, Mem, Imm) // AVX AVX512_F-VL - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Ymm, Ymm, Ymm, Imm) // AVX512_F-VL VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Ymm, Ymm, Mem, Imm) // AVX512_F-VL VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Zmm, Zmm, Zmm, Imm) // AVX512_F VPCLMULQDQ - ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Zmm, Zmm, Mem, Imm) // AVX512_F VPCLMULQDQ - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Xmm, Xmm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Xmm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Ymm, Ymm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Ymm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Zmm, Zmm, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Zmm, Mem, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Xmm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Ymm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Zmm, Mem, Imm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Xmm, Xmm, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Xmm, Mem, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Xmm, Xmm, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] - ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Xmm, Mem, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Xmm, Xmm, Imm, ECX) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Xmm, Mem, Imm, ECX) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Xmm, Xmm, Imm, XMM0) // AVX [EXPLICIT] - ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Xmm, Mem, Imm, XMM0) // AVX [EXPLICIT] - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Xmm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Ymm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Zmm, Mem, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Xmm, Xmm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Xmm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Ymm, Ymm, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Ymm, Mem, Imm) // AVX512_BW{k}-VL - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Zmm, Zmm, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Zmm, Mem, Imm) // AVX512_BW{k} - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Xmm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Ymm, Mem, Imm) // AVX512_F{k|b32}-VL - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Zmm, Mem, Imm) // AVX512_F{k|b32} - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Xmm, Xmm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Xmm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Ymm, Ymm, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Ymm, Mem, Imm) // AVX512_F{k|b64}-VL - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Zmm, Zmm, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Zmm, Mem, Imm) // AVX512_F{k|b64} - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Xmm, Xmm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Xmm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Ymm, Ymm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Ymm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Zmm, Zmm, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Zmm, Mem, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Xmm, Xmm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Xmm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Ymm, Ymm, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Ymm, Mem, Imm) // AVX512_BW{k|b64}-VL - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Zmm, Zmm, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Zmm, Mem, Imm) // AVX512_BW{k|b64} - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictd, Vpconflictd, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vpconflictq, Vpconflictq, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Xmm, Xmm, Xmm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Xmm, Xmm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Ymm, Ymm, Ymm) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Ymm, Ymm, Mem) // AVX512_VNNI{kz|b32}-VL - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Zmm, Zmm, Zmm) // AVX512_VNNI{kz|b32} - ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Zmm, Zmm, Mem) // AVX512_VNNI{kz|b32} - ASMJIT_INST_4i(vperm2f128, Vperm2f128, Ymm, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_4i(vperm2f128, Vperm2f128, Ymm, Ymm, Mem, Imm) // AVX - ASMJIT_INST_4i(vperm2i128, Vperm2i128, Ymm, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_4i(vperm2i128, Vperm2i128, Ymm, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vpermb, Vpermb, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermb, Vpermb, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermb, Vpermb, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermd, Vpermd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermd, Vpermd, Zmm, Zmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermi2b, Vpermi2b, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2d, Vpermi2d, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2q, Vpermi2q, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermi2w, Vpermi2w, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilpd, Vpermilpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilpd, Vpermilpd, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilps, Vpermilps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermilps, Vpermilps, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermilps, Vpermilps, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermilps, Vpermilps, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilps, Vpermilps, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermilps, Vpermilps, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpermpd, Vpermpd, Ymm, Ymm, Imm) // AVX2 - ASMJIT_INST_3i(vpermpd, Vpermpd, Ymm, Mem, Imm) // AVX2 - ASMJIT_INST_3x(vpermps, Vpermps, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpermps, Vpermps, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3i(vpermq, Vpermq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Ymm, Mem, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermq, Vpermq, Zmm, Zmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Zmm, Zmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpermq, Vpermq, Zmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Xmm, Xmm, Xmm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Xmm, Xmm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Ymm, Ymm, Ymm) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Ymm, Ymm, Mem) // AVX512_VBMI{kz}-VL - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Zmm, Zmm, Zmm) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermt2b, Vpermt2b, Zmm, Zmm, Mem) // AVX512_VBMI{kz} - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2d, Vpermt2d, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2q, Vpermt2q, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermt2w, Vpermt2w, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermw, Vpermw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpermw, Vpermw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpermw, Vpermw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandb, Vpexpandb, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandd, Vpexpandd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Ymm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Zmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandq, Vpexpandq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_2x(vpexpandw, Vpexpandw, Zmm, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpabsb, Vpabsb, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsb, Vpabsb, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsd, Vpabsd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpabsd, Vpabsd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpabsq, Vpabsq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpabsq, Vpabsq, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpabsw, Vpabsw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpabsw, Vpabsw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackssdw, Vpackssdw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackssdw, Vpackssdw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpacksswb, Vpacksswb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpacksswb, Vpacksswb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackusdw, Vpackusdw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackusdw, Vpackusdw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz|b32} + ASMJIT_INST_3x(vpackuswb, Vpackuswb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpackuswb, Vpackuswb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddb, Vpaddb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddb, Vpaddb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddd, Vpaddd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpaddd, Vpaddd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpaddq, Vpaddq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpaddq, Vpaddq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpaddsb, Vpaddsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsb, Vpaddsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsw, Vpaddsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddsw, Vpaddsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusb, Vpaddusb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusb, Vpaddusb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusw, Vpaddusw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddusw, Vpaddusw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddw, Vpaddw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpaddw, Vpaddw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpalignr, Vpalignr, Vec, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpalignr, Vpalignr, Vec, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpand, Vpand, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpand, Vpand, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpandd, Vpandd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandd, Vpandd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandn, Vpandn, Vec, Vec, Vec) // AV+ + ASMJIT_INST_3x(vpandn, Vpandn, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpandnd, Vpandnd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandnd, Vpandnd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpandnq, Vpandnq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandnq, Vpandnq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandq, Vpandq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpandq, Vpandq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpavgb, Vpavgb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgb, Vpavgb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgw, Vpavgw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpavgw, Vpavgw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_4i(vpblendd, Vpblendd, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vpblendd, Vpblendd, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_4x(vpblendvb, Vpblendvb, Vec, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_4x(vpblendvb, Vpblendvb, Vec, Vec, Mem, Vec) // AVX+ + ASMJIT_INST_4i(vpblendw, Vpblendw, Vec, Vec, Vec, Imm) // AVX+ + ASMJIT_INST_4i(vpblendw, Vpblendw, Vec, Vec, Mem, Imm) // AVX+ + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Vec) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Mem) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastb, Vpbroadcastb, Vec, Gp) // AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Vec) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Mem) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastd, Vpbroadcastd, Vec, Gp) // AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastmb2d, Vpbroadcastmb2d, Vec, KReg) // AVX512_CD + ASMJIT_INST_2x(vpbroadcastmb2q, Vpbroadcastmb2q, Vec, KReg) // AVX512_CD + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Vec) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Mem) // AVX2 AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastq, Vpbroadcastq, Vec, Gp) // AVX512_F{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Vec) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Mem) // AVX2 AVX512_BW{kz} + ASMJIT_INST_2x(vpbroadcastw, Vpbroadcastw, Vec, Gp) // AVX512_BW{kz} + ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Vec, Vec, Vec, Imm) // AVX VPCLMULQDQ AVX512_F + ASMJIT_INST_4i(vpclmulqdq, Vpclmulqdq, Vec, Vec, Mem, Imm) // AVX VPCLMULQDQ AVX512_F + ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Vec, Vec, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpb, Vpcmpb, KReg, Vec, Mem, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Vec, Vec, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpd, Vpcmpd, KReg, Vec, Mem, Imm) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqb, Vpcmpeqb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqd, Vpcmpeqd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpeqq, Vpcmpeqq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpeqw, Vpcmpeqw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Vec, Vec, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestri, Vpcmpestri, Vec, Mem, Imm, ECX, EAX, EDX) // AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Vec, Vec, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] + ASMJIT_INST_6x(vpcmpestrm, Vpcmpestrm, Vec, Mem, Imm, XMM0, EAX, EDX)// AVX [EXPLICIT] + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtb, Vpcmpgtb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpgtd, Vpcmpgtd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpgtq, Vpcmpgtq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vpcmpgtw, Vpcmpgtw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Vec, Vec, Imm, ECX) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistri, Vpcmpistri, Vec, Mem, Imm, ECX) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Vec, Vec, Imm, XMM0) // AVX [EXPLICIT] + ASMJIT_INST_4x(vpcmpistrm, Vpcmpistrm, Vec, Mem, Imm, XMM0) // AVX [EXPLICIT] + ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Vec, Vec, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpq, Vpcmpq, KReg, Vec, Mem, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Vec, Vec, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpub, Vpcmpub, KReg, Vec, Mem, Imm) // AVX512_BW{k} + ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Vec, Vec, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpud, Vpcmpud, KReg, Vec, Mem, Imm) // AVX512_F{k|b32} + ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Vec, Vec, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpuq, Vpcmpuq, KReg, Vec, Mem, Imm) // AVX512_F{k|b64} + ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Vec, Vec, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpuw, Vpcmpuw, KReg, Vec, Mem, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Vec, Vec, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_4i(vpcmpw, Vpcmpw, KReg, Vec, Mem, Imm) // AVX512_BW{k|b64} + ASMJIT_INST_2x(vpcompressb, Vpcompressb, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressb, Vpcompressb, Mem, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressd, Vpcompressd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressd, Vpcompressd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressq, Vpcompressq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressq, Vpcompressq, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpcompressw, Vpcompressw, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpcompressw, Vpcompressw, Mem, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpconflictd, Vpconflictd, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictd, Vpconflictd, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictq, Vpconflictq, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vpconflictq, Vpconflictq, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusd, Vpdpbusd, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpbusds, Vpdpbusds, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssd, Vpdpwssd, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Vec, Vec, Vec) // AVX512_VNNI{kz|b32} + ASMJIT_INST_3x(vpdpwssds, Vpdpwssds, Vec, Vec, Mem) // AVX512_VNNI{kz|b32} + ASMJIT_INST_4i(vperm2f128, Vperm2f128, Vec, Vec, Vec, Imm) // AVX + ASMJIT_INST_4i(vperm2f128, Vperm2f128, Vec, Vec, Mem, Imm) // AVX + ASMJIT_INST_4i(vperm2i128, Vperm2i128, Vec, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_4i(vperm2i128, Vperm2i128, Vec, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_3x(vpermb, Vpermb, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermb, Vpermb, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermd, Vpermd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermd, Vpermd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2b, Vpermi2b, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermi2b, Vpermi2b, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermi2d, Vpermi2d, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2d, Vpermi2d, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2pd, Vpermi2pd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2ps, Vpermi2ps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermi2q, Vpermi2q, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2q, Vpermi2q, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermi2w, Vpermi2w, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermi2w, Vpermi2w, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermilpd, Vpermilpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilpd, Vpermilpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilpd, Vpermilpd, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilpd, Vpermilpd, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilps, Vpermilps, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermilps, Vpermilps, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilps, Vpermilps, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermilps, Vpermilps, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermpd, Vpermpd, Vec, Vec, Imm) // AVX2 + ASMJIT_INST_3i(vpermpd, Vpermpd, Vec, Mem, Imm) // AVX2 + ASMJIT_INST_3x(vpermps, Vpermps, Vec, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpermps, Vpermps, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3i(vpermq, Vpermq, Vec, Vec, Imm) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3i(vpermq, Vpermq, Vec, Mem, Imm) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermq, Vpermq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermq, Vpermq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2b, Vpermt2b, Vec, Vec, Vec) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermt2b, Vpermt2b, Vec, Vec, Mem) // AVX512_VBMI{kz} + ASMJIT_INST_3x(vpermt2d, Vpermt2d, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2d, Vpermt2d, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2pd, Vpermt2pd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2ps, Vpermt2ps, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpermt2q, Vpermt2q, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2q, Vpermt2q, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpermt2w, Vpermt2w, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermt2w, Vpermt2w, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermw, Vpermw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpermw, Vpermw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_2x(vpexpandb, Vpexpandb, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandb, Vpexpandb, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandd, Vpexpandd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandd, Vpexpandd, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandq, Vpexpandq, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandq, Vpexpandq, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_2x(vpexpandw, Vpexpandw, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_2x(vpexpandw, Vpexpandw, Vec, Mem) // AVX512_VBMI2{kz} ASMJIT_INST_3i(vpextrb, Vpextrb, Gp, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrb, Vpextrb, Mem, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrd, Vpextrd, Gp, Xmm, Imm) // AVX AVX512_DQ @@ -3742,51 +2808,28 @@ public: ASMJIT_INST_3i(vpextrq, Vpextrq, Mem, Xmm, Imm) // AVX AVX512_DQ ASMJIT_INST_3i(vpextrw, Vpextrw, Gp, Xmm, Imm) // AVX AVX512_BW ASMJIT_INST_3i(vpextrw, Vpextrw, Mem, Xmm, Imm) // AVX AVX512_BW - ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherqd, Vpgatherqd, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Xmm, Mem, Xmm) // AVX2 - ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Ymm, Mem, Ymm) // AVX2 - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Xmm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Ymm, Mem) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Zmm, Mem) // AVX512_F{k} - ASMJIT_INST_3x(vphaddd, Vphaddd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddd, Vphaddd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddd, Vphaddd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddd, Vphaddd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddsw, Vphaddsw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphaddw, Vphaddw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphaddw, Vphaddw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphaddw, Vphaddw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphaddw, Vphaddw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_2x(vphminposuw, Vphminposuw, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vphminposuw, Vphminposuw, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubd, Vphsubd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubd, Vphsubd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubsw, Vphsubsw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vphsubw, Vphsubw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vphsubw, Vphsubw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vphsubw, Vphsubw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vphsubw, Vphsubw, Ymm, Ymm, Mem) // AVX2 + ASMJIT_INST_2x(vpgatherdd, Vpgatherdd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherdd, Vpgatherdd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherdq, Vpgatherdq, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherdq, Vpgatherdq, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherqd, Vpgatherqd, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherqd, Vpgatherqd, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_2x(vpgatherqq, Vpgatherqq, Vec, Mem) // AVX512_F{k} + ASMJIT_INST_3x(vpgatherqq, Vpgatherqq, Vec, Mem, Vec) // AVX2 + ASMJIT_INST_3x(vphaddd, Vphaddd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddd, Vphaddd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphaddsw, Vphaddsw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddsw, Vphaddsw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphaddw, Vphaddw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphaddw, Vphaddw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_2x(vphminposuw, Vphminposuw, Vec, Vec) // AVX + ASMJIT_INST_2x(vphminposuw, Vphminposuw, Vec, Mem) // AVX + ASMJIT_INST_3x(vphsubd, Vphsubd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubd, Vphsubd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphsubsw, Vphsubsw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubsw, Vphsubsw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vphsubw, Vphsubw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vphsubw, Vphsubw, Vec, Vec, Mem) // AVX+ ASMJIT_INST_4i(vpinsrb, Vpinsrb, Xmm, Xmm, Gp, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrb, Vpinsrb, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrd, Vpinsrd, Xmm, Xmm, Gp, Imm) // AVX AVX512_DQ{kz} @@ -3795,1099 +2838,411 @@ public: ASMJIT_INST_4i(vpinsrq, Vpinsrq, Xmm, Xmm, Mem, Imm) // AVX AVX512_DQ{kz} ASMJIT_INST_4i(vpinsrw, Vpinsrw, Xmm, Xmm, Gp, Imm) // AVX AVX512_BW{kz} ASMJIT_INST_4i(vpinsrw, Vpinsrw, Xmm, Xmm, Mem, Imm) // AVX AVX512_BW{kz} - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Xmm, Xmm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Xmm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Ymm, Ymm) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Ymm, Mem) // AVX512_CD{kz|b32}-VL - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Zmm, Zmm) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vplzcntd, Vplzcntd, Zmm, Mem) // AVX512_CD{kz|b32} - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Xmm, Xmm) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Xmm, Mem) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Ymm, Ymm) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Ymm, Mem) // AVX512_CD{kz|b64}-VL - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Zmm, Zmm) // AVX512_CD{kz|b64} - ASMJIT_INST_2x(vplzcntq, Vplzcntq, Zmm, Mem) // AVX512_CD{kz|b64} - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Xmm, Xmm, Xmm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Xmm, Xmm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Ymm, Ymm, Ymm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Ymm, Ymm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Zmm, Zmm, Zmm) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Zmm, Zmm, Mem) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Xmm, Xmm, Xmm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Xmm, Xmm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Ymm, Ymm, Ymm) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Ymm, Ymm, Mem) // AVX512_IFMA{kz|b64}-VL - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Zmm, Zmm, Zmm) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Zmm, Zmm, Mem) // AVX512_IFMA{kz|b64} - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Xmm, Xmm) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Xmm, Xmm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Xmm, Xmm) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Xmm, Xmm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxub, Vpmaxub, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxud, Vpmaxud, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsb, Vpminsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsb, Vpminsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsb, Vpminsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsd, Vpminsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminsd, Vpminsd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminsd, Vpminsd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminsq, Vpminsq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminsq, Vpminsq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminsq, Vpminsq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminsw, Vpminsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminsw, Vpminsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminsw, Vpminsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminub, Vpminub, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminub, Vpminub, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminub, Vpminub, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminud, Vpminud, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpminud, Vpminud, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminud, Vpminud, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpminuq, Vpminuq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpminuq, Vpminuq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminuq, Vpminuq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpminuw, Vpminuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpminuw, Vpminuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpminuw, Vpminuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Xmm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Ymm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Zmm) // AVX512_BW - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Xmm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Ymm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Zmm) // AVX512_DQ - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Xmm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Ymm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Zmm, KReg) // AVX512_BW - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Xmm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Ymm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Zmm, KReg) // AVX512_DQ - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Xmm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Ymm, KReg) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Zmm, KReg) // AVX512_DQ - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Xmm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Ymm, KReg) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Zmm, KReg) // AVX512_BW - ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Xmm) // AVX - ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Ymm) // AVX2 - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Xmm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Ymm) // AVX512_DQ-VL - ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Zmm) // AVX512_DQ - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Zmm, Ymm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Ymm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Ymm) // AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Xmm, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Zmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Xmm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Ymm) // AVX512_BW-VL - ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Zmm) // AVX512_BW - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Xmm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Ymm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Zmm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Zmm, Ymm) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Zmm, Ymm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmuldq, Vpmuldq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulhw, Vpmulhw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmulld, Vpmulld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpmulld, Vpmulld, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmulld, Vpmulld, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpmullq, Vpmullq, Xmm, Xmm, Xmm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Xmm, Xmm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Ymm, Ymm, Ymm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Ymm, Ymm, Mem) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vpmullq, Vpmullq, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vpmullq, Vpmullq, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vpmullw, Vpmullw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpmullw, Vpmullw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmullw, Vpmullw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Xmm, Xmm, Xmm) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Xmm, Xmm, Mem) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Ymm, Ymm, Ymm) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Ymm, Ymm, Mem) // AVX512_VBMI{kz|b64}-VL - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Zmm, Zmm, Zmm) // AVX512_VBMI{kz|b64} - ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Zmm, Zmm, Mem) // AVX512_VBMI{kz|b64} - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpmuludq, Vpmuludq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Xmm, Xmm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Xmm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Ymm, Ymm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Ymm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Zmm, Zmm) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntb, Vpopcntb, Zmm, Mem) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Xmm, Xmm) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Xmm, Mem) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Ymm, Ymm) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Ymm, Mem) // AVX512_VPOPCNTDQ{kz|b32}-VL - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Zmm, Zmm) // AVX512_VPOPCNTDQ{kz|b32} - ASMJIT_INST_2x(vpopcntd, Vpopcntd, Zmm, Mem) // AVX512_VPOPCNTDQ{kz|b32} - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Xmm, Xmm) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Xmm, Mem) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Ymm, Ymm) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Ymm, Mem) // AVX512_VPOPCNTDQ{kz|b64}-VL - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Zmm, Zmm) // AVX512_VPOPCNTDQ{kz|b64} - ASMJIT_INST_2x(vpopcntq, Vpopcntq, Zmm, Mem) // AVX512_VPOPCNTDQ{kz|b64} - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Xmm, Xmm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Xmm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Ymm, Ymm) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Ymm, Mem) // AVX512_BITALG{kz|b32}-VL - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Zmm, Zmm) // AVX512_BITALG{kz|b32} - ASMJIT_INST_2x(vpopcntw, Vpopcntw, Zmm, Mem) // AVX512_BITALG{kz|b32} - ASMJIT_INST_3x(vpor, Vpor, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpor, Vpor, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpor, Vpor, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpor, Vpor, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpord, Vpord, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpord, Vpord, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpord, Vpord, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vporq, Vporq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vporq, Vporq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vporq, Vporq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprold, Vprold, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprold, Vprold, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprold, Vprold, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprolq, Vprolq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprolq, Vprolq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprolq, Vprolq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprolvd, Vprolvd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprolvd, Vprolvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprolvd, Vprolvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprolvq, Vprolvq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprolvq, Vprolvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprolvq, Vprolvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprord, Vprord, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vprord, Vprord, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprord, Vprord, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vprorq, Vprorq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vprorq, Vprorq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vprorq, Vprorq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprorvd, Vprorvd, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vprorvd, Vprorvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprorvd, Vprorvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vprorvq, Vprorvq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vprorvq, Vprorvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vprorvq, Vprorvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Xmm, Xmm, Xmm) // AVX AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Xmm, Xmm, Mem) // AVX AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW-VL - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Zmm, Zmm, Zmm) // AVX512_BW - ASMJIT_INST_3x(vpsadbw, Vpsadbw, Zmm, Zmm, Mem) // AVX512_BW - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Ymm) // AVX512_F{k} - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_4i(vpshldd, Vpshldd, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshldd, Vpshldd, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshldd, Vpshldd, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvd, Vpshldvd, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvq, Vpshldvq, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshldvw, Vpshldvw, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdd, Vpshrdd, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Xmm, Xmm, Xmm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Xmm, Xmm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Ymm, Ymm, Ymm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Ymm, Ymm, Mem) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Zmm, Zmm, Zmm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Zmm, Zmm, Mem) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Xmm, Xmm, Xmm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Xmm, Xmm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Ymm, Ymm, Ymm, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Ymm, Ymm, Mem, Imm) // AVX512_VBMI2{kz}-VL - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Zmm, Zmm, Zmm, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_4i(vpshrdw, Vpshrdw, Zmm, Zmm, Mem, Imm) // AVX512_VBMI2{kz} - ASMJIT_INST_3x(vpshufb, Vpshufb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpshufb, Vpshufb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpshufb, Vpshufb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Xmm, Xmm) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Xmm, Mem) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Ymm, Ymm) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Ymm, Mem) // AVX512_BITALG{k}-VL - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Zmm, Zmm) // AVX512_BITALG{k} - ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Zmm, Mem) // AVX512_BITALG{k} - ASMJIT_INST_3i(vpshufd, Vpshufd, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Xmm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Ymm, Mem, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpshufd, Vpshufd, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpshufd, Vpshufd, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshufhw, Vpshufhw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Xmm, Mem, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Ymm, Mem, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpshuflw, Vpshuflw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsignb, Vpsignb, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignb, Vpsignb, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignb, Vpsignb, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignb, Vpsignb, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpsignd, Vpsignd, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignd, Vpsignd, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignd, Vpsignd, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignd, Vpsignd, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpsignw, Vpsignw, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpsignw, Vpsignw, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpsignw, Vpsignw, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpsignw, Vpsignw, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3i(vpslld, Vpslld, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpslld, Vpslld, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpslld, Vpslld, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpslld, Vpslld, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpslld, Vpslld, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpslld, Vpslld, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpslldq, Vpslldq, Xmm, Xmm, Imm) // AVX AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Ymm, Ymm, Imm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Xmm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Ymm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpslldq, Vpslldq, Zmm, Zmm, Imm) // AVX512_BW - ASMJIT_INST_3i(vpslldq, Vpslldq, Zmm, Mem, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsllq, Vpsllq, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsllq, Vpsllq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllq, Vpsllq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsllq, Vpsllq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsllq, Vpsllq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsllq, Vpsllq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsllvd, Vpsllvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvq, Vpsllvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsllvw, Vpsllvw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsllw, Vpsllw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsllw, Vpsllw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsllw, Vpsllw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsllw, Vpsllw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrad, Vpsrad, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpsrad, Vpsrad, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrad, Vpsrad, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrad, Vpsrad, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrad, Vpsrad, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrad, Vpsrad, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsraq, Vpsraq, Xmm, Xmm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Xmm, Xmm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Ymm, Ymm, Xmm) // AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Ymm, Ymm, Mem) // AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsraq, Vpsraq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsraq, Vpsraq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsraq, Vpsraq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsraq, Vpsraq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsraq, Vpsraq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravd, Vpsravd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsravd, Vpsravd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsravd, Vpsravd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsravq, Vpsravq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsravq, Vpsravq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravq, Vpsravq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsravw, Vpsravw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsravw, Vpsravw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsravw, Vpsravw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsraw, Vpsraw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsraw, Vpsraw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsraw, Vpsraw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsraw, Vpsraw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrld, Vpsrld, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vpsrld, Vpsrld, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrld, Vpsrld, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrld, Vpsrld, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrld, Vpsrld, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrld, Vpsrld, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Xmm, Xmm, Imm) // AVX AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Ymm, Ymm, Imm) // AVX2 AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Xmm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Ymm, Mem, Imm) // AVX512_BW-VL - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Zmm, Zmm, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsrldq, Vpsrldq, Zmm, Mem, Imm) // AVX512_BW - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Xmm, Xmm, Mem) // AVX AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Ymm, Ymm, Imm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Ymm, Ymm, Xmm) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Zmm, Zmm, Xmm) // AVX512_F{kz} - ASMJIT_INST_3x(vpsrlq, Vpsrlq, Zmm, Zmm, Mem) // AVX512_F{kz} - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3i(vpsrlq, Vpsrlq, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Xmm, Xmm, Xmm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Xmm, Xmm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Xmm, Xmm, Xmm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Xmm, Xmm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Ymm, Ymm, Ymm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Ymm, Ymm, Mem) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Xmm, Xmm, Imm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Ymm, Ymm, Imm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Ymm, Ymm, Xmm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Xmm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Ymm, Mem, Imm) // AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Zmm, Zmm, Xmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsrlw, Vpsrlw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Zmm, Zmm, Imm) // AVX512_BW{kz} - ASMJIT_INST_3i(vpsrlw, Vpsrlw, Zmm, Mem, Imm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubb, Vpsubb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubb, Vpsubb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubb, Vpsubb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubd, Vpsubd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpsubd, Vpsubd, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsubd, Vpsubd, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpsubq, Vpsubq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpsubq, Vpsubq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsubq, Vpsubq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsb, Vpsubsb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubsw, Vpsubsw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusb, Vpsubusb, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubusw, Vpsubusw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubw, Vpsubw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpsubw, Vpsubw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpsubw, Vpsubw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vpternlogd, Vpternlogd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vpternlogq, Vpternlogq, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vptest, Vptest, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vptest, Vptest, Xmm, Mem) // AVX - ASMJIT_INST_2x(vptest, Vptest, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vptest, Vptest, Ymm, Mem) // AVX - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Xmm, Xmm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Xmm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Ymm, Ymm) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Ymm, Mem) // AVX512_F{k|b32}-VL - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Zmm, Zmm) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Zmm, Mem) // AVX512_F{k|b32} - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Xmm, Xmm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Xmm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Ymm, Ymm) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Ymm, Mem) // AVX512_F{k|b64}-VL - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Zmm, Zmm) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Zmm, Mem) // AVX512_F{k|b64} - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Xmm, Xmm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Xmm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Ymm, Ymm) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Ymm, Mem) // AVX512_BW{k}-VL - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Zmm, Zmm) // AVX512_BW{k} - ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Zmm, Mem) // AVX512_BW{k} - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Xmm, Xmm, Xmm) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Xmm, Xmm, Mem) // AVX AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Ymm, Ymm, Ymm) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Ymm, Ymm, Mem) // AVX2 AVX512_BW{kz}-VL - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Zmm, Zmm, Zmm) // AVX512_BW{kz} - ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Zmm, Zmm, Mem) // AVX512_BW{kz} - ASMJIT_INST_3x(vpxor, Vpxor, Xmm, Xmm, Xmm) // AVX - ASMJIT_INST_3x(vpxor, Vpxor, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vpxor, Vpxor, Ymm, Ymm, Ymm) // AVX2 - ASMJIT_INST_3x(vpxor, Vpxor, Ymm, Ymm, Mem) // AVX2 - ASMJIT_INST_3x(vpxord, Vpxord, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vpxord, Vpxord, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpxord, Vpxord, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vpxorq, Vpxorq, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vpxorq, Vpxorq, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vpxorq, Vpxorq, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vrangepd, Vrangepd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Ymm, Ymm, Ymm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_4i(vrangepd, Vrangepd, Zmm, Zmm, Zmm, Imm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_4i(vrangepd, Vrangepd, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz|sae|b64} - ASMJIT_INST_4i(vrangeps, Vrangeps, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Ymm, Ymm, Ymm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Ymm, Ymm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_4i(vrangeps, Vrangeps, Zmm, Zmm, Zmm, Imm) // AVX512_DQ{kz|sae|b32} - ASMJIT_INST_4i(vrangeps, Vrangeps, Zmm, Zmm, Mem, Imm) // AVX512_DQ{kz|sae|b32} + ASMJIT_INST_2x(vplzcntd, Vplzcntd, Vec, Vec) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vplzcntd, Vplzcntd, Vec, Mem) // AVX512_CD{kz|b32} + ASMJIT_INST_2x(vplzcntq, Vplzcntq, Vec, Vec) // AVX512_CD{kz|b64} + ASMJIT_INST_2x(vplzcntq, Vplzcntq, Vec, Mem) // AVX512_CD{kz|b64} + ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Vec, Vec, Vec) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52huq, Vpmadd52huq, Vec, Vec, Mem) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Vec, Vec, Vec) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmadd52luq, Vpmadd52luq, Vec, Vec, Mem) // AVX512_IFMA{kz|b64} + ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddubsw, Vpmaddubsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaddwd, Vpmaddwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Mem, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpmaskmovd, Vpmaskmovd, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Mem, Vec, Vec) // AVX2 + ASMJIT_INST_3x(vpmaskmovq, Vpmaskmovq, Vec, Vec, Mem) // AVX2 + ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsb, Vpmaxsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxsd, Vpmaxsd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxsq, Vpmaxsq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxsw, Vpmaxsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxub, Vpmaxub, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxub, Vpmaxub, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxud, Vpmaxud, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxud, Vpmaxud, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxuq, Vpmaxuq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmaxuw, Vpmaxuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsb, Vpminsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsb, Vpminsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsd, Vpminsd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminsd, Vpminsd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminsq, Vpminsq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminsq, Vpminsq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminsw, Vpminsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminsw, Vpminsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminub, Vpminub, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminub, Vpminub, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminud, Vpminud, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminud, Vpminud, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpminuq, Vpminuq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminuq, Vpminuq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpminuw, Vpminuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpminuw, Vpminuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovb2m, Vpmovb2m, KReg, Vec) // AVX512_BW + ASMJIT_INST_2x(vpmovd2m, Vpmovd2m, KReg, Vec) // AVX512_DQ + ASMJIT_INST_2x(vpmovdb, Vpmovdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdb, Vpmovdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdw, Vpmovdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovdw, Vpmovdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovm2b, Vpmovm2b, Vec, KReg) // AVX512_BW + ASMJIT_INST_2x(vpmovm2d, Vpmovm2d, Vec, KReg) // AVX512_DQ + ASMJIT_INST_2x(vpmovm2q, Vpmovm2q, Vec, KReg) // AVX512_DQ + ASMJIT_INST_2x(vpmovm2w, Vpmovm2w, Vec, KReg) // AVX512_BW + ASMJIT_INST_2x(vpmovmskb, Vpmovmskb, Gp, Vec) // AVX+ + ASMJIT_INST_2x(vpmovq2m, Vpmovq2m, KReg, Vec) // AVX512_DQ + ASMJIT_INST_2x(vpmovqb, Vpmovqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqb, Vpmovqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqd, Vpmovqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqd, Vpmovqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqw, Vpmovqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovqw, Vpmovqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdb, Vpmovsdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsdw, Vpmovsdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqb, Vpmovsqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqd, Vpmovsqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovsqw, Vpmovsqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovswb, Vpmovswb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovswb, Vpmovswb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbd, Vpmovsxbd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbq, Vpmovsxbq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxbw, Vpmovsxbw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxdq, Vpmovsxdq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwd, Vpmovsxwd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovsxwq, Vpmovsxwq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdb, Vpmovusdb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusdw, Vpmovusdw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqb, Vpmovusqb, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqd, Vpmovusqd, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovusqw, Vpmovusqw, Mem, Vec) // AVX512_F{kz} + ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovuswb, Vpmovuswb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovw2m, Vpmovw2m, KReg, Vec) // AVX512_BW + ASMJIT_INST_2x(vpmovwb, Vpmovwb, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovwb, Vpmovwb, Mem, Vec) // AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbd, Vpmovzxbd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbq, Vpmovzxbq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxbw, Vpmovzxbw, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxdq, Vpmovzxdq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwd, Vpmovzxwd, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_2x(vpmovzxwq, Vpmovzxwq, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpmuldq, Vpmuldq, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmuldq, Vpmuldq, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhrsw, Vpmulhrsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhuw, Vpmulhuw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhw, Vpmulhw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulhw, Vpmulhw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmulld, Vpmulld, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmulld, Vpmulld, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpmullq, Vpmullq, Vec, Vec, Vec) // AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vpmullq, Vpmullq, Vec, Vec, Mem) // AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vpmullw, Vpmullw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmullw, Vpmullw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Vec, Vec, Vec) // AVX512_VBMI{kz|b64} + ASMJIT_INST_3x(vpmultishiftqb, Vpmultishiftqb, Vec, Vec, Mem) // AVX512_VBMI{kz|b64} + ASMJIT_INST_3x(vpmuludq, Vpmuludq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpmuludq, Vpmuludq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_2x(vpopcntb, Vpopcntb, Vec, Vec) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntb, Vpopcntb, Vec, Mem) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntd, Vpopcntd, Vec, Vec) // AVX512_VPOPCNTDQ{kz|b32} + ASMJIT_INST_2x(vpopcntd, Vpopcntd, Vec, Mem) // AVX512_VPOPCNTDQ{kz|b32} + ASMJIT_INST_2x(vpopcntq, Vpopcntq, Vec, Vec) // AVX512_VPOPCNTDQ{kz|b64} + ASMJIT_INST_2x(vpopcntq, Vpopcntq, Vec, Mem) // AVX512_VPOPCNTDQ{kz|b64} + ASMJIT_INST_2x(vpopcntw, Vpopcntw, Vec, Vec) // AVX512_BITALG{kz|b32} + ASMJIT_INST_2x(vpopcntw, Vpopcntw, Vec, Mem) // AVX512_BITALG{kz|b32} + ASMJIT_INST_3x(vpor, Vpor, Vec, Vec, Vec) // AV+ + ASMJIT_INST_3x(vpor, Vpor, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpord, Vpord, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpord, Vpord, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vporq, Vporq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vporq, Vporq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprold, Vprold, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprold, Vprold, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprolq, Vprolq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprolq, Vprolq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprolvd, Vprolvd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprolvd, Vprolvd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprolvq, Vprolvq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprolvq, Vprolvq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprord, Vprord, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprord, Vprord, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vprorq, Vprorq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vprorq, Vprorq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprorvd, Vprorvd, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprorvd, Vprorvd, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vprorvq, Vprorvq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vprorvq, Vprorvq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsadbw, Vpsadbw, Vec, Vec, Vec) // AVX+ AVX512_BW + ASMJIT_INST_3x(vpsadbw, Vpsadbw, Vec, Vec, Mem) // AVX+ AVX512_BW + ASMJIT_INST_2x(vpscatterdd, Vpscatterdd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterdq, Vpscatterdq, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterqd, Vpscatterqd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vpscatterqq, Vpscatterqq, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_4i(vpshldd, Vpshldd, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshldd, Vpshldd, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvd, Vpshldvd, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvd, Vpshldvd, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvq, Vpshldvq, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvq, Vpshldvq, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvw, Vpshldvw, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshldvw, Vpshldvw, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdd, Vpshrdd, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdd, Vpshrdd, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvd, Vpshrdvd, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvq, Vpshrdvq, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Vec, Vec, Vec) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshrdvw, Vpshrdvw, Vec, Vec, Mem) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdw, Vpshrdw, Vec, Vec, Vec, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_4i(vpshrdw, Vpshrdw, Vec, Vec, Mem, Imm) // AVX512_VBMI2{kz} + ASMJIT_INST_3x(vpshufb, Vpshufb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpshufb, Vpshufb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Vec, Vec) // AVX512_BITALG{k} + ASMJIT_INST_3x(vpshufbitqmb, Vpshufbitqmb, KReg, Vec, Mem) // AVX512_BITALG{k} + ASMJIT_INST_3i(vpshufd, Vpshufd, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3i(vpshufd, Vpshufd, Vec, Mem, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3i(vpshufhw, Vpshufhw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshufhw, Vpshufhw, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshuflw, Vpshuflw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpshuflw, Vpshuflw, Vec, Mem, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsignb, Vpsignb, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignb, Vpsignb, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpsignd, Vpsignd, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignd, Vpsignd, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpsignw, Vpsignw, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpsignw, Vpsignw, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3i(vpslld, Vpslld, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpslld, Vpslld, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpslld, Vpslld, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpslld, Vpslld, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vpslldq, Vpslldq, Vec, Vec, Imm) // AVX+ AVX512_BW + ASMJIT_INST_3i(vpslldq, Vpslldq, Vec, Mem, Imm) // AVX512_BW + ASMJIT_INST_3i(vpsllq, Vpsllq, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllq, Vpsllq, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsllq, Vpsllq, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsllq, Vpsllq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvd, Vpsllvd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsllvd, Vpsllvd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsllvq, Vpsllvq, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvq, Vpsllvq, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsllvw, Vpsllvw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsllvw, Vpsllvw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsllw, Vpsllw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsllw, Vpsllw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsllw, Vpsllw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsllw, Vpsllw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrad, Vpsrad, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrad, Vpsrad, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsrad, Vpsrad, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsrad, Vpsrad, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsraq, Vpsraq, Vec, Vec, Vec) // AVX512_F{kz} + ASMJIT_INST_3x(vpsraq, Vpsraq, Vec, Vec, Mem) // AVX512_F{kz} + ASMJIT_INST_3i(vpsraq, Vpsraq, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vpsraq, Vpsraq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravd, Vpsravd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsravd, Vpsravd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsravq, Vpsravq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravq, Vpsravq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsravw, Vpsravw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsravw, Vpsravw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsraw, Vpsraw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsraw, Vpsraw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsraw, Vpsraw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsraw, Vpsraw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrld, Vpsrld, Vec, Vec, Imm) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrld, Vpsrld, Vec, Vec, Vec) // AVX+ AVX512_F{kz} + ASMJIT_INST_3x(vpsrld, Vpsrld, Vec, Vec, Mem) // AVX+ AVX512_F{kz} + ASMJIT_INST_3i(vpsrld, Vpsrld, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vpsrldq, Vpsrldq, Vec, Vec, Imm) // AVX+ AVX512_BW + ASMJIT_INST_3i(vpsrldq, Vpsrldq, Vec, Mem, Imm) // AVX512_BW + ASMJIT_INST_3i(vpsrlq, Vpsrlq, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlq, Vpsrlq, Vec, Vec, Vec) // AVX AVX512_F{kz} + ASMJIT_INST_3x(vpsrlq, Vpsrlq, Vec, Vec, Mem) // AVX AVX512_F{kz} + ASMJIT_INST_3i(vpsrlq, Vpsrlq, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrlvd, Vpsrlvd, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Vec, Vec, Vec) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvq, Vpsrlvq, Vec, Vec, Mem) // AVX2 AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Vec, Vec, Vec) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlvw, Vpsrlvw, Vec, Vec, Mem) // AVX512_BW{kz} + ASMJIT_INST_3i(vpsrlw, Vpsrlw, Vec, Vec, Imm) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlw, Vpsrlw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsrlw, Vpsrlw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3i(vpsrlw, Vpsrlw, Vec, Mem, Imm) // AVX512_BW{kz} + ASMJIT_INST_3x(vpsubb, Vpsubb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubb, Vpsubb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubd, Vpsubd, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsubd, Vpsubd, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpsubq, Vpsubq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsubq, Vpsubq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpsubsb, Vpsubsb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsb, Vpsubsb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsw, Vpsubsw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubsw, Vpsubsw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusb, Vpsubusb, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusb, Vpsubusb, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusw, Vpsubusw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubusw, Vpsubusw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpsubw, Vpsubw, Vec, Vec, Vec) // AVX AVX512_BW{kz} + ASMJIT_INST_3x(vpsubw, Vpsubw, Vec, Vec, Mem) // AVX AVX512_BW{kz} + ASMJIT_INST_4i(vpternlogd, Vpternlogd, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vpternlogd, Vpternlogd, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vpternlogq, Vpternlogq, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vpternlogq, Vpternlogq, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vptest, Vptest, Vec, Vec) // AVX + ASMJIT_INST_2x(vptest, Vptest, Vec, Mem) // AVX + ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmb, Vptestmb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestmd, Vptestmd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestmq, Vptestmq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestmw, Vptestmw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmb, Vptestnmb, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Vec, Vec) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestnmd, Vptestnmd, KReg, Vec, Mem) // AVX512_F{k|b32} + ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Vec, Vec) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestnmq, Vptestnmq, KReg, Vec, Mem) // AVX512_F{k|b64} + ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Vec, Vec) // AVX512_BW{k} + ASMJIT_INST_3x(vptestnmw, Vptestnmw, KReg, Vec, Mem) // AVX512_BW{k} + ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhbw, Vpunpckhbw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckhdq, Vpunpckhdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpckhqdq, Vpunpckhqdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckhwd, Vpunpckhwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklbw, Vpunpcklbw, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpckldq, Vpunpckldq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b32} + ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Vec, Vec, Vec) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpcklqdq, Vpunpcklqdq, Vec, Vec, Mem) // AVX+ AVX512_F{kz|b64} + ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Vec, Vec, Vec) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpunpcklwd, Vpunpcklwd, Vec, Vec, Mem) // AVX+ AVX512_BW{kz} + ASMJIT_INST_3x(vpxor, Vpxor, Vec, Vec, Vec) // AVX+ + ASMJIT_INST_3x(vpxor, Vpxor, Vec, Vec, Mem) // AVX+ + ASMJIT_INST_3x(vpxord, Vpxord, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpxord, Vpxord, Vec, Vec, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vpxorq, Vpxorq, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vpxorq, Vpxorq, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vrangepd, Vrangepd, Vec, Vec, Vec, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_4i(vrangepd, Vrangepd, Vec, Vec, Mem, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_4i(vrangeps, Vrangeps, Vec, Vec, Vec, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_4i(vrangeps, Vrangeps, Vec, Vec, Mem, Imm) // AVX512_DQ{kz|b32} ASMJIT_INST_4i(vrangesd, Vrangesd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangesd, Vrangesd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangess, Vrangess, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz|sae} ASMJIT_INST_4i(vrangess, Vrangess, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz|sae} - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrcp14pd, Vrcp14pd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrcp14ps, Vrcp14ps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vrcp14sd, Vrcp14sd, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14sd, Vrcp14sd, Xmm, Xmm, Mem) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14ss, Vrcp14ss, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrcp14ss, Vrcp14ss, Xmm, Xmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrcp28pd, Vrcp28pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrcp28ps, Vrcp28ps, Vec, Mem) // AVX512_ER{kz|sae|b32} ASMJIT_INST_3x(vrcp28sd, Vrcp28sd, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28sd, Vrcp28sd, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28ss, Vrcp28ss, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrcp28ss, Vrcp28ss, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} - ASMJIT_INST_2x(vrcpps, Vrcpps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vrcpps, Vrcpps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vrcpps, Vrcpps, Vec, Vec) // AVX + ASMJIT_INST_2x(vrcpps, Vrcpps, Vec, Mem) // AVX ASMJIT_INST_3x(vrcpss, Vrcpss, Xmm, Xmm, Xmm) // AVX ASMJIT_INST_3x(vrcpss, Vrcpss, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3i(vreducepd, Vreducepd, Xmm, Xmm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Xmm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Ymm, Ymm, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Ymm, Mem, Imm) // AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3i(vreducepd, Vreducepd, Zmm, Zmm, Imm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3i(vreducepd, Vreducepd, Zmm, Mem, Imm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3i(vreduceps, Vreduceps, Xmm, Xmm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Xmm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Ymm, Ymm, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Ymm, Mem, Imm) // AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3i(vreduceps, Vreduceps, Zmm, Zmm, Imm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3i(vreduceps, Vreduceps, Zmm, Mem, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_3i(vreducepd, Vreducepd, Vec, Vec, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_3i(vreducepd, Vreducepd, Vec, Mem, Imm) // AVX512_DQ{kz|b64} + ASMJIT_INST_3i(vreduceps, Vreduceps, Vec, Vec, Imm) // AVX512_DQ{kz|b32} + ASMJIT_INST_3i(vreduceps, Vreduceps, Vec, Mem, Imm) // AVX512_DQ{kz|b32} ASMJIT_INST_4i(vreducesd, Vreducesd, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducesd, Vreducesd, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducess, Vreducess, Xmm, Xmm, Xmm, Imm) // AVX512_DQ{kz} ASMJIT_INST_4i(vreducess, Vreducess, Xmm, Xmm, Mem, Imm) // AVX512_DQ{kz} - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Xmm, Xmm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Xmm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Zmm, Mem, Imm) // AVX512_F{kz|sae|b64} - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Xmm, Xmm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Xmm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Zmm, Zmm, Imm) // AVX512_F{kz|sae|b32} - ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Zmm, Mem, Imm) // AVX512_F{kz|sae|b32} + ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vrndscalepd, Vrndscalepd, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_3i(vrndscaleps, Vrndscaleps, Vec, Mem, Imm) // AVX512_F{kz|b32} ASMJIT_INST_4i(vrndscalesd, Vrndscalesd, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscalesd, Vrndscalesd, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscaless, Vrndscaless, Xmm, Xmm, Xmm, Imm) // AVX512_F{kz|sae} ASMJIT_INST_4i(vrndscaless, Vrndscaless, Xmm, Xmm, Mem, Imm) // AVX512_F{kz|sae} - ASMJIT_INST_3i(vroundpd, Vroundpd, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Xmm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vroundpd, Vroundpd, Ymm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Xmm, Xmm, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Xmm, Mem, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Ymm, Ymm, Imm) // AVX - ASMJIT_INST_3i(vroundps, Vroundps, Ymm, Mem, Imm) // AVX + ASMJIT_INST_3i(vroundpd, Vroundpd, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vroundpd, Vroundpd, Vec, Mem, Imm) // AVX + ASMJIT_INST_3i(vroundps, Vroundps, Vec, Vec, Imm) // AVX + ASMJIT_INST_3i(vroundps, Vroundps, Vec, Mem, Imm) // AVX ASMJIT_INST_4i(vroundsd, Vroundsd, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vroundsd, Vroundsd, Xmm, Xmm, Mem, Imm) // AVX ASMJIT_INST_4i(vroundss, Vroundss, Xmm, Xmm, Xmm, Imm) // AVX ASMJIT_INST_4i(vroundss, Vroundss, Xmm, Xmm, Mem, Imm) // AVX - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Zmm, Mem) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrsqrt14pd, Vrsqrt14pd, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_2x(vrsqrt14ps, Vrsqrt14ps, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vrsqrt14sd, Vrsqrt14sd, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14sd, Vrsqrt14sd, Xmm, Xmm, Mem) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14ss, Vrsqrt14ss, Xmm, Xmm, Xmm) // AVX512_F{kz} ASMJIT_INST_3x(vrsqrt14ss, Vrsqrt14ss, Xmm, Xmm, Mem) // AVX512_F{kz} - ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Zmm, Zmm) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Zmm, Mem) // AVX512_ER{kz|sae|b64} - ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Zmm, Zmm) // AVX512_ER{kz|sae|b32} - ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Zmm, Mem) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Vec, Vec) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrsqrt28pd, Vrsqrt28pd, Vec, Mem) // AVX512_ER{kz|sae|b64} + ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Vec, Vec) // AVX512_ER{kz|sae|b32} + ASMJIT_INST_2x(vrsqrt28ps, Vrsqrt28ps, Vec, Mem) // AVX512_ER{kz|sae|b32} ASMJIT_INST_3x(vrsqrt28sd, Vrsqrt28sd, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28sd, Vrsqrt28sd, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28ss, Vrsqrt28ss, Xmm, Xmm, Xmm) // AVX512_ER{kz|sae} ASMJIT_INST_3x(vrsqrt28ss, Vrsqrt28ss, Xmm, Xmm, Mem) // AVX512_ER{kz|sae} - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Vec, Vec) // AVX + ASMJIT_INST_2x(vrsqrtps, Vrsqrtps, Vec, Mem) // AVX ASMJIT_INST_3x(vrsqrtss, Vrsqrtss, Xmm, Xmm, Xmm) // AVX ASMJIT_INST_3x(vrsqrtss, Vrsqrtss, Xmm, Xmm, Mem) // AVX - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Xmm, Xmm, Xmm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Xmm, Xmm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Ymm, Ymm, Ymm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Ymm, Ymm, Mem) // AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vscalefpd, Vscalefpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vscalefps, Vscalefps, Xmm, Xmm, Xmm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Xmm, Xmm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Ymm, Ymm, Ymm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Ymm, Ymm, Mem) // AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vscalefps, Vscalefps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vscalefps, Vscalefps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vscalefpd, Vscalefpd, Vec, Vec, Vec) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vscalefpd, Vscalefpd, Vec, Vec, Mem) // AVX512_F{kz|b64} + ASMJIT_INST_3x(vscalefps, Vscalefps, Vec, Vec, Vec) // AVX512_F{kz|b32} + ASMJIT_INST_3x(vscalefps, Vscalefps, Vec, Vec, Mem) // AVX512_F{kz|b32} ASMJIT_INST_3x(vscalefsd, Vscalefsd, Xmm, Xmm, Xmm) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefsd, Vscalefsd, Xmm, Xmm, Mem) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefss, Vscalefss, Xmm, Xmm, Xmm) // AVX512_F{kz|er} ASMJIT_INST_3x(vscalefss, Vscalefss, Xmm, Xmm, Mem) // AVX512_F{kz|er} - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Zmm) // AVX512_F{k} + ASMJIT_INST_2x(vscatterdpd, Vscatterdpd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vscatterdps, Vscatterdps, Mem, Vec) // AVX512_F{k} ASMJIT_INST_1x(vscatterpf0dpd, Vscatterpf0dpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf0dps, Vscatterpf0dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf0qpd, Vscatterpf0qpd, Mem) // AVX512_PF{k} @@ -4896,120 +3251,57 @@ public: ASMJIT_INST_1x(vscatterpf1dps, Vscatterpf1dps, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf1qpd, Vscatterpf1qpd, Mem) // AVX512_PF{k} ASMJIT_INST_1x(vscatterpf1qps, Vscatterpf1qps, Mem) // AVX512_PF{k} - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Ymm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Zmm) // AVX512_F{k} - ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Xmm) // AVX512_F{k}-VL - ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Ymm) // AVX512_F{k} - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Ymm, Ymm, Ymm, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Ymm, Ymm, Mem, Imm) // AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufpd, Vshufpd, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Xmm, Xmm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Ymm, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Ymm, Ymm, Mem, Imm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_4i(vshufpd, Vshufpd, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufpd, Vshufpd, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b32} - ASMJIT_INST_4i(vshufps, Vshufps, Xmm, Xmm, Xmm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Xmm, Xmm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Ymm, Ymm, Ymm, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Ymm, Ymm, Mem, Imm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_4i(vshufps, Vshufps, Zmm, Zmm, Zmm, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_4i(vshufps, Vshufps, Zmm, Zmm, Mem, Imm) // AVX512_F{kz|b64} - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_2x(vsqrtps, Vsqrtps, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_2x(vscatterqpd, Vscatterqpd, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_2x(vscatterqps, Vscatterqps, Mem, Vec) // AVX512_F{k} + ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshuff32x4, Vshuff32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshuff64x2, Vshuff64x2, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Vec, Vec, Vec, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufi32x4, Vshufi32x4, Vec, Vec, Mem, Imm) // AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Vec, Vec, Vec, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufi64x2, Vshufi64x2, Vec, Vec, Mem, Imm) // AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufpd, Vshufpd, Vec, Vec, Vec, Imm) // AVX AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufpd, Vshufpd, Vec, Vec, Mem, Imm) // AVX AVX512_F{kz|b32} + ASMJIT_INST_4i(vshufps, Vshufps, Vec, Vec, Vec, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_4i(vshufps, Vshufps, Vec, Vec, Mem, Imm) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtpd, Vsqrtpd, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_2x(vsqrtps, Vsqrtps, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_2x(vsqrtps, Vsqrtps, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vsqrtsd, Vsqrtsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtsd, Vsqrtsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtss, Vsqrtss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsqrtss, Vsqrtss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_1x(vstmxcsr, Vstmxcsr, Mem) // AVX - ASMJIT_INST_3x(vsubpd, Vsubpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vsubpd, Vsubpd, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vsubpd, Vsubpd, Zmm, Zmm, Mem) // AVX512_F{kz|er|b64} - ASMJIT_INST_3x(vsubps, Vsubps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Ymm, Ymm, Ymm) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Ymm, Ymm, Mem) // AVX2 AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vsubps, Vsubps, Zmm, Zmm, Zmm) // AVX512_F{kz|er|b32} - ASMJIT_INST_3x(vsubps, Vsubps, Zmm, Zmm, Mem) // AVX512_F{kz|er|b32} + ASMJIT_INST_3x(vsubpd, Vsubpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vsubpd, Vsubpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vsubps, Vsubps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vsubps, Vsubps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} ASMJIT_INST_3x(vsubsd, Vsubsd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubsd, Vsubsd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubss, Vsubss, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|er} ASMJIT_INST_3x(vsubss, Vsubss, Xmm, Xmm, Mem) // AVX AVX512_F{kz|er} - ASMJIT_INST_2x(vtestpd, Vtestpd, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Xmm, Mem) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vtestpd, Vtestpd, Ymm, Mem) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Xmm, Xmm) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Xmm, Mem) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Ymm, Ymm) // AVX - ASMJIT_INST_2x(vtestps, Vtestps, Ymm, Mem) // AVX + ASMJIT_INST_2x(vtestpd, Vtestpd, Vec, Vec) // AVX + ASMJIT_INST_2x(vtestpd, Vtestpd, Vec, Mem) // AVX + ASMJIT_INST_2x(vtestps, Vtestps, Vec, Vec) // AVX + ASMJIT_INST_2x(vtestps, Vtestps, Vec, Mem) // AVX ASMJIT_INST_2x(vucomisd, Vucomisd, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomisd, Vucomisd, Xmm, Mem) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomiss, Vucomiss, Xmm, Xmm) // AVX AVX512_F{sae} ASMJIT_INST_2x(vucomiss, Vucomiss, Xmm, Mem) // AVX AVX512_F{sae} - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpckhps, Vunpckhps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b64}-VL - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Zmm, Zmm, Zmm) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Zmm, Zmm, Mem) // AVX512_F{kz|b64} - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Xmm, Xmm, Xmm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Xmm, Xmm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Ymm, Ymm, Ymm) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Ymm, Ymm, Mem) // AVX AVX512_F{kz|b32}-VL - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Zmm, Zmm, Zmm) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vunpcklps, Vunpcklps, Zmm, Zmm, Mem) // AVX512_F{kz|b32} - ASMJIT_INST_3x(vxorpd, Vxorpd, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b64}-VL - ASMJIT_INST_3x(vxorpd, Vxorpd, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vxorpd, Vxorpd, Zmm, Zmm, Mem) // AVX512_DQ{kz|b64} - ASMJIT_INST_3x(vxorps, Vxorps, Xmm, Xmm, Xmm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Xmm, Xmm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Ymm, Ymm, Ymm) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Ymm, Ymm, Mem) // AVX AVX512_DQ{kz|b32}-VL - ASMJIT_INST_3x(vxorps, Vxorps, Zmm, Zmm, Zmm) // AVX512_DQ{kz|b32} - ASMJIT_INST_3x(vxorps, Vxorps, Zmm, Zmm, Mem) // AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpckhpd, Vunpckhpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpckhps, Vunpckhps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpckhps, Vunpckhps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Vec, Vec, Vec) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpcklpd, Vunpcklpd, Vec, Vec, Mem) // AVX AVX512_F{kz|b64} + ASMJIT_INST_3x(vunpcklps, Vunpcklps, Vec, Vec, Vec) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vunpcklps, Vunpcklps, Vec, Vec, Mem) // AVX AVX512_F{kz|b32} + ASMJIT_INST_3x(vxorpd, Vxorpd, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vxorpd, Vxorpd, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b64} + ASMJIT_INST_3x(vxorps, Vxorps, Vec, Vec, Vec) // AVX AVX512_DQ{kz|b32} + ASMJIT_INST_3x(vxorps, Vxorps, Vec, Vec, Mem) // AVX AVX512_DQ{kz|b32} ASMJIT_INST_0x(vzeroall, Vzeroall) // AVX ASMJIT_INST_0x(vzeroupper, Vzeroupper) // AVX @@ -5018,96 +3310,60 @@ public: //! \name FMA4 Instructions //! \{ - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddps, Vfmaddps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddpd, Vfmaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddps, Vfmaddps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddsd, Vfmaddsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmaddss, Vfmaddss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfmsubps, Vfmsubps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubpd, Vfmaddsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmaddsubps, Vfmaddsubps, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddpd, Vfmsubaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubaddps, Vfmsubaddps, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubpd, Vfmsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfmsubps, Vfmsubps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubsd, Vfmsubsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfmsubss, Vfmsubss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddpd, Vfnmaddpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmaddps, Vfnmaddps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddsd, Vfnmaddsd, Xmm, Xmm, Xmm, Mem) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmaddss, Vfnmaddss, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Ymm, Ymm, Ymm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Xmm, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Mem, Xmm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Xmm, Xmm, Xmm, Mem) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Ymm, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Mem, Ymm) // FMA4 - ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Ymm, Ymm, Ymm, Mem) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubpd, Vfnmsubpd, Vec, Vec, Vec, Mem) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Vec, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Mem, Vec) // FMA4 + ASMJIT_INST_4x(vfnmsubps, Vfnmsubps, Vec, Vec, Vec, Mem) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Xmm, Xmm) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Mem, Xmm) // FMA4 ASMJIT_INST_4x(vfnmsubsd, Vfnmsubsd, Xmm, Xmm, Xmm, Mem) // FMA4 @@ -5120,24 +3376,17 @@ public: //! \name XOP Instructions (Deprecated) //! \{ - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Xmm, Xmm) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Xmm, Mem) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Ymm, Ymm) // XOP - ASMJIT_INST_2x(vfrczpd, Vfrczpd, Ymm, Mem) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Xmm, Xmm) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Xmm, Mem) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Ymm, Ymm) // XOP - ASMJIT_INST_2x(vfrczps, Vfrczps, Ymm, Mem) // XOP + ASMJIT_INST_2x(vfrczpd, Vfrczpd, Vec, Vec) // XOP + ASMJIT_INST_2x(vfrczpd, Vfrczpd, Vec, Mem) // XOP + ASMJIT_INST_2x(vfrczps, Vfrczps, Vec, Vec) // XOP + ASMJIT_INST_2x(vfrczps, Vfrczps, Vec, Mem) // XOP ASMJIT_INST_2x(vfrczsd, Vfrczsd, Xmm, Xmm) // XOP ASMJIT_INST_2x(vfrczsd, Vfrczsd, Xmm, Mem) // XOP ASMJIT_INST_2x(vfrczss, Vfrczss, Xmm, Xmm) // XOP ASMJIT_INST_2x(vfrczss, Vfrczss, Xmm, Mem) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Xmm, Xmm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Mem, Xmm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Xmm, Xmm, Xmm, Mem) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Ymm, Ymm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Mem, Ymm) // XOP - ASMJIT_INST_4x(vpcmov, Vpcmov, Ymm, Ymm, Ymm, Mem) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Vec, Vec) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Mem, Vec) // XOP + ASMJIT_INST_4x(vpcmov, Vpcmov, Vec, Vec, Vec, Mem) // XOP ASMJIT_INST_4i(vpcomb, Vpcomb, Xmm, Xmm, Xmm, Imm) // XOP ASMJIT_INST_4i(vpcomb, Vpcomb, Xmm, Xmm, Mem, Imm) // XOP ASMJIT_INST_4i(vpcomd, Vpcomd, Xmm, Xmm, Xmm, Imm) // XOP @@ -5154,18 +3403,12 @@ public: ASMJIT_INST_4i(vpcomuq, Vpcomuq, Xmm, Xmm, Mem, Imm) // XOP ASMJIT_INST_4i(vpcomuw, Vpcomuw, Xmm, Xmm, Xmm, Imm) // XOP ASMJIT_INST_4i(vpcomuw, Vpcomuw, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Xmm, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Mem, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Xmm, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Ymm, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Mem, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Ymm, Ymm, Ymm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Xmm, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Mem, Xmm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Xmm, Xmm, Xmm, Mem, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Ymm, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Mem, Ymm, Imm) // XOP - ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Ymm, Ymm, Ymm, Mem, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Vec, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Mem, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2pd, Vpermil2pd, Vec, Vec, Vec, Mem, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Vec, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Mem, Vec, Imm) // XOP + ASMJIT_INST_5i(vpermil2ps, Vpermil2ps, Vec, Vec, Vec, Mem, Imm) // XOP ASMJIT_INST_2x(vphaddbd, Vphaddbd, Xmm, Xmm) // XOP ASMJIT_INST_2x(vphaddbd, Vphaddbd, Xmm, Mem) // XOP ASMJIT_INST_2x(vphaddbq, Vphaddbq, Xmm, Xmm) // XOP diff --git a/3rdparty/asmjit/src/asmjit/x86/x86features.cpp b/3rdparty/asmjit/src/asmjit/x86/x86features.cpp index 6ee5772374b..7c9505da197 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86features.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86features.cpp @@ -106,22 +106,25 @@ static inline void simplifyCpuVendor(CpuInfo& cpu, uint32_t d0, uint32_t d1, uin } static inline void simplifyCpuBrand(char* s) noexcept { - // Used to always clear the current character to ensure that the result - // doesn't contain garbage after the new zero terminator. char* d = s; + char c = s[0]; char prev = 0; - char curr = s[0]; + + // Used to always clear the current character to ensure that the result + // doesn't contain garbage after a new null terminator is placed at the end. s[0] = '\0'; for (;;) { - if (curr == 0) + if (!c) break; - if (!(curr == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) - *d++ = prev = curr; + if (!(c == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) { + *d++ = c; + prev = c; + } - curr = *++s; + c = *++s; s[0] = '\0'; } @@ -136,7 +139,9 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept { Features& features = cpu._features.as<Features>(); cpu.reset(); - cpu._archInfo.init(ArchInfo::kIdHost); + cpu._arch = Environment::kArchHost; + cpu._subArch = Environment::kSubArchUnknown; + cpu._reserved = 0; cpu._maxLogicalProcessors = 1; features.add(Features::kI486); diff --git a/3rdparty/asmjit/src/asmjit/x86/x86features.h b/3rdparty/asmjit/src/asmjit/x86/x86features.h index d73c063877f..b26b52454b1 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86features.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86features.h @@ -40,6 +40,8 @@ class Features : public BaseFeatures { public: //! CPU feature ID. enum Id : uint32_t { + // @EnumValuesBegin{"enum": "x86::Features::Id"}@ + kNone = 0, //!< No feature (never set, used internally). kMT, //!< CPU has multi-threading capabilities. @@ -145,6 +147,8 @@ public: kXSAVEOPT, //!< CPU has XSAVEOPT. kXSAVES, //!< CPU has XSAVES. + // @EnumValuesEnd@ + kCount //!< Count of X86 CPU features. }; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86logging.cpp b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp index cfb91dbf596..06553e401e0 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86logging.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp @@ -26,8 +26,9 @@ #include "../core/misc_p.h" #include "../core/support.h" +#include "../x86/x86features.h" +#include "../x86/x86formatter_p.h" #include "../x86/x86instdb_p.h" -#include "../x86/x86logging_p.h" #include "../x86/x86operand.h" #ifndef ASMJIT_NO_COMPILER @@ -37,7 +38,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // ============================================================================ -// [asmjit::x86::LoggingInternal - Constants] +// [asmjit::x86::FormatterInternal - Constants] // ============================================================================ struct RegFormatInfo { @@ -196,56 +197,181 @@ static const char* x86GetAddressSizeString(uint32_t size) noexcept { } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Operand] +// [asmjit::x86::FormatterInternal - Format Feature] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( +Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept { + // @EnumStringBegin{"enum": "x86::Features::Id", "output": "sFeature", "strip": "k"}@ + static const char sFeatureString[] = + "None\0" + "MT\0" + "NX\0" + "3DNOW\0" + "3DNOW2\0" + "ADX\0" + "AESNI\0" + "ALTMOVCR8\0" + "AVX\0" + "AVX2\0" + "AVX512_4FMAPS\0" + "AVX512_4VNNIW\0" + "AVX512_BF16\0" + "AVX512_BITALG\0" + "AVX512_BW\0" + "AVX512_CDI\0" + "AVX512_DQ\0" + "AVX512_ERI\0" + "AVX512_F\0" + "AVX512_IFMA\0" + "AVX512_PFI\0" + "AVX512_VBMI\0" + "AVX512_VBMI2\0" + "AVX512_VL\0" + "AVX512_VNNI\0" + "AVX512_VP2INTERSECT\0" + "AVX512_VPOPCNTDQ\0" + "BMI\0" + "BMI2\0" + "CLDEMOTE\0" + "CLFLUSH\0" + "CLFLUSHOPT\0" + "CLWB\0" + "CLZERO\0" + "CMOV\0" + "CMPXCHG16B\0" + "CMPXCHG8B\0" + "ENCLV\0" + "ENQCMD\0" + "ERMS\0" + "F16C\0" + "FMA\0" + "FMA4\0" + "FPU\0" + "FSGSBASE\0" + "FXSR\0" + "FXSROPT\0" + "GEODE\0" + "GFNI\0" + "HLE\0" + "I486\0" + "LAHFSAHF\0" + "LWP\0" + "LZCNT\0" + "MMX\0" + "MMX2\0" + "MONITOR\0" + "MONITORX\0" + "MOVBE\0" + "MOVDIR64B\0" + "MOVDIRI\0" + "MPX\0" + "MSR\0" + "MSSE\0" + "OSXSAVE\0" + "PCLMULQDQ\0" + "PCOMMIT\0" + "PCONFIG\0" + "POPCNT\0" + "PREFETCHW\0" + "PREFETCHWT1\0" + "RDPID\0" + "RDRAND\0" + "RDSEED\0" + "RDTSC\0" + "RDTSCP\0" + "RTM\0" + "SHA\0" + "SKINIT\0" + "SMAP\0" + "SMEP\0" + "SMX\0" + "SSE\0" + "SSE2\0" + "SSE3\0" + "SSE4_1\0" + "SSE4_2\0" + "SSE4A\0" + "SSSE3\0" + "SVM\0" + "TBM\0" + "TSX\0" + "VAES\0" + "VMX\0" + "VPCLMULQDQ\0" + "WAITPKG\0" + "WBNOINVD\0" + "XOP\0" + "XSAVE\0" + "XSAVEC\0" + "XSAVEOPT\0" + "XSAVES\0" + "<Unknown>\0"; + + static const uint16_t sFeatureIndex[] = { + 0, 5, 8, 11, 17, 24, 28, 34, 44, 48, 53, 67, 81, 93, 107, 117, 128, 138, + 149, 158, 170, 181, 193, 206, 216, 228, 248, 265, 269, 274, 283, 291, 302, + 307, 314, 319, 330, 340, 346, 353, 358, 363, 367, 372, 376, 385, 390, 398, + 404, 409, 413, 418, 427, 431, 437, 441, 446, 454, 463, 469, 479, 487, 491, + 495, 500, 508, 518, 526, 534, 541, 551, 563, 569, 576, 583, 589, 596, 600, + 604, 611, 616, 621, 625, 629, 634, 639, 646, 653, 659, 665, 669, 673, 677, + 682, 686, 697, 705, 714, 718, 724, 731, 740, 747 + }; + // @EnumStringEnd@ + + return sb.append(sFeatureString + sFeatureIndex[Support::min<uint32_t>(featureId, x86::Features::kCount)]); +} + +// ============================================================================ +// [asmjit::x86::FormatterInternal - Format Operand] +// ============================================================================ + +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand( String& sb, uint32_t flags, const BaseEmitter* emitter, - uint32_t archId, + uint32_t arch, const Operand_& op) noexcept { if (op.isReg()) - return formatRegister(sb, flags, emitter, archId, op.as<BaseReg>().type(), op.as<BaseReg>().id()); + return formatRegister(sb, flags, emitter, arch, op.as<BaseReg>().type(), op.as<BaseReg>().id()); if (op.isMem()) { const Mem& m = op.as<Mem>(); - ASMJIT_PROPAGATE(sb.appendString(x86GetAddressSizeString(m.size()))); + ASMJIT_PROPAGATE(sb.append(x86GetAddressSizeString(m.size()))); // Segment override prefix. uint32_t seg = m.segmentId(); if (seg != SReg::kIdNone && seg < SReg::kIdCount) - ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + seg * 4)); + ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + size_t(seg) * 4)); - ASMJIT_PROPAGATE(sb.appendChar('[')); + ASMJIT_PROPAGATE(sb.append('[')); switch (m.addrType()) { - case BaseMem::kAddrTypeAbs: ASMJIT_PROPAGATE(sb.appendString("abs ")); break; - case BaseMem::kAddrTypeRel: ASMJIT_PROPAGATE(sb.appendString("rel ")); break; + case BaseMem::kAddrTypeAbs: ASMJIT_PROPAGATE(sb.append("abs ")); break; + case BaseMem::kAddrTypeRel: ASMJIT_PROPAGATE(sb.append("rel ")); break; } char opSign = '\0'; if (m.hasBase()) { opSign = '+'; if (m.hasBaseLabel()) { - ASMJIT_PROPAGATE(Logging::formatLabel(sb, flags, emitter, m.baseId())); + ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId())); } else { uint32_t modifiedFlags = flags; if (m.isRegHome()) { - ASMJIT_PROPAGATE(sb.appendString("&")); + ASMJIT_PROPAGATE(sb.append("&")); modifiedFlags &= ~FormatOptions::kFlagRegCasts; } - ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, archId, m.baseType(), m.baseId())); + ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId())); } } if (m.hasIndex()) { if (opSign) - ASMJIT_PROPAGATE(sb.appendChar(opSign)); + ASMJIT_PROPAGATE(sb.append(opSign)); opSign = '+'; - ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, archId, m.indexType(), m.indexId())); + ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId())); if (m.hasShift()) ASMJIT_PROPAGATE(sb.appendFormat("*%u", 1 << m.shift())); } @@ -258,26 +384,26 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( } if (opSign) - ASMJIT_PROPAGATE(sb.appendChar(opSign)); + ASMJIT_PROPAGATE(sb.append(opSign)); uint32_t base = 10; if ((flags & FormatOptions::kFlagHexOffsets) != 0 && off > 9) { - ASMJIT_PROPAGATE(sb.appendString("0x", 2)); + ASMJIT_PROPAGATE(sb.append("0x", 2)); base = 16; } ASMJIT_PROPAGATE(sb.appendUInt(off, base)); } - return sb.appendChar(']'); + return sb.append(']'); } if (op.isImm()) { const Imm& i = op.as<Imm>(); - int64_t val = i.i64(); + int64_t val = i.value(); if ((flags & FormatOptions::kFlagHexImms) != 0 && uint64_t(val) > 9) { - ASMJIT_PROPAGATE(sb.appendString("0x", 2)); + ASMJIT_PROPAGATE(sb.append("0x", 2)); return sb.appendUInt(uint64_t(val), 16); } else { @@ -286,14 +412,14 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatOperand( } if (op.isLabel()) { - return Logging::formatLabel(sb, flags, emitter, op.id()); + return Formatter::formatLabel(sb, flags, emitter, op.id()); } - return sb.appendString("<None>"); + return sb.append("<None>"); } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Immediate (Extension)] +// [asmjit::x86::FormatterInternal - Format Immediate (Extension)] // ============================================================================ static constexpr char kImmCharStart = '{'; @@ -312,22 +438,22 @@ struct ImmBits { char text[48 - 3]; }; -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { uint32_t mask = (1 << bits) - 1; for (uint32_t i = 0; i < count; i++, u8 >>= bits) { uint32_t value = u8 & mask; - ASMJIT_PROPAGATE(sb.appendChar(i == 0 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); ASMJIT_PROPAGATE(sb.appendUInt(value)); } if (kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { uint32_t n = 0; char buf[64]; @@ -354,33 +480,33 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmBits(String& sb, uint32_ if (!str[0]) continue; - ASMJIT_PROPAGATE(sb.appendChar(++n == 1 ? kImmCharStart : kImmCharOr)); - ASMJIT_PROPAGATE(sb.appendString(str)); + ASMJIT_PROPAGATE(sb.append(++n == 1 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(str)); } if (n && kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { +ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { uint32_t mask = (1u << bits) - 1; uint32_t pos = 0; for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) { uint32_t value = (u8 & mask) + pos; - ASMJIT_PROPAGATE(sb.appendChar(i == 0 ? kImmCharStart : kImmCharOr)); - ASMJIT_PROPAGATE(sb.appendString(Support::findPackedString(text, value))); + ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr)); + ASMJIT_PROPAGATE(sb.append(Support::findPackedString(text, value))); } if (kImmCharEnd) - ASMJIT_PROPAGATE(sb.appendChar(kImmCharEnd)); + ASMJIT_PROPAGATE(sb.append(kImmCharEnd)); return kErrorOk; } -ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( +ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst( String& sb, uint32_t flags, uint32_t instId, @@ -456,51 +582,51 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( { 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" } }; - uint32_t u8 = imm.u8(); + uint32_t u8 = imm.valueAs<uint8_t>(); switch (instId) { case Inst::kIdVblendpd: case Inst::kIdBlendpd: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8); case Inst::kIdVblendps: case Inst::kIdBlendps: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 4); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 4); case Inst::kIdVcmppd: case Inst::kIdVcmpps: case Inst::kIdVcmpsd: case Inst::kIdVcmpss: - return LoggingInternal_formatImmText(sb, u8, 5, 0, vcmpx); + return FormatterInternal_formatImmText(sb, u8, 5, 0, vcmpx); case Inst::kIdCmppd: case Inst::kIdCmpps: case Inst::kIdCmpsd: case Inst::kIdCmpss: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vcmpx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx); case Inst::kIdVdbpsadbw: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVdppd: case Inst::kIdVdpps: case Inst::kIdDppd: case Inst::kIdDpps: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVmpsadbw: case Inst::kIdMpsadbw: - return LoggingInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4)); + return FormatterInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4)); case Inst::kIdVpblendw: case Inst::kIdPblendw: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVpblendd: - return LoggingInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8)); + return FormatterInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8)); case Inst::kIdVpclmulqdq: case Inst::kIdPclmulqdq: - return LoggingInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); + return FormatterInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); case Inst::kIdVroundpd: case Inst::kIdVroundps: @@ -510,57 +636,57 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdRoundps: case Inst::kIdRoundsd: case Inst::kIdRoundss: - return LoggingInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); + return FormatterInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); case Inst::kIdVshufpd: case Inst::kIdShufpd: - return LoggingInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8)); + return FormatterInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8)); case Inst::kIdVshufps: case Inst::kIdShufps: - return LoggingInternal_formatImmText(sb, u8, 2, 4, vshufps, 4); + return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4); case Inst::kIdVcvtps2ph: - return LoggingInternal_formatImmBits(sb, u8, vroundxx, 1); + return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1); case Inst::kIdVperm2f128: case Inst::kIdVperm2i128: - return LoggingInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); + return FormatterInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); case Inst::kIdVpermilpd: - return LoggingInternal_formatImmShuf(sb, u8, 1, vecSize / 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8); case Inst::kIdVpermilps: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpshufd: case Inst::kIdPshufd: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpshufhw: case Inst::kIdVpshuflw: case Inst::kIdPshufhw: case Inst::kIdPshuflw: case Inst::kIdPshufw: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVfixupimmpd: case Inst::kIdVfixupimmps: case Inst::kIdVfixupimmsd: case Inst::kIdVfixupimmss: - return LoggingInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx)); + return FormatterInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx)); case Inst::kIdVfpclasspd: case Inst::kIdVfpclassps: case Inst::kIdVfpclasssd: case Inst::kIdVfpclassss: - return LoggingInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); + return FormatterInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); case Inst::kIdVgetmantpd: case Inst::kIdVgetmantps: case Inst::kIdVgetmantsd: case Inst::kIdVgetmantss: - return LoggingInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); + return FormatterInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); case Inst::kIdVpcmpb: case Inst::kIdVpcmpd: @@ -570,7 +696,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVpcmpud: case Inst::kIdVpcmpuq: case Inst::kIdVpcmpuw: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vpcmpx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcmpx); case Inst::kIdVpcomb: case Inst::kIdVpcomd: @@ -580,21 +706,21 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVpcomud: case Inst::kIdVpcomuq: case Inst::kIdVpcomuw: - return LoggingInternal_formatImmText(sb, u8, 3, 0, vpcomx); + return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcomx); case Inst::kIdVpermq: case Inst::kIdVpermpd: - return LoggingInternal_formatImmShuf(sb, u8, 2, 4); + return FormatterInternal_formatImmShuf(sb, u8, 2, 4); case Inst::kIdVpternlogd: case Inst::kIdVpternlogq: - return LoggingInternal_formatImmShuf(sb, u8, 1, 8); + return FormatterInternal_formatImmShuf(sb, u8, 1, 8); case Inst::kIdVrangepd: case Inst::kIdVrangeps: case Inst::kIdVrangesd: case Inst::kIdVrangess: - return LoggingInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); + return FormatterInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); case Inst::kIdVreducepd: case Inst::kIdVreduceps: @@ -604,7 +730,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVrndscaleps: case Inst::kIdVrndscalesd: case Inst::kIdVrndscaless: - return LoggingInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); + return FormatterInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); case Inst::kIdVshuff32x4: case Inst::kIdVshuff64x2: @@ -612,7 +738,7 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( case Inst::kIdVshufi64x2: { uint32_t count = Support::max<uint32_t>(vecSize / 16, 2u); uint32_t bits = count <= 2 ? 1u : 2u; - return LoggingInternal_formatImmShuf(sb, u8, bits, count); + return FormatterInternal_formatImmShuf(sb, u8, bits, count); } default: @@ -621,11 +747,11 @@ ASMJIT_FAVOR_SIZE static Error LoggingInternal_explainConst( } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Register] +// [asmjit::x86::FormatterInternal - Format Register] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t flags, const BaseEmitter* emitter, uint32_t archId, uint32_t rType, uint32_t rId) noexcept { - DebugUtils::unused(archId); +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, uint32_t flags, const BaseEmitter* emitter, uint32_t arch, uint32_t rType, uint32_t rId) noexcept { + DebugUtils::unused(arch); const RegFormatInfo& info = x86RegFormatInfo; #ifndef ASMJIT_NO_COMPILER @@ -638,7 +764,7 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla const char* name = vReg->name(); if (name && name[0] != '\0') - ASMJIT_PROPAGATE(sb.appendString(name)); + ASMJIT_PROPAGATE(sb.append(name)); else ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId)))); @@ -660,7 +786,7 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla const RegFormatInfo::NameEntry& nameEntry = info.nameEntries[rType]; if (rId < nameEntry.specialCount) - return sb.appendString(info.nameStrings + nameEntry.specialIndex + rId * 4); + return sb.append(info.nameStrings + nameEntry.specialIndex + rId * 4); if (rId < nameEntry.count) return sb.appendFormat(info.nameStrings + nameEntry.formatIndex, unsigned(rId)); @@ -674,15 +800,15 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatRegister(String& sb, uint32_t fla } // ============================================================================ -// [asmjit::x86::LoggingInternal - Format Instruction] +// [asmjit::x86::FormatterInternal - Format Instruction] // ============================================================================ -ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( +ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction( String& sb, uint32_t flags, const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept { uint32_t instId = inst.id(); uint32_t options = inst.options(); @@ -690,21 +816,21 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( // Format instruction options and instruction mnemonic. if (instId < Inst::_kIdCount) { // SHORT|LONG options. - if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short ")); - if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long ")); + if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.append("short ")); + if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.append("long ")); // LOCK|XACQUIRE|XRELEASE options. - if (options & Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.appendString("xacquire ")); - if (options & Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.appendString("xrelease ")); - if (options & Inst::kOptionLock) ASMJIT_PROPAGATE(sb.appendString("lock ")); + if (options & Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.append("xacquire ")); + if (options & Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.append("xrelease ")); + if (options & Inst::kOptionLock) ASMJIT_PROPAGATE(sb.append("lock ")); // REP|REPNE options. if (options & (Inst::kOptionRep | Inst::kOptionRepne)) { - sb.appendString((options & Inst::kOptionRep) ? "rep " : "repnz "); + sb.append((options & Inst::kOptionRep) ? "rep " : "repnz "); if (inst.hasExtraReg()) { - ASMJIT_PROPAGATE(sb.appendString("{")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, archId, inst.extraReg().toReg<BaseReg>())); - ASMJIT_PROPAGATE(sb.appendString("} ")); + ASMJIT_PROPAGATE(sb.append("{")); + ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, inst.extraReg().toReg<BaseReg>())); + ASMJIT_PROPAGATE(sb.append("} ")); } } @@ -715,23 +841,23 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( Inst::kOptionOpCodeB | Inst::kOptionOpCodeW ; if (options & kRXBWMask) { - sb.appendString("rex."); - if (options & Inst::kOptionOpCodeR) sb.appendChar('r'); - if (options & Inst::kOptionOpCodeX) sb.appendChar('x'); - if (options & Inst::kOptionOpCodeB) sb.appendChar('b'); - if (options & Inst::kOptionOpCodeW) sb.appendChar('w'); - sb.appendChar(' '); + sb.append("rex."); + if (options & Inst::kOptionOpCodeR) sb.append('r'); + if (options & Inst::kOptionOpCodeX) sb.append('x'); + if (options & Inst::kOptionOpCodeB) sb.append('b'); + if (options & Inst::kOptionOpCodeW) sb.append('w'); + sb.append(' '); } else { - ASMJIT_PROPAGATE(sb.appendString("rex ")); + ASMJIT_PROPAGATE(sb.append("rex ")); } } // VEX|EVEX options. - if (options & Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.appendString("vex3 ")); - if (options & Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.appendString("evex ")); + if (options & Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.append("vex3 ")); + if (options & Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.append("evex ")); - ASMJIT_PROPAGATE(InstAPI::instIdToString(archId, instId, sb)); + ASMJIT_PROPAGATE(InstAPI::instIdToString(arch, instId, sb)); } else { ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId))); @@ -741,29 +867,29 @@ ASMJIT_FAVOR_SIZE Error LoggingInternal::formatInstruction( const Operand_& op = operands[i]; if (op.isNone()) break; - ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", ")); - ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, archId, op)); + ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", ")); + ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, op)); if (op.isImm() && (flags & FormatOptions::kFlagExplainImms)) { uint32_t vecSize = 16; for (uint32_t j = 0; j < opCount; j++) if (operands[j].isReg()) vecSize = Support::max<uint32_t>(vecSize, operands[j].size()); - ASMJIT_PROPAGATE(LoggingInternal_explainConst(sb, flags, instId, vecSize, op.as<Imm>())); + ASMJIT_PROPAGATE(FormatterInternal_explainConst(sb, flags, instId, vecSize, op.as<Imm>())); } // Support AVX-512 masking - {k}{z}. if (i == 0) { if (inst.extraReg().group() == Reg::kGroupKReg) { - ASMJIT_PROPAGATE(sb.appendString(" {")); - ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, archId, inst.extraReg().type(), inst.extraReg().id())); - ASMJIT_PROPAGATE(sb.appendChar('}')); + ASMJIT_PROPAGATE(sb.append(" {")); + ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, inst.extraReg().type(), inst.extraReg().id())); + ASMJIT_PROPAGATE(sb.append('}')); if (options & Inst::kOptionZMask) - ASMJIT_PROPAGATE(sb.appendString("{z}")); + ASMJIT_PROPAGATE(sb.append("{z}")); } else if (options & Inst::kOptionZMask) { - ASMJIT_PROPAGATE(sb.appendString(" {z}")); + ASMJIT_PROPAGATE(sb.append(" {z}")); } } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86logging_p.h b/3rdparty/asmjit/src/asmjit/x86/x86formatter_p.h index c0d7d16e3f2..d7d58e42d67 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86logging_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86formatter_p.h @@ -21,52 +21,60 @@ // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. -#ifndef ASMJIT_X86_X86LOGGING_P_H_INCLUDED -#define ASMJIT_X86_X86LOGGING_P_H_INCLUDED +#ifndef ASMJIT_X86_X86FORMATTER_P_H_INCLUDED +#define ASMJIT_X86_X86FORMATTER_P_H_INCLUDED #include "../core/api-config.h" #ifndef ASMJIT_NO_LOGGING -#include "../core/logging.h" +#include "../core/formatter.h" #include "../core/string.h" #include "../x86/x86globals.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) +//! \cond INTERNAL //! \addtogroup asmjit_x86 //! \{ // ============================================================================ -// [asmjit::x86::LoggingInternal] +// [asmjit::x86::FormatterInternal] // ============================================================================ -namespace LoggingInternal { - Error formatRegister( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - uint32_t regType, - uint32_t regId) noexcept; +namespace FormatterInternal { - Error formatOperand( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const Operand_& op) noexcept; +Error formatFeature( + String& sb, + uint32_t featureId) noexcept; - Error formatInstruction( - String& sb, - uint32_t flags, - const BaseEmitter* emitter, - uint32_t archId, - const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; -}; +Error formatRegister( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + uint32_t regType, + uint32_t regId) noexcept; + +Error formatOperand( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + const Operand_& op) noexcept; + +Error formatInstruction( + String& sb, + uint32_t flags, + const BaseEmitter* emitter, + uint32_t arch, + const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept; + +} // {FormatterInternal} //! \} +//! \endcond ASMJIT_END_SUB_NAMESPACE #endif // !ASMJIT_NO_LOGGING -#endif // ASMJIT_X86_X86LOGGING_P_H_INCLUDED +#endif // ASMJIT_X86_X86FORMATTER_P_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86globals.h b/3rdparty/asmjit/src/asmjit/x86/x86globals.h index dca2b95732c..f7d258f3b62 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86globals.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86globals.h @@ -1652,14 +1652,14 @@ namespace Condition { kUnsignedGT = kA, //!< Unsigned `a > b`. kUnsignedGE = kAE, //!< Unsigned `a >= b`. - kZero = kZ, - kNotZero = kNZ, + kZero = kZ, //!< Zero flag. + kNotZero = kNZ, //!< Non-zero flag. - kNegative = kS, - kPositive = kNS, + kNegative = kS, //!< Sign flag. + kPositive = kNS, //!< No sign flag. - kParityEven = kP, - kParityOdd = kPO + kParityEven = kP, //!< Even parity flag. + kParityOdd = kPO //!< Odd parity flag. }; static constexpr uint8_t reverseTable[kCount] = { @@ -1696,54 +1696,92 @@ namespace Condition { // [asmjit::x86::FpuWord] // ============================================================================ -//! FPU control and status word. +//! FPU control and status words. namespace FpuWord { //! FPU status word. enum Status : uint32_t { + //! Invalid operation. kStatusInvalid = 0x0001u, + //! Denormalized operand. kStatusDenormalized = 0x0002u, + //! Division by zero. kStatusDivByZero = 0x0004u, + //! Overflown. kStatusOverflow = 0x0008u, + //! Underflown. kStatusUnderflow = 0x0010u, + //! Precision lost. kStatusPrecision = 0x0020u, + //! Stack fault. kStatusStackFault = 0x0040u, + //! Interrupt. kStatusInterrupt = 0x0080u, + //! C0 flag. kStatusC0 = 0x0100u, + //! C1 flag. kStatusC1 = 0x0200u, + //! C2 flag. kStatusC2 = 0x0400u, + //! Top of the stack. kStatusTop = 0x3800u, + //! C3 flag. kStatusC3 = 0x4000u, + //! FPU is busy. kStatusBusy = 0x8000u }; //! FPU control word. enum Control : uint32_t { - // Bits 0-5. + // [Bits 0-5] + + //! Exception mask (0x3F). kControlEM_Mask = 0x003Fu, + //! Invalid operation exception. kControlEM_Invalid = 0x0001u, + //! Denormalized operand exception. kControlEM_Denormal = 0x0002u, + //! Division by zero exception. kControlEM_DivByZero = 0x0004u, + //! Overflow exception. kControlEM_Overflow = 0x0008u, + //! Underflow exception. kControlEM_Underflow = 0x0010u, + //! Inexact operation exception. kControlEM_Inexact = 0x0020u, - // Bits 8-9. + // [Bits 8-9] + + //! Precision control mask. kControlPC_Mask = 0x0300u, + //! Single precision (24 bits). kControlPC_Float = 0x0000u, + //! Reserved. kControlPC_Reserved = 0x0100u, + //! Double precision (53 bits). kControlPC_Double = 0x0200u, + //! Extended precision (64 bits). kControlPC_Extended = 0x0300u, - // Bits 10-11. + // [Bits 10-11] + + //! Rounding control mask. kControlRC_Mask = 0x0C00u, + //! Round to nearest even. kControlRC_Nearest = 0x0000u, + //! Round down (floor). kControlRC_Down = 0x0400u, + //! Round up (ceil). kControlRC_Up = 0x0800u, + //! Round towards zero (truncate). kControlRC_Truncate = 0x0C00u, - // Bit 12. + // [Bit 12] + + //! Infinity control. kControlIC_Mask = 0x1000u, + //! Projective (not supported on X64). kControlIC_Projective = 0x0000u, + //! Affine (default). kControlIC_Affine = 0x1000u }; } @@ -1760,26 +1798,39 @@ namespace Status { // [Architecture Neutral Flags - 0x000000FF] // ------------------------------------------------------------------------ - kCF = 0x00000001u, //!< Carry flag. - kOF = 0x00000002u, //!< Signed overflow flag. - kSF = 0x00000004u, //!< Sign flag (negative/sign, if set). - kZF = 0x00000008u, //!< Zero and/or equality flag (1 if zero/equal). + //! Carry flag. + kCF = 0x00000001u, + //! Signed overflow flag. + kOF = 0x00000002u, + //! Sign flag (negative/sign, if set). + kSF = 0x00000004u, + //! Zero and/or equality flag (1 if zero/equal). + kZF = 0x00000008u, // ------------------------------------------------------------------------ // [Architecture Specific Flags - 0xFFFFFF00] // ------------------------------------------------------------------------ - kAF = 0x00000100u, //!< Adjust flag. - kPF = 0x00000200u, //!< Parity flag. - kDF = 0x00000400u, //!< Direction flag. - kIF = 0x00000800u, //!< Interrupt enable flag. - - kAC = 0x00001000u, //!< Alignment check. - - kC0 = 0x00010000u, //!< FPU C0 status flag. - kC1 = 0x00020000u, //!< FPU C1 status flag. - kC2 = 0x00040000u, //!< FPU C2 status flag. - kC3 = 0x00080000u //!< FPU C3 status flag. + //! Adjust flag. + kAF = 0x00000100u, + //! Parity flag. + kPF = 0x00000200u, + //! Direction flag. + kDF = 0x00000400u, + //! Interrupt enable flag. + kIF = 0x00000800u, + + //! Alignment check. + kAC = 0x00001000u, + + //! FPU C0 status flag. + kC0 = 0x00010000u, + //! FPU C1 status flag. + kC1 = 0x00020000u, + //! FPU C2 status flag. + kC2 = 0x00040000u, + //! FPU C3 status flag. + kC3 = 0x00080000u }; } @@ -1834,12 +1885,18 @@ namespace Predicate { //! A predicate used by ROUND[PD|PS|SD|SS] instructions. enum Round : uint32_t { - kRoundNearest = 0x00u, //!< Round to nearest (even). - kRoundDown = 0x01u, //!< Round to down toward -INF (floor), - kRoundUp = 0x02u, //!< Round to up toward +INF (ceil). - kRoundTrunc = 0x03u, //!< Round toward zero (truncate). - kRoundCurrent = 0x04u, //!< Round to the current rounding mode set (ignores other RC bits). - kRoundInexact = 0x08u //!< Avoids inexact exception, if set. + //! Round to nearest (even). + kRoundNearest = 0x00u, + //! Round to down toward -INF (floor), + kRoundDown = 0x01u, + //! Round to up toward +INF (ceil). + kRoundUp = 0x02u, + //! Round toward zero (truncate). + kRoundTrunc = 0x03u, + //! Round to the current rounding mode set (ignores other RC bits). + kRoundCurrent = 0x04u, + //! Avoids inexact exception, if set. + kRoundInexact = 0x08u }; //! A predicate used by VCMP[PD|PS|SD|SS] instructions. @@ -1998,25 +2055,46 @@ namespace Predicate { //! Bitwise ternary logic between 3 operands introduced by AVX-512. namespace TLog { //! A predicate that can be used to create a common predicate for VPTERNLOG[D|Q]. + //! + //! There are 3 inputs to the instruction (\ref kA, \ref kB, \ref kC), and + //! ternary logic can define any combination that would be performed on these + //! 3 inputs to get the desired output - any combination of AND, OR, XOR, NOT. enum Operator : uint32_t { - k0 = 0x00u, //!< 0 value. - k1 = 0xFFu, //!< 1 value. - kA = 0xF0u, //!< A value. - kB = 0xCCu, //!< B value. - kC = 0xAAu, //!< C value. - kNotA = kA ^ k1, //!< `!A` expression. - kNotB = kB ^ k1, //!< `!B` expression. - kNotC = kC ^ k1, //!< `!C` expression. - - kAB = kA & kB, //!< `A & B` expression. - kAC = kA & kC, //!< `A & C` expression. - kBC = kB & kC, //!< `B & C` expression. - kNotAB = kAB ^ k1, //!< `!(A & B)` expression. - kNotAC = kAC ^ k1, //!< `!(A & C)` expression. - kNotBC = kBC ^ k1, //!< `!(B & C)` expression. - - kABC = kAB & kC, //!< `A & B & C` expression. - kNotABC = kABC ^ k1 //!< `!(A & B & C)` expression. + //! 0 value. + k0 = 0x00u, + //! 1 value. + k1 = 0xFFu, + //! A value. + kA = 0xF0u, + //! B value. + kB = 0xCCu, + //! C value. + kC = 0xAAu, + + //! `!A` expression. + kNotA = kA ^ k1, + //! `!B` expression. + kNotB = kB ^ k1, + //! `!C` expression. + kNotC = kC ^ k1, + + //! `A & B` expression. + kAB = kA & kB, + //! `A & C` expression. + kAC = kA & kC, + //! `B & C` expression. + kBC = kB & kC, + //! `!(A & B)` expression. + kNotAB = kAB ^ k1, + //! `!(A & C)` expression. + kNotAC = kAC ^ k1, + //! `!(B & C)` expression. + kNotBC = kBC ^ k1, + + //! `A & B & C` expression. + kABC = kAB & kC, + //! `!(A & B & C)` expression. + kNotABC = kABC ^ k1 }; //! Creates an immediate that can be used by VPTERNLOG[D|Q] instructions. diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp b/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp index 6c5e28be46a..82f782e0fc6 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp @@ -58,18 +58,18 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) // ============================================================================ #ifndef ASMJIT_NO_TEXT -Error InstInternal::instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept { - DebugUtils::unused(archId); +Error InstInternal::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept { + DebugUtils::unused(arch); if (ASMJIT_UNLIKELY(!Inst::isDefinedId(instId))) return DebugUtils::errored(kErrorInvalidInstruction); const InstDB::InstInfo& info = InstDB::infoById(instId); - return output.appendString(InstDB::_nameData + info._nameDataIndex); + return output.append(InstDB::_nameData + info._nameDataIndex); } -uint32_t InstInternal::stringToInstId(uint32_t archId, const char* s, size_t len) noexcept { - DebugUtils::unused(archId); +uint32_t InstInternal::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept { + DebugUtils::unused(arch); if (ASMJIT_UNLIKELY(!s)) return Inst::kIdNone; @@ -235,18 +235,18 @@ static ASMJIT_INLINE bool x86CheckOSig(const InstDB::OpSignature& op, const Inst return true; } -ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept { - // Only called when `archId` matches X86 family. - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); +ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept { + // Only called when `arch` matches X86 family. + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); const X86ValidationData* vd; - if (archId == ArchInfo::kIdX86) + if (arch == Environment::kArchX86) vd = &_x86ValidationData; else vd = &_x64ValidationData; uint32_t i; - uint32_t mode = InstDB::modeFromArchId(archId); + uint32_t mode = InstDB::modeFromArch(arch); // Get the instruction data. uint32_t instId = inst.id(); @@ -328,7 +328,6 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& // that the register is virtual and its index will be assigned later // by the register allocator. We must pass unless asked to disallow // virtual registers. - // TODO: We need an option to refuse virtual regs here. uint32_t regId = op.id(); if (regId < Operand::kVirtIdMin) { if (ASMJIT_UNLIKELY(regId >= 32)) @@ -341,6 +340,8 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& combinedRegMask |= regMask; } else { + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); regMask = 0xFFFFFFFFu; } break; @@ -393,6 +394,9 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& // memory operand. Basically only usable for string instructions and other // instructions where memory operand is implicit and has 'seg:[reg]' form. if (baseId < Operand::kVirtIdMin) { + if (ASMJIT_UNLIKELY(baseId >= 32)) + return DebugUtils::errored(kErrorInvalidPhysId); + // Physical base id. regMask = Support::bitMask(baseId); combinedRegMask |= regMask; @@ -400,6 +404,8 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& else { // Virtual base id - fill the whole mask for implicit mem validation. // The register is not assigned yet, so we cannot predict the phys id. + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); regMask = 0xFFFFFFFFu; } @@ -461,8 +467,16 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& return DebugUtils::errored(kErrorInvalidAddress); uint32_t indexId = m.indexId(); - if (indexId < Operand::kVirtIdMin) + if (indexId < Operand::kVirtIdMin) { + if (ASMJIT_UNLIKELY(indexId >= 32)) + return DebugUtils::errored(kErrorInvalidPhysId); + combinedRegMask |= Support::bitMask(indexId); + } + else { + if (!(validationFlags & InstAPI::kValidationFlagVirtRegs)) + return DebugUtils::errored(kErrorIllegalVirtReg); + } // Only used for implicit memory operands having 'seg:[reg]' form, so clear it. regMask = 0; @@ -490,7 +504,7 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& } case Operand::kOpImm: { - uint64_t immValue = op.as<Imm>().u64(); + uint64_t immValue = op.as<Imm>().valueAs<uint64_t>(); uint32_t immFlags = 0; if (int64_t(immValue) >= 0) { @@ -574,7 +588,9 @@ ASMJIT_FAVOR_SIZE Error InstInternal::validate(uint32_t archId, const BaseInst& } else { // Illegal use of a high 8-bit register with REX prefix. - if (ASMJIT_UNLIKELY((combinedOpFlags & InstDB::kOpGpbHi) != 0 && (combinedRegMask & 0xFFFFFF00u) != 0)) + bool hasREX = inst.hasOption(Inst::kOptionRex) || + ((combinedRegMask & 0xFFFFFF00u) != 0); + if (ASMJIT_UNLIKELY(hasREX && (combinedOpFlags & InstDB::kOpGpbHi) != 0)) return DebugUtils::errored(kErrorInvalidUseOfGpbHi); } @@ -761,12 +777,6 @@ static const uint64_t rwRegGroupByteMask[Reg::kGroupCount] = { 0x00000000000000FFu // RIP. }; -// TODO: Make universal. -static ASMJIT_INLINE uint32_t gpRegSizeByArchId(uint32_t archId) noexcept { - static const uint8_t table[] = { 0, 4, 8, 4, 8 }; - return table[archId]; -} - static ASMJIT_INLINE void rwZeroExtendGp(OpRWInfo& opRwInfo, const Gp& reg, uint32_t nativeGpSize) noexcept { ASMJIT_ASSERT(BaseReg::isGp(reg.as<Operand>())); if (reg.size() + 4 == nativeGpSize) { @@ -793,11 +803,11 @@ static ASMJIT_INLINE void rwZeroExtendNonVec(OpRWInfo& opRwInfo, const Reg& reg) } } -Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept { +Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept { using namespace Status; - // Only called when `archId` matches X86 family. - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); + // Only called when `arch` matches X86 family. + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); // Get the instruction data. uint32_t instId = inst.id(); @@ -817,14 +827,14 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const InstDB::RWInfo& instRwInfo = InstDB::rwInfo[InstDB::rwInfoIndex[instId * 2u + uint32_t(opCount != 2)]]; const InstDB::RWInfoRm& instRmInfo = InstDB::rwInfoRm[instRwInfo.rmInfo]; - out._instFlags = 0; - out._opCount = uint8_t(opCount); - out._rmFeature = instRmInfo.rmFeature; - out._extraReg.reset(); - out._readFlags = rwFlags.readFlags; - out._writeFlags = rwFlags.writeFlags; + out->_instFlags = 0; + out->_opCount = uint8_t(opCount); + out->_rmFeature = instRmInfo.rmFeature; + out->_extraReg.reset(); + out->_readFlags = rwFlags.readFlags; + out->_writeFlags = rwFlags.writeFlags; - uint32_t nativeGpSize = gpRegSizeByArchId(archId); + uint32_t nativeGpSize = Environment::registerSizeFromArch(arch); constexpr uint32_t R = OpRWInfo::kRead; constexpr uint32_t W = OpRWInfo::kWrite; @@ -839,7 +849,7 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t rmMaxSize = 0; for (i = 0; i < opCount; i++) { - OpRWInfo& op = out._operands[i]; + OpRWInfo& op = out->_operands[i]; const Operand_& srcOp = operands[i]; const InstDB::RWInfoOp& rwOpData = InstDB::rwInfoOp[instRwInfo.opInfoIndex[i]]; @@ -893,7 +903,7 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope do { i = it.next(); - OpRWInfo& op = out._operands[i]; + OpRWInfo& op = out->_operands[i]; op.addOpFlags(RegM); switch (instRmInfo.category) { @@ -932,38 +942,38 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const Reg& o1 = operands[1].as<Reg>(); if (o0.isGp() && o1.isGp()) { - out._operands[0].reset(W | RegM, operands[0].size()); - out._operands[1].reset(R | RegM, operands[1].size()); + out->_operands[0].reset(W | RegM, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[1].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (o0.isGp() && o1.isSReg()) { - out._operands[0].reset(W | RegM, nativeGpSize); - out._operands[0].setRmSize(2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W | RegM, nativeGpSize); + out->_operands[0].setRmSize(2); + out->_operands[1].reset(R, 2); return kErrorOk; } if (o0.isSReg() && o1.isGp()) { - out._operands[0].reset(W, 2); - out._operands[1].reset(R | RegM, 2); - out._operands[1].setRmSize(2); + out->_operands[0].reset(W, 2); + out->_operands[1].reset(R | RegM, 2); + out->_operands[1].setRmSize(2); return kErrorOk; } if (o0.isGp() && (o1.isCReg() || o1.isDReg())) { - out._operands[0].reset(W, nativeGpSize); - out._operands[1].reset(R, nativeGpSize); - out._writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; + out->_operands[0].reset(W, nativeGpSize); + out->_operands[1].reset(R, nativeGpSize); + out->_writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; return kErrorOk; } if ((o0.isCReg() || o0.isDReg()) && o1.isGp()) { - out._operands[0].reset(W, nativeGpSize); - out._operands[1].reset(R, nativeGpSize); - out._writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; + out->_operands[0].reset(W, nativeGpSize); + out->_operands[1].reset(R, nativeGpSize); + out->_writeFlags = kOF | kSF | kZF | kAF | kPF | kCF; return kErrorOk; } } @@ -974,18 +984,18 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (o0.isGp()) { if (!o1.isOffset64Bit()) - out._operands[0].reset(W, o0.size()); + out->_operands[0].reset(W, o0.size()); else - out._operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx); + out->_operands[0].reset(W | RegPhys, o0.size(), Gp::kIdAx); - out._operands[1].reset(R | MibRead, o0.size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + out->_operands[1].reset(R | MibRead, o0.size()); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (o0.isSReg()) { - out._operands[0].reset(W, 2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W, 2); + out->_operands[1].reset(R, 2); return kErrorOk; } } @@ -995,34 +1005,34 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope const Reg& o1 = operands[1].as<Reg>(); if (o1.isGp()) { - out._operands[0].reset(W | MibRead, o1.size()); + out->_operands[0].reset(W | MibRead, o1.size()); if (!o0.isOffset64Bit()) - out._operands[1].reset(R, o1.size()); + out->_operands[1].reset(R, o1.size()); else - out._operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx); + out->_operands[1].reset(R | RegPhys, o1.size(), Gp::kIdAx); return kErrorOk; } if (o1.isSReg()) { - out._operands[0].reset(W | MibRead, 2); - out._operands[1].reset(R, 2); + out->_operands[0].reset(W | MibRead, 2); + out->_operands[1].reset(R, 2); return kErrorOk; } } if (Reg::isGp(operands[0]) && operands[1].isImm()) { const Reg& o0 = operands[0].as<Reg>(); - out._operands[0].reset(W | RegM, o0.size()); - out._operands[1].reset(); + out->_operands[0].reset(W | RegM, o0.size()); + out->_operands[1].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (operands[0].isMem() && operands[1].isImm()) { const Reg& o0 = operands[0].as<Reg>(); - out._operands[0].reset(W | MibRead, o0.size()); - out._operands[1].reset(); + out->_operands[0].reset(W | MibRead, o0.size()); + out->_operands[1].reset(); return kErrorOk; } } @@ -1040,51 +1050,51 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount == 2) { if (operands[0].isReg() && operands[1].isImm()) { - out._operands[0].reset(X, operands[0].size()); - out._operands[1].reset(); + out->_operands[0].reset(X, operands[0].size()); + out->_operands[1].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); return kErrorOk; } if (Reg::isGpw(operands[0]) && operands[1].size() == 1) { // imul ax, r8/m8 <- AX = AL * r8/m8 - out._operands[0].reset(X | RegPhys, 2, Gp::kIdAx); - out._operands[0].setReadByteMask(Support::lsbMask<uint64_t>(1)); - out._operands[1].reset(R | RegM, 1); + out->_operands[0].reset(X | RegPhys, 2, Gp::kIdAx); + out->_operands[0].setReadByteMask(Support::lsbMask<uint64_t>(1)); + out->_operands[1].reset(R | RegM, 1); } else { // imul r?, r?/m? - out._operands[0].reset(X, operands[0].size()); - out._operands[1].reset(R | RegM, operands[0].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + out->_operands[0].reset(X, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[0].size()); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); } if (operands[1].isMem()) - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } if (opCount == 3) { if (operands[2].isImm()) { - out._operands[0].reset(W, operands[0].size()); - out._operands[1].reset(R | RegM, operands[1].size()); - out._operands[2].reset(); + out->_operands[0].reset(W, operands[0].size()); + out->_operands[1].reset(R | RegM, operands[1].size()); + out->_operands[2].reset(); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); if (operands[1].isMem()) - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } else { - out._operands[0].reset(W | RegPhys, operands[0].size(), Gp::kIdDx); - out._operands[1].reset(X | RegPhys, operands[1].size(), Gp::kIdAx); - out._operands[2].reset(R | RegM, operands[2].size()); + out->_operands[0].reset(W | RegPhys, operands[0].size(), Gp::kIdDx); + out->_operands[1].reset(X | RegPhys, operands[1].size(), Gp::kIdAx); + out->_operands[2].reset(R | RegM, operands[2].size()); - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); - rwZeroExtendGp(out._operands[1], operands[1].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[1], operands[1].as<Gp>(), nativeGpSize); if (operands[2].isMem()) - out._operands[2].addOpFlags(MibRead); + out->_operands[2].addOpFlags(MibRead); return kErrorOk; } } @@ -1097,16 +1107,16 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // 2 or 3 operands that are use `kCategoryGeneric`. if (opCount == 2) { if (BaseReg::isVec(operands[0]) && operands[1].isMem()) { - out._operands[0].reset(W, 8); - out._operands[0].setWriteByteMask(Support::lsbMask<uint64_t>(8) << 8); - out._operands[1].reset(R | MibRead, 8); + out->_operands[0].reset(W, 8); + out->_operands[0].setWriteByteMask(Support::lsbMask<uint64_t>(8) << 8); + out->_operands[1].reset(R | MibRead, 8); return kErrorOk; } if (operands[0].isMem() && BaseReg::isVec(operands[1])) { - out._operands[0].reset(W | MibRead, 8); - out._operands[1].reset(R, 8); - out._operands[1].setReadByteMask(Support::lsbMask<uint64_t>(8) << 8); + out->_operands[0].reset(W | MibRead, 8); + out->_operands[1].reset(R, 8); + out->_operands[1].setReadByteMask(Support::lsbMask<uint64_t>(8) << 8); return kErrorOk; } } @@ -1117,18 +1127,18 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // Special case for 'vmaskmovpd|vmaskmovps|vpmaskmovd|vpmaskmovq' instructions. if (opCount == 3) { if (BaseReg::isVec(operands[0]) && BaseReg::isVec(operands[1]) && operands[2].isMem()) { - out._operands[0].reset(W, operands[0].size()); - out._operands[1].reset(R, operands[1].size()); - out._operands[2].reset(R | MibRead, operands[1].size()); + out->_operands[0].reset(W, operands[0].size()); + out->_operands[1].reset(R, operands[1].size()); + out->_operands[2].reset(R | MibRead, operands[1].size()); - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } if (operands[0].isMem() && BaseReg::isVec(operands[1]) && BaseReg::isVec(operands[2])) { - out._operands[0].reset(X | MibRead, operands[1].size()); - out._operands[1].reset(R, operands[1].size()); - out._operands[2].reset(R, operands[2].size()); + out->_operands[0].reset(X | MibRead, operands[1].size()); + out->_operands[1].reset(R, operands[1].size()); + out->_operands[2].reset(R, operands[2].size()); return kErrorOk; } } @@ -1145,11 +1155,11 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t o0Size = operands[0].size(); uint32_t o1Size = o0Size == 16 ? 8 : o0Size; - out._operands[0].reset(W, o0Size); - out._operands[1].reset(R | RegM, o1Size); - out._operands[1]._readByteMask &= 0x00FF00FF00FF00FFu; + out->_operands[0].reset(W, o0Size); + out->_operands[1].reset(R | RegM, o1Size); + out->_operands[1]._readByteMask &= 0x00FF00FF00FF00FFu; - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } @@ -1157,10 +1167,10 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t o0Size = operands[0].size(); uint32_t o1Size = o0Size == 16 ? 8 : o0Size; - out._operands[0].reset(W, o0Size); - out._operands[1].reset(R | MibRead, o1Size); + out->_operands[0].reset(W, o0Size); + out->_operands[1].reset(R | MibRead, o1Size); - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } } @@ -1172,9 +1182,9 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope // Special case for 'vmovmskpd|vmovmskps' instructions. if (opCount == 2) { if (BaseReg::isGp(operands[0]) && BaseReg::isVec(operands[1])) { - out._operands[0].reset(W, 1); - out._operands[0].setExtendByteMask(Support::lsbMask<uint32_t>(nativeGpSize - 1) << 1); - out._operands[1].reset(R, operands[1].size()); + out->_operands[0].reset(W, 1); + out->_operands[0].setExtendByteMask(Support::lsbMask<uint32_t>(nativeGpSize - 1) << 1); + out->_operands[1].reset(R, operands[1].size()); return kErrorOk; } } @@ -1208,32 +1218,32 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount >= 3) { if (opCount > 3) return DebugUtils::errored(kErrorInvalidInstruction); - out._operands[2].reset(); + out->_operands[2].reset(); } if (operands[0].isReg() && operands[1].isReg()) { uint32_t size1 = operands[1].size(); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R, size1); if (instRmInfo.rmOpsMask & 0x1) { - out._operands[0].addOpFlags(RegM); - out._operands[0].setRmSize(size0); + out->_operands[0].addOpFlags(RegM); + out->_operands[0].setRmSize(size0); } if (instRmInfo.rmOpsMask & 0x2) { - out._operands[1].addOpFlags(RegM); - out._operands[1].setRmSize(size1); + out->_operands[1].addOpFlags(RegM); + out->_operands[1].setRmSize(size1); } // Handle 'pmovmskb|vpmovmskb'. if (BaseReg::isGp(operands[0])) - rwZeroExtendGp(out._operands[0], operands[0].as<Gp>(), nativeGpSize); + rwZeroExtendGp(out->_operands[0], operands[0].as<Gp>(), nativeGpSize); if (BaseReg::isVec(operands[0])) - rwZeroExtendAvxVec(out._operands[0], operands[0].as<Vec>()); + rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>()); return kErrorOk; } @@ -1242,8 +1252,8 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t size1 = operands[1].size() ? operands[1].size() : uint32_t(16); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R | MibRead, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R | MibRead, size1); return kErrorOk; } @@ -1251,8 +1261,8 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope uint32_t size1 = operands[1].size(); uint32_t size0 = size1 >> shift; - out._operands[0].reset(W | MibRead, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W | MibRead, size0); + out->_operands[1].reset(R, size1); return kErrorOk; } } @@ -1285,30 +1295,30 @@ Error InstInternal::queryRWInfo(uint32_t archId, const BaseInst& inst, const Ope if (opCount >= 3) { if (opCount > 3) return DebugUtils::errored(kErrorInvalidInstruction); - out._operands[2].reset(); + out->_operands[2].reset(); } uint32_t size0 = operands[0].size(); uint32_t size1 = size0 >> shift; - out._operands[0].reset(W, size0); - out._operands[1].reset(R, size1); + out->_operands[0].reset(W, size0); + out->_operands[1].reset(R, size1); if (operands[0].isReg() && operands[1].isReg()) { if (instRmInfo.rmOpsMask & 0x1) { - out._operands[0].addOpFlags(RegM); - out._operands[0].setRmSize(size0); + out->_operands[0].addOpFlags(RegM); + out->_operands[0].setRmSize(size0); } if (instRmInfo.rmOpsMask & 0x2) { - out._operands[1].addOpFlags(RegM); - out._operands[1].setRmSize(size1); + out->_operands[1].addOpFlags(RegM); + out->_operands[1].setRmSize(size1); } return kErrorOk; } if (operands[0].isReg() && operands[1].isMem()) { - out._operands[1].addOpFlags(MibRead); + out->_operands[1].addOpFlags(MibRead); return kErrorOk; } } @@ -1334,7 +1344,7 @@ struct RegAnalysis { } }; -static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, uint32_t opCount) noexcept { +static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, size_t opCount) noexcept { uint32_t mask = 0; uint32_t highVecUsed = 0; @@ -1359,10 +1369,10 @@ static RegAnalysis InstInternal_regAnalysis(const Operand_* operands, uint32_t o return RegAnalysis { mask, highVecUsed }; } -Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept { - // Only called when `archId` matches X86 family. - DebugUtils::unused(archId); - ASMJIT_ASSERT(ArchInfo::isX86Family(archId)); +Error InstInternal::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept { + // Only called when `arch` matches X86 family. + DebugUtils::unused(arch); + ASMJIT_ASSERT(Environment::isFamilyX86(arch)); // Get the instruction data. uint32_t instId = inst.id(); @@ -1378,12 +1388,12 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O const uint8_t* fEnd = tableB.featuresEnd(); // Copy all features to `out`. - out.reset(); + out->reset(); do { uint32_t feature = fData[0]; if (!feature) break; - out.add(feature); + out->add(feature); } while (++fData != fEnd); // Since AsmJit aggregates instructions that share the same name we have to @@ -1392,19 +1402,19 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O RegAnalysis regAnalysis = InstInternal_regAnalysis(operands, opCount); // Handle MMX vs SSE overlap. - if (out.has(Features::kMMX) || out.has(Features::kMMX2)) { + if (out->has(Features::kMMX) || out->has(Features::kMMX2)) { // Only instructions defined by SSE and SSE2 overlap. Instructions // introduced by newer instruction sets like SSE3+ don't state MMX as // they require SSE3+. - if (out.has(Features::kSSE) || out.has(Features::kSSE2)) { + if (out->has(Features::kSSE) || out->has(Features::kSSE2)) { if (!regAnalysis.hasRegType(Reg::kTypeXmm)) { // The instruction doesn't use XMM register(s), thus it's MMX/MMX2 only. - out.remove(Features::kSSE); - out.remove(Features::kSSE2); + out->remove(Features::kSSE); + out->remove(Features::kSSE2); } else { - out.remove(Features::kMMX); - out.remove(Features::kMMX2); + out->remove(Features::kMMX); + out->remove(Features::kMMX2); } // Special case: PEXTRW instruction is MMX/SSE2 instruction. However, @@ -1414,34 +1424,34 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O // can extract directly to memory. This instruction is, of course, not // compatible with MMX/SSE2 and would #UD if SSE4.1 is not supported. if (instId == Inst::kIdPextrw) { - ASMJIT_ASSERT(out.has(Features::kSSE2)); - ASMJIT_ASSERT(out.has(Features::kSSE4_1)); + ASMJIT_ASSERT(out->has(Features::kSSE2)); + ASMJIT_ASSERT(out->has(Features::kSSE4_1)); if (opCount >= 1 && operands[0].isMem()) - out.remove(Features::kSSE2); + out->remove(Features::kSSE2); else - out.remove(Features::kSSE4_1); + out->remove(Features::kSSE4_1); } } } // Handle PCLMULQDQ vs VPCLMULQDQ. - if (out.has(Features::kVPCLMULQDQ)) { + if (out->has(Features::kVPCLMULQDQ)) { if (regAnalysis.hasRegType(Reg::kTypeZmm) || Support::bitTest(options, Inst::kOptionEvex)) { // AVX512_F & VPCLMULQDQ. - out.remove(Features::kAVX, Features::kPCLMULQDQ); + out->remove(Features::kAVX, Features::kPCLMULQDQ); } else if (regAnalysis.hasRegType(Reg::kTypeYmm)) { - out.remove(Features::kAVX512_F, Features::kAVX512_VL); + out->remove(Features::kAVX512_F, Features::kAVX512_VL); } else { // AVX & PCLMULQDQ. - out.remove(Features::kAVX512_F, Features::kAVX512_VL, Features::kVPCLMULQDQ); + out->remove(Features::kAVX512_F, Features::kAVX512_VL, Features::kVPCLMULQDQ); } } // Handle AVX vs AVX2 overlap. - if (out.has(Features::kAVX) && out.has(Features::kAVX2)) { + if (out->has(Features::kAVX) && out->has(Features::kAVX2)) { bool isAVX2 = true; // Special case: VBROADCASTSS and VBROADCASTSD were introduced in AVX, but // only version that uses memory as a source operand. AVX2 then added support @@ -1459,15 +1469,15 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O } if (isAVX2) - out.remove(Features::kAVX); + out->remove(Features::kAVX); else - out.remove(Features::kAVX2); + out->remove(Features::kAVX2); } // Handle AVX|AVX2|FMA|F16C vs AVX512 overlap. - if (out.has(Features::kAVX) || out.has(Features::kAVX2) || out.has(Features::kFMA) || out.has(Features::kF16C)) { + if (out->has(Features::kAVX) || out->has(Features::kAVX2) || out->has(Features::kFMA) || out->has(Features::kF16C)) { // Only AVX512-F|BW|DQ allow to encode AVX/AVX2/FMA/F16C instructions - if (out.has(Features::kAVX512_F) || out.has(Features::kAVX512_BW) || out.has(Features::kAVX512_DQ)) { + if (out->has(Features::kAVX512_F) || out->has(Features::kAVX512_BW) || out->has(Features::kAVX512_DQ)) { uint32_t hasEvex = options & (Inst::kOptionEvex | Inst::_kOptionAvx512Mask); uint32_t hasKMask = inst.extraReg().type() == Reg::kTypeKReg; uint32_t hasKOrZmm = regAnalysis.regTypeMask & Support::bitMask(Reg::kTypeZmm, Reg::kTypeKReg); @@ -1500,15 +1510,15 @@ Error InstInternal::queryFeatures(uint32_t archId, const BaseInst& inst, const O } if (!(hasEvex | mustUseEvex | hasKMask | hasKOrZmm | regAnalysis.highVecUsed)) - out.remove(Features::kAVX512_F, Features::kAVX512_BW, Features::kAVX512_DQ, Features::kAVX512_VL); + out->remove(Features::kAVX512_F, Features::kAVX512_BW, Features::kAVX512_DQ, Features::kAVX512_VL); else - out.remove(Features::kAVX, Features::kAVX2, Features::kFMA, Features::kF16C); + out->remove(Features::kAVX, Features::kAVX2, Features::kFMA, Features::kF16C); } } // Clear AVX512_VL if ZMM register is used. if (regAnalysis.hasRegType(Reg::kTypeZmm)) - out.remove(Features::kAVX512_VL); + out->remove(Features::kAVX512_VL); } return kErrorOk; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h b/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h index 0389cf562a9..83b3f77cf6d 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h @@ -36,17 +36,17 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) namespace InstInternal { #ifndef ASMJIT_NO_TEXT -Error instIdToString(uint32_t archId, uint32_t instId, String& output) noexcept; -uint32_t stringToInstId(uint32_t archId, const char* s, size_t len) noexcept; +Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept; +uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept; #endif // !ASMJIT_NO_TEXT #ifndef ASMJIT_NO_VALIDATION -Error validate(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount) noexcept; +Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept; #endif // !ASMJIT_NO_VALIDATION #ifndef ASMJIT_NO_INTROSPECTION -Error queryRWInfo(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, InstRWInfo& out) noexcept; -Error queryFeatures(uint32_t archId, const BaseInst& inst, const Operand_* operands, uint32_t opCount, BaseFeatures& out) noexcept; +Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept; +Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept; #endif // !ASMJIT_NO_INTROSPECTION } // {InstInternal} diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp b/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp index 2d4855848f8..72ad0989c26 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86instdb.cpp @@ -537,7 +537,7 @@ const InstDB::InstInfo InstDB::_instInfoTable[] = { INST(Movsldup , ExtRm , O(F30F00,12,_,_,_,_,_,_ ), 0 , 6 , 0 , 6179 , 5 , 6 ), // #440 INST(Movss , ExtMov , O(F30F00,10,_,_,_,_,_,_ ), O(F30F00,11,_,_,_,_,_,_ ), 6 , 61 , 6189 , 124, 5 ), // #441 INST(Movsx , X86MovsxMovzx , O(000F00,BE,_,_,x,_,_,_ ), 0 , 4 , 0 , 1962 , 125, 0 ), // #442 - INST(Movsxd , X86Rm , O(000000,63,_,_,1,_,_,_ ), 0 , 20 , 0 , 1968 , 126, 0 ), // #443 + INST(Movsxd , X86Rm , O(000000,63,_,_,x,_,_,_ ), 0 , 0 , 0 , 1968 , 126, 0 ), // #443 INST(Movupd , ExtMov , O(660F00,10,_,_,_,_,_,_ ), O(660F00,11,_,_,_,_,_,_ ), 3 , 62 , 6196 , 107, 4 ), // #444 INST(Movups , ExtMov , O(000F00,10,_,_,_,_,_,_ ), O(000F00,11,_,_,_,_,_,_ ), 4 , 63 , 6204 , 107, 5 ), // #445 INST(Movzx , X86MovsxMovzx , O(000F00,B6,_,_,x,_,_,_ ), 0 , 4 , 0 , 1975 , 125, 0 ), // #446 @@ -1610,7 +1610,7 @@ const InstDB::InstInfo InstDB::_instInfoTable[] = { // ${MainOpcodeTable:Begin} // ------------------- Automatically generated, do not edit ------------------- const uint32_t InstDB::_mainOpcodeTable[] = { - O(000000,00,0,0,0,0,0,_ ), // #0 [ref=55x] + O(000000,00,0,0,0,0,0,_ ), // #0 [ref=56x] O(000000,00,2,0,0,0,0,_ ), // #1 [ref=4x] O(660F38,00,0,0,0,0,0,_ ), // #2 [ref=42x] O(660F00,00,0,0,0,0,0,_ ), // #3 [ref=38x] @@ -1630,7 +1630,7 @@ const uint32_t InstDB::_mainOpcodeTable[] = { V(000F38,00,2,0,0,0,0,_ ), // #17 [ref=1x] V(000F38,00,1,0,0,0,0,_ ), // #18 [ref=1x] O(660000,00,0,0,0,0,0,_ ), // #19 [ref=7x] - O(000000,00,0,0,1,0,0,_ ), // #20 [ref=4x] + O(000000,00,0,0,1,0,0,_ ), // #20 [ref=3x] O(000F01,00,0,0,0,0,0,_ ), // #21 [ref=25x] O(000F00,00,7,0,0,0,0,_ ), // #22 [ref=5x] O(660F00,00,7,0,0,0,0,_ ), // #23 [ref=2x] @@ -1991,8 +1991,8 @@ const uint32_t InstDB::_altOpcodeTable[] = { #define SINGLE_REG(VAL) InstDB::kSingleReg##VAL const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { 0 , 0 , 0 , CONTROL(None) , SINGLE_REG(None), 0 }, // #0 [ref=1x] - { 0 , 339, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #1 [ref=4x] - { 0 , 340, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #2 [ref=2x] + { 0 , 341, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #1 [ref=4x] + { 0 , 342, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #2 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(None), 0 }, // #3 [ref=2x] { 0 , 151, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #4 [ref=2x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #5 [ref=54x] @@ -2002,173 +2002,173 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Lock)|F(XAcquire)|F(XRelease) , 28 , 11, CONTROL(None) , SINGLE_REG(RO) , 0 }, // #9 [ref=1x] { F(Vex) , 237, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #10 [ref=3x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #11 [ref=12x] - { 0 , 341, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #12 [ref=1x] + { 0 , 343, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #12 [ref=1x] { F(Vex) , 239, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #13 [ref=5x] { F(Vex) , 151, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #14 [ref=12x] - { F(Vec) , 342, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #15 [ref=4x] + { F(Vec) , 344, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #15 [ref=4x] { 0 , 241, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #16 [ref=3x] - { F(Mib) , 343, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #17 [ref=1x] - { 0 , 344, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #18 [ref=1x] + { F(Mib) , 345, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #17 [ref=1x] + { 0 , 346, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #18 [ref=1x] { 0 , 243, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #19 [ref=1x] - { F(Mib) , 345, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #20 [ref=1x] + { F(Mib) , 347, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #20 [ref=1x] { 0 , 245, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #21 [ref=1x] { 0 , 150, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #22 [ref=35x] - { 0 , 346, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #23 [ref=3x] + { 0 , 348, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #23 [ref=3x] { 0 , 114, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #24 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 114, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #25 [ref=3x] { F(Rep)|F(RepIgnored) , 247, 2 , CONTROL(Call) , SINGLE_REG(None), 0 }, // #26 [ref=1x] - { 0 , 347, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #27 [ref=1x] - { 0 , 348, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #28 [ref=2x] - { 0 , 322, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #29 [ref=1x] + { 0 , 349, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #27 [ref=1x] + { 0 , 350, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #28 [ref=2x] + { 0 , 324, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #29 [ref=1x] { 0 , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #30 [ref=74x] - { 0 , 349, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #31 [ref=24x] - { 0 , 350, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #32 [ref=1x] + { 0 , 351, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #31 [ref=24x] + { 0 , 352, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #32 [ref=1x] { 0 , 16 , 12, CONTROL(None) , SINGLE_REG(None), 0 }, // #33 [ref=1x] - { F(Rep) , 351, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #34 [ref=1x] - { F(Vec) , 352, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #35 [ref=2x] - { F(Vec) , 353, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #36 [ref=3x] + { F(Rep) , 353, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #34 [ref=1x] + { F(Vec) , 354, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #35 [ref=2x] + { F(Vec) , 355, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #36 [ref=3x] { F(Lock)|F(XAcquire)|F(XRelease) , 118, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #37 [ref=1x] - { F(Lock)|F(XAcquire)|F(XRelease) , 354, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #38 [ref=1x] - { F(Lock)|F(XAcquire)|F(XRelease) , 355, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #39 [ref=1x] - { 0 , 356, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #40 [ref=1x] - { 0 , 357, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #41 [ref=1x] + { F(Lock)|F(XAcquire)|F(XRelease) , 356, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #38 [ref=1x] + { F(Lock)|F(XAcquire)|F(XRelease) , 357, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #39 [ref=1x] + { 0 , 358, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #40 [ref=1x] + { 0 , 359, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #41 [ref=1x] { 0 , 249, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #42 [ref=1x] - { F(Mmx)|F(Vec) , 358, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #43 [ref=2x] - { F(Mmx)|F(Vec) , 359, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #44 [ref=2x] - { F(Mmx)|F(Vec) , 360, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #45 [ref=2x] - { F(Vec) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #46 [ref=2x] - { F(Vec) , 362, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #47 [ref=2x] - { F(Vec) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #48 [ref=2x] - { 0 , 364, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #49 [ref=1x] - { 0 , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #50 [ref=2x] + { F(Mmx)|F(Vec) , 360, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #43 [ref=2x] + { F(Mmx)|F(Vec) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #44 [ref=2x] + { F(Mmx)|F(Vec) , 362, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #45 [ref=2x] + { F(Vec) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #46 [ref=2x] + { F(Vec) , 364, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #47 [ref=2x] + { F(Vec) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #48 [ref=2x] + { 0 , 366, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #49 [ref=1x] + { 0 , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #50 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 251, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #51 [ref=2x] { 0 , 39 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #52 [ref=3x] { F(Mmx) , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #53 [ref=1x] { 0 , 253, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #54 [ref=2x] - { 0 , 366, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #55 [ref=1x] - { F(Vec) , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #56 [ref=2x] + { 0 , 368, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #55 [ref=1x] + { F(Vec) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #56 [ref=2x] { F(Vec) , 255, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #57 [ref=1x] { F(FpuM32)|F(FpuM64) , 153, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #58 [ref=6x] { 0 , 257, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #59 [ref=9x] - { F(FpuM80) , 368, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #60 [ref=2x] + { F(FpuM80) , 370, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #60 [ref=2x] { 0 , 258, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #61 [ref=13x] { F(FpuM32)|F(FpuM64) , 259, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #62 [ref=2x] - { F(FpuM16)|F(FpuM32) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #63 [ref=9x] - { F(FpuM16)|F(FpuM32)|F(FpuM64) , 370, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #64 [ref=3x] - { F(FpuM32)|F(FpuM64)|F(FpuM80) , 371, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #65 [ref=2x] - { F(FpuM16) , 372, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #66 [ref=3x] - { F(FpuM16) , 373, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #67 [ref=2x] + { F(FpuM16)|F(FpuM32) , 371, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #63 [ref=9x] + { F(FpuM16)|F(FpuM32)|F(FpuM64) , 372, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #64 [ref=3x] + { F(FpuM32)|F(FpuM64)|F(FpuM80) , 373, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #65 [ref=2x] + { F(FpuM16) , 374, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #66 [ref=3x] + { F(FpuM16) , 375, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #67 [ref=2x] { F(FpuM32)|F(FpuM64) , 260, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #68 [ref=1x] - { 0 , 374, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #69 [ref=2x] + { 0 , 376, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #69 [ref=2x] { 0 , 39 , 10, CONTROL(None) , SINGLE_REG(None), 0 }, // #70 [ref=1x] - { 0 , 375, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #71 [ref=1x] - { F(Rep) , 376, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #72 [ref=1x] + { 0 , 377, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #71 [ref=1x] + { F(Rep) , 378, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #72 [ref=1x] { F(Vec) , 261, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #73 [ref=1x] - { 0 , 377, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #74 [ref=2x] - { 0 , 378, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #75 [ref=8x] + { 0 , 379, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #74 [ref=2x] + { 0 , 380, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #75 [ref=8x] { 0 , 263, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #76 [ref=3x] { 0 , 265, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #77 [ref=1x] { 0 , 257, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #78 [ref=3x] - { 0 , 379, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #79 [ref=1x] + { 0 , 381, 1 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #79 [ref=1x] { F(Rep)|F(RepIgnored) , 267, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #80 [ref=30x] { F(Rep)|F(RepIgnored) , 269, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #81 [ref=1x] { F(Rep)|F(RepIgnored) , 271, 2 , CONTROL(Jump) , SINGLE_REG(None), 0 }, // #82 [ref=1x] - { F(Vec)|F(Vex) , 380, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #83 [ref=27x] + { F(Vec)|F(Vex) , 382, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #83 [ref=27x] { F(Vec)|F(Vex) , 273, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #84 [ref=1x] { F(Vec)|F(Vex) , 275, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #85 [ref=1x] { F(Vec)|F(Vex) , 277, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #86 [ref=1x] { F(Vec)|F(Vex) , 279, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #87 [ref=1x] - { F(Vec)|F(Vex) , 381, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #88 [ref=12x] - { F(Vec)|F(Vex) , 382, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #89 [ref=8x] - { 0 , 383, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #90 [ref=2x] + { F(Vec)|F(Vex) , 383, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #88 [ref=12x] + { F(Vec)|F(Vex) , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #89 [ref=8x] + { 0 , 385, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #90 [ref=2x] { 0 , 281, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #91 [ref=1x] { F(Vec) , 192, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #92 [ref=2x] - { 0 , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #93 [ref=2x] + { 0 , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #93 [ref=2x] { 0 , 283, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #94 [ref=2x] - { 0 , 385, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #95 [ref=1x] + { 0 , 387, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #95 [ref=1x] { 0 , 156, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #96 [ref=3x] - { 0 , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #97 [ref=5x] - { F(Vex) , 387, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #98 [ref=2x] - { F(Rep) , 388, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #99 [ref=1x] + { 0 , 388, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #97 [ref=5x] + { F(Vex) , 389, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #98 [ref=2x] + { F(Rep) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #99 [ref=1x] { 0 , 269, 2 , CONTROL(Branch) , SINGLE_REG(None), 0 }, // #100 [ref=3x] { 0 , 285, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #101 [ref=1x] - { F(Vex) , 389, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #102 [ref=2x] - { F(Vec) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #103 [ref=1x] - { F(Mmx) , 391, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #104 [ref=1x] - { 0 , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #105 [ref=2x] + { F(Vex) , 391, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #102 [ref=2x] + { F(Vec) , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #103 [ref=1x] + { F(Mmx) , 393, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #104 [ref=1x] + { 0 , 394, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #105 [ref=2x] { F(XRelease) , 0 , 16, CONTROL(None) , SINGLE_REG(None), 0 }, // #106 [ref=1x] { F(Vec) , 70 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #107 [ref=6x] { 0 , 64 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #108 [ref=1x] { F(Mmx)|F(Vec) , 287, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #109 [ref=1x] - { 0 , 393, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #110 [ref=1x] + { 0 , 395, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #110 [ref=1x] { 0 , 68 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #111 [ref=2x] - { F(Mmx)|F(Vec) , 394, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #112 [ref=1x] + { F(Mmx)|F(Vec) , 396, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #112 [ref=1x] { F(Vec) , 256, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #113 [ref=2x] { F(Vec) , 198, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #114 [ref=4x] - { F(Vec) , 395, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #115 [ref=2x] + { F(Vec) , 397, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #115 [ref=2x] { F(Vec) , 71 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #116 [ref=3x] - { F(Mmx) , 396, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #117 [ref=1x] + { F(Mmx) , 398, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #117 [ref=1x] { F(Vec) , 98 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #118 [ref=1x] { F(Vec) , 201, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #119 [ref=1x] { F(Mmx)|F(Vec) , 94 , 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #120 [ref=1x] - { F(Mmx)|F(Vec) , 397, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #121 [ref=1x] - { F(Rep) , 398, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #122 [ref=1x] + { F(Mmx)|F(Vec) , 399, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #121 [ref=1x] + { F(Rep) , 400, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #122 [ref=1x] { F(Vec) , 97 , 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #123 [ref=1x] { F(Vec) , 289, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #124 [ref=1x] { 0 , 291, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #125 [ref=2x] - { 0 , 399, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #126 [ref=1x] - { F(Vex) , 293, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #127 [ref=1x] - { 0 , 400, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #128 [ref=1x] - { 0 , 401, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #129 [ref=1x] + { 0 , 293, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #126 [ref=1x] + { F(Vex) , 295, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #127 [ref=1x] + { 0 , 401, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #128 [ref=1x] + { 0 , 402, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #129 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 252, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #130 [ref=2x] - { 0 , 295, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #131 [ref=1x] + { 0 , 297, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #131 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(RO) , 0 }, // #132 [ref=1x] - { 0 , 402, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #133 [ref=1x] - { F(Rep) , 403, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #134 [ref=1x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #135 [ref=40x] - { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #136 [ref=1x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #137 [ref=6x] - { F(Mmx)|F(Vec) , 297, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #138 [ref=16x] - { F(Mmx) , 297, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #139 [ref=26x] + { 0 , 403, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #133 [ref=1x] + { F(Rep) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #134 [ref=1x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #135 [ref=40x] + { F(Mmx)|F(Vec) , 301, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #136 [ref=1x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #137 [ref=6x] + { F(Mmx)|F(Vec) , 299, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #138 [ref=16x] + { F(Mmx) , 299, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #139 [ref=26x] { F(Vec) , 70 , 1 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #140 [ref=4x] - { F(Vec) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #141 [ref=1x] - { F(Vec) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #142 [ref=1x] - { F(Vec) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #143 [ref=1x] - { F(Vec) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #144 [ref=1x] - { F(Vec) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #145 [ref=1x] - { F(Vec) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #146 [ref=1x] - { F(Mmx)|F(Vec) , 301, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #147 [ref=1x] - { F(Vec) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #148 [ref=1x] - { F(Vec) , 411, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #149 [ref=1x] - { F(Vec) , 412, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #150 [ref=1x] - { F(Mmx)|F(Vec) , 413, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #151 [ref=1x] - { F(Mmx)|F(Vec) , 414, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #152 [ref=1x] + { F(Vec) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #141 [ref=1x] + { F(Vec) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #142 [ref=1x] + { F(Vec) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #143 [ref=1x] + { F(Vec) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #144 [ref=1x] + { F(Vec) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #145 [ref=1x] + { F(Vec) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #146 [ref=1x] + { F(Mmx)|F(Vec) , 303, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #147 [ref=1x] + { F(Vec) , 411, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #148 [ref=1x] + { F(Vec) , 412, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #149 [ref=1x] + { F(Vec) , 413, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #150 [ref=1x] + { F(Mmx)|F(Vec) , 414, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #151 [ref=1x] + { F(Mmx)|F(Vec) , 415, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #152 [ref=1x] { F(Vec) , 225, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #153 [ref=2x] { 0 , 122, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #154 [ref=1x] - { 0 , 379, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #155 [ref=6x] - { F(Mmx) , 299, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #156 [ref=1x] - { F(Mmx)|F(Vec) , 303, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #157 [ref=8x] - { F(Vec) , 415, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #158 [ref=2x] + { 0 , 381, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #155 [ref=6x] + { F(Mmx) , 301, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #156 [ref=1x] + { F(Mmx)|F(Vec) , 305, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #157 [ref=8x] + { F(Vec) , 416, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #158 [ref=2x] { 0 , 126, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #159 [ref=1x] - { 0 , 416, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #160 [ref=8x] - { 0 , 417, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #161 [ref=4x] - { 0 , 418, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #162 [ref=6x] - { 0 , 305, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #163 [ref=1x] - { F(Rep)|F(RepIgnored) , 307, 2 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #164 [ref=1x] - { F(Vex) , 309, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #165 [ref=1x] + { 0 , 417, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #160 [ref=8x] + { 0 , 418, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #161 [ref=4x] + { 0 , 419, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #162 [ref=6x] + { 0 , 307, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #163 [ref=1x] + { F(Rep)|F(RepIgnored) , 309, 2 , CONTROL(Return) , SINGLE_REG(None), 0 }, // #164 [ref=1x] + { F(Vex) , 311, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #165 [ref=1x] { F(Lock)|F(XAcquire)|F(XRelease) , 16 , 12, CONTROL(None) , SINGLE_REG(WO) , 0 }, // #166 [ref=3x] - { F(Rep) , 419, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #167 [ref=1x] - { 0 , 420, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #168 [ref=30x] + { F(Rep) , 420, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #167 [ref=1x] + { 0 , 421, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #168 [ref=30x] { 0 , 159, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #169 [ref=2x] - { 0 , 421, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #170 [ref=3x] - { F(Rep) , 422, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #171 [ref=1x] + { 0 , 422, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #170 [ref=3x] + { F(Rep) , 423, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #171 [ref=1x] { 0 , 57 , 7 , CONTROL(None) , SINGLE_REG(None), 0 }, // #172 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 423, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #173 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 424, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #174 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 424, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #173 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512T4X)|F(Avx512KZ) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #174 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #175 [ref=22x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #176 [ref=22x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #177 [ref=18x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #178 [ref=17x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #177 [ref=18x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #178 [ref=17x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #179 [ref=15x] { F(Vec)|F(Vex)|F(Evex) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #180 [ref=5x] { F(Vec)|F(Vex) , 70 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #181 [ref=17x] @@ -2183,136 +2183,136 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #190 [ref=16x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #191 [ref=19x] { F(Vec)|F(Vex) , 165, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #192 [ref=6x] - { F(Vec)|F(Vex) , 311, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #193 [ref=3x] - { F(Vec)|F(Vex) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #194 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #195 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #196 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 430, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #197 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 431, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #198 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #199 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 432, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #200 [ref=1x] + { F(Vec)|F(Vex) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #193 [ref=3x] + { F(Vec)|F(Vex) , 428, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #194 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #195 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 430, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #196 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 431, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #197 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 432, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #198 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 429, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #199 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 433, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #200 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 168, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #201 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 168, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #202 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 433, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #203 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 434, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #204 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 434, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #203 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #204 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 97 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #205 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 222, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #206 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 171, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #207 [ref=6x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #208 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #209 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #210 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #211 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #210 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #211 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #212 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #213 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #213 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #214 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #215 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 180, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #216 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #217 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #218 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #219 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #220 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #221 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #222 [ref=3x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #223 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #224 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #225 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #219 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #220 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #221 [ref=2x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #222 [ref=3x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512ER_SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #223 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #224 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #225 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #226 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 313, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #227 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #227 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #228 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #229 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #230 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #231 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512SAE) , 361, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #232 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #233 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #234 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #231 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512SAE) , 363, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #232 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #233 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512SAE) , 365, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #234 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 174, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #235 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 435, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #236 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512ER_SAE) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #236 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #237 [ref=3x] { F(Vec)|F(Vex) , 165, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #238 [ref=9x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 74 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #239 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 74 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #240 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #241 [ref=9x] { F(Vec)|F(Vex) , 181, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #242 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 436, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #243 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #243 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ) , 182, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #244 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 367, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #245 [ref=2x] + { F(Vec)|F(Vex)|F(Evex) , 369, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #245 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #246 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #247 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #248 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #249 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #248 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #249 [ref=4x] { F(Vec)|F(Vex) , 130, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #250 [ref=13x] - { F(Vec)|F(Vex) , 315, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #251 [ref=4x] - { F(Vec)|F(Vex) , 317, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #252 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512K_B64) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #253 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K_B32) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #254 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #255 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512K) , 441, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #256 [ref=1x] + { F(Vec)|F(Vex) , 317, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #251 [ref=4x] + { F(Vec)|F(Vex) , 319, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #252 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512K_B64) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #253 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K_B32) , 440, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #254 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K) , 441, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #255 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512K) , 442, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #256 [ref=1x] { F(Vec)|F(Vex) , 177, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #257 [ref=7x] { F(Vec)|F(Vex) , 97 , 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #258 [ref=1x] { F(Vec)|F(Vex) , 222, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #259 [ref=1x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 99 , 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #260 [ref=2x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 104, 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #261 [ref=2x] - { F(Vsib)|F(Evex)|F(Avx512K) , 442, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #262 [ref=4x] - { F(Vsib)|F(Evex)|F(Avx512K) , 443, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #263 [ref=4x] - { F(Vsib)|F(Evex)|F(Avx512K) , 444, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #264 [ref=8x] + { F(Vsib)|F(Evex)|F(Avx512K) , 443, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #262 [ref=4x] + { F(Vsib)|F(Evex)|F(Avx512K) , 444, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #263 [ref=4x] + { F(Vsib)|F(Evex)|F(Avx512K) , 445, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #264 [ref=8x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 109, 5 , CONTROL(None) , SINGLE_REG(None), 0 }, // #265 [ref=2x] { F(Vec)|F(Vsib)|F(Vex)|F(Evex)|F(Avx512K) , 134, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #266 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #267 [ref=3x] - { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #268 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #267 [ref=3x] + { F(Vec)|F(Evex)|F(Avx512KZ_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #268 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B64) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #269 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_SAE_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #270 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #271 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #272 [ref=22x] - { F(Vec)|F(Vex) , 319, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #273 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 319, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #274 [ref=4x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 445, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #275 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #276 [ref=1x] + { F(Vec)|F(Vex) , 321, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #273 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 321, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #274 [ref=4x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 446, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #275 [ref=4x] + { F(Vec)|F(Vex)|F(Evex) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #276 [ref=1x] { F(Vec)|F(Vex) , 192, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #277 [ref=1x] - { F(Vex) , 384, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #278 [ref=2x] - { F(Vec)|F(Vex) , 390, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #279 [ref=1x] + { F(Vex) , 386, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #278 [ref=2x] + { F(Vec)|F(Vex) , 392, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #279 [ref=1x] { F(Vec)|F(Vex) , 138, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #280 [ref=4x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #281 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #282 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #283 [ref=2x] - { 0 , 446, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #284 [ref=4x] - { 0 , 321, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #285 [ref=3x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #283 [ref=2x] + { 0 , 447, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #284 [ref=4x] + { 0 , 323, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #285 [ref=3x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 70 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #286 [ref=4x] - { F(Vec)|F(Vex)|F(Evex) , 323, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #287 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 325, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #287 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 186, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #288 [ref=1x] { F(Vec)|F(Vex) , 70 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #289 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ) , 70 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #290 [ref=6x] { F(Vec)|F(Vex)|F(Evex) , 200, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #291 [ref=2x] - { F(Vec)|F(Vex)|F(Evex) , 325, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #292 [ref=4x] - { F(Vec)|F(Vex) , 447, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #293 [ref=3x] + { F(Vec)|F(Vex)|F(Evex) , 327, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #292 [ref=4x] + { F(Vec)|F(Vex) , 448, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #293 [ref=3x] { F(Vec)|F(Vex)|F(Evex) , 189, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #294 [ref=3x] { F(Vec)|F(Vex)|F(Evex) , 192, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #295 [ref=1x] { F(Vec)|F(Vex)|F(Evex) , 195, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #296 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 198, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #297 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #298 [ref=5x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 201, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #299 [ref=1x] - { 0 , 327, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #300 [ref=1x] - { 0 , 329, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #301 [ref=1x] + { 0 , 329, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #300 [ref=1x] + { 0 , 331, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #301 [ref=1x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #302 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #303 [ref=2x] { F(Vec)|F(Vex) , 162, 2 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #304 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #305 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #306 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #307 [ref=2x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 448, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #308 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 449, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #309 [ref=1x] - { F(Vec)|F(Evex) , 450, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #310 [ref=6x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 449, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #308 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 450, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #309 [ref=1x] + { F(Vec)|F(Evex) , 451, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #310 [ref=6x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 204, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #311 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 451, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #312 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 452, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #312 [ref=1x] { F(Vec)|F(Vex)|F(Evex) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #313 [ref=1x] { F(Vec)|F(Evex)|F(Avx512K) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #314 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B32) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #315 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #316 [ref=4x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K_B32) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #317 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512K_B64) , 210, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #318 [ref=2x] - { F(Vec)|F(Vex) , 404, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #319 [ref=1x] - { F(Vec)|F(Vex) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #320 [ref=1x] - { F(Vec)|F(Vex) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #321 [ref=1x] - { F(Vec)|F(Vex) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #322 [ref=1x] + { F(Vec)|F(Vex) , 405, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #319 [ref=1x] + { F(Vec)|F(Vex) , 406, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #320 [ref=1x] + { F(Vec)|F(Vex) , 407, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #321 [ref=1x] + { F(Vec)|F(Vex) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #322 [ref=1x] { F(Vec)|F(Evex)|F(Avx512K_B64) , 207, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #323 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #324 [ref=6x] { F(Vec)|F(Vex) , 166, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #325 [ref=2x] @@ -2320,17 +2320,17 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex) , 142, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #327 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 76 , 6 , CONTROL(None) , SINGLE_REG(None), 0 }, // #328 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 146, 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #329 [ref=2x] - { F(Vec)|F(Vex)|F(Evex) , 408, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #330 [ref=1x] - { F(Vec)|F(Vex)|F(Evex) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #331 [ref=1x] - { F(Vec)|F(Vex)|F(Evex) , 452, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #332 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 453, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #333 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 454, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #334 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 455, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #335 [ref=1x] - { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 456, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #336 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 409, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #330 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 410, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #331 [ref=1x] + { F(Vec)|F(Vex)|F(Evex) , 453, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #332 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 454, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #333 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 455, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #334 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 456, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #335 [ref=1x] + { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 457, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #336 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #337 [ref=4x] - { F(Vec)|F(Vex) , 311, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #338 [ref=12x] + { F(Vec)|F(Vex) , 313, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #338 [ref=12x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 162, 3 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #339 [ref=8x] - { F(Vec)|F(Evex) , 457, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #340 [ref=4x] + { F(Vec)|F(Evex) , 458, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #340 [ref=4x] { F(Vec)|F(Evex)|F(Avx512KZ) , 213, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #341 [ref=6x] { F(Vec)|F(Evex)|F(Avx512KZ) , 216, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #342 [ref=9x] { F(Vec)|F(Evex)|F(Avx512KZ) , 219, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #343 [ref=3x] @@ -2340,11 +2340,11 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex) , 130, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #347 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #348 [ref=3x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #349 [ref=3x] - { F(Vec)|F(Vex) , 331, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #350 [ref=4x] + { F(Vec)|F(Vex) , 333, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #350 [ref=4x] { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 228, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #351 [ref=3x] - { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 333, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #352 [ref=2x] + { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 335, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #352 [ref=2x] { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 231, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #353 [ref=2x] - { F(Vec)|F(Vex) , 335, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #354 [ref=8x] + { F(Vec)|F(Vex) , 337, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #354 [ref=8x] { F(Vec)|F(Evex)|F(Avx512K) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #355 [ref=5x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #356 [ref=1x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ) , 183, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #357 [ref=2x] @@ -2358,19 +2358,19 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(WO) , 0 }, // #365 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B32) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #366 [ref=2x] { F(Vec)|F(Evex)|F(Avx512K_B64) , 234, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #367 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #368 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #369 [ref=2x] - { F(Vec)|F(Vex) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #370 [ref=2x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #371 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #372 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #368 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #369 [ref=2x] + { F(Vec)|F(Vex) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #370 [ref=2x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #371 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #372 [ref=1x] { F(Vec)|F(Vex) , 183, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #373 [ref=2x] - { F(Vec)|F(Vex) , 437, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #374 [ref=1x] - { F(Vec)|F(Vex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #375 [ref=1x] + { F(Vec)|F(Vex) , 438, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #374 [ref=1x] + { F(Vec)|F(Vex) , 439, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #375 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #376 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE_B32) , 162, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #377 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 425, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #378 [ref=1x] - { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #379 [ref=1x] - { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 337, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #380 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 426, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #378 [ref=1x] + { F(Vec)|F(Evex)|F(Avx512KZ_ER_SAE) , 427, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #379 [ref=1x] + { F(Vec)|F(Vsib)|F(Evex)|F(Avx512K) , 339, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #380 [ref=1x] { F(Vec)|F(Evex)|F(Avx512KZ_B32) , 166, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #381 [ref=2x] { F(Vec)|F(Evex)|F(Avx512KZ_B64) , 166, 2 , CONTROL(None) , SINGLE_REG(None), 0 }, // #382 [ref=2x] { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_B32) , 165, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #383 [ref=1x] @@ -2378,10 +2378,10 @@ const InstDB::CommonInfo InstDB::_commonInfoTable[] = { { F(Vec)|F(Vex)|F(Evex)|F(Avx512KZ_ER_SAE_B64) , 177, 3 , CONTROL(None) , SINGLE_REG(None), 0 }, // #385 [ref=1x] { F(Vec)|F(Vex) , 257, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #386 [ref=2x] { F(Lock)|F(XAcquire)|F(XRelease) , 49 , 4 , CONTROL(None) , SINGLE_REG(None), 0 }, // #387 [ref=1x] - { 0 , 458, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #388 [ref=1x] + { 0 , 459, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #388 [ref=1x] { F(Lock)|F(XAcquire) , 49 , 8 , CONTROL(None) , SINGLE_REG(RO) , 0 }, // #389 [ref=1x] - { 0 , 459, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #390 [ref=6x] - { 0 , 460, 1 , CONTROL(None) , SINGLE_REG(None), 0 } // #391 [ref=6x] + { 0 , 460, 1 , CONTROL(None) , SINGLE_REG(None), 0 }, // #390 [ref=6x] + { 0 , 461, 1 , CONTROL(None) , SINGLE_REG(None), 0 } // #391 [ref=6x] }; #undef SINGLE_REG #undef CONTROL @@ -3070,174 +3070,175 @@ const InstDB::InstSignature InstDB::_instSignatureTable[] = { ROW(2, 1, 1, 0, 29 , 45 , 0 , 0 , 0 , 0 ), // {m32|mem, xmm} ROW(2, 1, 1, 0, 4 , 9 , 0 , 0 , 0 , 0 ), // #291 {r16, r8lo|r8hi|m8} ROW(2, 1, 1, 0, 114, 115, 0 , 0 , 0 , 0 ), // {r32|r64, r8lo|r8hi|m8|r16|m16} - ROW(4, 1, 1, 1, 6 , 6 , 28 , 35 , 0 , 0 ), // #293 {r32, r32, r32|m32|mem, <edx>} + ROW(2, 0, 1, 0, 4 , 27 , 0 , 0 , 0 , 0 ), // #293 {r16, r16|m16|mem} + ROW(2, 0, 1, 0, 114, 28 , 0 , 0 , 0 , 0 ), // {r32|r64, r32|m32|mem} + ROW(4, 1, 1, 1, 6 , 6 , 28 , 35 , 0 , 0 ), // #295 {r32, r32, r32|m32|mem, <edx>} ROW(4, 0, 1, 1, 8 , 8 , 15 , 37 , 0 , 0 ), // {r64, r64, r64|m64|mem, <rdx>} - ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #295 {} + ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #297 {} ROW(1, 1, 1, 0, 116, 0 , 0 , 0 , 0 , 0 ), // {r16|m16|r32|m32} - ROW(2, 1, 1, 0, 57 , 117, 0 , 0 , 0 , 0 ), // #297 {mm, mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 117, 0 , 0 , 0 , 0 ), // #299 {mm, mm|m64|mem} ROW(2, 1, 1, 0, 45 , 46 , 0 , 0 , 0 , 0 ), // {xmm, xmm|m128|mem} - ROW(3, 1, 1, 0, 57 , 117, 10 , 0 , 0 , 0 ), // #299 {mm, mm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 57 , 117, 10 , 0 , 0 , 0 ), // #301 {mm, mm|m64|mem, i8|u8} ROW(3, 1, 1, 0, 45 , 46 , 10 , 0 , 0 , 0 ), // {xmm, xmm|m128|mem, i8|u8} - ROW(3, 1, 1, 0, 6 , 59 , 10 , 0 , 0 , 0 ), // #301 {r32, mm|xmm, i8|u8} + ROW(3, 1, 1, 0, 6 , 59 , 10 , 0 , 0 , 0 ), // #303 {r32, mm|xmm, i8|u8} ROW(3, 1, 1, 0, 21 , 45 , 10 , 0 , 0 , 0 ), // {m16|mem, xmm, i8|u8} - ROW(2, 1, 1, 0, 57 , 118, 0 , 0 , 0 , 0 ), // #303 {mm, i8|u8|mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 118, 0 , 0 , 0 , 0 ), // #305 {mm, i8|u8|mm|m64|mem} ROW(2, 1, 1, 0, 45 , 54 , 0 , 0 , 0 , 0 ), // {xmm, i8|u8|xmm|m128|mem} - ROW(1, 1, 0, 0, 6 , 0 , 0 , 0 , 0 , 0 ), // #305 {r32} + ROW(1, 1, 0, 0, 6 , 0 , 0 , 0 , 0 , 0 ), // #307 {r32} ROW(1, 0, 1, 0, 8 , 0 , 0 , 0 , 0 , 0 ), // {r64} - ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #307 {} + ROW(0, 1, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #309 {} ROW(1, 1, 1, 0, 119, 0 , 0 , 0 , 0 , 0 ), // {u16} - ROW(3, 1, 1, 0, 6 , 28 , 10 , 0 , 0 , 0 ), // #309 {r32, r32|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 6 , 28 , 10 , 0 , 0 , 0 ), // #311 {r32, r32|m32|mem, i8|u8} ROW(3, 0, 1, 0, 8 , 15 , 10 , 0 , 0 , 0 ), // {r64, r64|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 46 , 45 , 0 , 0 ), // #311 {xmm, xmm, xmm|m128|mem, xmm} + ROW(4, 1, 1, 0, 45 , 45 , 46 , 45 , 0 , 0 ), // #313 {xmm, xmm, xmm|m128|mem, xmm} ROW(4, 1, 1, 0, 48 , 48 , 49 , 48 , 0 , 0 ), // {ymm, ymm, ymm|m256|mem, ymm} - ROW(2, 1, 1, 0, 45 , 120, 0 , 0 , 0 , 0 ), // #313 {xmm, xmm|m128|ymm|m256} + ROW(2, 1, 1, 0, 45 , 120, 0 , 0 , 0 , 0 ), // #315 {xmm, xmm|m128|ymm|m256} ROW(2, 1, 1, 0, 48 , 52 , 0 , 0 , 0 , 0 ), // {ymm, zmm|m512|mem} - ROW(4, 1, 1, 0, 45 , 45 , 45 , 60 , 0 , 0 ), // #315 {xmm, xmm, xmm, xmm|m64|mem} + ROW(4, 1, 1, 0, 45 , 45 , 45 , 60 , 0 , 0 ), // #317 {xmm, xmm, xmm, xmm|m64|mem} ROW(4, 1, 1, 0, 45 , 45 , 30 , 45 , 0 , 0 ), // {xmm, xmm, m64|mem, xmm} - ROW(4, 1, 1, 0, 45 , 45 , 45 , 87 , 0 , 0 ), // #317 {xmm, xmm, xmm, xmm|m32|mem} + ROW(4, 1, 1, 0, 45 , 45 , 45 , 87 , 0 , 0 ), // #319 {xmm, xmm, xmm, xmm|m32|mem} ROW(4, 1, 1, 0, 45 , 45 , 29 , 45 , 0 , 0 ), // {xmm, xmm, m32|mem, xmm} - ROW(4, 1, 1, 0, 48 , 48 , 46 , 10 , 0 , 0 ), // #319 {ymm, ymm, xmm|m128|mem, i8|u8} + ROW(4, 1, 1, 0, 48 , 48 , 46 , 10 , 0 , 0 ), // #321 {ymm, ymm, xmm|m128|mem, i8|u8} ROW(4, 1, 1, 0, 51 , 51 , 46 , 10 , 0 , 0 ), // {zmm, zmm, xmm|m128|mem, i8|u8} - ROW(1, 1, 0, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #321 {<eax>} - ROW(1, 0, 1, 1, 38 , 0 , 0 , 0 , 0 , 0 ), // #322 {<rax>} - ROW(2, 1, 1, 0, 28 , 45 , 0 , 0 , 0 , 0 ), // #323 {r32|m32|mem, xmm} + ROW(1, 1, 0, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #323 {<eax>} + ROW(1, 0, 1, 1, 38 , 0 , 0 , 0 , 0 , 0 ), // #324 {<rax>} + ROW(2, 1, 1, 0, 28 , 45 , 0 , 0 , 0 , 0 ), // #325 {r32|m32|mem, xmm} ROW(2, 1, 1, 0, 45 , 28 , 0 , 0 , 0 , 0 ), // {xmm, r32|m32|mem} - ROW(2, 1, 1, 0, 30 , 45 , 0 , 0 , 0 , 0 ), // #325 {m64|mem, xmm} + ROW(2, 1, 1, 0, 30 , 45 , 0 , 0 , 0 , 0 ), // #327 {m64|mem, xmm} ROW(3, 1, 1, 0, 45 , 45 , 30 , 0 , 0 , 0 ), // {xmm, xmm, m64|mem} - ROW(2, 1, 0, 0, 28 , 6 , 0 , 0 , 0 , 0 ), // #327 {r32|m32|mem, r32} + ROW(2, 1, 0, 0, 28 , 6 , 0 , 0 , 0 , 0 ), // #329 {r32|m32|mem, r32} ROW(2, 0, 1, 0, 15 , 8 , 0 , 0 , 0 , 0 ), // {r64|m64|mem, r64} - ROW(2, 1, 0, 0, 6 , 28 , 0 , 0 , 0 , 0 ), // #329 {r32, r32|m32|mem} + ROW(2, 1, 0, 0, 6 , 28 , 0 , 0 , 0 , 0 ), // #331 {r32, r32|m32|mem} ROW(2, 0, 1, 0, 8 , 15 , 0 , 0 , 0 , 0 ), // {r64, r64|m64|mem} - ROW(3, 1, 1, 0, 45 , 45 , 54 , 0 , 0 , 0 ), // #331 {xmm, xmm, xmm|m128|mem|i8|u8} + ROW(3, 1, 1, 0, 45 , 45 , 54 , 0 , 0 , 0 ), // #333 {xmm, xmm, xmm|m128|mem|i8|u8} ROW(3, 1, 1, 0, 45 , 47 , 121, 0 , 0 , 0 ), // {xmm, m128|mem, i8|u8|xmm} - ROW(2, 1, 1, 0, 74 , 45 , 0 , 0 , 0 , 0 ), // #333 {vm64x|vm64y, xmm} + ROW(2, 1, 1, 0, 74 , 45 , 0 , 0 , 0 , 0 ), // #335 {vm64x|vm64y, xmm} ROW(2, 1, 1, 0, 66 , 48 , 0 , 0 , 0 , 0 ), // {vm64z, ymm} - ROW(3, 1, 1, 0, 45 , 45 , 46 , 0 , 0 , 0 ), // #335 {xmm, xmm, xmm|m128|mem} + ROW(3, 1, 1, 0, 45 , 45 , 46 , 0 , 0 , 0 ), // #337 {xmm, xmm, xmm|m128|mem} ROW(3, 1, 1, 0, 45 , 47 , 45 , 0 , 0 , 0 ), // {xmm, m128|mem, xmm} - ROW(2, 1, 1, 0, 61 , 86 , 0 , 0 , 0 , 0 ), // #337 {vm32x, xmm|ymm} + ROW(2, 1, 1, 0, 61 , 86 , 0 , 0 , 0 , 0 ), // #339 {vm32x, xmm|ymm} ROW(2, 1, 1, 0, 62 , 51 , 0 , 0 , 0 , 0 ), // {vm32y, zmm} - ROW(1, 1, 0, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #339 {<ax>} - ROW(2, 1, 0, 1, 33 , 10 , 0 , 0 , 0 , 0 ), // #340 {<ax>, i8|u8} - ROW(2, 1, 0, 0, 27 , 4 , 0 , 0 , 0 , 0 ), // #341 {r16|m16|mem, r16} - ROW(3, 1, 1, 1, 45 , 46 , 122, 0 , 0 , 0 ), // #342 {xmm, xmm|m128|mem, <xmm0>} - ROW(2, 1, 1, 0, 89 , 123, 0 , 0 , 0 , 0 ), // #343 {bnd, mib} - ROW(2, 1, 1, 0, 89 , 91 , 0 , 0 , 0 , 0 ), // #344 {bnd, mem} - ROW(2, 1, 1, 0, 123, 89 , 0 , 0 , 0 , 0 ), // #345 {mib, bnd} - ROW(1, 1, 1, 0, 124, 0 , 0 , 0 , 0 , 0 ), // #346 {r16|r32|r64} - ROW(1, 1, 1, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #347 {<ax>} - ROW(2, 1, 1, 2, 35 , 36 , 0 , 0 , 0 , 0 ), // #348 {<edx>, <eax>} - ROW(1, 1, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #349 {mem} - ROW(1, 1, 1, 1, 125, 0 , 0 , 0 , 0 , 0 ), // #350 {<ds:[memBase|zax]>} - ROW(2, 1, 1, 2, 126, 127, 0 , 0 , 0 , 0 ), // #351 {<ds:[memBase|zsi]>, <es:[memBase|zdi]>} - ROW(3, 1, 1, 0, 45 , 60 , 10 , 0 , 0 , 0 ), // #352 {xmm, xmm|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 45 , 87 , 10 , 0 , 0 , 0 ), // #353 {xmm, xmm|m32|mem, i8|u8} - ROW(5, 0, 1, 4, 47 , 37 , 38 , 128, 129, 0 ), // #354 {m128|mem, <rdx>, <rax>, <rcx>, <rbx>} - ROW(5, 1, 1, 4, 30 , 35 , 36 , 99 , 130, 0 ), // #355 {m64|mem, <edx>, <eax>, <ecx>, <ebx>} - ROW(4, 1, 1, 4, 36 , 130, 99 , 35 , 0 , 0 ), // #356 {<eax>, <ebx>, <ecx>, <edx>} - ROW(2, 0, 1, 2, 37 , 38 , 0 , 0 , 0 , 0 ), // #357 {<rdx>, <rax>} - ROW(2, 1, 1, 0, 57 , 46 , 0 , 0 , 0 , 0 ), // #358 {mm, xmm|m128|mem} - ROW(2, 1, 1, 0, 45 , 117, 0 , 0 , 0 , 0 ), // #359 {xmm, mm|m64|mem} - ROW(2, 1, 1, 0, 57 , 60 , 0 , 0 , 0 , 0 ), // #360 {mm, xmm|m64|mem} - ROW(2, 1, 1, 0, 114, 60 , 0 , 0 , 0 , 0 ), // #361 {r32|r64, xmm|m64|mem} - ROW(2, 1, 1, 0, 45 , 131, 0 , 0 , 0 , 0 ), // #362 {xmm, r32|m32|mem|r64|m64} - ROW(2, 1, 1, 0, 114, 87 , 0 , 0 , 0 , 0 ), // #363 {r32|r64, xmm|m32|mem} - ROW(2, 1, 1, 2, 34 , 33 , 0 , 0 , 0 , 0 ), // #364 {<dx>, <ax>} - ROW(1, 1, 1, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #365 {<eax>} - ROW(2, 1, 1, 0, 12 , 10 , 0 , 0 , 0 , 0 ), // #366 {i16|u16, i8|u8} - ROW(3, 1, 1, 0, 28 , 45 , 10 , 0 , 0 , 0 ), // #367 {r32|m32|mem, xmm, i8|u8} - ROW(1, 1, 1, 0, 80 , 0 , 0 , 0 , 0 , 0 ), // #368 {m80|mem} - ROW(1, 1, 1, 0, 132, 0 , 0 , 0 , 0 , 0 ), // #369 {m16|m32} - ROW(1, 1, 1, 0, 133, 0 , 0 , 0 , 0 , 0 ), // #370 {m16|m32|m64} - ROW(1, 1, 1, 0, 134, 0 , 0 , 0 , 0 , 0 ), // #371 {m32|m64|m80|st} - ROW(1, 1, 1, 0, 21 , 0 , 0 , 0 , 0 , 0 ), // #372 {m16|mem} - ROW(1, 1, 1, 0, 135, 0 , 0 , 0 , 0 , 0 ), // #373 {ax|m16|mem} - ROW(1, 0, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #374 {mem} - ROW(2, 1, 1, 0, 136, 137, 0 , 0 , 0 , 0 ), // #375 {al|ax|eax, i8|u8|dx} - ROW(2, 1, 1, 0, 138, 139, 0 , 0 , 0 , 0 ), // #376 {es:[memBase|zdi], dx} - ROW(1, 1, 1, 0, 10 , 0 , 0 , 0 , 0 , 0 ), // #377 {i8|u8} - ROW(0, 1, 0, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #378 {} - ROW(0, 0, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #379 {} - ROW(3, 1, 1, 0, 84 , 84 , 84 , 0 , 0 , 0 ), // #380 {k, k, k} - ROW(2, 1, 1, 0, 84 , 84 , 0 , 0 , 0 , 0 ), // #381 {k, k} - ROW(3, 1, 1, 0, 84 , 84 , 10 , 0 , 0 , 0 ), // #382 {k, k, i8|u8} - ROW(1, 1, 1, 1, 140, 0 , 0 , 0 , 0 , 0 ), // #383 {<ah>} - ROW(1, 1, 1, 0, 29 , 0 , 0 , 0 , 0 , 0 ), // #384 {m32|mem} - ROW(2, 1, 1, 0, 124, 141, 0 , 0 , 0 , 0 ), // #385 {r16|r32|r64, mem|m8|m16|m32|m48|m64|m80|m128|m256|m512|m1024} - ROW(1, 1, 1, 0, 27 , 0 , 0 , 0 , 0 , 0 ), // #386 {r16|m16|mem} - ROW(1, 1, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #387 {r32|r64} - ROW(2, 1, 1, 2, 142, 126, 0 , 0 , 0 , 0 ), // #388 {<al|ax|eax|rax>, <ds:[memBase|zsi]>} - ROW(3, 1, 1, 0, 114, 28 , 14 , 0 , 0 , 0 ), // #389 {r32|r64, r32|m32|mem, i32|u32} - ROW(3, 1, 1, 1, 45 , 45 , 143, 0 , 0 , 0 ), // #390 {xmm, xmm, <ds:[memBase|zdi]>} - ROW(3, 1, 1, 1, 57 , 57 , 143, 0 , 0 , 0 ), // #391 {mm, mm, <ds:[memBase|zdi]>} - ROW(3, 1, 1, 3, 125, 99 , 35 , 0 , 0 , 0 ), // #392 {<ds:[memBase|zax]>, <ecx>, <edx>} - ROW(2, 1, 1, 0, 97 , 53 , 0 , 0 , 0 , 0 ), // #393 {es:[memBase], m512|mem} - ROW(2, 1, 1, 0, 57 , 45 , 0 , 0 , 0 , 0 ), // #394 {mm, xmm} - ROW(2, 1, 1, 0, 6 , 45 , 0 , 0 , 0 , 0 ), // #395 {r32, xmm} - ROW(2, 1, 1, 0, 30 , 57 , 0 , 0 , 0 , 0 ), // #396 {m64|mem, mm} - ROW(2, 1, 1, 0, 45 , 57 , 0 , 0 , 0 , 0 ), // #397 {xmm, mm} - ROW(2, 1, 1, 2, 127, 126, 0 , 0 , 0 , 0 ), // #398 {<es:[memBase|zdi]>, <ds:[memBase|zsi]>} - ROW(2, 0, 1, 0, 8 , 28 , 0 , 0 , 0 , 0 ), // #399 {r64, r32|m32|mem} - ROW(2, 1, 1, 2, 36 , 99 , 0 , 0 , 0 , 0 ), // #400 {<eax>, <ecx>} - ROW(3, 1, 1, 3, 36 , 99 , 130, 0 , 0 , 0 ), // #401 {<eax>, <ecx>, <ebx>} - ROW(2, 1, 1, 0, 144, 136, 0 , 0 , 0 , 0 ), // #402 {u8|dx, al|ax|eax} - ROW(2, 1, 1, 0, 139, 145, 0 , 0 , 0 , 0 ), // #403 {dx, ds:[memBase|zsi]} - ROW(6, 1, 1, 3, 45 , 46 , 10 , 99 , 36 , 35 ), // #404 {xmm, xmm|m128|mem, i8|u8, <ecx>, <eax>, <edx>} - ROW(6, 1, 1, 3, 45 , 46 , 10 , 122, 36 , 35 ), // #405 {xmm, xmm|m128|mem, i8|u8, <xmm0>, <eax>, <edx>} - ROW(4, 1, 1, 1, 45 , 46 , 10 , 99 , 0 , 0 ), // #406 {xmm, xmm|m128|mem, i8|u8, <ecx>} - ROW(4, 1, 1, 1, 45 , 46 , 10 , 122, 0 , 0 ), // #407 {xmm, xmm|m128|mem, i8|u8, <xmm0>} - ROW(3, 1, 1, 0, 109, 45 , 10 , 0 , 0 , 0 ), // #408 {r32|m8|mem|r8lo|r8hi|r16, xmm, i8|u8} - ROW(3, 0, 1, 0, 15 , 45 , 10 , 0 , 0 , 0 ), // #409 {r64|m64|mem, xmm, i8|u8} - ROW(3, 1, 1, 0, 45 , 109, 10 , 0 , 0 , 0 ), // #410 {xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} - ROW(3, 1, 1, 0, 45 , 28 , 10 , 0 , 0 , 0 ), // #411 {xmm, r32|m32|mem, i8|u8} - ROW(3, 0, 1, 0, 45 , 15 , 10 , 0 , 0 , 0 ), // #412 {xmm, r64|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 59 , 113, 10 , 0 , 0 , 0 ), // #413 {mm|xmm, r32|m16|mem|r16, i8|u8} - ROW(2, 1, 1, 0, 6 , 59 , 0 , 0 , 0 , 0 ), // #414 {r32, mm|xmm} - ROW(2, 1, 1, 0, 45 , 10 , 0 , 0 , 0 , 0 ), // #415 {xmm, i8|u8} - ROW(2, 1, 1, 0, 31 , 81 , 0 , 0 , 0 , 0 ), // #416 {r8lo|r8hi|m8|r16|m16|r32|m32|r64|m64|mem, cl|i8|u8} - ROW(1, 0, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #417 {r32|r64} - ROW(3, 1, 1, 3, 35 , 36 , 99 , 0 , 0 , 0 ), // #418 {<edx>, <eax>, <ecx>} - ROW(2, 1, 1, 2, 142, 127, 0 , 0 , 0 , 0 ), // #419 {<al|ax|eax|rax>, <es:[memBase|zdi]>} - ROW(1, 1, 1, 0, 1 , 0 , 0 , 0 , 0 , 0 ), // #420 {r8lo|r8hi|m8|mem} - ROW(1, 1, 1, 0, 146, 0 , 0 , 0 , 0 , 0 ), // #421 {r16|m16|mem|r32|r64} - ROW(2, 1, 1, 2, 127, 142, 0 , 0 , 0 , 0 ), // #422 {<es:[memBase|zdi]>, <al|ax|eax|rax>} - ROW(6, 1, 1, 0, 51 , 51 , 51 , 51 , 51 , 47 ), // #423 {zmm, zmm, zmm, zmm, zmm, m128|mem} - ROW(6, 1, 1, 0, 45 , 45 , 45 , 45 , 45 , 47 ), // #424 {xmm, xmm, xmm, xmm, xmm, m128|mem} - ROW(3, 1, 1, 0, 45 , 45 , 60 , 0 , 0 , 0 ), // #425 {xmm, xmm, xmm|m64|mem} - ROW(3, 1, 1, 0, 45 , 45 , 87 , 0 , 0 , 0 ), // #426 {xmm, xmm, xmm|m32|mem} - ROW(2, 1, 1, 0, 48 , 47 , 0 , 0 , 0 , 0 ), // #427 {ymm, m128|mem} - ROW(2, 1, 1, 0, 147, 60 , 0 , 0 , 0 , 0 ), // #428 {ymm|zmm, xmm|m64|mem} - ROW(2, 1, 1, 0, 147, 47 , 0 , 0 , 0 , 0 ), // #429 {ymm|zmm, m128|mem} - ROW(2, 1, 1, 0, 51 , 50 , 0 , 0 , 0 , 0 ), // #430 {zmm, m256|mem} - ROW(2, 1, 1, 0, 148, 60 , 0 , 0 , 0 , 0 ), // #431 {xmm|ymm|zmm, xmm|m64|mem} - ROW(2, 1, 1, 0, 148, 87 , 0 , 0 , 0 , 0 ), // #432 {xmm|ymm|zmm, m32|mem|xmm} - ROW(4, 1, 1, 0, 82 , 45 , 60 , 10 , 0 , 0 ), // #433 {xmm|k, xmm, xmm|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 82 , 45 , 87 , 10 , 0 , 0 ), // #434 {xmm|k, xmm, xmm|m32|mem, i8|u8} - ROW(3, 1, 1, 0, 45 , 45 , 131, 0 , 0 , 0 ), // #435 {xmm, xmm, r32|m32|mem|r64|m64} - ROW(3, 1, 1, 0, 46 , 147, 10 , 0 , 0 , 0 ), // #436 {xmm|m128|mem, ymm|zmm, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 60 , 10 , 0 , 0 ), // #437 {xmm, xmm, xmm|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 87 , 10 , 0 , 0 ), // #438 {xmm, xmm, xmm|m32|mem, i8|u8} - ROW(3, 1, 1, 0, 84 , 149, 10 , 0 , 0 , 0 ), // #439 {k, xmm|m128|ymm|m256|zmm|m512, i8|u8} - ROW(3, 1, 1, 0, 84 , 60 , 10 , 0 , 0 , 0 ), // #440 {k, xmm|m64|mem, i8|u8} - ROW(3, 1, 1, 0, 84 , 87 , 10 , 0 , 0 , 0 ), // #441 {k, xmm|m32|mem, i8|u8} - ROW(1, 1, 1, 0, 62 , 0 , 0 , 0 , 0 , 0 ), // #442 {vm32y} - ROW(1, 1, 1, 0, 63 , 0 , 0 , 0 , 0 , 0 ), // #443 {vm32z} - ROW(1, 1, 1, 0, 66 , 0 , 0 , 0 , 0 , 0 ), // #444 {vm64z} - ROW(4, 1, 1, 0, 51 , 51 , 49 , 10 , 0 , 0 ), // #445 {zmm, zmm, ymm|m256|mem, i8|u8} - ROW(1, 1, 1, 0, 30 , 0 , 0 , 0 , 0 , 0 ), // #446 {m64|mem} - ROW(2, 1, 1, 0, 6 , 86 , 0 , 0 , 0 , 0 ), // #447 {r32, xmm|ymm} - ROW(2, 1, 1, 0, 148, 150, 0 , 0 , 0 , 0 ), // #448 {xmm|ymm|zmm, xmm|m8|mem|r32|r8lo|r8hi|r16} - ROW(2, 1, 1, 0, 148, 151, 0 , 0 , 0 , 0 ), // #449 {xmm|ymm|zmm, xmm|m32|mem|r32} - ROW(2, 1, 1, 0, 148, 84 , 0 , 0 , 0 , 0 ), // #450 {xmm|ymm|zmm, k} - ROW(2, 1, 1, 0, 148, 152, 0 , 0 , 0 , 0 ), // #451 {xmm|ymm|zmm, xmm|m16|mem|r32|r16} - ROW(3, 1, 1, 0, 113, 45 , 10 , 0 , 0 , 0 ), // #452 {r32|m16|mem|r16, xmm, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 109, 10 , 0 , 0 ), // #453 {xmm, xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 28 , 10 , 0 , 0 ), // #454 {xmm, xmm, r32|m32|mem, i8|u8} - ROW(4, 0, 1, 0, 45 , 45 , 15 , 10 , 0 , 0 ), // #455 {xmm, xmm, r64|m64|mem, i8|u8} - ROW(4, 1, 1, 0, 45 , 45 , 113, 10 , 0 , 0 ), // #456 {xmm, xmm, r32|m16|mem|r16, i8|u8} - ROW(2, 1, 1, 0, 84 , 148, 0 , 0 , 0 , 0 ), // #457 {k, xmm|ymm|zmm} - ROW(1, 1, 1, 0, 102, 0 , 0 , 0 , 0 , 0 ), // #458 {rel16|rel32} - ROW(3, 1, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ), // #459 {mem, <edx>, <eax>} - ROW(3, 0, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ) // #460 {mem, <edx>, <eax>} + ROW(1, 1, 0, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #341 {<ax>} + ROW(2, 1, 0, 1, 33 , 10 , 0 , 0 , 0 , 0 ), // #342 {<ax>, i8|u8} + ROW(2, 1, 0, 0, 27 , 4 , 0 , 0 , 0 , 0 ), // #343 {r16|m16|mem, r16} + ROW(3, 1, 1, 1, 45 , 46 , 122, 0 , 0 , 0 ), // #344 {xmm, xmm|m128|mem, <xmm0>} + ROW(2, 1, 1, 0, 89 , 123, 0 , 0 , 0 , 0 ), // #345 {bnd, mib} + ROW(2, 1, 1, 0, 89 , 91 , 0 , 0 , 0 , 0 ), // #346 {bnd, mem} + ROW(2, 1, 1, 0, 123, 89 , 0 , 0 , 0 , 0 ), // #347 {mib, bnd} + ROW(1, 1, 1, 0, 124, 0 , 0 , 0 , 0 , 0 ), // #348 {r16|r32|r64} + ROW(1, 1, 1, 1, 33 , 0 , 0 , 0 , 0 , 0 ), // #349 {<ax>} + ROW(2, 1, 1, 2, 35 , 36 , 0 , 0 , 0 , 0 ), // #350 {<edx>, <eax>} + ROW(1, 1, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #351 {mem} + ROW(1, 1, 1, 1, 125, 0 , 0 , 0 , 0 , 0 ), // #352 {<ds:[memBase|zax]>} + ROW(2, 1, 1, 2, 126, 127, 0 , 0 , 0 , 0 ), // #353 {<ds:[memBase|zsi]>, <es:[memBase|zdi]>} + ROW(3, 1, 1, 0, 45 , 60 , 10 , 0 , 0 , 0 ), // #354 {xmm, xmm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 45 , 87 , 10 , 0 , 0 , 0 ), // #355 {xmm, xmm|m32|mem, i8|u8} + ROW(5, 0, 1, 4, 47 , 37 , 38 , 128, 129, 0 ), // #356 {m128|mem, <rdx>, <rax>, <rcx>, <rbx>} + ROW(5, 1, 1, 4, 30 , 35 , 36 , 99 , 130, 0 ), // #357 {m64|mem, <edx>, <eax>, <ecx>, <ebx>} + ROW(4, 1, 1, 4, 36 , 130, 99 , 35 , 0 , 0 ), // #358 {<eax>, <ebx>, <ecx>, <edx>} + ROW(2, 0, 1, 2, 37 , 38 , 0 , 0 , 0 , 0 ), // #359 {<rdx>, <rax>} + ROW(2, 1, 1, 0, 57 , 46 , 0 , 0 , 0 , 0 ), // #360 {mm, xmm|m128|mem} + ROW(2, 1, 1, 0, 45 , 117, 0 , 0 , 0 , 0 ), // #361 {xmm, mm|m64|mem} + ROW(2, 1, 1, 0, 57 , 60 , 0 , 0 , 0 , 0 ), // #362 {mm, xmm|m64|mem} + ROW(2, 1, 1, 0, 114, 60 , 0 , 0 , 0 , 0 ), // #363 {r32|r64, xmm|m64|mem} + ROW(2, 1, 1, 0, 45 , 131, 0 , 0 , 0 , 0 ), // #364 {xmm, r32|m32|mem|r64|m64} + ROW(2, 1, 1, 0, 114, 87 , 0 , 0 , 0 , 0 ), // #365 {r32|r64, xmm|m32|mem} + ROW(2, 1, 1, 2, 34 , 33 , 0 , 0 , 0 , 0 ), // #366 {<dx>, <ax>} + ROW(1, 1, 1, 1, 36 , 0 , 0 , 0 , 0 , 0 ), // #367 {<eax>} + ROW(2, 1, 1, 0, 12 , 10 , 0 , 0 , 0 , 0 ), // #368 {i16|u16, i8|u8} + ROW(3, 1, 1, 0, 28 , 45 , 10 , 0 , 0 , 0 ), // #369 {r32|m32|mem, xmm, i8|u8} + ROW(1, 1, 1, 0, 80 , 0 , 0 , 0 , 0 , 0 ), // #370 {m80|mem} + ROW(1, 1, 1, 0, 132, 0 , 0 , 0 , 0 , 0 ), // #371 {m16|m32} + ROW(1, 1, 1, 0, 133, 0 , 0 , 0 , 0 , 0 ), // #372 {m16|m32|m64} + ROW(1, 1, 1, 0, 134, 0 , 0 , 0 , 0 , 0 ), // #373 {m32|m64|m80|st} + ROW(1, 1, 1, 0, 21 , 0 , 0 , 0 , 0 , 0 ), // #374 {m16|mem} + ROW(1, 1, 1, 0, 135, 0 , 0 , 0 , 0 , 0 ), // #375 {ax|m16|mem} + ROW(1, 0, 1, 0, 91 , 0 , 0 , 0 , 0 , 0 ), // #376 {mem} + ROW(2, 1, 1, 0, 136, 137, 0 , 0 , 0 , 0 ), // #377 {al|ax|eax, i8|u8|dx} + ROW(2, 1, 1, 0, 138, 139, 0 , 0 , 0 , 0 ), // #378 {es:[memBase|zdi], dx} + ROW(1, 1, 1, 0, 10 , 0 , 0 , 0 , 0 , 0 ), // #379 {i8|u8} + ROW(0, 1, 0, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #380 {} + ROW(0, 0, 1, 0, 0 , 0 , 0 , 0 , 0 , 0 ), // #381 {} + ROW(3, 1, 1, 0, 84 , 84 , 84 , 0 , 0 , 0 ), // #382 {k, k, k} + ROW(2, 1, 1, 0, 84 , 84 , 0 , 0 , 0 , 0 ), // #383 {k, k} + ROW(3, 1, 1, 0, 84 , 84 , 10 , 0 , 0 , 0 ), // #384 {k, k, i8|u8} + ROW(1, 1, 1, 1, 140, 0 , 0 , 0 , 0 , 0 ), // #385 {<ah>} + ROW(1, 1, 1, 0, 29 , 0 , 0 , 0 , 0 , 0 ), // #386 {m32|mem} + ROW(2, 1, 1, 0, 124, 141, 0 , 0 , 0 , 0 ), // #387 {r16|r32|r64, mem|m8|m16|m32|m48|m64|m80|m128|m256|m512|m1024} + ROW(1, 1, 1, 0, 27 , 0 , 0 , 0 , 0 , 0 ), // #388 {r16|m16|mem} + ROW(1, 1, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #389 {r32|r64} + ROW(2, 1, 1, 2, 142, 126, 0 , 0 , 0 , 0 ), // #390 {<al|ax|eax|rax>, <ds:[memBase|zsi]>} + ROW(3, 1, 1, 0, 114, 28 , 14 , 0 , 0 , 0 ), // #391 {r32|r64, r32|m32|mem, i32|u32} + ROW(3, 1, 1, 1, 45 , 45 , 143, 0 , 0 , 0 ), // #392 {xmm, xmm, <ds:[memBase|zdi]>} + ROW(3, 1, 1, 1, 57 , 57 , 143, 0 , 0 , 0 ), // #393 {mm, mm, <ds:[memBase|zdi]>} + ROW(3, 1, 1, 3, 125, 99 , 35 , 0 , 0 , 0 ), // #394 {<ds:[memBase|zax]>, <ecx>, <edx>} + ROW(2, 1, 1, 0, 97 , 53 , 0 , 0 , 0 , 0 ), // #395 {es:[memBase], m512|mem} + ROW(2, 1, 1, 0, 57 , 45 , 0 , 0 , 0 , 0 ), // #396 {mm, xmm} + ROW(2, 1, 1, 0, 6 , 45 , 0 , 0 , 0 , 0 ), // #397 {r32, xmm} + ROW(2, 1, 1, 0, 30 , 57 , 0 , 0 , 0 , 0 ), // #398 {m64|mem, mm} + ROW(2, 1, 1, 0, 45 , 57 , 0 , 0 , 0 , 0 ), // #399 {xmm, mm} + ROW(2, 1, 1, 2, 127, 126, 0 , 0 , 0 , 0 ), // #400 {<es:[memBase|zdi]>, <ds:[memBase|zsi]>} + ROW(2, 1, 1, 2, 36 , 99 , 0 , 0 , 0 , 0 ), // #401 {<eax>, <ecx>} + ROW(3, 1, 1, 3, 36 , 99 , 130, 0 , 0 , 0 ), // #402 {<eax>, <ecx>, <ebx>} + ROW(2, 1, 1, 0, 144, 136, 0 , 0 , 0 , 0 ), // #403 {u8|dx, al|ax|eax} + ROW(2, 1, 1, 0, 139, 145, 0 , 0 , 0 , 0 ), // #404 {dx, ds:[memBase|zsi]} + ROW(6, 1, 1, 3, 45 , 46 , 10 , 99 , 36 , 35 ), // #405 {xmm, xmm|m128|mem, i8|u8, <ecx>, <eax>, <edx>} + ROW(6, 1, 1, 3, 45 , 46 , 10 , 122, 36 , 35 ), // #406 {xmm, xmm|m128|mem, i8|u8, <xmm0>, <eax>, <edx>} + ROW(4, 1, 1, 1, 45 , 46 , 10 , 99 , 0 , 0 ), // #407 {xmm, xmm|m128|mem, i8|u8, <ecx>} + ROW(4, 1, 1, 1, 45 , 46 , 10 , 122, 0 , 0 ), // #408 {xmm, xmm|m128|mem, i8|u8, <xmm0>} + ROW(3, 1, 1, 0, 109, 45 , 10 , 0 , 0 , 0 ), // #409 {r32|m8|mem|r8lo|r8hi|r16, xmm, i8|u8} + ROW(3, 0, 1, 0, 15 , 45 , 10 , 0 , 0 , 0 ), // #410 {r64|m64|mem, xmm, i8|u8} + ROW(3, 1, 1, 0, 45 , 109, 10 , 0 , 0 , 0 ), // #411 {xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} + ROW(3, 1, 1, 0, 45 , 28 , 10 , 0 , 0 , 0 ), // #412 {xmm, r32|m32|mem, i8|u8} + ROW(3, 0, 1, 0, 45 , 15 , 10 , 0 , 0 , 0 ), // #413 {xmm, r64|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 59 , 113, 10 , 0 , 0 , 0 ), // #414 {mm|xmm, r32|m16|mem|r16, i8|u8} + ROW(2, 1, 1, 0, 6 , 59 , 0 , 0 , 0 , 0 ), // #415 {r32, mm|xmm} + ROW(2, 1, 1, 0, 45 , 10 , 0 , 0 , 0 , 0 ), // #416 {xmm, i8|u8} + ROW(2, 1, 1, 0, 31 , 81 , 0 , 0 , 0 , 0 ), // #417 {r8lo|r8hi|m8|r16|m16|r32|m32|r64|m64|mem, cl|i8|u8} + ROW(1, 0, 1, 0, 114, 0 , 0 , 0 , 0 , 0 ), // #418 {r32|r64} + ROW(3, 1, 1, 3, 35 , 36 , 99 , 0 , 0 , 0 ), // #419 {<edx>, <eax>, <ecx>} + ROW(2, 1, 1, 2, 142, 127, 0 , 0 , 0 , 0 ), // #420 {<al|ax|eax|rax>, <es:[memBase|zdi]>} + ROW(1, 1, 1, 0, 1 , 0 , 0 , 0 , 0 , 0 ), // #421 {r8lo|r8hi|m8|mem} + ROW(1, 1, 1, 0, 146, 0 , 0 , 0 , 0 , 0 ), // #422 {r16|m16|mem|r32|r64} + ROW(2, 1, 1, 2, 127, 142, 0 , 0 , 0 , 0 ), // #423 {<es:[memBase|zdi]>, <al|ax|eax|rax>} + ROW(6, 1, 1, 0, 51 , 51 , 51 , 51 , 51 , 47 ), // #424 {zmm, zmm, zmm, zmm, zmm, m128|mem} + ROW(6, 1, 1, 0, 45 , 45 , 45 , 45 , 45 , 47 ), // #425 {xmm, xmm, xmm, xmm, xmm, m128|mem} + ROW(3, 1, 1, 0, 45 , 45 , 60 , 0 , 0 , 0 ), // #426 {xmm, xmm, xmm|m64|mem} + ROW(3, 1, 1, 0, 45 , 45 , 87 , 0 , 0 , 0 ), // #427 {xmm, xmm, xmm|m32|mem} + ROW(2, 1, 1, 0, 48 , 47 , 0 , 0 , 0 , 0 ), // #428 {ymm, m128|mem} + ROW(2, 1, 1, 0, 147, 60 , 0 , 0 , 0 , 0 ), // #429 {ymm|zmm, xmm|m64|mem} + ROW(2, 1, 1, 0, 147, 47 , 0 , 0 , 0 , 0 ), // #430 {ymm|zmm, m128|mem} + ROW(2, 1, 1, 0, 51 , 50 , 0 , 0 , 0 , 0 ), // #431 {zmm, m256|mem} + ROW(2, 1, 1, 0, 148, 60 , 0 , 0 , 0 , 0 ), // #432 {xmm|ymm|zmm, xmm|m64|mem} + ROW(2, 1, 1, 0, 148, 87 , 0 , 0 , 0 , 0 ), // #433 {xmm|ymm|zmm, m32|mem|xmm} + ROW(4, 1, 1, 0, 82 , 45 , 60 , 10 , 0 , 0 ), // #434 {xmm|k, xmm, xmm|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 82 , 45 , 87 , 10 , 0 , 0 ), // #435 {xmm|k, xmm, xmm|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 45 , 45 , 131, 0 , 0 , 0 ), // #436 {xmm, xmm, r32|m32|mem|r64|m64} + ROW(3, 1, 1, 0, 46 , 147, 10 , 0 , 0 , 0 ), // #437 {xmm|m128|mem, ymm|zmm, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 60 , 10 , 0 , 0 ), // #438 {xmm, xmm, xmm|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 87 , 10 , 0 , 0 ), // #439 {xmm, xmm, xmm|m32|mem, i8|u8} + ROW(3, 1, 1, 0, 84 , 149, 10 , 0 , 0 , 0 ), // #440 {k, xmm|m128|ymm|m256|zmm|m512, i8|u8} + ROW(3, 1, 1, 0, 84 , 60 , 10 , 0 , 0 , 0 ), // #441 {k, xmm|m64|mem, i8|u8} + ROW(3, 1, 1, 0, 84 , 87 , 10 , 0 , 0 , 0 ), // #442 {k, xmm|m32|mem, i8|u8} + ROW(1, 1, 1, 0, 62 , 0 , 0 , 0 , 0 , 0 ), // #443 {vm32y} + ROW(1, 1, 1, 0, 63 , 0 , 0 , 0 , 0 , 0 ), // #444 {vm32z} + ROW(1, 1, 1, 0, 66 , 0 , 0 , 0 , 0 , 0 ), // #445 {vm64z} + ROW(4, 1, 1, 0, 51 , 51 , 49 , 10 , 0 , 0 ), // #446 {zmm, zmm, ymm|m256|mem, i8|u8} + ROW(1, 1, 1, 0, 30 , 0 , 0 , 0 , 0 , 0 ), // #447 {m64|mem} + ROW(2, 1, 1, 0, 6 , 86 , 0 , 0 , 0 , 0 ), // #448 {r32, xmm|ymm} + ROW(2, 1, 1, 0, 148, 150, 0 , 0 , 0 , 0 ), // #449 {xmm|ymm|zmm, xmm|m8|mem|r32|r8lo|r8hi|r16} + ROW(2, 1, 1, 0, 148, 151, 0 , 0 , 0 , 0 ), // #450 {xmm|ymm|zmm, xmm|m32|mem|r32} + ROW(2, 1, 1, 0, 148, 84 , 0 , 0 , 0 , 0 ), // #451 {xmm|ymm|zmm, k} + ROW(2, 1, 1, 0, 148, 152, 0 , 0 , 0 , 0 ), // #452 {xmm|ymm|zmm, xmm|m16|mem|r32|r16} + ROW(3, 1, 1, 0, 113, 45 , 10 , 0 , 0 , 0 ), // #453 {r32|m16|mem|r16, xmm, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 109, 10 , 0 , 0 ), // #454 {xmm, xmm, r32|m8|mem|r8lo|r8hi|r16, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 28 , 10 , 0 , 0 ), // #455 {xmm, xmm, r32|m32|mem, i8|u8} + ROW(4, 0, 1, 0, 45 , 45 , 15 , 10 , 0 , 0 ), // #456 {xmm, xmm, r64|m64|mem, i8|u8} + ROW(4, 1, 1, 0, 45 , 45 , 113, 10 , 0 , 0 ), // #457 {xmm, xmm, r32|m16|mem|r16, i8|u8} + ROW(2, 1, 1, 0, 84 , 148, 0 , 0 , 0 , 0 ), // #458 {k, xmm|ymm|zmm} + ROW(1, 1, 1, 0, 102, 0 , 0 , 0 , 0 , 0 ), // #459 {rel16|rel32} + ROW(3, 1, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ), // #460 {mem, <edx>, <eax>} + ROW(3, 0, 1, 2, 91 , 35 , 36 , 0 , 0 , 0 ) // #461 {mem, <edx>, <eax>} }; #undef ROW @@ -3451,104 +3452,104 @@ const uint8_t InstDB::rwInfoIndex[Inst::_kIdCount * 2] = { 0, 81, 0, 36, 0, 112, 0, 111, 0, 86, 0, 110, 0, 110, 0, 113, 0, 114, 0, 114, 0, 115, 0, 116, 0, 116, 0, 117, 0, 117, 0, 97, 0, 97, 0, 111, 0, 97, 0, 97, 0, 116, 0, 116, 0, 118, 0, 82, 0, 86, 0, 119, 0, 82, 0, 7, 0, 7, 0, 81, 0, 120, - 0, 121, 0, 110, 0, 110, 0, 120, 0, 0, 4, 49, 122, 4, 0, 4, 0, 5, 0, 6, 0, 0, - 123, 124, 0, 0, 125, 0, 48, 0, 126, 0, 48, 2, 0, 4, 0, 4, 0, 127, 0, 128, 0, 11, + 0, 11, 0, 110, 0, 110, 0, 120, 0, 0, 4, 49, 121, 4, 0, 4, 0, 5, 0, 6, 0, 0, 122, + 123, 0, 0, 124, 0, 48, 0, 125, 0, 48, 2, 0, 4, 0, 4, 0, 126, 0, 127, 0, 11, 0, 11, 0, 11, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, - 3, 0, 3, 0, 0, 3, 3, 0, 3, 0, 0, 0, 3, 0, 129, 0, 3, 0, 0, 12, 0, 4, 0, 4, 3, - 0, 3, 0, 4, 0, 3, 0, 0, 130, 0, 131, 3, 0, 3, 0, 4, 0, 3, 0, 0, 132, 0, 133, - 0, 0, 0, 8, 0, 8, 0, 134, 0, 52, 0, 135, 0, 136, 39, 0, 39, 0, 129, 0, 129, 0, - 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 129, 0, 39, 0, 129, - 0, 129, 0, 129, 0, 39, 0, 39, 0, 129, 0, 129, 0, 129, 0, 3, 0, 3, 0, 3, 0, 137, - 0, 3, 0, 3, 0, 3, 0, 39, 0, 39, 0, 0, 138, 0, 72, 0, 139, 0, 140, 3, 0, 3, 0, - 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 141, - 0, 142, 0, 143, 0, 36, 0, 36, 0, 36, 0, 142, 0, 142, 0, 143, 0, 36, 0, 36, 0, - 36, 0, 142, 0, 4, 0, 3, 0, 129, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 0, 144, 0, 0, + 3, 0, 3, 0, 0, 3, 3, 0, 3, 0, 0, 0, 3, 0, 128, 0, 3, 0, 0, 12, 0, 4, 0, 4, 3, + 0, 3, 0, 4, 0, 3, 0, 0, 129, 0, 130, 3, 0, 3, 0, 4, 0, 3, 0, 0, 131, 0, 132, + 0, 0, 0, 8, 0, 8, 0, 133, 0, 52, 0, 134, 0, 135, 39, 0, 39, 0, 128, 0, 128, 0, + 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 128, 0, 39, 0, 128, 0, + 128, 0, 128, 0, 39, 0, 39, 0, 128, 0, 128, 0, 128, 0, 3, 0, 3, 0, 3, 0, 136, + 0, 3, 0, 3, 0, 3, 0, 39, 0, 39, 0, 0, 137, 0, 72, 0, 138, 0, 139, 3, 0, 3, 0, + 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 4, 0, 4, 0, 3, 0, 3, 0, 4, 0, 4, 0, 140, + 0, 141, 0, 142, 0, 36, 0, 36, 0, 36, 0, 141, 0, 141, 0, 142, 0, 36, 0, 36, 0, + 36, 0, 141, 0, 4, 0, 3, 0, 128, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 0, 143, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, - 0, 24, 3, 0, 3, 0, 0, 7, 0, 7, 0, 7, 0, 39, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, - 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, - 3, 0, 3, 0, 3, 0, 39, 0, 145, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 4, 0, 3, - 0, 0, 146, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 147, 0, 7, 0, 148, 0, 147, 0, - 0, 149, 0, 149, 0, 150, 0, 149, 0, 150, 0, 149, 0, 149, 151, 0, 0, 152, 0, 0, - 147, 0, 147, 0, 0, 11, 0, 7, 0, 7, 0, 38, 0, 148, 0, 0, 7, 0, 148, 0, 0, 153, - 147, 0, 147, 0, 0, 10, 2, 0, 154, 0, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, - 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, - 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, - 0, 155, 0, 155, 0, 155, 0, 155, 0, 155, 0, 0, 0, 64, 4, 0, 4, 0, 4, 0, 0, 4, - 4, 0, 4, 0, 0, 12, 147, 0, 0, 156, 0, 10, 147, 0, 0, 156, 0, 10, 0, 4, 0, 4, - 0, 64, 0, 47, 0, 157, 0, 149, 0, 157, 7, 0, 7, 0, 38, 0, 148, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 158, 159, 0, 0, 157, 2, 0, 4, 0, 4, 0, 5, 0, 6, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 19, 0, 11, 0, 11, 0, 31, 0, 32, 0, - 0, 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 160, 0, 161, 0, 160, 0, 161, 0, 8, 0, 8, 0, 162, - 0, 163, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 7, 0, 0, 7, 0, 8, 0, 8, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 164, 0, 164, - 165, 0, 40, 0, 166, 0, 167, 0, 166, 0, 167, 0, 165, 0, 40, 0, 166, 0, 167, - 0, 166, 0, 167, 0, 168, 0, 169, 0, 0, 8, 0, 8, 0, 170, 0, 171, 31, 0, 32, 0, - 172, 0, 172, 0, 173, 0, 11, 0, 0, 8, 120, 0, 174, 0, 174, 0, 11, 0, 174, 0, 11, - 0, 173, 0, 11, 0, 173, 0, 0, 175, 173, 0, 11, 0, 173, 0, 11, 0, 174, 0, 40, - 0, 0, 176, 40, 0, 0, 177, 0, 178, 0, 179, 45, 0, 45, 0, 174, 0, 11, 0, 174, 0, - 11, 0, 11, 0, 173, 0, 11, 0, 173, 0, 40, 0, 40, 0, 45, 0, 45, 0, 173, 0, 11, - 0, 11, 0, 174, 0, 0, 177, 0, 178, 0, 8, 0, 8, 0, 8, 0, 162, 0, 163, 0, 8, 0, 180, - 0, 8, 0, 101, 0, 101, 181, 0, 181, 0, 11, 0, 11, 0, 0, 182, 0, 183, 0, 184, - 0, 183, 0, 184, 0, 182, 0, 183, 0, 184, 0, 183, 0, 184, 0, 52, 0, 185, 0, 185, - 0, 186, 0, 187, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, - 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 190, 0, 190, 0, 191, 0, 192, 0, 185, 0, - 185, 0, 185, 0, 185, 0, 185, 0, 185, 0, 190, 0, 190, 0, 185, 0, 185, 0, 188, - 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, - 0, 185, 0, 185, 0, 185, 0, 185, 0, 185, 0, 190, 0, 190, 0, 190, 0, 190, 0, - 191, 0, 192, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, - 185, 0, 185, 0, 188, 0, 189, 0, 190, 0, 190, 0, 191, 0, 192, 0, 185, 0, 185, - 0, 188, 0, 189, 0, 185, 0, 185, 0, 188, 0, 189, 0, 185, 0, 185, 0, 193, 0, 194, - 0, 190, 0, 190, 0, 191, 0, 192, 0, 195, 0, 195, 0, 39, 0, 121, 11, 0, 11, 0, + 0, 24, 3, 0, 3, 0, 0, 7, 0, 7, 0, 7, 0, 39, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, + 0, 3, 0, 3, 0, 3, 0, 3, 0, 54, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, 3, 0, + 3, 0, 3, 0, 3, 0, 39, 0, 144, 0, 3, 0, 3, 0, 4, 0, 3, 0, 3, 0, 3, 0, 4, 0, 3, + 0, 0, 145, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 146, 0, 7, 0, 147, 0, 146, 0, 0, + 148, 0, 148, 0, 149, 0, 148, 0, 149, 0, 148, 0, 148, 150, 0, 0, 151, 0, 0, 146, + 0, 146, 0, 0, 11, 0, 7, 0, 7, 0, 38, 0, 147, 0, 0, 7, 0, 147, 0, 0, 152, 146, + 0, 146, 0, 0, 10, 2, 0, 153, 0, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, + 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, + 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, + 0, 154, 0, 154, 0, 154, 0, 154, 0, 154, 0, 0, 0, 64, 4, 0, 4, 0, 4, 0, 0, 4, + 4, 0, 4, 0, 0, 12, 146, 0, 0, 155, 0, 10, 146, 0, 0, 155, 0, 10, 0, 4, 0, 4, + 0, 64, 0, 47, 0, 156, 0, 148, 0, 156, 7, 0, 7, 0, 38, 0, 147, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 157, 158, 0, 0, 156, 2, 0, 4, 0, 4, 0, 5, 0, 6, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 0, 19, 0, 11, 0, 11, 0, 31, 0, 32, 0, 0, + 0, 4, 0, 4, 0, 4, 0, 4, 0, 0, 159, 0, 160, 0, 159, 0, 160, 0, 8, 0, 8, 0, 161, + 0, 162, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 7, 0, 0, 7, 0, 8, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 163, 0, 163, + 164, 0, 40, 0, 165, 0, 166, 0, 165, 0, 166, 0, 164, 0, 40, 0, 165, 0, 166, + 0, 165, 0, 166, 0, 167, 0, 168, 0, 0, 8, 0, 8, 0, 169, 0, 170, 31, 0, 32, 0, 171, + 0, 171, 0, 172, 0, 11, 0, 0, 8, 120, 0, 173, 0, 173, 0, 11, 0, 173, 0, 11, + 0, 172, 0, 11, 0, 172, 0, 0, 174, 172, 0, 11, 0, 172, 0, 11, 0, 173, 0, 40, 0, + 0, 175, 40, 0, 0, 176, 0, 177, 0, 178, 45, 0, 45, 0, 173, 0, 11, 0, 173, 0, + 11, 0, 11, 0, 172, 0, 11, 0, 172, 0, 40, 0, 40, 0, 45, 0, 45, 0, 172, 0, 11, 0, + 11, 0, 173, 0, 0, 176, 0, 177, 0, 8, 0, 8, 0, 8, 0, 161, 0, 162, 0, 8, 0, 179, + 0, 8, 0, 101, 0, 101, 180, 0, 180, 0, 11, 0, 11, 0, 0, 181, 0, 182, 0, 183, + 0, 182, 0, 183, 0, 181, 0, 182, 0, 183, 0, 182, 0, 183, 0, 52, 0, 184, 0, 184, + 0, 185, 0, 186, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, + 0, 184, 0, 184, 0, 187, 0, 188, 0, 189, 0, 189, 0, 190, 0, 191, 0, 184, 0, + 184, 0, 184, 0, 184, 0, 184, 0, 184, 0, 189, 0, 189, 0, 184, 0, 184, 0, 187, + 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, + 0, 184, 0, 184, 0, 184, 0, 184, 0, 184, 0, 189, 0, 189, 0, 189, 0, 189, 0, 190, + 0, 191, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, + 184, 0, 184, 0, 187, 0, 188, 0, 189, 0, 189, 0, 190, 0, 191, 0, 184, 0, 184, + 0, 187, 0, 188, 0, 184, 0, 184, 0, 187, 0, 188, 0, 184, 0, 184, 0, 192, 0, 193, + 0, 189, 0, 189, 0, 190, 0, 191, 0, 194, 0, 194, 0, 39, 0, 195, 11, 0, 11, 0, 39, 0, 196, 0, 99, 197, 99, 198, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, - 24, 0, 24, 99, 198, 99, 199, 11, 0, 11, 0, 0, 200, 0, 201, 0, 11, 0, 11, 0, - 200, 0, 201, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 202, 0, 203, 0, 204, - 0, 203, 0, 204, 0, 202, 0, 203, 0, 204, 0, 203, 0, 204, 0, 163, 111, 0, 0, 98, - 0, 106, 0, 205, 0, 205, 0, 8, 0, 8, 0, 162, 0, 163, 0, 0, 0, 206, 0, 0, 0, 8, - 0, 8, 0, 162, 0, 163, 0, 0, 0, 207, 0, 0, 208, 0, 208, 0, 81, 0, 209, 0, 208, + 24, 0, 24, 99, 198, 99, 199, 11, 0, 11, 0, 0, 200, 0, 201, 0, 11, 0, 11, 0, 200, + 0, 201, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 202, 0, 203, 0, 204, + 0, 203, 0, 204, 0, 202, 0, 203, 0, 204, 0, 203, 0, 204, 0, 162, 111, 0, 0, 98, + 0, 106, 0, 205, 0, 205, 0, 8, 0, 8, 0, 161, 0, 162, 0, 0, 0, 206, 0, 0, 0, 8, + 0, 8, 0, 161, 0, 162, 0, 0, 0, 207, 0, 0, 208, 0, 208, 0, 81, 0, 209, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 208, 0, 0, 210, 211, 212, 211, 212, 0, 213, 116, 214, 116, 214, 215, 0, 216, 0, 111, 0, 111, 0, 111, 0, 111, 0, 217, 0, 116, 218, 11, 0, 11, 0, 118, 219, 208, 0, 208, 0, 0, 8, 0, 220, - 0, 206, 172, 0, 0, 0, 0, 221, 0, 207, 0, 8, 0, 8, 0, 162, 0, 163, 222, 0, 0, - 220, 0, 8, 0, 8, 0, 223, 0, 223, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 164, 0, 8, 224, 0, 45, 0, 225, 0, 225, - 0, 40, 0, 226, 0, 0, 8, 0, 190, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 130, 0, 131, 0, 8, 0, 8, 0, 8, 0, 8, 0, 132, 0, 133, 0, 227, 0, 227, 0, 227, 0, - 227, 0, 227, 0, 227, 0, 180, 0, 180, 172, 0, 172, 0, 172, 0, 172, 0, 0, 180, - 0, 180, 0, 180, 0, 180, 0, 180, 0, 180, 11, 0, 11, 0, 0, 185, 0, 185, 0, 185, - 0, 185, 0, 228, 0, 228, 0, 8, 0, 8, 0, 8, 0, 185, 0, 8, 0, 8, 0, 185, 0, 185, - 0, 190, 0, 190, 0, 229, 0, 229, 0, 229, 0, 8, 0, 229, 0, 8, 0, 185, 0, 185, 0, - 185, 0, 185, 0, 185, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 134, 0, 52, 0, 135, + 0, 206, 171, 0, 0, 0, 0, 221, 0, 207, 0, 8, 0, 8, 0, 161, 0, 162, 222, 0, 0, + 220, 0, 8, 0, 8, 0, 223, 0, 223, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, 8, + 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, + 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 163, 0, 8, 224, 0, 45, 0, 225, 0, 225, + 0, 40, 0, 226, 0, 0, 8, 0, 189, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, 129, + 0, 130, 0, 8, 0, 8, 0, 8, 0, 8, 0, 131, 0, 132, 0, 227, 0, 227, 0, 227, 0, + 227, 0, 227, 0, 227, 0, 179, 0, 179, 171, 0, 171, 0, 171, 0, 171, 0, 0, 179, + 0, 179, 0, 179, 0, 179, 0, 179, 0, 179, 11, 0, 11, 0, 0, 184, 0, 184, 0, 184, + 0, 184, 0, 228, 0, 228, 0, 8, 0, 8, 0, 8, 0, 184, 0, 8, 0, 8, 0, 184, 0, 184, + 0, 189, 0, 189, 0, 229, 0, 229, 0, 229, 0, 8, 0, 229, 0, 8, 0, 184, 0, 184, 0, + 184, 0, 184, 0, 184, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 133, 0, 52, 0, 134, 0, 230, 99, 198, 99, 197, 99, 199, 99, 198, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 0, - 8, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 7, 0, 137, 0, 7, 0, 0, 8, - 7, 0, 0, 8, 0, 8, 7, 0, 0, 231, 0, 163, 0, 162, 0, 232, 11, 0, 11, 0, 0, 233, - 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, - 0, 233, 0, 185, 0, 185, 0, 8, 0, 8, 0, 205, 0, 205, 0, 8, 0, 8, 0, 8, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 234, 0, - 234, 0, 235, 0, 175, 0, 225, 0, 225, 0, 225, 0, 225, 0, 141, 0, 234, 0, 236, - 0, 175, 0, 235, 0, 235, 0, 175, 0, 236, 0, 175, 0, 235, 0, 175, 0, 237, 0, 238, - 0, 173, 0, 173, 0, 173, 0, 237, 0, 235, 0, 175, 0, 236, 0, 175, 0, 235, 0, - 175, 0, 234, 0, 175, 0, 237, 0, 238, 0, 173, 0, 173, 0, 173, 0, 237, 0, 0, 8, - 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, + 8, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 7, 0, 0, 8, 7, 0, 7, 0, 136, 0, 7, 0, 0, 8, 7, + 0, 0, 8, 0, 8, 7, 0, 0, 231, 0, 162, 0, 161, 0, 232, 11, 0, 11, 0, 0, 233, 0, + 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, 0, 233, + 0, 233, 0, 184, 0, 184, 0, 8, 0, 8, 0, 205, 0, 205, 0, 8, 0, 8, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 234, 0, + 234, 0, 235, 0, 174, 0, 225, 0, 225, 0, 225, 0, 225, 0, 140, 0, 234, 0, 236, + 0, 174, 0, 235, 0, 235, 0, 174, 0, 236, 0, 174, 0, 235, 0, 174, 0, 237, 0, 238, + 0, 172, 0, 172, 0, 172, 0, 237, 0, 235, 0, 174, 0, 236, 0, 174, 0, 235, 0, 174, + 0, 234, 0, 174, 0, 237, 0, 238, 0, 172, 0, 172, 0, 172, 0, 237, 0, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 11, 0, 11, 0, 0, 8, 0, 8, 0, 8, 0, 239, 0, 11, 0, 11, 0, 8, 0, 8, 0, 11, 0, 11, 0, 8, 0, 8, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 111, 0, 111, 0, 241, 0, 111, 0, 0, 240, 0, - 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 0, 8, 0, 185, 0, 185, 0, 185, 0, 8, - 0, 240, 0, 240, 0, 8, 0, 8, 0, 185, 0, 185, 0, 185, 0, 8, 0, 8, 0, 227, 0, 11, + 240, 0, 240, 0, 240, 0, 240, 0, 240, 0, 8, 0, 8, 0, 184, 0, 184, 0, 184, 0, 8, + 0, 240, 0, 240, 0, 8, 0, 8, 0, 184, 0, 184, 0, 184, 0, 8, 0, 8, 0, 227, 0, 11, 0, 11, 0, 11, 0, 8, 0, 8, 0, 8, 0, 242, 0, 243, 0, 242, 0, 8, 0, 8, 0, 8, 0, 242, 0, 242, 0, 242, 0, 8, 0, 8, 0, 8, 0, 242, 0, 242, 0, 243, 0, 242, 0, 8, - 0, 8, 0, 8, 0, 242, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 185, 0, - 185, 222, 0, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, + 0, 8, 0, 8, 0, 242, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 184, 0, + 184, 222, 0, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 227, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, - 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 181, 0, 181, 0, 0, 200, 0, 201, + 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 180, 0, 180, 0, 0, 200, 0, 201, 11, 0, 0, 201, 0, 11, 0, 11, 0, 200, 0, 201, 0, 11, 0, 11, 0, 200, 0, 201, 0, - 11, 0, 11, 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 181, 0, 181, 0, 0, 200, - 0, 201, 11, 0, 0, 201, 0, 8, 0, 8, 0, 162, 0, 163, 111, 0, 111, 0, 0, 24, - 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 111, 0, 241, 0, 0, 8, 0, 8, 0, - 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 0, 200, 0, 201, 0, 158, 0, 8, 0, 8, 0, 162, - 0, 163, 222, 0, 222, 0, 31, 0, 32, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 102, 0, 244, 0, 0, 245, 0, 0, 0, 246, 0, 0, - 0, 0, 150, 0, 0, 2, 0, 4, 0, 4, 0, 0, 247, 0, 247, 0, 247, 0, 247, 0, 248, 0, - 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 244, 0, 0 + 11, 0, 11, 0, 200, 0, 201, 11, 0, 11, 0, 0, 200, 0, 201, 180, 0, 180, 0, 0, 200, + 0, 201, 11, 0, 0, 201, 0, 8, 0, 8, 0, 161, 0, 162, 111, 0, 111, 0, 0, 24, 0, + 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 0, 24, 111, 0, 241, 0, 0, 8, 0, 8, 0, + 8, 0, 8, 0, 8, 0, 8, 11, 0, 11, 0, 0, 200, 0, 201, 0, 157, 0, 8, 0, 8, 0, 161, + 0, 162, 222, 0, 222, 0, 31, 0, 32, 0, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, 8, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 102, 0, 102, 0, 244, 0, 0, 245, 0, 0, 0, 246, 0, 0, 0, + 0, 149, 0, 0, 2, 0, 4, 0, 4, 0, 0, 247, 0, 247, 0, 247, 0, 247, 0, 248, 0, 248, + 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 248, 0, 244, 0, 0 }; const InstDB::RWInfo InstDB::rwInfo[] = { @@ -3563,7 +3564,7 @@ const InstDB::RWInfo InstDB::rwInfo[] = { { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 0 , 0 , 0 } }, // #8 [ref=186x] { InstDB::RWInfo::kCategoryGeneric , 7 , { 12, 13, 0 , 0 , 0 , 0 } }, // #9 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 3 , 0 , 0 , 0 } }, // #10 [ref=5x] - { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 0 , 0 , 0 , 0 } }, // #11 [ref=80x] + { InstDB::RWInfo::kCategoryGeneric , 2 , { 11, 3 , 0 , 0 , 0 , 0 } }, // #11 [ref=81x] { InstDB::RWInfo::kCategoryGeneric , 3 , { 4 , 5 , 14, 0 , 0 , 0 } }, // #12 [ref=4x] { InstDB::RWInfo::kCategoryGeneric , 2 , { 5 , 3 , 0 , 0 , 0 , 0 } }, // #13 [ref=3x] { InstDB::RWInfo::kCategoryGeneric , 8 , { 10, 3 , 0 , 0 , 0 , 0 } }, // #14 [ref=2x] @@ -3673,81 +3674,81 @@ const InstDB::RWInfo InstDB::rwInfo[] = { { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 9 , 0 , 0 , 0 , 0 } }, // #118 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 19, 0 , 0 , 0 , 0 } }, // #119 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 14, { 11, 3 , 0 , 0 , 0 , 0 } }, // #120 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 34, 9 , 0 , 0 , 0 , 0 } }, // #121 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 59, 41, 3 , 0 , 0 , 0 } }, // #122 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 60, 0 , 0 } }, // #123 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 0 , 0 , 0 , 0 } }, // #124 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 29, 0 , 0 , 0 } }, // #125 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #126 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 21, 0 , 0 , 0 , 0 } }, // #127 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 61, 0 , 0 , 0 , 0 } }, // #128 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 25, 7 , 0 , 0 , 0 , 0 } }, // #129 [ref=18x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 16, 56 } }, // #130 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 16, 56 } }, // #131 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 0 , 0 } }, // #132 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 0 , 0 } }, // #133 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 53, 5 , 0 , 0 , 0 , 0 } }, // #134 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 32, { 34, 5 , 0 , 0 , 0 , 0 } }, // #135 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 33, { 47, 3 , 0 , 0 , 0 , 0 } }, // #136 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 64, 5 , 0 , 0 , 0 , 0 } }, // #137 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 39, 0 , 0 , 0 , 0 } }, // #138 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #139 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #140 [ref=1x] - { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #141 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #142 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #143 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 65, 0 , 0 , 0 , 0 , 0 } }, // #144 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #145 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 60, 0 , 0 , 0 , 0 , 0 } }, // #146 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 66, 0 , 0 , 0 , 0 } }, // #147 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 5 , { 36, 9 , 0 , 0 , 0 , 0 } }, // #148 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 0 , 0 , 0 , 0 , 0 } }, // #149 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 28, 0 , 0 , 0 } }, // #150 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 0 , 0 , 0 , 0 } }, // #151 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 62, 0 , 0 , 0 } }, // #152 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 68, 0 , 0 , 0 , 0 , 0 } }, // #153 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 21, 20, 0 , 0 , 0 , 0 } }, // #154 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 31, { 69, 0 , 0 , 0 , 0 , 0 } }, // #155 [ref=30x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 66, 0 , 0 , 0 } }, // #156 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 34, { 11, 0 , 0 , 0 , 0 , 0 } }, // #157 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 0 , 0 , 0 , 0 , 0 } }, // #158 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 21, 0 , 0 , 0 , 0 } }, // #159 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 70, 43, 43, 43, 43, 5 } }, // #160 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 4 , 5 , 5 , 5 , 5 , 5 } }, // #161 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 5 , 7 , 0 , 0 , 0 } }, // #162 [ref=8x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 9 , 0 , 0 , 0 } }, // #163 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 3 , 0 , 0 } }, // #164 [ref=3x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 71, 5 , 0 , 0 , 0 , 0 } }, // #165 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 12, { 11, 5 , 0 , 0 , 0 , 0 } }, // #166 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 37, { 72, 73, 0 , 0 , 0 , 0 } }, // #167 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 38, { 11, 7 , 0 , 0 , 0 , 0 } }, // #168 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 39, { 11, 9 , 0 , 0 , 0 , 0 } }, // #169 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 11, 5 , 7 , 0 , 0 , 0 } }, // #170 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 11, 5 , 9 , 0 , 0 , 0 } }, // #171 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #172 [ref=7x] - { InstDB::RWInfo::kCategoryVmov2_1 , 40, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #173 [ref=14x] - { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #174 [ref=7x] - { InstDB::RWInfo::kCategoryVmov1_2 , 41, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #175 [ref=10x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 74, 7 , 0 , 0 , 0 } }, // #176 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 57, 3 , 0 , 0 , 0 } }, // #177 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 74, 3 , 0 , 0 , 0 } }, // #178 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 57, 9 , 0 , 0 , 0 } }, // #179 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 43, { 10, 5 , 5 , 0 , 0 , 0 } }, // #180 [ref=9x] - { InstDB::RWInfo::kCategoryGeneric , 44, { 72, 43, 0 , 0 , 0 , 0 } }, // #181 [ref=6x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 73, 0 , 0 , 0 , 0 } }, // #182 [ref=2x] - { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 3 , 0 , 0 , 0 , 0 } }, // #183 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 46, { 71, 43, 0 , 0 , 0 , 0 } }, // #184 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 6 , { 2 , 3 , 3 , 0 , 0 , 0 } }, // #185 [ref=60x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 4 , 57, 7 , 0 , 0 , 0 } }, // #186 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 4 , 74, 9 , 0 , 0 , 0 } }, // #187 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #188 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #189 [ref=11x] - { InstDB::RWInfo::kCategoryGeneric , 47, { 11, 3 , 3 , 3 , 0 , 0 } }, // #190 [ref=15x] - { InstDB::RWInfo::kCategoryGeneric , 48, { 34, 7 , 7 , 7 , 0 , 0 } }, // #191 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 49, { 42, 9 , 9 , 9 , 0 , 0 } }, // #192 [ref=4x] - { InstDB::RWInfo::kCategoryGeneric , 35, { 25, 7 , 7 , 0 , 0 , 0 } }, // #193 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 36, { 75, 9 , 9 , 0 , 0 , 0 } }, // #194 [ref=1x] - { InstDB::RWInfo::kCategoryGeneric , 14, { 34, 3 , 0 , 0 , 0 , 0 } }, // #195 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 59, 41, 3 , 0 , 0 , 0 } }, // #121 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 11, 3 , 60, 0 , 0 } }, // #122 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 0 , 0 , 0 , 0 } }, // #123 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 16, 28, 29, 0 , 0 , 0 } }, // #124 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 3 , 0 , 0 , 0 , 0 , 0 } }, // #125 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 21, 0 , 0 , 0 , 0 } }, // #126 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 50, 61, 0 , 0 , 0 , 0 } }, // #127 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 25, 7 , 0 , 0 , 0 , 0 } }, // #128 [ref=18x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 16, 56 } }, // #129 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 16, 56 } }, // #130 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 62, 0 , 0 } }, // #131 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 63, 0 , 0 } }, // #132 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 31, { 53, 5 , 0 , 0 , 0 , 0 } }, // #133 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 32, { 34, 5 , 0 , 0 , 0 , 0 } }, // #134 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 33, { 47, 3 , 0 , 0 , 0 , 0 } }, // #135 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 64, 5 , 0 , 0 , 0 , 0 } }, // #136 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 15, { 4 , 39, 0 , 0 , 0 , 0 } }, // #137 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 4 , { 4 , 7 , 0 , 0 , 0 , 0 } }, // #138 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 2 , 13, 0 , 0 , 0 , 0 } }, // #139 [ref=1x] + { InstDB::RWInfo::kCategoryVmov1_8 , 0 , { 0 , 0 , 0 , 0 , 0 , 0 } }, // #140 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 10, 9 , 0 , 0 , 0 , 0 } }, // #141 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 27, { 10, 13, 0 , 0 , 0 , 0 } }, // #142 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 65, 0 , 0 , 0 , 0 , 0 } }, // #143 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 3 , { 5 , 5 , 0 , 0 , 0 , 0 } }, // #144 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 60, 0 , 0 , 0 , 0 , 0 } }, // #145 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 10, { 2 , 66, 0 , 0 , 0 , 0 } }, // #146 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 36, 9 , 0 , 0 , 0 , 0 } }, // #147 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 11, 0 , 0 , 0 , 0 , 0 } }, // #148 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 28, 0 , 0 , 0 } }, // #149 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 0 , 0 , 0 , 0 } }, // #150 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 15, 67, 62, 0 , 0 , 0 } }, // #151 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 68, 0 , 0 , 0 , 0 , 0 } }, // #152 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 21, 20, 0 , 0 , 0 , 0 } }, // #153 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 31, { 69, 0 , 0 , 0 , 0 , 0 } }, // #154 [ref=30x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 2 , 3 , 66, 0 , 0 , 0 } }, // #155 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 34, { 11, 0 , 0 , 0 , 0 , 0 } }, // #156 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 28, { 42, 0 , 0 , 0 , 0 , 0 } }, // #157 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 0 , { 20, 21, 0 , 0 , 0 , 0 } }, // #158 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 70, 43, 43, 43, 43, 5 } }, // #159 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 4 , 5 , 5 , 5 , 5 , 5 } }, // #160 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 5 , 7 , 0 , 0 , 0 } }, // #161 [ref=8x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 5 , 9 , 0 , 0 , 0 } }, // #162 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 11, 3 , 3 , 3 , 0 , 0 } }, // #163 [ref=3x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 71, 5 , 0 , 0 , 0 , 0 } }, // #164 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 12, { 11, 5 , 0 , 0 , 0 , 0 } }, // #165 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 37, { 72, 73, 0 , 0 , 0 , 0 } }, // #166 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 38, { 11, 7 , 0 , 0 , 0 , 0 } }, // #167 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 39, { 11, 9 , 0 , 0 , 0 , 0 } }, // #168 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 11, 5 , 7 , 0 , 0 , 0 } }, // #169 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 11, 5 , 9 , 0 , 0 , 0 } }, // #170 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 11, { 11, 3 , 0 , 0 , 0 , 0 } }, // #171 [ref=7x] + { InstDB::RWInfo::kCategoryVmov2_1 , 40, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #172 [ref=14x] + { InstDB::RWInfo::kCategoryVmov1_2 , 14, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #173 [ref=7x] + { InstDB::RWInfo::kCategoryVmov1_2 , 41, { 0 , 0 , 0 , 0 , 0 , 0 } }, // #174 [ref=10x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 10, 74, 7 , 0 , 0 , 0 } }, // #175 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 57, 3 , 0 , 0 , 0 } }, // #176 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 42, { 10, 74, 3 , 0 , 0 , 0 } }, // #177 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 10, 57, 9 , 0 , 0 , 0 } }, // #178 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 43, { 10, 5 , 5 , 0 , 0 , 0 } }, // #179 [ref=9x] + { InstDB::RWInfo::kCategoryGeneric , 44, { 72, 43, 0 , 0 , 0 , 0 } }, // #180 [ref=6x] + { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 73, 0 , 0 , 0 , 0 } }, // #181 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 45, { 10, 3 , 0 , 0 , 0 , 0 } }, // #182 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 46, { 71, 43, 0 , 0 , 0 , 0 } }, // #183 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 6 , { 2 , 3 , 3 , 0 , 0 , 0 } }, // #184 [ref=60x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 4 , 57, 7 , 0 , 0 , 0 } }, // #185 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 4 , 74, 9 , 0 , 0 , 0 } }, // #186 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 6 , 7 , 7 , 0 , 0 , 0 } }, // #187 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 8 , 9 , 9 , 0 , 0 , 0 } }, // #188 [ref=11x] + { InstDB::RWInfo::kCategoryGeneric , 47, { 11, 3 , 3 , 3 , 0 , 0 } }, // #189 [ref=15x] + { InstDB::RWInfo::kCategoryGeneric , 48, { 34, 7 , 7 , 7 , 0 , 0 } }, // #190 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 49, { 42, 9 , 9 , 9 , 0 , 0 } }, // #191 [ref=4x] + { InstDB::RWInfo::kCategoryGeneric , 35, { 25, 7 , 7 , 0 , 0 , 0 } }, // #192 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 36, { 75, 9 , 9 , 0 , 0 , 0 } }, // #193 [ref=1x] + { InstDB::RWInfo::kCategoryGeneric , 14, { 34, 3 , 0 , 0 , 0 , 0 } }, // #194 [ref=2x] + { InstDB::RWInfo::kCategoryGeneric , 5 , { 34, 9 , 0 , 0 , 0 , 0 } }, // #195 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 5 , { 42, 9 , 0 , 0 , 0 , 0 } }, // #196 [ref=1x] { InstDB::RWInfo::kCategoryGeneric , 8 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #197 [ref=2x] { InstDB::RWInfo::kCategoryGeneric , 0 , { 2 , 3 , 2 , 0 , 0 , 0 } }, // #198 [ref=4x] @@ -3807,15 +3808,15 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, 0 }, // #0 [ref=14957x] { 0x0000000000000003u, 0x0000000000000003u, 0x00, { 0 }, OpRWInfo::kRW | OpRWInfo::kRegPhysId }, // #1 [ref=10x] { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt }, // #2 [ref=217x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #3 [ref=978x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #3 [ref=979x] { 0x000000000000FFFFu, 0x000000000000FFFFu, 0xFF, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt }, // #4 [ref=92x] { 0x000000000000FFFFu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #5 [ref=305x] { 0x00000000000000FFu, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kRW }, // #6 [ref=18x] { 0x00000000000000FFu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #7 [ref=181x] { 0x000000000000000Fu, 0x000000000000000Fu, 0xFF, { 0 }, OpRWInfo::kRW }, // #8 [ref=18x] - { 0x000000000000000Fu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #9 [ref=130x] + { 0x000000000000000Fu, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #9 [ref=129x] { 0x0000000000000000u, 0x000000000000FFFFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #10 [ref=160x] - { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #11 [ref=415x] + { 0x0000000000000000u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #11 [ref=416x] { 0x0000000000000003u, 0x0000000000000003u, 0xFF, { 0 }, OpRWInfo::kRW }, // #12 [ref=1x] { 0x0000000000000003u, 0x0000000000000000u, 0xFF, { 0 }, OpRWInfo::kRead }, // #13 [ref=34x] { 0x000000000000FFFFu, 0x0000000000000000u, 0x00, { 0 }, OpRWInfo::kRead | OpRWInfo::kRegPhysId }, // #14 [ref=4x] @@ -3838,7 +3839,7 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { { 0x000000000000000Fu, 0x000000000000000Fu, 0x01, { 0 }, OpRWInfo::kRW | OpRWInfo::kZExt | OpRWInfo::kRegPhysId }, // #31 [ref=1x] { 0x0000000000000000u, 0x00000000000000FFu, 0x02, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt | OpRWInfo::kRegPhysId }, // #32 [ref=1x] { 0x00000000000000FFu, 0x0000000000000000u, 0x00, { 0 }, OpRWInfo::kRead | OpRWInfo::kRegPhysId }, // #33 [ref=1x] - { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #34 [ref=76x] + { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite | OpRWInfo::kZExt }, // #34 [ref=75x] { 0x0000000000000000u, 0x00000000000000FFu, 0xFF, { 0 }, OpRWInfo::kWrite }, // #35 [ref=6x] { 0x0000000000000000u, 0x000000000000000Fu, 0xFF, { 0 }, OpRWInfo::kWrite }, // #36 [ref=6x] { 0x0000000000000000u, 0x0000000000000003u, 0x02, { 0 }, OpRWInfo::kWrite | OpRWInfo::kRegPhysId }, // #37 [ref=1x] @@ -3886,10 +3887,10 @@ const InstDB::RWInfoOp InstDB::rwInfoOp[] = { const InstDB::RWInfoRm InstDB::rwInfoRm[] = { { InstDB::RWInfoRm::kCategoryNone , 0x00, 0 , 0, 0 }, // #0 [ref=1809x] { InstDB::RWInfoRm::kCategoryConsistent, 0x03, 0 , InstDB::RWInfoRm::kFlagAmbiguous, 0 }, // #1 [ref=8x] - { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, 0 }, // #2 [ref=193x] + { InstDB::RWInfoRm::kCategoryConsistent, 0x02, 0 , 0, 0 }, // #2 [ref=194x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 16, 0, 0 }, // #3 [ref=122x] { InstDB::RWInfoRm::kCategoryFixed , 0x02, 8 , 0, 0 }, // #4 [ref=66x] - { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , 0, 0 }, // #5 [ref=34x] + { InstDB::RWInfoRm::kCategoryFixed , 0x02, 4 , 0, 0 }, // #5 [ref=33x] { InstDB::RWInfoRm::kCategoryConsistent, 0x04, 0 , 0, 0 }, // #6 [ref=270x] { InstDB::RWInfoRm::kCategoryFixed , 0x01, 2 , 0, 0 }, // #7 [ref=9x] { InstDB::RWInfoRm::kCategoryFixed , 0x00, 0 , 0, 0 }, // #8 [ref=60x] diff --git a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h b/3rdparty/asmjit/src/asmjit/x86/x86instdb.h index d03b87035c3..6bc2af5000a 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86instdb.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86instdb.h @@ -46,9 +46,9 @@ enum Mode : uint32_t { kModeAny = 0x03u //!< Both X86 and X64 modes supported. }; -static constexpr uint32_t modeFromArchId(uint32_t archId) noexcept { - return archId == ArchInfo::kIdX86 ? kModeX86 : - archId == ArchInfo::kIdX64 ? kModeX64 : kModeNone; +static constexpr uint32_t modeFromArch(uint32_t arch) noexcept { + return arch == Environment::kArchX86 ? kModeX86 : + arch == Environment::kArchX64 ? kModeX64 : kModeNone; } // ============================================================================ @@ -142,12 +142,6 @@ enum MemFlags : uint32_t { enum Flags : uint32_t { kFlagNone = 0x00000000u, //!< No flags. - // TODO: Deprecated - // ---------------- - - kFlagVolatile = 0x00000040u, - kFlagPrivileged = 0x00000080u, //!< This is a privileged operation that cannot run in user mode. - // Instruction Family // ------------------ // diff --git a/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp b/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp index a35b0d34e33..062525f5982 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86internal.cpp @@ -24,7 +24,7 @@ #include "../core/api-build_p.h" #ifdef ASMJIT_BUILD_X86 -#include "../core/logging.h" +#include "../core/formatter.h" #include "../core/string.h" #include "../core/support.h" #include "../core/type.h" @@ -67,11 +67,9 @@ static inline uint32_t x86KmovFromSize(uint32_t size) noexcept { // [asmjit::X86Internal - FuncDetail] // ============================================================================ -ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const FuncSignature& sign, uint32_t gpSize) noexcept { - DebugUtils::unused(sign); - +ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const FuncSignature& signature, uint32_t registerSize) noexcept { const CallConv& cc = func.callConv(); - uint32_t archId = cc.archId(); + uint32_t arch = cc.arch(); uint32_t stackOffset = cc._spillZoneSize; uint32_t i; @@ -82,7 +80,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func switch (typeId) { case Type::kIdI64: case Type::kIdU64: { - if (archId == ArchInfo::kIdX86) { + if (Environment::is32Bit(arch)) { // Convert a 64-bit return value to two 32-bit return values. func._retCount = 2; typeId -= 2; @@ -114,7 +112,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func case Type::kIdF32: case Type::kIdF64: { - uint32_t regType = (archId == ArchInfo::kIdX86) ? Reg::kTypeSt : Reg::kTypeXmm; + uint32_t regType = Environment::is32Bit(arch) ? Reg::kTypeSt : Reg::kTypeXmm; func._rets[0].initReg(regType, 0, typeId); break; } @@ -127,9 +125,9 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func case Type::kIdMmx32: case Type::kIdMmx64: { - // MM registers are returned through XMM or GPQ (Win64). + // MM registers are returned through XMM (SystemV) or GPQ (Win64). uint32_t regType = Reg::kTypeMm; - if (archId != ArchInfo::kIdX86) + if (Environment::is64Bit(arch)) regType = cc.strategy() == CallConv::kStrategyDefault ? Reg::kTypeXmm : Reg::kTypeGpq; func._rets[0].initReg(regType, 0, typeId); @@ -143,90 +141,156 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func } } - if (cc.strategy() == CallConv::kStrategyDefault) { - uint32_t gpzPos = 0; - uint32_t vecPos = 0; - - for (i = 0; i < argCount; i++) { - FuncValue& arg = func._args[i]; - uint32_t typeId = arg.typeId(); - - if (Type::isInt(typeId)) { - uint32_t regId = gpzPos < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupGp].id[gpzPos] : uint8_t(BaseReg::kIdBad); - if (regId != BaseReg::kIdBad) { - uint32_t regType = (typeId <= Type::kIdU32) ? Reg::kTypeGpd : Reg::kTypeGpq; - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); - gpzPos++; - } - else { - uint32_t size = Support::max<uint32_t>(Type::sizeOf(typeId), gpSize); - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += size; - } - continue; - } + switch (cc.strategy()) { + case CallConv::kStrategyDefault: { + uint32_t gpzPos = 0; + uint32_t vecPos = 0; + + for (i = 0; i < argCount; i++) { + FuncValue& arg = func._args[i]; + uint32_t typeId = arg.typeId(); - if (Type::isFloat(typeId) || Type::isVec(typeId)) { - uint32_t regId = vecPos < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupVec].id[vecPos] : uint8_t(BaseReg::kIdBad); + if (Type::isInt(typeId)) { + uint32_t regId = BaseReg::kIdBad; - // If this is a float, but `floatByVec` is false, we have to pass by stack. - if (Type::isFloat(typeId) && !cc.hasFlag(CallConv::kFlagPassFloatsByVec)) - regId = BaseReg::kIdBad; + if (gpzPos < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupGp].id[gpzPos]; - if (regId != BaseReg::kIdBad) { - arg.initTypeId(typeId); - arg.assignRegData(x86VecTypeIdToRegType(typeId), regId); - func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); - vecPos++; + if (regId != BaseReg::kIdBad) { + uint32_t regType = (typeId <= Type::kIdU32) ? Reg::kTypeGpd : Reg::kTypeGpq; + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); + gpzPos++; + } + else { + uint32_t size = Support::max<uint32_t>(Type::sizeOf(typeId), registerSize); + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += size; + } + continue; } - else { - uint32_t size = Type::sizeOf(typeId); - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += size; + + if (Type::isFloat(typeId) || Type::isVec(typeId)) { + uint32_t regId = BaseReg::kIdBad; + + if (vecPos < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupVec].id[vecPos]; + + if (Type::isFloat(typeId)) { + // If this is a float, but `kFlagPassFloatsByVec` is false, we have + // to use stack instead. This should be only used by 32-bit calling + // conventions. + if (!cc.hasFlag(CallConv::kFlagPassFloatsByVec)) + regId = BaseReg::kIdBad; + } + else { + // Pass vector registers via stack if this is a variable arguments + // function. This should be only used by 32-bit calling conventions. + if (signature.hasVarArgs() && cc.hasFlag(CallConv::kFlagPassVecByStackIfVA)) + regId = BaseReg::kIdBad; + } + + if (regId != BaseReg::kIdBad) { + arg.initTypeId(typeId); + arg.assignRegData(x86VecTypeIdToRegType(typeId), regId); + func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); + vecPos++; + } + else { + uint32_t size = Type::sizeOf(typeId); + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += size; + } + continue; } - continue; } + break; } - } - if (cc.strategy() == CallConv::kStrategyWin64) { - for (i = 0; i < argCount; i++) { - FuncValue& arg = func._args[i]; + case CallConv::kStrategyX64Windows: + case CallConv::kStrategyX64VectorCall: { + // Both X64 and VectorCall behave similarly - arguments are indexed + // from left to right. The position of the argument determines in + // which register the argument is allocated, so it's either GP or + // one of XMM/YMM/ZMM registers. + // + // [ X64 ] [VecCall] + // Index: #0 #1 #2 #3 #4 #5 + // + // GP : RCX RDX R8 R9 + // VEC : XMM0 XMM1 XMM2 XMM3 XMM4 XMM5 + // + // For example function `f(int a, double b, int c, double d)` will be: + // + // (a) (b) (c) (d) + // RCX XMM1 R8 XMM3 + // + // Unused vector registers are used by HVA. + + bool isVectorCall = (cc.strategy() == CallConv::kStrategyX64VectorCall); + + for (i = 0; i < argCount; i++) { + FuncValue& arg = func._args[i]; + + uint32_t typeId = arg.typeId(); + uint32_t size = Type::sizeOf(typeId); + + if (Type::isInt(typeId) || Type::isMmx(typeId)) { + uint32_t regId = BaseReg::kIdBad; + + if (i < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupGp].id[i]; + + if (regId != BaseReg::kIdBad) { + uint32_t regType = (size <= 4 && !Type::isMmx(typeId)) ? Reg::kTypeGpd : Reg::kTypeGpq; + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); + } + else { + arg.assignStackOffset(int32_t(stackOffset)); + stackOffset += 8; + } + continue; + } - uint32_t typeId = arg.typeId(); - uint32_t size = Type::sizeOf(typeId); + if (Type::isFloat(typeId) || Type::isVec(typeId)) { + uint32_t regId = BaseReg::kIdBad; - if (Type::isInt(typeId) || Type::isMmx(typeId)) { - uint32_t regId = i < CallConv::kMaxRegArgsPerGroup ? cc._passedOrder[Reg::kGroupGp].id[i] : uint8_t(BaseReg::kIdBad); - if (regId != BaseReg::kIdBad) { - uint32_t regType = (size <= 4 && !Type::isMmx(typeId)) ? Reg::kTypeGpd : Reg::kTypeGpq; - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupGp, Support::bitMask(regId)); - } - else { - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += gpSize; - } - continue; - } + if (i < CallConv::kMaxRegArgsPerGroup) + regId = cc._passedOrder[Reg::kGroupVec].id[i]; - if (Type::isFloat(typeId) || Type::isVec(typeId)) { - uint32_t regId = BaseReg::kIdBad; - if (i < CallConv::kMaxRegArgsPerGroup) - regId = cc._passedOrder[Reg::kGroupVec].id[i]; + if (regId != BaseReg::kIdBad) { + // X64-ABI doesn't allow vector types (XMM|YMM|ZMM) to be passed + // via registers, however, VectorCall was designed for that purpose. + if (Type::isFloat(typeId) || isVectorCall) { + uint32_t regType = x86VecTypeIdToRegType(typeId); + arg.assignRegData(regType, regId); + func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); + continue; + } + } - if (regId != BaseReg::kIdBad && (Type::isFloat(typeId) || cc.hasFlag(CallConv::kFlagVectorCall))) { - uint32_t regType = x86VecTypeIdToRegType(typeId); - arg.assignRegData(regType, regId); - func.addUsedRegs(Reg::kGroupVec, Support::bitMask(regId)); - } - else { - arg.assignStackOffset(int32_t(stackOffset)); - stackOffset += 8; // Always 8 bytes (float/double). + // Passed via stack if the argument is float/double or indirectly. + // The trap is - if the argument is passed indirectly, the address + // can be passed via register, if the argument's index has GP one. + if (Type::isFloat(typeId)) { + arg.assignStackOffset(int32_t(stackOffset)); + } + else { + uint32_t gpRegId = cc._passedOrder[Reg::kGroupGp].id[i]; + if (gpRegId != BaseReg::kIdBad) + arg.assignRegData(Reg::kTypeGpq, gpRegId); + else + arg.assignStackOffset(int32_t(stackOffset)); + arg.addFlags(FuncValue::kFlagIsIndirect); + } + + // Always 8 bytes (float/double/pointer). + stackOffset += 8; + continue; } - continue; } + break; } } @@ -238,14 +302,14 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncDetail(FuncDetail& func, const Func // [asmjit::X86FuncArgsContext] // ============================================================================ -static RegInfo x86GetRegForMemToMemMove(uint32_t archId, uint32_t dstTypeId, uint32_t srcTypeId) noexcept { +static RegInfo x86GetRegForMemToMemMove(uint32_t arch, uint32_t dstTypeId, uint32_t srcTypeId) noexcept { uint32_t dstSize = Type::sizeOf(dstTypeId); uint32_t srcSize = Type::sizeOf(srcTypeId); uint32_t maxSize = Support::max<uint32_t>(dstSize, srcSize); - uint32_t gpSize = archId == ArchInfo::kIdX86 ? 4 : 8; + uint32_t regSize = Environment::registerSizeFromArch(arch); uint32_t signature = 0; - if (maxSize <= gpSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId))) + if (maxSize <= regSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId))) signature = maxSize <= 4 ? Gpd::kSignature : Gpq::kSignature; else if (maxSize <= 16) signature = Xmm::kSignature; @@ -360,7 +424,7 @@ public: uint8_t _physToVarId[32]; //!< Physical ID to variable ID mapping. }; - uint8_t _archId; + uint8_t _arch; bool _hasStackSrc; //!< Has arguments passed via stack (SRC). bool _hasPreservedFP; //!< Has preserved frame-pointer (FP). uint8_t _stackDstMask; //!< Has arguments assigned to stack (DST). @@ -372,12 +436,12 @@ public: X86FuncArgsContext() noexcept; - inline uint32_t archId() const noexcept { return _archId; } + inline uint32_t arch() const noexcept { return _arch; } inline uint32_t varCount() const noexcept { return _varCount; } - inline Var& var(uint32_t varId) noexcept { return _vars[varId]; } - inline const Var& var(uint32_t varId) const noexcept { return _vars[varId]; } - inline uint32_t indexOf(const Var* var) const noexcept { return uint32_t((size_t)(var - _vars)); } + inline Var& var(size_t varId) noexcept { return _vars[varId]; } + inline const Var& var(size_t varId) const noexcept { return _vars[varId]; } + inline size_t indexOf(const Var* var) const noexcept { return (size_t)(var - _vars); } Error initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args) noexcept; Error markScratchRegs(FuncFrame& frame) noexcept; @@ -386,7 +450,7 @@ public: }; X86FuncArgsContext::X86FuncArgsContext() noexcept { - _archId = ArchInfo::kIdNone; + _arch = Environment::kArchUnknown; _varCount = 0; _hasStackSrc = false; _hasPreservedFP = false; @@ -405,11 +469,11 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t i; const FuncDetail& func = *args.funcDetail(); - // Initialize ArchType. - uint32_t archId = func.callConv().archId(); - uint32_t archRegCount = (archId == ArchInfo::kIdX86) ? 8 : 16; + // Initialize Architecture. + uint32_t arch = func.callConv().arch(); + uint32_t archRegCount = Environment::is32Bit(arch) ? 8 : 16; - _archId = uint8_t(archId); + _arch = uint8_t(arch); // Initialize `_archRegs`. _workData[Reg::kGroupGp ]._archRegs = Support::lsbMask<uint32_t>(archRegCount) & ~Support::bitMask(Gp::kIdSp); @@ -424,7 +488,8 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t varId = 0; for (i = 0; i < kFuncArgCountLoHi; i++) { const FuncValue& dst_ = args.arg(i); - if (!dst_.isAssigned()) continue; + if (!dst_.isAssigned()) + continue; const FuncValue& src_ = func.arg(i); if (ASMJIT_UNLIKELY(!src_.isAssigned())) @@ -440,6 +505,10 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, uint32_t dstId = BaseReg::kIdBad; WorkData* dstWd = nullptr; + // Not supported. + if (src.isIndirect()) + return DebugUtils::errored(kErrorInvalidAssignment); + if (dst.isReg()) { uint32_t dstType = dst.regType(); if (ASMJIT_UNLIKELY(dstType >= Reg::kTypeCount)) @@ -471,7 +540,7 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, if (!dst.hasTypeId()) dst.setTypeId(src.typeId()); - RegInfo regInfo = x86GetRegForMemToMemMove(archId, dst.typeId(), src.typeId()); + RegInfo regInfo = x86GetRegForMemToMemMove(arch, dst.typeId(), src.typeId()); if (ASMJIT_UNLIKELY(!regInfo.isValid())) return DebugUtils::errored(kErrorInvalidState); _stackDstMask = uint8_t(_stackDstMask | Support::bitMask(regInfo.group())); @@ -530,8 +599,8 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::initWorkData(const FuncFrame& frame, } if (saRegRequired) { - uint32_t ptrTypeId = (archId == ArchInfo::kIdX86) ? Type::kIdU32 : Type::kIdU64; - uint32_t ptrRegType = (archId == ArchInfo::kIdX86) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; + uint32_t ptrTypeId = Environment::is32Bit(arch) ? Type::kIdU32 : Type::kIdU64; + uint32_t ptrRegType = Environment::is32Bit(arch) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64; _saVarId = uint8_t(varId); _hasPreservedFP = frame.hasPreservedFP(); @@ -622,7 +691,7 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no if (!groupMask) return kErrorOk; - // selects one dirty register per affected group that can be used as a scratch register. + // Selects one dirty register per affected group that can be used as a scratch register. for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) { if (Support::bitTest(groupMask, group)) { WorkData& wd = _workData[group]; @@ -632,15 +701,18 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no uint32_t regs = workRegs & ~(wd.usedRegs() | wd._dstShuf); // If that didn't work out pick some register which is not in 'used'. - if (!regs) regs = workRegs & ~wd.usedRegs(); + if (!regs) + regs = workRegs & ~wd.usedRegs(); // If that didn't work out pick any other register that is allocable. // This last resort case will, however, result in marking one more // register dirty. - if (!regs) regs = wd.archRegs() & ~workRegs; + if (!regs) + regs = wd.archRegs() & ~workRegs; // If that didn't work out we will have to use XORs instead of MOVs. - if (!regs) continue; + if (!regs) + continue; uint32_t regMask = Support::blsi(regs); wd._workRegs |= regMask; @@ -652,7 +724,6 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markScratchRegs(FuncFrame& frame) no } ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markStackArgsReg(FuncFrame& frame) noexcept { - // TODO: Validate, improve... if (_saVarId != kVarIdNone) { const Var& var = _vars[_saVarId]; frame.setSARegId(var.cur.regId()); @@ -670,14 +741,14 @@ ASMJIT_FAVOR_SIZE Error X86FuncArgsContext::markStackArgsReg(FuncFrame& frame) n // ============================================================================ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncFrame(FuncFrame& frame, const FuncDetail& func) noexcept { - uint32_t archId = func.callConv().archId(); + uint32_t arch = func.callConv().arch(); // Initializing FuncFrame means making a copy of some properties of `func`. // Properties like `_localStackSize` will be set by the user before the frame // is finalized. frame.reset(); - frame._archId = uint8_t(archId); + frame._arch = uint8_t(arch); frame._spRegId = Gp::kIdSp; frame._saRegId = Gp::kIdBad; @@ -710,7 +781,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::initFuncFrame(FuncFrame& frame, const FuncD } ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcept { - uint32_t gpSize = frame.archId() == ArchInfo::kIdX86 ? 4 : 8; + uint32_t registerSize = Environment::registerSizeFromArch(frame.arch()); // The final stack alignment must be updated accordingly to call and local stack alignments. uint32_t stackAlignment = frame._finalStackAlignment; @@ -746,7 +817,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep frame._saRegId = uint8_t(saRegId); // Setup stack size used to save preserved registers. - frame._gpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupGp )) * gpSize); + frame._gpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupGp )) * registerSize); frame._nonGpSaveSize = uint16_t(Support::popcnt(frame.savedRegs(Reg::kGroupVec )) * vecSize + Support::popcnt(frame.savedRegs(Reg::kGroupMm )) * 8 + Support::popcnt(frame.savedRegs(Reg::kGroupKReg)) * 8); @@ -772,15 +843,15 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep // Calculate if dynamic alignment (DA) slot (stored as offset relative to SP) is required and its offset. if (hasDA && !hasFP) { frame._daOffset = v; // Store 'daOffset' <- DA pointer would be stored here. - v += gpSize; // Count 'daOffset'. + v += registerSize; // Count 'daOffset'. } else { frame._daOffset = FuncFrame::kTagInvalidOffset; } // The return address should be stored after GP save/restore regs. It has - // the same size as `gpSize` (basically the native register/pointer size). - // We don't adjust it now as `v` now contains the exact size that the + // the same size as `registerSize` (basically the native register/pointer + // size). We don't adjust it now as `v` now contains the exact size that the // function requires to adjust (call frame + stack frame, vec stack size). // The stack (if we consider this size) is misaligned now, as it's always // aligned before the function call - when `call()` is executed it pushes @@ -788,27 +859,27 @@ ASMJIT_FAVOR_SIZE Error X86Internal::finalizeFuncFrame(FuncFrame& frame) noexcep // (depending on the architecture). So count number of bytes needed to align // it up to the function's CallFrame (the beginning). if (v || frame.hasFuncCalls()) - v += Support::alignUpDiff(v + frame.gpSaveSize() + gpSize, stackAlignment); + v += Support::alignUpDiff(v + frame.gpSaveSize() + registerSize, stackAlignment); frame._gpSaveOffset = v; // Store 'gpSaveOffset' <- Function's GP Save/Restore starts here. frame._stackAdjustment = v; // Store 'stackAdjustment' <- SA used by 'add zsp, SA' and 'sub zsp, SA'. v += frame._gpSaveSize; // Count 'gpSaveSize' <- Function's GP Save/Restore ends here. - v += gpSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. + v += registerSize; // Count 'ReturnAddress' <- As CALL pushes onto stack. // If the function performs dynamic stack alignment then the stack-adjustment must be aligned. if (hasDA) frame._stackAdjustment = Support::alignUp(frame._stackAdjustment, stackAlignment); uint32_t saInvOff = FuncFrame::kTagInvalidOffset; - uint32_t saTmpOff = gpSize + frame._gpSaveSize; + uint32_t saTmpOff = registerSize + frame._gpSaveSize; // Calculate where the function arguments start relative to SP. frame._saOffsetFromSP = hasDA ? saInvOff : v; // Calculate where the function arguments start relative to FP or user-provided register. - frame._saOffsetFromSA = hasFP ? gpSize * 2 // Return address + frame pointer. - : saTmpOff; // Return address + all saved GP regs. + frame._saOffsetFromSA = hasFP ? registerSize * 2 // Return address + frame pointer. + : saTmpOff; // Return address + all saved GP regs. return kErrorOk; } @@ -943,7 +1014,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, const Operand_& src_, uint32_t srcTypeId, bool avxEnabled, const char* comment) { // Deduce optional `dstTypeId`, which may be `Type::kIdVoid` in some cases. - if (!dstTypeId) dstTypeId = opData.archRegs.regTypeToTypeId[dst_.type()]; + if (!dstTypeId) + dstTypeId = opData.archRegs.regTypeToTypeId[dst_.type()]; // Invalid or abstract TypeIds are not allowed. ASMJIT_ASSERT(Type::isValid(dstTypeId) && !Type::isAbstract(dstTypeId)); @@ -969,11 +1041,13 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, typeOp == ((Type::kIdI32 << 8) | Type::kIdI8 ) || typeOp == ((Type::kIdI32 << 8) | Type::kIdI16) || typeOp == ((Type::kIdI64 << 8) | Type::kIdI8 ) || - typeOp == ((Type::kIdI64 << 8) | Type::kIdI16)) break; + typeOp == ((Type::kIdI64 << 8) | Type::kIdI16)) + break; // Sign extend by using 'movsxd'. instId = Inst::kIdMovsxd; - if (typeOp == ((Type::kIdI64 << 8) | Type::kIdI32)) break; + if (typeOp == ((Type::kIdI64 << 8) | Type::kIdI32)) + break; } if (Type::isInt(srcTypeId) || src_.isMem()) { @@ -991,7 +1065,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, dst.setSignature(srcSize == 4 ? Reg::signatureOfT<Reg::kTypeGpd>() : Reg::signatureOfT<Reg::kTypeGpq>()); - if (src.isReg()) src.setSignature(dst.signature()); + if (src.isReg()) + src.setSignature(dst.signature()); } break; } @@ -1003,7 +1078,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isMmx(srcTypeId)) { // 64-bit move. instId = Inst::kIdMovq; - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = Inst::kIdMovd; @@ -1021,7 +1097,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isVec(srcTypeId)) { // 64-bit move. instId = avxEnabled ? Inst::kIdVmovq : Inst::kIdMovq; - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd; @@ -1036,19 +1113,23 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isInt(srcTypeId) || src.isMem()) { // 64-bit move. - if (srcSize == 8) break; + if (srcSize == 8) + break; // 32-bit move. instId = Inst::kIdMovd; - if (src.isReg()) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (src.isReg()) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } - if (Type::isMmx(srcTypeId)) break; + if (Type::isMmx(srcTypeId)) + break; // This will hurt if `avxEnabled`. instId = Inst::kIdMovdq2q; - if (Type::isVec(srcTypeId)) break; + if (Type::isVec(srcTypeId)) +break; } if (Type::isMask(dstTypeId)) { @@ -1056,7 +1137,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Type::isInt(srcTypeId) || Type::isMask(srcTypeId) || src.isMem()) { instId = x86KmovFromSize(srcSize); - if (Reg::isGp(src) && srcSize <= 4) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (Reg::isGp(src) && srcSize <= 4) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } } @@ -1112,7 +1194,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, // 32-bit move. if (srcSize <= 4) { instId = avxEnabled ? Inst::kIdVmovd : Inst::kIdMovd; - if (src.isReg()) src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); + if (src.isReg()) + src.setSignature(Reg::signatureOfT<Reg::kTypeGpd>()); break; } @@ -1125,10 +1208,14 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgMove(Emitter* emitter, if (Reg::isVec(src) || src.isMem()) { instId = avxEnabled ? Inst::kIdVmovaps : Inst::kIdMovaps; - uint32_t sign = Reg::signatureOfVecBySize(srcSize); - dst.setSignature(sign); - if (src.isReg()) src.setSignature(sign); + if (src.isMem() && srcSize < emitter->environment().stackAlignment()) + instId = avxEnabled ? Inst::kIdVmovups : Inst::kIdMovups; + + uint32_t signature = Reg::signatureOfVecBySize(srcSize); + dst.setSignature(signature); + if (src.isReg()) + src.setSignature(signature); break; } } @@ -1249,7 +1336,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram uint32_t i; uint32_t regId; - uint32_t gpSize = emitter->gpSize(); + uint32_t registerSize = emitter->registerSize(); uint32_t gpSaved = frame.savedRegs(Reg::kGroupGp); Gp zsp = emitter->zsp(); // ESP|RSP register. @@ -1287,7 +1374,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram if (frame.hasPreservedFP()) { // Emit 'mov zsp, zbp' or 'lea zsp, [zbp - x]' - int32_t count = int32_t(frame.gpSaveSize() - gpSize); + int32_t count = int32_t(frame.gpSaveSize() - registerSize); if (!count) ASMJIT_PROPAGATE(emitter->mov(zsp, zbp)); else @@ -1338,24 +1425,28 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitEpilog(Emitter* emitter, const FuncFram // ============================================================================ #ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT -static void dumpFuncValue(String& sb, uint32_t archId, const FuncValue& value) noexcept { - Logging::formatTypeId(sb, value.typeId()); - sb.appendChar('@'); - if (value.isReg()) { - Logging::formatRegister(sb, 0, nullptr, archId, value.regType(), value.regId()); - } - else if (value.isStack()) { +static void dumpFuncValue(String& sb, uint32_t arch, const FuncValue& value) noexcept { + Formatter::formatTypeId(sb, value.typeId()); + sb.append('@'); + + if (value.isIndirect()) + sb.append('['); + + if (value.isReg()) + Formatter::formatRegister(sb, 0, nullptr, arch, value.regType(), value.regId()); + else if (value.isStack()) sb.appendFormat("[%d]", value.stackOffset()); - } - else { - sb.appendString("<none>"); - } + else + sb.append("<none>"); + + if (value.isIndirect()) + sb.append(']'); } static void dumpAssignment(String& sb, const X86FuncArgsContext& ctx) noexcept { typedef X86FuncArgsContext::Var Var; - uint32_t archId = ctx.archId(); + uint32_t arch = ctx.arch(); uint32_t varCount = ctx.varCount(); for (uint32_t i = 0; i < varCount; i++) { @@ -1364,14 +1455,14 @@ static void dumpAssignment(String& sb, const X86FuncArgsContext& ctx) noexcept { const FuncValue& cur = var.cur; sb.appendFormat("Var%u: ", i); - dumpFuncValue(sb, archId, dst); - sb.appendString(" <- "); - dumpFuncValue(sb, archId, cur); + dumpFuncValue(sb, arch, dst); + sb.append(" <- "); + dumpFuncValue(sb, arch, cur); if (var.isDone()) - sb.appendString(" {Done}"); + sb.append(" {Done}"); - sb.appendChar('\n'); + sb.append('\n'); } } #endif @@ -1398,7 +1489,7 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const } #endif - uint32_t archId = ctx.archId(); + uint32_t arch = ctx.arch(); uint32_t varCount = ctx._varCount; WorkData* workData = ctx._workData; @@ -1415,6 +1506,8 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const saRegId = saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId(); } + RegInfo gpRegInfo = emitter->_gpRegInfo; + // -------------------------------------------------------------------------- // Register to stack and stack to stack moves must be first as now we have // the biggest chance of having as many as possible unassigned registers. @@ -1427,24 +1520,42 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (!var.out.isStack()) continue; - ASMJIT_ASSERT(var.cur.isReg() || var.cur.isStack()); + if (!var.out.isStack()) + continue; + + FuncValue& cur = var.cur; + FuncValue& out = var.out; + + ASMJIT_ASSERT(cur.isReg() || cur.isStack()); Reg reg; - if (var.cur.isReg()) { - WorkData& wd = workData[Reg::groupOf(var.cur.regType())]; - uint32_t rId = var.cur.regId(); + Mem dstStackPtr = baseStackPtr.cloneAdjusted(out.stackOffset()); + Mem srcStackPtr = baseArgPtr.cloneAdjusted(cur.stackOffset()); + + if (cur.isIndirect()) { + if (cur.isStack()) { + // TODO: Indirect stack. + return DebugUtils::errored(kErrorInvalidAssignment); + } + else { + srcStackPtr = ptr(Gp(gpRegInfo.signature(), cur.regId())); + } + } + + if (cur.isReg() && !cur.isIndirect()) { + WorkData& wd = workData[Reg::groupOf(cur.regType())]; + uint32_t rId = cur.regId(); - reg.setSignatureAndId(Reg::signatureOf(var.cur.regType()), rId); + reg.setSignatureAndId(Reg::signatureOf(cur.regType()), rId); wd.unassign(varId, rId); } else { // Stack to reg move - tricky since we move stack to stack we can decide which // register to use. In general we follow the rule that IntToInt moves will use - // GP regs with possibility to sign or zero extend, and all other moves will + // GP regs with possibility to signature or zero extend, and all other moves will // either use GP or VEC regs depending on the size of the move. - RegInfo rInfo = x86GetRegForMemToMemMove(archId, var.out.typeId(), var.cur.typeId()); + RegInfo rInfo = x86GetRegForMemToMemMove(arch, out.typeId(), cur.typeId()); if (ASMJIT_UNLIKELY(!rInfo.isValid())) return DebugUtils::errored(kErrorInvalidState); @@ -1456,54 +1567,42 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const uint32_t rId = Support::ctz(availableRegs); reg.setSignatureAndId(rInfo.signature(), rId); - ASMJIT_PROPAGATE( - emitArgMove(emitter, - reg, - var.out.typeId(), - baseArgPtr.cloneAdjusted(var.cur.stackOffset()), - var.cur.typeId(), - avxEnabled)); + ASMJIT_PROPAGATE(emitArgMove(emitter, reg, out.typeId(), srcStackPtr, cur.typeId(), avxEnabled)); } - // Register to stack move. - ASMJIT_PROPAGATE( - emitRegMove(emitter, baseStackPtr.cloneAdjusted(var.out.stackOffset()), reg, var.cur.typeId(), avxEnabled)); + if (cur.isIndirect() && cur.isReg()) + workData[BaseReg::kGroupGp].unassign(varId, cur.regId()); + // Register to stack move. + ASMJIT_PROPAGATE(emitRegMove(emitter, dstStackPtr, reg, cur.typeId(), avxEnabled)); var.markDone(); } } // -------------------------------------------------------------------------- - // Shuffle all registers that are currently assigned accordingly to the assignment. + // Shuffle all registers that are currently assigned accordingly to target + // assignment. // -------------------------------------------------------------------------- uint32_t workFlags = kWorkNone; for (;;) { for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (var.isDone() || !var.cur.isReg()) continue; + if (var.isDone() || !var.cur.isReg()) + continue; - uint32_t curType = var.cur.regType(); - uint32_t outType = var.out.regType(); + FuncValue& cur = var.cur; + FuncValue& out = var.out; - uint32_t curGroup = Reg::groupOf(curType); - uint32_t outGroup = Reg::groupOf(outType); + uint32_t curGroup = Reg::groupOf(cur.regType()); + uint32_t outGroup = Reg::groupOf(out.regType()); - uint32_t curId = var.cur.regId(); - uint32_t outId = var.out.regId(); + uint32_t curId = cur.regId(); + uint32_t outId = out.regId(); if (curGroup != outGroup) { - ASMJIT_ASSERT(false); - - // Requires a conversion between two register groups. - if (workData[outGroup]._numSwaps) { - // TODO: Postponed - workFlags |= kWorkPending; - } - else { - // TODO: - workFlags |= kWorkPending; - } + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); } else { WorkData& wd = workData[outGroup]; @@ -1511,13 +1610,13 @@ ASMJIT_FAVOR_SIZE Error X86Internal::emitArgsAssignment(Emitter* emitter, const EmitMove: ASMJIT_PROPAGATE( emitArgMove(emitter, - Reg::fromTypeAndId(outType, outId), var.out.typeId(), - Reg::fromTypeAndId(curType, curId), var.cur.typeId(), avxEnabled)); + Reg::fromTypeAndId(out.regType(), outId), out.typeId(), + Reg::fromTypeAndId(cur.regType(), curId), cur.typeId(), avxEnabled)); wd.reassign(varId, outId, curId); - var.cur.initReg(outType, outId, var.out.typeId()); + cur.initReg(out.regType(), outId, out.typeId()); - if (outId == var.out.regId()) + if (outId == out.regId()) var.markDone(); workFlags |= kWorkDidSome | kWorkPending; } @@ -1528,13 +1627,13 @@ EmitMove: if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) { // Swap operation is possible only between two GP registers. if (curGroup == Reg::kGroupGp) { - uint32_t highestType = Support::max(var.cur.regType(), altVar.cur.regType()); + uint32_t highestType = Support::max(cur.regType(), altVar.cur.regType()); uint32_t signature = highestType == Reg::kTypeGpq ? Reg::signatureOfT<Reg::kTypeGpq>() : Reg::signatureOfT<Reg::kTypeGpd>(); ASMJIT_PROPAGATE(emitter->emit(Inst::kIdXchg, Reg(signature, outId), Reg(signature, curId))); wd.swap(varId, curId, altId, outId); - var.cur.setRegId(outId); + cur.setRegId(outId); var.markDone(); altVar.cur.setRegId(curId); @@ -1590,7 +1689,8 @@ EmitMove: for (uint32_t iter = 0; iter < iterCount; iter++) { for (uint32_t varId = 0; varId < varCount; varId++) { Var& var = ctx._vars[varId]; - if (var.isDone()) continue; + if (var.isDone()) + continue; if (var.cur.isStack()) { ASMJIT_ASSERT(var.out.isReg()); diff --git a/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h b/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h index a1b76963f2a..d4ea8e1f9bf 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86internal_p.h @@ -43,10 +43,10 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! X86 utilities used at multiple places, not part of public API, not exported. struct X86Internal { //! Initialize `FuncDetail` (X86 specific). - static Error initFuncDetail(FuncDetail& func, const FuncSignature& sign, uint32_t gpSize) noexcept; + static Error initFuncDetail(FuncDetail& func, const FuncSignature& signature, uint32_t registerSize) noexcept; //! Initialize `FuncFrame` (X86 specific). - static Error initFuncFrame(FuncFrame& frame, const FuncDetail& func) noexcept; + static Error initFuncFrame(FuncFrame& frame, const FuncDetail& signature) noexcept; //! Finalize `FuncFrame` (X86 specific). static Error finalizeFuncFrame(FuncFrame& frame) noexcept; diff --git a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h index 69cafe5be7c..164b26c1dea 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h @@ -24,8 +24,6 @@ #ifndef ASMJIT_X86_X86OPCODE_P_H_INCLUDED #define ASMJIT_X86_X86OPCODE_P_H_INCLUDED -#include "../core/logging.h" -#include "../core/string.h" #include "../x86/x86globals.h" ASMJIT_BEGIN_SUB_NAMESPACE(x86) diff --git a/3rdparty/asmjit/src/asmjit/x86/x86operand.h b/3rdparty/asmjit/src/asmjit/x86/x86operand.h index 7e220214271..ccbe87e9ea3 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86operand.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86operand.h @@ -31,6 +31,58 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) +#define ASMJIT_MEM_PTR(FUNC, SIZE) \ + static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ + return Mem(base, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ + return Mem(base, index, shift, offset, SIZE); \ + } \ + static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ + return Mem(rip_, offset, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base) noexcept { \ + return Mem(base, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE); \ + } \ + \ + static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ + return Mem(base, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ + } \ + \ + static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ + return Mem(base, SIZE, BaseMem::kSignatureMemRel); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ + } \ + static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ + return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ + } + +//! \addtogroup asmjit_x86 +//! \{ + // ============================================================================ // [Forward Declarations] // ============================================================================ @@ -58,11 +110,8 @@ class St; class Bnd; class Rip; -//! \addtogroup asmjit_x86 -//! \{ - // ============================================================================ -// [asmjit::x86::RegTraits] +// [asmjit::x86::Reg] // ============================================================================ //! Register traits (X86). @@ -96,10 +145,6 @@ ASMJIT_DEFINE_REG_TRAITS(Bnd , BaseReg::kTypeCustom + 4, BaseReg::kGroupVirt + ASMJIT_DEFINE_REG_TRAITS(Rip , BaseReg::kTypeIP , BaseReg::kGroupVirt + 5, 0 , 1 , Type::kIdVoid ); //! \endcond -// ============================================================================ -// [asmjit::x86::Reg] -// ============================================================================ - //! Register (X86). class Reg : public BaseReg { public: @@ -403,6 +448,303 @@ inline Ymm Vec::ymm() const noexcept { return Ymm(id()); } inline Zmm Vec::zmm() const noexcept { return Zmm(id()); } //! \endcond +//! \namespace asmjit::x86::regs +//! +//! Registers provided by X86 and X64 ISAs are in both `asmjit::x86` and +//! `asmjit::x86::regs` namespaces so they can be included with using directive. +//! For example `using namespace asmjit::x86::regs` would include all registers, +//! but not other X86-specific API, whereas `using namespace asmjit::x86` would +//! include everything X86-specific. +#ifndef _DOXYGEN +namespace regs { +#endif + +//! Creates an 8-bit low GPB register operand. +static constexpr GpbLo gpb(uint32_t rId) noexcept { return GpbLo(rId); } +//! Creates an 8-bit low GPB register operand. +static constexpr GpbLo gpb_lo(uint32_t rId) noexcept { return GpbLo(rId); } +//! Creates an 8-bit high GPB register operand. +static constexpr GpbHi gpb_hi(uint32_t rId) noexcept { return GpbHi(rId); } +//! Creates a 16-bit GPW register operand. +static constexpr Gpw gpw(uint32_t rId) noexcept { return Gpw(rId); } +//! Creates a 32-bit GPD register operand. +static constexpr Gpd gpd(uint32_t rId) noexcept { return Gpd(rId); } +//! Creates a 64-bit GPQ register operand (64-bit). +static constexpr Gpq gpq(uint32_t rId) noexcept { return Gpq(rId); } +//! Creates a 128-bit XMM register operand. +static constexpr Xmm xmm(uint32_t rId) noexcept { return Xmm(rId); } +//! Creates a 256-bit YMM register operand. +static constexpr Ymm ymm(uint32_t rId) noexcept { return Ymm(rId); } +//! Creates a 512-bit ZMM register operand. +static constexpr Zmm zmm(uint32_t rId) noexcept { return Zmm(rId); } +//! Creates a 64-bit Mm register operand. +static constexpr Mm mm(uint32_t rId) noexcept { return Mm(rId); } +//! Creates a 64-bit K register operand. +static constexpr KReg k(uint32_t rId) noexcept { return KReg(rId); } +//! Creates a 32-bit or 64-bit control register operand. +static constexpr CReg cr(uint32_t rId) noexcept { return CReg(rId); } +//! Creates a 32-bit or 64-bit debug register operand. +static constexpr DReg dr(uint32_t rId) noexcept { return DReg(rId); } +//! Creates an 80-bit st register operand. +static constexpr St st(uint32_t rId) noexcept { return St(rId); } +//! Creates a 128-bit bound register operand. +static constexpr Bnd bnd(uint32_t rId) noexcept { return Bnd(rId); } + +static constexpr Gp al = Gp(GpbLo::kSignature, Gp::kIdAx); +static constexpr Gp bl = Gp(GpbLo::kSignature, Gp::kIdBx); +static constexpr Gp cl = Gp(GpbLo::kSignature, Gp::kIdCx); +static constexpr Gp dl = Gp(GpbLo::kSignature, Gp::kIdDx); +static constexpr Gp spl = Gp(GpbLo::kSignature, Gp::kIdSp); +static constexpr Gp bpl = Gp(GpbLo::kSignature, Gp::kIdBp); +static constexpr Gp sil = Gp(GpbLo::kSignature, Gp::kIdSi); +static constexpr Gp dil = Gp(GpbLo::kSignature, Gp::kIdDi); +static constexpr Gp r8b = Gp(GpbLo::kSignature, Gp::kIdR8); +static constexpr Gp r9b = Gp(GpbLo::kSignature, Gp::kIdR9); +static constexpr Gp r10b = Gp(GpbLo::kSignature, Gp::kIdR10); +static constexpr Gp r11b = Gp(GpbLo::kSignature, Gp::kIdR11); +static constexpr Gp r12b = Gp(GpbLo::kSignature, Gp::kIdR12); +static constexpr Gp r13b = Gp(GpbLo::kSignature, Gp::kIdR13); +static constexpr Gp r14b = Gp(GpbLo::kSignature, Gp::kIdR14); +static constexpr Gp r15b = Gp(GpbLo::kSignature, Gp::kIdR15); + +static constexpr Gp ah = Gp(GpbHi::kSignature, Gp::kIdAx); +static constexpr Gp bh = Gp(GpbHi::kSignature, Gp::kIdBx); +static constexpr Gp ch = Gp(GpbHi::kSignature, Gp::kIdCx); +static constexpr Gp dh = Gp(GpbHi::kSignature, Gp::kIdDx); + +static constexpr Gp ax = Gp(Gpw::kSignature, Gp::kIdAx); +static constexpr Gp bx = Gp(Gpw::kSignature, Gp::kIdBx); +static constexpr Gp cx = Gp(Gpw::kSignature, Gp::kIdCx); +static constexpr Gp dx = Gp(Gpw::kSignature, Gp::kIdDx); +static constexpr Gp sp = Gp(Gpw::kSignature, Gp::kIdSp); +static constexpr Gp bp = Gp(Gpw::kSignature, Gp::kIdBp); +static constexpr Gp si = Gp(Gpw::kSignature, Gp::kIdSi); +static constexpr Gp di = Gp(Gpw::kSignature, Gp::kIdDi); +static constexpr Gp r8w = Gp(Gpw::kSignature, Gp::kIdR8); +static constexpr Gp r9w = Gp(Gpw::kSignature, Gp::kIdR9); +static constexpr Gp r10w = Gp(Gpw::kSignature, Gp::kIdR10); +static constexpr Gp r11w = Gp(Gpw::kSignature, Gp::kIdR11); +static constexpr Gp r12w = Gp(Gpw::kSignature, Gp::kIdR12); +static constexpr Gp r13w = Gp(Gpw::kSignature, Gp::kIdR13); +static constexpr Gp r14w = Gp(Gpw::kSignature, Gp::kIdR14); +static constexpr Gp r15w = Gp(Gpw::kSignature, Gp::kIdR15); + +static constexpr Gp eax = Gp(Gpd::kSignature, Gp::kIdAx); +static constexpr Gp ebx = Gp(Gpd::kSignature, Gp::kIdBx); +static constexpr Gp ecx = Gp(Gpd::kSignature, Gp::kIdCx); +static constexpr Gp edx = Gp(Gpd::kSignature, Gp::kIdDx); +static constexpr Gp esp = Gp(Gpd::kSignature, Gp::kIdSp); +static constexpr Gp ebp = Gp(Gpd::kSignature, Gp::kIdBp); +static constexpr Gp esi = Gp(Gpd::kSignature, Gp::kIdSi); +static constexpr Gp edi = Gp(Gpd::kSignature, Gp::kIdDi); +static constexpr Gp r8d = Gp(Gpd::kSignature, Gp::kIdR8); +static constexpr Gp r9d = Gp(Gpd::kSignature, Gp::kIdR9); +static constexpr Gp r10d = Gp(Gpd::kSignature, Gp::kIdR10); +static constexpr Gp r11d = Gp(Gpd::kSignature, Gp::kIdR11); +static constexpr Gp r12d = Gp(Gpd::kSignature, Gp::kIdR12); +static constexpr Gp r13d = Gp(Gpd::kSignature, Gp::kIdR13); +static constexpr Gp r14d = Gp(Gpd::kSignature, Gp::kIdR14); +static constexpr Gp r15d = Gp(Gpd::kSignature, Gp::kIdR15); + +static constexpr Gp rax = Gp(Gpq::kSignature, Gp::kIdAx); +static constexpr Gp rbx = Gp(Gpq::kSignature, Gp::kIdBx); +static constexpr Gp rcx = Gp(Gpq::kSignature, Gp::kIdCx); +static constexpr Gp rdx = Gp(Gpq::kSignature, Gp::kIdDx); +static constexpr Gp rsp = Gp(Gpq::kSignature, Gp::kIdSp); +static constexpr Gp rbp = Gp(Gpq::kSignature, Gp::kIdBp); +static constexpr Gp rsi = Gp(Gpq::kSignature, Gp::kIdSi); +static constexpr Gp rdi = Gp(Gpq::kSignature, Gp::kIdDi); +static constexpr Gp r8 = Gp(Gpq::kSignature, Gp::kIdR8); +static constexpr Gp r9 = Gp(Gpq::kSignature, Gp::kIdR9); +static constexpr Gp r10 = Gp(Gpq::kSignature, Gp::kIdR10); +static constexpr Gp r11 = Gp(Gpq::kSignature, Gp::kIdR11); +static constexpr Gp r12 = Gp(Gpq::kSignature, Gp::kIdR12); +static constexpr Gp r13 = Gp(Gpq::kSignature, Gp::kIdR13); +static constexpr Gp r14 = Gp(Gpq::kSignature, Gp::kIdR14); +static constexpr Gp r15 = Gp(Gpq::kSignature, Gp::kIdR15); + +static constexpr Xmm xmm0 = Xmm(0); +static constexpr Xmm xmm1 = Xmm(1); +static constexpr Xmm xmm2 = Xmm(2); +static constexpr Xmm xmm3 = Xmm(3); +static constexpr Xmm xmm4 = Xmm(4); +static constexpr Xmm xmm5 = Xmm(5); +static constexpr Xmm xmm6 = Xmm(6); +static constexpr Xmm xmm7 = Xmm(7); +static constexpr Xmm xmm8 = Xmm(8); +static constexpr Xmm xmm9 = Xmm(9); +static constexpr Xmm xmm10 = Xmm(10); +static constexpr Xmm xmm11 = Xmm(11); +static constexpr Xmm xmm12 = Xmm(12); +static constexpr Xmm xmm13 = Xmm(13); +static constexpr Xmm xmm14 = Xmm(14); +static constexpr Xmm xmm15 = Xmm(15); +static constexpr Xmm xmm16 = Xmm(16); +static constexpr Xmm xmm17 = Xmm(17); +static constexpr Xmm xmm18 = Xmm(18); +static constexpr Xmm xmm19 = Xmm(19); +static constexpr Xmm xmm20 = Xmm(20); +static constexpr Xmm xmm21 = Xmm(21); +static constexpr Xmm xmm22 = Xmm(22); +static constexpr Xmm xmm23 = Xmm(23); +static constexpr Xmm xmm24 = Xmm(24); +static constexpr Xmm xmm25 = Xmm(25); +static constexpr Xmm xmm26 = Xmm(26); +static constexpr Xmm xmm27 = Xmm(27); +static constexpr Xmm xmm28 = Xmm(28); +static constexpr Xmm xmm29 = Xmm(29); +static constexpr Xmm xmm30 = Xmm(30); +static constexpr Xmm xmm31 = Xmm(31); + +static constexpr Ymm ymm0 = Ymm(0); +static constexpr Ymm ymm1 = Ymm(1); +static constexpr Ymm ymm2 = Ymm(2); +static constexpr Ymm ymm3 = Ymm(3); +static constexpr Ymm ymm4 = Ymm(4); +static constexpr Ymm ymm5 = Ymm(5); +static constexpr Ymm ymm6 = Ymm(6); +static constexpr Ymm ymm7 = Ymm(7); +static constexpr Ymm ymm8 = Ymm(8); +static constexpr Ymm ymm9 = Ymm(9); +static constexpr Ymm ymm10 = Ymm(10); +static constexpr Ymm ymm11 = Ymm(11); +static constexpr Ymm ymm12 = Ymm(12); +static constexpr Ymm ymm13 = Ymm(13); +static constexpr Ymm ymm14 = Ymm(14); +static constexpr Ymm ymm15 = Ymm(15); +static constexpr Ymm ymm16 = Ymm(16); +static constexpr Ymm ymm17 = Ymm(17); +static constexpr Ymm ymm18 = Ymm(18); +static constexpr Ymm ymm19 = Ymm(19); +static constexpr Ymm ymm20 = Ymm(20); +static constexpr Ymm ymm21 = Ymm(21); +static constexpr Ymm ymm22 = Ymm(22); +static constexpr Ymm ymm23 = Ymm(23); +static constexpr Ymm ymm24 = Ymm(24); +static constexpr Ymm ymm25 = Ymm(25); +static constexpr Ymm ymm26 = Ymm(26); +static constexpr Ymm ymm27 = Ymm(27); +static constexpr Ymm ymm28 = Ymm(28); +static constexpr Ymm ymm29 = Ymm(29); +static constexpr Ymm ymm30 = Ymm(30); +static constexpr Ymm ymm31 = Ymm(31); + +static constexpr Zmm zmm0 = Zmm(0); +static constexpr Zmm zmm1 = Zmm(1); +static constexpr Zmm zmm2 = Zmm(2); +static constexpr Zmm zmm3 = Zmm(3); +static constexpr Zmm zmm4 = Zmm(4); +static constexpr Zmm zmm5 = Zmm(5); +static constexpr Zmm zmm6 = Zmm(6); +static constexpr Zmm zmm7 = Zmm(7); +static constexpr Zmm zmm8 = Zmm(8); +static constexpr Zmm zmm9 = Zmm(9); +static constexpr Zmm zmm10 = Zmm(10); +static constexpr Zmm zmm11 = Zmm(11); +static constexpr Zmm zmm12 = Zmm(12); +static constexpr Zmm zmm13 = Zmm(13); +static constexpr Zmm zmm14 = Zmm(14); +static constexpr Zmm zmm15 = Zmm(15); +static constexpr Zmm zmm16 = Zmm(16); +static constexpr Zmm zmm17 = Zmm(17); +static constexpr Zmm zmm18 = Zmm(18); +static constexpr Zmm zmm19 = Zmm(19); +static constexpr Zmm zmm20 = Zmm(20); +static constexpr Zmm zmm21 = Zmm(21); +static constexpr Zmm zmm22 = Zmm(22); +static constexpr Zmm zmm23 = Zmm(23); +static constexpr Zmm zmm24 = Zmm(24); +static constexpr Zmm zmm25 = Zmm(25); +static constexpr Zmm zmm26 = Zmm(26); +static constexpr Zmm zmm27 = Zmm(27); +static constexpr Zmm zmm28 = Zmm(28); +static constexpr Zmm zmm29 = Zmm(29); +static constexpr Zmm zmm30 = Zmm(30); +static constexpr Zmm zmm31 = Zmm(31); + +static constexpr Mm mm0 = Mm(0); +static constexpr Mm mm1 = Mm(1); +static constexpr Mm mm2 = Mm(2); +static constexpr Mm mm3 = Mm(3); +static constexpr Mm mm4 = Mm(4); +static constexpr Mm mm5 = Mm(5); +static constexpr Mm mm6 = Mm(6); +static constexpr Mm mm7 = Mm(7); + +static constexpr KReg k0 = KReg(0); +static constexpr KReg k1 = KReg(1); +static constexpr KReg k2 = KReg(2); +static constexpr KReg k3 = KReg(3); +static constexpr KReg k4 = KReg(4); +static constexpr KReg k5 = KReg(5); +static constexpr KReg k6 = KReg(6); +static constexpr KReg k7 = KReg(7); + +static constexpr SReg no_seg = SReg(SReg::kIdNone); +static constexpr SReg es = SReg(SReg::kIdEs); +static constexpr SReg cs = SReg(SReg::kIdCs); +static constexpr SReg ss = SReg(SReg::kIdSs); +static constexpr SReg ds = SReg(SReg::kIdDs); +static constexpr SReg fs = SReg(SReg::kIdFs); +static constexpr SReg gs = SReg(SReg::kIdGs); + +static constexpr CReg cr0 = CReg(0); +static constexpr CReg cr1 = CReg(1); +static constexpr CReg cr2 = CReg(2); +static constexpr CReg cr3 = CReg(3); +static constexpr CReg cr4 = CReg(4); +static constexpr CReg cr5 = CReg(5); +static constexpr CReg cr6 = CReg(6); +static constexpr CReg cr7 = CReg(7); +static constexpr CReg cr8 = CReg(8); +static constexpr CReg cr9 = CReg(9); +static constexpr CReg cr10 = CReg(10); +static constexpr CReg cr11 = CReg(11); +static constexpr CReg cr12 = CReg(12); +static constexpr CReg cr13 = CReg(13); +static constexpr CReg cr14 = CReg(14); +static constexpr CReg cr15 = CReg(15); + +static constexpr DReg dr0 = DReg(0); +static constexpr DReg dr1 = DReg(1); +static constexpr DReg dr2 = DReg(2); +static constexpr DReg dr3 = DReg(3); +static constexpr DReg dr4 = DReg(4); +static constexpr DReg dr5 = DReg(5); +static constexpr DReg dr6 = DReg(6); +static constexpr DReg dr7 = DReg(7); +static constexpr DReg dr8 = DReg(8); +static constexpr DReg dr9 = DReg(9); +static constexpr DReg dr10 = DReg(10); +static constexpr DReg dr11 = DReg(11); +static constexpr DReg dr12 = DReg(12); +static constexpr DReg dr13 = DReg(13); +static constexpr DReg dr14 = DReg(14); +static constexpr DReg dr15 = DReg(15); + +static constexpr St st0 = St(0); +static constexpr St st1 = St(1); +static constexpr St st2 = St(2); +static constexpr St st3 = St(3); +static constexpr St st4 = St(4); +static constexpr St st5 = St(5); +static constexpr St st6 = St(6); +static constexpr St st7 = St(7); + +static constexpr Bnd bnd0 = Bnd(0); +static constexpr Bnd bnd1 = Bnd(1); +static constexpr Bnd bnd2 = Bnd(2); +static constexpr Bnd bnd3 = Bnd(3); + +static constexpr Rip rip = Rip(0); + +#ifndef _DOXYGEN +} // {regs} + +// Make `x86::regs` accessible through `x86` namespace as well. +using namespace regs; +#endif + // ============================================================================ // [asmjit::x86::Mem] // ============================================================================ @@ -552,328 +894,6 @@ public: inline Mem& operator=(const Mem& other) noexcept = default; }; -// ============================================================================ -// [asmjit::x86::OpData] -// ============================================================================ - -struct OpData { - //! Information about all architecture registers. - ArchRegs archRegs; -}; -ASMJIT_VARAPI const OpData opData; - -//! \cond -// ... Reg methods that require `opData`. -inline uint32_t Reg::groupOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regInfo[rType].group(); -} - -inline uint32_t Reg::typeIdOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regTypeToTypeId[rType]; -} - -inline uint32_t Reg::signatureOf(uint32_t rType) noexcept { - ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); - return opData.archRegs.regInfo[rType].signature(); -} -//! \endcond - -// ============================================================================ -// [asmjit::x86::regs] -// ============================================================================ - -namespace regs { - -//! Creates an 8-bit low GPB register operand. -static constexpr GpbLo gpb(uint32_t rId) noexcept { return GpbLo(rId); } -//! Creates an 8-bit low GPB register operand. -static constexpr GpbLo gpb_lo(uint32_t rId) noexcept { return GpbLo(rId); } -//! Creates an 8-bit high GPB register operand. -static constexpr GpbHi gpb_hi(uint32_t rId) noexcept { return GpbHi(rId); } -//! Creates a 16-bit GPW register operand. -static constexpr Gpw gpw(uint32_t rId) noexcept { return Gpw(rId); } -//! Creates a 32-bit GPD register operand. -static constexpr Gpd gpd(uint32_t rId) noexcept { return Gpd(rId); } -//! Creates a 64-bit GPQ register operand (64-bit). -static constexpr Gpq gpq(uint32_t rId) noexcept { return Gpq(rId); } -//! Creates a 128-bit XMM register operand. -static constexpr Xmm xmm(uint32_t rId) noexcept { return Xmm(rId); } -//! Creates a 256-bit YMM register operand. -static constexpr Ymm ymm(uint32_t rId) noexcept { return Ymm(rId); } -//! Creates a 512-bit ZMM register operand. -static constexpr Zmm zmm(uint32_t rId) noexcept { return Zmm(rId); } -//! Creates a 64-bit Mm register operand. -static constexpr Mm mm(uint32_t rId) noexcept { return Mm(rId); } -//! Creates a 64-bit K register operand. -static constexpr KReg k(uint32_t rId) noexcept { return KReg(rId); } -//! Creates a 32-bit or 64-bit control register operand. -static constexpr CReg cr(uint32_t rId) noexcept { return CReg(rId); } -//! Creates a 32-bit or 64-bit debug register operand. -static constexpr DReg dr(uint32_t rId) noexcept { return DReg(rId); } -//! Creates an 80-bit st register operand. -static constexpr St st(uint32_t rId) noexcept { return St(rId); } -//! Creates a 128-bit bound register operand. -static constexpr Bnd bnd(uint32_t rId) noexcept { return Bnd(rId); } - -static constexpr Gp al(GpbLo::kSignature, Gp::kIdAx); -static constexpr Gp bl(GpbLo::kSignature, Gp::kIdBx); -static constexpr Gp cl(GpbLo::kSignature, Gp::kIdCx); -static constexpr Gp dl(GpbLo::kSignature, Gp::kIdDx); -static constexpr Gp spl(GpbLo::kSignature, Gp::kIdSp); -static constexpr Gp bpl(GpbLo::kSignature, Gp::kIdBp); -static constexpr Gp sil(GpbLo::kSignature, Gp::kIdSi); -static constexpr Gp dil(GpbLo::kSignature, Gp::kIdDi); -static constexpr Gp r8b(GpbLo::kSignature, Gp::kIdR8); -static constexpr Gp r9b(GpbLo::kSignature, Gp::kIdR9); -static constexpr Gp r10b(GpbLo::kSignature, Gp::kIdR10); -static constexpr Gp r11b(GpbLo::kSignature, Gp::kIdR11); -static constexpr Gp r12b(GpbLo::kSignature, Gp::kIdR12); -static constexpr Gp r13b(GpbLo::kSignature, Gp::kIdR13); -static constexpr Gp r14b(GpbLo::kSignature, Gp::kIdR14); -static constexpr Gp r15b(GpbLo::kSignature, Gp::kIdR15); - -static constexpr Gp ah(GpbHi::kSignature, Gp::kIdAx); -static constexpr Gp bh(GpbHi::kSignature, Gp::kIdBx); -static constexpr Gp ch(GpbHi::kSignature, Gp::kIdCx); -static constexpr Gp dh(GpbHi::kSignature, Gp::kIdDx); - -static constexpr Gp ax(Gpw::kSignature, Gp::kIdAx); -static constexpr Gp bx(Gpw::kSignature, Gp::kIdBx); -static constexpr Gp cx(Gpw::kSignature, Gp::kIdCx); -static constexpr Gp dx(Gpw::kSignature, Gp::kIdDx); -static constexpr Gp sp(Gpw::kSignature, Gp::kIdSp); -static constexpr Gp bp(Gpw::kSignature, Gp::kIdBp); -static constexpr Gp si(Gpw::kSignature, Gp::kIdSi); -static constexpr Gp di(Gpw::kSignature, Gp::kIdDi); -static constexpr Gp r8w(Gpw::kSignature, Gp::kIdR8); -static constexpr Gp r9w(Gpw::kSignature, Gp::kIdR9); -static constexpr Gp r10w(Gpw::kSignature, Gp::kIdR10); -static constexpr Gp r11w(Gpw::kSignature, Gp::kIdR11); -static constexpr Gp r12w(Gpw::kSignature, Gp::kIdR12); -static constexpr Gp r13w(Gpw::kSignature, Gp::kIdR13); -static constexpr Gp r14w(Gpw::kSignature, Gp::kIdR14); -static constexpr Gp r15w(Gpw::kSignature, Gp::kIdR15); - -static constexpr Gp eax(Gpd::kSignature, Gp::kIdAx); -static constexpr Gp ebx(Gpd::kSignature, Gp::kIdBx); -static constexpr Gp ecx(Gpd::kSignature, Gp::kIdCx); -static constexpr Gp edx(Gpd::kSignature, Gp::kIdDx); -static constexpr Gp esp(Gpd::kSignature, Gp::kIdSp); -static constexpr Gp ebp(Gpd::kSignature, Gp::kIdBp); -static constexpr Gp esi(Gpd::kSignature, Gp::kIdSi); -static constexpr Gp edi(Gpd::kSignature, Gp::kIdDi); -static constexpr Gp r8d(Gpd::kSignature, Gp::kIdR8); -static constexpr Gp r9d(Gpd::kSignature, Gp::kIdR9); -static constexpr Gp r10d(Gpd::kSignature, Gp::kIdR10); -static constexpr Gp r11d(Gpd::kSignature, Gp::kIdR11); -static constexpr Gp r12d(Gpd::kSignature, Gp::kIdR12); -static constexpr Gp r13d(Gpd::kSignature, Gp::kIdR13); -static constexpr Gp r14d(Gpd::kSignature, Gp::kIdR14); -static constexpr Gp r15d(Gpd::kSignature, Gp::kIdR15); - -static constexpr Gp rax(Gpq::kSignature, Gp::kIdAx); -static constexpr Gp rbx(Gpq::kSignature, Gp::kIdBx); -static constexpr Gp rcx(Gpq::kSignature, Gp::kIdCx); -static constexpr Gp rdx(Gpq::kSignature, Gp::kIdDx); -static constexpr Gp rsp(Gpq::kSignature, Gp::kIdSp); -static constexpr Gp rbp(Gpq::kSignature, Gp::kIdBp); -static constexpr Gp rsi(Gpq::kSignature, Gp::kIdSi); -static constexpr Gp rdi(Gpq::kSignature, Gp::kIdDi); -static constexpr Gp r8(Gpq::kSignature, Gp::kIdR8); -static constexpr Gp r9(Gpq::kSignature, Gp::kIdR9); -static constexpr Gp r10(Gpq::kSignature, Gp::kIdR10); -static constexpr Gp r11(Gpq::kSignature, Gp::kIdR11); -static constexpr Gp r12(Gpq::kSignature, Gp::kIdR12); -static constexpr Gp r13(Gpq::kSignature, Gp::kIdR13); -static constexpr Gp r14(Gpq::kSignature, Gp::kIdR14); -static constexpr Gp r15(Gpq::kSignature, Gp::kIdR15); - -static constexpr Xmm xmm0(0); -static constexpr Xmm xmm1(1); -static constexpr Xmm xmm2(2); -static constexpr Xmm xmm3(3); -static constexpr Xmm xmm4(4); -static constexpr Xmm xmm5(5); -static constexpr Xmm xmm6(6); -static constexpr Xmm xmm7(7); -static constexpr Xmm xmm8(8); -static constexpr Xmm xmm9(9); -static constexpr Xmm xmm10(10); -static constexpr Xmm xmm11(11); -static constexpr Xmm xmm12(12); -static constexpr Xmm xmm13(13); -static constexpr Xmm xmm14(14); -static constexpr Xmm xmm15(15); -static constexpr Xmm xmm16(16); -static constexpr Xmm xmm17(17); -static constexpr Xmm xmm18(18); -static constexpr Xmm xmm19(19); -static constexpr Xmm xmm20(20); -static constexpr Xmm xmm21(21); -static constexpr Xmm xmm22(22); -static constexpr Xmm xmm23(23); -static constexpr Xmm xmm24(24); -static constexpr Xmm xmm25(25); -static constexpr Xmm xmm26(26); -static constexpr Xmm xmm27(27); -static constexpr Xmm xmm28(28); -static constexpr Xmm xmm29(29); -static constexpr Xmm xmm30(30); -static constexpr Xmm xmm31(31); - -static constexpr Ymm ymm0(0); -static constexpr Ymm ymm1(1); -static constexpr Ymm ymm2(2); -static constexpr Ymm ymm3(3); -static constexpr Ymm ymm4(4); -static constexpr Ymm ymm5(5); -static constexpr Ymm ymm6(6); -static constexpr Ymm ymm7(7); -static constexpr Ymm ymm8(8); -static constexpr Ymm ymm9(9); -static constexpr Ymm ymm10(10); -static constexpr Ymm ymm11(11); -static constexpr Ymm ymm12(12); -static constexpr Ymm ymm13(13); -static constexpr Ymm ymm14(14); -static constexpr Ymm ymm15(15); -static constexpr Ymm ymm16(16); -static constexpr Ymm ymm17(17); -static constexpr Ymm ymm18(18); -static constexpr Ymm ymm19(19); -static constexpr Ymm ymm20(20); -static constexpr Ymm ymm21(21); -static constexpr Ymm ymm22(22); -static constexpr Ymm ymm23(23); -static constexpr Ymm ymm24(24); -static constexpr Ymm ymm25(25); -static constexpr Ymm ymm26(26); -static constexpr Ymm ymm27(27); -static constexpr Ymm ymm28(28); -static constexpr Ymm ymm29(29); -static constexpr Ymm ymm30(30); -static constexpr Ymm ymm31(31); - -static constexpr Zmm zmm0(0); -static constexpr Zmm zmm1(1); -static constexpr Zmm zmm2(2); -static constexpr Zmm zmm3(3); -static constexpr Zmm zmm4(4); -static constexpr Zmm zmm5(5); -static constexpr Zmm zmm6(6); -static constexpr Zmm zmm7(7); -static constexpr Zmm zmm8(8); -static constexpr Zmm zmm9(9); -static constexpr Zmm zmm10(10); -static constexpr Zmm zmm11(11); -static constexpr Zmm zmm12(12); -static constexpr Zmm zmm13(13); -static constexpr Zmm zmm14(14); -static constexpr Zmm zmm15(15); -static constexpr Zmm zmm16(16); -static constexpr Zmm zmm17(17); -static constexpr Zmm zmm18(18); -static constexpr Zmm zmm19(19); -static constexpr Zmm zmm20(20); -static constexpr Zmm zmm21(21); -static constexpr Zmm zmm22(22); -static constexpr Zmm zmm23(23); -static constexpr Zmm zmm24(24); -static constexpr Zmm zmm25(25); -static constexpr Zmm zmm26(26); -static constexpr Zmm zmm27(27); -static constexpr Zmm zmm28(28); -static constexpr Zmm zmm29(29); -static constexpr Zmm zmm30(30); -static constexpr Zmm zmm31(31); - -static constexpr Mm mm0(0); -static constexpr Mm mm1(1); -static constexpr Mm mm2(2); -static constexpr Mm mm3(3); -static constexpr Mm mm4(4); -static constexpr Mm mm5(5); -static constexpr Mm mm6(6); -static constexpr Mm mm7(7); - -static constexpr KReg k0(0); -static constexpr KReg k1(1); -static constexpr KReg k2(2); -static constexpr KReg k3(3); -static constexpr KReg k4(4); -static constexpr KReg k5(5); -static constexpr KReg k6(6); -static constexpr KReg k7(7); - -static constexpr SReg no_seg(SReg::kIdNone); -static constexpr SReg es(SReg::kIdEs); -static constexpr SReg cs(SReg::kIdCs); -static constexpr SReg ss(SReg::kIdSs); -static constexpr SReg ds(SReg::kIdDs); -static constexpr SReg fs(SReg::kIdFs); -static constexpr SReg gs(SReg::kIdGs); - -static constexpr CReg cr0(0); -static constexpr CReg cr1(1); -static constexpr CReg cr2(2); -static constexpr CReg cr3(3); -static constexpr CReg cr4(4); -static constexpr CReg cr5(5); -static constexpr CReg cr6(6); -static constexpr CReg cr7(7); -static constexpr CReg cr8(8); -static constexpr CReg cr9(9); -static constexpr CReg cr10(10); -static constexpr CReg cr11(11); -static constexpr CReg cr12(12); -static constexpr CReg cr13(13); -static constexpr CReg cr14(14); -static constexpr CReg cr15(15); - -static constexpr DReg dr0(0); -static constexpr DReg dr1(1); -static constexpr DReg dr2(2); -static constexpr DReg dr3(3); -static constexpr DReg dr4(4); -static constexpr DReg dr5(5); -static constexpr DReg dr6(6); -static constexpr DReg dr7(7); -static constexpr DReg dr8(8); -static constexpr DReg dr9(9); -static constexpr DReg dr10(10); -static constexpr DReg dr11(11); -static constexpr DReg dr12(12); -static constexpr DReg dr13(13); -static constexpr DReg dr14(14); -static constexpr DReg dr15(15); - -static constexpr St st0(0); -static constexpr St st1(1); -static constexpr St st2(2); -static constexpr St st3(3); -static constexpr St st4(4); -static constexpr St st5(5); -static constexpr St st6(6); -static constexpr St st7(7); - -static constexpr Bnd bnd0(0); -static constexpr Bnd bnd1(1); -static constexpr Bnd bnd2(2); -static constexpr Bnd bnd3(3); - -static constexpr Rip rip(0); - -} // {regs} - -// Make `x86::regs` accessible through `x86` namespace as well. -using namespace regs; - -// ============================================================================ -// [asmjit::x86::ptr] -// ============================================================================ - //! Creates `[base.reg + offset]` memory operand. static constexpr Mem ptr(const Gp& base, int32_t offset = 0, uint32_t size = 0) noexcept { return Mem(base, offset, size); @@ -944,70 +964,6 @@ static constexpr Mem ptr_rel(uint64_t base, const Vec& index, uint32_t shift = 0 return Mem(base, index, shift, size, BaseMem::kSignatureMemRel); } -#define ASMJIT_MEM_PTR(FUNC, SIZE) \ - /*! Creates `[base + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Gp& base, const Vec& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[base + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Label& base, int32_t offset = 0) noexcept { \ - return Mem(base, offset, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Label& base, const Gp& index, uint32_t shift = 0, int32_t offset = 0) noexcept { \ - return Mem(base, index, shift, offset, SIZE); \ - } \ - /*! Creates `[rip + offset]` memory operand. */ \ - static constexpr Mem FUNC(const Rip& rip_, int32_t offset = 0) noexcept { \ - return Mem(rip_, offset, SIZE); \ - } \ - /*! Creates `[ptr]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base) noexcept { \ - return Mem(base, SIZE); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand. */ \ - static constexpr Mem FUNC(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE); \ - } \ - \ - /*! Creates `[base + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base) noexcept { \ - return Mem(base, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand (absolute). */ \ - static constexpr Mem FUNC##_abs(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemAbs); \ - } \ - \ - /*! Creates `[base + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base) noexcept { \ - return Mem(base, SIZE, BaseMem::kSignatureMemRel); \ - } \ - /*! Creates `[base + (index << shift) + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base, const Gp& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ - } \ - /*! Creates `[base + (vec_index << shift) + offset]` memory operand (relative). */ \ - static constexpr Mem FUNC##_rel(uint64_t base, const Vec& index, uint32_t shift = 0) noexcept { \ - return Mem(base, index, shift, SIZE, BaseMem::kSignatureMemRel); \ - } - // Definition of memory operand constructors that use platform independent naming. ASMJIT_MEM_PTR(ptr_8, 1) ASMJIT_MEM_PTR(ptr_16, 2) @@ -1032,7 +988,33 @@ ASMJIT_MEM_PTR(xmmword_ptr, 16) ASMJIT_MEM_PTR(ymmword_ptr, 32) ASMJIT_MEM_PTR(zmmword_ptr, 64) -#undef ASMJIT_MEM_PTR +// ============================================================================ +// [asmjit::x86::OpData] +// ============================================================================ + +struct OpData { + //! Information about all architecture registers. + ArchRegs archRegs; +}; +ASMJIT_VARAPI const OpData opData; + +//! \cond +// ... Reg methods that require `opData`. +inline uint32_t Reg::groupOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regInfo[rType].group(); +} + +inline uint32_t Reg::typeIdOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regTypeToTypeId[rType]; +} + +inline uint32_t Reg::signatureOf(uint32_t rType) noexcept { + ASMJIT_ASSERT(rType <= BaseReg::kTypeMax); + return opData.archRegs.regInfo[rType].signature(); +} +//! \endcond //! \} @@ -1043,7 +1025,6 @@ ASMJIT_END_SUB_NAMESPACE // ============================================================================ //! \cond INTERNAL - ASMJIT_BEGIN_NAMESPACE ASMJIT_DEFINE_TYPE_ID(x86::Gpb, kIdI8); ASMJIT_DEFINE_TYPE_ID(x86::Gpw, kIdI16); @@ -1054,7 +1035,8 @@ ASMJIT_DEFINE_TYPE_ID(x86::Xmm, kIdI32x4); ASMJIT_DEFINE_TYPE_ID(x86::Ymm, kIdI32x8); ASMJIT_DEFINE_TYPE_ID(x86::Zmm, kIdI32x16); ASMJIT_END_NAMESPACE - //! \endcond +#undef ASMJIT_MEM_PTR + #endif // ASMJIT_X86_X86OPERAND_H_INCLUDED diff --git a/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp b/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp index cd6ebb5d6d5..6cbb0064388 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp +++ b/3rdparty/asmjit/src/asmjit/x86/x86rapass.cpp @@ -91,14 +91,14 @@ static ASMJIT_INLINE uint32_t raMemIndexRwFlags(uint32_t flags) noexcept { class X86RACFGBuilder : public RACFGBuilder<X86RACFGBuilder> { public: - uint32_t _archId; + uint32_t _arch; bool _is64Bit; bool _avxEnabled; inline X86RACFGBuilder(X86RAPass* pass) noexcept : RACFGBuilder<X86RACFGBuilder>(pass), - _archId(pass->cc()->archId()), - _is64Bit(pass->gpSize() == 8), + _arch(pass->cc()->arch()), + _is64Bit(pass->registerSize() == 8), _avxEnabled(pass->_avxEnabled) { } @@ -110,12 +110,13 @@ public: Error onInst(InstNode* inst, uint32_t& controlType, RAInstBuilder& ib) noexcept; - Error onBeforeCall(FuncCallNode* call) noexcept; - Error onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept; + Error onBeforeInvoke(InvokeNode* invokeNode) noexcept; + Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept; - Error moveImmToRegArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept; - Error moveImmToStackArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_) noexcept; - Error moveRegToStackArg(FuncCallNode* call, const FuncValue& arg, const BaseReg& reg) noexcept; + Error moveVecToPtr(InvokeNode* invokeNode, const FuncValue& arg, const Vec& src, BaseReg* out) noexcept; + Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept; + Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept; + Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept; Error onBeforeRet(FuncRetNode* funcRet) noexcept; Error onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept; @@ -132,7 +133,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild if (Inst::isDefinedId(instId)) { uint32_t opCount = inst->opCount(); const Operand* opArray = inst->operands(); - ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_archId, inst->baseInst(), opArray, opCount, rwInfo)); + ASMJIT_PROPAGATE(InstInternal::queryRWInfo(_arch, inst->baseInst(), opArray, opCount, &rwInfo)); const InstDB::InstInfo& instInfo = InstDB::infoById(instId); bool hasGpbHiConstraint = false; @@ -343,10 +344,10 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild if (singleRegOps == opCount) { singleRegCase = instInfo.singleRegCase(); } - else if (opCount == 2 && inst->opType(1).isImm()) { + else if (opCount == 2 && inst->op(1).isImm()) { // Handle some tricks used by X86 asm. - const BaseReg& reg = inst->opType(0).as<BaseReg>(); - const Imm& imm = inst->opType(1).as<Imm>(); + const BaseReg& reg = inst->op(0).as<BaseReg>(); + const Imm& imm = inst->op(1).as<Imm>(); const RAWorkReg* workReg = _pass->workRegById(ib[0]->workId()); uint32_t workRegSize = workReg->info().size(); @@ -355,7 +356,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild case Inst::kIdOr: { // Sets the value of the destination register to -1, previous content unused. if (reg.size() >= 4 || reg.size() >= workRegSize) { - if (imm.i64() == -1 || imm.u64() == raImmMaskFromSize(reg.size())) + if (imm.value() == -1 || imm.valueAs<uint64_t>() == raImmMaskFromSize(reg.size())) singleRegCase = InstDB::kSingleRegWO; } ASMJIT_FALLTHROUGH; @@ -372,7 +373,7 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild case Inst::kIdXor: { // Updates [E|R]FLAGS without changing the content. if (reg.size() != 4 || reg.size() >= workRegSize) { - if (imm.u64() == 0) + if (imm.value() == 0) singleRegCase = InstDB::kSingleRegRO; } break; @@ -402,20 +403,23 @@ Error X86RACFGBuilder::onInst(InstNode* inst, uint32_t& controlType, RAInstBuild // [asmjit::x86::X86RACFGBuilder - OnCall] // ============================================================================ -Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { - uint32_t argCount = call->argCount(); - uint32_t retCount = call->retCount(); - const FuncDetail& fd = call->detail(); +Error X86RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept { + uint32_t argCount = invokeNode->argCount(); + uint32_t retCount = invokeNode->retCount(); + const FuncDetail& fd = invokeNode->detail(); - cc()->_setCursor(call->prev()); + cc()->_setCursor(invokeNode->prev()); - for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { - for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { - if (!fd.hasArg(argIndex + argHi)) + uint32_t nativeRegType = cc()->_gpRegInfo.type(); + + for (uint32_t loIndex = 0; loIndex < argCount; loIndex++) { + for (uint32_t hiIndex = 0; hiIndex <= kFuncArgHi; hiIndex += kFuncArgHi) { + uint32_t argIndex = loIndex + hiIndex; + if (!fd.hasArg(argIndex)) continue; - const FuncValue& arg = fd.arg(argIndex + argHi); - const Operand& op = call->arg(argIndex + argHi); + const FuncValue& arg = fd.arg(argIndex); + const Operand& op = invokeNode->arg(argIndex); if (op.isNone()) continue; @@ -429,35 +433,64 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { uint32_t regGroup = workReg->group(); uint32_t argGroup = Reg::groupOf(arg.regType()); - if (regGroup != argGroup) { - // TODO: - ASMJIT_ASSERT(false); + if (arg.isIndirect()) { + if (reg.isGp()) { + if (reg.type() != nativeRegType) + return DebugUtils::errored(kErrorInvalidAssignment); + // It's considered allocated if this is an indirect argument and the user used GP. + continue; + } + + BaseReg indirectReg; + moveVecToPtr(invokeNode, arg, reg.as<Vec>(), &indirectReg); + invokeNode->_args[argIndex] = indirectReg; + } + else { + if (regGroup != argGroup) { + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); + } } } else { - ASMJIT_PROPAGATE(moveRegToStackArg(call, arg, op.as<BaseReg>())); + if (arg.isIndirect()) { + if (reg.isGp()) { + if (reg.type() != nativeRegType) + return DebugUtils::errored(kErrorInvalidAssignment); + + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg)); + continue; + } + + BaseReg indirectReg; + moveVecToPtr(invokeNode, arg, reg.as<Vec>(), &indirectReg); + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, indirectReg)); + } + else { + ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg)); + } } } else if (op.isImm()) { if (arg.isReg()) { BaseReg reg; - ASMJIT_PROPAGATE(moveImmToRegArg(call, arg, op.as<Imm>(), ®)); - call->_args[argIndex + argHi] = reg; + ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), ®)); + invokeNode->_args[argIndex] = reg; } else { - ASMJIT_PROPAGATE(moveImmToStackArg(call, arg, op.as<Imm>())); + ASMJIT_PROPAGATE(moveImmToStackArg(invokeNode, arg, op.as<Imm>())); } } } } - cc()->_setCursor(call); + cc()->_setCursor(invokeNode); if (fd.hasFlag(CallConv::kFlagCalleePopsStack)) ASMJIT_PROPAGATE(cc()->sub(cc()->zsp(), fd.argStackSize())); for (uint32_t retIndex = 0; retIndex < retCount; retIndex++) { const FuncValue& ret = fd.ret(retIndex); - const Operand& op = call->ret(retIndex); + const Operand& op = invokeNode->ret(retIndex); if (op.isReg()) { const Reg& reg = op.as<Reg>(); @@ -500,15 +533,15 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { uint32_t retGroup = Reg::groupOf(ret.regType()); if (regGroup != retGroup) { - // TODO: - ASMJIT_ASSERT(false); + // TODO: Conversion is not supported. + return DebugUtils::errored(kErrorInvalidAssignment); } } } } } - // This block has function call(s). + // This block has function invokeNode(s). _curBlock->addFlags(RABlock::kFlagHasFuncCalls); _pass->func()->frame().addAttributes(FuncFrame::kAttrHasFuncCalls); _pass->func()->frame().updateCallStackSize(fd.argStackSize()); @@ -516,10 +549,10 @@ Error X86RACFGBuilder::onBeforeCall(FuncCallNode* call) noexcept { return kErrorOk; } -Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { - uint32_t argCount = call->argCount(); - uint32_t retCount = call->retCount(); - const FuncDetail& fd = call->detail(); +Error X86RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept { + uint32_t argCount = invokeNode->argCount(); + uint32_t retCount = invokeNode->retCount(); + const FuncDetail& fd = invokeNode->detail(); for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { @@ -527,7 +560,7 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { continue; const FuncValue& arg = fd.arg(argIndex + argHi); - const Operand& op = call->arg(argIndex + argHi); + const Operand& op = invokeNode->arg(argIndex + argHi); if (op.isNone()) continue; @@ -537,7 +570,13 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { RAWorkReg* workReg; ASMJIT_PROPAGATE(_pass->virtIndexAsWorkReg(Operand::virtIdToIndex(reg.id()), &workReg)); - if (arg.isReg()) { + if (arg.isIndirect()) { + uint32_t regGroup = workReg->group(); + if (regGroup != BaseReg::kGroupGp) + return DebugUtils::errored(kErrorInvalidState); + ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId())); + } + else if (arg.isReg()) { uint32_t regGroup = workReg->group(); uint32_t argGroup = Reg::groupOf(arg.regType()); @@ -551,7 +590,7 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { for (uint32_t retIndex = 0; retIndex < retCount; retIndex++) { const FuncValue& ret = fd.ret(retIndex); - const Operand& op = call->ret(retIndex); + const Operand& op = invokeNode->ret(retIndex); // Not handled here... if (ret.regType() == Reg::kTypeSt) @@ -586,11 +625,62 @@ Error X86RACFGBuilder::onCall(FuncCallNode* call, RAInstBuilder& ib) noexcept { } // ============================================================================ +// [asmjit::x86::X86RACFGBuilder - MoveVecToPtr] +// ============================================================================ + +static uint32_t x86VecRegSignatureBySize(uint32_t size) noexcept { + if (size >= 64) + return Zmm::kSignature; + else if (size >= 32) + return Ymm::kSignature; + else + return Xmm::kSignature; +} + +Error X86RACFGBuilder::moveVecToPtr(InvokeNode* invokeNode, const FuncValue& arg, const Vec& src, BaseReg* out) noexcept { + DebugUtils::unused(invokeNode); + ASMJIT_ASSERT(arg.isReg()); + + uint32_t argSize = Type::sizeOf(arg.typeId()); + if (argSize == 0) + return DebugUtils::errored(kErrorInvalidState); + + if (argSize < 16) + argSize = 16; + + uint32_t argStackOffset = Support::alignUp(invokeNode->detail()._argStackSize, argSize); + _funcNode->frame().updateCallStackAlignment(argSize); + invokeNode->detail()._argStackSize = argStackOffset + argSize; + + Vec vecReg(x86VecRegSignatureBySize(argSize), src.id()); + Mem vecPtr = ptr(_pass->_sp.as<Gp>(), int32_t(argStackOffset)); + + uint32_t vMovInstId = choose(Inst::kIdMovaps, Inst::kIdVmovaps); + if (argSize > 16) + vMovInstId = Inst::kIdVmovaps; + + ASMJIT_PROPAGATE(cc()->_newReg(out, cc()->_gpRegInfo.type(), nullptr)); + + VirtReg* vReg = cc()->virtRegById(out->id()); + vReg->setWeight(RAPass::kCallArgWeight); + + ASMJIT_PROPAGATE(cc()->lea(out->as<Gp>(), vecPtr)); + ASMJIT_PROPAGATE(cc()->emit(vMovInstId, ptr(out->as<Gp>()), vecReg)); + + if (arg.isStack()) { + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + ASMJIT_PROPAGATE(cc()->mov(stackPtr, out->as<Gp>())); + } + + return kErrorOk; +} + +// ============================================================================ // [asmjit::x86::X86RACFGBuilder - MoveImmToRegArg] // ============================================================================ -Error X86RACFGBuilder::moveImmToRegArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isReg()); Imm imm(imm_); @@ -620,10 +710,10 @@ MovU32: break; default: - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); } - ASMJIT_PROPAGATE(cc()->_newReg(*out, rTypeId, nullptr)); + ASMJIT_PROPAGATE(cc()->_newReg(out, rTypeId, nullptr)); cc()->virtRegById(out->id())->setWeight(RAPass::kCallArgWeight); return cc()->mov(out->as<x86::Gp>(), imm); @@ -633,14 +723,14 @@ MovU32: // [asmjit::x86::X86RACFGBuilder - MoveImmToStackArg] // ============================================================================ -Error X86RACFGBuilder::moveImmToStackArg(FuncCallNode* call, const FuncValue& arg, const Imm& imm_) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isStack()); - Mem mem = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); Imm imm[2]; - mem.setSize(4); + stackPtr.setSize(4); imm[0] = imm_; uint32_t nMovs = 0; @@ -669,23 +759,23 @@ MovU32: case Type::kIdMmx32: case Type::kIdMmx64: if (_is64Bit && imm[0].isInt32()) { - mem.setSize(8); + stackPtr.setSize(8); nMovs = 1; break; } - imm[1].setU32(imm[0].u32Hi()); + imm[1].setValue(imm[0].uint32Hi()); imm[0].zeroExtend32Bits(); nMovs = 2; break; default: - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); } for (uint32_t i = 0; i < nMovs; i++) { - ASMJIT_PROPAGATE(cc()->mov(mem, imm[i])); - mem.addOffsetLo32(int32_t(mem.size())); + ASMJIT_PROPAGATE(cc()->mov(stackPtr, imm[i])); + stackPtr.addOffsetLo32(int32_t(stackPtr.size())); } return kErrorOk; @@ -695,15 +785,15 @@ MovU32: // [asmjit::x86::X86RACFGBuilder - MoveRegToStackArg] // ============================================================================ -Error X86RACFGBuilder::moveRegToStackArg(FuncCallNode* call, const FuncValue& arg, const BaseReg& reg) noexcept { - DebugUtils::unused(call); +Error X86RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept { + DebugUtils::unused(invokeNode); ASMJIT_ASSERT(arg.isStack()); - Mem mem = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); + Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset()); Reg r0, r1; VirtReg* vr = cc()->virtRegById(reg.id()); - uint32_t gpSize = cc()->gpSize(); + uint32_t registerSize = cc()->registerSize(); uint32_t instId = 0; uint32_t dstTypeId = arg.typeId(); @@ -812,75 +902,89 @@ Error X86RACFGBuilder::moveRegToStackArg(FuncCallNode* call, const FuncValue& ar break; default: - // TODO: Vector types by stack. + if (Type::isVec(dstTypeId) && reg.as<Reg>().isVec()) { + stackPtr.setSize(Type::sizeOf(dstTypeId)); + uint32_t vMovInstId = choose(Inst::kIdMovaps, Inst::kIdVmovaps); + + if (Type::isVec128(dstTypeId)) + r0.setRegT<Reg::kTypeXmm>(reg.id()); + else if (Type::isVec256(dstTypeId)) + r0.setRegT<Reg::kTypeYmm>(reg.id()); + else if (Type::isVec512(dstTypeId)) + r0.setRegT<Reg::kTypeZmm>(reg.id()); + else + break; + + return cc()->emit(vMovInstId, stackPtr, r0); + } break; } - return DebugUtils::errored(kErrorInvalidState); + return DebugUtils::errored(kErrorInvalidAssignment); // Extend+Move Gp. ExtendMovGpD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); return kErrorOk; ExtendMovGpXQ: - if (gpSize == 8) { - mem.setSize(8); + if (registerSize == 8) { + stackPtr.setSize(8); r0.setRegT<Reg::kTypeGpq>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); } else { - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); ASMJIT_PROPAGATE(cc()->emit(instId, r0, r1)); ExtendMovGpDQ: - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, mem, r0)); - mem.addOffsetLo32(4); - ASMJIT_PROPAGATE(cc()->emit(Inst::kIdAnd, mem, 0)); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdMov, stackPtr, r0)); + stackPtr.addOffsetLo32(4); + ASMJIT_PROPAGATE(cc()->emit(Inst::kIdAnd, stackPtr, 0)); } return kErrorOk; ZeroExtendGpDQ: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); goto ExtendMovGpDQ; MovGpD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeGpd>(reg.id()); - return cc()->emit(Inst::kIdMov, mem, r0); + return cc()->emit(Inst::kIdMov, stackPtr, r0); MovGpQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeGpq>(reg.id()); - return cc()->emit(Inst::kIdMov, mem, r0); + return cc()->emit(Inst::kIdMov, stackPtr, r0); MovMmD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeMm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovd, Inst::kIdVmovd), mem, r0); + return cc()->emit(choose(Inst::kIdMovd, Inst::kIdVmovd), stackPtr, r0); MovMmQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeMm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovq, Inst::kIdVmovq), mem, r0); + return cc()->emit(choose(Inst::kIdMovq, Inst::kIdVmovq), stackPtr, r0); MovXmmD: - mem.setSize(4); + stackPtr.setSize(4); r0.setRegT<Reg::kTypeXmm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovss, Inst::kIdVmovss), mem, r0); + return cc()->emit(choose(Inst::kIdMovss, Inst::kIdVmovss), stackPtr, r0); MovXmmQ: - mem.setSize(8); + stackPtr.setSize(8); r0.setRegT<Reg::kTypeXmm>(reg.id()); - return cc()->emit(choose(Inst::kIdMovlps, Inst::kIdVmovlps), mem, r0); + return cc()->emit(choose(Inst::kIdMovlps, Inst::kIdVmovlps), stackPtr, r0); } // ============================================================================ @@ -997,8 +1101,8 @@ X86RAPass::~X86RAPass() noexcept {} // ============================================================================ void X86RAPass::onInit() noexcept { - uint32_t archId = cc()->archId(); - uint32_t baseRegCount = archId == ArchInfo::kIdX86 ? 8u : 16u; + uint32_t arch = cc()->arch(); + uint32_t baseRegCount = Environment::is32Bit(arch) ? 8u : 16u; _archRegsInfo = &opData.archRegs; _archTraits[Reg::kGroupGp] |= RAArchTraits::kHasSwap; @@ -1117,13 +1221,13 @@ Error X86RAPass::onEmitJump(const Label& label) noexcept { return cc()->jmp(label); } -Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { - if (call->detail().hasVarArgs()) { - uint32_t argCount = call->argCount(); - const FuncDetail& fd = call->detail(); +Error X86RAPass::onEmitPreCall(InvokeNode* invokeNode) noexcept { + if (invokeNode->detail().hasVarArgs() && cc()->is64Bit()) { + uint32_t argCount = invokeNode->argCount(); + const FuncDetail& fd = invokeNode->detail(); - switch (call->detail().callConv().id()) { - case CallConv::kIdX86SysV64: { + switch (invokeNode->detail().callConv().id()) { + case CallConv::kIdX64SystemV: { // AL register contains the number of arguments passed in XMM register(s). uint32_t n = 0; for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { @@ -1144,7 +1248,7 @@ Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { break; } - case CallConv::kIdX86Win64: { + case CallConv::kIdX64Windows: { // Each double-precision argument passed in XMM must be also passed in GP. for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) { for (uint32_t argHi = 0; argHi <= kFuncArgHi; argHi += kFuncArgHi) { @@ -1161,6 +1265,9 @@ Error X86RAPass::onEmitPreCall(FuncCallNode* call) noexcept { } break; } + + default: + return DebugUtils::errored(kErrorInvalidState); } } diff --git a/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h b/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h index 4fa688b41a3..99093ab69f8 100644 --- a/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h +++ b/3rdparty/asmjit/src/asmjit/x86/x86rapass_p.h @@ -37,12 +37,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! \cond INTERNAL -//! \defgroup asmjit_x86_ra X86 RA -//! \ingroup asmjit_x86 -//! //! \brief X86/X64 register allocation. -//! \addtogroup asmjit_x86_ra +//! \addtogroup asmjit_ra //! \{ // ============================================================================ @@ -106,7 +103,7 @@ public: Error onEmitSave(uint32_t workId, uint32_t srcPhysId) noexcept override; Error onEmitJump(const Label& label) noexcept override; - Error onEmitPreCall(FuncCallNode* node) noexcept override; + Error onEmitPreCall(InvokeNode* invokeNode) noexcept override; }; //! \} diff --git a/3rdparty/asmjit/test/asmjit_bench_x86.cpp b/3rdparty/asmjit/test/asmjit_bench_x86.cpp index 95f792d0c03..40d90088c01 100644 --- a/3rdparty/asmjit/test/asmjit_bench_x86.cpp +++ b/3rdparty/asmjit/test/asmjit_bench_x86.cpp @@ -37,7 +37,7 @@ using namespace asmjit; // [Configuration] // ============================================================================ -static constexpr uint32_t kNumRepeats = 25; +static constexpr uint32_t kNumRepeats = 20; static constexpr uint32_t kNumIterations = 1000; // ============================================================================ @@ -80,12 +80,12 @@ namespace BenchUtils { } template<typename EmitterT, typename FuncT> - static void bench(CodeHolder& code, uint32_t archId, const char* testName, const FuncT& func) noexcept { + static void bench(CodeHolder& code, uint32_t arch, const char* testName, const FuncT& func) noexcept { EmitterT emitter; const char* archName = - archId == ArchInfo::kIdX86 ? "X86" : - archId == ArchInfo::kIdX64 ? "X64" : "???"; + arch == Environment::kArchX86 ? "X86" : + arch == Environment::kArchX64 ? "X64" : "???"; const char* emitterName = emitter.isAssembler() ? "Assembler" : @@ -95,14 +95,13 @@ namespace BenchUtils { Performance perf; uint64_t codeSize = 0; - CodeInfo codeInfo(archId); - codeInfo.setCdeclCallConv(archId == ArchInfo::kIdX86 ? CallConv::kIdX86CDecl : CallConv::kIdX86SysV64); + Environment env(arch); for (uint32_t r = 0; r < kNumRepeats; r++) { perf.start(); codeSize = 0; for (uint32_t i = 0; i < kNumIterations; i++) { - code.init(codeInfo); + code.init(env); code.attach(&emitter); func(emitter); @@ -113,7 +112,7 @@ namespace BenchUtils { perf.end(); } - printf("[%s] %-9s %-8s | Time:%6u [ms] | ", archName, emitterName, testName, perf.best); + printf("[%s] %-9s %-10s | Time:%6u [ms] | ", archName, emitterName, testName, perf.best); if (codeSize) printf("Speed: %7.3f [MB/s]", mbps(perf.best, codeSize)); else @@ -127,30 +126,35 @@ namespace BenchUtils { // ============================================================================ #ifdef ASMJIT_BUILD_X86 -static void benchX86(uint32_t archId) noexcept { +static void benchX86(uint32_t arch) noexcept { CodeHolder code; - BenchUtils::bench<x86::Assembler>(code, archId, "[raw]", [](x86::Assembler& a) { + BenchUtils::bench<x86::Assembler>(code, arch, "[fast]", [](x86::Assembler& a) { + asmtest::generateOpcodes(a.as<x86::Emitter>()); + }); + + BenchUtils::bench<x86::Assembler>(code, arch, "[validate]", [](x86::Assembler& a) { + a.addValidationOptions(BaseEmitter::kValidationOptionAssembler); asmtest::generateOpcodes(a.as<x86::Emitter>()); }); #ifndef ASMJIT_NO_BUILDER - BenchUtils::bench<x86::Builder>(code, archId, "[raw]", [](x86::Builder& cb) { + BenchUtils::bench<x86::Builder>(code, arch, "[no-asm]", [](x86::Builder& cb) { asmtest::generateOpcodes(cb.as<x86::Emitter>()); }); - BenchUtils::bench<x86::Builder>(code, archId, "[final]", [](x86::Builder& cb) { + BenchUtils::bench<x86::Builder>(code, arch, "[asm]", [](x86::Builder& cb) { asmtest::generateOpcodes(cb.as<x86::Emitter>()); cb.finalize(); }); #endif #ifndef ASMJIT_NO_COMPILER - BenchUtils::bench<x86::Compiler>(code, archId, "[raw]", [](x86::Compiler& cc) { + BenchUtils::bench<x86::Compiler>(code, arch, "[no-asm]", [](x86::Compiler& cc) { asmtest::generateAlphaBlend(cc); }); - BenchUtils::bench<x86::Compiler>(code, archId, "[final]", [](x86::Compiler& cc) { + BenchUtils::bench<x86::Compiler>(code, arch, "[asm]", [](x86::Compiler& cc) { asmtest::generateAlphaBlend(cc); cc.finalize(); }); @@ -160,8 +164,8 @@ static void benchX86(uint32_t archId) noexcept { int main() { #ifdef ASMJIT_BUILD_X86 - benchX86(ArchInfo::kIdX86); - benchX86(ArchInfo::kIdX64); + benchX86(Environment::kArchX86); + benchX86(Environment::kArchX64); #endif return 0; diff --git a/3rdparty/asmjit/test/asmjit_test_misc.h b/3rdparty/asmjit/test/asmjit_test_misc.h index be1757ab1c9..03273272d1b 100644 --- a/3rdparty/asmjit/test/asmjit_test_misc.h +++ b/3rdparty/asmjit/test/asmjit_test_misc.h @@ -52,7 +52,7 @@ static void generateAlphaBlend(asmjit::x86::Compiler& cc) { Label L_LargeEnd = cc.newLabel(); Label L_DataPool = cc.newLabel(); - cc.addFunc(FuncSignatureT<void, void*, const void*, size_t>(cc.codeInfo().cdeclCallConv())); + cc.addFunc(FuncSignatureT<void, void*, const void*, size_t>(CallConv::kIdHost)); cc.setArg(0, dst); cc.setArg(1, src); @@ -177,8 +177,8 @@ static void generateAlphaBlend(asmjit::x86::Compiler& cc) { // Data. cc.align(kAlignData, 16); cc.bind(L_DataPool); - cc.dxmm(Data128::fromI16(0x0080)); - cc.dxmm(Data128::fromI16(0x0101)); + cc.embedUInt16(uint16_t(0x0080u), 8); + cc.embedUInt16(uint16_t(0x0101u), 8); } } // {asmtest} diff --git a/3rdparty/asmjit/test/asmjit_test_opcode.cpp b/3rdparty/asmjit/test/asmjit_test_opcode.cpp index 908435beb00..d61a6e4bc29 100644 --- a/3rdparty/asmjit/test/asmjit_test_opcode.cpp +++ b/3rdparty/asmjit/test/asmjit_test_opcode.cpp @@ -21,9 +21,11 @@ // misrepresented as being the original software. // 3. This notice may not be removed or altered from any source distribution. +// ---------------------------------------------------------------------------- // This file is used to test opcodes generated by AsmJit. Output can be // disassembled in your IDE or by your favorite disassembler. Instructions // are grouped by category and then sorted alphabetically. +// ---------------------------------------------------------------------------- #include <asmjit/x86.h> #include <stdio.h> @@ -34,21 +36,21 @@ using namespace asmjit; struct OpcodeDumpInfo { - uint32_t archId; + uint32_t arch; bool useRex1; bool useRex2; }; -static const char* archIdToString(uint32_t archId) { - switch (archId) { - case ArchInfo::kIdNone: return "None"; - case ArchInfo::kIdX86 : return "X86"; - case ArchInfo::kIdX64 : return "X64"; - case ArchInfo::kIdA32 : return "A32"; - case ArchInfo::kIdA64 : return "A64"; - - default: - return "<unknown>"; +static const char* archToString(uint32_t arch) noexcept { + switch (arch & ~Environment::kArchBigEndianMask) { + case Environment::kArchX86 : return "X86"; + case Environment::kArchX64 : return "X64"; + case Environment::kArchARM : return "ARM"; + case Environment::kArchThumb : return "Thumb"; + case Environment::kArchAArch64 : return "AArch64"; + case Environment::kArchMIPS_LE : return "MIPS"; + case Environment::kArchMIPS64_LE: return "MIPS64"; + default: return "Unknown"; } } @@ -65,23 +67,23 @@ int main() { TestErrorHandler eh; OpcodeDumpInfo infoList[] = { - { ArchInfo::kIdX86, false, false }, - { ArchInfo::kIdX64, false, false }, - { ArchInfo::kIdX64, false, true }, - { ArchInfo::kIdX64, true , false }, - { ArchInfo::kIdX64, true , true } + { Environment::kArchX86, false, false }, + { Environment::kArchX64, false, false }, + { Environment::kArchX64, false, true }, + { Environment::kArchX64, true , false }, + { Environment::kArchX64, true , true } }; for (uint32_t i = 0; i < ASMJIT_ARRAY_SIZE(infoList); i++) { const OpcodeDumpInfo& info = infoList[i]; printf("Opcodes [ARCH=%s REX1=%s REX2=%s]\n", - archIdToString(info.archId), + archToString(info.arch), info.useRex1 ? "true" : "false", info.useRex2 ? "true" : "false"); CodeHolder code; - code.init(CodeInfo(info.archId)); + code.init(Environment(info.arch)); code.setErrorHandler(&eh); #ifndef ASMJIT_NO_LOGGING @@ -95,7 +97,7 @@ int main() { // If this is the host architecture the code generated can be executed // for debugging purposes (the first instruction is ret anyway). - if (code.archId() == ArchInfo::kIdHost) { + if (code.arch() == Environment::kArchHost) { JitRuntime runtime; VoidFunc p; diff --git a/3rdparty/asmjit/test/asmjit_test_opcode.h b/3rdparty/asmjit/test/asmjit_test_opcode.h index e89db426ffd..6f052f526b8 100644 --- a/3rdparty/asmjit/test/asmjit_test_opcode.h +++ b/3rdparty/asmjit/test/asmjit_test_opcode.h @@ -91,7 +91,6 @@ static void generateOpcodes(asmjit::x86::Emitter* e, bool useRex1 = false, bool Zmm zmmA = useRex1 ? zmm8 : zmm0; Zmm zmmB = useRex2 ? zmm9 : zmm1; Zmm zmmC = useRex2 ? zmm10 : zmm2; - Zmm zmmD = useRex2 ? zmm11 : zmm3; Mem vx_ptr = ptr(gzB, xmmB); Mem vy_ptr = ptr(gzB, ymmB); diff --git a/3rdparty/asmjit/test/asmjit_test_unit.cpp b/3rdparty/asmjit/test/asmjit_test_unit.cpp index f88018a7ac1..3aac7401e17 100644 --- a/3rdparty/asmjit/test/asmjit_test_unit.cpp +++ b/3rdparty/asmjit/test/asmjit_test_unit.cpp @@ -35,25 +35,26 @@ struct DumpCpuFeature { const char* name; }; -static const char* hostArch() noexcept { - switch (ArchInfo::kIdHost) { - case ArchInfo::kIdX86: return "X86"; - case ArchInfo::kIdX64: return "X64"; - case ArchInfo::kIdA32: return "ARM32"; - case ArchInfo::kIdA64: return "ARM64"; +static const char* archToString(uint32_t arch) noexcept { + switch (arch & ~Environment::kArchBigEndianMask) { + case Environment::kArchX86 : return "X86"; + case Environment::kArchX64 : return "X64"; + case Environment::kArchARM : return "ARM"; + case Environment::kArchThumb : return "Thumb"; + case Environment::kArchAArch64 : return "AArch64"; + case Environment::kArchMIPS_LE : return "MIPS"; + case Environment::kArchMIPS64_LE: return "MIPS64"; default: return "Unknown"; } } -static void dumpFeatures(const CpuInfo& cpu, const DumpCpuFeature* data, size_t count) noexcept { - for (size_t i = 0; i < count; i++) - if (cpu.hasFeature(data[i].feature)) - INFO(" %s", data[i].name); -} - static void dumpCpu(void) noexcept { const CpuInfo& cpu = CpuInfo::host(); + // -------------------------------------------------------------------------- + // [CPU Information] + // -------------------------------------------------------------------------- + INFO("Host CPU:"); INFO(" Vendor : %s", cpu.vendor()); INFO(" Brand : %s", cpu.brand()); @@ -68,137 +69,20 @@ static void dumpCpu(void) noexcept { INFO(""); // -------------------------------------------------------------------------- - // [X86] + // [CPU Features] // -------------------------------------------------------------------------- -#if ASMJIT_ARCH_X86 - static const DumpCpuFeature x86FeaturesList[] = { - { x86::Features::kNX , "NX" }, - { x86::Features::kMT , "MT" }, - { x86::Features::k3DNOW , "3DNOW" }, - { x86::Features::k3DNOW2 , "3DNOW2" }, - { x86::Features::kADX , "ADX" }, - { x86::Features::kAESNI , "AESNI" }, - { x86::Features::kALTMOVCR8 , "ALTMOVCR8" }, - { x86::Features::kAVX , "AVX" }, - { x86::Features::kAVX2 , "AVX2" }, - { x86::Features::kAVX512_4FMAPS , "AVX512_4FMAPS" }, - { x86::Features::kAVX512_4VNNIW , "AVX512_4VNNIW" }, - { x86::Features::kAVX512_BITALG , "AVX512_BITALG" }, - { x86::Features::kAVX512_BW , "AVX512_BW" }, - { x86::Features::kAVX512_CDI , "AVX512_CDI" }, - { x86::Features::kAVX512_DQ , "AVX512_DQ" }, - { x86::Features::kAVX512_ERI , "AVX512_ERI" }, - { x86::Features::kAVX512_F , "AVX512_F" }, - { x86::Features::kAVX512_IFMA , "AVX512_IFMA" }, - { x86::Features::kAVX512_PFI , "AVX512_PFI" }, - { x86::Features::kAVX512_VBMI , "AVX512_VBMI" }, - { x86::Features::kAVX512_VBMI2 , "AVX512_VBMI2" }, - { x86::Features::kAVX512_VL , "AVX512_VL" }, - { x86::Features::kAVX512_VNNI , "AVX512_VNNI" }, - { x86::Features::kAVX512_VPOPCNTDQ, "AVX512_VPOPCNTDQ" }, - { x86::Features::kBMI , "BMI" }, - { x86::Features::kBMI2 , "BMI2" }, - { x86::Features::kCLFLUSH , "CLFLUSH" }, - { x86::Features::kCLFLUSHOPT , "CLFLUSHOPT" }, - { x86::Features::kCLWB , "CLWB" }, - { x86::Features::kCLZERO , "CLZERO" }, - { x86::Features::kCMOV , "CMOV" }, - { x86::Features::kCMPXCHG16B , "CMPXCHG16B" }, - { x86::Features::kCMPXCHG8B , "CMPXCHG8B" }, - { x86::Features::kERMS , "ERMS" }, - { x86::Features::kF16C , "F16C" }, - { x86::Features::kFMA , "FMA" }, - { x86::Features::kFMA4 , "FMA4" }, - { x86::Features::kFPU , "FPU" }, - { x86::Features::kFSGSBASE , "FSGSBASE" }, - { x86::Features::kFXSR , "FXSR" }, - { x86::Features::kFXSROPT , "FXSROPT" }, - { x86::Features::kGEODE , "GEODE" }, - { x86::Features::kGFNI , "GFNI" }, - { x86::Features::kHLE , "HLE" }, - { x86::Features::kI486 , "I486" }, - { x86::Features::kLAHFSAHF , "LAHFSAHF" }, - { x86::Features::kLWP , "LWP" }, - { x86::Features::kLZCNT , "LZCNT" }, - { x86::Features::kMMX , "MMX" }, - { x86::Features::kMMX2 , "MMX2" }, - { x86::Features::kMONITOR , "MONITOR" }, - { x86::Features::kMONITORX , "MONITORX" }, - { x86::Features::kMOVBE , "MOVBE" }, - { x86::Features::kMPX , "MPX" }, - { x86::Features::kMSR , "MSR" }, - { x86::Features::kMSSE , "MSSE" }, - { x86::Features::kOSXSAVE , "OSXSAVE" }, - { x86::Features::kPCLMULQDQ , "PCLMULQDQ" }, - { x86::Features::kPCOMMIT , "PCOMMIT" }, - { x86::Features::kPOPCNT , "POPCNT" }, - { x86::Features::kPREFETCHW , "PREFETCHW" }, - { x86::Features::kPREFETCHWT1 , "PREFETCHWT1" }, - { x86::Features::kRDRAND , "RDRAND" }, - { x86::Features::kRDSEED , "RDSEED" }, - { x86::Features::kRDTSC , "RDTSC" }, - { x86::Features::kRDTSCP , "RDTSCP" }, - { x86::Features::kRTM , "RTM" }, - { x86::Features::kSHA , "SHA" }, - { x86::Features::kSKINIT , "SKINIT" }, - { x86::Features::kSMAP , "SMAP" }, - { x86::Features::kSMEP , "SMEP" }, - { x86::Features::kSMX , "SMX" }, - { x86::Features::kSSE , "SSE" }, - { x86::Features::kSSE2 , "SSE2" }, - { x86::Features::kSSE3 , "SSE3" }, - { x86::Features::kSSE4_1 , "SSE4.1" }, - { x86::Features::kSSE4_2 , "SSE4.2" }, - { x86::Features::kSSE4A , "SSE4A" }, - { x86::Features::kSSSE3 , "SSSE3" }, - { x86::Features::kSVM , "SVM" }, - { x86::Features::kTBM , "TBM" }, - { x86::Features::kTSX , "TSX" }, - { x86::Features::kVAES , "VAES" }, - { x86::Features::kVMX , "VMX" }, - { x86::Features::kVPCLMULQDQ , "VPCLMULQDQ" }, - { x86::Features::kXOP , "XOP" }, - { x86::Features::kXSAVE , "XSAVE" }, - { x86::Features::kXSAVEC , "XSAVEC" }, - { x86::Features::kXSAVEOPT , "XSAVEOPT" }, - { x86::Features::kXSAVES , "XSAVES" } +#ifndef ASMJIT_NO_LOGGING + INFO("CPU Features:"); + BaseFeatures::Iterator it(cpu.features().iterator()); + while (it.hasNext()) { + uint32_t featureId = uint32_t(it.next()); + StringTmp<64> featureString; + Formatter::formatFeature(featureString, cpu.arch(), featureId); + INFO(" %s\n", featureString.data()); }; - - INFO("X86 Features:"); - dumpFeatures(cpu, x86FeaturesList, ASMJIT_ARRAY_SIZE(x86FeaturesList)); INFO(""); -#endif - - // -------------------------------------------------------------------------- - // [ARM] - // -------------------------------------------------------------------------- - -#if ASMJIT_ARCH_ARM - static const DumpCpuFeature armFeaturesList[] = { - { arm::Features::kARMv6 , "ARMv6" }, - { arm::Features::kARMv7 , "ARMv7" }, - { arm::Features::kARMv8 , "ARMv8" }, - { arm::Features::kTHUMB , "THUMB" }, - { arm::Features::kTHUMBv2 , "THUMBv2" }, - { arm::Features::kVFP2 , "VFPv2" }, - { arm::Features::kVFP3 , "VFPv3" }, - { arm::Features::kVFP4 , "VFPv4" }, - { arm::Features::kVFP_D32 , "VFP D32" }, - { arm::Features::kNEON , "NEON" }, - { arm::Features::kDSP , "DSP" }, - { arm::Features::kIDIV , "IDIV" }, - { arm::Features::kAES , "AES" }, - { arm::Features::kCRC32 , "CRC32" }, - { arm::Features::kSHA1 , "SHA1" }, - { arm::Features::kSHA256 , "SHA256" }, - { arm::Features::kATOMIC64 , "ATOMIC64" } - }; - - INFO("ARM Features:"); - dumpFeatures(cpu, armFeaturesList, ASMJIT_ARRAY_SIZE(armFeaturesList)); - INFO(""); -#endif +#endif // !ASMJIT_NO_LOGGING } // ============================================================================ @@ -281,7 +165,7 @@ static void dumpSizeOf(void) noexcept { DUMP_TYPE(BaseCompiler); DUMP_TYPE(FuncNode); DUMP_TYPE(FuncRetNode); - DUMP_TYPE(FuncCallNode); + DUMP_TYPE(InvokeNode); INFO(""); #endif @@ -324,7 +208,7 @@ int main(int argc, const char* argv[]) { unsigned((ASMJIT_LIBRARY_VERSION >> 16) ), unsigned((ASMJIT_LIBRARY_VERSION >> 8) & 0xFF), unsigned((ASMJIT_LIBRARY_VERSION ) & 0xFF), - hostArch(), + archToString(Environment::kArchHost), buildType ); diff --git a/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp b/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp index a01185d80f9..ba85100dae0 100644 --- a/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp +++ b/3rdparty/asmjit/test/asmjit_test_x86_asm.cpp @@ -48,7 +48,7 @@ static void makeRawFunc(x86::Emitter* emitter) noexcept { // Create and initialize `FuncDetail` and `FuncFrame`. FuncDetail func; - func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost)); + func.init(FuncSignatureT<void, int*, const int*, const int*>(CallConv::kIdHost), emitter->environment()); FuncFrame frame; frame.init(func); @@ -101,10 +101,11 @@ static void makeCompiledFunc(x86::Compiler* cc) noexcept { static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept { #ifndef ASMJIT_NO_LOGGING FileLogger logger(stdout); + logger.setIndentation(FormatOptions::kIndentationCode, 2); #endif CodeHolder code; - code.init(rt.codeInfo()); + code.init(rt.environment()); #ifndef ASMJIT_NO_LOGGING code.setLogger(&logger); @@ -173,8 +174,10 @@ static uint32_t testFunc(JitRuntime& rt, uint32_t emitterType) noexcept { } int main() { - unsigned nFailed = 0; + printf("AsmJit X86 Emitter Test\n\n"); + JitRuntime rt; + unsigned nFailed = 0; nFailed += testFunc(rt, BaseEmitter::kTypeAssembler); @@ -187,9 +190,9 @@ int main() { #endif if (!nFailed) - printf("[PASSED] All tests passed\n"); + printf("Success:\n All tests passed\n"); else - printf("[FAILED] %u %s failed\n", nFailed, nFailed == 1 ? "test" : "tests"); + printf("Failure:\n %u %s failed\n", nFailed, nFailed == 1 ? "test" : "tests"); return nFailed ? 1 : 0; } diff --git a/3rdparty/asmjit/test/asmjit_test_x86_cc.cpp b/3rdparty/asmjit/test/asmjit_test_x86_cc.cpp index a0e50e97097..9e80d871978 100644 --- a/3rdparty/asmjit/test/asmjit_test_x86_cc.cpp +++ b/3rdparty/asmjit/test/asmjit_test_x86_cc.cpp @@ -27,6 +27,12 @@ #include <stdlib.h> #include <string.h> +#include <memory> +#include <vector> + +// Required for function tests that pass / return XMM registers. +#include <emmintrin.h> + #include "./asmjit_test_misc.h" #ifdef _MSC_VER @@ -67,7 +73,7 @@ public: virtual void handleError(Error err, const char* message, BaseEmitter* origin) { DebugUtils::unused(origin); _err = err; - _message.assignString(message); + _message.assign(message); } Error _err; @@ -81,7 +87,7 @@ public: //! Base test interface for testing `x86::Compiler`. class X86Test { public: - X86Test(const char* name = nullptr) { _name.assignString(name); } + X86Test(const char* name = nullptr) { _name.assign(name); } virtual ~X86Test() {} inline const char* name() const { return _name.data(); } @@ -98,9 +104,7 @@ public: class X86TestApp { public: - Zone _zone; - ZoneAllocator _allocator; - ZoneVector<X86Test*> _tests; + std::vector<std::unique_ptr<X86Test>> _tests; unsigned _nFailed; size_t _outputSize; @@ -109,20 +113,15 @@ public: bool _dumpAsm; X86TestApp() noexcept - : _zone(8096 - Zone::kBlockOverhead), - _allocator(&_zone), - _nFailed(0), + : _nFailed(0), _outputSize(0), _verbose(false), _dumpAsm(false) {} - ~X86TestApp() noexcept { - for (X86Test* test : _tests) - delete test; - } + ~X86TestApp() noexcept {} - Error add(X86Test* test) noexcept{ - return _tests.append(&_allocator, test); + void add(X86Test* test) noexcept { + _tests.push_back(std::unique_ptr<X86Test>(test)); } template<class T> @@ -169,12 +168,12 @@ int X86TestApp::run() { stringLogger.addFlags(kFormatFlags); #endif - for (X86Test* test : _tests) { + for (std::unique_ptr<X86Test>& test : _tests) { JitRuntime runtime; CodeHolder code; SimpleErrorHandler errorHandler; - code.init(runtime.codeInfo()); + code.init(runtime.environment()); code.setErrorHandler(&errorHandler); #ifndef ASMJIT_NO_LOGGING @@ -207,7 +206,7 @@ int X86TestApp::run() { if (!_verbose) printf("\n"); String sb; - cc.dump(sb, kFormatFlags); + Formatter::formatNodeList(sb, kFormatFlags, &cc); printf("%s", sb.data()); } #endif @@ -261,11 +260,12 @@ int X86TestApp::run() { } if (_nFailed == 0) - printf("\n[PASSED] All %u tests passed\n", unsigned(_tests.size())); + printf("\nSuccess:\n All %u tests passed\n", unsigned(_tests.size())); else - printf("\n[FAILED] %u %s of %u failed\n", _nFailed, _nFailed == 1 ? "test" : "tests", unsigned(_tests.size())); + printf("\nFailure:\n %u %s of %u failed\n", _nFailed, _nFailed == 1 ? "test" : "tests", unsigned(_tests.size())); printf(" OutputSize=%zu\n", _outputSize); + printf("\n"); return _nFailed == 0 ? 0 : 1; } @@ -703,8 +703,8 @@ public: func(); - result.appendString("ret={}"); - expect.appendString("ret={}"); + result.append("ret={}"); + expect.append("ret={}"); return true; } @@ -750,8 +750,8 @@ public: func(); - result.appendString("ret={}"); - expect.appendString("ret={}"); + result.append("ret={}"); + expect.append("ret={}"); return true; } @@ -1051,8 +1051,8 @@ public: for (i = 0; i < ASMJIT_ARRAY_SIZE(resultBuf); i++) { if (i != 0) { - result.appendChar(','); - expect.appendChar(','); + result.append(','); + expect.append(','); } result.appendFormat("%u", resultBuf[i]); @@ -1971,6 +1971,59 @@ public: }; // ============================================================================ +// [X86Test_AllocArgsVec] +// ============================================================================ + +class X86Test_AllocArgsVec : public X86Test { +public: + X86Test_AllocArgsVec() : X86Test("AllocArgsVec") {} + + static void add(X86TestApp& app) { + // Not supported on Windows. +#ifndef _WIN32 + app.add(new X86Test_AllocArgsVec()); +#endif + } + + virtual void compile(x86::Compiler& cc) { + cc.addFunc(FuncSignatureT<x86::Xmm, x86::Xmm, x86::Xmm>(CallConv::kIdHost)); + + x86::Xmm a = cc.newXmm("aXmm"); + x86::Xmm b = cc.newXmm("bXmm"); + + cc.setArg(0, a); + cc.setArg(1, b); + + cc.paddb(a, b); + cc.ret(a); + + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef __m128i (*Func)(__m128i, __m128i); + Func func = ptr_as_func<Func>(_func); + + uint8_t aData[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + uint8_t bData[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + uint8_t rData[16]; + uint8_t eData[16] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; + + __m128i aVec = _mm_loadu_si128(reinterpret_cast<const __m128i*>(aData)); + __m128i bVec = _mm_loadu_si128(reinterpret_cast<const __m128i*>(bData)); + + __m128i rVec = func(aVec, bVec); + _mm_storeu_si128(reinterpret_cast<__m128i*>(rData), rVec); + + result.appendHex(rData, 16); + expect.appendHex(eData, 16); + + return result == expect; + } +}; + +// ============================================================================ // [X86Test_AllocRetFloat1] // ============================================================================ @@ -2253,21 +2306,21 @@ public: func(dstBuffer, srcBuffer, kCount); - result.assignString("buf={"); - expect.assignString("buf={"); + result.assign("buf={"); + expect.assign("buf={"); for (i = 0; i < kCount; i++) { if (i != 0) { - result.appendString(", "); - expect.appendString(", "); + result.append(", "); + expect.append(", "); } result.appendFormat("%u", unsigned(dstBuffer[i])); expect.appendFormat("%u", unsigned(srcBuffer[i])); } - result.appendString("}"); - expect.appendString("}"); + result.append("}"); + expect.append("}"); return result == expect; } @@ -2395,21 +2448,21 @@ public: func(dstBuffer, srcBuffer, kCount); - result.assignString("buf={"); - expect.assignString("buf={"); + result.assign("buf={"); + expect.assign("buf={"); for (i = 0; i < kCount; i++) { if (i != 0) { - result.appendString(", "); - expect.appendString(", "); + result.append(", "); + expect.append(", "); } result.appendFormat("%08X", unsigned(dstBuffer[i])); expect.appendFormat("%08X", unsigned(expBuffer[i])); } - result.appendString("}"); - expect.appendString("}"); + result.append("}"); + expect.append("}"); return result == expect; } @@ -2443,11 +2496,12 @@ public: cc.shl(v2, 1); // Call a function. - FuncCallNode* call = cc.call(imm((void*)calledFunc), FuncSignatureT<int, int, int, int>(CallConv::kIdHost)); - call->setArg(0, v2); - call->setArg(1, v1); - call->setArg(2, v0); - call->setRet(0, v0); + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int, int, int>(CallConv::kIdHost)); + invokeNode->setArg(0, v2); + invokeNode->setArg(1, v1); + invokeNode->setArg(2, v0); + invokeNode->setRet(0, v0); cc.ret(v0); cc.endFunc(); @@ -2498,29 +2552,29 @@ public: Label L_Exit = cc.newLabel(); static const char token[kTokenSize] = "-+:|abcdefghijklmnopqrstuvwxyz|"; - FuncCallNode* call; + InvokeNode* invokeNode; cc.lea(p1, s1); cc.lea(p2, s2); // Try to corrupt the stack if wrongly allocated. - call = cc.call(imm((void*)memcpy), FuncSignatureT<void*, void*, void*, size_t>(CallConv::kIdHostCDecl)); - call->setArg(0, p1); - call->setArg(1, imm(token)); - call->setArg(2, imm(kTokenSize)); - call->setRet(0, p1); - - call = cc.call(imm((void*)memcpy), FuncSignatureT<void*, void*, void*, size_t>(CallConv::kIdHostCDecl)); - call->setArg(0, p2); - call->setArg(1, imm(token)); - call->setArg(2, imm(kTokenSize)); - call->setRet(0, p2); - - call = cc.call(imm((void*)memcmp), FuncSignatureT<int, void*, void*, size_t>(CallConv::kIdHostCDecl)); - call->setArg(0, p1); - call->setArg(1, p2); - call->setArg(2, imm(kTokenSize)); - call->setRet(0, ret); + cc.invoke(&invokeNode, imm((void*)memcpy), FuncSignatureT<void*, void*, void*, size_t>(CallConv::kIdCDecl)); + invokeNode->setArg(0, p1); + invokeNode->setArg(1, imm(token)); + invokeNode->setArg(2, imm(kTokenSize)); + invokeNode->setRet(0, p1); + + cc.invoke(&invokeNode, imm((void*)memcpy), FuncSignatureT<void*, void*, void*, size_t>(CallConv::kIdCDecl)); + invokeNode->setArg(0, p2); + invokeNode->setArg(1, imm(token)); + invokeNode->setArg(2, imm(kTokenSize)); + invokeNode->setRet(0, p2); + + cc.invoke(&invokeNode, imm((void*)memcmp), FuncSignatureT<int, void*, void*, size_t>(CallConv::kIdCDecl)); + invokeNode->setArg(0, p1); + invokeNode->setArg(1, p2); + invokeNode->setArg(2, imm(kTokenSize)); + invokeNode->setRet(0, ret); // This should be 0 on success, however, if both `p1` and `p2` were // allocated in the same address this check will still pass. @@ -2573,13 +2627,14 @@ public: cc.setArg(1, y); cc.setArg(2, z); - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), - FuncSignatureT<int, int, int, int>(CallConv::kIdHostStdCall)); - call->setArg(0, x); - call->setArg(1, y); - call->setArg(2, z); - call->setRet(0, x); + FuncSignatureT<int, int, int, int>(CallConv::kIdStdCall)); + invokeNode->setArg(0, x); + invokeNode->setArg(1, y); + invokeNode->setArg(2, z); + invokeNode->setRet(0, x); cc.ret(x); cc.endFunc(); @@ -2622,18 +2677,15 @@ public: cc.addFunc(FuncSignatureT<int, int>(CallConv::kIdHost)); cc.setArg(0, var); - FuncCallNode* call; - call = cc.call( - imm((void*)calledFunc), - FuncSignatureT<int, int>(CallConv::kIdHostFastCall)); - call->setArg(0, var); - call->setRet(0, var); + InvokeNode* invokeNode; - call = cc.call( - imm((void*)calledFunc), - FuncSignatureT<int, int>(CallConv::kIdHostFastCall)); - call->setArg(0, var); - call->setRet(0, var); + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int>(CallConv::kIdFastCall)); + invokeNode->setArg(0, var); + invokeNode->setRet(0, var); + + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int>(CallConv::kIdFastCall)); + invokeNode->setArg(0, var); + invokeNode->setRet(0, var); cc.ret(var); cc.endFunc(); @@ -2659,6 +2711,97 @@ public: }; // ============================================================================ +// [X86Test_FuncCallSIMD] +// ============================================================================ + +class X86Test_FuncCallSIMD : public X86Test { +public: + bool _useVectorCall; + + X86Test_FuncCallSIMD(bool useVectorCall) + : X86Test(), + _useVectorCall(useVectorCall) { + _name.assignFormat("FuncCallSIMD {%s}", _useVectorCall ? "__vectorcall" : "__cdecl"); + } + + static void add(X86TestApp& app) { + app.add(new X86Test_FuncCallSIMD(false)); +#ifdef _MSC_VER + app.add(new X86Test_FuncCallSIMD(true)); +#endif + } + + virtual void compile(x86::Compiler& cc) { + cc.addFunc(FuncSignatureT<void, void*, const void*, const void*>(CallConv::kIdHost)); + + x86::Gp resultPtr = cc.newIntPtr("resultPtr"); + x86::Gp aPtr = cc.newIntPtr("aPtr"); + x86::Gp bPtr = cc.newIntPtr("bPtr"); + x86::Gp pFn = cc.newIntPtr("pFn"); + + x86::Xmm aXmm = cc.newXmm("aXmm"); + x86::Xmm bXmm = cc.newXmm("bXmm"); + + cc.setArg(0, resultPtr); + cc.setArg(1, aPtr); + cc.setArg(2, bPtr); + + uint32_t ccId = CallConv::kIdCDecl; + Imm pFnImm = imm((void*)calledFunc_cdecl); + +#ifdef _MSC_VER + if (_useVectorCall) { + ccId = CallConv::kIdVectorCall; + pFnImm = imm((void*)calledFunc_vcall); + } +#endif + + cc.mov(pFn, pFnImm); + cc.movdqu(aXmm, x86::ptr(aPtr)); + cc.movdqu(bXmm, x86::ptr(bPtr)); + + InvokeNode* invokeNode; + cc.invoke(&invokeNode, pFn, FuncSignatureT<x86::Xmm, x86::Xmm, x86::Xmm>(ccId)); + + invokeNode->setArg(0, aXmm); + invokeNode->setArg(1, bXmm); + invokeNode->setRet(0, aXmm); + + cc.movdqu(x86::ptr(resultPtr), aXmm); + + cc.endFunc(); + } + + virtual bool run(void* _func, String& result, String& expect) { + typedef void (*Func)(void*, const void*, const void*); + Func func = ptr_as_func<Func>(_func); + + uint8_t aData[16] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; + uint8_t bData[16] = { 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 }; + + uint8_t rData[16]; + uint8_t eData[16] = { 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15 }; + + func(rData, aData, bData); + + result.appendHex(rData, 16); + expect.appendHex(eData, 16); + + return result == expect; + } + + static __m128i calledFunc_cdecl(__m128i a, __m128i b) { + return _mm_add_epi8(a, b); + } + +#ifdef _MSC_VER + static __m128i __vectorcall calledFunc_vcall(__m128i a, __m128i b) { + return _mm_add_epi8(a, b); + } +#endif +}; + +// ============================================================================ // [X86Test_FuncCallLight] // ============================================================================ @@ -2671,8 +2814,8 @@ public: } virtual void compile(x86::Compiler& cc) { - FuncSignatureT<void, const void*, const void*, const void*, const void*, void*> funcSig(CallConv::kIdHostCDecl); - FuncSignatureT<x86::Xmm, x86::Xmm, x86::Xmm> fastSig(CallConv::kIdHostLightCall2); + FuncSignatureT<void, const void*, const void*, const void*, const void*, void*> funcSig(CallConv::kIdCDecl); + FuncSignatureT<x86::Xmm, x86::Xmm, x86::Xmm> fastSig(CallConv::kIdLightCall2); FuncNode* func = cc.newFunc(funcSig); FuncNode* fast = cc.newFunc(fastSig); @@ -2705,15 +2848,17 @@ public: x86::Xmm xXmm = cc.newXmm("xXmm"); x86::Xmm yXmm = cc.newXmm("yXmm"); - FuncCallNode* call1 = cc.call(fast->label(), fastSig); - call1->setArg(0, aXmm); - call1->setArg(1, bXmm); - call1->setRet(0, xXmm); + InvokeNode* invokeNode; + + cc.invoke(&invokeNode, fast->label(), fastSig); + invokeNode->setArg(0, aXmm); + invokeNode->setArg(1, bXmm); + invokeNode->setRet(0, xXmm); - FuncCallNode* call2 = cc.call(fast->label(), fastSig); - call2->setArg(0, cXmm); - call2->setArg(1, dXmm); - call2->setRet(0, yXmm); + cc.invoke(&invokeNode, fast->label(), fastSig); + invokeNode->setArg(0, cXmm); + invokeNode->setArg(1, dXmm); + invokeNode->setRet(0, yXmm); cc.pmullw(xXmm, yXmm); cc.movups(x86::ptr(pOut), xXmm); @@ -2798,21 +2943,22 @@ public: cc.mov(vi, 0x18); cc.mov(vj, 0x1E); - // Call function. - FuncCallNode* call = cc.call( + // Function call. + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int, int, int, int, int, int, int, int, int, int>(CallConv::kIdHost)); - call->setArg(0, va); - call->setArg(1, vb); - call->setArg(2, vc); - call->setArg(3, vd); - call->setArg(4, ve); - call->setArg(5, vf); - call->setArg(6, vg); - call->setArg(7, vh); - call->setArg(8, vi); - call->setArg(9, vj); - call->setRet(0, va); + invokeNode->setArg(0, va); + invokeNode->setArg(1, vb); + invokeNode->setArg(2, vc); + invokeNode->setArg(3, vd); + invokeNode->setArg(4, ve); + invokeNode->setArg(5, vf); + invokeNode->setArg(6, vg); + invokeNode->setArg(7, vh); + invokeNode->setArg(8, vi); + invokeNode->setArg(9, vj); + invokeNode->setRet(0, va); cc.ret(va); cc.endFunc(); @@ -2856,20 +3002,21 @@ public: cc.mov(a, 3); // Call function. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int, int, int, int, int, int, int, int, int, int>(CallConv::kIdHost)); - call->setArg(0, a); - call->setArg(1, a); - call->setArg(2, a); - call->setArg(3, a); - call->setArg(4, a); - call->setArg(5, a); - call->setArg(6, a); - call->setArg(7, a); - call->setArg(8, a); - call->setArg(9, a); - call->setRet(0, a); + invokeNode->setArg(0, a); + invokeNode->setArg(1, a); + invokeNode->setArg(2, a); + invokeNode->setArg(3, a); + invokeNode->setArg(4, a); + invokeNode->setArg(5, a); + invokeNode->setArg(6, a); + invokeNode->setArg(7, a); + invokeNode->setArg(8, a); + invokeNode->setArg(9, a); + invokeNode->setRet(0, a); cc.ret(a); cc.endFunc(); @@ -2908,21 +3055,22 @@ public: x86::Gp rv = cc.newInt32("rv"); // Call function. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)X86Test_FuncCallManyArgs::calledFunc), FuncSignatureT<int, int, int, int, int, int, int, int, int, int, int>(CallConv::kIdHost)); - call->setArg(0, imm(0x03)); - call->setArg(1, imm(0x12)); - call->setArg(2, imm(0xA0)); - call->setArg(3, imm(0x0B)); - call->setArg(4, imm(0x2F)); - call->setArg(5, imm(0x02)); - call->setArg(6, imm(0x0C)); - call->setArg(7, imm(0x12)); - call->setArg(8, imm(0x18)); - call->setArg(9, imm(0x1E)); - call->setRet(0, rv); + invokeNode->setArg(0, imm(0x03)); + invokeNode->setArg(1, imm(0x12)); + invokeNode->setArg(2, imm(0xA0)); + invokeNode->setArg(3, imm(0x0B)); + invokeNode->setArg(4, imm(0x2F)); + invokeNode->setArg(5, imm(0x02)); + invokeNode->setArg(6, imm(0x0C)); + invokeNode->setArg(7, imm(0x12)); + invokeNode->setArg(8, imm(0x18)); + invokeNode->setArg(9, imm(0x1E)); + invokeNode->setRet(0, rv); cc.ret(rv); cc.endFunc(); @@ -2974,21 +3122,22 @@ public: x86::Gp rv = cc.newInt32("rv"); // Call function. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, void*, void*, void*, void*, void*, void*, void*, void*, void*, void*>(CallConv::kIdHost)); - call->setArg(0, imm(0x01)); - call->setArg(1, imm(0x02)); - call->setArg(2, imm(0x03)); - call->setArg(3, imm(0x04)); - call->setArg(4, imm(0x05)); - call->setArg(5, imm(0x06)); - call->setArg(6, imm(0x07)); - call->setArg(7, imm(0x08)); - call->setArg(8, imm(0x09)); - call->setArg(9, imm(0x0A)); - call->setRet(0, rv); + invokeNode->setArg(0, imm(0x01)); + invokeNode->setArg(1, imm(0x02)); + invokeNode->setArg(2, imm(0x03)); + invokeNode->setArg(3, imm(0x04)); + invokeNode->setArg(4, imm(0x05)); + invokeNode->setArg(5, imm(0x06)); + invokeNode->setArg(6, imm(0x07)); + invokeNode->setArg(7, imm(0x08)); + invokeNode->setArg(8, imm(0x09)); + invokeNode->setArg(9, imm(0x0A)); + invokeNode->setRet(0, rv); cc.ret(rv); cc.endFunc(); @@ -3044,15 +3193,16 @@ public: cc.setArg(3, arg4); // Call function. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, int&, int&, int&, int&>(CallConv::kIdHost)); - call->setArg(0, arg1); - call->setArg(1, arg2); - call->setArg(2, arg3); - call->setArg(3, arg4); - call->setRet(0, rv); + invokeNode->setArg(0, arg1); + invokeNode->setArg(1, arg2); + invokeNode->setArg(2, arg3); + invokeNode->setArg(3, arg4); + invokeNode->setRet(0, rv); cc.ret(rv); cc.endFunc(); @@ -3101,12 +3251,11 @@ public: cc.setArg(1, b); // Call function. - FuncCallNode* call = cc.call( - imm((void*)calledFunc), - FuncSignatureT<float, float, float>(CallConv::kIdHost)); - call->setArg(0, a); - call->setArg(1, b); - call->setRet(0, ret); + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<float, float, float>(CallConv::kIdHost)); + invokeNode->setArg(0, a); + invokeNode->setArg(1, b); + invokeNode->setRet(0, ret); cc.ret(ret); cc.endFunc(); @@ -3152,12 +3301,11 @@ public: cc.setArg(0, a); cc.setArg(1, b); - FuncCallNode* call = cc.call( - imm((void*)calledFunc), - FuncSignatureT<double, double, double>(CallConv::kIdHost)); - call->setArg(0, a); - call->setArg(1, b); - call->setRet(0, ret); + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<double, double, double>(CallConv::kIdHost)); + invokeNode->setArg(0, a); + invokeNode->setArg(1, b); + invokeNode->setRet(0, ret); cc.ret(ret); cc.endFunc(); @@ -3194,7 +3342,7 @@ public: x86::Gp y = cc.newInt32("y"); x86::Gp op = cc.newInt32("op"); - FuncCallNode* call; + InvokeNode* invokeNode; x86::Gp result; cc.addFunc(FuncSignatureT<int, int, int, int>(CallConv::kIdHost)); @@ -3217,19 +3365,19 @@ public: cc.bind(opAdd); result = cc.newInt32("result_1"); - call = cc.call((uint64_t)calledFuncAdd, FuncSignatureT<int, int, int>(CallConv::kIdHost)); - call->setArg(0, x); - call->setArg(1, y); - call->setRet(0, result); + cc.invoke(&invokeNode, (uint64_t)calledFuncAdd, FuncSignatureT<int, int, int>(CallConv::kIdHost)); + invokeNode->setArg(0, x); + invokeNode->setArg(1, y); + invokeNode->setRet(0, result); cc.ret(result); cc.bind(opMul); result = cc.newInt32("result_2"); - call = cc.call((uint64_t)calledFuncMul, FuncSignatureT<int, int, int>(CallConv::kIdHost)); - call->setArg(0, x); - call->setArg(1, y); - call->setRet(0, result); + cc.invoke(&invokeNode, (uint64_t)calledFuncMul, FuncSignatureT<int, int, int>(CallConv::kIdHost)); + invokeNode->setArg(0, x); + invokeNode->setArg(1, y); + invokeNode->setRet(0, result); cc.ret(result); cc.endFunc(); @@ -3291,25 +3439,25 @@ public: x86::Gp ret = cc.newInt32("ret"); x86::Gp ptr = cc.newIntPtr("ptr"); x86::Gp idx = cc.newInt32("idx"); - FuncCallNode* call; + InvokeNode* invokeNode; cc.mov(ptr, buf); cc.mov(idx, int(i)); - call = cc.call((uint64_t)calledFunc, FuncSignatureT<int, int*, int>(CallConv::kIdHostFastCall)); - call->setArg(0, ptr); - call->setArg(1, idx); - call->setRet(0, ret); + cc.invoke(&invokeNode, (uint64_t)calledFunc, FuncSignatureT<int, int*, int>(CallConv::kIdFastCall)); + invokeNode->setArg(0, ptr); + invokeNode->setArg(1, idx); + invokeNode->setRet(0, ret); cc.add(acc0, ret); cc.mov(ptr, buf); cc.mov(idx, int(i)); - call = cc.call((uint64_t)calledFunc, FuncSignatureT<int, int*, int>(CallConv::kIdHostFastCall)); - call->setArg(0, ptr); - call->setArg(1, idx); - call->setRet(0, ret); + cc.invoke(&invokeNode, (uint64_t)calledFunc, FuncSignatureT<int, int*, int>(CallConv::kIdFastCall)); + invokeNode->setArg(0, ptr); + invokeNode->setArg(1, idx); + invokeNode->setRet(0, ret); cc.sub(acc1, ret); } @@ -3361,9 +3509,11 @@ public: cc.mov(tmp, val); cc.dec(tmp); - FuncCallNode* call = cc.call(func->label(), FuncSignatureT<int, int>(CallConv::kIdHost)); - call->setArg(0, tmp); - call->setRet(0, tmp); + InvokeNode* invokeNode; + + cc.invoke(&invokeNode, func->label(), FuncSignatureT<int, int>(CallConv::kIdHost)); + invokeNode->setArg(0, tmp); + invokeNode->setRet(0, tmp); cc.mul(cc.newInt32(), val, tmp); cc.bind(skip); @@ -3413,15 +3563,16 @@ public: // We call `int func(size_t, ...)` // - The `vaIndex` must be 1 (first argument after size_t). // - The full signature of varargs (int, int, int, int) must follow. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<int, size_t, int, int, int, int>(CallConv::kIdHost, 1)); - call->setArg(0, imm(4)); - call->setArg(1, a0); - call->setArg(2, a1); - call->setArg(3, a2); - call->setArg(4, a3); - call->setRet(0, a0); + invokeNode->setArg(0, imm(4)); + invokeNode->setArg(1, a0); + invokeNode->setArg(2, a1); + invokeNode->setArg(3, a2); + invokeNode->setArg(4, a3); + invokeNode->setRet(0, a0); cc.ret(a0); cc.endFunc(); @@ -3481,15 +3632,16 @@ public: // We call `double func(size_t, ...)` // - The `vaIndex` must be 1 (first argument after size_t). // - The full signature of varargs (double, double, double, double) must follow. - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)calledFunc), FuncSignatureT<double, size_t, double, double, double, double>(CallConv::kIdHost, 1)); - call->setArg(0, imm(4)); - call->setArg(1, a0); - call->setArg(2, a1); - call->setArg(3, a2); - call->setArg(4, a3); - call->setRet(0, a0); + invokeNode->setArg(0, imm(4)); + invokeNode->setArg(1, a0); + invokeNode->setArg(2, a1); + invokeNode->setArg(3, a2); + invokeNode->setArg(4, a3); + invokeNode->setRet(0, a0); cc.ret(a0); cc.endFunc(); @@ -3545,11 +3697,12 @@ public: cc.setArg(0, a); cc.setArg(1, b); - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)dummy), FuncSignatureT<void, int, int>(CallConv::kIdHost)); - call->setArg(0, a); - call->setArg(1, b); + invokeNode->setArg(0, a); + invokeNode->setArg(1, b); cc.lea(r, x86::ptr(a, b)); cc.ret(r); @@ -3593,11 +3746,12 @@ public: cc.setArg(0, p); cc.movsd(arg, x86::ptr(p)); - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)op), FuncSignatureT<double, double>(CallConv::kIdHost)); - call->setArg(0, arg); - call->setRet(0, ret); + invokeNode->setArg(0, arg); + invokeNode->setRet(0, ret); cc.ret(ret); cc.endFunc(); @@ -3643,11 +3797,12 @@ public: cc.setArg(0, p); cc.movsd(arg, x86::ptr(p)); - FuncCallNode* call = cc.call( + InvokeNode* invokeNode; + cc.invoke(&invokeNode, imm((void*)op), FuncSignatureT<double, double>(CallConv::kIdHost)); - call->setArg(0, arg); - call->setRet(0, ret); + invokeNode->setArg(0, arg); + invokeNode->setRet(0, ret); cc.xorps(arg, arg); cc.subsd(arg, ret); @@ -3687,18 +3842,20 @@ public: } virtual void compile(x86::Compiler& cc) { - FuncSignatureBuilder funcPrototype; - funcPrototype.setCallConv(CallConv::kIdHost); - funcPrototype.setRet(Type::kIdF64); - cc.addFunc(funcPrototype); + InvokeNode* invokeNode; - FuncSignatureBuilder callPrototype; - callPrototype.setCallConv(CallConv::kIdHost); - callPrototype.setRet(Type::kIdF64); - FuncCallNode* call = cc.call(imm((void*)calledFunc), callPrototype); + FuncSignatureBuilder funcSignature; + funcSignature.setCallConv(CallConv::kIdHost); + funcSignature.setRet(Type::kIdF64); + cc.addFunc(funcSignature); + FuncSignatureBuilder invokeSignature; + invokeSignature.setCallConv(CallConv::kIdHost); + invokeSignature.setRet(Type::kIdF64); + + cc.invoke(&invokeNode, imm((void*)calledFunc), invokeSignature); x86::Xmm ret = cc.newXmmSd("ret"); - call->setRet(0, ret); + invokeNode->setRet(0, ret); cc.ret(ret); cc.endFunc(); @@ -3739,7 +3896,7 @@ public: x86::Gp pFn = cc.newIntPtr("pFn"); x86::Gp vars[16]; - uint32_t i, regCount = cc.gpCount(); + uint32_t i, regCount = cc.arch() == Environment::kArchX86 ? 8 : 16; ASMJIT_ASSERT(regCount <= ASMJIT_ARRAY_SIZE(vars)); cc.mov(pFn, imm((void*)calledFunc)); @@ -3752,7 +3909,9 @@ public: cc.mov(vars[i], 1); } - cc.call(pFn, FuncSignatureT<void>(CallConv::kIdHost)); + InvokeNode* invokeNode; + cc.invoke(&invokeNode, pFn, FuncSignatureT<void>(CallConv::kIdHost)); + for (i = 1; i < regCount; i++) if (vars[i].isValid()) cc.add(vars[0], vars[i]); @@ -3979,10 +4138,11 @@ public: cc.setArg(0, a); cc.setArg(1, b); - FuncCallNode* call = cc.call(f2->label(), FuncSignatureT<int, int, int>(CallConv::kIdHost)); - call->setArg(0, a); - call->setArg(1, b); - call->setRet(0, a); + InvokeNode* invokeNode; + cc.invoke(&invokeNode, f2->label(), FuncSignatureT<int, int, int>(CallConv::kIdHost)); + invokeNode->setArg(0, a); + invokeNode->setArg(1, b); + invokeNode->setRet(0, a); cc.ret(a); cc.endFunc(); @@ -4037,7 +4197,7 @@ public: // arguments will be passed by registers and there won't be any stack // misalignment when we call the `handler()`. This was failing on OSX // when targeting 32-bit. - cc.addFunc(FuncSignatureT<int, int, void*>(CallConv::kIdHostFastCall)); + cc.addFunc(FuncSignatureT<int, int, void*>(CallConv::kIdFastCall)); x86::Gp a = cc.newInt32("a"); x86::Gp b = cc.newIntPtr("b"); @@ -4123,6 +4283,7 @@ int main(int argc, char* argv[]) { app.addT<X86Test_AllocArgsIntPtr>(); app.addT<X86Test_AllocArgsFloat>(); app.addT<X86Test_AllocArgsDouble>(); + app.addT<X86Test_AllocArgsVec>(); app.addT<X86Test_AllocRetFloat1>(); app.addT<X86Test_AllocRetFloat2>(); app.addT<X86Test_AllocRetDouble1>(); @@ -4137,6 +4298,7 @@ int main(int argc, char* argv[]) { app.addT<X86Test_FuncCallBase2>(); app.addT<X86Test_FuncCallStd>(); app.addT<X86Test_FuncCallFast>(); + app.addT<X86Test_FuncCallSIMD>(); app.addT<X86Test_FuncCallLight>(); app.addT<X86Test_FuncCallManyArgs>(); app.addT<X86Test_FuncCallDuplicateArgs>(); diff --git a/3rdparty/asmjit/test/asmjit_test_x86_instinfo.cpp b/3rdparty/asmjit/test/asmjit_test_x86_instinfo.cpp new file mode 100644 index 00000000000..1d7d5003f8b --- /dev/null +++ b/3rdparty/asmjit/test/asmjit_test_x86_instinfo.cpp @@ -0,0 +1,128 @@ +// AsmJit - Machine code generation for C++ +// +// * Official AsmJit Home Page: https://asmjit.com +// * Official Github Repository: https://github.com/asmjit/asmjit +// +// Copyright (c) 2008-2020 The AsmJit Authors +// +// This software is provided 'as-is', without any express or implied +// warranty. In no event will the authors be held liable for any damages +// arising from the use of this software. +// +// Permission is granted to anyone to use this software for any purpose, +// including commercial applications, and to alter it and redistribute it +// freely, subject to the following restrictions: +// +// 1. The origin of this software must not be misrepresented; you must not +// claim that you wrote the original software. If you use this software +// in a product, an acknowledgment in the product documentation would be +// appreciated but is not required. +// 2. Altered source versions must be plainly marked as such, and must not be +// misrepresented as being the original software. +// 3. This notice may not be removed or altered from any source distribution. + +#include <asmjit/x86.h> +#include <stdio.h> + +using namespace asmjit; + +static void printInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount) { + StringTmp<512> sb; + + // Read & Write Information + // ------------------------ + + InstRWInfo rw; + InstAPI::queryRWInfo(arch, inst, operands, opCount, &rw); + + sb.append("Instruction:\n"); + sb.append(" "); +#ifndef ASMJIT_NO_LOGGING + Formatter::formatInstruction(sb, 0, nullptr, arch, inst, operands, opCount); +#else + sb.append("<Logging-Not-Available>"); +#endif + sb.append("\n"); + + sb.append("Operands:\n"); + for (uint32_t i = 0; i < rw.opCount(); i++) { + const OpRWInfo& op = rw.operand(i); + const char* access = op.isReadOnly() ? "R" : + op.isWriteOnly() ? "W" : + op.isReadWrite() ? "X" : "_"; + + sb.appendFormat(" [%u] RW=%s Read=%016llX Write=%016llX Extend=%016llX", + i, access, op.readByteMask(), op.writeByteMask(), op.extendByteMask()); + sb.append("\n"); + } + + // CPU Features + // ------------ + + BaseFeatures features; + InstAPI::queryFeatures(arch, inst, operands, opCount, &features); + +#ifndef ASMJIT_NO_LOGGING + if (!features.empty()) { + sb.append("Features:\n"); + sb.append(" "); + + bool first = true; + BaseFeatures::Iterator it(features.iterator()); + while (it.hasNext()) { + uint32_t featureId = uint32_t(it.next()); + if (!first) + sb.append(" & "); + Formatter::formatFeature(sb, arch, featureId); + first = false; + } + sb.append("\n"); + } +#endif + + printf("%s\n", sb.data()); +} + +template<typename... Args> +static void printInfoSimple(uint32_t arch, uint32_t instId, Args&&... args) { + BaseInst inst(instId); + Operand_ opArray[] = { std::forward<Args>(args)... }; + printInfo(arch, inst, opArray, sizeof...(args)); +} + +int main() { + using namespace x86; + uint32_t arch = Environment::kArchX64; + + printf("AsmJit X86 Instruction Information Test\n\n"); + + printInfoSimple(arch, + x86::Inst::kIdAdd, + x86::eax, x86::ebx); + + printInfoSimple(arch, + x86::Inst::kIdPshufd, + x86::xmm0, x86::xmm1, imm(0)); + + printInfoSimple(arch, + x86::Inst::kIdPextrw, + x86::eax, x86::xmm1, imm(0)); + + printInfoSimple(arch, + x86::Inst::kIdPextrw, + x86::ptr(rax), x86::xmm1, imm(0)); + + printInfoSimple(arch, + x86::Inst::kIdVaddpd, + x86::ymm0, x86::ymm1, x86::ymm2); + + printInfoSimple(arch, + x86::Inst::kIdVaddpd, + x86::ymm0, x86::ymm30, x86::ymm31); + + printInfoSimple(arch, + x86::Inst::kIdVaddpd, + x86::zmm0, x86::zmm1, x86::zmm2); + + return 0; +} diff --git a/3rdparty/asmjit/test/asmjit_test_x86_sections.cpp b/3rdparty/asmjit/test/asmjit_test_x86_sections.cpp index a9645b31649..ddafd63b8bc 100644 --- a/3rdparty/asmjit/test/asmjit_test_x86_sections.cpp +++ b/3rdparty/asmjit/test/asmjit_test_x86_sections.cpp @@ -53,7 +53,9 @@ static void fail(const char* message, Error err) { } int main() { - CodeInfo codeInfo(ArchInfo::kIdHost); + printf("AsmJit X86 Sections Test\n\n"); + + Environment env = hostEnvironment(); JitAllocator allocator; #ifndef ASMJIT_NO_LOGGING @@ -62,7 +64,7 @@ int main() { #endif CodeHolder code; - code.init(codeInfo); + code.init(env); #ifndef ASMJIT_NO_LOGGING code.setLogger(&logger); @@ -83,7 +85,7 @@ int main() { Label data = a.newLabel(); FuncDetail func; - func.init(FuncSignatureT<size_t, size_t>(CallConv::kIdHost)); + func.init(FuncSignatureT<size_t, size_t>(CallConv::kIdHost), code.environment()); FuncFrame frame; frame.init(func); @@ -159,18 +161,15 @@ int main() { typedef size_t (*Func)(size_t idx); Func fn = (Func)roPtr; - printf("\nTesting the generated function:\n"); + printf("\n"); if (fn(0) != dataArray[0] || fn(3) != dataArray[3] || fn(6) != dataArray[6] || fn(9) != dataArray[9] ) { - printf(" [FAILED] The generated function returned incorrect result(s)\n"); + printf("Failure:\n The generated function returned incorrect result(s)\n"); return 1; } - else { - printf(" [PASSED] The generated function returned expected results\n"); - } - allocator.release((void*)fn); + printf("Success:\n The generated function returned expected results\n"); return 0; } diff --git a/3rdparty/asmjit/tools/configure-makefiles.sh b/3rdparty/asmjit/tools/configure-makefiles.sh index 1c2729af90c..8bf7ca90347 100644 --- a/3rdparty/asmjit/tools/configure-makefiles.sh +++ b/3rdparty/asmjit/tools/configure-makefiles.sh @@ -7,7 +7,7 @@ BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1" echo "** Configuring ${BUILD_DIR}_dbg [Debug Build] **" mkdir -p ../${BUILD_DIR}_dbg cd ../${BUILD_DIR}_dbg -eval cmake .. -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} -DASMJIT_SANITIZE=1 +eval cmake .. -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} cd ${CURRENT_DIR} echo "** Configuring ${BUILD_DIR}_rel [Release Build] **" diff --git a/3rdparty/asmjit/tools/configure-ninja.sh b/3rdparty/asmjit/tools/configure-ninja.sh index a3da4178aa9..0ff2779062f 100644 --- a/3rdparty/asmjit/tools/configure-ninja.sh +++ b/3rdparty/asmjit/tools/configure-ninja.sh @@ -7,7 +7,7 @@ BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1" echo "** Configuring ${BUILD_DIR}_dbg [Debug Build] **" mkdir -p ../${BUILD_DIR}_dbg cd ../${BUILD_DIR}_dbg -eval cmake .. -G"Ninja" -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} -DASMJIT_SANITIZE=1 +eval cmake .. -G"Ninja" -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} cd ${CURRENT_DIR} echo "** Configuring ${BUILD_DIR}_rel [Release Build] **" diff --git a/3rdparty/asmjit/tools/configure-sanitizers.sh b/3rdparty/asmjit/tools/configure-sanitizers.sh index 46e332cfb7e..14a16b4d92a 100644 --- a/3rdparty/asmjit/tools/configure-sanitizers.sh +++ b/3rdparty/asmjit/tools/configure-sanitizers.sh @@ -5,13 +5,13 @@ BUILD_DIR="build" BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1" echo "** Configuring '${BUILD_DIR}_rel_asan' [Sanitize=Address] **" -mkdir -p ../${BUILD_DIR}_rel_asan -cd ../${BUILD_DIR}_rel_asan -eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS} -DASMJIT_SANITIZE=address +mkdir -p ../${BUILD_DIR}_dbg_asan +cd ../${BUILD_DIR}_dbg_asan +eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} -DASMJIT_SANITIZE=address cd ${CURRENT_DIR} echo "** Configuring '${BUILD_DIR}_rel_ubsan' [Sanitize=Undefined] **" -mkdir -p ../${BUILD_DIR}_rel_ubsan -cd ../${BUILD_DIR}_rel_ubsan -eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS} -DASMJIT_SANITIZE=undefined +mkdir -p ../${BUILD_DIR}_dbg_ubsan +cd ../${BUILD_DIR}_dbg_ubsan +eval cmake .. -GNinja -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} -DASMJIT_SANITIZE=undefined cd ${CURRENT_DIR} diff --git a/3rdparty/asmjit/tools/enumgen.js b/3rdparty/asmjit/tools/enumgen.js new file mode 100644 index 00000000000..b9d57e3dac9 --- /dev/null +++ b/3rdparty/asmjit/tools/enumgen.js @@ -0,0 +1,417 @@ +"use strict"; + +const fs = require("fs"); +const path = require("path"); + +const hasOwn = Object.prototype.hasOwnProperty; + +// ============================================================================ +// [Tokenizer] +// ============================================================================ + +// The list of "token types" which our lexer understands: +const tokenizerPatterns = [ + { type: "space" , re: /^\s+/ }, + { type: "comment" , re: /^(\/\/.*(\n|$)|\/\*.*\*\/)/ }, + { type: "symbol" , re: /^[a-zA-Z_]\w*/ }, + { type: "integer" , re: /^(-?\d+|0[x|X][0-9A-Fa-f]+)(l)?(l)?(u)?\b/ }, + { type: "comma" , re: /^,/ }, + { type: "operator", re: /(\+|\+\+|-|--|\/|\*|<<|>>|=|==|<|<=|>|>=|&|&&|\||\|\||\^|~|!)/ }, + { type: "paren" , re: /^[\(\)\{\}\[\]]/ } +]; + +function nextToken(input, from, patterns) { + if (from >= input.length) { + return { + type: "end", + begin: from, + end: from, + content: "" + } + } + + const s = input.slice(from); + for (var i = 0; i < patterns.length; i++) { + const pattern = patterns[i]; + const result = s.match(pattern.re); + + if (result !== null) { + const content = result[0]; + return { + type: pattern.type, + begin: from, + end: from + content.length, + content: content + }; + } + } + + return { + type: "invalid", + begin: from, + end: from + 1, + content: input[from] + }; +} + +class Tokenizer { + constructor(input, patterns) { + this.input = input; + this.index = 0; + this.patterns = patterns; + } + + next() { + for (;;) { + const token = nextToken(this.input, this.index, this.patterns); + this.index = token.end; + if (token.type === "space" || token.type === "comment") + continue; + return token; + } + } + + revert(token) { + this.index = token.begin; + } +} + +// ============================================================================ +// [Parser] +// ============================================================================ + +function parseEnum(input) { + const map = Object.create(null); + const hasOwn = Object.prototype.hasOwnProperty; + const tokenizer = new Tokenizer(input, tokenizerPatterns); + + var value = -1; + + for (;;) { + var token = tokenizer.next(); + if (token.type === "end") + break; + + if (token.type === "symbol") { + const symbol = token.content; + token = tokenizer.next(); + if (token.content === "=") { + token = tokenizer.next(); + if (token.type !== "integer") + throw Error(`Expected an integer after symbol '${symbol} = '`); + value = parseInt(token.content); + } + else { + value++; + } + + if (!hasOwn.call(map, symbol)) + map[symbol] = value; + else + console.log(`${symbol} already defined, skipping...`); + + token = tokenizer.next(); + if (token.type !== "comma") + tokenizer.revert(token); + continue; + } + + throw Error(`Unexpected token ${token.type} (${token.content})`); + } + + return map; +} + +// ============================================================================ +// [Stringify] +// ============================================================================ + +function compare(a, b) { + return a < b ? -1 : a == b ? 0 : 1; +} + +function compactedSize(table) { + var size = 0; + for (var i = 0; i < table.length; i++) + size += table[i].name.length + 1; + return size; +} + +function indexTypeFromSize(size) { + if (size <= 256) + return 'uint8_t'; + else if (size <= 65536) + return 'uint16_t'; + else + return 'uint32_t'; +} + +function indent(s, indentation) { + var lines = s.split(/\r?\n/g); + if (indentation) { + for (var i = 0; i < lines.length; i++) { + var line = lines[i]; + if (line) lines[i] = indentation + line; + } + } + + return lines.join("\n"); +} + +function stringifyEnum(map, options) { + var output = ""; + + const stripPrefix = options.strip; + const outputPrefix = options.output; + + var max = -1; + var table = []; + + for (var k in map) { + var name = k; + if (stripPrefix) { + if (name.startsWith(stripPrefix)) + name = name.substring(stripPrefix.length); + else + throw Error(`Cannot strip prefix '${stripPrefix}' in '${key}'`); + } + + table.push({ name: name, value: map[k] }); + max = Math.max(max, map[k]); + } + + table.sort(function(a, b) { return compare(a.value, b.value); }); + + const unknownIndex = compactedSize(table); + table.push({ name: "<Unknown>", value: max + 1 }); + + const indexType = indexTypeFromSize(compactedSize(table)); + + function buildStringData() { + var s = ""; + for (var i = 0; i < table.length; i++) { + s += ` "${table[i].name}\\0"`; + if (i == table.length - 1) + s += `;`; + s += `\n`; + } + return s; + } + + function buildIndexData() { + var index = 0; + var indexArray = []; + + for (var i = 0; i < table.length; i++) { + while (indexArray.length < table[i].value) + indexArray.push(unknownIndex); + + indexArray.push(index); + index += table[i].name.length + 1; + } + + var s = ""; + var line = ""; + var pos = 0; + + for (var i = 0; i < indexArray.length; i++) { + if (line) + line += " "; + + line += `${indexArray[i]}`; + if (i != indexArray.length - 1) + line += `,`; + + if (i == indexArray.length - 1 || line.length >= 72) { + s += ` ${line}\n`; + line = ""; + } + } + + return s; + } + + output += `static const char ${outputPrefix}String[] =\n` + buildStringData() + `\n`; + output += `static const ${indexType} ${outputPrefix}Index[] = {\n` + buildIndexData() + `};\n`; + + return output; +} + +// ============================================================================ +// [FileSystem] +// ============================================================================ + +function walkDir(baseDir) { + function walk(baseDir, nestedPath, out) { + fs.readdirSync(baseDir).forEach((file) => { + const stat = fs.statSync(path.join(baseDir, file)); + if (stat.isDirectory()) { + if (!stat.isSymbolicLink()) + walk(path.join(baseDir, file), path.join(nestedPath, file), out) + } + else { + out.push(path.join(nestedPath, file)); + } + }); + return out; + } + + return walk(baseDir, "", []); +} + +// ============================================================================ +// [Generator] +// ============================================================================ + +class Generator { + constructor(options) { + this.enumMap = Object.create(null); + this.outputs = []; + + this.verify = options.verify; + this.baseDir = options.baseDir; + this.noBackup = options.noBackup; + } + + readEnums() { + console.log(`Scanning: ${this.baseDir}`); + walkDir(this.baseDir).forEach((fileName) => { + if (/\.(cc|cpp|h|hpp)$/.test(fileName)) { + const content = fs.readFileSync(path.join(this.baseDir, fileName), "utf8"); + this.addEnumsFromSource(fileName, content); + + if (/@EnumStringBegin(\{.*\})@/.test(content)) + this.outputs.push(fileName); + } + }); + } + + writeEnums() { + this.outputs.forEach((fileName) => { + console.log(`Output: ${fileName}`); + + const oldContent = fs.readFileSync(path.join(this.baseDir, fileName), "utf8"); + const newContent = this.injectEnumsToSource(oldContent); + + if (oldContent != newContent) { + if (this.verify) { + console.log(` FAILED: File is not up to date.`); + process.exit(1); + } + else { + if (!this.noBackup) { + fs.writeFileSync(path.join(this.baseDir, fileName + ".backup"), oldContent, "utf8"); + console.log(` Created ${fileName}.backup`); + } + fs.writeFileSync(path.join(this.baseDir, fileName), newContent, "utf8"); + console.log(` Updated ${fileName}`); + } + } + else { + console.log(` File is up to date.`); + } + }); + } + + addEnumsFromSource(fileName, src) { + var found = false; + const matches = [...src.matchAll(/(?:@EnumValuesBegin(\{.*\})@|@EnumValuesEnd@)/g)]; + + for (var i = 0; i < matches.length; i += 2) { + const def = matches[i]; + const end = matches[i + 1]; + + if (!def[0].startsWith("@EnumValuesBegin")) + throw new Error(`Cannot start with '${def[0]}'`); + + if (!end) + throw new Error(`Missing @EnumValuesEnd for '${def[0]}'`); + + if (!end[0].startsWith("@EnumValuesEnd@")) + throw new Error(`Expected @EnumValuesEnd@ for '${def[0]}' and not '${end[0]}'`); + + const options = JSON.parse(def[1]); + const enumName = options.enum; + + if (!enumName) + throw Error(`Missing 'enum' in '${def[0]}`); + + if (hasOwn.call(this.enumMap, enumName)) + throw new Error(`Enumeration '${enumName}' is already defined`); + + const startIndex = src.lastIndexOf("\n", def.index) + 1; + const endIndex = end.index + end[0].length; + + if (startIndex === -1 || startIndex > endIndex) + throw new Error(`Internal Error, indexes have unexpected values: startIndex=${startIndex} endIndex=${endIndex}`); + + if (!found) { + found = true; + console.log(`Found: ${fileName}`); + } + + console.log(` Parsing Enum: ${enumName}`); + this.enumMap[enumName] = parseEnum(src.substring(startIndex, endIndex)); + } + } + + injectEnumsToSource(src) { + const matches = [...src.matchAll(/(?:@EnumStringBegin(\{.*\})@|@EnumStringEnd@)/g)]; + var delta = 0; + + for (var i = 0; i < matches.length; i += 2) { + const def = matches[i]; + const end = matches[i + 1]; + + if (!def[0].startsWith("@EnumStringBegin")) + throw new Error(`Cannot start with '${def[0]}'`); + + if (!end) + throw new Error(`Missing @EnumStringEnd@ for '${def[0]}'`); + + if (!end[0].startsWith("@EnumStringEnd@")) + throw new Error(`Expected @EnumStringEnd@ for '${def[0]}' and not '${end[0]}'`); + + const options = JSON.parse(def[1]); + const enumName = options.enum; + + if (!enumName) + throwError(`Missing 'name' in '${def[0]}`); + + if (!hasOwn.call(this.enumMap, enumName)) + throw new Error(`Enumeration '${enumName}' not found`); + + console.log(` Injecting Enum: ${enumName}`); + + const startIndex = src.indexOf("\n", def.index + delta) + 1; + const endIndex = src.lastIndexOf("\n", end.index + delta) + 1; + + if (startIndex === -1 || endIndex === -1 || startIndex > endIndex) + throw new Error(`Internal Error, indexes have unexpected values: startIndex=${startIndex} endIndex=${endIndex}`); + + // Calculate the indentation. + const indentation = (function() { + const begin = src.lastIndexOf("\n", def.index + delta) + 1; + const end = src.indexOf("/", begin); + return src.substring(begin, end); + })(); + + const newContent = indent(stringifyEnum(this.enumMap[enumName], options), indentation); + src = src.substring(0, startIndex) + newContent + src.substring(endIndex); + + delta -= endIndex - startIndex; + delta += newContent.length; + } + + return src; + } +} + +const generator = new Generator({ + baseDir : path.resolve(__dirname, "../src"), + verify : process.argv.indexOf("--verify") !== -1, + noBackup: process.argv.indexOf("--no-backup") !== -1 +}); + +generator.readEnums(); +generator.writeEnums(); diff --git a/3rdparty/asmjit/tools/enumgen.sh b/3rdparty/asmjit/tools/enumgen.sh new file mode 100644 index 00000000000..4783db2449d --- /dev/null +++ b/3rdparty/asmjit/tools/enumgen.sh @@ -0,0 +1,3 @@ +#!/usr/bin/env sh +set -e +node ./enumgen.js $@ diff --git a/3rdparty/asmjit/tools/tablegen.sh b/3rdparty/asmjit/tools/tablegen.sh index dbb37f1d791..40facf326dc 100644 --- a/3rdparty/asmjit/tools/tablegen.sh +++ b/3rdparty/asmjit/tools/tablegen.sh @@ -1,3 +1,3 @@ -#!/bin/sh - -node ./tablegen-x86.js +#!/usr/bin/env sh +set -e +node ./tablegen-x86.js $@ diff --git a/scripts/src/3rdparty.lua b/scripts/src/3rdparty.lua index 462f7a73173..941a2988bf2 100644 --- a/scripts/src/3rdparty.lua +++ b/scripts/src/3rdparty.lua @@ -2252,6 +2252,7 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/builder.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/callconv.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/callconv.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/codebuffer.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/codebufferwriter_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/codeholder.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/codeholder.h", @@ -2264,7 +2265,15 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/datatypes.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/emitter.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/emitter.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/emitterutils.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/emitterutils_p.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/environment.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/environment.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/errorhandler.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/errorhandler.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/features.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/formatter.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/formatter.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/func.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/func.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/globals.cpp", @@ -2275,13 +2284,14 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/jitallocator.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/jitruntime.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/jitruntime.h", - MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/logging.cpp", - MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/logging.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/logger.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/logger.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/misc_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/operand.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/operand.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/osutils.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/osutils.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/osutils_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/raassignment_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/rabuilders_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/radefs_p.h", @@ -2314,6 +2324,8 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/zonetree.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/zonevector.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/core/zonevector.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86archdata.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86archdata_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86assembler.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86assembler.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86builder.cpp", @@ -2325,6 +2337,8 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86emitter.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86features.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86features.h", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp", + MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86formatter_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86globals.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86instapi.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86instapi_p.h", @@ -2333,8 +2347,6 @@ project "asmjit" MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86instdb_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86internal.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86internal_p.h", - MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86logging.cpp", - MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86logging_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86opcode_p.h", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86operand.cpp", MAME_DIR .. "3rdparty/asmjit/src/asmjit/x86/x86operand.h", |