mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-16 20:17:05 +03:00
[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:
2
.github/workflows/build-config.json
vendored
2
.github/workflows/build-config.json
vendored
@@ -12,7 +12,7 @@
|
||||
],
|
||||
|
||||
"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_assembler"] },
|
||||
{ "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] },
|
||||
|
||||
31
.github/workflows/build.yml
vendored
31
.github/workflows/build.yml
vendored
@@ -18,10 +18,10 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
|
||||
- name: "Setup node.js"
|
||||
uses: actions/setup-node@v4
|
||||
uses: actions/setup-node@v5
|
||||
with:
|
||||
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-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: "macos" , host: "macos-13" , arch: "x64" , cc: "gcc-14" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "gcc-14" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "clang" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-13" , arch: "x64" , cc: "clang" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "macos" , host: "macos-14" , arch: "arm64" , cc: "clang" , 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" , arch: "x86" , cc: "clang-20", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-24.04" , arch: "x86" , cc: "clang-20", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-20", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-20", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||
- { title: "linux" , host: "ubuntu-24.04-arm", arch: "arm64" , cc: "clang-20", conf: "Debug" , 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: "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: "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: "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: "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: "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:
|
||||
- name: "Checkout"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
path: "source"
|
||||
|
||||
- name: "Checkout Build Actions"
|
||||
uses: actions/checkout@v4
|
||||
uses: actions/checkout@v5
|
||||
with:
|
||||
repository: build-actions/build-actions
|
||||
path: "build-actions"
|
||||
|
||||
- name: "Python"
|
||||
uses: actions/setup-python@v5
|
||||
uses: actions/setup-python@v6
|
||||
with:
|
||||
python-version: "3.x"
|
||||
|
||||
|
||||
181
CMakeLists.txt
181
CMakeLists.txt
@@ -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
|
||||
# it possible to support both add_subdirectory() and include() ways of using AsmJit as a
|
||||
# dependency.
|
||||
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()
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
@@ -194,7 +202,7 @@ function(asmjit_detect_sanitizers out)
|
||||
set(${out} "${_out_array}" PARENT_SCOPE)
|
||||
endfunction()
|
||||
|
||||
function(asmjit_add_target target target_type)
|
||||
function(asmjit_addapp target target_type)
|
||||
set(single_val "")
|
||||
set(multi_val SOURCES LIBRARIES CFLAGS CFLAGS_DBG CFLAGS_REL)
|
||||
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 ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS
|
||||
-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 -W4) # [+] Warning level 4.
|
||||
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG
|
||||
-GS) # [+] Buffer security-check.
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -MP) # [+] Multi-Process Compilation.
|
||||
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
|
||||
-GS- # [-] Buffer security-check.
|
||||
-O2 # [+] Favor speed over size.
|
||||
-Oi) # [+] Generate intrinsic functions.
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang|AppleClang)$")
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG -GS) # [+] Buffer security-check.
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -GS-) # [-] Buffer security-check.
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) # [+] Favor speed over size.
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -Oi) # [+] Generate intrinsic functions.
|
||||
elseif ("${CMAKE_CXX_COMPILER_ID}" MATCHES "GNU|Clang")
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -Wall -Wextra -Wconversion) # [+] Add baseline warnings that can be used safely even with system headers.
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -Wdouble-promotion) # [+] Warn about double promotions.
|
||||
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.
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS
|
||||
-Wdouble-promotion
|
||||
-Wduplicated-cond
|
||||
-Wduplicated-branches
|
||||
-Wlogical-op
|
||||
-Wrestrict
|
||||
)
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-math-errno) # [-] Disable math functions setting errno (performance reasons).
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics) # [-] Don't add guards when initializing statics (we don't need it).
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -O2) # [+] Compiling with -O2 in release mode is what we generally want.
|
||||
list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -fmerge-all-constants) # [+] We don't need unique address per constant (merging improves library size).
|
||||
|
||||
# -fno-semantic-interposition is not available on apple - the compiler issues a warning, which is not detected.
|
||||
if (APPLE)
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics)
|
||||
else()
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-threadsafe-statics -fno-semantic-interposition)
|
||||
if (NOT APPLE)
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS -fno-semantic-interposition)
|
||||
endif()
|
||||
|
||||
# The following flags can save few bytes in the resulting binary.
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL
|
||||
-fmerge-all-constants # Merge all constants even if it violates ISO C++.
|
||||
-fno-enforce-eh-specs) # Don't enforce termination if noexcept function throws.
|
||||
if (NOT "${CMAKE_SYSTEM_NAME}" STREQUAL "iOS")
|
||||
asmjit_detect_cflags(ASMJIT_PRIVATE_CFLAGS_REL -fno-enforce-eh-specs) # [-] Don't enforce termination if noexcept function throws.
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -547,9 +549,10 @@ set(ASMJIT_SRC_LIST
|
||||
asmjit/x86/x86rapass_p.h
|
||||
|
||||
asmjit/ujit/ujitbase.h
|
||||
asmjit/ujit/unicompiler.h
|
||||
asmjit/ujit/unicompiler_a64.cpp
|
||||
asmjit/ujit/unicompiler_x86.cpp
|
||||
asmjit/ujit/unicompiler.h
|
||||
asmjit/ujit/unicompiler_utils_p.h
|
||||
asmjit/ujit/uniop.h
|
||||
asmjit/ujit/vecconsttable.cpp
|
||||
asmjit/ujit/vecconsttable.h
|
||||
@@ -592,7 +595,7 @@ message(" ASMJIT_PRIVATE_CFLAGS_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
|
||||
|
||||
if (NOT ASMJIT_EMBED)
|
||||
# Add AsmJit target.
|
||||
asmjit_add_target(asmjit "${ASMJIT_TARGET_TYPE}"
|
||||
asmjit_addapp(asmjit "${ASMJIT_TARGET_TYPE}"
|
||||
SOURCES ${ASMJIT_SRC}
|
||||
LIBRARIES ${ASMJIT_DEPS}
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
@@ -632,47 +635,33 @@ if (NOT ASMJIT_EMBED)
|
||||
enable_testing()
|
||||
|
||||
# Special target that always uses embedded AsmJit.
|
||||
asmjit_add_target(asmjit_test_unit TEST
|
||||
asmjit_addapp(asmjit_test_runner TEST
|
||||
SOURCES ${ASMJIT_SRC}
|
||||
test/asmjit_test_unit.cpp
|
||||
test/broken.cpp
|
||||
test/broken.h
|
||||
testing/tests/asmjit_test_runner.cpp
|
||||
testing/tests/broken.cpp
|
||||
testing/tests/broken.h
|
||||
LIBRARIES ${ASMJIT_DEPS}
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
-DASMJIT_TEST
|
||||
-DASMJIT_STATIC
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
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
|
||||
SOURCES test/asmjit_test_assembler.cpp
|
||||
test/asmjit_test_assembler.h
|
||||
test/asmjit_test_assembler_a64.cpp
|
||||
test/asmjit_test_assembler_x64.cpp
|
||||
test/asmjit_test_assembler_x86.cpp
|
||||
asmjit_addapp(asmjit_test_assembler TEST
|
||||
SOURCES testing/tests/asmjit_test_assembler.cpp
|
||||
testing/tests/asmjit_test_assembler.h
|
||||
testing/tests/asmjit_test_assembler_a64.cpp
|
||||
testing/tests/asmjit_test_assembler_x64.cpp
|
||||
testing/tests/asmjit_test_assembler_x86.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
|
||||
asmjit_add_target(asmjit_bench_codegen EXECUTABLE
|
||||
SOURCES test/asmjit_bench_codegen.cpp
|
||||
test/asmjit_bench_codegen_a64.cpp
|
||||
test/asmjit_bench_codegen_x86.cpp
|
||||
SOURCES test/asmjit_bench_codegen.h
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
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
|
||||
foreach(app asmjit_test_environment asmjit_test_emitters asmjit_test_x86_sections)
|
||||
asmjit_addapp(${app} TEST
|
||||
SOURCES testing/tests/${app}.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
@@ -680,8 +669,8 @@ if (NOT ASMJIT_EMBED)
|
||||
endforeach()
|
||||
|
||||
if (NOT ASMJIT_NO_INTROSPECTION)
|
||||
asmjit_add_target(asmjit_test_instinfo TEST
|
||||
SOURCES test/asmjit_test_instinfo.cpp
|
||||
asmjit_addapp(asmjit_test_instinfo TEST
|
||||
SOURCES testing/tests/asmjit_test_instinfo.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
@@ -727,28 +716,48 @@ if (NOT ASMJIT_EMBED)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set_property(SOURCE test/asmjit_test_unicompiler_avx2fma.cpp APPEND PROPERTY COMPILE_OPTIONS ${ASMJIT_AVX2FMA_CFLAGS})
|
||||
|
||||
asmjit_add_target(asmjit_test_compiler TEST
|
||||
SOURCES test/asmjit_test_compiler.cpp
|
||||
test/asmjit_test_compiler.h
|
||||
test/asmjit_test_compiler_a64.cpp
|
||||
test/asmjit_test_compiler_x86.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
|
||||
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
|
||||
asmjit_addapp(asmjit_test_compiler TEST
|
||||
SOURCES testing/tests/asmjit_test_compiler.cpp
|
||||
testing/tests/asmjit_test_compiler.h
|
||||
testing/tests/asmjit_test_compiler_a64.cpp
|
||||
testing/tests/asmjit_test_compiler_x86.cpp
|
||||
LIBRARIES asmjit::asmjit
|
||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_SSE2_CFLAGS}
|
||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||
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()
|
||||
|
||||
@@ -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
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
|
||||
11
README.md
11
README.md
@@ -17,10 +17,12 @@ Project Organization
|
||||
* **src** - Source code
|
||||
* **asmjit** - Source code and headers (always point include path in here)
|
||||
* **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
|
||||
* **ujit** - Universal JIT API
|
||||
* **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
|
||||
-------
|
||||
@@ -38,6 +40,11 @@ Documentation
|
||||
* [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))
|
||||
|
||||
Development & Testing
|
||||
---------------------
|
||||
|
||||
* Basic configure scripts that invoke cmake are provided in project root.
|
||||
|
||||
Breaking Changes
|
||||
----------------
|
||||
|
||||
|
||||
11
configure.sh
Executable file
11
configure.sh
Executable 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
15
configure_sanitizers.sh
Executable 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
2
configure_vs2022_x64.bat
Normal 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
2
configure_vs2022_x86.bat
Normal file
@@ -0,0 +1,2 @@
|
||||
@echo off
|
||||
cmake . -B build_x86 -G"Visual Studio 17" -A Win32 -DASMJIT_TEST=ON
|
||||
128
db/isa_x86.json
128
db/isa_x86.json
@@ -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: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": "cmovb W: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": "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": "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": "cmovnb W: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": "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": "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": "cmovno W: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": "cmovns W: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": "cmovo W: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": "cmovs W: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": "cmovb X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 42 /r" , "io": "CF=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 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 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 X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 43 /r" , "io": "CF=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 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 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 X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 41 /r" , "io": "OF=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 X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 49 /r" , "io": "SF=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 X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 40 /r" , "io": "OF=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 X:rv, R:rv, R:rv/mv" , "op": "[VRM] EVEX.ND=1.LLZ.Pv.MAP4.Wv 48 /r" , "io": "SF=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: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"},
|
||||
@@ -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: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": "cfcmovb W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "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 W: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: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" , "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": "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 W: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: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" , "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": "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 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 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: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" , "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": "cfcmovnb W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "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 W: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: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" , "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": "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 W: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: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" , "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": "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 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 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: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" , "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": "cfcmovno W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovnp W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovns W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovnz W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovo W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovp W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovs W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "cfcmovz W: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 W?:mv, R:rv" , "op": "[MR ] EVEX.ND=0.NF=1.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 X:rv, 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": "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" },
|
||||
|
||||
@@ -4491,14 +4491,14 @@ Case_BaseLdurStur:
|
||||
goto InvalidInstruction;
|
||||
|
||||
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 (gpMustBeX && !x)
|
||||
if (gp_must_be_x && !x)
|
||||
goto InvalidInstruction;
|
||||
}
|
||||
else {
|
||||
if (x != gpMustBeX)
|
||||
if (x != gp_must_be_x)
|
||||
goto InvalidInstruction;
|
||||
}
|
||||
|
||||
|
||||
@@ -37,75 +37,87 @@ public:
|
||||
//! \name Virtual Registers
|
||||
//! \{
|
||||
|
||||
//! \cond INTERNAL
|
||||
template<typename RegT, typename Type>
|
||||
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type) {
|
||||
RegT reg(Globals::NoInit);
|
||||
_new_reg(Out<Reg>{reg}, type, nullptr);
|
||||
return reg;
|
||||
}
|
||||
//! Creates a new general-purpose register with `type_id` type and optional name passed via `args`.
|
||||
//!
|
||||
//! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_gp32(),
|
||||
//! \ref new_gp64(), and \ref new_gpz() or \ref new_gp_ptr().
|
||||
template<typename... Args>
|
||||
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>
|
||||
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type, const char* s) {
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
RegT reg(Globals::NoInit);
|
||||
_new_reg(Out<Reg>{reg}, type, s);
|
||||
return reg;
|
||||
#else
|
||||
Support::maybe_unused(s);
|
||||
return _new_reg_internal<RegT>(type);
|
||||
#endif
|
||||
}
|
||||
//! Creates a new vector register with `type_id` type and optional name passed via `args`.
|
||||
//!
|
||||
//! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_vec128(),
|
||||
//! \ref new_vec_s(), \ref new_vec_d(), \ref new_vec_q(), ...
|
||||
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 RegT, typename Type, typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG RegT _new_reg_internal(const Type& type, const char* s, Args&&... args) {
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
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
|
||||
//! Creates a new 32-bit general purpose register mapped to low 32 bits of a full register (on 64-bit targets).
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return new_reg<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
|
||||
|
||||
template<typename RegT, typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref, Args&&... args) {
|
||||
return _new_reg_internal<RegT>(ref, std::forward<Args>(args)...);
|
||||
}
|
||||
//! Creates a new 64-bit general purpose register.
|
||||
template<typename... 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>
|
||||
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>
|
||||
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>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt32, 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)...); }
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gpz(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>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gpw(Args&&... args) { return _new_reg_internal<Gp>(TypeId::kUInt32, 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)...); }
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp_ptr(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
|
||||
|
||||
//! Creates a new 128-bit vector register.
|
||||
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>
|
||||
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>
|
||||
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>
|
||||
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)...); }
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
@@ -188,19 +188,16 @@ namespace asmjit {
|
||||
//! you can just use the following CMake snippet that integrates AsmJit with your own CMake project:
|
||||
//!
|
||||
//! ```cmake
|
||||
//! cmake_minimum_required(VERSION 3.30)
|
||||
//!
|
||||
//! project(asmjit_consumer C CXX) # Both C and CXX are required.
|
||||
//! set(CMAKE_CXX_STANDARD 17) # C++17 and never is supported.
|
||||
//! cmake_minimum_required(VERSION 3.30 FATAL_ERROR)
|
||||
//! project(app C CXX)
|
||||
//!
|
||||
//! set(ASMJIT_DIR "3rdparty/asmjit") # Location of AsmJit.
|
||||
//! set(ASMJIT_STATIC TRUE) # Force static build.
|
||||
//! add_subdirectory("${ASMJIT_DIR}") # Adds AsmJit sub-project to your project.
|
||||
//!
|
||||
//! 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.
|
||||
//! add_executable(app asmjit_consumer.cpp) # Adds executable that uses AsmJit.
|
||||
//! 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.
|
||||
//! ```
|
||||
//!
|
||||
//! \section build_type Build Type Configuration
|
||||
@@ -2111,8 +2108,53 @@ namespace asmjit {
|
||||
//! \defgroup asmjit_a64 AArch64 Backend
|
||||
//! \brief AArch64 backend.
|
||||
|
||||
//! \defgroup asmjit_ujit UJIT
|
||||
//! \brief Universal JIT - abstracts X86|X86_64 and AArch64 code generation.
|
||||
//! \defgroup asmjit_ujit Universal JIT
|
||||
//! \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
|
||||
//! \defgroup asmjit_ra RA
|
||||
@@ -2122,7 +2164,16 @@ namespace asmjit {
|
||||
} // {asmjit}
|
||||
|
||||
#include "asmjit-scope-begin.h"
|
||||
#include "core/api-config.h"
|
||||
#include "core/archcommons.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/builder.h"
|
||||
#include "core/codebuffer.h"
|
||||
@@ -2149,13 +2200,6 @@ namespace asmjit {
|
||||
#include "core/target.h"
|
||||
#include "core/type.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"
|
||||
|
||||
#endif // ASMJIT_CORE_H_INCLUDED
|
||||
|
||||
@@ -68,7 +68,7 @@
|
||||
|
||||
// Include a unit testing package if this is a `asmjit_test_unit` build.
|
||||
#if defined(ASMJIT_TEST)
|
||||
#include "../../../test/broken.h"
|
||||
#include "../../../testing/tests/broken.h"
|
||||
#endif
|
||||
|
||||
#endif // ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
#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.
|
||||
#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
|
||||
//!
|
||||
@@ -27,7 +27,7 @@
|
||||
//! 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.
|
||||
#if !defined(ASMJIT_ABI_NAMESPACE)
|
||||
#define ASMJIT_ABI_NAMESPACE v1_18
|
||||
#define ASMJIT_ABI_NAMESPACE v1_19
|
||||
#endif // !ASMJIT_ABI_NAMESPACE
|
||||
|
||||
//! \}
|
||||
|
||||
@@ -21,8 +21,6 @@
|
||||
#include "../core/support.h"
|
||||
#include "../core/type.h"
|
||||
|
||||
#define ASMJIT_NO_NODE_USERDATA
|
||||
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
//! \addtogroup asmjit_builder
|
||||
|
||||
@@ -259,7 +259,7 @@ Error BaseCompiler::new_virt_reg(Out<VirtReg*> out, TypeId type_id, OperandSigna
|
||||
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;
|
||||
out->reset();
|
||||
|
||||
@@ -276,7 +276,7 @@ Error BaseCompiler::_new_reg(Out<Reg> out, TypeId type_id, const char* name) {
|
||||
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();
|
||||
|
||||
OperandSignature reg_signature;
|
||||
@@ -351,7 +351,7 @@ Error BaseCompiler::_new_reg(Out<Reg> out, const Reg& ref, const char* name) {
|
||||
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;
|
||||
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());
|
||||
}
|
||||
|
||||
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;
|
||||
StringTmp<256> sb;
|
||||
|
||||
|
||||
@@ -152,26 +152,86 @@ public:
|
||||
|
||||
//! 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
|
||||
//! specific `new_reg()` functionality instead or functions like \ref _new_reg() and \ref _new_reg_fmt().
|
||||
//! \note This function is public, but it's not generally recommended to be used by AsmJit users, use `new_reg()`,
|
||||
//! `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);
|
||||
|
||||
//! \cond INTERNAL
|
||||
|
||||
//! 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`.
|
||||
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.
|
||||
//!
|
||||
//! \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, ...);
|
||||
//! \overload
|
||||
ASMJIT_INLINE Error _new_reg_fmt(Out<Reg> out, TypeId type_id) { return _new_reg(out, type_id); }
|
||||
ASMJIT_API Error _new_reg_with_vfmt(Out<Reg> out, TypeId type_id, const char* fmt, ...);
|
||||
|
||||
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
||||
//!
|
||||
//! \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.
|
||||
[[nodiscard]]
|
||||
|
||||
@@ -593,6 +593,98 @@ static ASMJIT_FAVOR_SIZE void detect_x86_cpu(CpuInfo& cpu) noexcept {
|
||||
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}
|
||||
|
||||
#endif // ASMJIT_ARCH_X86
|
||||
@@ -2237,6 +2329,15 @@ static ASMJIT_FAVOR_SIZE void detect_arm_cpu(CpuInfo& cpu) noexcept {
|
||||
}
|
||||
#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}
|
||||
|
||||
#endif
|
||||
@@ -2261,8 +2362,9 @@ const CpuInfo& CpuInfo::host() noexcept {
|
||||
#elif ASMJIT_ARCH_ARM
|
||||
arm::detect_arm_cpu(cpu_info_local);
|
||||
#endif
|
||||
|
||||
cpu_info_local._hw_thread_count = detect_hw_thread_count();
|
||||
cpu_info_local.update_hints();
|
||||
|
||||
cpu_info_global = cpu_info_local;
|
||||
cpu_info_initialized_flag.store(1, std::memory_order_seq_cst);
|
||||
}
|
||||
@@ -2270,4 +2372,15 @@ const CpuInfo& CpuInfo::host() noexcept {
|
||||
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
|
||||
|
||||
@@ -525,6 +525,59 @@ public:
|
||||
ASMJIT_X86_FEATURE(has_amx_transpose, kAMX_TRANSPOSE)
|
||||
|
||||
#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.
|
||||
@@ -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.
|
||||
class CpuInfo {
|
||||
public:
|
||||
@@ -1142,6 +1228,9 @@ public:
|
||||
//! CPU features.
|
||||
CpuFeatures _features {};
|
||||
|
||||
//! CPU hints.
|
||||
CpuHints _hints {};
|
||||
|
||||
//! \}
|
||||
|
||||
//! \name Construction & Destruction
|
||||
@@ -1167,6 +1256,12 @@ public:
|
||||
[[nodiscard]]
|
||||
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
|
||||
@@ -1298,6 +1393,16 @@ public:
|
||||
template<typename... 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); }
|
||||
|
||||
//! \}
|
||||
};
|
||||
|
||||
|
||||
@@ -668,9 +668,9 @@ public:
|
||||
//! \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);
|
||||
|
||||
//! \}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
#include "../core/virtmem.h"
|
||||
|
||||
#if defined(ASMJIT_TEST)
|
||||
#include "../../../test/asmjit_test_random.h"
|
||||
#include "../../../testing/commons/random.h"
|
||||
#endif // ASMJIT_TEST
|
||||
|
||||
ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
@@ -15,7 +15,10 @@ JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept
|
||||
: _allocator(params) {
|
||||
_environment = Environment::host();
|
||||
_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 {}
|
||||
|
||||
@@ -11,9 +11,7 @@
|
||||
|
||||
#if defined(_MSC_VER)
|
||||
#include <intrin.h>
|
||||
#endif
|
||||
|
||||
#if defined(__BMI2__)
|
||||
#elif defined(__BMI2__)
|
||||
#include <x86intrin.h>
|
||||
#endif
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ ASMJIT_BEGIN_NAMESPACE
|
||||
|
||||
Target::Target() noexcept
|
||||
: _environment{},
|
||||
_cpu_features{} {}
|
||||
_cpu_features{},
|
||||
_cpu_hints{} {}
|
||||
Target::~Target() noexcept {}
|
||||
|
||||
ASMJIT_END_NAMESPACE
|
||||
|
||||
@@ -25,6 +25,8 @@ public:
|
||||
Environment _environment;
|
||||
//! Target CPU features.
|
||||
CpuFeatures _cpu_features;
|
||||
//! Target CPU hints.
|
||||
CpuHints _cpu_hints;
|
||||
|
||||
//! \name Construction & Destruction
|
||||
//! \{
|
||||
@@ -55,6 +57,10 @@ public:
|
||||
//! Returns target 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; }
|
||||
|
||||
//! \}
|
||||
};
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "asmjit-scope-begin.h"
|
||||
#include "ujit/ujitbase.h"
|
||||
#include "ujit/unicompiler.h"
|
||||
#include "ujit/unicondition.h"
|
||||
#include "ujit/uniop.h"
|
||||
#include "ujit/vecconsttable.h"
|
||||
#include "asmjit-scope-end.h"
|
||||
|
||||
@@ -14,23 +14,35 @@
|
||||
|
||||
#if !defined(ASMJIT_NO_UJIT)
|
||||
|
||||
//! \namespace asmjit::ujit
|
||||
//! \ingroup asmjit_ujit
|
||||
//!
|
||||
//! Namespace that provides all UJIT (Universal JIT) functionality.
|
||||
|
||||
ASMJIT_BEGIN_SUB_NAMESPACE(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;
|
||||
//! Condition code is simply an alias to a `host::CondCode`.
|
||||
using CondCode = host::CondCode;
|
||||
//! Target memory operand.
|
||||
using Mem = host::Mem;
|
||||
//! Target general-purpose register.
|
||||
using Gp = host::Gp;
|
||||
//! Target vector register.
|
||||
using Vec = host::Vec;
|
||||
|
||||
#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, const Gp& index, uint32_t shift = 0, int32_t disp = 0) noexcept { return x86::ptr(base, index, shift, disp); }
|
||||
#endif
|
||||
|
||||
#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, const Gp& index, uint32_t shift = 0) noexcept { return a64::ptr(base, index, a64::lsl(shift)); }
|
||||
#endif
|
||||
@@ -38,6 +50,7 @@ static ASMJIT_INLINE_NODEBUG Mem mem_ptr(const Gp& base, const Gp& index, uint32
|
||||
// Types & Enums
|
||||
// -------------
|
||||
|
||||
//! Data alignment.
|
||||
enum class Alignment : uint32_t {};
|
||||
|
||||
//! The behavior of a floating point scalar operation.
|
||||
@@ -48,6 +61,16 @@ enum class ScalarOpBehavior : uint8_t {
|
||||
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.
|
||||
enum class FMinFMaxOpBehavior : uint8_t {
|
||||
//! 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.
|
||||
enum class DataWidth : uint8_t {
|
||||
//! 8-bit elements.
|
||||
k8 = 0,
|
||||
//! 16-bit elements.
|
||||
k16 = 1,
|
||||
//! 32-bit elements.
|
||||
k32 = 2,
|
||||
//! 64-bit elements or 64-bit wide data is used.
|
||||
k64 = 3,
|
||||
//! 128-bit elements or 128-bit wide data is used.
|
||||
k128 = 4
|
||||
};
|
||||
|
||||
//! Vector register width.
|
||||
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,
|
||||
//! 256-bit vector register (AVX2+).
|
||||
k256 = 1,
|
||||
@@ -89,9 +117,13 @@ enum class VecWidth : uint8_t {
|
||||
|
||||
//! Broadcast width.
|
||||
enum class Bcst : uint8_t {
|
||||
//! Broadcast 8-bit elements.
|
||||
k8 = 0,
|
||||
//! Broadcast 16-bit elements.
|
||||
k16 = 1,
|
||||
//! Broadcast 32-bit elements.
|
||||
k32 = 2,
|
||||
//! Broadcast 64-bit elements.
|
||||
k64 = 3,
|
||||
|
||||
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));
|
||||
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 {
|
||||
@@ -143,7 +175,7 @@ static ASMJIT_INLINE Vec clone_vec_as(const Vec& src, VecWidth vw) noexcept {
|
||||
// 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
|
||||
//! on initialization.
|
||||
@@ -151,12 +183,15 @@ class OpArray {
|
||||
public:
|
||||
using Op = Operand_;
|
||||
|
||||
//! Maximum number of active operands `OpArray` can hold.
|
||||
static inline constexpr size_t kMaxSize = 8;
|
||||
|
||||
//! \name Members
|
||||
//! \{
|
||||
|
||||
//! Number of operands in OpArray
|
||||
size_t _size;
|
||||
//! Underlying operand array.
|
||||
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); }
|
||||
};
|
||||
|
||||
//! 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 {
|
||||
public:
|
||||
//! \name Construction & Destruction
|
||||
@@ -587,7 +632,7 @@ static ASMJIT_INLINE void reset_var_array(T* array, size_t size) noexcept {
|
||||
|
||||
template<typename T>
|
||||
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; }
|
||||
@@ -615,10 +660,12 @@ struct Swizzle4 {
|
||||
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 {
|
||||
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 {
|
||||
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
|
||||
};
|
||||
|
||||
//! 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 {
|
||||
return uint8_t((uint32_t(hi) << 4) | (uint32_t(lo)));
|
||||
}
|
||||
|
||||
@@ -17,159 +17,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
|
||||
//! \addtogroup asmjit_ujit
|
||||
//! \{
|
||||
|
||||
//! Condition represents either a condition or an assignment operation that can be checked.
|
||||
class Condition {
|
||||
public:
|
||||
//! \name Members
|
||||
//! \{
|
||||
class UniCondition;
|
||||
|
||||
UniOpCond op;
|
||||
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.
|
||||
//! Universal compiler.
|
||||
class UniCompiler {
|
||||
public:
|
||||
ASMJIT_NONCOPYABLE(UniCompiler)
|
||||
@@ -285,7 +135,10 @@ public:
|
||||
//! AsmJit compiler.
|
||||
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)
|
||||
//! General purpose extension mask (X86 and X86_64 only).
|
||||
@@ -306,14 +159,16 @@ public:
|
||||
//! The behavior of scalar operations (mostly floating point).
|
||||
ScalarOpBehavior _scalar_op_behavior {};
|
||||
//! 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.
|
||||
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.
|
||||
CpuFeatures _features {};
|
||||
//! Optimization flags.
|
||||
UniOptFlags _opt_flags = UniOptFlags::kNone;
|
||||
CpuHints _cpu_hints {};
|
||||
|
||||
//! Number of available vector registers.
|
||||
uint32_t _vec_reg_count = 0;
|
||||
@@ -323,20 +178,20 @@ public:
|
||||
//! SIMD multiplier, derived from `_vec_width` (1, 2, 4).
|
||||
uint8_t _vec_multiplier = 0;
|
||||
//! SIMD register type (AsmJit).
|
||||
asmjit::RegType _vec_reg_type = asmjit::RegType::kNone;
|
||||
RegType _vec_reg_type = RegType::kNone;
|
||||
//! SIMD type id (AsmJit).
|
||||
asmjit::TypeId _vec_type_id = asmjit::TypeId::kVoid;
|
||||
TypeId _vec_type_id = TypeId::kVoid;
|
||||
|
||||
//! Function node.
|
||||
asmjit::FuncNode* _func_node = nullptr;
|
||||
FuncNode* _func_node = nullptr;
|
||||
//! Function initialization hook.
|
||||
asmjit::BaseNode* _func_init = nullptr;
|
||||
BaseNode* _func_init = nullptr;
|
||||
//! Function end hook (to add 'unlikely' branches).
|
||||
asmjit::BaseNode* _func_end = nullptr;
|
||||
BaseNode* _func_end = nullptr;
|
||||
|
||||
//! Invalid GP register.
|
||||
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];
|
||||
|
||||
//! Offset to the first constant to the `commonTable` global.
|
||||
@@ -359,15 +214,22 @@ public:
|
||||
uint32_t virt_reg_id;
|
||||
};
|
||||
|
||||
asmjit::ArenaVector<VecConstData> _vec_consts;
|
||||
asmjit::ArenaVector<VecConstDataEx> _vec_consts_ex;
|
||||
ArenaVector<VecConstData> _vec_consts;
|
||||
ArenaVector<VecConstDataEx> _vec_consts_ex;
|
||||
|
||||
//! \}
|
||||
|
||||
//! \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;
|
||||
|
||||
//! \}
|
||||
@@ -375,22 +237,39 @@ public:
|
||||
//! \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
|
||||
//! \{
|
||||
|
||||
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_64bit() const noexcept { return cc->is_64bit(); }
|
||||
ASMJIT_INLINE_NODEBUG uint32_t register_size() const noexcept { return cc->register_size(); }
|
||||
|
||||
#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; }
|
||||
//! 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; }
|
||||
//! 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; }
|
||||
|
||||
//! Tests whether ADX extension is available.
|
||||
@@ -468,7 +347,9 @@ public:
|
||||
#endif // ASMJIT_UJIT_X86
|
||||
|
||||
#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; }
|
||||
//! 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; }
|
||||
|
||||
//! Tests whether CSSC extension is available.
|
||||
@@ -535,9 +416,12 @@ public:
|
||||
//! Returns the behavior of scalar operations (mostly floating point).
|
||||
ASMJIT_INLINE_NODEBUG ScalarOpBehavior scalar_op_behavior() const noexcept { return _scalar_op_behavior; }
|
||||
//! 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.
|
||||
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).
|
||||
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; }
|
||||
|
||||
//! 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).
|
||||
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).
|
||||
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.
|
||||
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; }
|
||||
ASMJIT_INLINE_NODEBUG bool has_opt_flag(UniOptFlags flag) const noexcept { return Support::test(_opt_flags, flag); }
|
||||
//! Returns CPU hints.
|
||||
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).
|
||||
ASMJIT_INLINE_NODEBUG OperandSignature gp_signature() const noexcept { return cc->gp_signature(); }
|
||||
@@ -599,7 +485,7 @@ public:
|
||||
//! \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 {
|
||||
for (uint32_t i = 0; i < op_array.size(); i++)
|
||||
cc->rename(op_array[i].as<asmjit::Reg>(), "%s%u", name, unsigned(i));
|
||||
for (uint32_t i = 0; i < op_array.size(); 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 {
|
||||
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));
|
||||
for (uint32_t i = 0; i < op_array.size(); 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)
|
||||
//! \{
|
||||
|
||||
ASMJIT_INLINE Gp new_gp32() noexcept { return cc->new_gp32(); }
|
||||
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); }
|
||||
//! Wraps `BackendCompiler::new_reg(type_id, 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>
|
||||
ASMJIT_INLINE Vec new_vec(const char* name, Args&&... args) noexcept {
|
||||
Vec reg;
|
||||
cc->_new_reg_fmt(Out<Reg>(reg), _vec_type_id, name, std::forward<Args>(args)...);
|
||||
return reg;
|
||||
ASMJIT_INLINE Gp new_gp32(Args&&... args) noexcept {
|
||||
return cc->new_gp32(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
//! 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>
|
||||
ASMJIT_INLINE Vec new_vec(VecWidth vw, const char* name, Args&&... args) noexcept {
|
||||
Vec reg;
|
||||
cc->_new_reg_fmt(Out<Reg>(reg), VecWidthUtils::type_id_of(vw), name, std::forward<Args>(args)...);
|
||||
return reg;
|
||||
ASMJIT_INLINE Vec new_vec(Args&&... args) noexcept {
|
||||
return cc->new_vec(_vec_type_id, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
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);
|
||||
dst._size = n;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), type_id, "%s%u", name, i);
|
||||
for (size_t i = 0; i < n; 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);
|
||||
dst._size = n;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), type_id, "%s%s%u", prefix, name, i);
|
||||
for (size_t i = 0; i < n; 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);
|
||||
dst._size = n;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), ref, "%s%u", name, i);
|
||||
for (size_t i = 0; i < n; 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);
|
||||
dst._size = n;
|
||||
for (uint32_t i = 0; i < n; i++) {
|
||||
cc->_new_reg_fmt(Out(dst[i].as<asmjit::Reg>()), ref, "%s%s%u", prefix, name, i);
|
||||
for (size_t i = 0; i < n; 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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
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;
|
||||
|
||||
//! \}
|
||||
@@ -722,165 +689,6 @@ public:
|
||||
|
||||
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)
|
||||
//! \{
|
||||
|
||||
@@ -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 _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)
|
||||
ASMJIT_API Vec simd_const_16b(const void* data16) noexcept;
|
||||
#endif // 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
|
||||
|
||||
//! \}
|
||||
@@ -920,12 +728,12 @@ public:
|
||||
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_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_select(const Gp& dst, const Operand_& sel1_, const Operand_& sel2_, 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 UniCondition& condition) 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_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 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_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 Mem& 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 UniCondition& condition) noexcept { emit_cmov(dst, sel, condition); }
|
||||
|
||||
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 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 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;
|
||||
|
||||
@@ -1283,8 +1091,12 @@ public:
|
||||
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_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_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_f64, UniOpVV::kNegF64)
|
||||
DEFINE_OP_2V(v_not_f32, UniOpVV::kNotF32)
|
||||
@@ -1301,10 +1113,18 @@ public:
|
||||
DEFINE_OP_2V(s_ceil_f64, UniOpVV::kCeilF64S)
|
||||
DEFINE_OP_2V(v_ceil_f32, UniOpVV::kCeilF32)
|
||||
DEFINE_OP_2V(v_ceil_f64, UniOpVV::kCeilF64)
|
||||
DEFINE_OP_2V(s_round_f32, UniOpVV::kRoundF32S)
|
||||
DEFINE_OP_2V(s_round_f64, UniOpVV::kRoundF64S)
|
||||
DEFINE_OP_2V(v_round_f32, UniOpVV::kRoundF32)
|
||||
DEFINE_OP_2V(v_round_f64, UniOpVV::kRoundF64)
|
||||
DEFINE_OP_2V(s_round_even_f32, UniOpVV::kRoundEvenF32S)
|
||||
DEFINE_OP_2V(s_round_even_f64, UniOpVV::kRoundEvenF64S)
|
||||
DEFINE_OP_2V(v_round_even_f32, UniOpVV::kRoundEvenF32)
|
||||
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_f64, UniOpVV::kRcpF64)
|
||||
DEFINE_OP_2V(s_sqrt_f32, UniOpVV::kSqrtF32S)
|
||||
@@ -1743,6 +1563,10 @@ public:
|
||||
DEFINE_OP_3V(s_div_f64, UniOpVVV::kDivF64S)
|
||||
DEFINE_OP_3V(v_div_f32, UniOpVVV::kDivF32)
|
||||
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_f64, UniOpVVV::kMinF64S)
|
||||
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_f64, UniOpVVVI::kInsertV256_F64)
|
||||
|
||||
|
||||
DEFINE_OP_4V(v_blendv_u8, UniOpVVVV::kBlendV_U8)
|
||||
DEFINE_OP_4V(v_madd_i16, UniOpVVVV::kMAddU16)
|
||||
DEFINE_OP_4V(v_madd_u16, UniOpVVVV::kMAddU16)
|
||||
@@ -1944,7 +1767,7 @@ public:
|
||||
//! \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) {
|
||||
case 1: v_load8(dst, src); 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) {
|
||||
case 1: v_store8(dst, src); break;
|
||||
case 2: v_storea16(dst, src, alignment); break;
|
||||
@@ -2005,27 +1828,6 @@ public:
|
||||
#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
32
src/asmjit/ujit/unicompiler_utils_p.h
Normal file
32
src/asmjit/ujit/unicompiler_utils_p.h
Normal 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
293
src/asmjit/ujit/unicondition.h
Normal file
293
src/asmjit/ujit/unicondition.h
Normal 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
@@ -6,7 +6,7 @@
|
||||
#ifndef ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED
|
||||
#define ASMJIT_UJIT_VECCONSTTABLE_H_INCLUDED
|
||||
|
||||
#include "ujitbase.h"
|
||||
#include "../core/globals.h"
|
||||
|
||||
#if !defined(ASMJIT_NO_UJIT)
|
||||
|
||||
@@ -18,6 +18,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(ujit)
|
||||
template<typename T, size_t W>
|
||||
struct VecConst;
|
||||
|
||||
//! \cond
|
||||
|
||||
//! A 64-bit vector constant of type `T` aligned to 64 bits.
|
||||
template<typename T>
|
||||
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");
|
||||
|
||||
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.
|
||||
@@ -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");
|
||||
|
||||
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.
|
||||
@@ -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");
|
||||
|
||||
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.
|
||||
@@ -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");
|
||||
|
||||
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 VecConst128 = VecConst<T, 16>;
|
||||
template<typename T> using VecConst256 = VecConst<T, 32>;
|
||||
@@ -400,15 +428,24 @@ struct VecConstTable {
|
||||
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));
|
||||
|
||||
VecConstNative<uint64_t> f32_0_5_minus_1ulp = make_const<VecConstNative<uint64_t>>(0x3EFFFFFF3EFFFFFFu); // 0.49999997 (0.5f - 1ulp)
|
||||
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_max = make_const<VecConstNative<float>>(8388608.0f);
|
||||
VecConstNative<float> f32_round_magic = make_const<VecConstNative<float>>(8388608.0f);
|
||||
|
||||
VecConstNative<uint64_t> f64_0_5_minus_1ulp = make_const<VecConstNative<uint64_t>>(0x3FDFFFFFFFFFFFFFu); // 0.49999999999999994 (0.5 - 1ulp).
|
||||
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_max = make_const<VecConstNative<double>>(4503599627370496.0);
|
||||
VecConstNative<double> f64_round_magic = make_const<VecConstNative<double>>(4503599627370496.0);
|
||||
};
|
||||
|
||||
ASMJIT_VARAPI const VecConstTable vec_const_table;
|
||||
|
||||
struct VecConstTableRef {
|
||||
const VecConstTable& table;
|
||||
size_t size;
|
||||
};
|
||||
|
||||
//! \}
|
||||
|
||||
ASMJIT_END_SUB_NAMESPACE
|
||||
|
||||
@@ -511,99 +511,182 @@ public:
|
||||
//! \name Virtual Registers
|
||||
//! \{
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
|
||||
_new_reg_fmt(Out<Reg>{OUT}, PARAM, FORMAT, ARGS)
|
||||
#else
|
||||
# define ASMJIT_NEW_REG_FMT(OUT, PARAM, FORMAT, ARGS) \
|
||||
Support::maybe_unused(FORMAT); \
|
||||
Support::maybe_unused(std::forward<Args>(args)...); \
|
||||
_new_reg(Out<Reg>{OUT}, PARAM)
|
||||
#endif
|
||||
//! Creates a new general-purpose register with `type_id` type and optional name passed via `args`.
|
||||
//!
|
||||
//! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_gp8(),
|
||||
//! \ref new_gp16(), \ref new_gp32(), \ref new_gp64(), and \ref new_gpz() or \ref new_gp_ptr().
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp(TypeId type_id, Args&&... args) { return new_reg<Gp>(type_id, std::forward<Args>(args)...); }
|
||||
|
||||
#define ASMJIT_NEW_REG_CUSTOM(FUNC, REG) \
|
||||
ASMJIT_INLINE_NODEBUG REG FUNC(TypeId type_id) { \
|
||||
REG reg(Globals::NoInit); \
|
||||
_new_reg(Out<Reg>{reg}, type_id); \
|
||||
return reg; \
|
||||
} \
|
||||
\
|
||||
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; \
|
||||
}
|
||||
//! Creates a new vector register with `type_id` type and optional name passed via `args`.
|
||||
//!
|
||||
//! \note Using \ref TypeId is too generic. In general it's recommended to use \ref new_vec128(),
|
||||
//! \ref new_vec256(), \ref new_vec512(), or alternatively \ref new_xmm(), \ref new_ymm(), and \ref new_zmm().
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Vec new_vec(TypeId type_id, Args&&... args) { return new_reg<Vec>(type_id, std::forward<Args>(args)...); }
|
||||
|
||||
#define ASMJIT_NEW_REG_TYPED(FUNC, REG, TYPE_ID) \
|
||||
ASMJIT_INLINE_NODEBUG REG FUNC() { \
|
||||
REG reg(Globals::NoInit); \
|
||||
_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; \
|
||||
}
|
||||
//! Creates a new mask register with `type_id` type and optional name passed via `args`.
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG KReg new_k(TypeId type_id, Args&&... args) { return new_reg<KReg>(type_id, std::forward<Args>(args)...); }
|
||||
|
||||
template<typename RegT>
|
||||
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref) {
|
||||
RegT reg(Globals::NoInit);
|
||||
_new_reg(Out<Reg>(reg), ref);
|
||||
return reg;
|
||||
}
|
||||
//! Creates a new 8-bit general purpose register mapped to low 8 bits of a full register.
|
||||
//!
|
||||
//! \note Using 8-bit registers is not recommended, use at least 32-bit registers in portable code.
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp8(Args&&... args) { return new_reg<Gp>(TypeId::kUInt8, std::forward<Args>(args)...); }
|
||||
|
||||
template<typename RegT, typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG RegT new_similar_reg(const RegT& ref, const char* fmt, Args&&... args) {
|
||||
RegT reg(Globals::NoInit);
|
||||
ASMJIT_NEW_REG_FMT(reg, ref, fmt, std::forward<Args>(args)...);
|
||||
return reg;
|
||||
}
|
||||
//! Creates a new 16-bit general purpose register mapped to low 16 bits of a full register.
|
||||
//!
|
||||
//! \note Using 16-bit registers is not recommended, use at least 32-bit registers in portable code.
|
||||
template<typename... Args>
|
||||
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 )
|
||||
ASMJIT_NEW_REG_CUSTOM(new_gp , Gp )
|
||||
ASMJIT_NEW_REG_CUSTOM(new_vec , Vec )
|
||||
ASMJIT_NEW_REG_CUSTOM(new_kreg , KReg)
|
||||
//! Creates a new 32-bit general purpose register mapped to low 32 bits of a full register (on 64-bit targets).
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gp32(Args&&... args) { return new_reg<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
|
||||
|
||||
ASMJIT_NEW_REG_TYPED(new_gp8 , Gp , TypeId::kUInt8)
|
||||
ASMJIT_NEW_REG_TYPED(new_gp16 , Gp , TypeId::kUInt16)
|
||||
ASMJIT_NEW_REG_TYPED(new_gp32 , Gp , TypeId::kUInt32)
|
||||
ASMJIT_NEW_REG_TYPED(new_gp64 , Gp , TypeId::kUInt64)
|
||||
//! Creates a new 64-bit general purpose register.
|
||||
//!
|
||||
//! \warning The target must be 64-bit in order to create 64-bit registers.
|
||||
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)
|
||||
ASMJIT_NEW_REG_TYPED(new_gpw , Gp , TypeId::kUInt16)
|
||||
ASMJIT_NEW_REG_TYPED(new_gpd , Gp , TypeId::kUInt32)
|
||||
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)
|
||||
//! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Gp new_gpz(Args&&... args) { return new_reg<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
|
||||
|
||||
ASMJIT_NEW_REG_TYPED(new_xmm , Vec , TypeId::kInt32x4)
|
||||
ASMJIT_NEW_REG_TYPED(new_xmm_ss, Vec , TypeId::kFloat32x1)
|
||||
ASMJIT_NEW_REG_TYPED(new_xmm_sd, Vec , TypeId::kFloat64x1)
|
||||
ASMJIT_NEW_REG_TYPED(new_xmm_ps, Vec , TypeId::kFloat32x4)
|
||||
ASMJIT_NEW_REG_TYPED(new_xmm_pd, Vec , TypeId::kFloat64x2)
|
||||
//! Creates a new 32-bit or 64-bit general purpose register depending on the target register width.
|
||||
//!
|
||||
//! \note This is just an alternative name that maps more closely to C's `uintptr_t`, it's the same function as
|
||||
//! \ref new_gpz().
|
||||
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)
|
||||
ASMJIT_NEW_REG_TYPED(new_ymm_ps, Vec , TypeId::kFloat32x8)
|
||||
ASMJIT_NEW_REG_TYPED(new_ymm_pd, Vec , TypeId::kFloat64x4)
|
||||
//! Creates a new 128-bit vector register (XMM).
|
||||
template<typename... Args>
|
||||
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)
|
||||
ASMJIT_NEW_REG_TYPED(new_zmm_ps, Vec , TypeId::kFloat32x16)
|
||||
ASMJIT_NEW_REG_TYPED(new_zmm_pd, Vec , TypeId::kFloat64x8)
|
||||
//! Creates a new 128-bit vector register (XMM) that will be used for scalar 32-bit floating point operation.
|
||||
template<typename... Args>
|
||||
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)
|
||||
ASMJIT_NEW_REG_TYPED(new_kw , KReg, TypeId::kMask16)
|
||||
ASMJIT_NEW_REG_TYPED(new_kd , KReg, TypeId::kMask32)
|
||||
ASMJIT_NEW_REG_TYPED(new_kq , KReg, TypeId::kMask64)
|
||||
//! Creates a new 128-bit vector register (XMM) that will be used for packed 32-bit floating point operation.
|
||||
template<typename... Args>
|
||||
ASMJIT_INLINE_NODEBUG Vec new_vec128_f32x4(Args&&... args) { return new_reg<Vec>(TypeId::kFloat32x4, std::forward<Args>(args)...); }
|
||||
|
||||
#undef ASMJIT_NEW_REG_TYPED
|
||||
#undef ASMJIT_NEW_REG_CUSTOM
|
||||
#undef ASMJIT_NEW_REG_FMT
|
||||
//! Creates a new 128-bit vector register (XMM) 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 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)...); }
|
||||
|
||||
//! \}
|
||||
|
||||
|
||||
@@ -561,7 +561,7 @@ struct ImmBits {
|
||||
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 last_predicate_shift = bits * (count - 1u);
|
||||
|
||||
@@ -576,7 +576,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint3
|
||||
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;
|
||||
char buf[64];
|
||||
|
||||
@@ -615,7 +615,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint3
|
||||
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 pos = 0;
|
||||
|
||||
@@ -628,7 +628,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint3
|
||||
return sb.append(kImmCharEnd);
|
||||
}
|
||||
|
||||
ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
ASMJIT_FAVOR_SIZE static Error FormatterInternal_explain_const(
|
||||
String& sb,
|
||||
FormatFlags format_flags,
|
||||
InstId inst_id,
|
||||
@@ -700,55 +700,55 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
};
|
||||
|
||||
static const ImmBits vroundxx[] = {
|
||||
{ 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "\0" "\0" "\0" "\0" },
|
||||
{ 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" }
|
||||
{ 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "CURRENT\0" "\0" "\0" "\0" },
|
||||
{ 0x08u, 3, ImmBits::kModeLookup, "\0" "SUPPRESS\0" }
|
||||
};
|
||||
|
||||
uint32_t u8 = imm.value_as<uint8_t>();
|
||||
switch (inst_id) {
|
||||
case Inst::kIdVblendpd:
|
||||
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::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::kIdVcmpps:
|
||||
case Inst::kIdVcmpsd:
|
||||
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::kIdCmpps:
|
||||
case Inst::kIdCmpsd:
|
||||
case Inst::kIdCmpss:
|
||||
return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx);
|
||||
return FormatterInternal_format_imm_text(sb, u8, 3, 0, vcmpx);
|
||||
|
||||
case Inst::kIdVdbpsadbw:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
|
||||
|
||||
case Inst::kIdVdppd:
|
||||
case Inst::kIdVdpps:
|
||||
case Inst::kIdDppd:
|
||||
case Inst::kIdDpps:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
|
||||
|
||||
case Inst::kIdVmpsadbw:
|
||||
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::kIdPblendw:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
|
||||
|
||||
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::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::kIdVroundps:
|
||||
@@ -758,57 +758,57 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
case Inst::kIdRoundps:
|
||||
case Inst::kIdRoundsd:
|
||||
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::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::kIdShufps:
|
||||
return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4);
|
||||
return FormatterInternal_format_imm_text(sb, u8, 2, 4, vshufps, 4);
|
||||
|
||||
case Inst::kIdVcvtps2ph:
|
||||
return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1);
|
||||
return FormatterInternal_format_imm_bits(sb, u8, vroundxx, 1);
|
||||
|
||||
case Inst::kIdVperm2f128:
|
||||
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:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 1, vec_size / 8);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 1, vec_size / 8);
|
||||
|
||||
case Inst::kIdVpermilps:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
|
||||
|
||||
case Inst::kIdVpshufd:
|
||||
case Inst::kIdPshufd:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
|
||||
|
||||
case Inst::kIdVpshufhw:
|
||||
case Inst::kIdVpshuflw:
|
||||
case Inst::kIdPshufhw:
|
||||
case Inst::kIdPshuflw:
|
||||
case Inst::kIdPshufw:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
|
||||
|
||||
case Inst::kIdVfixupimmpd:
|
||||
case Inst::kIdVfixupimmps:
|
||||
case Inst::kIdVfixupimmsd:
|
||||
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::kIdVfpclassps:
|
||||
case Inst::kIdVfpclasssd:
|
||||
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::kIdVgetmantps:
|
||||
case Inst::kIdVgetmantsd:
|
||||
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::kIdVpcmpd:
|
||||
@@ -818,7 +818,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
case Inst::kIdVpcmpud:
|
||||
case Inst::kIdVpcmpuq:
|
||||
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::kIdVpcomd:
|
||||
@@ -828,21 +828,21 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
case Inst::kIdVpcomud:
|
||||
case Inst::kIdVpcomuq:
|
||||
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::kIdVpermpd:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 2, 4);
|
||||
|
||||
case Inst::kIdVpternlogd:
|
||||
case Inst::kIdVpternlogq:
|
||||
return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
|
||||
return FormatterInternal_format_imm_shuf(sb, u8, 1, 8);
|
||||
|
||||
case Inst::kIdVrangepd:
|
||||
case Inst::kIdVrangeps:
|
||||
case Inst::kIdVrangesd:
|
||||
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::kIdVreduceps:
|
||||
@@ -852,7 +852,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
case Inst::kIdVrndscaleps:
|
||||
case Inst::kIdVrndscalesd:
|
||||
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::kIdVshuff64x2:
|
||||
@@ -860,7 +860,7 @@ ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
|
||||
case Inst::kIdVshufi64x2: {
|
||||
uint32_t count = Support::max<uint32_t>(vec_size / 16, 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:
|
||||
@@ -969,7 +969,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::format_instruction(
|
||||
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}.
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "cmdline.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
#include "../commons/cmdline.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -7,8 +7,9 @@
|
||||
#define ASMJIT_TEST_PERF_H_INCLUDED
|
||||
|
||||
#include <asmjit/core.h>
|
||||
#include "asmjitutils.h"
|
||||
#include "performancetimer.h"
|
||||
|
||||
#include "../commons/asmjitutils.h"
|
||||
#include "../commons/performancetimer.h"
|
||||
|
||||
namespace asmjit_perf_utils {
|
||||
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjit_bench_codegen.h"
|
||||
#include "asmjit_test_misc.h"
|
||||
#include "../tests/asmjit_test_misc.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
#include <stdint.h>
|
||||
#include <asmjit/host.h>
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "cmdline.h"
|
||||
#include "performancetimer.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
#include "../commons/cmdline.h"
|
||||
#include "../commons/performancetimer.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -20,13 +20,12 @@
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
|
||||
#if !defined(ASMJIT_NO_COMPILER)
|
||||
#include "cmdline.h"
|
||||
#include "performancetimer.h"
|
||||
#include "asmjit_test_compiler.h"
|
||||
#include "asmjit_test_random.h"
|
||||
#include "../commons/cmdline.h"
|
||||
#include "../commons/performancetimer.h"
|
||||
#include "../commons/random.h"
|
||||
#endif
|
||||
|
||||
using namespace asmjit;
|
||||
@@ -88,6 +88,8 @@ static void print_cpu_info() noexcept {
|
||||
// CPU Features
|
||||
// ------------
|
||||
|
||||
using asmjit::CpuHints;
|
||||
|
||||
#ifndef ASMJIT_NO_LOGGING
|
||||
printf("CPU Features:\n");
|
||||
asmjit::CpuFeatures::Iterator it(cpu.features().iterator());
|
||||
@@ -99,6 +101,27 @@ static void print_cpu_info() noexcept {
|
||||
};
|
||||
printf("\n");
|
||||
#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]]
|
||||
@@ -3,8 +3,8 @@
|
||||
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||
// SPDX-License-Identifier: Zlib
|
||||
|
||||
#ifndef ASMJIT_TEST_RANDOM_H_INCLUDED
|
||||
#define ASMJIT_TEST_RANDOM_H_INCLUDED
|
||||
#ifndef TESTING_COMMONS_RANDOM_H_INCLUDED
|
||||
#define TESTING_COMMONS_RANDOM_H_INCLUDED
|
||||
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
@@ -74,4 +74,4 @@ public:
|
||||
} // {anonymous}
|
||||
} // {TestUtils}
|
||||
|
||||
#endif // ASMJIT_TEST_RANDOM_H_INCLUDED
|
||||
#endif // TESTING_COMMONS_RANDOM_H_INCLUDED
|
||||
@@ -8,11 +8,11 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
#include "asmjit_test_assembler.h"
|
||||
|
||||
#include "../commons/asmjitutils.h"
|
||||
#include "../commons/cmdline.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjit_test_assembler.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjit_test_assembler.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
#include <string.h>
|
||||
|
||||
#include "asmjit_test_assembler.h"
|
||||
#include "cmdline.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -15,10 +15,10 @@
|
||||
|
||||
#if !defined(ASMJIT_NO_COMPILER)
|
||||
|
||||
#include "cmdline.h"
|
||||
#include "performancetimer.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
#include "../commons/cmdline.h"
|
||||
#include "../commons/performancetimer.h"
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "asmjit_test_compiler.h"
|
||||
|
||||
#if !defined(ASMJIT_NO_X86)
|
||||
@@ -11,7 +11,7 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "./asmjit_test_compiler.h"
|
||||
#include "asmjit_test_compiler.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <asmjit/core.h>
|
||||
#include "asmjitutils.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
|
||||
#if ASMJIT_ARCH_X86 != 0
|
||||
#include <asmjit/x86.h>
|
||||
@@ -13,7 +13,7 @@
|
||||
#include <asmjit/a64.h>
|
||||
#endif
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include "asmjitutils.h"
|
||||
|
||||
#include "../commons/asmjitutils.h"
|
||||
|
||||
using namespace asmjit;
|
||||
|
||||
@@ -13,8 +13,8 @@
|
||||
#include <asmjit/a64.h>
|
||||
#endif
|
||||
|
||||
#include "asmjitutils.h"
|
||||
#include "broken.h"
|
||||
#include "../commons/asmjitutils.h"
|
||||
|
||||
#if !defined(ASMJIT_NO_COMPILER)
|
||||
#include <asmjit/core/racfgblock_p.h>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -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)));
|
||||
}
|
||||
|
||||
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 {
|
||||
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)));
|
||||
}
|
||||
|
||||
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 {
|
||||
return _mm_cvtsd_f64(_mm_add_sd(_mm_mul_sd(_mm_set1_pd(a), _mm_set1_pd(b)), _mm_set1_pd(c)));
|
||||
}
|
||||
@@ -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 ""
|
||||
@@ -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 ""
|
||||
@@ -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 ""
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
cmake .. -B "..\build_vs2019_x64" -G"Visual Studio 16" -A x64 -DASMJIT_TEST=1
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
cmake .. -B "..\build_vs2019_x86" -G"Visual Studio 16" -A Win32 -DASMJIT_TEST=1
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
cmake .. -B "..\build_vs2022_x64" -G"Visual Studio 17" -A x64 -DASMJIT_TEST=1
|
||||
@@ -1,2 +0,0 @@
|
||||
@echo off
|
||||
cmake .. -B "..\build_vs2022_x86" -G"Visual Studio 17" -A Win32 -DASMJIT_TEST=1
|
||||
@@ -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}
|
||||
Reference in New Issue
Block a user