[abi] Added more functionality to ujit

* Renamed round to round_even
  * Added round_half_up intrinsic
  * Added floating-point mod
  * Added a scalar version of floating-point abs and neg
  * Added a behavior enum to specify how float to int conversion
    handles out-of-range and NaN cases
  * Updated some APX stuff in instruction database
This commit is contained in:
kobalicek
2025-10-05 16:10:33 +02:00
parent 32b5f78700
commit cdc4eacbb1
75 changed files with 3493 additions and 2402 deletions

View File

@@ -12,7 +12,7 @@
], ],
"tests": [ "tests": [
{ "optional": true, "cmd": ["asmjit_test_unit", "--quick"] }, { "optional": true, "cmd": ["asmjit_test_runner", "--quick"] },
{ "optional": true, "cmd": ["asmjit_test_environment"] }, { "optional": true, "cmd": ["asmjit_test_environment"] },
{ "optional": true, "cmd": ["asmjit_test_assembler"] }, { "optional": true, "cmd": ["asmjit_test_assembler"] },
{ "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] }, { "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] },

View File

@@ -18,10 +18,10 @@ jobs:
steps: steps:
- name: "Checkout" - name: "Checkout"
uses: actions/checkout@v4 uses: actions/checkout@v5
- name: "Setup node.js" - name: "Setup node.js"
uses: actions/setup-node@v4 uses: actions/setup-node@v5
with: with:
node-version: "*" node-version: "*"
@@ -104,22 +104,25 @@ jobs:
- { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "gcc-14" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04" , arch: "x86" , cc: "clang-20", conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "gcc-14" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04" , arch: "x86" , cc: "clang-20", conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-20", conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-20", conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-14" , arch: "arm64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-20", conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-14" , arch: "arm64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-20", conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15-intel" , arch: "x64" , cc: "gcc-14" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15-intel" , arch: "x64" , cc: "gcc-14" , conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15-intel" , arch: "x64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15-intel" , arch: "x64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15" , arch: "arm64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "macos" , host: "macos-15" , arch: "arm64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
- { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" } - { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
# Cross compiled, cannot run tests (Windows/UWP).
- { title: "windows/uwp" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=0,CMAKE_SYSTEM_NAME=WindowsStore,CMAKE_SYSTEM_VERSION=10.0,CMAKE_CXX_FLAGS=-D_WIN32_WINNT=0x0A00" } - { title: "windows/uwp" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=0,CMAKE_SYSTEM_NAME=WindowsStore,CMAKE_SYSTEM_VERSION=10.0,CMAKE_CXX_FLAGS=-D_WIN32_WINNT=0x0A00" }
- { title: "freebsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.2", defs: "ASMJIT_TEST=1" } - { title: "freebsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.2", defs: "ASMJIT_TEST=1" }
- { title: "freebsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.2", defs: "ASMJIT_TEST=1" } - { title: "freebsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.2", defs: "ASMJIT_TEST=1" }
- { title: "netbsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "10.1", defs: "ASMJIT_TEST=1" } - { title: "netbsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "10.1", defs: "ASMJIT_TEST=1" }
@@ -135,18 +138,18 @@ jobs:
steps: steps:
- name: "Checkout" - name: "Checkout"
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
path: "source" path: "source"
- name: "Checkout Build Actions" - name: "Checkout Build Actions"
uses: actions/checkout@v4 uses: actions/checkout@v5
with: with:
repository: build-actions/build-actions repository: build-actions/build-actions
path: "build-actions" path: "build-actions"
- name: "Python" - name: "Python"
uses: actions/setup-python@v5 uses: actions/setup-python@v6
with: with:
python-version: "3.x" python-version: "3.x"

View File

@@ -1,10 +1,18 @@
cmake_minimum_required(VERSION 3.19 FATAL_ERROR) # AsmJit
# ======
# To consume asmjit as a dependency, use asmjit::asmjit alias.
cmake_minimum_required(VERSION 3.24 FATAL_ERROR)
# Don't create a project if it was already created by another CMakeLists.txt. This makes # Don't create a project if it was already created by another CMakeLists.txt. This makes
# it possible to support both add_subdirectory() and include() ways of using AsmJit as a # it possible to support both add_subdirectory() and include() ways of using AsmJit as a
# dependency. # dependency.
if (NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" STREQUAL "asmjit") if (NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" STREQUAL "asmjit")
project(asmjit CXX) project(asmjit
LANGUAGES CXX
DESCRIPTION "Low-latency machine code generation"
HOMEPAGE_URL "https://asmjit.com")
endif() endif()
include(CheckCXXCompilerFlag) include(CheckCXXCompilerFlag)
@@ -194,7 +202,7 @@ function(asmjit_detect_sanitizers out)
set(${out} "${_out_array}" PARENT_SCOPE) set(${out} "${_out_array}" PARENT_SCOPE)
endfunction() endfunction()
function(asmjit_add_target target target_type) function(asmjit_addapp target target_type)
set(single_val "") set(single_val "")
set(multi_val SOURCES LIBRARIES CFLAGS CFLAGS_DBG CFLAGS_REL) set(multi_val SOURCES LIBRARIES CFLAGS CFLAGS_DBG CFLAGS_REL)
cmake_parse_arguments("X" "" "${single_val}" "${multi_val}" ${ARGN}) cmake_parse_arguments("X" "" "${single_val}" "${multi_val}" ${ARGN})
@@ -227,47 +235,41 @@ set(ASMJIT_INCLUDE_DIR "${ASMJIT_INCLUDE_DIRS}")
if (NOT ASMJIT_NO_CUSTOM_FLAGS) if (NOT ASMJIT_NO_CUSTOM_FLAGS)
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC") if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
list(APPEND ASMJIT_PRIVATE_CFLAGS list(APPEND ASMJIT_PRIVATE_CFLAGS -W4) # [+] Warning level 4.
-MP # [+] Multi-Process Compilation.
-GF # [+] Eliminate duplicate strings.
-Zc:__cplusplus # [+] Conforming __cplusplus definition.
-Zc:inline # [+] Remove unreferenced COMDAT.
-Zc:strictStrings # [+] Strict const qualification of string literals.
-Zc:threadSafeInit- # [-] Thread-safe statics.
-W4) # [+] Warning level 4.
list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG list(APPEND ASMJIT_PRIVATE_CFLAGS -MP) # [+] Multi-Process Compilation.
-GS) # [+] Buffer security-check. list(APPEND ASMJIT_PRIVATE_CFLAGS -GF) # [+] Eliminate duplicate strings.
list(APPEND ASMJIT_PRIVATE_CFLAGS -Zc:__cplusplus) # [+] Conforming __cplusplus definition.
list(APPEND ASMJIT_PRIVATE_CFLAGS -Zc:inline) # [+] Remove unreferenced COMDAT.
list(APPEND ASMJIT_PRIVATE_CFLAGS -Zc:strictStrings) # [+] Strict const qualification of string literals.
list(APPEND ASMJIT_PRIVATE_CFLAGS -Zc:threadSafeInit-) # [-] Thread-safe statics.
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG -GS) # [+] Buffer security-check.
-GS- # [-] Buffer security-check. list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -GS-) # [-] Buffer security-check.
-O2 # [+] Favor speed over size. list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) # [+] Favor speed over size.
-Oi) # [+] Generate intrinsic functions. list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -Oi) # [+] Generate intrinsic functions.
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang)$") elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang")
list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion) list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion) # [+] Add baseline warnings that can be used safely even with system headers.
list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno) asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wdouble-promotion) # [+] Warn about double promotions.
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wduplicated-cond) # [+] Warn about duplicate conditions.
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wduplicated-branches) # [+] Warn about duplicate branches.
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wlogical-op) # [+] Warn about suspicious uses of logical operators in expressions.
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wlogical-not-parentheses) # [+] Warn about logical not used on the left hand side operand of a comparison.
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wrestrict)
# We would like also '-Wzero-as-null-pointer-constant' but it would warn when it comes to system headers. list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno) # [-] Disable math functions setting errno (performance reasons).
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics) # [-] Don't add guards when initializing statics (we don't need it).
-Wdouble-promotion list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) # [+] Compiling with -O2 in release mode is what we generally want.
-Wduplicated-cond list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -fmerge-all-constants) # [+] We don't need unique address per constant (merging improves library size).
-Wduplicated-branches
-Wlogical-op
-Wrestrict
)
# -fno-semantic-interposition is not available on apple - the compiler issues a warning, which is not detected. # -fno-semantic-interposition is not available on apple - the compiler issues a warning, which is not detected.
if (APPLE) if (NOT APPLE)
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics) asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-semantic-interposition)
else()
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics -fno-semantic-interposition)
endif() endif()
# The following flags can save few bytes in the resulting binary. if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL -fno-enforce-eh-specs) # [-] Don't enforce termination if noexcept function throws.
-fmerge-all-constants # Merge all constants even if it violates ISO C++. endif()
-fno-enforce-eh-specs) # Don't enforce termination if noexcept function throws.
endif() endif()
endif() endif()
@@ -547,9 +549,10 @@ set(ASMJIT_SRC_LIST
asmjit/x86/x86rapass_p.h asmjit/x86/x86rapass_p.h
asmjit/ujit/ujitbase.h asmjit/ujit/ujitbase.h
asmjit/ujit/unicompiler.h
asmjit/ujit/unicompiler_a64.cpp asmjit/ujit/unicompiler_a64.cpp
asmjit/ujit/unicompiler_x86.cpp asmjit/ujit/unicompiler_x86.cpp
asmjit/ujit/unicompiler.h asmjit/ujit/unicompiler_utils_p.h
asmjit/ujit/uniop.h asmjit/ujit/uniop.h
asmjit/ujit/vecconsttable.cpp asmjit/ujit/vecconsttable.cpp
asmjit/ujit/vecconsttable.h asmjit/ujit/vecconsttable.h
@@ -592,12 +595,12 @@ message(" ASMJIT_PRIVATE_CFLAGS_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
if (NOT ASMJIT_EMBED) if (NOT ASMJIT_EMBED)
# Add AsmJit target. # Add AsmJit target.
asmjit_add_target(asmjit "${ASMJIT_TARGET_TYPE}" asmjit_addapp(asmjit "${ASMJIT_TARGET_TYPE}"
SOURCES ${ASMJIT_SRC} SOURCES ${ASMJIT_SRC}
LIBRARIES ${ASMJIT_DEPS} LIBRARIES ${ASMJIT_DEPS}
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
target_compile_options(asmjit INTERFACE ${ASMJIT_CFLAGS}) target_compile_options(asmjit INTERFACE ${ASMJIT_CFLAGS})
target_include_directories(asmjit BEFORE INTERFACE target_include_directories(asmjit BEFORE INTERFACE
@@ -632,60 +635,46 @@ if (NOT ASMJIT_EMBED)
enable_testing() enable_testing()
# Special target that always uses embedded AsmJit. # Special target that always uses embedded AsmJit.
asmjit_add_target(asmjit_test_unit TEST asmjit_addapp(asmjit_test_runner TEST
SOURCES ${ASMJIT_SRC} SOURCES ${ASMJIT_SRC}
test/asmjit_test_unit.cpp testing/tests/asmjit_test_runner.cpp
test/broken.cpp testing/tests/broken.cpp
test/broken.h testing/tests/broken.h
LIBRARIES ${ASMJIT_DEPS} LIBRARIES ${ASMJIT_DEPS}
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
-DASMJIT_TEST -DASMJIT_TEST
-DASMJIT_STATIC -DASMJIT_STATIC
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
target_include_directories(asmjit_test_unit BEFORE PRIVATE ${ASMJIT_INCLUDE_DIRS}) target_include_directories(asmjit_test_runner BEFORE PRIVATE ${ASMJIT_INCLUDE_DIRS})
asmjit_add_target(asmjit_test_assembler TEST asmjit_addapp(asmjit_test_assembler TEST
SOURCES test/asmjit_test_assembler.cpp SOURCES testing/tests/asmjit_test_assembler.cpp
test/asmjit_test_assembler.h testing/tests/asmjit_test_assembler.h
test/asmjit_test_assembler_a64.cpp testing/tests/asmjit_test_assembler_a64.cpp
test/asmjit_test_assembler_x64.cpp testing/tests/asmjit_test_assembler_x64.cpp
test/asmjit_test_assembler_x86.cpp testing/tests/asmjit_test_assembler_x86.cpp
LIBRARIES asmjit::asmjit LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
asmjit_add_target(asmjit_bench_codegen EXECUTABLE foreach(app asmjit_test_environment asmjit_test_emitters asmjit_test_x86_sections)
SOURCES test/asmjit_bench_codegen.cpp asmjit_addapp(${app} TEST
test/asmjit_bench_codegen_a64.cpp SOURCES testing/tests/${app}.cpp
test/asmjit_bench_codegen_x86.cpp LIBRARIES asmjit::asmjit
SOURCES test/asmjit_bench_codegen.h CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
LIBRARIES asmjit::asmjit CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
foreach(_target asmjit_bench_overhead
asmjit_bench_regalloc
asmjit_test_environment
asmjit_test_emitters
asmjit_test_x86_sections)
asmjit_add_target(${_target} TEST
SOURCES test/${_target}.cpp
LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
endforeach() endforeach()
if (NOT ASMJIT_NO_INTROSPECTION) if (NOT ASMJIT_NO_INTROSPECTION)
asmjit_add_target(asmjit_test_instinfo TEST asmjit_addapp(asmjit_test_instinfo TEST
SOURCES test/asmjit_test_instinfo.cpp SOURCES testing/tests/asmjit_test_instinfo.cpp
LIBRARIES asmjit::asmjit LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG} CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL}) CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
endif() endif()
if (NOT (ASMJIT_NO_BUILDER OR ASMJIT_NO_COMPILER)) if (NOT (ASMJIT_NO_BUILDER OR ASMJIT_NO_COMPILER))
@@ -727,28 +716,48 @@ if (NOT ASMJIT_EMBED)
endif() endif()
endif() endif()
set_property(SOURCE test/asmjit_test_unicompiler_avx2fma.cpp APPEND PROPERTY COMPILE_OPTIONS ${ASMJIT_AVX2FMA_CFLAGS}) asmjit_addapp(asmjit_test_compiler TEST
SOURCES testing/tests/asmjit_test_compiler.cpp
asmjit_add_target(asmjit_test_compiler TEST testing/tests/asmjit_test_compiler.h
SOURCES test/asmjit_test_compiler.cpp testing/tests/asmjit_test_compiler_a64.cpp
test/asmjit_test_compiler.h testing/tests/asmjit_test_compiler_x86.cpp
test/asmjit_test_compiler_a64.cpp LIBRARIES asmjit::asmjit
test/asmjit_test_compiler_x86.cpp CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
LIBRARIES asmjit::asmjit CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS} CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
asmjit_add_target(asmjit_test_unicompiler TEST
SOURCES test/asmjit_test_unicompiler.cpp
test/asmjit_test_unicompiler_sse2.cpp
test/asmjit_test_unicompiler_avx2fma.cpp
test/broken.cpp
LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
endif() endif()
if (NOT ASMJIT_NO_UJIT)
asmjit_addapp(asmjit_test_unicompiler TEST
SOURCES testing/tests/asmjit_test_unicompiler.cpp
testing/tests/asmjit_test_unicompiler_sse2.cpp
testing/tests/asmjit_test_unicompiler_avx2fma.cpp
testing/tests/broken.cpp
LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
set_property(SOURCE testing/tests/asmjit_test_unicompiler_avx2fma.cpp APPEND PROPERTY COMPILE_OPTIONS ${ASMJIT_AVX2FMA_CFLAGS})
endif()
asmjit_addapp(asmjit_bench_codegen EXECUTABLE
SOURCES testing/bench/asmjit_bench_codegen.cpp
testing/bench/asmjit_bench_codegen_a64.cpp
testing/bench/asmjit_bench_codegen_x86.cpp
SOURCES testing/bench/asmjit_bench_codegen.h
LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
foreach(app asmjit_bench_overhead asmjit_bench_regalloc)
asmjit_addapp(${app} TEST
SOURCES testing/bench/${app}.cpp
LIBRARIES asmjit::asmjit
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
endforeach()
endif() endif()
endif() endif()

View File

@@ -1,4 +1,4 @@
Copyright (c) 2008-2025 The AsmJit Authors Copyright (c) 2008-2025 Petr Kobalicek
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages

View File

@@ -17,10 +17,12 @@ Project Organization
* **src** - Source code * **src** - Source code
* **asmjit** - Source code and headers (always point include path in here) * **asmjit** - Source code and headers (always point include path in here)
* **core** - Core API, backend independent except relocations * **core** - Core API, backend independent except relocations
* **arm** - ARM specific API, used only by ARM and AArch64 backends * **arm** - ARM specific API, designed to be common for both AArch32 and AArch64
* **a64** - AArch64 specific API, used only by AArch64 backends
* **x86** - X86 specific API, used only by X86 and X64 backends * **x86** - X86 specific API, used only by X86 and X64 backends
* **ujit** - Universal JIT API
* **test** - Unit and integration tests (don't embed in your project) * **test** - Unit and integration tests (don't embed in your project)
* **tools** - Tools used for configuring, documenting, and generating files * **tools** - Tools used to re-regenerate generated files (instruction DB, enum strings)
Roadmap Roadmap
------- -------
@@ -38,6 +40,11 @@ Documentation
* [Documentation Index](https://asmjit.com/doc/index.html) * [Documentation Index](https://asmjit.com/doc/index.html)
* [Build Instructions](https://asmjit.com/doc/group__asmjit__build.html) (includes [CMake Integration](https://asmjit.com/doc/group__asmjit__build.html#cmake_integration)) * [Build Instructions](https://asmjit.com/doc/group__asmjit__build.html) (includes [CMake Integration](https://asmjit.com/doc/group__asmjit__build.html#cmake_integration))
Development & Testing
---------------------
* Basic configure scripts that invoke cmake are provided in project root.
Breaking Changes Breaking Changes
---------------- ----------------

11
configure.sh Executable file
View File

@@ -0,0 +1,11 @@
#!/bin/sh
BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
echo "== [Configuring Build - Debug] =="
eval cmake . -B build/Debug -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS} "$@"
echo ""
echo "== [Configuring Build - Release] =="
eval cmake . -B build/Release -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS} "$@"
echo ""

15
configure_sanitizers.sh Executable file
View File

@@ -0,0 +1,15 @@
#!/bin/sh
BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
echo "== [Configuring Build - Release_ASAN] =="
eval cmake . -B build/Release_ASAN ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=address "$@"
echo ""
echo "== [Configuring Build - Release_MSAN] =="
eval cmake . -B build/Release_MSAN ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=memory "$@"
echo ""
echo "== [Configuring Build - Release_UBSAN] =="
eval cmake . -B build/Release_UBSAN ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=undefined "$@"
echo ""

2
configure_vs2022_x64.bat Normal file
View File

@@ -0,0 +1,2 @@
@echo off
cmake . -B build_x64 -G"Visual Studio 17" -A x64 -DASMJIT_TEST=ON

2
configure_vs2022_x86.bat Normal file
View File

@@ -0,0 +1,2 @@
@echo off
cmake . -B build_x86 -G"Visual Studio 17" -A Win32 -DASMJIT_TEST=ON

View File

@@ -3633,22 +3633,22 @@
{"apx": "and{nf} W:r8, R:r8/m8, imm8" , "op": "[VM ] EVEX.ND=1.LLZ.NP.MAP4.WIG 80 /4 ib" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"}, {"apx": "and{nf} W:r8, R:r8/m8, imm8" , "op": "[VM ] EVEX.ND=1.LLZ.NP.MAP4.WIG 80 /4 ib" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"},
{"apx": "and{nf} W:rv, R:rv/mv, imms8" , "op": "[VM ] EVEX.ND=1.LLZ.Pv.MAP4.Wv 83 /4 ib" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"}, {"apx": "and{nf} W:rv, R:rv/mv, imms8" , "op": "[VM ] EVEX.ND=1.LLZ.Pv.MAP4.Wv 83 /4 ib" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"},
{"apx": "and{nf} W:rv, R:rv/mv, immv" , "op": "[VM ] EVEX.ND=1.LLZ.Pv.MAP4.Wv 81 /4 iv" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"}, {"apx": "and{nf} W:rv, R:rv/mv, immv" , "op": "[VM ] EVEX.ND=1.LLZ.Pv.MAP4.Wv 81 /4 iv" , "io": "OF=0 SF=W ZF=W AF=U PF=W CF=0"},
{"apx": "cmovb W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"}, {"apx": "cmovb X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"},
{"apx": "cmovbe W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"}, {"apx": "cmovbe X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"},
{"apx": "cmovl W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"}, {"apx": "cmovl X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"},
{"apx": "cmovle W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"}, {"apx": "cmovle X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"},
{"apx": "cmovnb W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"}, {"apx": "cmovnb X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"},
{"apx": "cmovnbe W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"}, {"apx": "cmovnbe X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"},
{"apx": "cmovnl W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"}, {"apx": "cmovnl X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"},
{"apx": "cmovnle W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"}, {"apx": "cmovnle X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"},
{"apx": "cmovno W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"}, {"apx": "cmovno X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"},
{"apx": "cmovnp W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"}, {"apx": "cmovnp X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"},
{"apx": "cmovns W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"}, {"apx": "cmovns X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"},
{"apx": "cmovnz W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"}, {"apx": "cmovnz X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"},
{"apx": "cmovo W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"}, {"apx": "cmovo X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"},
{"apx": "cmovp W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"}, {"apx": "cmovp X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"},
{"apx": "cmovs W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"}, {"apx": "cmovs X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"},
{"apx": "cmovz W:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"}, {"apx": "cmovz X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"},
{"any": "crc32 X:r32, R:r8/m8" , "op": "[RM ] EVEX.ND=0.LLZ.NP.MAP4.W0 F0 /r"}, {"any": "crc32 X:r32, R:r8/m8" , "op": "[RM ] EVEX.ND=0.LLZ.NP.MAP4.W0 F0 /r"},
{"any": "crc32 X:r64, R:r8/m8" , "op": "[RM ] EVEX.ND=0.LLZ.NP.MAP4.W1 F0 /r"}, {"any": "crc32 X:r64, R:r8/m8" , "op": "[RM ] EVEX.ND=0.LLZ.NP.MAP4.W1 F0 /r"},
{"any": "crc32 X:r32, R:r16/m16" , "op": "[RM ] EVEX.ND=0.LLZ.66.MAP4.W0 F1 /r"}, {"any": "crc32 X:r32, R:r16/m16" , "op": "[RM ] EVEX.ND=0.LLZ.66.MAP4.W0 F1 /r"},
@@ -3970,69 +3970,69 @@
{"x64": "ccmpz dfv, R:r8/m8, imm8" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.NP.MAP4.WIG 80 /7 ib" }, {"x64": "ccmpz dfv, R:r8/m8, imm8" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.NP.MAP4.WIG 80 /7 ib" },
{"x64": "ccmpz dfv, R:rv/mv, imms8" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.Pv.MAP4.Wv 83 /7 ib" }, {"x64": "ccmpz dfv, R:rv/mv, imms8" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.Pv.MAP4.Wv 83 /7 ib" },
{"x64": "ccmpz dfv, R:rv/mv, immv" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.Pv.MAP4.Wv 81 /7 iv" }, {"x64": "ccmpz dfv, R:rv/mv, immv" , "op": "[M ] EVEX.ND=0.SCC=4.LLZ.Pv.MAP4.Wv 81 /7 iv" },
{"x64": "cfcmovb W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"}, {"x64": "cfcmovb X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"},
{"x64": "cfcmovb W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"}, {"x64": "cfcmovb X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"},
{"x64": "cfcmovb W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"}, {"x64": "cfcmovb X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"},
{"x64": "cfcmovb W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"}, {"x64": "cfcmovb W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=R"},
{"x64": "cfcmovbe W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovbe X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovbe W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovbe X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovbe W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovbe X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovbe W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovbe W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 46 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovl W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovl X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovl W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovl X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovl W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovl X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovl W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovl W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4C /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovle W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovle X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovle W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovle X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovle W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovle X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovle W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovle W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4E /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovnb W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"}, {"x64": "cfcmovnb X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"},
{"x64": "cfcmovnb W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"}, {"x64": "cfcmovnb X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"},
{"x64": "cfcmovnb W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"}, {"x64": "cfcmovnb X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"},
{"x64": "cfcmovnb W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"}, {"x64": "cfcmovnb W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=R"},
{"x64": "cfcmovnbe W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovnbe X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovnbe W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovnbe X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovnbe W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovnbe X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovnbe W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"}, {"x64": "cfcmovnbe W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 47 /r" , "io": "CF=R ZF=R"},
{"x64": "cfcmovnl W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovnl X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovnl W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovnl X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovnl W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovnl X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovnl W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"}, {"x64": "cfcmovnl W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4D /r" , "io": "SF=R OF=R"},
{"x64": "cfcmovnle W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovnle X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovnle W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovnle X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovnle W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovnle X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovnle W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"}, {"x64": "cfcmovnle W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4F /r" , "io": "ZF=R SF=R OF=R"},
{"x64": "cfcmovno W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"}, {"x64": "cfcmovno X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"},
{"x64": "cfcmovno W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"}, {"x64": "cfcmovno X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"},
{"x64": "cfcmovno W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"}, {"x64": "cfcmovno X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"},
{"x64": "cfcmovno W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"}, {"x64": "cfcmovno W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=R"},
{"x64": "cfcmovnp W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"}, {"x64": "cfcmovnp X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"},
{"x64": "cfcmovnp W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"}, {"x64": "cfcmovnp X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"},
{"x64": "cfcmovnp W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"}, {"x64": "cfcmovnp X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"},
{"x64": "cfcmovnp W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"}, {"x64": "cfcmovnp W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4B /r" , "io": "PF=R"},
{"x64": "cfcmovns W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"}, {"x64": "cfcmovns X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"},
{"x64": "cfcmovns W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"}, {"x64": "cfcmovns X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"},
{"x64": "cfcmovns W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"}, {"x64": "cfcmovns X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"},
{"x64": "cfcmovns W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"}, {"x64": "cfcmovns W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=R"},
{"x64": "cfcmovnz W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"}, {"x64": "cfcmovnz X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"},
{"x64": "cfcmovnz W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"}, {"x64": "cfcmovnz X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"},
{"x64": "cfcmovnz W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"}, {"x64": "cfcmovnz X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"},
{"x64": "cfcmovnz W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"}, {"x64": "cfcmovnz W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 45 /r" , "io": "ZF=R"},
{"x64": "cfcmovo W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"}, {"x64": "cfcmovo X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"},
{"x64": "cfcmovo W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"}, {"x64": "cfcmovo X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"},
{"x64": "cfcmovo W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"}, {"x64": "cfcmovo X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"},
{"x64": "cfcmovo W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"}, {"x64": "cfcmovo W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=R"},
{"x64": "cfcmovp W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"}, {"x64": "cfcmovp X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"},
{"x64": "cfcmovp W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"}, {"x64": "cfcmovp X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"},
{"x64": "cfcmovp W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"}, {"x64": "cfcmovp X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"},
{"x64": "cfcmovp W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"}, {"x64": "cfcmovp W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 4A /r" , "io": "PF=R"},
{"x64": "cfcmovs W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"}, {"x64": "cfcmovs X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"},
{"x64": "cfcmovs W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"}, {"x64": "cfcmovs X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"},
{"x64": "cfcmovs W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"}, {"x64": "cfcmovs X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"},
{"x64": "cfcmovs W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"}, {"x64": "cfcmovs W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=R"},
{"x64": "cfcmovz W:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"}, {"x64": "cfcmovz X:rv, R:rv/mv" , "op": "[RM ] EVEX.ND=0.NF=0.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"},
{"x64": "cfcmovz W:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"}, {"x64": "cfcmovz X:rv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"},
{"x64": "cfcmovz W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"}, {"x64": "cfcmovz X?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"},
{"x64": "cfcmovz W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"}, {"x64": "cfcmovz W:rv, R:rv, R?:rv/mv" , "op": "[VRM] EVEX.ND=1.NF=1.LLZ.Pv.MAP4.Wv 44 /r" , "io": "ZF=R"},
{"x64": "ctestb dfv, R:r8/m8, R:r8" , "op": "[MR ] EVEX.ND=0.SCC=2.LLZ.NP.MAP4.WIG 84 /r" }, {"x64": "ctestb dfv, R:r8/m8, R:r8" , "op": "[MR ] EVEX.ND=0.SCC=2.LLZ.NP.MAP4.WIG 84 /r" },
{"x64": "ctestb dfv, R:rv/mv, R:rv" , "op": "[MR ] EVEX.ND=0.SCC=2.LLZ.Pv.MAP4.Wv 85 /r" }, {"x64": "ctestb dfv, R:rv/mv, R:rv" , "op": "[MR ] EVEX.ND=0.SCC=2.LLZ.Pv.MAP4.Wv 85 /r" },

View File

@@ -4491,14 +4491,14 @@ Case_BaseLdurStur:
goto InvalidInstruction; goto InvalidInstruction;
uint32_t x = o0.as<Gp>().is_gp64(); uint32_t x = o0.as<Gp>().is_gp64();
uint32_t gpMustBeX = uint32_t(size_op.size() >= 3u - op_data.is_signed); uint32_t gp_must_be_x = uint32_t(size_op.size() >= 3u - op_data.is_signed);
if (op_data.is_signed) { if (op_data.is_signed) {
if (gpMustBeX && !x) if (gp_must_be_x && !x)
goto InvalidInstruction; goto InvalidInstruction;
} }
else { else {
if (x != gpMustBeX) if (x != gp_must_be_x)
goto InvalidInstruction; goto InvalidInstruction;
} }

View File

@@ -37,75 +37,87 @@ public:
//! \name Virtual Registers //! \name Virtual Registers
//! \{ //! \{
//! \cond INTERNAL //! Creates a new general-purpose register with `type_id` type and optional name passed via `args`.
template<typename RegT, typename Type> //!
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type) { //! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_gp32(),
RegT reg(Globals::NoInit); //! \ref new_gp64(), and \ref new_gpz() or \ref new_gp_ptr().
_new_reg(Out<Reg>{reg}, type, nullptr); template<typename... Args>
return reg; ASMJIT_INLINE_NODEBUG Gp new_gp(TypeId type_id, Args&&... args) { return new_reg<Gp>(type_id, std::forward<Args>(args)...); }
}
template<typename RegT, typename Type> //! Creates a new vector register with `type_id` type and optional name passed via `args`.
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type, const char* s) { //!
#ifndef ASMJIT_NO_LOGGING //! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_vec128(),
RegT reg(Globals::NoInit); //! \ref new_vec_s(), \ref new_vec_d(), \ref new_vec_q(), ...
_new_reg(Out<Reg>{reg}, type, s); template<typename... Args>
return reg; ASMJIT_INLINE_NODEBUG Vec new_vec(TypeId type_id, Args&&... args) { return new_reg<Vec>(type_id, std::forward<Args>(args)...); }
#else
Support::maybe_unused(s);
return _new_reg_internal<RegT>(type);
#endif
}
template<typename RegT, typename Type, typename... Args> //! Creates a new 32-bit general purpose register mapped to low 32 bits of a full register (on 64-bit targets).
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type, const char* s, Args&&... args) { template<typename... Args>
#ifndef ASMJIT_NO_LOGGING ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return new_reg<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
RegT reg(Globals::NoInit);
_new_reg_fmt(Out<Reg>{reg}, type, s, std::forward<Args>(args)...);
return reg;
#else
Support::maybe_unused(s, std::forward<Args>(args)...);
return _new_reg_internal<RegT>(type);
#endif
}
//! \endcond
template<typename RegT, typename... Args> //! Creates a new 64-bit general purpose register.
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref, Args&&... args) { template<typename... Args>
return _new_reg_internal<RegT>(ref, std::forward<Args>(args)...); ASMJIT_INLINE_NODEBUG Gp new_gp64(Args&&... args) { return new_reg<Gp>(TypeId::kUInt64, std::forward<Args>(args)...); }
}
//! Creates a new 32-bit general purpose register.
//!
//! \note This is a convenience function alias of \ref new_gp32().
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Reg new_reg(TypeId type_id, Args&&... args) { return _new_reg_internal<Reg>(type_id, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Gp new_gpw(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
//! Creates a new 64-bit general purpose register.
//!
//! \note This is a convenience function alias of \ref new_gp64().
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp(TypeId type_id, Args&&... args) { return _new_reg_internal<Gp>(type_id, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Gp new_gpx(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
//! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
//!
//! \note This is a convenience function, on aarch64 target it always creates a 64-bit general-purpose register.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Gp new_gpz(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp64(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt64, std::forward<Args>(args)...); }
//! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
//!
//! \note This is a convenience function, on aarch64 target it always creates a 64-bit general-purpose register.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gpw(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Gp new_gp_ptr(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gpx(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt64, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gpz(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp_ptr(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
//! Creates a new 128-bit vector register.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec(TypeId type_id, Args&&... args) { return _new_reg_internal<Vec>(type_id, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Vec new_vec128(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x4, std::forward<Args>(args)...); }
//! Creates a new 128-bit vector register that will be used for scalar 32-bit floating point operation.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_s(Args&&... args) { return _new_reg_internal<Vec>(TypeId::kFloat32, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Vec new_vec128_f32x1(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x1, std::forward<Args>(args)...); }
//! Creates a new 128-bit vector register that will be used for scalar 64-bit floating point operation.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_d(Args&&... args) { return _new_reg_internal<Vec>(TypeId::kFloat64, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Vec new_vec128_f64x1(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x1, std::forward<Args>(args)...); }
//! Creates a new 128-bit vector register that will be used for packed 32-bit floating point operation.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_q(Args&&... args) { return _new_reg_internal<Vec>(TypeId::kUInt8x16, std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG Vec new_vec128_f32x4(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x4, std::forward<Args>(args)...); }
//! Creates a new 128-bit vector register that will be used for packed 64-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec128_f64x2(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x2, std::forward<Args>(args)...); }
//! Creates a new 32-bit vector register (S).
//!
//! \note This may look like an alias of \ref new_vec128_f32x1(), but it's not. This really creates a 32-bit
//! register, which has a type \ref RegType::kVec32, whereas \ref new_vec128_f32x1() creates a register,
//! which has a type \ref RegType::kVec64
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_s(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128_f64x1() that matches aarch64 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_d(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128() that matches aarch64 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec_q(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x4, std::forward<Args>(args)...); }
//! \} //! \}

View File

@@ -188,19 +188,16 @@ namespace asmjit {
//! you can just use the following CMake snippet that integrates AsmJit with your own CMake project: //! you can just use the following CMake snippet that integrates AsmJit with your own CMake project:
//! //!
//! ```cmake //! ```cmake
//! cmake_minimum_required(VERSION 3.30) //! cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
//! project(app C CXX)
//! //!
//! project(asmjit_consumer C CXX) # Both C and CXX are required. //! set(ASMJIT_DIR "3rdparty/asmjit") # Location of AsmJit.
//! set(CMAKE_CXX_STANDARD 17) # C++17 and never is supported. //! set(ASMJIT_STATIC TRUE) # Force static build.
//! add_subdirectory("${ASMJIT_DIR}") # Adds AsmJit sub-project to your project.
//! //!
//! set(ASMJIT_DIR "3rdparty/asmjit") # Location of AsmJit. //! add_executable(app asmjit_consumer.cpp) # Adds executable that uses AsmJit.
//! set(ASMJIT_STATIC TRUE) # Force static build. //! target_link_libraries(app asmjit::asmjit) # Adds AsmJit as a dependency to app.
//! //! target_compile_features(app PUBLIC cxx_std_17) # Makes C++17 as a requirement.
//! add_subdirectory("${ASMJIT_DIR}") # This adds AsmJit as a part of your project.
//!
//! add_executable(asmjit_consumer asmjit_consumer.cpp)
//! target_link_libraries(
//! asmjit_consumer asmjit::asmjit) # This adds AsmJit as a dependency to your target.
//! ``` //! ```
//! //!
//! \section build_type Build Type Configuration //! \section build_type Build Type Configuration
@@ -2111,8 +2108,53 @@ namespace asmjit {
//! \defgroup asmjit_a64 AArch64 Backend //! \defgroup asmjit_a64 AArch64 Backend
//! \brief AArch64 backend. //! \brief AArch64 backend.
//! \defgroup asmjit_ujit UJIT //! \defgroup asmjit_ujit Universal JIT
//! \brief Universal JIT - abstracts X86|X86_64 and AArch64 code generation. //! \brief Universal JIT abstracts X86, X86_64, and AArch64 code generation.
//!
//! ### Overview
//!
//! Universal JIT (UJIT) is an abstraction that uses AsmJit's Compiler, but provides target independent API that
//! users can use to target multiple target architectures at a time. The goal of Universal JIT is not to provide
//! its own IR. Instead, it translates user calls into target-dependent instructions (or instruction sequences)
//! and allows users to switch to target-specific assembly only where required for extra performance.
//!
//! \warning UJIT is still in an experimental phase, expect minor API breaks in the future.
//!
//! API Overview
//!
//! Compiler:
//!
//! - \ref ujit::UniCompiler - UniCompiler that wraps an existing \ref ujit::BackendCompiler.
//! - \ref ujit::BackendCompiler - alias of a platform-dependent Compiler (\ref x86::Compiler or \ref a64::Compiler).
//!
//! Operands:
//!
//! - \ref ujit::Gp - alias of a platform-dependent general-purpose register (\ref x86::Gp, \ref a64::Gp).
//! - \ref ujit::Vec - alias of a platform-dependent vector register (\ref x86::Vec, \ref a64::Vec).
//! - \ref ujit::Mem - alias of a platform-dependent memory operand (\ref x86::Mem, \ref a64::Mem).
//!
//! Conditions:
//!
//! - \ref ujit::CondCode - alias of a platform-dependent condition code (\ref x86::CondCode, a64::CondCode).
//! - \ref ujit::UniCondition - platform-independent condition representation that can be used with some ujit
//! instructions.
//!
//! Instructions:
//!
//! - \ref ujit::UniOpCond - instruction that can be used by \ref ujit::UniCondition.
//! - \ref ujit::UniOpM - instruction with a single `[mem]` operand.
//! - \ref ujit::UniOpRM - instruction with `[reg, mem]` operands.
//! - \ref ujit::UniOpMR - instruction with `[mem, reg]` operands.
//! - \ref ujit::UniOpRR - instruction with `[reg, reg]` operands.
//! - \ref ujit::UniOpRRR - instruction with `[reg, reg, reg]` operands.
//! - \ref ujit::UniOpVR - instruction with `[vec, reg]` operands.
//! - \ref ujit::UniOpVM - instruction with `[vec, mem]` operands.
//! - \ref ujit::UniOpMV - instruction with `[mem, vec]` operands.
//! - \ref ujit::UniOpVV - instruction with `[vec, vec]` operands.
//! - \ref ujit::UniOpVVI - instruction with `[vec, vec, imm]` operands.
//! - \ref ujit::UniOpVVV - instruction with `[vec, vec, vec]` operands.
//! - \ref ujit::UniOpVVVI - instruction with `[vec, vec, vec, imm]` operands.
//! - \ref ujit::UniOpVVVV - instruction with `[vec, vec, vec, vec]` operands.
//! \cond INTERNAL //! \cond INTERNAL
//! \defgroup asmjit_ra RA //! \defgroup asmjit_ra RA
@@ -2122,7 +2164,16 @@ namespace asmjit {
} // {asmjit} } // {asmjit}
#include "asmjit-scope-begin.h" #include "asmjit-scope-begin.h"
#include "core/api-config.h"
#include "core/archcommons.h"
#include "core/archtraits.h" #include "core/archtraits.h"
#include "core/arena.h"
#include "core/arenahash.h"
#include "core/arenalist.h"
#include "core/arenapool.h"
#include "core/arenastring.h"
#include "core/arenatree.h"
#include "core/arenavector.h"
#include "core/assembler.h" #include "core/assembler.h"
#include "core/builder.h" #include "core/builder.h"
#include "core/codebuffer.h" #include "core/codebuffer.h"
@@ -2149,13 +2200,6 @@ namespace asmjit {
#include "core/target.h" #include "core/target.h"
#include "core/type.h" #include "core/type.h"
#include "core/virtmem.h" #include "core/virtmem.h"
#include "core/arena.h"
#include "core/arenahash.h"
#include "core/arenalist.h"
#include "core/arenapool.h"
#include "core/arenatree.h"
#include "core/arenastring.h"
#include "core/arenavector.h"
#include "asmjit-scope-end.h" #include "asmjit-scope-end.h"
#endif // ASMJIT_CORE_H_INCLUDED #endif // ASMJIT_CORE_H_INCLUDED

View File

@@ -68,7 +68,7 @@
// Include a unit testing package if this is a `asmjit_test_unit` build. // Include a unit testing package if this is a `asmjit_test_unit` build.
#if defined(ASMJIT_TEST) #if defined(ASMJIT_TEST)
#include "../../../test/broken.h" #include "../../../testing/tests/broken.h"
#endif #endif
#endif // ASMJIT_CORE_API_BUILD_P_H_INCLUDED #endif // ASMJIT_CORE_API_BUILD_P_H_INCLUDED

View File

@@ -16,7 +16,7 @@
#define ASMJIT_LIBRARY_MAKE_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch)) #define ASMJIT_LIBRARY_MAKE_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
//! AsmJit library version, see \ref ASMJIT_LIBRARY_MAKE_VERSION for a version format reference. //! AsmJit library version, see \ref ASMJIT_LIBRARY_MAKE_VERSION for a version format reference.
#define ASMJIT_LIBRARY_VERSION ASMJIT_LIBRARY_MAKE_VERSION(1, 18, 1) #define ASMJIT_LIBRARY_VERSION ASMJIT_LIBRARY_MAKE_VERSION(1, 19, 0)
//! \def ASMJIT_ABI_NAMESPACE //! \def ASMJIT_ABI_NAMESPACE
//! //!
@@ -27,7 +27,7 @@
//! AsmJit default, which makes it possible to use multiple AsmJit libraries within a single project, totally //! AsmJit default, which makes it possible to use multiple AsmJit libraries within a single project, totally
//! controlled by users. This is useful especially in cases in which some of such library comes from third party. //! controlled by users. This is useful especially in cases in which some of such library comes from third party.
#if !defined(ASMJIT_ABI_NAMESPACE) #if !defined(ASMJIT_ABI_NAMESPACE)
#define ASMJIT_ABI_NAMESPACE v1_18 #define ASMJIT_ABI_NAMESPACE v1_19
#endif // !ASMJIT_ABI_NAMESPACE #endif // !ASMJIT_ABI_NAMESPACE
//! \} //! \}

View File

@@ -21,8 +21,6 @@
#include "../core/support.h" #include "../core/support.h"
#include "../core/type.h" #include "../core/type.h"
#define ASMJIT_NO_NODE_USERDATA
ASMJIT_BEGIN_NAMESPACE ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_builder //! \addtogroup asmjit_builder

View File

@@ -259,7 +259,7 @@ Error BaseCompiler::new_virt_reg(Out<VirtReg*> out, TypeId type_id, OperandSigna
return Error::kOk; return Error::kOk;
} }
Error BaseCompiler::_new_reg(Out<Reg> out, TypeId type_id, const char* name) { Error BaseCompiler::_new_reg_with_name(Out<Reg> out, TypeId type_id, const char* name) {
OperandSignature reg_signature; OperandSignature reg_signature;
out->reset(); out->reset();
@@ -276,7 +276,7 @@ Error BaseCompiler::_new_reg(Out<Reg> out, TypeId type_id, const char* name) {
return Error::kOk; return Error::kOk;
} }
Error BaseCompiler::_new_reg(Out<Reg> out, const Reg& ref, const char* name) { Error BaseCompiler::_new_reg_with_name(Out<Reg> out, const Reg& ref, const char* name) {
out->reset(); out->reset();
OperandSignature reg_signature; OperandSignature reg_signature;
@@ -351,7 +351,7 @@ Error BaseCompiler::_new_reg(Out<Reg> out, const Reg& ref, const char* name) {
return Error::kOk; return Error::kOk;
} }
Error BaseCompiler::_new_reg_fmt(Out<Reg> out, TypeId type_id, const char* fmt, ...) { Error BaseCompiler::_new_reg_with_vfmt(Out<Reg> out, TypeId type_id, const char* fmt, ...) {
va_list ap; va_list ap;
StringTmp<256> sb; StringTmp<256> sb;
@@ -362,7 +362,7 @@ Error BaseCompiler::_new_reg_fmt(Out<Reg> out, TypeId type_id, const char* fmt,
return _new_reg(out, type_id, sb.data()); return _new_reg(out, type_id, sb.data());
} }
Error BaseCompiler::_new_reg_fmt(Out<Reg> out, const Reg& ref, const char* fmt, ...) { Error BaseCompiler::_new_reg_with_vfmt(Out<Reg> out, const Reg& ref, const char* fmt, ...) {
va_list ap; va_list ap;
StringTmp<256> sb; StringTmp<256> sb;

View File

@@ -152,26 +152,86 @@ public:
//! Creates a new virtual register representing the given `type_id` and `signature`. //! Creates a new virtual register representing the given `type_id` and `signature`.
//! //!
//! \note This function is public, but it's not generally recommended to be used by AsmJit users, use architecture //! \note This function is public, but it's not generally recommended to be used by AsmJit users, use `new_reg()`,
//! specific `new_reg()` functionality instead or functions like \ref _new_reg() and \ref _new_reg_fmt(). //! `new_similar_reg()`, and architecture specific functions like \ref x86::Compiler::new_gp32(), etc...
ASMJIT_API Error new_virt_reg(Out<VirtReg*> out, TypeId type_id, OperandSignature signature, const char* name); ASMJIT_API Error new_virt_reg(Out<VirtReg*> out, TypeId type_id, OperandSignature signature, const char* name);
//! \cond INTERNAL
//! Creates a new virtual register of the given `type_id` and stores it to `out` operand. //! Creates a new virtual register of the given `type_id` and stores it to `out` operand.
ASMJIT_API Error _new_reg(Out<Reg> out, TypeId type_id, const char* name = nullptr); ASMJIT_API Error _new_reg_with_name(Out<Reg> out, TypeId type_id, const char* name);
//! Creates a new virtual register compatible with the provided reference register `ref`. //! Creates a new virtual register compatible with the provided reference register `ref`.
ASMJIT_API Error _new_reg(Out<Reg> out, const Reg& ref, const char* name = nullptr); ASMJIT_API Error _new_reg_with_name(Out<Reg> out, const Reg& ref, const char* name);
//! Creates a new virtual register of the given `type_id` and stores it to `out` operand. //! Creates a new virtual register of the given `type_id` and stores it to `out` operand.
//! //!
//! \note This version accepts a snprintf() format `fmt` followed by variadic arguments. //! \note This version accepts a snprintf() format `fmt` followed by variadic arguments.
ASMJIT_API Error _new_reg_fmt(Out<Reg> out, TypeId type_id, const char* fmt, ...); ASMJIT_API Error _new_reg_with_vfmt(Out<Reg> out, TypeId type_id, const char* fmt, ...);
//! \overload
ASMJIT_INLINE Error _new_reg_fmt(Out<Reg> out, TypeId type_id) { return _new_reg(out, type_id); }
//! Creates a new virtual register compatible with the provided reference register `ref`. //! Creates a new virtual register compatible with the provided reference register `ref`.
//! //!
//! \note This version accepts a snprintf() format `fmt` followed by variadic arguments. //! \note This version accepts a snprintf() format `fmt` followed by variadic arguments.
ASMJIT_API Error _new_reg_fmt(Out<Reg> out, const Reg& ref, const char* fmt, ...); ASMJIT_API Error _new_reg_with_vfmt(Out<Reg> out, const Reg& ref, const char* fmt, ...);
template<typename RegT>
ASMJIT_INLINE Error _new_reg(Out<RegT> out, TypeId type_id) {
return _new_reg_with_name(Out<Reg>(out.value()), type_id, nullptr);
}
template<typename RegT, typename... Args>
ASMJIT_INLINE Error _new_reg(Out<RegT> out, TypeId type_id, const char* name_or_fmt, Args&&... args) {
#ifndef ASMJIT_NO_LOGGING
if constexpr (sizeof...(args) == 0u) {
return _new_reg_with_name(Out<Reg>(out.value()), type_id, name_or_fmt);
}
else {
return _new_reg_with_vfmt(Out<Reg>(out.value()), type_id, name_or_fmt, std::forward<Args>(args)...);
}
#else
Support::maybe_unused(name_or_fmt, std::forward<Args>(args)...);
return _new_reg_with_name(Out<Reg>(out.value()), type_id, nullptr);
#endif
}
template<typename RegT>
ASMJIT_INLINE Error _new_reg(Out<RegT> out, const Reg& ref) {
return _new_reg_with_name(Out<Reg>(out.value()), ref, nullptr);
}
template<typename RegT, typename... Args>
ASMJIT_INLINE Error _new_reg(Out<RegT> out, const Reg& ref, const char* name_or_fmt, Args&&... args) {
#ifndef ASMJIT_NO_LOGGING
if constexpr (sizeof...(args) == 0u) {
return _new_reg_with_name(Out<Reg>(out.value()), ref, name_or_fmt);
}
else {
return _new_reg_with_vfmt(Out<Reg>(out.value()), ref, name_or_fmt, std::forward<Args>(args)...);
}
#else
Support::maybe_unused(name_or_fmt, std::forward<Args>(args)...);
return _new_reg_with_name(Out<Reg>(out.value()), ref, nullptr);
#endif
}
//! \endcond
template<typename RegT, typename... Args>
ASMJIT_INLINE_NODEBUG RegT new_reg(TypeId type_id, Args&&... args) {
RegT reg(Globals::NoInit);
(void)_new_reg<RegT>(Out(reg), type_id, std::forward<Args>(args)...);
return reg;
}
//! Creates and returns a new register, which is similar to `ref` in terms of size and type.
//!
//! \note Optionally you can provide a name and format parameters via `args`.
template<typename RegT, typename... Args>
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref, Args&&... args) {
RegT reg(Globals::NoInit);
(void)_new_reg<RegT>(Out(reg), ref, std::forward<Args>(args)...);
return reg;
}
//! Tests whether the given `virt_id` is a valid virtual register id. //! Tests whether the given `virt_id` is a valid virtual register id.
[[nodiscard]] [[nodiscard]]

View File

@@ -593,6 +593,98 @@ static ASMJIT_FAVOR_SIZE void detect_x86_cpu(CpuInfo& cpu) noexcept {
simplify_cpu_brand(cpu._brand.str); simplify_cpu_brand(cpu._brand.str);
} }
static ASMJIT_FAVOR_SIZE CpuHints recalculate_hints(const CpuInfo& cpu_info, const CpuFeatures::X86& features) noexcept {
CpuHints hints {};
// Vendor Independent CPU Hints
// ----------------------------
if (features.has_avx2()) {
hints |= CpuHints::kVecMaskedOps32 | CpuHints::kVecMaskedOps64;
}
if (features.has_avx512_bw()) {
hints |= CpuHints::kVecMaskedOps8 | CpuHints::kVecMaskedOps16 | CpuHints::kVecMaskedOps32 | CpuHints::kVecMaskedOps64;
}
// Select optimization flags based on CPU vendor and micro-architecture.
// AMD Specific CPU Hints
// ----------------------
if (cpu_info.is_vendor("AMD")) {
// Zen 3+ has fast gathers, scalar loads and shuffles are faster on Zen 2 and older CPUs.
if (cpu_info.family_id() >= 0x19u) {
hints |= CpuHints::kVecFastGather;
}
// Zen 1+ provides low-latency VPMULLD instruction.
if (features.has_avx2()) {
hints |= CpuHints::kVecFastIntMul32;
}
// Zen 4+ provides low-latency VPMULLQ instruction.
if (features.has_avx512_dq()) {
hints |= CpuHints::kVecFastIntMul64;
}
// Zen 4+ has fast mask operations (starts with AVX-512).
if (features.has_avx512_f()) {
hints |= CpuHints::kVecMaskedStore;
}
}
// Intel Specific CPU Hints
// ------------------------
if (cpu_info.is_vendor("INTEL")) {
if (features.has_avx2()) {
uint32_t family_id = cpu_info.family_id();
uint32_t model_id = cpu_info.model_id();
// NOTE: We only want to hint fast gathers in cases the CPU is immune to DOWNFALL. The reason is that the
// DOWNFALL mitigation delivered via a micro-code update makes gathers almost useless in a way that scalar
// loads can beat it significantly (in Blend2D case scalar loads can offer up to 50% more performance).
// This table basically picks CPUs that are known to not be affected by DOWNFALL.
if (family_id == 0x06u) {
switch (model_id) {
case 0x8Fu: // Sapphire Rapids.
case 0x96u: // Elkhart Lake.
case 0x97u: // Alder Lake / Catlow.
case 0x9Au: // Alder Lake / Arizona Beach.
case 0x9Cu: // Jasper Lake.
case 0xAAu: // Meteor Lake.
case 0xACu: // Meteor Lake.
case 0xADu: // Granite Rapids.
case 0xAEu: // Granite Rapids.
case 0xAFu: // Sierra Forest.
case 0xBAu: // Raptor Lake.
case 0xB5u: // Arrow Lake.
case 0xB6u: // Grand Ridge.
case 0xB7u: // Raptor Lake / Catlow.
case 0xBDu: // Lunar Lake.
case 0xBEu: // Alder Lake (N).
case 0xBFu: // Raptor Lake.
case 0xC5u: // Arrow Lake.
case 0xC6u: // Arrow Lake.
case 0xCFu: // Emerald Rapids.
case 0xDDu: // Clearwater Forest.
hints |= CpuHints::kVecFastGather;
break;
default:
break;
}
}
}
// TODO: It seems masked stores are very expensive on consumer INTEL CPUs.
// hints |= CpuHints::kVecMaskedStore;
}
return hints;
}
} // {x86} } // {x86}
#endif // ASMJIT_ARCH_X86 #endif // ASMJIT_ARCH_X86
@@ -2237,6 +2329,15 @@ static ASMJIT_FAVOR_SIZE void detect_arm_cpu(CpuInfo& cpu) noexcept {
} }
#endif #endif
static ASMJIT_FAVOR_SIZE CpuHints recalculate_hints(const CpuInfo& cpu_info, const CpuFeatures::ARM& features) noexcept {
Support::maybe_unused(cpu_info, features);
// Assume ARM CPUs have fast 32-bit SIMD integer multiplication.
CpuHints hints = CpuHints::kVecFastIntMul32;
return hints;
}
} // {arm} } // {arm}
#endif #endif
@@ -2261,8 +2362,9 @@ const CpuInfo& CpuInfo::host() noexcept {
#elif ASMJIT_ARCH_ARM #elif ASMJIT_ARCH_ARM
arm::detect_arm_cpu(cpu_info_local); arm::detect_arm_cpu(cpu_info_local);
#endif #endif
cpu_info_local._hw_thread_count = detect_hw_thread_count(); cpu_info_local._hw_thread_count = detect_hw_thread_count();
cpu_info_local.update_hints();
cpu_info_global = cpu_info_local; cpu_info_global = cpu_info_local;
cpu_info_initialized_flag.store(1, std::memory_order_seq_cst); cpu_info_initialized_flag.store(1, std::memory_order_seq_cst);
} }
@@ -2270,4 +2372,15 @@ const CpuInfo& CpuInfo::host() noexcept {
return cpu_info_global; return cpu_info_global;
} }
CpuHints CpuInfo::recalculate_hints(const CpuInfo& info, const CpuFeatures& features) noexcept {
#if ASMJIT_ARCH_X86
return x86::recalculate_hints(info, features.x86());
#elif ASMJIT_ARCH_ARM
return arm::recalculate_hints(info, features.arm());
#else
Support::maybe_unused(info, features);
return CpuHints::kNone;
#endif
}
ASMJIT_END_NAMESPACE ASMJIT_END_NAMESPACE

View File

@@ -525,6 +525,59 @@ public:
ASMJIT_X86_FEATURE(has_amx_transpose, kAMX_TRANSPOSE) ASMJIT_X86_FEATURE(has_amx_transpose, kAMX_TRANSPOSE)
#undef ASMJIT_X86_FEATURE #undef ASMJIT_X86_FEATURE
ASMJIT_INLINE void remove_avx() noexcept {
remove(kAVX ,
kAVX2 ,
kAVX_IFMA ,
kAVX_NE_CONVERT ,
kAVX_VNNI ,
kAVX_VNNI_INT16 ,
kAVX_VNNI_INT8 ,
kF16C ,
kFMA ,
kFMA4 ,
kVAES ,
kVPCLMULQDQ ,
kXOP);
remove_avx512();
}
ASMJIT_INLINE void remove_avx512() noexcept {
remove(kAVX512_BF16 ,
kAVX512_BITALG ,
kAVX512_BW ,
kAVX512_CD ,
kAVX512_DQ ,
kAVX512_F ,
kAVX512_FP16 ,
kAVX512_IFMA ,
kAVX512_VBMI ,
kAVX512_VBMI2 ,
kAVX512_VL ,
kAVX512_VNNI ,
kAVX512_VP2INTERSECT ,
kAVX512_VPOPCNTDQ ,
kAMX_AVX512);
remove_avx10();
}
ASMJIT_INLINE void remove_avx10() noexcept {
remove(kAVX10_1 | kAVX10_2);
}
ASMJIT_INLINE void remove_amx() noexcept {
remove(kAMX_AVX512 ,
kAMX_BF16 ,
kAMX_COMPLEX ,
kAMX_FP16 ,
kAMX_FP8 ,
kAMX_INT8 ,
kAMX_MOVRS ,
kAMX_TF32 ,
kAMX_TILE ,
kAMX_TRANSPOSE);
}
}; };
//! ARM specific features data. //! ARM specific features data.
@@ -1104,6 +1157,39 @@ public:
//! \} //! \}
}; };
//! Describe micro-architectural hints that can be used for optimization purposes and are not part of \ref CpuFeatures.
enum class CpuHints : uint32_t {
//! No honts.
kNone = 0x0u,
//! CPU provides fast 8-bit masked loads and stores.
kVecMaskedOps8 = 0x00000001u,
//! CPU provides fast 16-bit masked loads and stores.
kVecMaskedOps16 = 0x00000002u,
//! CPU provides fast 32-bit masked loads and stores.
kVecMaskedOps32 = 0x00000004u,
//! CPU provides fast 64-bit masked loads and stores.
kVecMaskedOps64 = 0x00000008u,
//! CPU provides low-latency 32-bit multiplication (AMD CPUs).
kVecFastIntMul32 = 0x00000010u,
//! CPU provides low-latency 64-bit multiplication (AMD CPUs).
kVecFastIntMul64 = 0x00000020u,
//! CPU provides fast hardware gathers, which are faster than a sequence of loads and inserts.
kVecFastGather = 0x00000040u,
//! CPU has fast stores with mask.
//!
//! \note This is a hint to the compiler to emit a masked store instead of a sequence having branches.
kVecMaskedStore = 0x00000080u
};
ASMJIT_DEFINE_ENUM_FLAGS(CpuHints)
//! CPU information. //! CPU information.
class CpuInfo { class CpuInfo {
public: public:
@@ -1142,6 +1228,9 @@ public:
//! CPU features. //! CPU features.
CpuFeatures _features {}; CpuFeatures _features {};
//! CPU hints.
CpuHints _hints {};
//! \} //! \}
//! \name Construction & Destruction //! \name Construction & Destruction
@@ -1167,6 +1256,12 @@ public:
[[nodiscard]] [[nodiscard]]
ASMJIT_API static const CpuInfo& host() noexcept; ASMJIT_API static const CpuInfo& host() noexcept;
//! Updates CPU hints based on the CPU data and features.
//!
//! \note This function is called automatically by the CPU detection logic. However, if you change the CPU features
//! in your own instance of \ref CpuInfo, CPU hints must be updated too, otherwise they would be out of sync.
ASMJIT_API static CpuHints recalculate_hints(const CpuInfo& info, const CpuFeatures& features) noexcept;
//! \} //! \}
//! \name Overloaded Operators //! \name Overloaded Operators
@@ -1298,6 +1393,16 @@ public:
template<typename... Args> template<typename... Args>
ASMJIT_INLINE_NODEBUG void remove_feature(Args&&... args) noexcept { return _features.remove(std::forward<Args>(args)...); } ASMJIT_INLINE_NODEBUG void remove_feature(Args&&... args) noexcept { return _features.remove(std::forward<Args>(args)...); }
//! Returns CPU hints.
[[nodiscard]]
ASMJIT_INLINE_NODEBUG CpuHints hints() const noexcept { return _hints; }
//! Updates CPU hints based on the CPU data and features.
//!
//! \note This function is called automatically by the CPU detection logic. However, if you change the CPU features
//! in your own instance of \ref CpuInfo, CPU hints must be updated too, otherwise they would be out of sync.
ASMJIT_INLINE void update_hints() noexcept { _hints = recalculate_hints(*this, _features); }
//! \} //! \}
}; };

View File

@@ -668,9 +668,9 @@ public:
//! \name Sections //! \name Sections
//! \{ //! \{
//! Switches the given `section`. //! Switches to the given `section`.
//! //!
//! Once switched, everything is added to the given `section`. //! Once switched, everything is emitted to `section`.
ASMJIT_API virtual Error section(Section* section); ASMJIT_API virtual Error section(Section* section);
//! \} //! \}

View File

@@ -17,7 +17,7 @@
#include "../core/virtmem.h" #include "../core/virtmem.h"
#if defined(ASMJIT_TEST) #if defined(ASMJIT_TEST)
#include "../../../test/asmjit_test_random.h" #include "../../../testing/commons/random.h"
#endif // ASMJIT_TEST #endif // ASMJIT_TEST
ASMJIT_BEGIN_NAMESPACE ASMJIT_BEGIN_NAMESPACE

View File

@@ -15,7 +15,10 @@ JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept
: _allocator(params) { : _allocator(params) {
_environment = Environment::host(); _environment = Environment::host();
_environment.set_object_format(ObjectFormat::kJIT); _environment.set_object_format(ObjectFormat::kJIT);
_cpu_features = CpuInfo::host().features();
const CpuInfo& host_cpu = CpuInfo::host();
_cpu_features = host_cpu.features();
_cpu_hints = host_cpu.hints();
} }
JitRuntime::~JitRuntime() noexcept {} JitRuntime::~JitRuntime() noexcept {}

View File

@@ -11,9 +11,7 @@
#if defined(_MSC_VER) #if defined(_MSC_VER)
#include <intrin.h> #include <intrin.h>
#endif #elif defined(__BMI2__)
#if defined(__BMI2__)
#include <x86intrin.h> #include <x86intrin.h>
#endif #endif

View File

@@ -10,7 +10,8 @@ ASMJIT_BEGIN_NAMESPACE
Target::Target() noexcept Target::Target() noexcept
: _environment{}, : _environment{},
_cpu_features{} {} _cpu_features{},
_cpu_hints{} {}
Target::~Target() noexcept {} Target::~Target() noexcept {}
ASMJIT_END_NAMESPACE ASMJIT_END_NAMESPACE

View File

@@ -25,6 +25,8 @@ public:
Environment _environment; Environment _environment;
//! Target CPU features. //! Target CPU features.
CpuFeatures _cpu_features; CpuFeatures _cpu_features;
//! Target CPU hints.
CpuHints _cpu_hints;
//! \name Construction & Destruction //! \name Construction & Destruction
//! \{ //! \{
@@ -55,6 +57,10 @@ public:
//! Returns target CPU features. //! Returns target CPU features.
ASMJIT_INLINE_NODEBUG const CpuFeatures& cpu_features() const noexcept { return _cpu_features; } ASMJIT_INLINE_NODEBUG const CpuFeatures& cpu_features() const noexcept { return _cpu_features; }
[[nodiscard]]
//! Returns target CPU hints.
ASMJIT_INLINE_NODEBUG CpuHints cpu_hints() const noexcept { return _cpu_hints; }
//! \} //! \}
}; };

View File

@@ -9,6 +9,7 @@
#include "asmjit-scope-begin.h" #include "asmjit-scope-begin.h"
#include "ujit/ujitbase.h" #include "ujit/ujitbase.h"
#include "ujit/unicompiler.h" #include "ujit/unicompiler.h"
#include "ujit/unicondition.h"
#include "ujit/uniop.h" #include "ujit/uniop.h"
#include "ujit/vecconsttable.h" #include "ujit/vecconsttable.h"
#include "asmjit-scope-end.h" #include "asmjit-scope-end.h"

View File

@@ -14,23 +14,35 @@
#if !defined(ASMJIT_NO_UJIT) #if !defined(ASMJIT_NO_UJIT)
//! \namespace asmjit::ujit
//! \ingroup asmjit_ujit
//!
//! Namespace that provides all UJIT (Universal JIT) functionality.
ASMJIT_BEGIN_SUB_NAMESPACE(ujit) ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
//! \addtogroup asmjit_ujit //! \addtogroup asmjit_ujit
//! \{ //! \{
//! Backend compiler is simply an alias to a `host::Compiler`, which would be used by \ref UniCompiler.
using BackendCompiler = host::Compiler; using BackendCompiler = host::Compiler;
//! Condition code is simply an alias to a `host::CondCode`.
using CondCode = host::CondCode; using CondCode = host::CondCode;
//! Target memory operand.
using Mem = host::Mem; using Mem = host::Mem;
//! Target general-purpose register.
using Gp = host::Gp; using Gp = host::Gp;
//! Target vector register.
using Vec = host::Vec; using Vec = host::Vec;
#if defined(ASMJIT_UJIT_X86) #if defined(ASMJIT_UJIT_X86)
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Label& label, int32_t disp = 0) noexcept { return x86::ptr(label, disp); }
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, int32_t disp = 0) noexcept { return x86::ptr(base, disp); } static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, int32_t disp = 0) noexcept { return x86::ptr(base, disp); }
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t disp = 0) noexcept { return x86::ptr(base, index, shift, disp); } static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32_t shift = 0, int32_t disp = 0) noexcept { return x86::ptr(base, index, shift, disp); }
#endif #endif
#if defined(ASMJIT_UJIT_AARCH64) #if defined(ASMJIT_UJIT_AARCH64)
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Label& label, int32_t disp = 0) noexcept { return a64::ptr(label, disp); }
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, int32_t disp = 0) noexcept { return a64::ptr(base, disp); } static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, int32_t disp = 0) noexcept { return a64::ptr(base, disp); }
static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32_t shift = 0) noexcept { return a64::ptr(base, index, a64::lsl(shift)); } static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32_t shift = 0) noexcept { return a64::ptr(base, index, a64::lsl(shift)); }
#endif #endif
@@ -38,6 +50,7 @@ static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32
// Types & Enums // Types & Enums
// ------------- // -------------
//! Data alignment.
enum class Alignment : uint32_t {}; enum class Alignment : uint32_t {};
//! The behavior of a floating point scalar operation. //! The behavior of a floating point scalar operation.
@@ -48,6 +61,16 @@ enum class ScalarOpBehavior : uint8_t {
kPreservingVec128 kPreservingVec128
}; };
//! The behavior of floating point to int conversion.
enum class FloatToIntOutsideRangeBehavior : uint8_t {
//! In case that the floating point is outside of the integer range, the value is the smallest integer value,
//! which would be `0x80`, `0x8000`, `0x80000000`, or `0x8000000000000000` depending on the target integer width.
kSmallestValue,
//! In case that the floating point is outside of the integer range, the resulting integer will be saturated. If
//! the floating point is NaN, the resulting integer value would be zero.
kSaturatedValue
};
//! The behavior of a floating point min/max instructions when comparing against NaN. //! The behavior of a floating point min/max instructions when comparing against NaN.
enum class FMinFMaxOpBehavior : uint8_t { enum class FMinFMaxOpBehavior : uint8_t {
//! Min and max selects a finite value if one of the compared values is NaN. //! Min and max selects a finite value if one of the compared values is NaN.
@@ -68,16 +91,21 @@ enum class FMAddOpBehavior : uint8_t {
//! SIMD data width. //! SIMD data width.
enum class DataWidth : uint8_t { enum class DataWidth : uint8_t {
//! 8-bit elements.
k8 = 0, k8 = 0,
//! 16-bit elements.
k16 = 1, k16 = 1,
//! 32-bit elements.
k32 = 2, k32 = 2,
//! 64-bit elements or 64-bit wide data is used.
k64 = 3, k64 = 3,
//! 128-bit elements or 128-bit wide data is used.
k128 = 4 k128 = 4
}; };
//! Vector register width. //! Vector register width.
enum class VecWidth : uint8_t { enum class VecWidth : uint8_t {
//! 128-bit vector register (baseline, SSE/AVX, NEON, ASIMD, etc...). //! 128-bit vector register (baseline, SSE/AVX, NEON, etc...).
k128 = 0, k128 = 0,
//! 256-bit vector register (AVX2+). //! 256-bit vector register (AVX2+).
k256 = 1, k256 = 1,
@@ -89,9 +117,13 @@ enum class VecWidth : uint8_t {
//! Broadcast width. //! Broadcast width.
enum class Bcst : uint8_t { enum class Bcst : uint8_t {
//! Broadcast 8-bit elements.
k8 = 0, k8 = 0,
//! Broadcast 16-bit elements.
k16 = 1, k16 = 1,
//! Broadcast 32-bit elements.
k32 = 2, k32 = 2,
//! Broadcast 64-bit elements.
k64 = 3, k64 = 3,
kNA = 0xFE, kNA = 0xFE,
@@ -104,7 +136,7 @@ static ASMJIT_INLINE OperandSignature signature_of(VecWidth vw) noexcept {
RegType reg_type = RegType(uint32_t(RegType::kVec128) + uint32_t(vw)); RegType reg_type = RegType(uint32_t(RegType::kVec128) + uint32_t(vw));
uint32_t reg_size = 16u << uint32_t(vw); uint32_t reg_size = 16u << uint32_t(vw);
return OperandSignature::from_reg_type_and_group(reg_type, RegGroup::kVec) | OperandSignature::from_size(reg_size); return OperandSignature::from_op_type(OperandType::kReg) | OperandSignature::from_reg_type_and_group(reg_type, RegGroup::kVec) | OperandSignature::from_size(reg_size);
} }
static ASMJIT_INLINE TypeId type_id_of(VecWidth vw) noexcept { static ASMJIT_INLINE TypeId type_id_of(VecWidth vw) noexcept {
@@ -143,7 +175,7 @@ static ASMJIT_INLINE Vec clone_vec_as(const Vec& src, VecWidth vw) noexcept {
// AsmJit Helpers // AsmJit Helpers
// ============== // ==============
//! Operand array used by SIMD pipeline. //! Operand array, mostly used for code generation that uses SIMD.
//! //!
//! Can hold up to `kMaxSize` registers, however, the number of actual registers is dynamic and depends //! Can hold up to `kMaxSize` registers, however, the number of actual registers is dynamic and depends
//! on initialization. //! on initialization.
@@ -151,12 +183,15 @@ class OpArray {
public: public:
using Op = Operand_; using Op = Operand_;
//! Maximum number of active operands `OpArray` can hold.
static inline constexpr size_t kMaxSize = 8; static inline constexpr size_t kMaxSize = 8;
//! \name Members //! \name Members
//! \{ //! \{
//! Number of operands in OpArray
size_t _size; size_t _size;
//! Underlying operand array.
Operand_ v[kMaxSize]; Operand_ v[kMaxSize];
//! \} //! \}
@@ -405,6 +440,16 @@ public:
ASMJIT_INLINE_NODEBUG OpArray even_odd(size_t from) const noexcept { return OpArray(*this, _size > 1u ? from : size_t(0), 2u, _size); } ASMJIT_INLINE_NODEBUG OpArray even_odd(size_t from) const noexcept { return OpArray(*this, _size > 1u ? from : size_t(0), 2u, _size); }
}; };
//! Vector operand array.
//!
//! Used to model SIMD code generation where the code generator can use up to \ref OpArray::kMaxSize registers per
//! `VecArray`. The advantage of `VecArray` is that it allows to parametrize the ideal number of registers at runtime
//! and to use a single code-path to generate advanced SIMD code.
//!
//! In addition, \ref UniCompiler fully understands `VecArray` so it can be passed instead of a regular operand when
//! emitting code, which greatly simplifies designing high-performance SIMD code.
//!
//! \note VecArray is like \ref OpArray, just the whole API works with \ref Vec instead of \ref Operand_.
class VecArray : public OpArray { class VecArray : public OpArray {
public: public:
//! \name Construction & Destruction //! \name Construction & Destruction
@@ -587,7 +632,7 @@ static ASMJIT_INLINE void reset_var_array(T* array, size_t size) noexcept {
template<typename T> template<typename T>
static ASMJIT_INLINE void reset_var_struct(T* data, size_t size = sizeof(T)) noexcept { static ASMJIT_INLINE void reset_var_struct(T* data, size_t size = sizeof(T)) noexcept {
reset_var_array(reinterpret_cast<asmjit::Reg*>(data), size / sizeof(asmjit::Reg)); reset_var_array(reinterpret_cast<Reg*>(data), size / sizeof(Reg));
} }
static ASMJIT_INLINE_NODEBUG const Operand_& first_op(const Operand_& operand) noexcept { return operand; } static ASMJIT_INLINE_NODEBUG const Operand_& first_op(const Operand_& operand) noexcept { return operand; }
@@ -615,10 +660,12 @@ struct Swizzle4 {
ASMJIT_INLINE_CONSTEXPR bool operator!=(const Swizzle4& other) const noexcept { return value != other.value; } ASMJIT_INLINE_CONSTEXPR bool operator!=(const Swizzle4& other) const noexcept { return value != other.value; }
}; };
//! Constructs a backend-independent 2-element vector swizzle parameter.
static ASMJIT_INLINE_CONSTEXPR Swizzle2 swizzle(uint8_t b, uint8_t a) noexcept { static ASMJIT_INLINE_CONSTEXPR Swizzle2 swizzle(uint8_t b, uint8_t a) noexcept {
return Swizzle2{(uint32_t(b) << 8) | a}; return Swizzle2{(uint32_t(b) << 8) | a};
} }
//! Constructs a backend-independent 4-element vector swizzle parameter.
static ASMJIT_INLINE_CONSTEXPR Swizzle4 swizzle(uint8_t d, uint8_t c, uint8_t b, uint8_t a) noexcept { static ASMJIT_INLINE_CONSTEXPR Swizzle4 swizzle(uint8_t d, uint8_t c, uint8_t b, uint8_t a) noexcept {
return Swizzle4{(uint32_t(d) << 24) | (uint32_t(c) << 16) | (uint32_t(b) << 8) | a}; return Swizzle4{(uint32_t(d) << 24) | (uint32_t(c) << 16) | (uint32_t(b) << 8) | a};
} }
@@ -631,6 +678,9 @@ enum class Perm2x128 : uint32_t {
kZero = 8 kZero = 8
}; };
//! Constructs a backend-independent permutation of 128-bit lanes.
//!
//! \note This is currently only used by AVX2 and AVX-512 backends.
static ASMJIT_INLINE_CONSTEXPR uint8_t perm_2x128_imm(Perm2x128 hi, Perm2x128 lo) noexcept { static ASMJIT_INLINE_CONSTEXPR uint8_t perm_2x128_imm(Perm2x128 hi, Perm2x128 lo) noexcept {
return uint8_t((uint32_t(hi) << 4) | (uint32_t(lo))); return uint8_t((uint32_t(hi) << 4) | (uint32_t(lo)));
} }

View File

@@ -17,159 +17,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
//! \addtogroup asmjit_ujit //! \addtogroup asmjit_ujit
//! \{ //! \{
//! Condition represents either a condition or an assignment operation that can be checked. class UniCondition;
class Condition {
public:
//! \name Members
//! \{
UniOpCond op; //! Universal compiler.
CondCode cond;
Operand a;
Operand b;
//! \}
//! \name Construction & Destruction
//! \{
ASMJIT_INLINE_NODEBUG Condition(UniOpCond op, CondCode cond, const Operand& a, const Operand& b) noexcept
: op(op),
cond(cond),
a(a),
b(b) {}
ASMJIT_INLINE_NODEBUG Condition(const Condition& other) noexcept = default;
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_NODEBUG Condition& operator=(const Condition& other) noexcept = default;
//! \}
};
static ASMJIT_INLINE Condition and_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition and_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition and_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition and_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition and_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition and_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition or_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition or_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition or_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition or_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition or_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition or_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition xor_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition xor_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition xor_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition xor_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition xor_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition xor_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition add_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition add_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition add_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition add_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition add_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition add_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition add_c(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
static ASMJIT_INLINE Condition add_c(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
static ASMJIT_INLINE Condition add_c(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
static ASMJIT_INLINE Condition add_nc(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
static ASMJIT_INLINE Condition add_nc(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
static ASMJIT_INLINE Condition add_nc(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
static ASMJIT_INLINE Condition add_s(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition add_s(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition add_s(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition add_ns(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition add_ns(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition add_ns(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition sub_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition sub_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition sub_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition sub_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition sub_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition sub_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition sub_c(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition sub_c(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition sub_c(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition sub_nc(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition sub_nc(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition sub_nc(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition sub_s(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition sub_s(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition sub_s(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
static ASMJIT_INLINE Condition sub_ns(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition sub_ns(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition sub_ns(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE Condition sub_ugt(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition sub_ugt(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition sub_ugt(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition shr_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition shr_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition shr_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition shr_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition shr_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition shr_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition cmp_eq(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
static ASMJIT_INLINE Condition cmp_eq(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
static ASMJIT_INLINE Condition cmp_eq(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
static ASMJIT_INLINE Condition cmp_ne(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
static ASMJIT_INLINE Condition cmp_ne(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
static ASMJIT_INLINE Condition cmp_ne(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
static ASMJIT_INLINE Condition scmp_lt(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
static ASMJIT_INLINE Condition scmp_lt(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
static ASMJIT_INLINE Condition scmp_lt(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
static ASMJIT_INLINE Condition scmp_le(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
static ASMJIT_INLINE Condition scmp_le(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
static ASMJIT_INLINE Condition scmp_le(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
static ASMJIT_INLINE Condition scmp_gt(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
static ASMJIT_INLINE Condition scmp_gt(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
static ASMJIT_INLINE Condition scmp_gt(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
static ASMJIT_INLINE Condition scmp_ge(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
static ASMJIT_INLINE Condition scmp_ge(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
static ASMJIT_INLINE Condition scmp_ge(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
static ASMJIT_INLINE Condition ucmp_lt(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition ucmp_lt(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition ucmp_lt(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
static ASMJIT_INLINE Condition ucmp_le(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
static ASMJIT_INLINE Condition ucmp_le(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
static ASMJIT_INLINE Condition ucmp_le(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
static ASMJIT_INLINE Condition ucmp_gt(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition ucmp_gt(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition ucmp_gt(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE Condition ucmp_ge(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition ucmp_ge(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition ucmp_ge(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
static ASMJIT_INLINE Condition test_z(const Gp& a) noexcept { return Condition(UniOpCond::kCompare, CondCode::kEqual, a, Imm(0)); }
static ASMJIT_INLINE Condition test_nz(const Gp& a) noexcept { return Condition(UniOpCond::kCompare, CondCode::kNotEqual, a, Imm(0)); }
static ASMJIT_INLINE Condition test_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition test_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition test_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kZero, a, b); }
static ASMJIT_INLINE Condition test_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition test_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition test_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
static ASMJIT_INLINE Condition bt_z(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
static ASMJIT_INLINE Condition bt_z(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
static ASMJIT_INLINE Condition bt_z(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
static ASMJIT_INLINE Condition bt_nz(const Gp& a, const Gp& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
static ASMJIT_INLINE Condition bt_nz(const Gp& a, const Mem& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
static ASMJIT_INLINE Condition bt_nz(const Gp& a, const Imm& b) noexcept { return Condition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
//! Pipeline compiler.
class UniCompiler { class UniCompiler {
public: public:
ASMJIT_NONCOPYABLE(UniCompiler) ASMJIT_NONCOPYABLE(UniCompiler)
@@ -285,7 +135,10 @@ public:
//! AsmJit compiler. //! AsmJit compiler.
BackendCompiler* cc = nullptr; BackendCompiler* cc = nullptr;
const VecConstTable& ct; //! Reference to a table that provides global constants.
//!
//! \note This table can be extended by users so it fits a particular use-case, see \ref UniCompiler constructor.
VecConstTableRef _ct_ref;
#if defined(ASMJIT_UJIT_X86) #if defined(ASMJIT_UJIT_X86)
//! General purpose extension mask (X86 and X86_64 only). //! General purpose extension mask (X86 and X86_64 only).
@@ -306,14 +159,16 @@ public:
//! The behavior of scalar operations (mostly floating point). //! The behavior of scalar operations (mostly floating point).
ScalarOpBehavior _scalar_op_behavior {}; ScalarOpBehavior _scalar_op_behavior {};
//! The behavior of floating point min/max operation. //! The behavior of floating point min/max operation.
FMinFMaxOpBehavior _fmin_fmax_op_hehavior {}; FMinFMaxOpBehavior _fmin_fmax_op_behavior {};
//! The behavior of floating point `madd` operation. //! The behavior of floating point `madd` operation.
FMAddOpBehavior _fmadd_op_behavior {}; FMAddOpBehavior _fmadd_op_behavior {};
//! The behavior of a float-to-int conversion when the float is out of integer range, infinite, or NaN.
FloatToIntOutsideRangeBehavior _float_to_int_outside_range_behavior {};
//! Target CPU features. //! Target CPU features.
CpuFeatures _features {}; CpuFeatures _features {};
//! Optimization flags. //! Optimization flags.
UniOptFlags _opt_flags = UniOptFlags::kNone; CpuHints _cpu_hints {};
//! Number of available vector registers. //! Number of available vector registers.
uint32_t _vec_reg_count = 0; uint32_t _vec_reg_count = 0;
@@ -323,20 +178,20 @@ public:
//! SIMD multiplier, derived from `_vec_width` (1, 2, 4). //! SIMD multiplier, derived from `_vec_width` (1, 2, 4).
uint8_t _vec_multiplier = 0; uint8_t _vec_multiplier = 0;
//! SIMD register type (AsmJit). //! SIMD register type (AsmJit).
asmjit::RegType _vec_reg_type = asmjit::RegType::kNone; RegType _vec_reg_type = RegType::kNone;
//! SIMD type id (AsmJit). //! SIMD type id (AsmJit).
asmjit::TypeId _vec_type_id = asmjit::TypeId::kVoid; TypeId _vec_type_id = TypeId::kVoid;
//! Function node. //! Function node.
asmjit::FuncNode* _func_node = nullptr; FuncNode* _func_node = nullptr;
//! Function initialization hook. //! Function initialization hook.
asmjit::BaseNode* _func_init = nullptr; BaseNode* _func_init = nullptr;
//! Function end hook (to add 'unlikely' branches). //! Function end hook (to add 'unlikely' branches).
asmjit::BaseNode* _func_end = nullptr; BaseNode* _func_end = nullptr;
//! Invalid GP register. //! Invalid GP register.
Gp _gp_none; Gp _gp_none;
//! Temporary stack used to transfer SIMD regs to GP/MM. //! Temporary stack used to transfer SIMD regs to GP.
Mem _tmp_stack[size_t(StackId::kMaxValue) + 1]; Mem _tmp_stack[size_t(StackId::kMaxValue) + 1];
//! Offset to the first constant to the `commonTable` global. //! Offset to the first constant to the `commonTable` global.
@@ -359,15 +214,22 @@ public:
uint32_t virt_reg_id; uint32_t virt_reg_id;
}; };
asmjit::ArenaVector<VecConstData> _vec_consts; ArenaVector<VecConstData> _vec_consts;
asmjit::ArenaVector<VecConstDataEx> _vec_consts_ex; ArenaVector<VecConstDataEx> _vec_consts_ex;
//! \} //! \}
//! \name Construction & Destruction //! \name Construction & Destruction
//! \{ //! \{
ASMJIT_API UniCompiler(BackendCompiler* cc, const CpuFeatures& features, UniOptFlags opt_flags) noexcept; //! Creates `UniCompiler` that would use the existing BackendCompiler (it would keep the pointer to it).
ASMJIT_API UniCompiler(BackendCompiler* cc, const CpuFeatures& features, CpuHints cpu_hints, VecConstTableRef ct_ref) noexcept;
//! Creates `UniCompiler` that would use the existing BackendCompiler (it would keep the pointer to it).
ASMJIT_INLINE UniCompiler(BackendCompiler* cc, const CpuFeatures& features, CpuHints cpu_hints) noexcept
: UniCompiler(cc, features, cpu_hints, VecConstTableRef{vec_const_table, sizeof(VecConstTable)}) {}
//! Destroys `UniCompiler` - the existing BackendCompiler would be untouched.
ASMJIT_API ~UniCompiler() noexcept; ASMJIT_API ~UniCompiler() noexcept;
//! \} //! \}
@@ -375,22 +237,39 @@ public:
//! \name Allocators //! \name Allocators
//! \{ //! \{
ASMJIT_INLINE_NODEBUG asmjit::Arena& arena() noexcept { return cc->_builder_arena; } //! Returns the arena used by `UniCompiler`.
ASMJIT_INLINE_NODEBUG Arena& arena() noexcept { return cc->_builder_arena; }
//! \}
//! \name Constant Table
//! \{
template<typename T = VecConstTable>
ASMJIT_INLINE_NODEBUG const T& ct() const noexcept { return static_cast<const T&>(_ct_ref.table); }
template<typename T = VecConstTable>
ASMJIT_INLINE_NODEBUG const T* ct_ptr() const noexcept { return static_cast<const T*>(&_ct_ref.table); }
ASMJIT_INLINE_NODEBUG size_t ct_size() const noexcept { return _ct_ref.size; }
//! \} //! \}
//! \name CPU Architecture, Features and Optimization Options //! \name CPU Architecture, Features and Optimization Options
//! \{ //! \{
ASMJIT_API void _init_extensions(const asmjit::CpuFeatures& features) noexcept; ASMJIT_API void _init_extensions(const CpuFeatures& features) noexcept;
ASMJIT_INLINE_NODEBUG bool is_32bit() const noexcept { return cc->is_32bit(); } ASMJIT_INLINE_NODEBUG bool is_32bit() const noexcept { return cc->is_32bit(); }
ASMJIT_INLINE_NODEBUG bool is_64bit() const noexcept { return cc->is_64bit(); } ASMJIT_INLINE_NODEBUG bool is_64bit() const noexcept { return cc->is_64bit(); }
ASMJIT_INLINE_NODEBUG uint32_t register_size() const noexcept { return cc->register_size(); } ASMJIT_INLINE_NODEBUG uint32_t register_size() const noexcept { return cc->register_size(); }
#if defined(ASMJIT_UJIT_X86) #if defined(ASMJIT_UJIT_X86)
//! Tests whether a general purpose extension `ext` is available.
ASMJIT_INLINE_NODEBUG bool has_gp_ext(GPExt ext) const noexcept { return (_gp_ext_mask & (1u << uint32_t(ext))) != 0; } ASMJIT_INLINE_NODEBUG bool has_gp_ext(GPExt ext) const noexcept { return (_gp_ext_mask & (1u << uint32_t(ext))) != 0; }
//! Tests whether an SSE extension `ext` is available.
ASMJIT_INLINE_NODEBUG bool has_sse_ext(SSEExt ext) const noexcept { return (_sse_ext_mask & (1u << uint32_t(ext))) != 0; } ASMJIT_INLINE_NODEBUG bool has_sse_ext(SSEExt ext) const noexcept { return (_sse_ext_mask & (1u << uint32_t(ext))) != 0; }
//! Tests whether an AVX or AVX-512 extension `ext` is available.
ASMJIT_INLINE_NODEBUG bool has_avx_ext(AVXExt ext) const noexcept { return (_avx_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; } ASMJIT_INLINE_NODEBUG bool has_avx_ext(AVXExt ext) const noexcept { return (_avx_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; }
//! Tests whether ADX extension is available. //! Tests whether ADX extension is available.
@@ -468,7 +347,9 @@ public:
#endif // ASMJIT_UJIT_X86 #endif // ASMJIT_UJIT_X86
#if defined(ASMJIT_UJIT_AARCH64) #if defined(ASMJIT_UJIT_AARCH64)
//! Tests whether a general purpose extension `ext` is available.
ASMJIT_INLINE_NODEBUG bool has_gp_ext(GPExt ext) const noexcept { return (_gp_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; } ASMJIT_INLINE_NODEBUG bool has_gp_ext(GPExt ext) const noexcept { return (_gp_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; }
//! Tests whether an ASIMD extension `ext` is available.
ASMJIT_INLINE_NODEBUG bool has_asimd_ext(ASIMDExt ext) const noexcept { return (_asimd_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; } ASMJIT_INLINE_NODEBUG bool has_asimd_ext(ASIMDExt ext) const noexcept { return (_asimd_ext_mask & (uint64_t(1) << uint32_t(ext))) != 0; }
//! Tests whether CSSC extension is available. //! Tests whether CSSC extension is available.
@@ -535,9 +416,12 @@ public:
//! Returns the behavior of scalar operations (mostly floating point). //! Returns the behavior of scalar operations (mostly floating point).
ASMJIT_INLINE_NODEBUG ScalarOpBehavior scalar_op_behavior() const noexcept { return _scalar_op_behavior; } ASMJIT_INLINE_NODEBUG ScalarOpBehavior scalar_op_behavior() const noexcept { return _scalar_op_behavior; }
//! Returns the behavior of floating point min/max operations. //! Returns the behavior of floating point min/max operations.
ASMJIT_INLINE_NODEBUG FMinFMaxOpBehavior fmin_fmax_op_hehavior() const noexcept { return _fmin_fmax_op_hehavior; } ASMJIT_INLINE_NODEBUG FMinFMaxOpBehavior fmin_fmax_op_behavior() const noexcept { return _fmin_fmax_op_behavior; }
//! Returns the behavior of floating point mul+add (`madd`) operations. //! Returns the behavior of floating point mul+add (`madd`) operations.
ASMJIT_INLINE_NODEBUG FMAddOpBehavior fmadd_op_behavior() const noexcept { return _fmadd_op_behavior; } ASMJIT_INLINE_NODEBUG FMAddOpBehavior fmadd_op_behavior() const noexcept { return _fmadd_op_behavior; }
//! Returns the behavior of float-to-integer conversion when the floating point is outside of the integer representable
//! range, infinite, or NaN.
ASMJIT_INLINE_NODEBUG FloatToIntOutsideRangeBehavior float_to_int_outside_range_behavior() const noexcept { return _float_to_int_outside_range_behavior; }
//! Tests whether a scalar operation is zeroing the rest of the destination register (AArch64). //! Tests whether a scalar operation is zeroing the rest of the destination register (AArch64).
ASMJIT_INLINE_NODEBUG bool is_scalar_op_zeroing() const noexcept { return _scalar_op_behavior == ScalarOpBehavior::kZeroing; } ASMJIT_INLINE_NODEBUG bool is_scalar_op_zeroing() const noexcept { return _scalar_op_behavior == ScalarOpBehavior::kZeroing; }
@@ -545,9 +429,9 @@ public:
ASMJIT_INLINE_NODEBUG bool is_scalar_op_preserving_vec128() const noexcept { return _scalar_op_behavior == ScalarOpBehavior::kPreservingVec128; } ASMJIT_INLINE_NODEBUG bool is_scalar_op_preserving_vec128() const noexcept { return _scalar_op_behavior == ScalarOpBehavior::kPreservingVec128; }
//! Tests whether a floating point min/max operation selects a finite value if one of the values is NaN (AArch64). //! Tests whether a floating point min/max operation selects a finite value if one of the values is NaN (AArch64).
ASMJIT_INLINE_NODEBUG bool is_fmin_fmax_finite() const noexcept { return _fmin_fmax_op_hehavior == FMinFMaxOpBehavior::kFiniteValue; } ASMJIT_INLINE_NODEBUG bool is_fmin_fmax_finite() const noexcept { return _fmin_fmax_op_behavior == FMinFMaxOpBehavior::kFiniteValue; }
//! Tests whether a floating point min/max operation works as a ternary if - `if a <|> b ? a : b` (X86|X86_64). //! Tests whether a floating point min/max operation works as a ternary if - `if a <|> b ? a : b` (X86|X86_64).
ASMJIT_INLINE_NODEBUG bool is_fmin_fmax_ternary() const noexcept { return _fmin_fmax_op_hehavior == FMinFMaxOpBehavior::kTernaryLogic; } ASMJIT_INLINE_NODEBUG bool is_fmin_fmax_ternary() const noexcept { return _fmin_fmax_op_behavior == FMinFMaxOpBehavior::kTernaryLogic; }
//! Tests whether a floating point mul+add operation is fused (uses FMA). //! Tests whether a floating point mul+add operation is fused (uses FMA).
ASMJIT_INLINE_NODEBUG bool is_fmadd_fused() const noexcept { return _fmadd_op_behavior != FMAddOpBehavior::kNoFMA; } ASMJIT_INLINE_NODEBUG bool is_fmadd_fused() const noexcept { return _fmadd_op_behavior != FMAddOpBehavior::kNoFMA; }
@@ -556,8 +440,10 @@ public:
//! Tests whether a FMA operation is available and that it only stores the result to accumulator register. //! Tests whether a FMA operation is available and that it only stores the result to accumulator register.
ASMJIT_INLINE_NODEBUG bool is_fma_storing_to_any_accumulator() const noexcept { return _fmadd_op_behavior == FMAddOpBehavior::kFMAStoreToAccumulator; } ASMJIT_INLINE_NODEBUG bool is_fma_storing_to_any_accumulator() const noexcept { return _fmadd_op_behavior == FMAddOpBehavior::kFMAStoreToAccumulator; }
ASMJIT_INLINE_NODEBUG UniOptFlags opt_flags() const noexcept { return _opt_flags; } //! Returns CPU hints.
ASMJIT_INLINE_NODEBUG bool has_opt_flag(UniOptFlags flag) const noexcept { return Support::test(_opt_flags, flag); } ASMJIT_INLINE_NODEBUG CpuHints cpu_hints() const noexcept { return _cpu_hints; }
//! Tests whether a CPU hint `hint` is enabled.
ASMJIT_INLINE_NODEBUG bool has_cpu_hint(CpuHints hint) const noexcept { return Support::test(_cpu_hints, hint); }
//! Returns a native register signature, either 32-bit or 64-bit depending on the target architecture). //! Returns a native register signature, either 32-bit or 64-bit depending on the target architecture).
ASMJIT_INLINE_NODEBUG OperandSignature gp_signature() const noexcept { return cc->gp_signature(); } ASMJIT_INLINE_NODEBUG OperandSignature gp_signature() const noexcept { return cc->gp_signature(); }
@@ -599,7 +485,7 @@ public:
//! \name Function //! \name Function
//! \{ //! \{
ASMJIT_API void init_function(asmjit::FuncNode* func_node) noexcept; ASMJIT_API void init_function(FuncNode* func_node) noexcept;
//! \} //! \}
@@ -607,13 +493,15 @@ public:
//! \{ //! \{
ASMJIT_INLINE void rename(const OpArray& op_array, const char* name) noexcept { ASMJIT_INLINE void rename(const OpArray& op_array, const char* name) noexcept {
for (uint32_t i = 0; i < op_array.size(); i++) for (uint32_t i = 0; i < op_array.size(); i++) {
cc->rename(op_array[i].as<asmjit::Reg>(), "%s%u", name, unsigned(i)); cc->rename(op_array[i].as<Reg>(), "%s%u", name, unsigned(i));
}
} }
ASMJIT_INLINE void rename(const OpArray& op_array, const char* prefix, const char* name) noexcept { ASMJIT_INLINE void rename(const OpArray& op_array, const char* prefix, const char* name) noexcept {
for (uint32_t i = 0; i < op_array.size(); i++) for (uint32_t i = 0; i < op_array.size(); i++) {
cc->rename(op_array[i].as<asmjit::Reg>(), "%s%s%u", prefix, name, unsigned(i)); cc->rename(op_array[i].as<Reg>(), "%s%s%u", prefix, name, unsigned(i));
}
} }
//! \} //! \}
@@ -631,84 +519,163 @@ public:
//! \name Virtual Registers & Memory (Target Independent) //! \name Virtual Registers & Memory (Target Independent)
//! \{ //! \{
ASMJIT_INLINE Gp new_gp32() noexcept { return cc->new_gp32(); } //! Wraps `BackendCompiler::new_reg(type_id, args...)`.
ASMJIT_INLINE Gp new_gp64() noexcept { return cc->new_gp64(); }
ASMJIT_INLINE Gp new_gpz() noexcept { return cc->new_gpz(); }
template<typename... Args>
ASMJIT_INLINE Gp new_gp32(const char* name, Args&&... args) noexcept { return cc->new_gp32(name, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE Gp new_gp64(const char* name, Args&&... args) noexcept { return cc->new_gp64(name, std::forward<Args>(args)...); }
template<typename... Args>
ASMJIT_INLINE Gp new_gpz(const char* name, Args&&... args) noexcept { return cc->new_gpz(name, std::forward<Args>(args)...); }
template<typename RegT>
ASMJIT_INLINE RegT new_similar_reg(const RegT& ref) noexcept { return cc->new_similar_reg(ref); }
template<typename RegT, typename... Args> template<typename RegT, typename... Args>
ASMJIT_INLINE RegT new_similar_reg(const RegT& ref, Args&&... args) noexcept { return cc->new_similar_reg(ref, std::forward<Args>(args)...); } ASMJIT_INLINE RegT new_reg(TypeId type_id, Args&&... args) noexcept {
return cc->new_similar_reg<RegT>(type_id, std::forward<Args>(args)...);
}
//! Wraps `BackendCompiler::new_similar_reg(ref, args...)`.
template<typename RegT, typename... Args>
ASMJIT_INLINE RegT new_similar_reg(const RegT& ref, Args&&... args) noexcept {
return cc->new_similar_reg(ref, std::forward<Args>(args)...);
}
//! Wraps `BackendCompiler::new_gp32(args...)`.
template<typename... Args> template<typename... Args>
ASMJIT_INLINE Vec new_vec(const char* name, Args&&... args) noexcept { ASMJIT_INLINE Gp new_gp32(Args&&... args) noexcept {
Vec reg; return cc->new_gp32(std::forward<Args>(args)...);
cc->_new_reg_fmt(Out<Reg>(reg), _vec_type_id, name, std::forward<Args>(args)...); }
return reg;
//! Wraps `BackendCompiler::new_gp64(args...)`.
template<typename... Args>
ASMJIT_INLINE Gp new_gp64(Args&&... args) noexcept {
return cc->new_gp64(std::forward<Args>(args)...);
}
//! Wraps `BackendCompiler::new_gpz(args...)`.
template<typename... Args>
ASMJIT_INLINE Gp new_gpz(Args&&... args) noexcept {
return cc->new_gpz(std::forward<Args>(args)...);
}
//! Wraps `BackendCompiler::new_gpz(args...)`.
template<typename... Args>
ASMJIT_INLINE Gp new_gp_ptr(Args&&... args) noexcept {
return cc->new_gp_ptr(std::forward<Args>(args)...);
} }
template<typename... Args> template<typename... Args>
ASMJIT_INLINE Vec new_vec(VecWidth vw, const char* name, Args&&... args) noexcept { ASMJIT_INLINE Vec new_vec(Args&&... args) noexcept {
Vec reg; return cc->new_vec(_vec_type_id, std::forward<Args>(args)...);
cc->_new_reg_fmt(Out<Reg>(reg), VecWidthUtils::type_id_of(vw), name, std::forward<Args>(args)...);
return reg;
} }
ASMJIT_NOINLINE void new_reg_array(OpArray& dst, uint32_t n, asmjit::TypeId type_id, const char* name) noexcept { template<typename... Args>
ASMJIT_INLINE Vec new_vec_with_width(VecWidth vw, Args&&... args) noexcept {
return cc->new_reg<Vec>(VecWidthUtils::type_id_of(vw), std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128(Args&&... args) noexcept {
return cc->new_vec128(std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_f32x1(Args&&... args) noexcept {
return cc->new_vec128_f32x1(std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_f64x1(Args&&... args) noexcept {
return cc->new_vec128_f64x1(std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_f32x4(Args&&... args) noexcept {
return cc->new_vec128_f32x4(std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_f64x2(Args&&... args) noexcept {
return cc->new_vec128_f64x2(std::forward<Args>(args)...);
}
#if defined(ASMJIT_UJIT_X86)
template<typename... Args>
ASMJIT_INLINE Vec new_vec256(Args&&... args) noexcept {
return cc->new_vec256(std::forward<Args>(args)...);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec512(Args&&... args) noexcept {
return cc->new_vec512(std::forward<Args>(args)...);
}
#endif // ASMJIT_UJIT_X86
ASMJIT_NOINLINE void new_reg_array(OpArray& dst, size_t n, TypeId type_id, const char* name) noexcept {
ASMJIT_ASSERT(n <= OpArray::kMaxSize); ASMJIT_ASSERT(n <= OpArray::kMaxSize);
dst._size = n; dst._size = n;
for (uint32_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), type_id, "%s%u", name, i); cc->_new_reg(Out(dst[i].as<Reg>()), type_id, "%s%u", name, i);
} }
} }
ASMJIT_NOINLINE void new_reg_array(OpArray& dst, uint32_t n, asmjit::TypeId type_id, const char* prefix, const char* name) noexcept { ASMJIT_NOINLINE void new_reg_array(OpArray& dst, size_t n, TypeId type_id, const char* prefix, const char* name) noexcept {
ASMJIT_ASSERT(n <= OpArray::kMaxSize); ASMJIT_ASSERT(n <= OpArray::kMaxSize);
dst._size = n; dst._size = n;
for (uint32_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), type_id, "%s%s%u", prefix, name, i); cc->_new_reg(Out(dst[i].as<Reg>()), type_id, "%s%s%u", prefix, name, i);
} }
} }
ASMJIT_NOINLINE void new_reg_array(OpArray& dst, uint32_t n, const asmjit::Reg& ref, const char* name) noexcept { ASMJIT_NOINLINE void new_reg_array(OpArray& dst, size_t n, const Reg& ref, const char* name) noexcept {
ASMJIT_ASSERT(n <= OpArray::kMaxSize); ASMJIT_ASSERT(n <= OpArray::kMaxSize);
dst._size = n; dst._size = n;
for (uint32_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), ref, "%s%u", name, i); cc->_new_reg(Out(dst[i].as<Reg>()), ref, "%s%u", name, i);
} }
} }
ASMJIT_NOINLINE void new_reg_array(OpArray& dst, uint32_t n, const asmjit::Reg& ref, const char* prefix, const char* name) noexcept { ASMJIT_NOINLINE void new_reg_array(OpArray& dst, size_t n, const Reg& ref, const char* prefix, const char* name) noexcept {
ASMJIT_ASSERT(n <= OpArray::kMaxSize); ASMJIT_ASSERT(n <= OpArray::kMaxSize);
dst._size = n; dst._size = n;
for (uint32_t i = 0; i < n; i++) { for (size_t i = 0; i < n; i++) {
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), ref, "%s%s%u", prefix, name, i); cc->_new_reg(Out(dst[i].as<Reg>()), ref, "%s%s%u", prefix, name, i);
} }
} }
ASMJIT_INLINE void new_vec_array(OpArray& dst, uint32_t n, VecWidth vw, const char* name) noexcept { ASMJIT_INLINE void new_vec_array(OpArray& dst, size_t n, VecWidth vw, const char* name) noexcept {
new_reg_array(dst, n, VecWidthUtils::type_id_of(vw), name); new_reg_array(dst, n, VecWidthUtils::type_id_of(vw), name);
} }
ASMJIT_INLINE void new_vec_array(OpArray& dst, uint32_t n, VecWidth vw, const char* prefix, const char* name) noexcept { ASMJIT_INLINE void new_vec_array(OpArray& dst, size_t n, VecWidth vw, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, VecWidthUtils::type_id_of(vw), prefix, name); new_reg_array(dst, n, VecWidthUtils::type_id_of(vw), prefix, name);
} }
ASMJIT_INLINE void new_vec_array(OpArray& dst, uint32_t n, const Vec& ref, const char* name) noexcept { ASMJIT_INLINE void new_vec_array(OpArray& dst, size_t n, const Vec& ref, const char* name) noexcept {
new_reg_array(dst, n, ref, name); new_reg_array(dst, n, ref, name);
} }
ASMJIT_INLINE void new_vec_array(OpArray& dst, uint32_t n, const Vec& ref, const char* prefix, const char* name) noexcept { ASMJIT_INLINE void new_vec_array(OpArray& dst, size_t n, const Vec& ref, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, ref, prefix, name); new_reg_array(dst, n, ref, prefix, name);
} }
ASMJIT_INLINE void new_vec128_array(OpArray& dst, size_t n, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x4, name);
}
ASMJIT_INLINE void new_vec128_array(OpArray& dst, size_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x4, prefix, name);
}
#if defined(ASMJIT_UJIT_X86)
ASMJIT_INLINE void new_vec256_array(OpArray& dst, size_t n, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x8, name);
}
ASMJIT_INLINE void new_vec256_array(OpArray& dst, size_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x8, prefix, name);
}
ASMJIT_INLINE void new_vec512_array(OpArray& dst, size_t n, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x16, name);
}
ASMJIT_INLINE void new_vec512_array(OpArray& dst, size_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, TypeId::kInt32x16, prefix, name);
}
#endif // ASMJIT_UJIT_X86
ASMJIT_API Mem tmp_stack(StackId id, uint32_t size) noexcept; ASMJIT_API Mem tmp_stack(StackId id, uint32_t size) noexcept;
//! \} //! \}
@@ -722,165 +689,6 @@ public:
ASMJIT_API void _init_vec_const_table_ptr() noexcept; ASMJIT_API void _init_vec_const_table_ptr() noexcept;
//! \name Virtual Registers
//! \{
#if defined(ASMJIT_UJIT_X86)
ASMJIT_INLINE Vec new_vec128() noexcept {
Vec reg;
cc->_new_reg(Out<Reg>(reg), asmjit::TypeId::kInt32x4);
return reg;
}
ASMJIT_INLINE Vec new_vec128_1xf32() noexcept {
Vec reg;
cc->_new_reg(Out<Reg>(reg), asmjit::TypeId::kFloat32x1);
return reg;
}
ASMJIT_INLINE Vec new_vec128_1xf64() noexcept {
Vec reg;
cc->_new_reg(Out<Reg>(reg), asmjit::TypeId::kFloat64x1);
return reg;
}
ASMJIT_INLINE Vec new_vec128_4xf32() noexcept {
Vec reg;
cc->_new_reg(Out<Reg>(reg), asmjit::TypeId::kFloat32x4);
return reg;
}
ASMJIT_INLINE Vec new_vec128_2xf64() noexcept {
Vec reg;
cc->_new_reg(Out<Reg>(reg), asmjit::TypeId::kFloat64x2);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128(Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kInt32x4, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_1xf32(Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat32x1, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_1xf64(Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat64x1, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_4xf32(Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat32x4, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_2xf64(Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat64x2, std::forward<Args>(args)...);
return reg;
}
ASMJIT_INLINE void new_vec128_array(OpArray& dst, uint32_t n, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x4, name);
}
ASMJIT_INLINE void new_vec128_array(OpArray& dst, uint32_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x4, prefix, name);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec256(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kInt32x8, name, std::forward<Args>(args)...);
return reg;
}
ASMJIT_INLINE void new_vec256_array(OpArray& dst, uint32_t n, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x8, name);
}
ASMJIT_INLINE void new_vec256_array(OpArray& dst, uint32_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x8, prefix, name);
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec512(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kInt32x16, name, std::forward<Args>(args)...);
return reg;
}
ASMJIT_INLINE void new_vec512_array(OpArray& dst, uint32_t n, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x16, name);
}
ASMJIT_INLINE void new_vec512_array(OpArray& dst, uint32_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x16, prefix, name);
}
#endif // ASMJIT_UJIT_X86
#if defined(ASMJIT_UJIT_AARCH64)
template<typename... Args>
ASMJIT_INLINE Vec new_vec128(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kInt32x4, name, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_1xf32(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat32x1, name, std::forward<Args>(args)...);
return reg.v128();
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_1xf64(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat64x1, name, std::forward<Args>(args)...);
return reg.v128();
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_4xf32(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat32x4, name, std::forward<Args>(args)...);
return reg;
}
template<typename... Args>
ASMJIT_INLINE Vec new_vec128_2xf64(const char* name, Args&&... args) noexcept {
Vec reg;
cc->_new_reg_fmt(Out<Reg>(reg), asmjit::TypeId::kFloat64x2, name, std::forward<Args>(args)...);
return reg;
}
ASMJIT_INLINE void new_vec128_array(OpArray& dst, uint32_t n, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x4, name);
}
ASMJIT_INLINE void new_vec128_array(OpArray& dst, uint32_t n, const char* prefix, const char* name) noexcept {
new_reg_array(dst, n, asmjit::TypeId::kInt32x4, prefix, name);
}
#endif
//! \}
//! \name Constants (X86|X86_64) //! \name Constants (X86|X86_64)
//! \{ //! \{
@@ -901,14 +709,14 @@ public:
ASMJIT_API Mem simd_mem_const(const void* c, Bcst bcst_width, const VecArray& similar_to) noexcept; ASMJIT_API Mem simd_mem_const(const void* c, Bcst bcst_width, const VecArray& similar_to) noexcept;
ASMJIT_API Mem _get_mem_const(const void* c) noexcept; ASMJIT_API Mem _get_mem_const(const void* c) noexcept;
ASMJIT_API Vec _new_vecConst(const void* c, bool is_unique_const) noexcept; ASMJIT_API Vec _new_vec_const(const void* c, bool is_unique_const) noexcept;
#if defined(ASMJIT_UJIT_AARCH64) #if defined(ASMJIT_UJIT_AARCH64)
ASMJIT_API Vec simd_const_16b(const void* data16) noexcept; ASMJIT_API Vec simd_const_16b(const void* data16) noexcept;
#endif // ASMJIT_UJIT_AARCH64 #endif // ASMJIT_UJIT_AARCH64
#if defined(ASMJIT_UJIT_AARCH64) #if defined(ASMJIT_UJIT_AARCH64)
inline Vec simd_vec_zero(const Vec& similar_to) noexcept { return simd_vec_const(&ct.p_0000000000000000, Bcst::k32, similar_to); } inline Vec simd_vec_zero(const Vec& similar_to) noexcept { return simd_vec_const(&ct().p_0000000000000000, Bcst::k32, similar_to); }
#endif // ASMJIT_UJIT_AARCH64 #endif // ASMJIT_UJIT_AARCH64
//! \} //! \}
@@ -920,12 +728,12 @@ public:
ASMJIT_API void emit_m(UniOpM op, const Mem& m) noexcept; ASMJIT_API void emit_m(UniOpM op, const Mem& m) noexcept;
ASMJIT_API void emit_rm(UniOpRM op, const Gp& dst, const Mem& src) noexcept; ASMJIT_API void emit_rm(UniOpRM op, const Gp& dst, const Mem& src) noexcept;
ASMJIT_API void emit_mr(UniOpMR op, const Mem& dst, const Gp& src) noexcept; ASMJIT_API void emit_mr(UniOpMR op, const Mem& dst, const Gp& src) noexcept;
ASMJIT_API void emit_cmov(const Gp& dst, const Operand_& sel, const Condition& condition) noexcept; ASMJIT_API void emit_cmov(const Gp& dst, const Operand_& sel, const UniCondition& condition) noexcept;
ASMJIT_API void emit_select(const Gp& dst, const Operand_& sel1_, const Operand_& sel2_, const Condition& condition) noexcept; ASMJIT_API void emit_select(const Gp& dst, const Operand_& sel1_, const Operand_& sel2_, const UniCondition& condition) noexcept;
ASMJIT_API void emit_2i(UniOpRR op, const Gp& dst, const Operand_& src_) noexcept; ASMJIT_API void emit_2i(UniOpRR op, const Gp& dst, const Operand_& src_) noexcept;
ASMJIT_API void emit_3i(UniOpRRR op, const Gp& dst, const Operand_& src1_, const Operand_& src2_) noexcept; ASMJIT_API void emit_3i(UniOpRRR op, const Gp& dst, const Operand_& src1_, const Operand_& src2_) noexcept;
ASMJIT_API void emit_j(const Operand_& target) noexcept; ASMJIT_API void emit_j(const Operand_& target) noexcept;
ASMJIT_API void emit_j_if(const Label& target, const Condition& condition) noexcept; ASMJIT_API void emit_j_if(const Label& target, const UniCondition& condition) noexcept;
ASMJIT_INLINE void mov(const Gp& dst, const Gp& src) noexcept { return emit_mov(dst, src); } ASMJIT_INLINE void mov(const Gp& dst, const Gp& src) noexcept { return emit_mov(dst, src); }
ASMJIT_INLINE void mov(const Gp& dst, const Imm& src) noexcept { return emit_mov(dst, src); } ASMJIT_INLINE void mov(const Gp& dst, const Imm& src) noexcept { return emit_mov(dst, src); }
@@ -963,11 +771,11 @@ public:
ASMJIT_INLINE void mem_add_u32(const Mem& dst, const Gp& src) noexcept { return emit_mr(UniOpMR::kAddU32, dst, src); } ASMJIT_INLINE void mem_add_u32(const Mem& dst, const Gp& src) noexcept { return emit_mr(UniOpMR::kAddU32, dst, src); }
ASMJIT_INLINE void mem_add_u64(const Mem& dst, const Gp& src) noexcept { return emit_mr(UniOpMR::kAddU64, dst, src); } ASMJIT_INLINE void mem_add_u64(const Mem& dst, const Gp& src) noexcept { return emit_mr(UniOpMR::kAddU64, dst, src); }
ASMJIT_INLINE void cmov(const Gp& dst, const Gp& sel, const Condition& condition) noexcept { emit_cmov(dst, sel, condition); } ASMJIT_INLINE void cmov(const Gp& dst, const Gp& sel, const UniCondition& condition) noexcept { emit_cmov(dst, sel, condition); }
ASMJIT_INLINE void cmov(const Gp& dst, const Mem& sel, const Condition& condition) noexcept { emit_cmov(dst, sel, condition); } ASMJIT_INLINE void cmov(const Gp& dst, const Mem& sel, const UniCondition& condition) noexcept { emit_cmov(dst, sel, condition); }
template<typename Sel1, typename Sel2> template<typename Sel1, typename Sel2>
ASMJIT_INLINE void select(const Gp& dst, const Sel1& sel1, const Sel2& sel2, const Condition& condition) noexcept { emit_select(dst, sel1, sel2, condition); } ASMJIT_INLINE void select(const Gp& dst, const Sel1& sel1, const Sel2& sel2, const UniCondition& condition) noexcept { emit_select(dst, sel1, sel2, condition); }
ASMJIT_INLINE void abs(const Gp& dst, const Gp& src) noexcept { emit_2i(UniOpRR::kAbs, dst, src); } ASMJIT_INLINE void abs(const Gp& dst, const Gp& src) noexcept { emit_2i(UniOpRR::kAbs, dst, src); }
ASMJIT_INLINE void abs(const Gp& dst, const Mem& src) noexcept { emit_2i(UniOpRR::kAbs, dst, src); } ASMJIT_INLINE void abs(const Gp& dst, const Mem& src) noexcept { emit_2i(UniOpRR::kAbs, dst, src); }
@@ -1101,7 +909,7 @@ public:
ASMJIT_INLINE void j(const Gp& target) noexcept { emit_j(target); } ASMJIT_INLINE void j(const Gp& target) noexcept { emit_j(target); }
ASMJIT_INLINE void j(const Label& target) noexcept { emit_j(target); } ASMJIT_INLINE void j(const Label& target) noexcept { emit_j(target); }
ASMJIT_INLINE void j(const Label& target, const Condition& condition) noexcept { emit_j_if(target, condition); } ASMJIT_INLINE void j(const Label& target, const UniCondition& condition) noexcept { emit_j_if(target, condition); }
ASMJIT_API void adds_u8(const Gp& dst, const Gp& src1, const Gp& src2) noexcept; ASMJIT_API void adds_u8(const Gp& dst, const Gp& src1, const Gp& src2) noexcept;
@@ -1283,8 +1091,12 @@ public:
DEFINE_OP_2V(v_cvt_i32_hi_to_i64, UniOpVV::kCvtI32HiToI64) DEFINE_OP_2V(v_cvt_i32_hi_to_i64, UniOpVV::kCvtI32HiToI64)
DEFINE_OP_2V(v_cvt_u32_lo_to_u64, UniOpVV::kCvtU32LoToU64) DEFINE_OP_2V(v_cvt_u32_lo_to_u64, UniOpVV::kCvtU32LoToU64)
DEFINE_OP_2V(v_cvt_u32_hi_to_u64, UniOpVV::kCvtU32HiToU64) DEFINE_OP_2V(v_cvt_u32_hi_to_u64, UniOpVV::kCvtU32HiToU64)
DEFINE_OP_2V(s_abs_f32, UniOpVV::kAbsF32S)
DEFINE_OP_2V(s_abs_f64, UniOpVV::kAbsF64S)
DEFINE_OP_2V(v_abs_f32, UniOpVV::kAbsF32) DEFINE_OP_2V(v_abs_f32, UniOpVV::kAbsF32)
DEFINE_OP_2V(v_abs_f64, UniOpVV::kAbsF64) DEFINE_OP_2V(v_abs_f64, UniOpVV::kAbsF64)
DEFINE_OP_2V(s_neg_f32, UniOpVV::kNegF32S)
DEFINE_OP_2V(s_neg_f64, UniOpVV::kNegF64S)
DEFINE_OP_2V(v_neg_f32, UniOpVV::kNegF32) DEFINE_OP_2V(v_neg_f32, UniOpVV::kNegF32)
DEFINE_OP_2V(v_neg_f64, UniOpVV::kNegF64) DEFINE_OP_2V(v_neg_f64, UniOpVV::kNegF64)
DEFINE_OP_2V(v_not_f32, UniOpVV::kNotF32) DEFINE_OP_2V(v_not_f32, UniOpVV::kNotF32)
@@ -1301,10 +1113,18 @@ public:
DEFINE_OP_2V(s_ceil_f64, UniOpVV::kCeilF64S) DEFINE_OP_2V(s_ceil_f64, UniOpVV::kCeilF64S)
DEFINE_OP_2V(v_ceil_f32, UniOpVV::kCeilF32) DEFINE_OP_2V(v_ceil_f32, UniOpVV::kCeilF32)
DEFINE_OP_2V(v_ceil_f64, UniOpVV::kCeilF64) DEFINE_OP_2V(v_ceil_f64, UniOpVV::kCeilF64)
DEFINE_OP_2V(s_round_f32, UniOpVV::kRoundF32S) DEFINE_OP_2V(s_round_even_f32, UniOpVV::kRoundEvenF32S)
DEFINE_OP_2V(s_round_f64, UniOpVV::kRoundF64S) DEFINE_OP_2V(s_round_even_f64, UniOpVV::kRoundEvenF64S)
DEFINE_OP_2V(v_round_f32, UniOpVV::kRoundF32) DEFINE_OP_2V(v_round_even_f32, UniOpVV::kRoundEvenF32)
DEFINE_OP_2V(v_round_f64, UniOpVV::kRoundF64) DEFINE_OP_2V(v_round_even_f64, UniOpVV::kRoundEvenF64)
DEFINE_OP_2V(s_round_half_away_f32, UniOpVV::kRoundHalfAwayF32S)
DEFINE_OP_2V(s_round_half_away_f64, UniOpVV::kRoundHalfAwayF64S)
DEFINE_OP_2V(v_round_half_away_f32, UniOpVV::kRoundHalfAwayF32)
DEFINE_OP_2V(v_round_half_away_f64, UniOpVV::kRoundHalfAwayF64)
DEFINE_OP_2V(s_round_half_up_f32, UniOpVV::kRoundHalfUpF32S)
DEFINE_OP_2V(s_round_half_up_f64, UniOpVV::kRoundHalfUpF64S)
DEFINE_OP_2V(v_round_half_up_f32, UniOpVV::kRoundHalfUpF32)
DEFINE_OP_2V(v_round_half_up_f64, UniOpVV::kRoundHalfUpF64)
DEFINE_OP_2V(v_rcp_f32, UniOpVV::kRcpF32) DEFINE_OP_2V(v_rcp_f32, UniOpVV::kRcpF32)
DEFINE_OP_2V(v_rcp_f64, UniOpVV::kRcpF64) DEFINE_OP_2V(v_rcp_f64, UniOpVV::kRcpF64)
DEFINE_OP_2V(s_sqrt_f32, UniOpVV::kSqrtF32S) DEFINE_OP_2V(s_sqrt_f32, UniOpVV::kSqrtF32S)
@@ -1743,6 +1563,10 @@ public:
DEFINE_OP_3V(s_div_f64, UniOpVVV::kDivF64S) DEFINE_OP_3V(s_div_f64, UniOpVVV::kDivF64S)
DEFINE_OP_3V(v_div_f32, UniOpVVV::kDivF32) DEFINE_OP_3V(v_div_f32, UniOpVVV::kDivF32)
DEFINE_OP_3V(v_div_f64, UniOpVVV::kDivF64) DEFINE_OP_3V(v_div_f64, UniOpVVV::kDivF64)
DEFINE_OP_3V(s_mod_f32, UniOpVVV::kModF32S)
DEFINE_OP_3V(s_mod_f64, UniOpVVV::kModF64S)
DEFINE_OP_3V(v_mod_f32, UniOpVVV::kModF32)
DEFINE_OP_3V(v_mod_f64, UniOpVVV::kModF64)
DEFINE_OP_3V(s_min_f32, UniOpVVV::kMinF32S) DEFINE_OP_3V(s_min_f32, UniOpVVV::kMinF32S)
DEFINE_OP_3V(s_min_f64, UniOpVVV::kMinF64S) DEFINE_OP_3V(s_min_f64, UniOpVVV::kMinF64S)
DEFINE_OP_3V(v_min_f32, UniOpVVV::kMinF32) DEFINE_OP_3V(v_min_f32, UniOpVVV::kMinF32)
@@ -1856,7 +1680,6 @@ public:
DEFINE_OP_3VI(v_insert_v256_u64, UniOpVVVI::kInsertV256_U64) DEFINE_OP_3VI(v_insert_v256_u64, UniOpVVVI::kInsertV256_U64)
DEFINE_OP_3VI(v_insert_v256_f64, UniOpVVVI::kInsertV256_F64) DEFINE_OP_3VI(v_insert_v256_f64, UniOpVVVI::kInsertV256_F64)
DEFINE_OP_4V(v_blendv_u8, UniOpVVVV::kBlendV_U8) DEFINE_OP_4V(v_blendv_u8, UniOpVVVV::kBlendV_U8)
DEFINE_OP_4V(v_madd_i16, UniOpVVVV::kMAddU16) DEFINE_OP_4V(v_madd_i16, UniOpVVVV::kMAddU16)
DEFINE_OP_4V(v_madd_u16, UniOpVVVV::kMAddU16) DEFINE_OP_4V(v_madd_u16, UniOpVVVV::kMAddU16)
@@ -1944,7 +1767,7 @@ public:
//! \name Memory Loads & Stores with Parameterized Size //! \name Memory Loads & Stores with Parameterized Size
//! \{ //! \{
ASMJIT_NOINLINE void v_load_iany(const Vec& dst, const Mem& src, uint32_t n_bytes, Alignment alignment) noexcept { ASMJIT_NOINLINE void v_load_iany(const Vec& dst, const Mem& src, size_t n_bytes, Alignment alignment) noexcept {
switch (n_bytes) { switch (n_bytes) {
case 1: v_load8(dst, src); break; case 1: v_load8(dst, src); break;
case 2: v_loada16(dst, src, alignment); break; case 2: v_loada16(dst, src, alignment); break;
@@ -1959,7 +1782,7 @@ public:
} }
} }
ASMJIT_NOINLINE void v_store_iany(const Mem& dst, const Vec& src, uint32_t n_bytes, Alignment alignment) noexcept { ASMJIT_NOINLINE void v_store_iany(const Mem& dst, const Vec& src, size_t n_bytes, Alignment alignment) noexcept {
switch (n_bytes) { switch (n_bytes) {
case 1: v_store8(dst, src); break; case 1: v_store8(dst, src); break;
case 2: v_storea16(dst, src, alignment); break; case 2: v_storea16(dst, src, alignment); break;
@@ -2005,27 +1828,6 @@ public:
#endif #endif
} }
// d = int(floor(a / b) * b).
template<typename VecOrMem>
ASMJIT_NOINLINE void v_mod_pd(const Vec& d, const Vec& a, const VecOrMem& b) noexcept {
#if defined(ASMJIT_UJIT_X86)
if (!has_sse4_1()) {
Vec t = new_vec128("vModTmp");
v_div_f64(d, a, b);
v_cvt_trunc_f64_to_i32_lo(t, d);
v_cvt_i32_lo_to_f64(d, t);
v_mul_f64(d, d, b);
}
else
#endif // ASMJIT_UJIT_X86
{
v_div_f64(d, a, b);
v_trunc_f64(d, d);
v_mul_f64(d, d, b);
}
}
//! \} //! \}
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
// This file is part of AsmJit project <https://asmjit.com>
//
// See <asmjit/core.h> or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_UJIT_UNICOMPILER_UTILS_P_H_INCLUDED
#define ASMJIT_UJIT_UNICOMPILER_UTILS_P_H_INCLUDED
#include "ujitbase.h"
#if !defined(ASMJIT_NO_UJIT)
#include "uniop.h"
ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
//! \addtogroup asmjit_ujit
//! \{
template<typename UniOpDst, typename UniOpSrc>
static ASMJIT_INLINE UniOpDst translate_op(UniOpSrc op, UniOpSrc begin, UniOpDst target) noexcept {
ASMJIT_ASSERT(begin <= op);
uint32_t offset = uint32_t(op) - uint32_t(begin);
return UniOpDst(uint32_t(target) + offset);
}
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_UJIT
#endif // ASMJIT_UJIT_UNICOMPILER_UTILS_P_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,293 @@
// This file is part of AsmJit project <https://asmjit.com>
//
// See <asmjit/core.h> or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_UJIT_UNICONDITION_H_INCLUDED
#define ASMJIT_UJIT_UNICONDITION_H_INCLUDED
#include "ujitbase.h"
#include "uniop.h"
#if !defined(ASMJIT_NO_UJIT)
ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
//! \addtogroup asmjit_ujit
//! \{
//! Condition represents either a condition or an assignment operation that can be checked.
class UniCondition {
public:
//! \name Members
//! \{
UniOpCond op;
CondCode cond;
Operand a;
Operand b;
//! \}
//! \name Construction & Destruction
//! \{
ASMJIT_INLINE_NODEBUG UniCondition(UniOpCond op, CondCode cond, const Operand& a, const Operand& b) noexcept
: op(op),
cond(cond),
a(a),
b(b) {}
ASMJIT_INLINE_NODEBUG UniCondition(const UniCondition& other) noexcept = default;
//! \}
//! \name Overloaded Operators
//! \{
ASMJIT_INLINE_NODEBUG UniCondition& operator=(const UniCondition& other) noexcept = default;
//! \}
};
//! Constructs a condition that would be `true` when `a = (a & b)` becomes zero.
static ASMJIT_INLINE UniCondition and_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a & b)` becomes zero.
static ASMJIT_INLINE UniCondition and_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a & b)` becomes zero.
static ASMJIT_INLINE UniCondition and_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a & b)` becomes non-zero.
static ASMJIT_INLINE UniCondition and_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a & b)` becomes non-zero.
static ASMJIT_INLINE UniCondition and_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a & b)` becomes non-zero.
static ASMJIT_INLINE UniCondition and_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAnd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes zero.
static ASMJIT_INLINE UniCondition or_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes zero.
static ASMJIT_INLINE UniCondition or_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes zero.
static ASMJIT_INLINE UniCondition or_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes non-zero.
static ASMJIT_INLINE UniCondition or_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes non-zero.
static ASMJIT_INLINE UniCondition or_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a | b)` becomes non-zero.
static ASMJIT_INLINE UniCondition or_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignOr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes zero.
static ASMJIT_INLINE UniCondition xor_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes zero.
static ASMJIT_INLINE UniCondition xor_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes zero.
static ASMJIT_INLINE UniCondition xor_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes non-zero.
static ASMJIT_INLINE UniCondition xor_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes non-zero.
static ASMJIT_INLINE UniCondition xor_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a ^ b)` becomes non-zero.
static ASMJIT_INLINE UniCondition xor_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignXor, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes zero.
static ASMJIT_INLINE UniCondition add_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes zero.
static ASMJIT_INLINE UniCondition add_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes zero.
static ASMJIT_INLINE UniCondition add_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes non-zero.
static ASMJIT_INLINE UniCondition add_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes non-zero.
static ASMJIT_INLINE UniCondition add_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` becomes non-zero.
static ASMJIT_INLINE UniCondition add_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` wraps (sets carry flag).
static ASMJIT_INLINE UniCondition add_c(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` wraps (sets carry flag).
static ASMJIT_INLINE UniCondition add_c(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` wraps (sets carry flag).
static ASMJIT_INLINE UniCondition add_c(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` doesn't wrap (doesn't set carry flag).
static ASMJIT_INLINE UniCondition add_nc(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` doesn't wrap (doesn't set carry flag).
static ASMJIT_INLINE UniCondition add_nc(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` doesn't wrap (doesn't set carry flag).
static ASMJIT_INLINE UniCondition add_nc(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotCarry, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition add_s(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition add_s(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition add_s(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition add_ns(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition add_ns(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a + b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition add_ns(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignAdd, CondCode::kNotSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes zero.
static ASMJIT_INLINE UniCondition sub_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes zero.
static ASMJIT_INLINE UniCondition sub_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes zero.
static ASMJIT_INLINE UniCondition sub_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes non-zero.
static ASMJIT_INLINE UniCondition sub_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes non-zero.
static ASMJIT_INLINE UniCondition sub_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` becomes non-zero.
static ASMJIT_INLINE UniCondition sub_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` wraps.
static ASMJIT_INLINE UniCondition sub_c(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` wraps.
static ASMJIT_INLINE UniCondition sub_c(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` wraps.
static ASMJIT_INLINE UniCondition sub_c(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` doesn't wrap.
static ASMJIT_INLINE UniCondition sub_nc(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` doesn't wrap.
static ASMJIT_INLINE UniCondition sub_nc(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` doesn't wrap.
static ASMJIT_INLINE UniCondition sub_nc(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition sub_s(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition sub_s(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit set.
static ASMJIT_INLINE UniCondition sub_s(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition sub_ns(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition sub_ns(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
//! Constructs a condition that would be `true` when `a = (a - b)` ends with the msb/sign bit unset.
static ASMJIT_INLINE UniCondition sub_ns(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kNotSign, a, b); }
static ASMJIT_INLINE UniCondition sub_ugt(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE UniCondition sub_ugt(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
static ASMJIT_INLINE UniCondition sub_ugt(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignSub, CondCode::kUnsignedGT, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes zero.
static ASMJIT_INLINE UniCondition shr_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes zero.
static ASMJIT_INLINE UniCondition shr_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes zero.
static ASMJIT_INLINE UniCondition shr_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes non-zero.
static ASMJIT_INLINE UniCondition shr_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes non-zero.
static ASMJIT_INLINE UniCondition shr_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a = (a << b)` becomes non-zero.
static ASMJIT_INLINE UniCondition shr_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kAssignShr, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a == b)`.
static ASMJIT_INLINE UniCondition cmp_eq(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
//! Constructs a condition that would be `true` when `a == b)`.
static ASMJIT_INLINE UniCondition cmp_eq(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
//! Constructs a condition that would be `true` when `a == b)`.
static ASMJIT_INLINE UniCondition cmp_eq(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kEqual, a, b); }
//! Constructs a condition that would be `true` when `a != b)`.
static ASMJIT_INLINE UniCondition cmp_ne(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
//! Constructs a condition that would be `true` when `a != b)`.
static ASMJIT_INLINE UniCondition cmp_ne(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
//! Constructs a condition that would be `true` when `a != b)`.
static ASMJIT_INLINE UniCondition cmp_ne(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kNotEqual, a, b); }
//! Constructs a condition that would be `true` when `a < b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_lt(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
//! Constructs a condition that would be `true` when `a < b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_lt(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
//! Constructs a condition that would be `true` when `a < b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_lt(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLT, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_le(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_le(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_le(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedLE, a, b); }
//! Constructs a condition that would be `true` when `a > b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_gt(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
//! Constructs a condition that would be `true` when `a > b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_gt(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
//! Constructs a condition that would be `true` when `a > b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_gt(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGT, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_ge(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_ge(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (signed comparison).
static ASMJIT_INLINE UniCondition scmp_ge(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kSignedGE, a, b); }
//! Constructs a condition that would be `true` when `a < b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_lt(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a < b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_lt(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a < b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_lt(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLT, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_le(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_le(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
//! Constructs a condition that would be `true` when `a <= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_le(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedLE, a, b); }
//! Constructs a condition that would be `true` when `a > b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_gt(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
//! Constructs a condition that would be `true` when `a > b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_gt(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
//! Constructs a condition that would be `true` when `a > b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_gt(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGT, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_ge(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_ge(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a >= b` (unsigned comparison).
static ASMJIT_INLINE UniCondition ucmp_ge(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kUnsignedGE, a, b); }
//! Constructs a condition that would be `true` when `a` is zero.
static ASMJIT_INLINE UniCondition test_z(const Gp& a) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kEqual, a, Imm(0)); }
//! Constructs a condition that would be `true` when `a` is non-zero.
static ASMJIT_INLINE UniCondition test_nz(const Gp& a) noexcept { return UniCondition(UniOpCond::kCompare, CondCode::kNotEqual, a, Imm(0)); }
//! Constructs a condition that would be `true` when `a & b` is zero.
static ASMJIT_INLINE UniCondition test_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a & b` is zero.
static ASMJIT_INLINE UniCondition test_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a & b` is zero.
static ASMJIT_INLINE UniCondition test_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kZero, a, b); }
//! Constructs a condition that would be `true` when `a & b` is non-zero.
static ASMJIT_INLINE UniCondition test_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a & b` is non-zero.
static ASMJIT_INLINE UniCondition test_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when `a & b` is non-zero.
static ASMJIT_INLINE UniCondition test_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kTest, CondCode::kNotZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is zero (`((a >> b) & 1) == 0`).
static ASMJIT_INLINE UniCondition bt_z(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is zero (`((a >> b) & 1) == 0`).
static ASMJIT_INLINE UniCondition bt_z(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is zero (`((a >> b) & 1) == 0`).
static ASMJIT_INLINE UniCondition bt_z(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is non-zero (`((a >> b) & 1) == 1`).
static ASMJIT_INLINE UniCondition bt_nz(const Gp& a, const Gp& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is non-zero (`((a >> b) & 1) == 1`).
static ASMJIT_INLINE UniCondition bt_nz(const Gp& a, const Mem& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
//! Constructs a condition that would be `true` when a bit in `a` at `b` is non-zero (`((a >> b) & 1) == 1`).
static ASMJIT_INLINE UniCondition bt_nz(const Gp& a, const Imm& b) noexcept { return UniCondition(UniOpCond::kBitTest, CondCode::kBTNotZero, a, b); }
//! \}
ASMJIT_END_SUB_NAMESPACE
#endif // !ASMJIT_NO_UJIT
#endif // ASMJIT_UJIT_UNICONDITION_H_INCLUDED

File diff suppressed because it is too large Load Diff

View File

@@ -6,7 +6,7 @@
#ifndef ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED #ifndef ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED
#define ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED #define ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED
#include "ujitbase.h" #include "../core/globals.h"
#if !defined(ASMJIT_NO_UJIT) #if !defined(ASMJIT_NO_UJIT)
@@ -18,6 +18,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
template<typename T, size_t W> template<typename T, size_t W>
struct VecConst; struct VecConst;
//! \cond
//! A 64-bit vector constant of type `T` aligned to 64 bits. //! A 64-bit vector constant of type `T` aligned to 64 bits.
template<typename T> template<typename T>
struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(8) VecConst<T, 8> { struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(8) VecConst<T, 8> {
@@ -30,6 +32,12 @@ struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(8) VecConst<T, 8> {
static_assert(kElementCount > 0u, "Vector constant must have at least one element"); static_assert(kElementCount > 0u, "Vector constant must have at least one element");
ElementType data[kElementCount]; ElementType data[kElementCount];
template<typename DstT>
ASMJIT_INLINE_NODEBUG const DstT& as() const noexcept {
static_assert(sizeof(DstT) <= sizeof(*this), "Size of the destination type DstT must be <= 8");
return *static_cast<const DstT*>(static_cast<const void*>(this));
}
}; };
//! A 128-bit vector constant of type `T` aligned to 128 bits. //! A 128-bit vector constant of type `T` aligned to 128 bits.
@@ -44,6 +52,12 @@ struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(16) VecConst<T, 16> {
static_assert(kElementCount > 0u, "Vector constant must have at least one element"); static_assert(kElementCount > 0u, "Vector constant must have at least one element");
ElementType data[kElementCount]; ElementType data[kElementCount];
template<typename DstT>
ASMJIT_INLINE_NODEBUG const DstT& as() const noexcept {
static_assert(sizeof(DstT) <= sizeof(*this), "Size of the destination type DstT must be <= 16");
return *static_cast<const DstT*>(static_cast<const void*>(this));
}
}; };
//! A 256-bit vector constant of type `T` aligned to 256 bits. //! A 256-bit vector constant of type `T` aligned to 256 bits.
@@ -58,6 +72,12 @@ struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(32) VecConst<T, 32> {
static_assert(kElementCount > 0u, "Vector constant must have at least one element"); static_assert(kElementCount > 0u, "Vector constant must have at least one element");
ElementType data[kElementCount]; ElementType data[kElementCount];
template<typename DstT>
ASMJIT_INLINE_NODEBUG const DstT& as() const noexcept {
static_assert(sizeof(DstT) <= sizeof(*this), "Size of the destination type DstT must be <= 32");
return *static_cast<const DstT*>(static_cast<const void*>(this));
}
}; };
//! A 512-bit vector constant of type `T` aligned to 512 bits. //! A 512-bit vector constant of type `T` aligned to 512 bits.
@@ -72,8 +92,16 @@ struct ASMJIT_MAY_ALIAS ASMJIT_ALIGNAS(64) VecConst<T, 64> {
static_assert(kElementCount > 0u, "Vector constant must have at least one element"); static_assert(kElementCount > 0u, "Vector constant must have at least one element");
ElementType data[kElementCount]; ElementType data[kElementCount];
template<typename DstT>
ASMJIT_INLINE_NODEBUG const DstT& as() const noexcept {
static_assert(sizeof(DstT) <= sizeof(*this), "Size of the destination type DstT must be <= 64");
return *static_cast<const DstT*>(static_cast<const void*>(this));
}
}; };
//! \endcond
template<typename T> using VecConst64 = VecConst<T, 8>; template<typename T> using VecConst64 = VecConst<T, 8>;
template<typename T> using VecConst128 = VecConst<T, 16>; template<typename T> using VecConst128 = VecConst<T, 16>;
template<typename T> using VecConst256 = VecConst<T, 32>; template<typename T> using VecConst256 = VecConst<T, 32>;
@@ -397,18 +425,27 @@ struct VecConstTable {
VecConstNative<uint64_t> p_0000800000008000 = make_const<VecConstNative<uint64_t>>(uint64_t(0x0000800000008000u)); VecConstNative<uint64_t> p_0000800000008000 = make_const<VecConstNative<uint64_t>>(uint64_t(0x0000800000008000u));
VecConst128<uint32_t> sign32_scalar = make_const<VecConst128<uint32_t>>(0u, 0u, 0u, uint32_t(0x80000000u)); VecConst128<uint32_t> sign32_scalar = make_const<VecConst128<uint32_t>>(0u, 0u, 0u, uint32_t(0x80000000u));
VecConst128<uint64_t> sign64_scalar = make_const<VecConst128<uint64_t>>(uint64_t(0u), uint64_t(0x8000000000000000u)); VecConst128<uint64_t> sign64_scalar = make_const<VecConst128<uint64_t>>(uint64_t(0u), uint64_t(0x8000000000000000u));
VecConstNative<float> f32_1 = make_const<VecConstNative<float>>(1.0f); VecConstNative<uint64_t> f32_0_5_minus_1ulp = make_const<VecConstNative<uint64_t>>(0x3EFFFFFF3EFFFFFFu); // 0.49999997 (0.5f - 1ulp)
VecConstNative<float> f32_round_max = make_const<VecConstNative<float>>(8388608.0f); VecConstNative<float> f32_0_5 = make_const<VecConstNative<float>>(0.5f);
VecConstNative<float> f32_1 = make_const<VecConstNative<float>>(1.0f);
VecConstNative<float> f32_round_magic = make_const<VecConstNative<float>>(8388608.0f);
VecConstNative<double> f64_1 = make_const<VecConstNative<double>>(1.0); VecConstNative<uint64_t> f64_0_5_minus_1ulp = make_const<VecConstNative<uint64_t>>(0x3FDFFFFFFFFFFFFFu); // 0.49999999999999994 (0.5 - 1ulp).
VecConstNative<double> f64_round_max = make_const<VecConstNative<double>>(4503599627370496.0); VecConstNative<double> f64_0_5 = make_const<VecConstNative<double>>(0.5);
VecConstNative<double> f64_1 = make_const<VecConstNative<double>>(1.0);
VecConstNative<double> f64_round_magic = make_const<VecConstNative<double>>(4503599627370496.0);
}; };
ASMJIT_VARAPI const VecConstTable vec_const_table; ASMJIT_VARAPI const VecConstTable vec_const_table;
struct VecConstTableRef {
const VecConstTable& table;
size_t size;
};
//! \} //! \}
ASMJIT_END_SUB_NAMESPACE ASMJIT_END_SUB_NAMESPACE

View File

@@ -511,99 +511,182 @@ public:
//! \name Virtual Registers //! \name Virtual Registers
//! \{ //! \{
#ifndef ASMJIT_NO_LOGGING //! Creates a new general-purpose register with `type_id` type and optional name passed via `args`.
# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ //!
_new_reg_fmt(Out<Reg>{OUT}, PARAM, FORMAT, ARGS) //! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_gp8(),
#else //! \ref new_gp16(), \ref new_gp32(), \ref new_gp64(), and \ref new_gpz() or \ref new_gp_ptr().
# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \ template<typename... Args>
Support::maybe_unused(FORMAT); \ ASMJIT_INLINE_NODEBUG Gp new_gp(TypeId type_id, Args&&... args) { return new_reg<Gp>(type_id, std::forward<Args>(args)...); }
Support::maybe_unused(std::forward<Args>(args)...); \
_new_reg(Out<Reg>{OUT}, PARAM)
#endif
#define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \ //! Creates a new vector register with `type_id` type and optional name passed via `args`.
ASMJIT_INLINE_NODEBUG REG FUNC(TypeId type_id) { \ //!
REG reg(Globals::NoInit); \ //! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_vec128(),
_new_reg(Out<Reg>{reg}, type_id); \ //! \ref new_vec256(), \ref new_vec512(), or alternatively \ref new_xmm(), \ref new_ymm(), and \ref new_zmm().
return reg; \ template<typename... Args>
} \ ASMJIT_INLINE_NODEBUG Vec new_vec(TypeId type_id, Args&&... args) { return new_reg<Vec>(type_id, std::forward<Args>(args)...); }
\
template<typename... Args> \
ASMJIT_INLINE_NODEBUG REG FUNC(TypeId type_id, const char* fmt, Args&&... args) {\
REG reg(Globals::NoInit); \
ASMJIT_NEW_REG_FMT(reg, type_id, fmt, std::forward<Args>(args)...); \
return reg; \
}
#define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \ //! Creates a new mask register with `type_id` type and optional name passed via `args`.
ASMJIT_INLINE_NODEBUG REG FUNC() { \ template<typename... Args>
REG reg(Globals::NoInit); \ ASMJIT_INLINE_NODEBUG KReg new_k(TypeId type_id, Args&&... args) { return new_reg<KReg>(type_id, std::forward<Args>(args)...); }
_new_reg(Out<Reg>{reg}, TYPE_ID); \
return reg; \
} \
\
template<typename... Args> \
ASMJIT_INLINE_NODEBUG REG FUNC(const char* fmt, Args&&... args) { \
REG reg(Globals::NoInit); \
ASMJIT_NEW_REG_FMT(reg, TYPE_ID, fmt, std::forward<Args>(args)...); \
return reg; \
}
template<typename RegT> //! Creates a new 8-bit general purpose register mapped to low 8 bits of a full register.
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref) { //!
RegT reg(Globals::NoInit); //! \note Using 8-bit registers is not recommended, use at least 32-bit registers in portable code.
_new_reg(Out<Reg>(reg), ref); template<typename... Args>
return reg; ASMJIT_INLINE_NODEBUG Gp new_gp8(Args&&... args) { return new_reg<Gp>(TypeId::kUInt8, std::forward<Args>(args)...); }
}
template<typename RegT, typename... Args> //! Creates a new 16-bit general purpose register mapped to low 16 bits of a full register.
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref, const char* fmt, Args&&... args) { //!
RegT reg(Globals::NoInit); //! \note Using 16-bit registers is not recommended, use at least 32-bit registers in portable code.
ASMJIT_NEW_REG_FMT(reg, ref, fmt, std::forward<Args>(args)...); template<typename... Args>
return reg; ASMJIT_INLINE_NODEBUG Gp new_gp16(Args&&... args) { return new_reg<Gp>(TypeId::kUInt16, std::forward<Args>(args)...); }
}
ASMJIT_NEW_REG_CUSTOM(new_reg , Reg ) //! Creates a new 32-bit general purpose register mapped to low 32 bits of a full register (on 64-bit targets).
ASMJIT_NEW_REG_CUSTOM(new_gp , Gp ) template<typename... Args>
ASMJIT_NEW_REG_CUSTOM(new_vec , Vec ) ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return new_reg<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_CUSTOM(new_kreg , KReg)
ASMJIT_NEW_REG_TYPED(new_gp8 , Gp , TypeId::kUInt8) //! Creates a new 64-bit general purpose register.
ASMJIT_NEW_REG_TYPED(new_gp16 , Gp , TypeId::kUInt16) //!
ASMJIT_NEW_REG_TYPED(new_gp32 , Gp , TypeId::kUInt32) //! \warning The target must be 64-bit in order to create 64-bit registers.
ASMJIT_NEW_REG_TYPED(new_gp64 , Gp , TypeId::kUInt64) template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp64(Args&&... args) { return new_reg<Gp>(TypeId::kUInt64, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_gpb , Gp , TypeId::kUInt8) //! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
ASMJIT_NEW_REG_TYPED(new_gpw , Gp , TypeId::kUInt16) template<typename... Args>
ASMJIT_NEW_REG_TYPED(new_gpd , Gp , TypeId::kUInt32) ASMJIT_INLINE_NODEBUG Gp new_gpz(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_gpq , Gp , TypeId::kUInt64)
ASMJIT_NEW_REG_TYPED(new_gpz , Gp , TypeId::kUIntPtr)
ASMJIT_NEW_REG_TYPED(new_gp_ptr, Gp , TypeId::kUIntPtr)
ASMJIT_NEW_REG_TYPED(new_xmm , Vec , TypeId::kInt32x4) //! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
ASMJIT_NEW_REG_TYPED(new_xmm_ss, Vec , TypeId::kFloat32x1) //!
ASMJIT_NEW_REG_TYPED(new_xmm_sd, Vec , TypeId::kFloat64x1) //! \note This is just an alternative name that maps more closely to C's `uintptr_t`, it's the same function as
ASMJIT_NEW_REG_TYPED(new_xmm_ps, Vec , TypeId::kFloat32x4) //! \ref new_gpz().
ASMJIT_NEW_REG_TYPED(new_xmm_pd, Vec , TypeId::kFloat64x2) template<typename... Args>
ASMJIT_INLINE_NODEBUG Gp new_gp_ptr(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_ymm , Vec , TypeId::kInt32x8) //! Creates a new 128-bit vector register (XMM).
ASMJIT_NEW_REG_TYPED(new_ymm_ps, Vec , TypeId::kFloat32x8) template<typename... Args>
ASMJIT_NEW_REG_TYPED(new_ymm_pd, Vec , TypeId::kFloat64x4) ASMJIT_INLINE_NODEBUG Vec new_vec128(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x4, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_zmm , Vec , TypeId::kInt32x16) //! Creates a new 128-bit vector register (XMM) that will be used for scalar 32-bit floating point operation.
ASMJIT_NEW_REG_TYPED(new_zmm_ps, Vec , TypeId::kFloat32x16) template<typename... Args>
ASMJIT_NEW_REG_TYPED(new_zmm_pd, Vec , TypeId::kFloat64x8) ASMJIT_INLINE_NODEBUG Vec new_vec128_f32x1(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x1, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_mm , Mm , TypeId::kMmx64) //! Creates a new 128-bit vector register (XMM) that will be used for scalar 64-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec128_f64x1(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x1, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_kb , KReg, TypeId::kMask8) //! Creates a new 128-bit vector register (XMM) that will be used for packed 32-bit floating point operation.
ASMJIT_NEW_REG_TYPED(new_kw , KReg, TypeId::kMask16) template<typename... Args>
ASMJIT_NEW_REG_TYPED(new_kd , KReg, TypeId::kMask32) ASMJIT_INLINE_NODEBUG Vec new_vec128_f32x4(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x4, std::forward<Args>(args)...); }
ASMJIT_NEW_REG_TYPED(new_kq , KReg, TypeId::kMask64)
#undef ASMJIT_NEW_REG_TYPED //! Creates a new 128-bit vector register (XMM) that will be used for packed 64-bit floating point operation.
#undef ASMJIT_NEW_REG_CUSTOM template<typename... Args>
#undef ASMJIT_NEW_REG_FMT ASMJIT_INLINE_NODEBUG Vec new_vec128_f64x2(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x2, std::forward<Args>(args)...); }
//! Creates a new 256-bit vector register (YMM).
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec256(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x8, std::forward<Args>(args)...); }
//! Creates a new 256-bit vector register (YMM) that will be used for packed 32-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec256_f32x8(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x8, std::forward<Args>(args)...); }
//! Creates a new 256-bit vector register (YMM) that will be used for packed 64-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec256_f64x4(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x4, std::forward<Args>(args)...); }
//! Creates a new 512-bit vector register (ZMM).
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec512(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x16, std::forward<Args>(args)...); }
//! Creates a new 512-bit vector register (ZMM) that will be used for packed 32-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec512_f32x16(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x16, std::forward<Args>(args)...); }
//! Creates a new 512-bit vector register (ZMM) that will be used for packed 64-bit floating point operation.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_vec512_f64x8(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x8, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_xmm(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x4, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128_f32x1() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_xmm_ss(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x1, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128_f64x1() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_xmm_sd(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x1, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128_f32x4() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_xmm_ps(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x4, std::forward<Args>(args)...); }
//! Alias of \ref new_vec128_f64x2() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_xmm_pd(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x2, std::forward<Args>(args)...); }
//! Alias of \ref new_vec256() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_ymm(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x8, std::forward<Args>(args)...); }
//! Alias of \ref new_vec256_f32x8() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_ymm_ps(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x8, std::forward<Args>(args)...); }
//! Alias of \ref new_vec256_f64x4() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_ymm_pd(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x4, std::forward<Args>(args)...); }
//! Alias of \ref new_vec512() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_zmm(Args&&... args) { return new_reg<Vec>(TypeId::kInt32x16, std::forward<Args>(args)...); }
//! Alias of \ref new_vec512_f32x16() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_zmm_ps(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x16, std::forward<Args>(args)...); }
//! Alias of \ref new_vec512_f64x8() that matches x86 architecture terminology.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Vec new_zmm_pd(Args&&... args) { return new_reg<Vec>(TypeId::kFloat64x8, std::forward<Args>(args)...); }
//! Creates a new 64-bit MMX register.
//!
//! \note MMX ISA is generally deprecated by the X86 architecture.
template<typename... Args>
ASMJIT_INLINE_NODEBUG Mm new_mm(Args&&... args) { return new_reg<Mm>(TypeId::kMmx64, std::forward<Args>(args)...); }
//! Creates a new 8-bit mask (K) register.
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_k8(Args&&... args) { return new_reg<KReg>(TypeId::kMask8, std::forward<Args>(args)...); }
//! Creates a new 16-bit mask (K) register.
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_k16(Args&&... args) { return new_reg<KReg>(TypeId::kMask16, std::forward<Args>(args)...); }
//! Creates a new 32-bit mask (K) register.
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_k32(Args&&... args) { return new_reg<KReg>(TypeId::kMask32, std::forward<Args>(args)...); }
//! Creates a new 64-bit mask (K) register.
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_k64(Args&&... args) { return new_reg<KReg>(TypeId::kMask64, std::forward<Args>(args)...); }
//! Creates a new 8-bit mask (K) register, alias of \ref new_k8().
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_kb(Args&&... args) { return new_reg<KReg>(TypeId::kMask8, std::forward<Args>(args)...); }
//! Creates a new 16-bit mask (K) register, alias of \ref new_k16().
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_kw(Args&&... args) { return new_reg<KReg>(TypeId::kMask16, std::forward<Args>(args)...); }
//! Creates a new 32-bit mask (K) register, alias of \ref new_k32().
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_kd(Args&&... args) { return new_reg<KReg>(TypeId::kMask32, std::forward<Args>(args)...); }
//! Creates a new 64-bit mask (K) register, alias of \ref new_k64().
template<typename... Args>
ASMJIT_INLINE_NODEBUG KReg new_kq(Args&&... args) { return new_reg<KReg>(TypeId::kMask64, std::forward<Args>(args)...); }
//! \} //! \}

View File

@@ -561,7 +561,7 @@ struct ImmBits {
char text[48 - 3]; char text[48 - 3];
}; };
ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t imm8, uint32_t bits, uint32_t count) noexcept { ASMJIT_FAVOR_SIZE static Error FormatterInternal_format_imm_shuf(String& sb, uint32_t imm8, uint32_t bits, uint32_t count) noexcept {
uint32_t mask = (1 << bits) - 1; uint32_t mask = (1 << bits) - 1;
uint32_t last_predicate_shift = bits * (count - 1u); uint32_t last_predicate_shift = bits * (count - 1u);
@@ -576,7 +576,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint3
return Error::kOk; return Error::kOk;
} }
ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t imm8, const ImmBits* bits, uint32_t count) noexcept { ASMJIT_FAVOR_SIZE static Error FormatterInternal_format_imm_bits(String& sb, uint32_t imm8, const ImmBits* bits, uint32_t count) noexcept {
uint32_t n = 0; uint32_t n = 0;
char buf[64]; char buf[64];
@@ -615,7 +615,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint3
return Error::kOk; return Error::kOk;
} }
ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t imm8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { ASMJIT_FAVOR_SIZE static Error FormatterInternal_format_imm_text(String& sb, uint32_t imm8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept {
uint32_t mask = (1u << bits) - 1; uint32_t mask = (1u << bits) - 1;
uint32_t pos = 0; uint32_t pos = 0;
@@ -628,7 +628,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint3
return sb.append(kImmCharEnd); return sb.append(kImmCharEnd);
} }
ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst( ASMJIT_FAVOR_SIZE static Error FormatterInternal_explain_const(
String& sb, String& sb,
FormatFlags format_flags, FormatFlags format_flags,
InstId inst_id, InstId inst_id,
@@ -700,55 +700,55 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
}; };
static const ImmBits vroundxx[] = { static const ImmBits vroundxx[] = {
{ 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "\0" "\0" "\0" "\0" }, { 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "CURRENT\0" "\0" "\0" "\0" },
{ 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" } { 0x08u, 3, ImmBits::kModeLookup, "\0" "SUPPRESS\0" }
}; };
uint32_t u8 = imm.value_as<uint8_t>(); uint32_t u8 = imm.value_as<uint8_t>();
switch (inst_id) { switch (inst_id) {
case Inst::kIdVblendpd: case Inst::kIdVblendpd:
case Inst::kIdBlendpd: case Inst::kIdBlendpd:
return FormatterInternal_formatImmShuf(sb, u8, 1, vec_size / 8); return FormatterInternal_format_imm_shuf(sb, u8, 1, vec_size / 8);
case Inst::kIdVblendps: case Inst::kIdVblendps:
case Inst::kIdBlendps: case Inst::kIdBlendps:
return FormatterInternal_formatImmShuf(sb, u8, 1, vec_size / 4); return FormatterInternal_format_imm_shuf(sb, u8, 1, vec_size / 4);
case Inst::kIdVcmppd: case Inst::kIdVcmppd:
case Inst::kIdVcmpps: case Inst::kIdVcmpps:
case Inst::kIdVcmpsd: case Inst::kIdVcmpsd:
case Inst::kIdVcmpss: case Inst::kIdVcmpss:
return FormatterInternal_formatImmText(sb, u8, 5, 0, vcmpx); return FormatterInternal_format_imm_text(sb, u8, 5, 0, vcmpx);
case Inst::kIdCmppd: case Inst::kIdCmppd:
case Inst::kIdCmpps: case Inst::kIdCmpps:
case Inst::kIdCmpsd: case Inst::kIdCmpsd:
case Inst::kIdCmpss: case Inst::kIdCmpss:
return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx); return FormatterInternal_format_imm_text(sb, u8, 3, 0, vcmpx);
case Inst::kIdVdbpsadbw: case Inst::kIdVdbpsadbw:
return FormatterInternal_formatImmShuf(sb, u8, 2, 4); return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
case Inst::kIdVdppd: case Inst::kIdVdppd:
case Inst::kIdVdpps: case Inst::kIdVdpps:
case Inst::kIdDppd: case Inst::kIdDppd:
case Inst::kIdDpps: case Inst::kIdDpps:
return FormatterInternal_formatImmShuf(sb, u8, 1, 8); return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
case Inst::kIdVmpsadbw: case Inst::kIdVmpsadbw:
case Inst::kIdMpsadbw: case Inst::kIdMpsadbw:
return FormatterInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vec_size / 8, 4)); return FormatterInternal_format_imm_bits(sb, u8, vmpsadbw, Support::min<uint32_t>(vec_size / 8, 4));
case Inst::kIdVpblendw: case Inst::kIdVpblendw:
case Inst::kIdPblendw: case Inst::kIdPblendw:
return FormatterInternal_formatImmShuf(sb, u8, 1, 8); return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
case Inst::kIdVpblendd: case Inst::kIdVpblendd:
return FormatterInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vec_size / 4, 8)); return FormatterInternal_format_imm_shuf(sb, u8, 1, Support::min<uint32_t>(vec_size / 4, 8));
case Inst::kIdVpclmulqdq: case Inst::kIdVpclmulqdq:
case Inst::kIdPclmulqdq: case Inst::kIdPclmulqdq:
return FormatterInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); return FormatterInternal_format_imm_bits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq));
case Inst::kIdVroundpd: case Inst::kIdVroundpd:
case Inst::kIdVroundps: case Inst::kIdVroundps:
@@ -758,57 +758,57 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
case Inst::kIdRoundps: case Inst::kIdRoundps:
case Inst::kIdRoundsd: case Inst::kIdRoundsd:
case Inst::kIdRoundss: case Inst::kIdRoundss:
return FormatterInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); return FormatterInternal_format_imm_bits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx));
case Inst::kIdVshufpd: case Inst::kIdVshufpd:
case Inst::kIdShufpd: case Inst::kIdShufpd:
return FormatterInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vec_size / 8, 8)); return FormatterInternal_format_imm_text(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vec_size / 8, 8));
case Inst::kIdVshufps: case Inst::kIdVshufps:
case Inst::kIdShufps: case Inst::kIdShufps:
return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4); return FormatterInternal_format_imm_text(sb, u8, 2, 4, vshufps, 4);
case Inst::kIdVcvtps2ph: case Inst::kIdVcvtps2ph:
return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1); return FormatterInternal_format_imm_bits(sb, u8, vroundxx, 1);
case Inst::kIdVperm2f128: case Inst::kIdVperm2f128:
case Inst::kIdVperm2i128: case Inst::kIdVperm2i128:
return FormatterInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); return FormatterInternal_format_imm_bits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128));
case Inst::kIdVpermilpd: case Inst::kIdVpermilpd:
return FormatterInternal_formatImmShuf(sb, u8, 1, vec_size / 8); return FormatterInternal_format_imm_shuf(sb, u8, 1, vec_size / 8);
case Inst::kIdVpermilps: case Inst::kIdVpermilps:
return FormatterInternal_formatImmShuf(sb, u8, 2, 4); return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
case Inst::kIdVpshufd: case Inst::kIdVpshufd:
case Inst::kIdPshufd: case Inst::kIdPshufd:
return FormatterInternal_formatImmShuf(sb, u8, 2, 4); return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
case Inst::kIdVpshufhw: case Inst::kIdVpshufhw:
case Inst::kIdVpshuflw: case Inst::kIdVpshuflw:
case Inst::kIdPshufhw: case Inst::kIdPshufhw:
case Inst::kIdPshuflw: case Inst::kIdPshuflw:
case Inst::kIdPshufw: case Inst::kIdPshufw:
return FormatterInternal_formatImmShuf(sb, u8, 2, 4); return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
case Inst::kIdVfixupimmpd: case Inst::kIdVfixupimmpd:
case Inst::kIdVfixupimmps: case Inst::kIdVfixupimmps:
case Inst::kIdVfixupimmsd: case Inst::kIdVfixupimmsd:
case Inst::kIdVfixupimmss: case Inst::kIdVfixupimmss:
return FormatterInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx)); return FormatterInternal_format_imm_bits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx));
case Inst::kIdVfpclasspd: case Inst::kIdVfpclasspd:
case Inst::kIdVfpclassps: case Inst::kIdVfpclassps:
case Inst::kIdVfpclasssd: case Inst::kIdVfpclasssd:
case Inst::kIdVfpclassss: case Inst::kIdVfpclassss:
return FormatterInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); return FormatterInternal_format_imm_bits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx));
case Inst::kIdVgetmantpd: case Inst::kIdVgetmantpd:
case Inst::kIdVgetmantps: case Inst::kIdVgetmantps:
case Inst::kIdVgetmantsd: case Inst::kIdVgetmantsd:
case Inst::kIdVgetmantss: case Inst::kIdVgetmantss:
return FormatterInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); return FormatterInternal_format_imm_bits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx));
case Inst::kIdVpcmpb: case Inst::kIdVpcmpb:
case Inst::kIdVpcmpd: case Inst::kIdVpcmpd:
@@ -818,7 +818,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
case Inst::kIdVpcmpud: case Inst::kIdVpcmpud:
case Inst::kIdVpcmpuq: case Inst::kIdVpcmpuq:
case Inst::kIdVpcmpuw: case Inst::kIdVpcmpuw:
return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcmpx); return FormatterInternal_format_imm_text(sb, u8, 3, 0, vpcmpx);
case Inst::kIdVpcomb: case Inst::kIdVpcomb:
case Inst::kIdVpcomd: case Inst::kIdVpcomd:
@@ -828,21 +828,21 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
case Inst::kIdVpcomud: case Inst::kIdVpcomud:
case Inst::kIdVpcomuq: case Inst::kIdVpcomuq:
case Inst::kIdVpcomuw: case Inst::kIdVpcomuw:
return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcomx); return FormatterInternal_format_imm_text(sb, u8, 3, 0, vpcomx);
case Inst::kIdVpermq: case Inst::kIdVpermq:
case Inst::kIdVpermpd: case Inst::kIdVpermpd:
return FormatterInternal_formatImmShuf(sb, u8, 2, 4); return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
case Inst::kIdVpternlogd: case Inst::kIdVpternlogd:
case Inst::kIdVpternlogq: case Inst::kIdVpternlogq:
return FormatterInternal_formatImmShuf(sb, u8, 1, 8); return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
case Inst::kIdVrangepd: case Inst::kIdVrangepd:
case Inst::kIdVrangeps: case Inst::kIdVrangeps:
case Inst::kIdVrangesd: case Inst::kIdVrangesd:
case Inst::kIdVrangess: case Inst::kIdVrangess:
return FormatterInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); return FormatterInternal_format_imm_bits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx));
case Inst::kIdVreducepd: case Inst::kIdVreducepd:
case Inst::kIdVreduceps: case Inst::kIdVreduceps:
@@ -852,7 +852,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
case Inst::kIdVrndscaleps: case Inst::kIdVrndscaleps:
case Inst::kIdVrndscalesd: case Inst::kIdVrndscalesd:
case Inst::kIdVrndscaless: case Inst::kIdVrndscaless:
return FormatterInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); return FormatterInternal_format_imm_bits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx));
case Inst::kIdVshuff32x4: case Inst::kIdVshuff32x4:
case Inst::kIdVshuff64x2: case Inst::kIdVshuff64x2:
@@ -860,7 +860,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
case Inst::kIdVshufi64x2: { case Inst::kIdVshufi64x2: {
uint32_t count = Support::max<uint32_t>(vec_size / 16, 2u); uint32_t count = Support::max<uint32_t>(vec_size / 16, 2u);
uint32_t bits = count <= 2 ? 1u : 2u; uint32_t bits = count <= 2 ? 1u : 2u;
return FormatterInternal_formatImmShuf(sb, u8, bits, count); return FormatterInternal_format_imm_shuf(sb, u8, bits, count);
} }
default: default:
@@ -969,7 +969,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::format_instruction(
vec_size = Support::max<uint32_t>(vec_size, operands[j].as<Reg>().size()); vec_size = Support::max<uint32_t>(vec_size, operands[j].as<Reg>().size());
} }
} }
ASMJIT_PROPAGATE(FormatterInternal_explainConst(sb, format_flags, inst_id, vec_size, op.as<Imm>())); ASMJIT_PROPAGATE(FormatterInternal_explain_const(sb, format_flags, inst_id, vec_size, op.as<Imm>()));
} }
// Support AVX-512 masking - {k}{z}. // Support AVX-512 masking - {k}{z}.

View File

@@ -8,8 +8,8 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asmjitutils.h" #include "../commons/asmjitutils.h"
#include "cmdline.h" #include "../commons/cmdline.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -7,8 +7,9 @@
#define ASMJIT_TEST_PERF_H_INCLUDED #define ASMJIT_TEST_PERF_H_INCLUDED
#include <asmjit/core.h> #include <asmjit/core.h>
#include "asmjitutils.h"
#include "performancetimer.h" #include "../commons/asmjitutils.h"
#include "../commons/performancetimer.h"
namespace asmjit_perf_utils { namespace asmjit_perf_utils {

View File

@@ -13,7 +13,7 @@
#include <string.h> #include <string.h>
#include "asmjit_bench_codegen.h" #include "asmjit_bench_codegen.h"
#include "asmjit_test_misc.h" #include "../tests/asmjit_test_misc.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -1,9 +1,9 @@
#include <stdint.h> #include <stdint.h>
#include <asmjit/host.h> #include <asmjit/host.h>
#include "asmjitutils.h" #include "../commons/asmjitutils.h"
#include "cmdline.h" #include "../commons/cmdline.h"
#include "performancetimer.h" #include "../commons/performancetimer.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -20,13 +20,12 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
#include "asmjitutils.h" #include "../commons/asmjitutils.h"
#if !defined(ASMJIT_NO_COMPILER) #if !defined(ASMJIT_NO_COMPILER)
#include "cmdline.h" #include "../commons/cmdline.h"
#include "performancetimer.h" #include "../commons/performancetimer.h"
#include "asmjit_test_compiler.h" #include "../commons/random.h"
#include "asmjit_test_random.h"
#endif #endif
using namespace asmjit; using namespace asmjit;

View File

@@ -88,6 +88,8 @@ static void print_cpu_info() noexcept {
// CPU Features // CPU Features
// ------------ // ------------
using asmjit::CpuHints;
#ifndef ASMJIT_NO_LOGGING #ifndef ASMJIT_NO_LOGGING
printf("CPU Features:\n"); printf("CPU Features:\n");
asmjit::CpuFeatures::Iterator it(cpu.features().iterator()); asmjit::CpuFeatures::Iterator it(cpu.features().iterator());
@@ -99,6 +101,27 @@ static void print_cpu_info() noexcept {
}; };
printf("\n"); printf("\n");
#endif // !ASMJIT_NO_LOGGING #endif // !ASMJIT_NO_LOGGING
// CPU Hints
// ---------
printf("CPU Hints:\n");
auto print_hint = [&](CpuHints hint, const char* name) {
if ((cpu.hints() & hint) != CpuHints::kNone) {
printf(" %s\n", name);
}
};
print_hint(CpuHints::kVecMaskedOps8 , "VecMaskedOps8" );
print_hint(CpuHints::kVecMaskedOps16 , "VecMaskedOps16" );
print_hint(CpuHints::kVecMaskedOps32 , "VecMaskedOps32" );
print_hint(CpuHints::kVecMaskedOps64 , "VecMaskedOps64" );
print_hint(CpuHints::kVecFastIntMul32, "VecFastIntMul32");
print_hint(CpuHints::kVecFastIntMul64, "VecFastIntMul64");
print_hint(CpuHints::kVecFastGather , "VecFastGather" );
print_hint(CpuHints::kVecMaskedStore , "VecMaskedStore" );
printf("\n");
} }
[[maybe_unused]] [[maybe_unused]]

View File

@@ -3,8 +3,8 @@
// See <asmjit/core.h> or LICENSE.md for license and copyright information // See <asmjit/core.h> or LICENSE.md for license and copyright information
// SPDX-License-Identifier: Zlib // SPDX-License-Identifier: Zlib
#ifndef ASMJIT_TEST_RANDOM_H_INCLUDED #ifndef TESTING_COMMONS_RANDOM_H_INCLUDED
#define ASMJIT_TEST_RANDOM_H_INCLUDED #define TESTING_COMMONS_RANDOM_H_INCLUDED
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
@@ -74,4 +74,4 @@ public:
} // {anonymous} } // {anonymous}
} // {TestUtils} } // {TestUtils}
#endif // ASMJIT_TEST_RANDOM_H_INCLUDED #endif // TESTING_COMMONS_RANDOM_H_INCLUDED

View File

@@ -8,11 +8,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "asmjitutils.h"
#include "cmdline.h"
#include "asmjit_test_assembler.h" #include "asmjit_test_assembler.h"
#include "../commons/asmjitutils.h"
#include "../commons/cmdline.h"
using namespace asmjit; using namespace asmjit;
#if !defined(ASMJIT_NO_X86) #if !defined(ASMJIT_NO_X86)

View File

@@ -12,7 +12,6 @@
#include <string.h> #include <string.h>
#include "asmjit_test_assembler.h" #include "asmjit_test_assembler.h"
#include "cmdline.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -12,7 +12,6 @@
#include <string.h> #include <string.h>
#include "asmjit_test_assembler.h" #include "asmjit_test_assembler.h"
#include "cmdline.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -12,7 +12,6 @@
#include <string.h> #include <string.h>
#include "asmjit_test_assembler.h" #include "asmjit_test_assembler.h"
#include "cmdline.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -15,10 +15,10 @@
#if !defined(ASMJIT_NO_COMPILER) #if !defined(ASMJIT_NO_COMPILER)
#include "cmdline.h" #include "../commons/asmjitutils.h"
#include "performancetimer.h" #include "../commons/cmdline.h"
#include "../commons/performancetimer.h"
#include "asmjitutils.h"
#include "asmjit_test_compiler.h" #include "asmjit_test_compiler.h"
#if !defined(ASMJIT_NO_X86) #if !defined(ASMJIT_NO_X86)

View File

@@ -11,7 +11,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include "./asmjit_test_compiler.h" #include "asmjit_test_compiler.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -8,7 +8,7 @@
#include <string.h> #include <string.h>
#include <asmjit/core.h> #include <asmjit/core.h>
#include "asmjitutils.h" #include "../commons/asmjitutils.h"
#if ASMJIT_ARCH_X86 != 0 #if ASMJIT_ARCH_X86 != 0
#include <asmjit/x86.h> #include <asmjit/x86.h>

View File

@@ -13,7 +13,7 @@
#include <asmjit/a64.h> #include <asmjit/a64.h>
#endif #endif
#include "asmjitutils.h" #include "../commons/asmjitutils.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -10,7 +10,8 @@
#endif #endif
#include <stdio.h> #include <stdio.h>
#include "asmjitutils.h"
#include "../commons/asmjitutils.h"
using namespace asmjit; using namespace asmjit;

View File

@@ -6,15 +6,15 @@
#include <asmjit/core.h> #include <asmjit/core.h>
#if !defined(ASMJIT_NO_X86) #if !defined(ASMJIT_NO_X86)
#include <asmjit/x86.h> #include <asmjit/x86.h>
#endif #endif
#if !defined(ASMJIT_NO_AARCH64) #if !defined(ASMJIT_NO_AARCH64)
#include <asmjit/a64.h> #include <asmjit/a64.h>
#endif #endif
#include "asmjitutils.h"
#include "broken.h" #include "broken.h"
#include "../commons/asmjitutils.h"
#if !defined(ASMJIT_NO_COMPILER) #if !defined(ASMJIT_NO_COMPILER)
#include <asmjit/core/racfgblock_p.h> #include <asmjit/core/racfgblock_p.h>

View File

@@ -35,6 +35,10 @@ float fdiv(float a, float b) noexcept {
return _mm_cvtss_f32(_mm_div_ss(_mm_set1_ps(a), _mm_set1_ps(b))); return _mm_cvtss_f32(_mm_div_ss(_mm_set1_ps(a), _mm_set1_ps(b)));
} }
float fsqrt(float a) noexcept {
return _mm_cvtss_f32(_mm_sqrt_ss(_mm_set1_ps(a)));
}
float fmadd_nofma_ref(float a, float b, float c) noexcept { float fmadd_nofma_ref(float a, float b, float c) noexcept {
return _mm_cvtss_f32(_mm_add_ss(_mm_mul_ss(_mm_set1_ps(a), _mm_set1_ps(b)), _mm_set1_ps(c))); return _mm_cvtss_f32(_mm_add_ss(_mm_mul_ss(_mm_set1_ps(a), _mm_set1_ps(b)), _mm_set1_ps(c)));
} }
@@ -55,6 +59,10 @@ double fdiv(double a, double b) noexcept {
return _mm_cvtsd_f64(_mm_div_sd(_mm_set1_pd(a), _mm_set1_pd(b))); return _mm_cvtsd_f64(_mm_div_sd(_mm_set1_pd(a), _mm_set1_pd(b)));
} }
double fsqrt(double a) noexcept {
return _mm_cvtsd_f64(_mm_sqrt_sd(_mm_setzero_pd(), _mm_set1_pd(a)));
}
double fmadd_nofma_ref(double a, double b, double c) noexcept { double fmadd_nofma_ref(double a, double b, double c) noexcept {
return _mm_cvtsd_f64(_mm_add_sd(_mm_mul_sd(_mm_set1_pd(a), _mm_set1_pd(b)), _mm_set1_pd(c))); return _mm_cvtsd_f64(_mm_add_sd(_mm_mul_sd(_mm_set1_pd(a), _mm_set1_pd(b)), _mm_set1_pd(c)));
} }

View File

@@ -1,13 +0,0 @@
#!/bin/sh
CURRENT_DIR="`pwd`"
BUILD_DIR="${CURRENT_DIR}/../build"
BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
echo "== [Configuring Build - Debug] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Debug" -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS}
echo ""
echo "== [Configuring Build - Release] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release" -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS}
echo ""

View File

@@ -1,13 +0,0 @@
#!/bin/sh
CURRENT_DIR="`pwd`"
BUILD_DIR="${CURRENT_DIR}/../build"
BUILD_OPTIONS="-G Ninja -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
echo "== [Configuring Build - Debug] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Debug" -DCMAKE_BUILD_TYPE=Debug ${BUILD_OPTIONS}
echo ""
echo "== [Configuring Build - Release] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release" -DCMAKE_BUILD_TYPE=Release ${BUILD_OPTIONS}
echo ""

View File

@@ -1,21 +0,0 @@
#!/bin/sh
CURRENT_DIR="`pwd`"
BUILD_DIR="${CURRENT_DIR}/../build"
BUILD_OPTIONS="-DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
echo "== [Configuring Build - Release_ASAN] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release_ASAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=address
echo ""
echo "== [Configuring Build - Release_UBSAN] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release_UBSAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=undefined
echo ""
echo "== [Configuring Build - Release_MSAN] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Release_MSAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Release -DASMJIT_SANITIZE=memory
echo ""
echo "== [Configuring Build - Debug_UBSAN] =="
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}/Debug_UBSAN" ${BUILD_OPTIONS} -DCMAKE_BUILD_TYPE=Debug -DASMJIT_SANITIZE=undefined
echo ""

View File

@@ -1,2 +0,0 @@
@echo off
cmake .. -B "..\build_vs2019_x64" -G"Visual Studio 16" -A x64 -DASMJIT_TEST=1

View File

@@ -1,2 +0,0 @@
@echo off
cmake .. -B "..\build_vs2019_x86" -G"Visual Studio 16" -A Win32 -DASMJIT_TEST=1

View File

@@ -1,2 +0,0 @@
@echo off
cmake .. -B "..\build_vs2022_x64" -G"Visual Studio 17" -A x64 -DASMJIT_TEST=1

View File

@@ -1,2 +0,0 @@
@echo off
cmake .. -B "..\build_vs2022_x86" -G"Visual Studio 17" -A Win32 -DASMJIT_TEST=1

View File

@@ -1,8 +0,0 @@
#!/bin/sh
CURRENT_DIR="`pwd`"
BUILD_DIR="${CURRENT_DIR}/../build"
BUILD_OPTIONS="-G Xcode -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DASMJIT_TEST=1"
mkdir -p "${BUILD_DIR}"
eval cmake "${CURRENT_DIR}/.." -B "${BUILD_DIR}" ${BUILD_OPTIONS}