mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 12:34:35 +03:00
[abi] AsmJit v1.17 - cumulative & breaking changes
* Reworked register operands - all vector registers are now
platform::Vec deriving from UniVec (universal vector operand),
additionally, there is no platform::Reg, instead asmjit::Reg
provides all necessary features to make it a base register for
each target architecture
* Reworked casting between registers - now architecture agnostic
names are preferred - use Gp32 instead of Gpd or GpW, Gp64
instead of Gpq and GpX, etc...
* Reworked vector registers and their names - architecture
agnostic naming is now preferred Vec32, Vec64, Vec128, etc...
* Reworked naming conventions used across AsmJit - for clarity
Identifiers are now prefixed with the type, like sectionId(),
labelId(), etc...
* Reworked how Zone and ZoneAllocator are used across AsmJit,
prefering Zone in most cases and ZoneAllocator only for
containers - this change alone achieves around 5% better
performance of Builder and Compiler
* Reworked LabelEntry - decreased the size of the base entry
to 16 bytes for anonymous and unnamed labels. Avoided an
indirection when using labelEntries() - LabelEntry is now
a value and not a pointer
* Renamed LabelLink to Fixup
* Added a new header <asmjit/host.h> which would include
<asmjit/core.h> + target tools for the host architecture,
if enabled and supported
* Added new AArch64 instructions (BTI, CSSC, CHKFEAT)
* Added a mvn_ alternative of mvn instruction (fix for Windows
ARM64 SDK)
* Added more AArch64 CPU features to CpuInfo
* Added better support for Apple CPU detection (Apple M3, M4)
* Added a new benchmarking tool asmjit_bench_overhead, which
benchmarks the overhead of CodeHolder::init()/reset() and
creating/attaching emitters to it. Thanks to the benchmark the
most common code-paths were optimized
* Added a new benchmarking tool asmjit_bench_regalloc, which
aims to benchmark the cost and complexity of register allocation.
* Renamed asmjit_test_perf to asmjit_bench_codegen to make it
clear what is a test and what is a benchmark
This commit is contained in:
3
.github/workflows/build-config.json
vendored
3
.github/workflows/build-config.json
vendored
@@ -17,10 +17,9 @@
|
|||||||
{ "optional": true, "cmd": ["asmjit_test_assembler"] },
|
{ "optional": true, "cmd": ["asmjit_test_assembler"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] },
|
{ "optional": true, "cmd": ["asmjit_test_assembler", "--validate"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_emitters"] },
|
{ "optional": true, "cmd": ["asmjit_test_emitters"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_execute"] },
|
|
||||||
{ "optional": true, "cmd": ["asmjit_test_compiler"] },
|
{ "optional": true, "cmd": ["asmjit_test_compiler"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_instinfo"] },
|
{ "optional": true, "cmd": ["asmjit_test_instinfo"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_x86_sections"] },
|
{ "optional": true, "cmd": ["asmjit_test_x86_sections"] },
|
||||||
{ "optional": true, "cmd": ["asmjit_test_perf", "--quick"] }
|
{ "optional": true, "cmd": ["asmjit_bench_codegen", "--quick"] }
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
32
.github/workflows/build.yml
vendored
32
.github/workflows/build.yml
vendored
@@ -35,13 +35,12 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { title: "diag-analyze" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , diagnostics: "analyze-build" }
|
- { title: "diag-analyze" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=0", diagnostics: "analyze-build"}
|
||||||
- { title: "diag-asan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", diagnostics: "asan", defs: "ASMJIT_TEST=1" }
|
- { title: "diag-asan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1", diagnostics: "asan", }
|
||||||
- { title: "diag-msan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", diagnostics: "msan", defs: "ASMJIT_TEST=1" }
|
- { title: "diag-msan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1", diagnostics: "msan", }
|
||||||
- { title: "diag-ubsan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", diagnostics: "ubsan", defs: "ASMJIT_TEST=1" }
|
- { title: "diag-ubsan" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1", diagnostics: "ubsan", }
|
||||||
- { title: "diag-hardened" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", diagnostics: "hardened", defs: "ASMJIT_TEST=1" }
|
- { title: "diag-hardened" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1", diagnostics: "hardened", }
|
||||||
- { title: "diag-valgrind" , host: "ubuntu-24.04" , arch: "x64" , cc: "clang-19", conf: "Release", diagnostics: "valgrind", defs: "ASMJIT_TEST=1" }
|
- { title: "diag-valgrind" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1", diagnostics: "valgrind", }
|
||||||
|
|
||||||
- { title: "no-deprecated" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_DEPRECATED=1" }
|
- { title: "no-deprecated" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_DEPRECATED=1" }
|
||||||
- { title: "no-intrinsics" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_INTRINSICS=1" }
|
- { title: "no-intrinsics" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_INTRINSICS=1" }
|
||||||
- { title: "no-logging" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_LOGGING=1" }
|
- { title: "no-logging" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_LOGGING=1" }
|
||||||
@@ -53,10 +52,8 @@ jobs:
|
|||||||
- { title: "no-validation" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_VALIDATION=1" }
|
- { title: "no-validation" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_VALIDATION=1" }
|
||||||
- { title: "no-x86" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_X86=1" }
|
- { title: "no-x86" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_X86=1" }
|
||||||
- { title: "no-aarch64" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_AARCH64=1" }
|
- { title: "no-aarch64" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Release", defs: "ASMJIT_TEST=1,ASMJIT_NO_AARCH64=1" }
|
||||||
|
|
||||||
- { title: "lang-c++20" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1,CMAKE_CXX_FLAGS=-std=c++20" }
|
- { title: "lang-c++20" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1,CMAKE_CXX_FLAGS=-std=c++20" }
|
||||||
- { title: "lang-c++23" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1,CMAKE_CXX_FLAGS=-std=c++23" }
|
- { title: "lang-c++23" , host: "ubuntu-latest" , arch: "x64" , cc: "clang-19", conf: "Debug" , defs: "ASMJIT_TEST=1,CMAKE_CXX_FLAGS=-std=c++23" }
|
||||||
|
|
||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "gcc-9" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "gcc-9" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
@@ -109,6 +106,8 @@ jobs:
|
|||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-18", conf: "Release", defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x86" , cc: "clang-18", conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-18", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-18", conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-18", conf: "Release", defs: "ASMJIT_TEST=1" }
|
- { title: "linux" , host: "ubuntu-22.04" , arch: "x64" , cc: "clang-18", 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: "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: "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: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
@@ -119,23 +118,20 @@ jobs:
|
|||||||
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
- { title: "windows" , host: "windows-2022" , arch: "x86" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
- { title: "windows" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||||
|
- { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=1" }
|
||||||
# Cross compiled, cannot run tests (Windows/ARM64).
|
- { title: "windows" , host: "windows-11-arm" , arch: "arm64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "windows" , host: "windows-2022" , arch: "arm64" , cc: "vs2022" , conf: "Debug" , defs: "ASMJIT_TEST=0" }
|
|
||||||
- { title: "windows" , host: "windows-2022" , arch: "arm64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=0" }
|
|
||||||
|
|
||||||
# Cross compiled, cannot run tests (Windows/UWP).
|
# Cross compiled, cannot run tests (Windows/UWP).
|
||||||
- { title: "windows/uwp" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=0,CMAKE_SYSTEM_NAME=WindowsStore,CMAKE_SYSTEM_VERSION=10.0,CMAKE_CXX_FLAGS=-D_WIN32_WINNT=0x0A00" }
|
- { title: "windows/uwp" , host: "windows-2022" , arch: "x64" , cc: "vs2022" , conf: "Release", defs: "ASMJIT_TEST=0,CMAKE_SYSTEM_NAME=WindowsStore,CMAKE_SYSTEM_VERSION=10.0,CMAKE_CXX_FLAGS=-D_WIN32_WINNT=0x0A00" }
|
||||||
|
|
||||||
- { title: "freebsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.1", defs: "ASMJIT_TEST=1" }
|
- { title: "freebsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.2", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "freebsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "freebsd", vm_ver: "14.1", 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.0", defs: "ASMJIT_TEST=1" }
|
- { title: "netbsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "10.1", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "netbsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "10.0", defs: "ASMJIT_TEST=1" }
|
- { title: "netbsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "netbsd" , vm_ver: "10.1", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "openbsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
- { title: "openbsd" , host: "ubuntu-latest" , arch: "x64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "openbsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
- { title: "openbsd" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "openbsd", vm_ver: "7.4" , defs: "ASMJIT_TEST=1" }
|
||||||
|
|
||||||
- { title: "debian" , host: "ubuntu-latest" , arch: "arm/v7" , cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
- { title: "debian" , host: "ubuntu-latest" , arch: "arm/v7" , cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "debian" , host: "ubuntu-latest" , arch: "arm64" , cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
|
||||||
- { title: "debian" , host: "ubuntu-latest" , arch: "riscv64", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
- { title: "debian" , host: "ubuntu-latest" , arch: "riscv64", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||||
- { title: "debian" , host: "ubuntu-latest" , arch: "ppc64le", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
- { title: "debian" , host: "ubuntu-latest" , arch: "ppc64le", cc: "clang" , conf: "Release", vm: "debian:unstable", defs: "ASMJIT_TEST=1" }
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,14 @@ if (ASMJIT_EMBED AND NOT ASMJIT_STATIC)
|
|||||||
set(ASMJIT_STATIC TRUE)
|
set(ASMJIT_STATIC TRUE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
if (NOT DEFINED ASMJIT_NO_DEPRECATED)
|
||||||
|
set(ASMJIT_NO_DEPRECATED FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
if (NOT DEFINED ASMJIT_NO_ABI_NAMESPACE)
|
||||||
|
set(ASMJIT_NO_ABI_NAMESPACE FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
# AsmJit - Configuration - Backend
|
# AsmJit - Configuration - Backend
|
||||||
# ================================
|
# ================================
|
||||||
|
|
||||||
@@ -61,10 +69,6 @@ endif()
|
|||||||
# AsmJit - Configuration - Features
|
# AsmJit - Configuration - Features
|
||||||
# =================================
|
# =================================
|
||||||
|
|
||||||
if (NOT DEFINED ASMJIT_NO_DEPRECATED)
|
|
||||||
set(ASMJIT_NO_DEPRECATED FALSE)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if (NOT DEFINED ASMJIT_NO_SHM_OPEN)
|
if (NOT DEFINED ASMJIT_NO_SHM_OPEN)
|
||||||
set(ASMJIT_NO_SHM_OPEN FALSE)
|
set(ASMJIT_NO_SHM_OPEN FALSE)
|
||||||
endif()
|
endif()
|
||||||
@@ -117,14 +121,16 @@ set(ASMJIT_NO_AARCH64 "${ASMJIT_NO_AARCH64}" CACHE BOOL "Disable AAr
|
|||||||
set(ASMJIT_NO_FOREIGN "${ASMJIT_NO_FOREIGN}" CACHE BOOL "Disable all foreign architectures (enables only a target architecture)")
|
set(ASMJIT_NO_FOREIGN "${ASMJIT_NO_FOREIGN}" CACHE BOOL "Disable all foreign architectures (enables only a target architecture)")
|
||||||
|
|
||||||
set(ASMJIT_NO_DEPRECATED "${ASMJIT_NO_DEPRECATED}" CACHE BOOL "Disable deprecated API at build time")
|
set(ASMJIT_NO_DEPRECATED "${ASMJIT_NO_DEPRECATED}" CACHE BOOL "Disable deprecated API at build time")
|
||||||
|
set(ASMJIT_NO_ABI_NAMESPACE "${ASMJIT_NO_ABI_NAMESPACE}" CACHE BOOL "Disable the use of ABI namespace (inline namespace in {asmjit} adding ABI version)")
|
||||||
|
|
||||||
set(ASMJIT_NO_SHM_OPEN "${ASMJIT_NO_SHM_OPEN}" CACHE BOOL "Disable the use of shm_open() even on platforms where it's supported")
|
set(ASMJIT_NO_SHM_OPEN "${ASMJIT_NO_SHM_OPEN}" CACHE BOOL "Disable the use of shm_open() even on platforms where it's supported")
|
||||||
set(ASMJIT_NO_JIT "${ASMJIT_NO_JIT}" CACHE BOOL "Disable VirtMem, JitAllocator, and JitRuntime at build time")
|
set(ASMJIT_NO_JIT "${ASMJIT_NO_JIT}" CACHE BOOL "Disable VirtMem, JitAllocator, and JitRuntime at build time")
|
||||||
set(ASMJIT_NO_TEXT "${ASMJIT_NO_TEXT}" CACHE BOOL "Disable textual representation of instructions, enums, cpu features, ...")
|
set(ASMJIT_NO_TEXT "${ASMJIT_NO_TEXT}" CACHE BOOL "Disable textual representation of instructions, enums, cpu features, ...")
|
||||||
set(ASMJIT_NO_LOGGING "${ASMJIT_NO_LOGGING}" CACHE BOOL "Disable logging features at build time")
|
set(ASMJIT_NO_LOGGING "${ASMJIT_NO_LOGGING}" CACHE BOOL "Disable logging features at build time")
|
||||||
set(ASMJIT_NO_VALIDATION "${ASMJIT_NO_VALIDATION}" CACHE BOOL "Disable instruction validation API at build time")
|
set(ASMJIT_NO_VALIDATION "${ASMJIT_NO_VALIDATION}" CACHE BOOL "Disable instruction validation API at build time")
|
||||||
set(ASMJIT_NO_INTROSPECTION "${ASMJIT_NO_INTROSPECTION}" CACHE BOOL "Disable instruction introspection API at build time")
|
set(ASMJIT_NO_INTROSPECTION "${ASMJIT_NO_INTROSPECTION}" CACHE BOOL "Disable instruction introspection API at build time")
|
||||||
set(ASMJIT_NO_BUILDER "${ASMJIT_NO_BUILDER}" CACHE BOOL "Disable Builder emitter at build time")
|
set(ASMJIT_NO_BUILDER "${ASMJIT_NO_BUILDER}" CACHE BOOL "Disable Builder at build time")
|
||||||
set(ASMJIT_NO_COMPILER "${ASMJIT_NO_COMPILER}" CACHE BOOL "Disable Compiler emitter at build time")
|
set(ASMJIT_NO_COMPILER "${ASMJIT_NO_COMPILER}" CACHE BOOL "Disable Compiler at build time")
|
||||||
|
|
||||||
# AsmJit - Project
|
# AsmJit - Project
|
||||||
# ================
|
# ================
|
||||||
@@ -333,11 +339,13 @@ endif()
|
|||||||
foreach(build_option # AsmJit build options.
|
foreach(build_option # AsmJit build options.
|
||||||
ASMJIT_STATIC
|
ASMJIT_STATIC
|
||||||
ASMJIT_NO_DEPRECATED
|
ASMJIT_NO_DEPRECATED
|
||||||
|
ASMJIT_NO_ABI_NAMESPACE
|
||||||
# AsmJit backends selection.
|
# AsmJit backends selection.
|
||||||
ASMJIT_NO_X86
|
ASMJIT_NO_X86
|
||||||
ASMJIT_NO_AARCH64
|
ASMJIT_NO_AARCH64
|
||||||
ASMJIT_NO_FOREIGN
|
ASMJIT_NO_FOREIGN
|
||||||
# AsmJit features selection.
|
# AsmJit features selection.
|
||||||
|
ASMJIT_NO_SHM_OPEN
|
||||||
ASMJIT_NO_JIT
|
ASMJIT_NO_JIT
|
||||||
ASMJIT_NO_TEXT
|
ASMJIT_NO_TEXT
|
||||||
ASMJIT_NO_LOGGING
|
ASMJIT_NO_LOGGING
|
||||||
@@ -400,6 +408,7 @@ set(ASMJIT_SRC_LIST
|
|||||||
asmjit/core/environment.h
|
asmjit/core/environment.h
|
||||||
asmjit/core/errorhandler.cpp
|
asmjit/core/errorhandler.cpp
|
||||||
asmjit/core/errorhandler.h
|
asmjit/core/errorhandler.h
|
||||||
|
asmjit/core/fixup.h
|
||||||
asmjit/core/formatter.cpp
|
asmjit/core/formatter.cpp
|
||||||
asmjit/core/formatter.h
|
asmjit/core/formatter.h
|
||||||
asmjit/core/func.cpp
|
asmjit/core/func.cpp
|
||||||
@@ -462,7 +471,6 @@ set(ASMJIT_SRC_LIST
|
|||||||
asmjit/arm/armformatter.cpp
|
asmjit/arm/armformatter.cpp
|
||||||
asmjit/arm/armformatter_p.h
|
asmjit/arm/armformatter_p.h
|
||||||
asmjit/arm/armglobals.h
|
asmjit/arm/armglobals.h
|
||||||
asmjit/arm/armoperand.h
|
|
||||||
asmjit/arm/armutils.h
|
asmjit/arm/armutils.h
|
||||||
asmjit/arm/a64archtraits_p.h
|
asmjit/arm/a64archtraits_p.h
|
||||||
asmjit/arm/a64assembler.cpp
|
asmjit/arm/a64assembler.cpp
|
||||||
@@ -616,19 +624,20 @@ if (NOT ASMJIT_EMBED)
|
|||||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||||
|
|
||||||
asmjit_add_target(asmjit_test_perf EXECUTABLE
|
asmjit_add_target(asmjit_bench_codegen EXECUTABLE
|
||||||
SOURCES test/asmjit_test_perf.cpp
|
SOURCES test/asmjit_bench_codegen.cpp
|
||||||
test/asmjit_test_perf_a64.cpp
|
test/asmjit_bench_codegen_a64.cpp
|
||||||
test/asmjit_test_perf_x86.cpp
|
test/asmjit_bench_codegen_x86.cpp
|
||||||
SOURCES test/asmjit_test_perf.h
|
SOURCES test/asmjit_bench_codegen.h
|
||||||
LIBRARIES asmjit::asmjit
|
LIBRARIES asmjit::asmjit
|
||||||
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
CFLAGS ${ASMJIT_PRIVATE_CFLAGS}
|
||||||
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS_DBG}
|
||||||
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS_REL})
|
||||||
|
|
||||||
foreach(_target asmjit_test_environment
|
foreach(_target asmjit_bench_overhead
|
||||||
|
asmjit_bench_regalloc
|
||||||
|
asmjit_test_environment
|
||||||
asmjit_test_emitters
|
asmjit_test_emitters
|
||||||
asmjit_test_execute
|
|
||||||
asmjit_test_x86_sections)
|
asmjit_test_x86_sections)
|
||||||
asmjit_add_target(${_target} TEST
|
asmjit_add_target(${_target} TEST
|
||||||
SOURCES test/${_target}.cpp
|
SOURCES test/${_target}.cpp
|
||||||
@@ -655,24 +664,37 @@ if (NOT ASMJIT_EMBED)
|
|||||||
set(ASMJIT_SSE2_CFLAGS "")
|
set(ASMJIT_SSE2_CFLAGS "")
|
||||||
|
|
||||||
check_cxx_source_compiles("
|
check_cxx_source_compiles("
|
||||||
#if defined(_M_IX86) || defined(__X86__) || defined(__i386__)
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
int target_is_32_bit_x86() { return 1; }
|
// Skip...
|
||||||
#else
|
#elif defined(_M_IX86) || defined(__X86__) || defined(__i386__)
|
||||||
// Compile error...
|
int target_arch_is_x86() { return 1; }
|
||||||
#endif
|
#endif
|
||||||
|
int main() { return target_arch_is_x86(); }
|
||||||
|
" ASMJIT_TARGET_ARCH_X86)
|
||||||
|
|
||||||
int main() {
|
check_cxx_source_compiles("
|
||||||
return target_is_32_bit_x86();
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
}
|
int target_arch_is_x86_64() { return 1; }
|
||||||
" ASMJIT_TARGET_IS_32_BIT_X86)
|
#endif
|
||||||
|
int main() { return target_arch_is_x86_64(); }
|
||||||
|
" ASMJIT_TARGET_ARCH_X86_64)
|
||||||
|
|
||||||
if (ASMJIT_TARGET_IS_32_BIT_X86)
|
|
||||||
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC" OR "x${CMAKE_CXX_COMPILER_FRONTEND_VARIANT}" STREQUAL "xMSVC")
|
||||||
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-arch:SSE2")
|
if (ASMJIT_TARGET_ARCH_X86)
|
||||||
|
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS -arch:SSE2)
|
||||||
|
endif()
|
||||||
|
if (ASMJIT_TARGET_ARCH_X86 OR ASMJIT_TARGET_ARCH_X86_64)
|
||||||
|
asmjit_detect_cflags(ASMJIT_AVX2FMA_CFLAGS -arch:AVX2)
|
||||||
|
endif()
|
||||||
else()
|
else()
|
||||||
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS "-msse2")
|
if (ASMJIT_TARGET_ARCH_X86)
|
||||||
|
asmjit_detect_cflags(ASMJIT_SSE2_CFLAGS -msse2)
|
||||||
|
endif()
|
||||||
|
if (ASMJIT_TARGET_ARCH_X86 OR ASMJIT_TARGET_ARCH_X86_64)
|
||||||
|
asmjit_detect_cflags(ASMJIT_AVX2FMA_CFLAGS -mavx2 -mfma)
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
asmjit_add_target(asmjit_test_compiler TEST
|
asmjit_add_target(asmjit_test_compiler TEST
|
||||||
SOURCES test/asmjit_test_compiler.cpp
|
SOURCES test/asmjit_test_compiler.cpp
|
||||||
test/asmjit_test_compiler.h
|
test/asmjit_test_compiler.h
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
(function($scope, $as) {
|
(function($scope, $as) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
(function($scope, $as) {
|
(function($scope, $as) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
(function($scope, $as) {
|
(function($scope, $as) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
(function($scope, $as) {
|
(function($scope, $as) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
"use strict";
|
"use strict";
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
(function($scope, $as) {
|
(function($scope, $as) {
|
||||||
|
|||||||
@@ -143,14 +143,14 @@
|
|||||||
<Expand HideRawView="true">
|
<Expand HideRawView="true">
|
||||||
<Item Name="data">_data</Item>
|
<Item Name="data">_data</Item>
|
||||||
<Item Name="typeId">(asmjit::TypeId)(typeId())</Item>
|
<Item Name="typeId">(asmjit::TypeId)(typeId())</Item>
|
||||||
<Item Name="regType" Condition="isReg()">(asmjit::BaseReg::RegType)regType()</Item>
|
<Item Name="regType" Condition="isReg()">(asmjit::RegType)regType()</Item>
|
||||||
<Item Name="regId" Condition="isReg()">regId()</Item>
|
<Item Name="regId" Condition="isReg()">regId()</Item>
|
||||||
<Item Name="stackOffset" Condition="isStack()">stackOffset()</Item>
|
<Item Name="stackOffset" Condition="isStack()">stackOffset()</Item>
|
||||||
</Expand>
|
</Expand>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
<Type Name="asmjit::BaseNode">
|
<Type Name="asmjit::BaseNode">
|
||||||
<Intrinsic Name="nodeType" Expression="_any._nodeType" />
|
<Intrinsic Name="nodeType" Expression="_nodeType" />
|
||||||
|
|
||||||
<Intrinsic Name="isInst" Expression="nodeType() == asmjit::NodeType::kInst"></Intrinsic>
|
<Intrinsic Name="isInst" Expression="nodeType() == asmjit::NodeType::kInst"></Intrinsic>
|
||||||
<Intrinsic Name="isSection" Expression="nodeType() == asmjit::NodeType::kSection"></Intrinsic>
|
<Intrinsic Name="isSection" Expression="nodeType() == asmjit::NodeType::kSection"></Intrinsic>
|
||||||
@@ -190,8 +190,8 @@
|
|||||||
<Item Name="prev">_prev</Item>
|
<Item Name="prev">_prev</Item>
|
||||||
<Item Name="next">_next</Item>
|
<Item Name="next">_next</Item>
|
||||||
|
|
||||||
<Item Name="nodeType">_any._nodeType</Item>
|
<Item Name="nodeType">_nodeType</Item>
|
||||||
<Item Name="nodeFlags">_any._nodeFlags</Item>
|
<Item Name="nodeFlags">_nodeFlags</Item>
|
||||||
|
|
||||||
<Item Name="position">_position</Item>
|
<Item Name="position">_position</Item>
|
||||||
<Item Name="userData.u64">_userDataU64</Item>
|
<Item Name="userData.u64">_userDataU64</Item>
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_A64_H_INCLUDED
|
#ifndef ASMJIT_A64_H_INCLUDED
|
||||||
@@ -26,21 +26,13 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Register Operands
|
//! ### Register Operands
|
||||||
//!
|
//!
|
||||||
//! - \ref arm::Reg - Base class of all AArch32/AArch64 registers.
|
//! - \ref a64::Gp - General purpose register (AArch64).
|
||||||
//! - \ref a64::Gp - General purpose register (AArch64):
|
//! - \ref a64::Vec - Vector (SIMD) register.
|
||||||
//! - \ref a64::GpW - 32-bit general purpose register (AArch64).
|
|
||||||
//! - \ref a64::GpX - 64-bit general purpose register (AArch64).
|
|
||||||
//! - \ref a64::Vec - Vector (SIMD) register:
|
|
||||||
//! - \ref a64::VecB - 8-bit SIMD register.
|
|
||||||
//! - \ref a64::VecH - 16-bit SIMD register.
|
|
||||||
//! - \ref a64::VecS - 32-bit SIMD register.
|
|
||||||
//! - \ref a64::VecD - 64-bit SIMD register.
|
|
||||||
//! - \ref a64::VecV - 128-bit SIMD register.
|
|
||||||
//!
|
//!
|
||||||
//! ### Memory Operands
|
//! ### Memory Operands
|
||||||
//!
|
//!
|
||||||
//! - \ref arm::Mem - AArch32/AArch64 memory operand that provides support for all ARM addressing features
|
//! - \ref a64::Mem - AArch64 memory operand that provides support for all ARM addressing features including base,
|
||||||
//! including base, index, pre/post increment, and ARM-specific shift addressing and index extending.
|
//! index, pre/post increment, and ARM-specific shift addressing + index extending.
|
||||||
//!
|
//!
|
||||||
//! ### Other
|
//! ### Other
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_H_INCLUDED
|
#ifndef ASMJIT_ARM_H_INCLUDED
|
||||||
@@ -48,22 +48,13 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Register Operands
|
//! ### Register Operands
|
||||||
//!
|
//!
|
||||||
//! - \ref arm::Reg - Base class of all AArch32/AArch64 registers.
|
//! - AArch32:
|
||||||
//! - \ref a32::Gp - 32-bit general purpose register used by AArch32:
|
//! - \ref a32::Gp - 32-bit general purpose register used by AArch32:
|
||||||
|
//! - \ref a32::Vec - Vector (SIMD) register.
|
||||||
|
//!
|
||||||
|
//! - AArch64:
|
||||||
//! - \ref a64::Gp - 32-bit or 64-bit general purpose register used by AArch64:
|
//! - \ref a64::Gp - 32-bit or 64-bit general purpose register used by AArch64:
|
||||||
//! - \ref a64::GpW - 32-bit register (AArch64).
|
//! - \ref a64::Vec - Vector (SIMD) register.
|
||||||
//! - \ref a64::GpX - 64-bit register (AArch64).
|
|
||||||
//! - \ref arm::BaseVec - Base vector (SIMD) register.
|
|
||||||
//! - \ref a32::Vec - Vector (SIMD) register (AArch32):
|
|
||||||
//! - \ref a32::VecS - 32-bit SIMD register (AArch32).
|
|
||||||
//! - \ref a32::VecD - 64-bit SIMD register (AArch32).
|
|
||||||
//! - \ref a32::VecV - 128-bit SIMD register (AArch32).
|
|
||||||
//! - \ref a64::Vec - Vector (SIMD) register (AArch64):
|
|
||||||
//! - \ref a64::VecB - 8-bit SIMD register (AArch64).
|
|
||||||
//! - \ref a64::VecH - 16-bit SIMD register (AArch64).
|
|
||||||
//! - \ref a64::VecS - 32-bit SIMD register (AArch64).
|
|
||||||
//! - \ref a64::VecD - 64-bit SIMD register (AArch64).
|
|
||||||
//! - \ref a64::VecV - 128-bit SIMD register (AArch64).
|
|
||||||
//!
|
//!
|
||||||
//! ### Memory Operands
|
//! ### Memory Operands
|
||||||
//!
|
//!
|
||||||
@@ -80,7 +71,6 @@
|
|||||||
|
|
||||||
#include "asmjit-scope-begin.h"
|
#include "asmjit-scope-begin.h"
|
||||||
#include "arm/armglobals.h"
|
#include "arm/armglobals.h"
|
||||||
#include "arm/armoperand.h"
|
|
||||||
#include "arm/armutils.h"
|
#include "arm/armutils.h"
|
||||||
#include "asmjit-scope-end.h"
|
#include "asmjit-scope-end.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64ARCHTRAITS_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64ARCHTRAITS_P_H_INCLUDED
|
||||||
@@ -20,18 +20,28 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
|||||||
|
|
||||||
static const constexpr ArchTraits a64ArchTraits = {
|
static const constexpr ArchTraits a64ArchTraits = {
|
||||||
// SP/FP/LR/PC.
|
// SP/FP/LR/PC.
|
||||||
Gp::kIdSp, Gp::kIdFp, Gp::kIdLr, 0xFF,
|
Gp::kIdSp, Gp::kIdFp, Gp::kIdLr, 0xFFu,
|
||||||
|
|
||||||
// Reserved.
|
// Reserved.
|
||||||
{ 0, 0, 0 },
|
{ 0u, 0u, 0u },
|
||||||
|
|
||||||
// HW stack alignment (AArch64 requires stack aligned to 16 bytes at HW level).
|
// HW stack alignment (AArch64 requires stack aligned to 16 bytes at HW level).
|
||||||
16,
|
16u,
|
||||||
|
|
||||||
// Min/max stack offset - byte addressing is the worst, VecQ addressing the best.
|
// Min/max stack offset - byte addressing is the worst, vec.q addressing the best.
|
||||||
4095, 65520,
|
4095, 65520,
|
||||||
|
|
||||||
// Instruction hints [Gp, Vec, ExtraVirt2, ExtraVirt3].
|
// Supported register types.
|
||||||
|
0u | (1u << uint32_t(RegType::kGp32 ))
|
||||||
|
| (1u << uint32_t(RegType::kGp64 ))
|
||||||
|
| (1u << uint32_t(RegType::kVec8 ))
|
||||||
|
| (1u << uint32_t(RegType::kVec16 ))
|
||||||
|
| (1u << uint32_t(RegType::kVec32 ))
|
||||||
|
| (1u << uint32_t(RegType::kVec64 ))
|
||||||
|
| (1u << uint32_t(RegType::kVec128))
|
||||||
|
| (1u << uint32_t(RegType::kMask )),
|
||||||
|
|
||||||
|
// Instruction hints [Gp, Vec, Mask, Extra].
|
||||||
{{
|
{{
|
||||||
InstHints::kPushPop,
|
InstHints::kPushPop,
|
||||||
InstHints::kPushPop,
|
InstHints::kPushPop,
|
||||||
@@ -39,29 +49,19 @@ static const constexpr ArchTraits a64ArchTraits = {
|
|||||||
InstHints::kNoHints
|
InstHints::kNoHints
|
||||||
}},
|
}},
|
||||||
|
|
||||||
// RegInfo.
|
|
||||||
#define V(index) OperandSignature{RegTraits<RegType(index)>::kSignature}
|
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
|
||||||
#undef V
|
|
||||||
|
|
||||||
// RegTypeToTypeId.
|
|
||||||
#define V(index) TypeId(RegTraits<RegType(index)>::kTypeId)
|
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
|
||||||
#undef V
|
|
||||||
|
|
||||||
// TypeIdToRegType.
|
// TypeIdToRegType.
|
||||||
#define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kARM_GpW : \
|
#define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kARM_GpW : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kARM_GpW : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kARM_GpW : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kARM_GpW : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kARM_GpW : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kGp32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt64) ? RegType::kARM_GpX : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt64) ? RegType::kGp64 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt64) ? RegType::kARM_GpX : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt64) ? RegType::kGp64 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kARM_GpX : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kGp64 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kARM_GpX : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kGp64 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kARM_VecS : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kVec32 : \
|
||||||
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kARM_VecD : RegType::kNone)
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kVec64 : RegType::kNone)
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64ASSEMBLER_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64ASSEMBLER_H_INCLUDED
|
||||||
@@ -48,8 +48,8 @@ public:
|
|||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -17,6 +17,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
|||||||
|
|
||||||
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
|
Builder::Builder(CodeHolder* code) noexcept : BaseBuilder() {
|
||||||
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
||||||
|
initEmitterFuncs(this);
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
code->attach(this);
|
code->attach(this);
|
||||||
}
|
}
|
||||||
@@ -26,20 +28,19 @@ Builder::~Builder() noexcept {}
|
|||||||
// a64::Builder - Events
|
// a64::Builder - Events
|
||||||
// =====================
|
// =====================
|
||||||
|
|
||||||
Error Builder::onAttach(CodeHolder* code) noexcept {
|
Error Builder::onAttach(CodeHolder& code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|
||||||
_instructionAlignment = uint8_t(4);
|
_instructionAlignment = uint8_t(4);
|
||||||
assignEmitterFuncs(this);
|
updateEmitterFuncs(this);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Builder::onDetach(CodeHolder* code) noexcept {
|
Error Builder::onDetach(CodeHolder& code) noexcept {
|
||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// a64::Builder - Finalize
|
// a64::Builder - Finalize
|
||||||
// =======================
|
// =======================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64BUILDER_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64BUILDER_H_INCLUDED
|
||||||
@@ -36,8 +36,8 @@ public:
|
|||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -18,6 +18,8 @@ ASMJIT_BEGIN_SUB_NAMESPACE(a64)
|
|||||||
|
|
||||||
Compiler::Compiler(CodeHolder* code) noexcept : BaseCompiler() {
|
Compiler::Compiler(CodeHolder* code) noexcept : BaseCompiler() {
|
||||||
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
_archMask = uint64_t(1) << uint32_t(Arch::kAArch64);
|
||||||
|
initEmitterFuncs(this);
|
||||||
|
|
||||||
if (code) {
|
if (code) {
|
||||||
code->attach(this);
|
code->attach(this);
|
||||||
}
|
}
|
||||||
@@ -27,7 +29,7 @@ Compiler::~Compiler() noexcept {}
|
|||||||
// a64::Compiler - Events
|
// a64::Compiler - Events
|
||||||
// ======================
|
// ======================
|
||||||
|
|
||||||
Error Compiler::onAttach(CodeHolder* code) noexcept {
|
Error Compiler::onAttach(CodeHolder& code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
Error err = addPassT<ARMRAPass>();
|
Error err = addPassT<ARMRAPass>();
|
||||||
|
|
||||||
@@ -37,15 +39,23 @@ Error Compiler::onAttach(CodeHolder* code) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
_instructionAlignment = uint8_t(4);
|
_instructionAlignment = uint8_t(4);
|
||||||
assignEmitterFuncs(this);
|
updateEmitterFuncs(this);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error Compiler::onDetach(CodeHolder* code) noexcept {
|
Error Compiler::onDetach(CodeHolder& code) noexcept {
|
||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error Compiler::onReinit(CodeHolder& code) noexcept {
|
||||||
|
Error err = Base::onReinit(code);
|
||||||
|
if (err == kErrorOk) {
|
||||||
|
err = addPassT<ARMRAPass>();
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// a64::Compiler - Finalize
|
// a64::Compiler - Finalize
|
||||||
// ========================
|
// ========================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64COMPILER_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64COMPILER_H_INCLUDED
|
||||||
@@ -99,6 +99,11 @@ public:
|
|||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ASMJIT_INLINE_NODEBUG Gp newUIntPtr(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
|
ASMJIT_INLINE_NODEBUG Gp newUIntPtr(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUIntPtr, std::forward<Args>(args)...); }
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
ASMJIT_INLINE_NODEBUG Gp newGp32(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
|
||||||
|
template<typename... Args>
|
||||||
|
ASMJIT_INLINE_NODEBUG Gp newGp64(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUInt64, std::forward<Args>(args)...); }
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ASMJIT_INLINE_NODEBUG Gp newGpw(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
|
ASMJIT_INLINE_NODEBUG Gp newGpw(Args&&... args) { return _newRegInternal<Gp>(TypeId::kUInt32, std::forward<Args>(args)...); }
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@@ -214,9 +219,9 @@ public:
|
|||||||
//! Return.
|
//! Return.
|
||||||
ASMJIT_INLINE_NODEBUG Error ret() { return addRet(Operand(), Operand()); }
|
ASMJIT_INLINE_NODEBUG Error ret() { return addRet(Operand(), Operand()); }
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_INLINE_NODEBUG Error ret(const BaseReg& o0) { return addRet(o0, Operand()); }
|
ASMJIT_INLINE_NODEBUG Error ret(const Reg& o0) { return addRet(o0, Operand()); }
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_INLINE_NODEBUG Error ret(const BaseReg& o0, const BaseReg& o1) { return addRet(o0, o1); }
|
ASMJIT_INLINE_NODEBUG Error ret(const Reg& o0, const Reg& o1) { return addRet(o0, o1); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -226,15 +231,16 @@ public:
|
|||||||
using EmitterExplicitT<Compiler>::br;
|
using EmitterExplicitT<Compiler>::br;
|
||||||
|
|
||||||
//! Adds a jump to the given `target` with the provided jump `annotation`.
|
//! Adds a jump to the given `target` with the provided jump `annotation`.
|
||||||
ASMJIT_INLINE_NODEBUG Error br(const BaseReg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdBr, target, annotation); }
|
ASMJIT_INLINE_NODEBUG Error br(const Reg& target, JumpAnnotation* annotation) { return emitAnnotatedJump(Inst::kIdBr, target, annotation); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
ASMJIT_API Error onReinit(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -148,8 +148,8 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitRegMove(
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error EmitHelper::emitRegSwap(
|
Error EmitHelper::emitRegSwap(
|
||||||
const BaseReg& a,
|
const Reg& a,
|
||||||
const BaseReg& b, const char* comment) {
|
const Reg& b, const char* comment) {
|
||||||
|
|
||||||
DebugUtils::unused(a, b, comment);
|
DebugUtils::unused(a, b, comment);
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
@@ -157,13 +157,12 @@ Error EmitHelper::emitRegSwap(
|
|||||||
|
|
||||||
// TODO: [ARM] EmitArgMove is unfinished.
|
// TODO: [ARM] EmitArgMove is unfinished.
|
||||||
Error EmitHelper::emitArgMove(
|
Error EmitHelper::emitArgMove(
|
||||||
const BaseReg& dst_, TypeId dstTypeId,
|
const Reg& dst_, TypeId dstTypeId,
|
||||||
const Operand_& src_, TypeId srcTypeId, const char* comment) {
|
const Operand_& src_, TypeId srcTypeId, const char* comment) {
|
||||||
|
|
||||||
// Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
|
// Deduce optional `dstTypeId`, which may be `TypeId::kVoid` in some cases.
|
||||||
if (dstTypeId == TypeId::kVoid) {
|
if (dstTypeId == TypeId::kVoid) {
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(_emitter->arch());
|
dstTypeId = RegUtils::typeIdOf(dst_.regType());
|
||||||
dstTypeId = archTraits.regTypeToTypeId(dst_.type());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Invalid or abstract TypeIds are not allowed.
|
// Invalid or abstract TypeIds are not allowed.
|
||||||
@@ -180,7 +179,7 @@ Error EmitHelper::emitArgMove(
|
|||||||
if (TypeUtils::isInt(srcTypeId)) {
|
if (TypeUtils::isInt(srcTypeId)) {
|
||||||
uint32_t x = uint32_t(dstSize == 8);
|
uint32_t x = uint32_t(dstSize == 8);
|
||||||
|
|
||||||
dst.setSignature(OperandSignature{x ? uint32_t(GpX::kSignature) : uint32_t(GpW::kSignature)});
|
dst.setSignature(OperandSignature{x ? RegTraits<RegType::kGp64>::kSignature : RegTraits<RegType::kGp32>::kSignature});
|
||||||
_emitter->setInlineComment(comment);
|
_emitter->setInlineComment(comment);
|
||||||
|
|
||||||
if (src.isReg()) {
|
if (src.isReg()) {
|
||||||
@@ -209,10 +208,10 @@ Error EmitHelper::emitArgMove(
|
|||||||
if (TypeUtils::isFloat(dstTypeId) || TypeUtils::isVec(dstTypeId)) {
|
if (TypeUtils::isFloat(dstTypeId) || TypeUtils::isVec(dstTypeId)) {
|
||||||
if (TypeUtils::isFloat(srcTypeId) || TypeUtils::isVec(srcTypeId)) {
|
if (TypeUtils::isFloat(srcTypeId) || TypeUtils::isVec(srcTypeId)) {
|
||||||
switch (srcSize) {
|
switch (srcSize) {
|
||||||
case 2: dst.as<Vec>().setSignature(OperandSignature{VecH::kSignature}); break;
|
case 2: dst.as<Vec>().setSignature(RegTraits<RegType::kVec16>::kSignature); break;
|
||||||
case 4: dst.as<Vec>().setSignature(OperandSignature{VecS::kSignature}); break;
|
case 4: dst.as<Vec>().setSignature(RegTraits<RegType::kVec32>::kSignature); break;
|
||||||
case 8: dst.as<Vec>().setSignature(OperandSignature{VecD::kSignature}); break;
|
case 8: dst.as<Vec>().setSignature(RegTraits<RegType::kVec64>::kSignature); break;
|
||||||
case 16: dst.as<Vec>().setSignature(OperandSignature{VecV::kSignature}); break;
|
case 16: dst.as<Vec>().setSignature(RegTraits<RegType::kVec128>::kSignature); break;
|
||||||
default:
|
default:
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
@@ -295,7 +294,7 @@ struct PrologEpilogInfo {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (n == 1) {
|
if (n == 1) {
|
||||||
pairs[pairCount].ids[1] = uint8_t(BaseReg::kIdBad);
|
pairs[pairCount].ids[1] = uint8_t(Reg::kIdBad);
|
||||||
pairs[pairCount].offset = uint16_t(offset);
|
pairs[pairCount].offset = uint16_t(offset);
|
||||||
offset += slotSize * 2;
|
offset += slotSize * 2;
|
||||||
pairCount++;
|
pairCount++;
|
||||||
@@ -321,10 +320,9 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
|
|||||||
{ Inst::kIdStr_v, Inst::kIdStp_v }
|
{ Inst::kIdStr_v, Inst::kIdStp_v }
|
||||||
}};
|
}};
|
||||||
|
|
||||||
// Emit: 'bti' (indirect branch protection).
|
// Emit: 'bti {jc}' (indirect branch protection).
|
||||||
if (frame.hasIndirectBranchProtection()) {
|
if (frame.hasIndirectBranchProtection()) {
|
||||||
// TODO: The instruction is not available at the moment (would be ABI break).
|
ASMJIT_PROPAGATE(emitter->bti(Predicate::BTI::kJC));
|
||||||
// ASMJIT_PROPAGATE(emitter->bti());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t adjustInitialOffset = pei.sizeTotal;
|
uint32_t adjustInitialOffset = pei.sizeTotal;
|
||||||
@@ -349,7 +347,7 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitProlog(const FuncFrame& frame) {
|
|||||||
mem.makePreIndex();
|
mem.makePreIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pair.ids[1] == BaseReg::kIdBad) {
|
if (pair.ids[1] == Reg::kIdBad) {
|
||||||
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
|
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -433,7 +431,7 @@ ASMJIT_FAVOR_SIZE Error EmitHelper::emitEpilog(const FuncFrame& frame) {
|
|||||||
mem.makePostIndex();
|
mem.makePostIndex();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pair.ids[1] == BaseReg::kIdBad) {
|
if (pair.ids[1] == Reg::kIdBad) {
|
||||||
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
|
ASMJIT_PROPAGATE(emitter->emit(insts.singleInstId, regs[0], mem));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -464,7 +462,7 @@ static Error ASMJIT_CDECL Emitter_emitArgsAssignment(BaseEmitter* emitter, const
|
|||||||
return emitHelper.emitArgsAssignment(frame, args);
|
return emitHelper.emitArgsAssignment(frame, args);
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignEmitterFuncs(BaseEmitter* emitter) {
|
void initEmitterFuncs(BaseEmitter* emitter) {
|
||||||
emitter->_funcs.emitProlog = Emitter_emitProlog;
|
emitter->_funcs.emitProlog = Emitter_emitProlog;
|
||||||
emitter->_funcs.emitEpilog = Emitter_emitEpilog;
|
emitter->_funcs.emitEpilog = Emitter_emitEpilog;
|
||||||
emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
|
emitter->_funcs.emitArgsAssignment = Emitter_emitArgsAssignment;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64EMITHELPER_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64EMITHELPER_P_H_INCLUDED
|
||||||
@@ -31,18 +31,21 @@ public:
|
|||||||
const Operand_& src_, TypeId typeId, const char* comment = nullptr) override;
|
const Operand_& src_, TypeId typeId, const char* comment = nullptr) override;
|
||||||
|
|
||||||
Error emitRegSwap(
|
Error emitRegSwap(
|
||||||
const BaseReg& a,
|
const Reg& a,
|
||||||
const BaseReg& b, const char* comment = nullptr) override;
|
const Reg& b, const char* comment = nullptr) override;
|
||||||
|
|
||||||
Error emitArgMove(
|
Error emitArgMove(
|
||||||
const BaseReg& dst_, TypeId dstTypeId,
|
const Reg& dst_, TypeId dstTypeId,
|
||||||
const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr) override;
|
const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr) override;
|
||||||
|
|
||||||
Error emitProlog(const FuncFrame& frame);
|
Error emitProlog(const FuncFrame& frame);
|
||||||
Error emitEpilog(const FuncFrame& frame);
|
Error emitEpilog(const FuncFrame& frame);
|
||||||
};
|
};
|
||||||
|
|
||||||
void assignEmitterFuncs(BaseEmitter* emitter);
|
void initEmitterFuncs(BaseEmitter* emitter);
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
|
static inline void updateEmitterFuncs(BaseEmitter* emitter) noexcept { DebugUtils::unused(emitter); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64EMITTER_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64EMITTER_H_INCLUDED
|
||||||
@@ -226,6 +226,9 @@ struct EmitterExplicitT {
|
|||||||
ASMJIT_INST_2x(mvn, Mvn, Gp, Gp)
|
ASMJIT_INST_2x(mvn, Mvn, Gp, Gp)
|
||||||
ASMJIT_INST_3x(mvn, Mvn, Gp, Gp, Imm)
|
ASMJIT_INST_3x(mvn, Mvn, Gp, Gp, Imm)
|
||||||
|
|
||||||
|
ASMJIT_INST_2x(mvn_, Mvn, Gp, Gp)
|
||||||
|
ASMJIT_INST_3x(mvn_, Mvn, Gp, Gp, Imm)
|
||||||
|
|
||||||
ASMJIT_INST_2x(neg, Neg, Gp, Gp)
|
ASMJIT_INST_2x(neg, Neg, Gp, Gp)
|
||||||
ASMJIT_INST_3x(neg, Neg, Gp, Gp, Imm)
|
ASMJIT_INST_3x(neg, Neg, Gp, Gp, Imm)
|
||||||
ASMJIT_INST_2x(negs, Negs, Gp, Gp)
|
ASMJIT_INST_2x(negs, Negs, Gp, Gp)
|
||||||
@@ -311,27 +314,9 @@ struct EmitterExplicitT {
|
|||||||
ASMJIT_INST_1x(dcps1, Dcps1, Imm)
|
ASMJIT_INST_1x(dcps1, Dcps1, Imm)
|
||||||
ASMJIT_INST_1x(dcps2, Dcps2, Imm)
|
ASMJIT_INST_1x(dcps2, Dcps2, Imm)
|
||||||
ASMJIT_INST_1x(dcps3, Dcps3, Imm)
|
ASMJIT_INST_1x(dcps3, Dcps3, Imm)
|
||||||
ASMJIT_INST_0x(dgh, Dgh)
|
|
||||||
ASMJIT_INST_0x(pssbb, Pssbb)
|
ASMJIT_INST_0x(pssbb, Pssbb)
|
||||||
ASMJIT_INST_0x(ssbb, Ssbb)
|
ASMJIT_INST_0x(ssbb, Ssbb)
|
||||||
ASMJIT_INST_1x(udf, Udf, Imm)
|
ASMJIT_INST_1x(udf, Udf, Imm)
|
||||||
ASMJIT_INST_1x(setf8, Setf8, Gp)
|
|
||||||
ASMJIT_INST_1x(setf16, Setf16, Gp)
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name ARMv8.4 Instructions
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
ASMJIT_INST_0x(cfinv, Cfinv)
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name ARMv8.5 Instructions
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
ASMJIT_INST_0x(axflag, Axflag)
|
|
||||||
ASMJIT_INST_0x(xaflag, Xaflag)
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -631,6 +616,27 @@ struct EmitterExplicitT {
|
|||||||
ASMJIT_INST_3x(swplh, Swplh, Gp, Gp, Mem)
|
ASMJIT_INST_3x(swplh, Swplh, Gp, Gp, Mem)
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
//! \name BTI Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_1x(bti, Bti, Imm);
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name CHK Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_1x(chkfeat, Chkfeat, Gp);
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name CLRBHB Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_0x(clrbhb, Clrbhb);
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name CRC Instructions (ARMv8.1-A, optional in ARMv8.0-A)
|
//! \name CRC Instructions (ARMv8.1-A, optional in ARMv8.0-A)
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -646,6 +652,55 @@ struct EmitterExplicitT {
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
//! \name CSSC Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_2x(abs, Abs, Gp, Gp);
|
||||||
|
ASMJIT_INST_2x(cnt, Cnt, Gp, Gp);
|
||||||
|
ASMJIT_INST_2x(ctz, Ctz, Gp, Gp);
|
||||||
|
ASMJIT_INST_3x(smax, Smax, Gp, Gp, Gp);
|
||||||
|
ASMJIT_INST_3x(smax, Smax, Gp, Gp, Imm);
|
||||||
|
ASMJIT_INST_3x(smin, Smin, Gp, Gp, Gp);
|
||||||
|
ASMJIT_INST_3x(smin, Smin, Gp, Gp, Imm);
|
||||||
|
ASMJIT_INST_3x(umax, Umax, Gp, Gp, Gp);
|
||||||
|
ASMJIT_INST_3x(umax, Umax, Gp, Gp, Imm);
|
||||||
|
ASMJIT_INST_3x(umin, Umin, Gp, Gp, Gp);
|
||||||
|
ASMJIT_INST_3x(umin, Umin, Gp, Gp, Imm);
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name DGH Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_0x(dgh, Dgh)
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name FLAGM Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_0x(cfinv, Cfinv)
|
||||||
|
ASMJIT_INST_1x(setf8, Setf8, Gp)
|
||||||
|
ASMJIT_INST_1x(setf16, Setf16, Gp)
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name FLAGM2 Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_0x(axflag, Axflag)
|
||||||
|
ASMJIT_INST_0x(xaflag, Xaflag)
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name HBC Instructions
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
ASMJIT_INST_1cc(bc, Bc, Imm)
|
||||||
|
ASMJIT_INST_1cc(bc, Bc, Label)
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name MTE Instructions
|
//! \name MTE Instructions
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -874,6 +929,7 @@ struct EmitterExplicitT {
|
|||||||
ASMJIT_INST_3x(movi, Movi_v, Vec, Imm, Imm);
|
ASMJIT_INST_3x(movi, Movi_v, Vec, Imm, Imm);
|
||||||
ASMJIT_INST_3x(mul, Mul_v, Vec, Vec, Vec);
|
ASMJIT_INST_3x(mul, Mul_v, Vec, Vec, Vec);
|
||||||
ASMJIT_INST_2x(mvn, Mvn_v, Vec, Vec);
|
ASMJIT_INST_2x(mvn, Mvn_v, Vec, Vec);
|
||||||
|
ASMJIT_INST_2x(mvn_, Mvn_v, Vec, Vec);
|
||||||
ASMJIT_INST_2x(mvni, Mvni_v, Vec, Imm);
|
ASMJIT_INST_2x(mvni, Mvni_v, Vec, Imm);
|
||||||
ASMJIT_INST_3x(mvni, Mvni_v, Vec, Imm, Imm);
|
ASMJIT_INST_3x(mvni, Mvni_v, Vec, Imm, Imm);
|
||||||
ASMJIT_INST_2x(neg, Neg_v, Vec, Vec);
|
ASMJIT_INST_2x(neg, Neg_v, Vec, Vec);
|
||||||
@@ -1213,7 +1269,7 @@ struct EmitterExplicitT {
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Emitter (ARM).
|
//! Emitter (AArch64).
|
||||||
//!
|
//!
|
||||||
//! \note This class cannot be instantiated, you can only cast to it and use it as emitter that emits to either
|
//! \note This class cannot be instantiated, you can only cast to it and use it as emitter that emits to either
|
||||||
//! `a64::Assembler`, `a64::Builder`, or `a64::Compiler` (use with caution with `a64::Compiler` as it requires
|
//! `a64::Assembler`, `a64::Builder`, or `a64::Compiler` (use with caution with `a64::Compiler` as it requires
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64FORMATTER_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64FORMATTER_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -26,19 +26,19 @@ static inline bool shouldTreatAsCDecl(CallConvId ccId) noexcept {
|
|||||||
|
|
||||||
static RegType regTypeFromFpOrVecTypeId(TypeId typeId) noexcept {
|
static RegType regTypeFromFpOrVecTypeId(TypeId typeId) noexcept {
|
||||||
if (typeId == TypeId::kFloat32) {
|
if (typeId == TypeId::kFloat32) {
|
||||||
return RegType::kARM_VecS;
|
return RegType::kVec32;
|
||||||
}
|
}
|
||||||
else if (typeId == TypeId::kFloat64) {
|
else if (typeId == TypeId::kFloat64) {
|
||||||
return RegType::kARM_VecD;
|
return RegType::kVec64;
|
||||||
}
|
}
|
||||||
else if (TypeUtils::isVec32(typeId)) {
|
else if (TypeUtils::isVec32(typeId)) {
|
||||||
return RegType::kARM_VecS;
|
return RegType::kVec32;
|
||||||
}
|
}
|
||||||
else if (TypeUtils::isVec64(typeId)) {
|
else if (TypeUtils::isVec64(typeId)) {
|
||||||
return RegType::kARM_VecD;
|
return RegType::kVec64;
|
||||||
}
|
}
|
||||||
else if (TypeUtils::isVec128(typeId)) {
|
else if (TypeUtils::isVec128(typeId)) {
|
||||||
return RegType::kARM_VecV;
|
return RegType::kVec128;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
return RegType::kNone;
|
return RegType::kNone;
|
||||||
@@ -103,20 +103,20 @@ ASMJIT_FAVOR_SIZE Error initFuncDetail(FuncDetail& func, const FuncSignature& si
|
|||||||
case TypeId::kInt8:
|
case TypeId::kInt8:
|
||||||
case TypeId::kInt16:
|
case TypeId::kInt16:
|
||||||
case TypeId::kInt32: {
|
case TypeId::kInt32: {
|
||||||
func._rets[valueIndex].initReg(RegType::kARM_GpW, valueIndex, TypeId::kInt32);
|
func._rets[valueIndex].initReg(RegType::kGp32, valueIndex, TypeId::kInt32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TypeId::kUInt8:
|
case TypeId::kUInt8:
|
||||||
case TypeId::kUInt16:
|
case TypeId::kUInt16:
|
||||||
case TypeId::kUInt32: {
|
case TypeId::kUInt32: {
|
||||||
func._rets[valueIndex].initReg(RegType::kARM_GpW, valueIndex, TypeId::kUInt32);
|
func._rets[valueIndex].initReg(RegType::kGp32, valueIndex, TypeId::kUInt32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case TypeId::kInt64:
|
case TypeId::kInt64:
|
||||||
case TypeId::kUInt64: {
|
case TypeId::kUInt64: {
|
||||||
func._rets[valueIndex].initReg(RegType::kARM_GpX, valueIndex, typeId);
|
func._rets[valueIndex].initReg(RegType::kGp64, valueIndex, typeId);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -144,14 +144,14 @@ ASMJIT_FAVOR_SIZE Error initFuncDetail(FuncDetail& func, const FuncSignature& si
|
|||||||
TypeId typeId = arg.typeId();
|
TypeId typeId = arg.typeId();
|
||||||
|
|
||||||
if (TypeUtils::isInt(typeId)) {
|
if (TypeUtils::isInt(typeId)) {
|
||||||
uint32_t regId = BaseReg::kIdBad;
|
uint32_t regId = Reg::kIdBad;
|
||||||
|
|
||||||
if (gpzPos < CallConv::kMaxRegArgsPerGroup) {
|
if (gpzPos < CallConv::kMaxRegArgsPerGroup) {
|
||||||
regId = cc._passedOrder[RegGroup::kGp].id[gpzPos];
|
regId = cc._passedOrder[RegGroup::kGp].id[gpzPos];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regId != BaseReg::kIdBad) {
|
if (regId != Reg::kIdBad) {
|
||||||
RegType regType = typeId <= TypeId::kUInt32 ? RegType::kARM_GpW : RegType::kARM_GpX;
|
RegType regType = typeId <= TypeId::kUInt32 ? RegType::kGp32 : RegType::kGp64;
|
||||||
arg.assignRegData(regType, regId);
|
arg.assignRegData(regType, regId);
|
||||||
func.addUsedRegs(RegGroup::kGp, Support::bitMask(regId));
|
func.addUsedRegs(RegGroup::kGp, Support::bitMask(regId));
|
||||||
gpzPos++;
|
gpzPos++;
|
||||||
@@ -168,13 +168,13 @@ ASMJIT_FAVOR_SIZE Error initFuncDetail(FuncDetail& func, const FuncSignature& si
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (TypeUtils::isFloat(typeId) || TypeUtils::isVec(typeId)) {
|
if (TypeUtils::isFloat(typeId) || TypeUtils::isVec(typeId)) {
|
||||||
uint32_t regId = BaseReg::kIdBad;
|
uint32_t regId = Reg::kIdBad;
|
||||||
|
|
||||||
if (vecPos < CallConv::kMaxRegArgsPerGroup) {
|
if (vecPos < CallConv::kMaxRegArgsPerGroup) {
|
||||||
regId = cc._passedOrder[RegGroup::kVec].id[vecPos];
|
regId = cc._passedOrder[RegGroup::kVec].id[vecPos];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (regId != BaseReg::kIdBad) {
|
if (regId != Reg::kIdBad) {
|
||||||
RegType regType = regTypeFromFpOrVecTypeId(typeId);
|
RegType regType = regTypeFromFpOrVecTypeId(typeId);
|
||||||
if (regType == RegType::kNone) {
|
if (regType == RegType::kNone) {
|
||||||
return DebugUtils::errored(kErrorInvalidRegType);
|
return DebugUtils::errored(kErrorInvalidRegType);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64FUNC_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64FUNC_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64GLOBALS_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64GLOBALS_H_INCLUDED
|
||||||
@@ -26,6 +26,7 @@ namespace Inst {
|
|||||||
enum Id : uint32_t {
|
enum Id : uint32_t {
|
||||||
// ${InstId:Begin}
|
// ${InstId:Begin}
|
||||||
kIdNone = 0, //!< Instruction ''.
|
kIdNone = 0, //!< Instruction ''.
|
||||||
|
kIdAbs, //!< Instruction 'abs'.
|
||||||
kIdAdc, //!< Instruction 'adc'.
|
kIdAdc, //!< Instruction 'adc'.
|
||||||
kIdAdcs, //!< Instruction 'adcs'.
|
kIdAdcs, //!< Instruction 'adcs'.
|
||||||
kIdAdd, //!< Instruction 'add'.
|
kIdAdd, //!< Instruction 'add'.
|
||||||
@@ -54,6 +55,7 @@ namespace Inst {
|
|||||||
kIdAutizb, //!< Instruction 'autizb'.
|
kIdAutizb, //!< Instruction 'autizb'.
|
||||||
kIdAxflag, //!< Instruction 'axflag'.
|
kIdAxflag, //!< Instruction 'axflag'.
|
||||||
kIdB, //!< Instruction 'b'.
|
kIdB, //!< Instruction 'b'.
|
||||||
|
kIdBc, //!< Instruction 'bc'.
|
||||||
kIdBfc, //!< Instruction 'bfc'.
|
kIdBfc, //!< Instruction 'bfc'.
|
||||||
kIdBfi, //!< Instruction 'bfi'.
|
kIdBfi, //!< Instruction 'bfi'.
|
||||||
kIdBfm, //!< Instruction 'bfm'.
|
kIdBfm, //!< Instruction 'bfm'.
|
||||||
@@ -64,6 +66,7 @@ namespace Inst {
|
|||||||
kIdBlr, //!< Instruction 'blr'.
|
kIdBlr, //!< Instruction 'blr'.
|
||||||
kIdBr, //!< Instruction 'br'.
|
kIdBr, //!< Instruction 'br'.
|
||||||
kIdBrk, //!< Instruction 'brk'.
|
kIdBrk, //!< Instruction 'brk'.
|
||||||
|
kIdBti, //!< Instruction 'bti'.
|
||||||
kIdCas, //!< Instruction 'cas'.
|
kIdCas, //!< Instruction 'cas'.
|
||||||
kIdCasa, //!< Instruction 'casa'.
|
kIdCasa, //!< Instruction 'casa'.
|
||||||
kIdCasab, //!< Instruction 'casab'.
|
kIdCasab, //!< Instruction 'casab'.
|
||||||
@@ -85,8 +88,10 @@ namespace Inst {
|
|||||||
kIdCcmn, //!< Instruction 'ccmn'.
|
kIdCcmn, //!< Instruction 'ccmn'.
|
||||||
kIdCcmp, //!< Instruction 'ccmp'.
|
kIdCcmp, //!< Instruction 'ccmp'.
|
||||||
kIdCfinv, //!< Instruction 'cfinv'.
|
kIdCfinv, //!< Instruction 'cfinv'.
|
||||||
|
kIdChkfeat, //!< Instruction 'chkfeat'.
|
||||||
kIdCinc, //!< Instruction 'cinc'.
|
kIdCinc, //!< Instruction 'cinc'.
|
||||||
kIdCinv, //!< Instruction 'cinv'.
|
kIdCinv, //!< Instruction 'cinv'.
|
||||||
|
kIdClrbhb, //!< Instruction 'clrbhb'.
|
||||||
kIdClrex, //!< Instruction 'clrex'.
|
kIdClrex, //!< Instruction 'clrex'.
|
||||||
kIdCls, //!< Instruction 'cls'.
|
kIdCls, //!< Instruction 'cls'.
|
||||||
kIdClz, //!< Instruction 'clz'.
|
kIdClz, //!< Instruction 'clz'.
|
||||||
@@ -94,6 +99,7 @@ namespace Inst {
|
|||||||
kIdCmp, //!< Instruction 'cmp'.
|
kIdCmp, //!< Instruction 'cmp'.
|
||||||
kIdCmpp, //!< Instruction 'cmpp'.
|
kIdCmpp, //!< Instruction 'cmpp'.
|
||||||
kIdCneg, //!< Instruction 'cneg'.
|
kIdCneg, //!< Instruction 'cneg'.
|
||||||
|
kIdCnt, //!< Instruction 'cnt'.
|
||||||
kIdCrc32b, //!< Instruction 'crc32b'.
|
kIdCrc32b, //!< Instruction 'crc32b'.
|
||||||
kIdCrc32cb, //!< Instruction 'crc32cb'.
|
kIdCrc32cb, //!< Instruction 'crc32cb'.
|
||||||
kIdCrc32ch, //!< Instruction 'crc32ch'.
|
kIdCrc32ch, //!< Instruction 'crc32ch'.
|
||||||
@@ -109,6 +115,7 @@ namespace Inst {
|
|||||||
kIdCsinc, //!< Instruction 'csinc'.
|
kIdCsinc, //!< Instruction 'csinc'.
|
||||||
kIdCsinv, //!< Instruction 'csinv'.
|
kIdCsinv, //!< Instruction 'csinv'.
|
||||||
kIdCsneg, //!< Instruction 'csneg'.
|
kIdCsneg, //!< Instruction 'csneg'.
|
||||||
|
kIdCtz, //!< Instruction 'ctz'.
|
||||||
kIdDc, //!< Instruction 'dc'.
|
kIdDc, //!< Instruction 'dc'.
|
||||||
kIdDcps1, //!< Instruction 'dcps1'.
|
kIdDcps1, //!< Instruction 'dcps1'.
|
||||||
kIdDcps2, //!< Instruction 'dcps2'.
|
kIdDcps2, //!< Instruction 'dcps2'.
|
||||||
@@ -311,7 +318,9 @@ namespace Inst {
|
|||||||
kIdSev, //!< Instruction 'sev'.
|
kIdSev, //!< Instruction 'sev'.
|
||||||
kIdSevl, //!< Instruction 'sevl'.
|
kIdSevl, //!< Instruction 'sevl'.
|
||||||
kIdSmaddl, //!< Instruction 'smaddl'.
|
kIdSmaddl, //!< Instruction 'smaddl'.
|
||||||
|
kIdSmax, //!< Instruction 'smax'.
|
||||||
kIdSmc, //!< Instruction 'smc'.
|
kIdSmc, //!< Instruction 'smc'.
|
||||||
|
kIdSmin, //!< Instruction 'smin'.
|
||||||
kIdSmnegl, //!< Instruction 'smnegl'.
|
kIdSmnegl, //!< Instruction 'smnegl'.
|
||||||
kIdSmsubl, //!< Instruction 'smsubl'.
|
kIdSmsubl, //!< Instruction 'smsubl'.
|
||||||
kIdSmulh, //!< Instruction 'smulh'.
|
kIdSmulh, //!< Instruction 'smulh'.
|
||||||
@@ -429,6 +438,8 @@ namespace Inst {
|
|||||||
kIdUdf, //!< Instruction 'udf'.
|
kIdUdf, //!< Instruction 'udf'.
|
||||||
kIdUdiv, //!< Instruction 'udiv'.
|
kIdUdiv, //!< Instruction 'udiv'.
|
||||||
kIdUmaddl, //!< Instruction 'umaddl'.
|
kIdUmaddl, //!< Instruction 'umaddl'.
|
||||||
|
kIdUmax, //!< Instruction 'umax'.
|
||||||
|
kIdUmin, //!< Instruction 'umin'.
|
||||||
kIdUmnegl, //!< Instruction 'umnegl'.
|
kIdUmnegl, //!< Instruction 'umnegl'.
|
||||||
kIdUmull, //!< Instruction 'umull'.
|
kIdUmull, //!< Instruction 'umull'.
|
||||||
kIdUmulh, //!< Instruction 'umulh'.
|
kIdUmulh, //!< Instruction 'umulh'.
|
||||||
@@ -824,6 +835,17 @@ namespace AT {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Branch target identification targets (BTI).
|
||||||
|
namespace BTI {
|
||||||
|
//! Branch target identification targets
|
||||||
|
enum Value : uint32_t {
|
||||||
|
kNone = 0u,
|
||||||
|
kC = 1u,
|
||||||
|
kJ = 2u,
|
||||||
|
kJC = 3u
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
//! Data barrier options (DMB/DSB).
|
//! Data barrier options (DMB/DSB).
|
||||||
namespace DB {
|
namespace DB {
|
||||||
//! Data barrier immediate values.
|
//! Data barrier immediate values.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -128,7 +128,7 @@ Error queryRWInfo(const BaseInst& inst, const Operand_* operands, size_t opCount
|
|||||||
OpRWFlags rwFlags = i < opCount - 1 ? (OpRWFlags)rwInfo.rwx[0] : (OpRWFlags)rwInfo.rwx[1];
|
OpRWFlags rwFlags = i < opCount - 1 ? (OpRWFlags)rwInfo.rwx[0] : (OpRWFlags)rwInfo.rwx[1];
|
||||||
|
|
||||||
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
||||||
op._physId = BaseReg::kIdBad;
|
op._physId = Reg::kIdBad;
|
||||||
op._rmSize = 0;
|
op._rmSize = 0;
|
||||||
op._resetReserved();
|
op._resetReserved();
|
||||||
|
|
||||||
@@ -177,7 +177,7 @@ Error queryRWInfo(const BaseInst& inst, const Operand_* operands, size_t opCount
|
|||||||
OpRWFlags rwFlags = (OpRWFlags)rwInfo.rwx[i];
|
OpRWFlags rwFlags = (OpRWFlags)rwInfo.rwx[i];
|
||||||
|
|
||||||
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
op._opFlags = rwFlags & ~(OpRWFlags::kZExt);
|
||||||
op._physId = BaseReg::kIdBad;
|
op._physId = Reg::kIdBad;
|
||||||
op._rmSize = 0;
|
op._rmSize = 0;
|
||||||
op._resetReserved();
|
op._resetReserved();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64INSTAPI_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64INSTAPI_P_H_INCLUDED
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64INSTDB_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64INSTDB_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64INSTDB_H_P_INCLUDED
|
#ifndef ASMJIT_ARM_A64INSTDB_H_P_INCLUDED
|
||||||
@@ -82,23 +82,22 @@ enum GpType : uint8_t {
|
|||||||
// ===================
|
// ===================
|
||||||
|
|
||||||
enum kOpSignature : uint32_t {
|
enum kOpSignature : uint32_t {
|
||||||
kOp_GpW = GpW::kSignature,
|
kOp_GpW = RegTraits<RegType::kGp32>::kSignature,
|
||||||
kOp_GpX = GpX::kSignature,
|
kOp_GpX = RegTraits<RegType::kGp64>::kSignature,
|
||||||
|
kOp_B = RegTraits<RegType::kVec8>::kSignature,
|
||||||
|
kOp_H = RegTraits<RegType::kVec16>::kSignature,
|
||||||
|
kOp_S = RegTraits<RegType::kVec32>::kSignature,
|
||||||
|
kOp_D = RegTraits<RegType::kVec64>::kSignature,
|
||||||
|
kOp_Q = RegTraits<RegType::kVec128>::kSignature,
|
||||||
|
|
||||||
kOp_B = VecB::kSignature,
|
kOp_V8B = kOp_D | Vec::kSignatureElementB,
|
||||||
kOp_H = VecH::kSignature,
|
kOp_V4H = kOp_D | Vec::kSignatureElementH,
|
||||||
kOp_S = VecS::kSignature,
|
kOp_V2S = kOp_D | Vec::kSignatureElementS,
|
||||||
kOp_D = VecD::kSignature,
|
|
||||||
kOp_Q = VecV::kSignature,
|
|
||||||
|
|
||||||
kOp_V8B = VecD::kSignature | Vec::kSignatureElementB,
|
kOp_V16B = kOp_Q | Vec::kSignatureElementB,
|
||||||
kOp_V4H = VecD::kSignature | Vec::kSignatureElementH,
|
kOp_V8H = kOp_Q | Vec::kSignatureElementH,
|
||||||
kOp_V2S = VecD::kSignature | Vec::kSignatureElementS,
|
kOp_V4S = kOp_Q | Vec::kSignatureElementS,
|
||||||
|
kOp_V2D = kOp_Q | Vec::kSignatureElementD
|
||||||
kOp_V16B = VecV::kSignature | Vec::kSignatureElementB,
|
|
||||||
kOp_V8H = VecV::kSignature | Vec::kSignatureElementH,
|
|
||||||
kOp_V4S = VecV::kSignature | Vec::kSignatureElementS,
|
|
||||||
kOp_V2D = VecV::kSignature | Vec::kSignatureElementD
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// a64::InstDB - HFConv
|
// a64::InstDB - HFConv
|
||||||
@@ -186,6 +185,7 @@ enum EncodingId : uint32_t {
|
|||||||
kEncodingBaseLdpStp,
|
kEncodingBaseLdpStp,
|
||||||
kEncodingBaseLdxp,
|
kEncodingBaseLdxp,
|
||||||
kEncodingBaseLogical,
|
kEncodingBaseLogical,
|
||||||
|
kEncodingBaseMinMax,
|
||||||
kEncodingBaseMov,
|
kEncodingBaseMov,
|
||||||
kEncodingBaseMovKNZ,
|
kEncodingBaseMovKNZ,
|
||||||
kEncodingBaseMrs,
|
kEncodingBaseMrs,
|
||||||
@@ -193,6 +193,7 @@ enum EncodingId : uint32_t {
|
|||||||
kEncodingBaseMvnNeg,
|
kEncodingBaseMvnNeg,
|
||||||
kEncodingBaseOp,
|
kEncodingBaseOp,
|
||||||
kEncodingBaseOpImm,
|
kEncodingBaseOpImm,
|
||||||
|
kEncodingBaseOpX16,
|
||||||
kEncodingBasePrfm,
|
kEncodingBasePrfm,
|
||||||
kEncodingBaseR,
|
kEncodingBaseR,
|
||||||
kEncodingBaseRM_NoImm,
|
kEncodingBaseRM_NoImm,
|
||||||
@@ -270,6 +271,10 @@ struct BaseOp {
|
|||||||
uint32_t opcode;
|
uint32_t opcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BaseOpX16 {
|
||||||
|
uint32_t opcode;
|
||||||
|
};
|
||||||
|
|
||||||
struct BaseOpImm {
|
struct BaseOpImm {
|
||||||
uint32_t opcode;
|
uint32_t opcode;
|
||||||
uint16_t immBits;
|
uint16_t immBits;
|
||||||
@@ -342,6 +347,11 @@ struct BaseAdcSbc {
|
|||||||
uint32_t opcode;
|
uint32_t opcode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct BaseMinMax {
|
||||||
|
uint32_t regOp;
|
||||||
|
uint32_t immOp;
|
||||||
|
};
|
||||||
|
|
||||||
struct BaseAddSub {
|
struct BaseAddSub {
|
||||||
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|Rd|
|
uint32_t shiftedOp : 10; // sf|.......|Sh|.|Rm| Imm:6 |Rn|Rd|
|
||||||
uint32_t extendedOp : 10; // sf|.......|..|.|Rm|Opt|Imm3|Rn|Rd|
|
uint32_t extendedOp : 10; // sf|.......|..|.|Rm|Opt|Imm3|Rn|Rd|
|
||||||
@@ -779,7 +789,7 @@ extern const BaseBfm baseBfm[3];
|
|||||||
extern const BaseBfx baseBfx[3];
|
extern const BaseBfx baseBfx[3];
|
||||||
extern const BaseBranchCmp baseBranchCmp[2];
|
extern const BaseBranchCmp baseBranchCmp[2];
|
||||||
extern const BaseBranchReg baseBranchReg[3];
|
extern const BaseBranchReg baseBranchReg[3];
|
||||||
extern const BaseBranchRel baseBranchRel[2];
|
extern const BaseBranchRel baseBranchRel[3];
|
||||||
extern const BaseBranchTst baseBranchTst[2];
|
extern const BaseBranchTst baseBranchTst[2];
|
||||||
extern const BaseCCmp baseCCmp[2];
|
extern const BaseCCmp baseCCmp[2];
|
||||||
extern const BaseCInc baseCInc[3];
|
extern const BaseCInc baseCInc[3];
|
||||||
@@ -792,16 +802,18 @@ extern const BaseLdSt baseLdSt[9];
|
|||||||
extern const BaseLdpStp baseLdpStp[6];
|
extern const BaseLdpStp baseLdpStp[6];
|
||||||
extern const BaseLdxp baseLdxp[2];
|
extern const BaseLdxp baseLdxp[2];
|
||||||
extern const BaseLogical baseLogical[8];
|
extern const BaseLogical baseLogical[8];
|
||||||
|
extern const BaseMinMax baseMinMax[4];
|
||||||
extern const BaseMovKNZ baseMovKNZ[3];
|
extern const BaseMovKNZ baseMovKNZ[3];
|
||||||
extern const BaseMvnNeg baseMvnNeg[3];
|
extern const BaseMvnNeg baseMvnNeg[3];
|
||||||
extern const BaseOp baseOp[23];
|
extern const BaseOp baseOp[24];
|
||||||
extern const BaseOpImm baseOpImm[14];
|
extern const BaseOpImm baseOpImm[15];
|
||||||
|
extern const BaseOpX16 baseOpX16[1];
|
||||||
extern const BasePrfm basePrfm[1];
|
extern const BasePrfm basePrfm[1];
|
||||||
extern const BaseR baseR[10];
|
extern const BaseR baseR[10];
|
||||||
extern const BaseRM_NoImm baseRM_NoImm[21];
|
extern const BaseRM_NoImm baseRM_NoImm[21];
|
||||||
extern const BaseRM_SImm10 baseRM_SImm10[2];
|
extern const BaseRM_SImm10 baseRM_SImm10[2];
|
||||||
extern const BaseRM_SImm9 baseRM_SImm9[23];
|
extern const BaseRM_SImm9 baseRM_SImm9[23];
|
||||||
extern const BaseRR baseRR[15];
|
extern const BaseRR baseRR[18];
|
||||||
extern const BaseRRII baseRRII[2];
|
extern const BaseRRII baseRRII[2];
|
||||||
extern const BaseRRR baseRRR[26];
|
extern const BaseRRR baseRRR[26];
|
||||||
extern const BaseRRRR baseRRRR[6];
|
extern const BaseRRRR baseRRRR[6];
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -32,28 +32,28 @@ UNIT(a64_operand) {
|
|||||||
EXPECT_EQ(sp.id(), Gp::kIdSp);
|
EXPECT_EQ(sp.id(), Gp::kIdSp);
|
||||||
EXPECT_EQ(w0.size(), 4u);
|
EXPECT_EQ(w0.size(), 4u);
|
||||||
EXPECT_EQ(x0.size(), 8u);
|
EXPECT_EQ(x0.size(), 8u);
|
||||||
EXPECT_EQ(w0.type(), RegType::kARM_GpW);
|
EXPECT_EQ(w0.regType(), RegType::kGp32);
|
||||||
EXPECT_EQ(x0.type(), RegType::kARM_GpX);
|
EXPECT_EQ(x0.regType(), RegType::kGp64);
|
||||||
EXPECT_EQ(w0.group(), RegGroup::kGp);
|
EXPECT_EQ(w0.regGroup(), RegGroup::kGp);
|
||||||
EXPECT_EQ(x0.group(), RegGroup::kGp);
|
EXPECT_EQ(x0.regGroup(), RegGroup::kGp);
|
||||||
|
|
||||||
INFO("Checking Vec register properties");
|
INFO("Checking Vec register properties");
|
||||||
EXPECT_EQ(v0.type(), RegType::kARM_VecV);
|
EXPECT_EQ(v0.regType(), RegType::kVec128);
|
||||||
EXPECT_EQ(d0.type(), RegType::kARM_VecD);
|
EXPECT_EQ(d0.regType(), RegType::kVec64);
|
||||||
EXPECT_EQ(s0.type(), RegType::kARM_VecS);
|
EXPECT_EQ(s0.regType(), RegType::kVec32);
|
||||||
EXPECT_EQ(h0.type(), RegType::kARM_VecH);
|
EXPECT_EQ(h0.regType(), RegType::kVec16);
|
||||||
EXPECT_EQ(b0.type(), RegType::kARM_VecB);
|
EXPECT_EQ(b0.regType(), RegType::kVec8);
|
||||||
|
|
||||||
EXPECT_EQ(v0.group(), RegGroup::kVec);
|
EXPECT_EQ(v0.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(d0.group(), RegGroup::kVec);
|
EXPECT_EQ(d0.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(s0.group(), RegGroup::kVec);
|
EXPECT_EQ(s0.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(h0.group(), RegGroup::kVec);
|
EXPECT_EQ(h0.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(b0.group(), RegGroup::kVec);
|
EXPECT_EQ(b0.regGroup(), RegGroup::kVec);
|
||||||
|
|
||||||
INFO("Checking Vec register element[] access");
|
INFO("Checking Vec register element[] access");
|
||||||
Vec vd_1 = v15.d(1);
|
Vec vd_1 = v15.d(1);
|
||||||
EXPECT_EQ(vd_1.type(), RegType::kARM_VecV);
|
EXPECT_EQ(vd_1.regType(), RegType::kVec128);
|
||||||
EXPECT_EQ(vd_1.group(), RegGroup::kVec);
|
EXPECT_EQ(vd_1.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(vd_1.id(), 15u);
|
EXPECT_EQ(vd_1.id(), 15u);
|
||||||
EXPECT_TRUE(vd_1.isVecD2());
|
EXPECT_TRUE(vd_1.isVecD2());
|
||||||
EXPECT_EQ(vd_1.elementType(), VecElementType::kD);
|
EXPECT_EQ(vd_1.elementType(), VecElementType::kD);
|
||||||
@@ -61,8 +61,8 @@ UNIT(a64_operand) {
|
|||||||
EXPECT_EQ(vd_1.elementIndex(), 1u);
|
EXPECT_EQ(vd_1.elementIndex(), 1u);
|
||||||
|
|
||||||
Vec vs_3 = v15.s(3);
|
Vec vs_3 = v15.s(3);
|
||||||
EXPECT_EQ(vs_3.type(), RegType::kARM_VecV);
|
EXPECT_EQ(vs_3.regType(), RegType::kVec128);
|
||||||
EXPECT_EQ(vs_3.group(), RegGroup::kVec);
|
EXPECT_EQ(vs_3.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(vs_3.id(), 15u);
|
EXPECT_EQ(vs_3.id(), 15u);
|
||||||
EXPECT_TRUE(vs_3.isVecS4());
|
EXPECT_TRUE(vs_3.isVecS4());
|
||||||
EXPECT_EQ(vs_3.elementType(), VecElementType::kS);
|
EXPECT_EQ(vs_3.elementType(), VecElementType::kS);
|
||||||
@@ -70,8 +70,8 @@ UNIT(a64_operand) {
|
|||||||
EXPECT_EQ(vs_3.elementIndex(), 3u);
|
EXPECT_EQ(vs_3.elementIndex(), 3u);
|
||||||
|
|
||||||
Vec vb_4 = v15.b4(3);
|
Vec vb_4 = v15.b4(3);
|
||||||
EXPECT_EQ(vb_4.type(), RegType::kARM_VecV);
|
EXPECT_EQ(vb_4.regType(), RegType::kVec128);
|
||||||
EXPECT_EQ(vb_4.group(), RegGroup::kVec);
|
EXPECT_EQ(vb_4.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(vb_4.id(), 15u);
|
EXPECT_EQ(vb_4.id(), 15u);
|
||||||
EXPECT_TRUE(vb_4.isVecB4x4());
|
EXPECT_TRUE(vb_4.isVecB4x4());
|
||||||
EXPECT_EQ(vb_4.elementType(), VecElementType::kB4);
|
EXPECT_EQ(vb_4.elementType(), VecElementType::kB4);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,13 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#if !defined(ASMJIT_NO_AARCH64) && !defined(ASMJIT_NO_COMPILER)
|
#if !defined(ASMJIT_NO_AARCH64) && !defined(ASMJIT_NO_COMPILER)
|
||||||
|
|
||||||
#include "../core/cpuinfo.h"
|
#include "../core/cpuinfo.h"
|
||||||
|
#include "../core/formatter_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
#include "../core/type.h"
|
#include "../core/type.h"
|
||||||
#include "../arm/a64assembler.h"
|
#include "../arm/a64assembler.h"
|
||||||
@@ -99,13 +100,13 @@ public:
|
|||||||
Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept;
|
Error onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept;
|
Error moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, Reg* out) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept;
|
Error moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept;
|
Error moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Reg& reg) noexcept;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
Error onBeforeRet(FuncRetNode* funcRet) noexcept;
|
Error onBeforeRet(FuncRetNode* funcRet) noexcept;
|
||||||
@@ -195,8 +196,8 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
|||||||
RegMask useRegs = _pass->_availableRegs[group];
|
RegMask useRegs = _pass->_availableRegs[group];
|
||||||
RegMask outRegs = useRegs;
|
RegMask outRegs = useRegs;
|
||||||
|
|
||||||
uint32_t useId = BaseReg::kIdBad;
|
uint32_t useId = Reg::kIdBad;
|
||||||
uint32_t outId = BaseReg::kIdBad;
|
uint32_t outId = Reg::kIdBad;
|
||||||
|
|
||||||
uint32_t useRewriteMask = 0;
|
uint32_t useRewriteMask = 0;
|
||||||
uint32_t outRewriteMask = 0;
|
uint32_t outRewriteMask = 0;
|
||||||
@@ -227,7 +228,7 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (Support::test(flags, RATiedFlags::kUse)) {
|
if (Support::test(flags, RATiedFlags::kUse)) {
|
||||||
useRewriteMask = Support::bitMask(inst->getRewriteIndex(®._baseId));
|
useRewriteMask = Support::bitMask(inst->_getRewriteIndex(®._baseId));
|
||||||
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
|
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
|
||||||
useId = opRwInfo.physId();
|
useId = opRwInfo.physId();
|
||||||
flags |= RATiedFlags::kUseFixed;
|
flags |= RATiedFlags::kUseFixed;
|
||||||
@@ -240,7 +241,7 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outRewriteMask = Support::bitMask(inst->getRewriteIndex(®._baseId));
|
outRewriteMask = Support::bitMask(inst->_getRewriteIndex(®._baseId));
|
||||||
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
|
if (opRwInfo.hasOpFlag(OpRWFlags::kRegPhysId)) {
|
||||||
outId = opRwInfo.physId();
|
outId = opRwInfo.physId();
|
||||||
flags |= RATiedFlags::kOutFixed;
|
flags |= RATiedFlags::kOutFixed;
|
||||||
@@ -300,17 +301,17 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
|||||||
RegMask allocable = _pass->_availableRegs[group];
|
RegMask allocable = _pass->_availableRegs[group];
|
||||||
|
|
||||||
// Base registers have never fixed id on ARM.
|
// Base registers have never fixed id on ARM.
|
||||||
const uint32_t useId = BaseReg::kIdBad;
|
const uint32_t useId = Reg::kIdBad;
|
||||||
const uint32_t outId = BaseReg::kIdBad;
|
const uint32_t outId = Reg::kIdBad;
|
||||||
|
|
||||||
uint32_t useRewriteMask = 0;
|
uint32_t useRewriteMask = 0;
|
||||||
uint32_t outRewriteMask = 0;
|
uint32_t outRewriteMask = 0;
|
||||||
|
|
||||||
if (Support::test(flags, RATiedFlags::kUse)) {
|
if (Support::test(flags, RATiedFlags::kUse)) {
|
||||||
useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
|
useRewriteMask = Support::bitMask(inst->_getRewriteIndex(&mem._baseId));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._baseId));
|
outRewriteMask = Support::bitMask(inst->_getRewriteIndex(&mem._baseId));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(ib.add(workReg, flags, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
|
ASMJIT_PROPAGATE(ib.add(workReg, flags, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
|
||||||
@@ -328,17 +329,17 @@ Error RACFGBuilder::onInst(InstNode* inst, InstControlFlow& controlType, RAInstB
|
|||||||
RegMask allocable = _pass->_availableRegs[group];
|
RegMask allocable = _pass->_availableRegs[group];
|
||||||
|
|
||||||
// Index registers have never fixed id on ARM.
|
// Index registers have never fixed id on ARM.
|
||||||
const uint32_t useId = BaseReg::kIdBad;
|
const uint32_t useId = Reg::kIdBad;
|
||||||
const uint32_t outId = BaseReg::kIdBad;
|
const uint32_t outId = Reg::kIdBad;
|
||||||
|
|
||||||
uint32_t useRewriteMask = 0;
|
uint32_t useRewriteMask = 0;
|
||||||
uint32_t outRewriteMask = 0;
|
uint32_t outRewriteMask = 0;
|
||||||
|
|
||||||
if (Support::test(flags, RATiedFlags::kUse)) {
|
if (Support::test(flags, RATiedFlags::kUse)) {
|
||||||
useRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
|
useRewriteMask = Support::bitMask(inst->_getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
outRewriteMask = Support::bitMask(inst->getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
|
outRewriteMask = Support::bitMask(inst->_getRewriteIndex(&mem._data[Operand::kDataMemIndexId]));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
|
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, useId, useRewriteMask, allocable, outId, outRewriteMask));
|
||||||
@@ -382,7 +383,7 @@ Error RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept {
|
|||||||
|
|
||||||
if (arg.isReg()) {
|
if (arg.isReg()) {
|
||||||
RegGroup regGroup = workReg->group();
|
RegGroup regGroup = workReg->group();
|
||||||
RegGroup argGroup = Reg::groupOf(arg.regType());
|
RegGroup argGroup = RegUtils::groupOf(arg.regType());
|
||||||
|
|
||||||
if (regGroup != argGroup) {
|
if (regGroup != argGroup) {
|
||||||
// TODO: [ARM] Conversion is not supported.
|
// TODO: [ARM] Conversion is not supported.
|
||||||
@@ -395,7 +396,7 @@ Error RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept {
|
|||||||
}
|
}
|
||||||
else if (op.isImm()) {
|
else if (op.isImm()) {
|
||||||
if (arg.isReg()) {
|
if (arg.isReg()) {
|
||||||
BaseReg reg;
|
Reg reg;
|
||||||
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), ®));
|
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, op.as<Imm>(), ®));
|
||||||
invokeNode->_args[argIndex][valueIndex] = reg;
|
invokeNode->_args[argIndex][valueIndex] = reg;
|
||||||
}
|
}
|
||||||
@@ -423,7 +424,7 @@ Error RACFGBuilder::onBeforeInvoke(InvokeNode* invokeNode) noexcept {
|
|||||||
|
|
||||||
if (ret.isReg()) {
|
if (ret.isReg()) {
|
||||||
RegGroup regGroup = workReg->group();
|
RegGroup regGroup = workReg->group();
|
||||||
RegGroup retGroup = Reg::groupOf(ret.regType());
|
RegGroup retGroup = RegUtils::groupOf(ret.regType());
|
||||||
|
|
||||||
if (regGroup != retGroup) {
|
if (regGroup != retGroup) {
|
||||||
// TODO: [ARM] Conversion is not supported.
|
// TODO: [ARM] Conversion is not supported.
|
||||||
@@ -474,7 +475,7 @@ Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept
|
|||||||
}
|
}
|
||||||
else if (arg.isReg()) {
|
else if (arg.isReg()) {
|
||||||
RegGroup regGroup = workReg->group();
|
RegGroup regGroup = workReg->group();
|
||||||
RegGroup argGroup = Reg::groupOf(arg.regType());
|
RegGroup argGroup = RegUtils::groupOf(arg.regType());
|
||||||
|
|
||||||
if (regGroup == argGroup) {
|
if (regGroup == argGroup) {
|
||||||
ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
|
ASMJIT_PROPAGATE(ib.addCallArg(workReg, arg.regId()));
|
||||||
@@ -498,7 +499,7 @@ Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept
|
|||||||
|
|
||||||
if (ret.isReg()) {
|
if (ret.isReg()) {
|
||||||
RegGroup regGroup = workReg->group();
|
RegGroup regGroup = workReg->group();
|
||||||
RegGroup retGroup = Reg::groupOf(ret.regType());
|
RegGroup retGroup = RegUtils::groupOf(ret.regType());
|
||||||
|
|
||||||
if (regGroup == retGroup) {
|
if (regGroup == retGroup) {
|
||||||
ASMJIT_PROPAGATE(ib.addCallRet(workReg, ret.regId()));
|
ASMJIT_PROPAGATE(ib.addCallRet(workReg, ret.regId()));
|
||||||
@@ -522,7 +523,7 @@ Error RACFGBuilder::onInvoke(InvokeNode* invokeNode, RAInstBuilder& ib) noexcept
|
|||||||
// a64::RACFGBuilder - MoveImmToRegArg
|
// a64::RACFGBuilder - MoveImmToRegArg
|
||||||
// ===================================
|
// ===================================
|
||||||
|
|
||||||
Error RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, BaseReg* out) noexcept {
|
Error RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_, Reg* out) noexcept {
|
||||||
DebugUtils::unused(invokeNode);
|
DebugUtils::unused(invokeNode);
|
||||||
ASMJIT_ASSERT(arg.isReg());
|
ASMJIT_ASSERT(arg.isReg());
|
||||||
|
|
||||||
@@ -552,7 +553,7 @@ Error RACFGBuilder::moveImmToRegArg(InvokeNode* invokeNode, const FuncValue& arg
|
|||||||
// =====================================
|
// =====================================
|
||||||
|
|
||||||
Error RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept {
|
Error RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Imm& imm_) noexcept {
|
||||||
BaseReg reg;
|
Reg reg;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, imm_, ®));
|
ASMJIT_PROPAGATE(moveImmToRegArg(invokeNode, arg, imm_, ®));
|
||||||
ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
|
ASMJIT_PROPAGATE(moveRegToStackArg(invokeNode, arg, reg));
|
||||||
@@ -563,7 +564,7 @@ Error RACFGBuilder::moveImmToStackArg(InvokeNode* invokeNode, const FuncValue& a
|
|||||||
// a64::RACFGBuilder - MoveRegToStackArg
|
// a64::RACFGBuilder - MoveRegToStackArg
|
||||||
// =====================================
|
// =====================================
|
||||||
|
|
||||||
Error RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const BaseReg& reg) noexcept {
|
Error RACFGBuilder::moveRegToStackArg(InvokeNode* invokeNode, const FuncValue& arg, const Reg& reg) noexcept {
|
||||||
DebugUtils::unused(invokeNode);
|
DebugUtils::unused(invokeNode);
|
||||||
Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset());
|
Mem stackPtr = ptr(_pass->_sp.as<Gp>(), arg.stackOffset());
|
||||||
|
|
||||||
@@ -613,7 +614,7 @@ Error RACFGBuilder::onRet(FuncRetNode* funcRet, RAInstBuilder& ib) noexcept {
|
|||||||
|
|
||||||
RegGroup group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
RegMask allocable = _pass->_availableRegs[group];
|
RegMask allocable = _pass->_availableRegs[group];
|
||||||
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, ret.regId(), 0, 0, BaseReg::kIdBad, 0));
|
ASMJIT_PROPAGATE(ib.add(workReg, RATiedFlags::kUse | RATiedFlags::kRead, allocable, ret.regId(), 0, 0, Reg::kIdBad, 0));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -714,14 +715,14 @@ ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) no
|
|||||||
uint32_t useId = tiedReg->useId();
|
uint32_t useId = tiedReg->useId();
|
||||||
|
|
||||||
while (useIt.hasNext()) {
|
while (useIt.hasNext()) {
|
||||||
inst->rewriteIdAtIndex(useIt.next(), useId);
|
inst->_rewriteIdAtIndex(useIt.next(), useId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::BitWordIterator<uint32_t> outIt(tiedReg->outRewriteMask());
|
Support::BitWordIterator<uint32_t> outIt(tiedReg->outRewriteMask());
|
||||||
uint32_t outId = tiedReg->outId();
|
uint32_t outId = tiedReg->outId();
|
||||||
|
|
||||||
while (outIt.hasNext()) {
|
while (outIt.hasNext()) {
|
||||||
inst->rewriteIdAtIndex(outIt.next(), outId);
|
inst->_rewriteIdAtIndex(outIt.next(), outId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -767,7 +768,7 @@ ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) no
|
|||||||
RAStackSlot* slot = workReg->stackSlot();
|
RAStackSlot* slot = workReg->stackSlot();
|
||||||
int32_t offset = slot->offset();
|
int32_t offset = slot->offset();
|
||||||
|
|
||||||
mem._setBase(_sp.type(), slot->baseRegId());
|
mem._setBase(_sp.regType(), slot->baseRegId());
|
||||||
mem.clearRegHome();
|
mem.clearRegHome();
|
||||||
mem.addOffsetLo32(offset);
|
mem.addOffsetLo32(offset);
|
||||||
}
|
}
|
||||||
@@ -788,8 +789,8 @@ ASMJIT_FAVOR_SPEED Error ARMRAPass::_rewrite(BaseNode* first, BaseNode* stop) no
|
|||||||
return DebugUtils::errored(kErrorInvalidAddressIndex);
|
return DebugUtils::errored(kErrorInvalidAddressIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
GpX dst(inst->op(0).as<Gp>().id());
|
Gp dst = Gp::make_r64(inst->op(0).as<Gp>().id());
|
||||||
GpX base(mem.baseId());
|
Gp base = Gp::make_r64(mem.baseId());
|
||||||
|
|
||||||
InstId arithInstId = offset < 0 ? Inst::kIdSub : Inst::kIdAdd;
|
InstId arithInstId = offset < 0 ? Inst::kIdSub : Inst::kIdAdd;
|
||||||
uint64_t absOffset = offset < 0 ? Support::neg(uint64_t(offset)) : uint64_t(offset);
|
uint64_t absOffset = offset < 0 ? Support::neg(uint64_t(offset)) : uint64_t(offset);
|
||||||
@@ -842,14 +843,15 @@ Error ARMRAPass::updateStackFrame() noexcept {
|
|||||||
|
|
||||||
Error ARMRAPass::emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
Error ARMRAPass::emitMove(uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
||||||
RAWorkReg* wReg = workRegById(workId);
|
RAWorkReg* wReg = workRegById(workId);
|
||||||
BaseReg dst(wReg->signature(), dstPhysId);
|
Reg dst(wReg->signature(), dstPhysId);
|
||||||
BaseReg src(wReg->signature(), srcPhysId);
|
Reg src(wReg->signature(), srcPhysId);
|
||||||
|
|
||||||
const char* comment = nullptr;
|
const char* comment = nullptr;
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
||||||
_tmpString.assignFormat("<MOVE> %s", workRegById(workId)->name());
|
_tmpString.clear();
|
||||||
|
Formatter::formatVirtRegNameWithPrefix(_tmpString, "<MOVE> ", 7u, wReg->virtReg());
|
||||||
comment = _tmpString.data();
|
comment = _tmpString.data();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -864,14 +866,15 @@ Error ARMRAPass::emitSwap(uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId,
|
|||||||
|
|
||||||
Error ARMRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept {
|
Error ARMRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept {
|
||||||
RAWorkReg* wReg = workRegById(workId);
|
RAWorkReg* wReg = workRegById(workId);
|
||||||
BaseReg dstReg(wReg->signature(), dstPhysId);
|
Reg dstReg(wReg->signature(), dstPhysId);
|
||||||
BaseMem srcMem(workRegAsMem(wReg));
|
BaseMem srcMem(workRegAsMem(wReg));
|
||||||
|
|
||||||
const char* comment = nullptr;
|
const char* comment = nullptr;
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
||||||
_tmpString.assignFormat("<LOAD> %s", workRegById(workId)->name());
|
_tmpString.clear();
|
||||||
|
Formatter::formatVirtRegNameWithPrefix(_tmpString, "<LOAD> ", 7u, wReg->virtReg());
|
||||||
comment = _tmpString.data();
|
comment = _tmpString.data();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -882,13 +885,14 @@ Error ARMRAPass::emitLoad(uint32_t workId, uint32_t dstPhysId) noexcept {
|
|||||||
Error ARMRAPass::emitSave(uint32_t workId, uint32_t srcPhysId) noexcept {
|
Error ARMRAPass::emitSave(uint32_t workId, uint32_t srcPhysId) noexcept {
|
||||||
RAWorkReg* wReg = workRegById(workId);
|
RAWorkReg* wReg = workRegById(workId);
|
||||||
BaseMem dstMem(workRegAsMem(wReg));
|
BaseMem dstMem(workRegAsMem(wReg));
|
||||||
BaseReg srcReg(wReg->signature(), srcPhysId);
|
Reg srcReg(wReg->signature(), srcPhysId);
|
||||||
|
|
||||||
const char* comment = nullptr;
|
const char* comment = nullptr;
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
if (hasDiagnosticOption(DiagnosticOptions::kRAAnnotate)) {
|
||||||
_tmpString.assignFormat("<SAVE> %s", workRegById(workId)->name());
|
_tmpString.clear();
|
||||||
|
Formatter::formatVirtRegNameWithPrefix(_tmpString, "<SAVE> ", 7u, wReg->virtReg());
|
||||||
comment = _tmpString.data();
|
comment = _tmpString.data();
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_A64RAPASS_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_A64RAPASS_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
|
||||||
|
#include "../core/formatter_p.h"
|
||||||
#include "../core/misc_p.h"
|
#include "../core/misc_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
#include "../arm/armformatter_p.h"
|
#include "../arm/armformatter_p.h"
|
||||||
@@ -48,6 +49,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"CHK\0"
|
"CHK\0"
|
||||||
"CLRBHB\0"
|
"CLRBHB\0"
|
||||||
"CMOW\0"
|
"CMOW\0"
|
||||||
|
"CMPBR\0"
|
||||||
"CONSTPACFIELD\0"
|
"CONSTPACFIELD\0"
|
||||||
"CPA\0"
|
"CPA\0"
|
||||||
"CPA2\0"
|
"CPA2\0"
|
||||||
@@ -69,6 +71,10 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"ECV\0"
|
"ECV\0"
|
||||||
"EDHSR\0"
|
"EDHSR\0"
|
||||||
"EDSP\0"
|
"EDSP\0"
|
||||||
|
"F8E4M3\0"
|
||||||
|
"F8E5M2\0"
|
||||||
|
"F8F16MM\0"
|
||||||
|
"F8F32MM\0"
|
||||||
"FAMINMAX\0"
|
"FAMINMAX\0"
|
||||||
"FCMA\0"
|
"FCMA\0"
|
||||||
"FGT\0"
|
"FGT\0"
|
||||||
@@ -85,6 +91,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"FP8DOT4\0"
|
"FP8DOT4\0"
|
||||||
"FP8FMA\0"
|
"FP8FMA\0"
|
||||||
"FPMR\0"
|
"FPMR\0"
|
||||||
|
"FPRCVT\0"
|
||||||
"FRINTTS\0"
|
"FRINTTS\0"
|
||||||
"GCS\0"
|
"GCS\0"
|
||||||
"HACDBS\0"
|
"HACDBS\0"
|
||||||
@@ -107,9 +114,12 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"LS64\0"
|
"LS64\0"
|
||||||
"LS64_ACCDATA\0"
|
"LS64_ACCDATA\0"
|
||||||
"LS64_V\0"
|
"LS64_V\0"
|
||||||
|
"LS64WB\0"
|
||||||
"LSE\0"
|
"LSE\0"
|
||||||
"LSE128\0"
|
"LSE128\0"
|
||||||
"LSE2\0"
|
"LSE2\0"
|
||||||
|
"LSFE\0"
|
||||||
|
"LSUI\0"
|
||||||
"LUT\0"
|
"LUT\0"
|
||||||
"LVA\0"
|
"LVA\0"
|
||||||
"LVA3\0"
|
"LVA3\0"
|
||||||
@@ -131,6 +141,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"NMI\0"
|
"NMI\0"
|
||||||
"NV\0"
|
"NV\0"
|
||||||
"NV2\0"
|
"NV2\0"
|
||||||
|
"OCCMO\0"
|
||||||
"PAN\0"
|
"PAN\0"
|
||||||
"PAN2\0"
|
"PAN2\0"
|
||||||
"PAN3\0"
|
"PAN3\0"
|
||||||
@@ -166,6 +177,8 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"SME\0"
|
"SME\0"
|
||||||
"SME2\0"
|
"SME2\0"
|
||||||
"SME2_1\0"
|
"SME2_1\0"
|
||||||
|
"SME2_2\0"
|
||||||
|
"SME_AES\0"
|
||||||
"SME_B16B16\0"
|
"SME_B16B16\0"
|
||||||
"SME_B16F32\0"
|
"SME_B16F32\0"
|
||||||
"SME_BI32I32\0"
|
"SME_BI32I32\0"
|
||||||
@@ -180,6 +193,8 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"SME_I16I64\0"
|
"SME_I16I64\0"
|
||||||
"SME_I8I32\0"
|
"SME_I8I32\0"
|
||||||
"SME_LUTv2\0"
|
"SME_LUTv2\0"
|
||||||
|
"SME_MOP4\0"
|
||||||
|
"SME_TMOP\0"
|
||||||
"SPE\0"
|
"SPE\0"
|
||||||
"SPE1_1\0"
|
"SPE1_1\0"
|
||||||
"SPE1_2\0"
|
"SPE1_2\0"
|
||||||
@@ -196,17 +211,25 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
"SPMU\0"
|
"SPMU\0"
|
||||||
"SSBS\0"
|
"SSBS\0"
|
||||||
"SSBS2\0"
|
"SSBS2\0"
|
||||||
|
"SSVE_AES\0"
|
||||||
|
"SSVE_BITPERM\0"
|
||||||
|
"SSVE_FEXPA\0"
|
||||||
"SSVE_FP8DOT2\0"
|
"SSVE_FP8DOT2\0"
|
||||||
"SSVE_FP8DOT4\0"
|
"SSVE_FP8DOT4\0"
|
||||||
"SSVE_FP8FMA\0"
|
"SSVE_FP8FMA\0"
|
||||||
"SVE\0"
|
"SVE\0"
|
||||||
"SVE2\0"
|
"SVE2\0"
|
||||||
"SVE2_1\0"
|
"SVE2_1\0"
|
||||||
|
"SVE2_2\0"
|
||||||
"SVE_AES\0"
|
"SVE_AES\0"
|
||||||
|
"SVE_AES2\0"
|
||||||
"SVE_B16B16\0"
|
"SVE_B16B16\0"
|
||||||
"SVE_BF16\0"
|
"SVE_BF16\0"
|
||||||
|
"SVE_BFSCALE\0"
|
||||||
"SVE_BITPERM\0"
|
"SVE_BITPERM\0"
|
||||||
"SVE_EBF16\0"
|
"SVE_EBF16\0"
|
||||||
|
"SVE_ELTPERM\0"
|
||||||
|
"SVE_F16MM\0"
|
||||||
"SVE_F32MM\0"
|
"SVE_F32MM\0"
|
||||||
"SVE_F64MM\0"
|
"SVE_F64MM\0"
|
||||||
"SVE_I8MM\0"
|
"SVE_I8MM\0"
|
||||||
@@ -232,19 +255,21 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
|
|||||||
|
|
||||||
static const uint16_t sFeatureIndex[] = {
|
static const uint16_t sFeatureIndex[] = {
|
||||||
0, 5, 11, 17, 24, 30, 38, 43, 49, 53, 57, 61, 66, 73, 79, 85, 90, 95, 99,
|
0, 5, 11, 17, 24, 30, 38, 43, 49, 53, 57, 61, 66, 73, 79, 85, 90, 95, 99,
|
||||||
103, 109, 113, 120, 125, 139, 143, 148, 154, 160, 165, 170, 177, 182, 187,
|
103, 109, 113, 120, 125, 131, 145, 149, 154, 160, 166, 171, 176, 183, 188,
|
||||||
191, 195, 203, 207, 212, 217, 223, 229, 233, 239, 244, 253, 258, 262, 267,
|
193, 197, 201, 209, 213, 218, 223, 229, 235, 239, 245, 250, 257, 264, 272,
|
||||||
271, 277, 284, 289, 292, 297, 306, 310, 318, 326, 333, 338, 346, 350, 357,
|
280, 289, 294, 298, 303, 307, 313, 320, 325, 328, 333, 342, 346, 354, 362,
|
||||||
364, 369, 375, 379, 383, 388, 394, 399, 405, 411, 415, 421, 425, 431, 438,
|
369, 374, 381, 389, 393, 400, 407, 412, 418, 422, 426, 431, 437, 442, 448,
|
||||||
445, 450, 463, 470, 474, 481, 486, 490, 494, 499, 503, 508, 513, 517, 522,
|
454, 458, 464, 468, 474, 481, 488, 493, 506, 513, 520, 524, 531, 536, 541,
|
||||||
527, 532, 547, 557, 576, 596, 608, 623, 638, 644, 648, 651, 655, 659, 664,
|
546, 550, 554, 559, 563, 568, 573, 577, 582, 587, 592, 607, 617, 636, 656,
|
||||||
669, 675, 680, 684, 690, 698, 702, 709, 714, 721, 725, 729, 733, 742, 748,
|
668, 683, 698, 704, 708, 711, 715, 721, 725, 730, 735, 741, 746, 750, 756,
|
||||||
754, 760, 766, 772, 778, 781, 788, 794, 799, 804, 811, 816, 823, 827, 831,
|
764, 768, 775, 780, 787, 791, 795, 799, 808, 814, 820, 826, 832, 838, 844,
|
||||||
835, 840, 847, 858, 869, 881, 892, 903, 914, 925, 935, 945, 954, 965, 976,
|
847, 854, 860, 865, 870, 877, 882, 889, 893, 897, 901, 906, 913, 920, 928,
|
||||||
986, 996, 1000, 1007, 1014, 1021, 1028, 1039, 1047, 1055, 1063, 1071, 1079,
|
939, 950, 962, 973, 984, 995, 1006, 1016, 1026, 1035, 1046, 1057, 1067, 1077,
|
||||||
1087, 1096, 1101, 1106, 1112, 1125, 1138, 1150, 1154, 1159, 1166, 1174, 1185,
|
1086, 1095, 1099, 1106, 1113, 1120, 1127, 1138, 1146, 1154, 1162, 1170, 1178,
|
||||||
1194, 1206, 1216, 1226, 1236, 1245, 1258, 1267, 1275, 1287, 1297, 1301, 1308,
|
1186, 1195, 1200, 1205, 1211, 1220, 1233, 1244, 1257, 1270, 1282, 1286, 1291,
|
||||||
1318, 1324, 1328, 1332, 1336, 1344, 1348, 1355, 1360, 1364, 1367
|
1298, 1305, 1313, 1322, 1333, 1342, 1354, 1366, 1376, 1388, 1398, 1408, 1418,
|
||||||
|
1427, 1440, 1449, 1457, 1469, 1479, 1483, 1490, 1500, 1506, 1510, 1514, 1518,
|
||||||
|
1526, 1530, 1537, 1542, 1546, 1549
|
||||||
};
|
};
|
||||||
// @EnumStringEnd@
|
// @EnumStringEnd@
|
||||||
|
|
||||||
@@ -333,14 +358,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
|||||||
VirtReg* vReg = cc->virtRegById(rId);
|
VirtReg* vReg = cc->virtRegById(rId);
|
||||||
ASMJIT_ASSERT(vReg != nullptr);
|
ASMJIT_ASSERT(vReg != nullptr);
|
||||||
|
|
||||||
const char* name = vReg->name();
|
ASMJIT_PROPAGATE(Formatter::formatVirtRegName(sb, vReg));
|
||||||
if (name && name[0] != '\0') {
|
|
||||||
ASMJIT_PROPAGATE(sb.append(name));
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId))));
|
|
||||||
}
|
|
||||||
|
|
||||||
virtRegFormatted = true;
|
virtRegFormatted = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -352,18 +370,18 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
|||||||
if (!virtRegFormatted) {
|
if (!virtRegFormatted) {
|
||||||
char letter = '\0';
|
char letter = '\0';
|
||||||
switch (regType) {
|
switch (regType) {
|
||||||
case RegType::kARM_VecB:
|
case RegType::kVec8:
|
||||||
case RegType::kARM_VecH:
|
case RegType::kVec16:
|
||||||
case RegType::kARM_VecS:
|
case RegType::kVec32:
|
||||||
case RegType::kARM_VecD:
|
case RegType::kVec64:
|
||||||
case RegType::kARM_VecV:
|
case RegType::kVec128:
|
||||||
letter = bhsdq[uint32_t(regType) - uint32_t(RegType::kARM_VecB)];
|
letter = bhsdq[uint32_t(regType) - uint32_t(RegType::kVec8)];
|
||||||
if (elementType) {
|
if (elementType) {
|
||||||
letter = 'v';
|
letter = 'v';
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RegType::kARM_GpW:
|
case RegType::kGp32:
|
||||||
if (Environment::is64Bit(arch)) {
|
if (Environment::is64Bit(arch)) {
|
||||||
letter = 'w';
|
letter = 'w';
|
||||||
|
|
||||||
@@ -380,7 +398,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case RegType::kARM_GpX:
|
case RegType::kGp64:
|
||||||
if (Environment::is64Bit(arch)) {
|
if (Environment::is64Bit(arch)) {
|
||||||
if (rId == a64::Gp::kIdZr) {
|
if (rId == a64::Gp::kIdZr) {
|
||||||
return sb.append("xzr", 3);
|
return sb.append("xzr", 3);
|
||||||
@@ -413,7 +431,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(
|
|||||||
FormatElementData elementData = formatElementDataTable[elementType];
|
FormatElementData elementData = formatElementDataTable[elementType];
|
||||||
uint32_t elementCount = elementData.elementCount;
|
uint32_t elementCount = elementData.elementCount;
|
||||||
|
|
||||||
if (regType == RegType::kARM_VecD) {
|
if (regType == RegType::kVec64) {
|
||||||
elementCount /= 2u;
|
elementCount /= 2u;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -481,20 +499,20 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
|||||||
const Operand_& op) noexcept {
|
const Operand_& op) noexcept {
|
||||||
|
|
||||||
if (op.isReg()) {
|
if (op.isReg()) {
|
||||||
const BaseReg& reg = op.as<BaseReg>();
|
const Reg& reg = op.as<Reg>();
|
||||||
|
|
||||||
uint32_t elementType = op._signature.getField<BaseVec::kSignatureRegElementTypeMask>();
|
uint32_t elementType = op._signature.getField<a64::Vec::kSignatureRegElementTypeMask>();
|
||||||
uint32_t elementIndex = op.as<BaseVec>().elementIndex();
|
uint32_t elementIndex = op.as<a64::Vec>().elementIndex();
|
||||||
|
|
||||||
if (!op.as<BaseVec>().hasElementIndex()) {
|
if (!op.as<a64::Vec>().hasElementIndex()) {
|
||||||
elementIndex = 0xFFFFFFFFu;
|
elementIndex = 0xFFFFFFFFu;
|
||||||
}
|
}
|
||||||
|
|
||||||
return formatRegister(sb, flags, emitter, arch, reg.type(), reg.id(), elementType, elementIndex);
|
return formatRegister(sb, flags, emitter, arch, reg.regType(), reg.id(), elementType, elementIndex);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op.isMem()) {
|
if (op.isMem()) {
|
||||||
const Mem& m = op.as<Mem>();
|
const a64::Mem& m = op.as<a64::Mem>();
|
||||||
ASMJIT_PROPAGATE(sb.append('['));
|
ASMJIT_PROPAGATE(sb.append('['));
|
||||||
|
|
||||||
if (m.hasBase()) {
|
if (m.hasBase()) {
|
||||||
@@ -591,7 +609,7 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
|
|||||||
|
|
||||||
if (op.isRegList()) {
|
if (op.isRegList()) {
|
||||||
const BaseRegList& regList = op.as<BaseRegList>();
|
const BaseRegList& regList = op.as<BaseRegList>();
|
||||||
return formatRegisterList(sb, flags, emitter, arch, regList.type(), regList.list());
|
return formatRegisterList(sb, flags, emitter, arch, regList.regType(), regList.list());
|
||||||
}
|
}
|
||||||
|
|
||||||
return sb.append("<None>");
|
return sb.append("<None>");
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_ARMFORMATTER_P_H_INCLUDED
|
#ifndef ASMJIT_ARM_ARMFORMATTER_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
|
#ifndef ASMJIT_ARM_ARMGLOBALS_H_INCLUDED
|
||||||
|
|||||||
@@ -1,399 +0,0 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
|
||||||
//
|
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
|
||||||
// SPDX-License-Identifier: Zlib
|
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_ARMOPERAND_H_INCLUDED
|
|
||||||
#define ASMJIT_ARM_ARMOPERAND_H_INCLUDED
|
|
||||||
|
|
||||||
#include "../core/archtraits.h"
|
|
||||||
#include "../core/operand.h"
|
|
||||||
#include "../core/type.h"
|
|
||||||
#include "../arm/armglobals.h"
|
|
||||||
|
|
||||||
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
|
||||||
|
|
||||||
//! \addtogroup asmjit_arm
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
class Reg;
|
|
||||||
class Mem;
|
|
||||||
|
|
||||||
//! Register traits (AArch32/AArch64).
|
|
||||||
//!
|
|
||||||
//! Register traits contains information about a particular register type. It's used by asmjit to setup register
|
|
||||||
//! information on-the-fly and to populate tables that contain register information (this way it's possible to
|
|
||||||
//! change register types and groups without having to reorder these tables).
|
|
||||||
template<RegType kRegType>
|
|
||||||
struct RegTraits : public BaseRegTraits {};
|
|
||||||
|
|
||||||
//! \cond
|
|
||||||
// <--------------------+------------------------+------------------------+---+------------------+
|
|
||||||
// | Reg-Type | Reg-Group |Sz | TypeId |
|
|
||||||
// <--------------------+------------------------+------------------------+---+------------------+
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpW , RegGroup::kGp , 4 , TypeId::kInt32 ); // AArch32 & AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_GpX , RegGroup::kGp , 8 , TypeId::kInt64 ); // AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecB , RegGroup::kVec , 1 , TypeId::kVoid ); // AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecH , RegGroup::kVec , 2 , TypeId::kVoid ); // AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecS , RegGroup::kVec , 4 , TypeId::kInt32x1 ); // AArch32 & AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecD , RegGroup::kVec , 8 , TypeId::kInt32x2 ); // AArch32 & AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_VecQ , RegGroup::kVec , 16, TypeId::kInt32x4 ); // AArch32 & AArch64
|
|
||||||
ASMJIT_DEFINE_REG_TRAITS(RegType::kARM_PC , RegGroup::kPC , 8 , TypeId::kInt64 ); // AArch64
|
|
||||||
//! \endcond
|
|
||||||
|
|
||||||
//! Register operand that can represent AArch32 and AArch64 registers.
|
|
||||||
class Reg : public BaseReg {
|
|
||||||
public:
|
|
||||||
ASMJIT_DEFINE_ABSTRACT_REG(Reg, BaseReg)
|
|
||||||
|
|
||||||
//! Gets whether the register is either `R` or `W` register (32-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isGpR() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
|
||||||
//! Gets whether the register is either `R` or `W` register (32-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isGpW() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpW>::kSignature; }
|
|
||||||
//! Gets whether the register is an `X` register (64-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isGpX() const noexcept { return baseSignature() == RegTraits<RegType::kARM_GpX>::kSignature; }
|
|
||||||
|
|
||||||
//! Gets whether the register is a VEC-B register (8-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecB() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
|
||||||
//! Gets whether the register is a VEC-H register (16-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecH() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
|
|
||||||
//! Gets whether the register is a VEC-S register (32-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecS() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
|
|
||||||
//! Gets whether the register is a VEC-D register (64-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecD() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
|
||||||
//! Gets whether the register is a VEC-Q register (128-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecQ() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
||||||
//! Gets whether the register is either VEC-D (64-bit) or VEC-Q (128-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecDOrQ() const noexcept { return uint32_t(type()) - uint32_t(RegType::kARM_VecD) <= 1u; }
|
|
||||||
//! Gets whether the register is a VEC-V register (128-bit).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVecV() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
||||||
|
|
||||||
//! Gets whether the register is an 8-bit vector register or view, alias if \ref isVecB().
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVec8() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecB>::kSignature; }
|
|
||||||
//! Gets whether the register is a 16-bit vector register or view, alias if \ref isVecH().
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVec16() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecH>::kSignature; }
|
|
||||||
//! Gets whether the register is a 32-bit vector register or view, alias if \ref isVecS().
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVec32() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecS>::kSignature; }
|
|
||||||
//! Gets whether the register is a 64-bit vector register or view, alias if \ref isVecD().
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVec64() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecD>::kSignature; }
|
|
||||||
//! Gets whether the register is a 128-bit vector register or view, alias if \ref isVecQ().
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isVec128() const noexcept { return baseSignature() == RegTraits<RegType::kARM_VecV>::kSignature; }
|
|
||||||
|
|
||||||
template<RegType kRegType>
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setRegT(uint32_t id) noexcept {
|
|
||||||
setSignature(RegTraits<kRegType>::kSignature);
|
|
||||||
setId(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void setTypeAndId(RegType type, uint32_t id) noexcept {
|
|
||||||
setSignature(signatureOf(type));
|
|
||||||
setId(id);
|
|
||||||
}
|
|
||||||
|
|
||||||
static ASMJIT_INLINE_NODEBUG RegGroup groupOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToGroup(type); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG TypeId typeIdOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToTypeId(type); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG OperandSignature signatureOf(RegType type) noexcept { return ArchTraits::byArch(Arch::kAArch64).regTypeToSignature(type); }
|
|
||||||
|
|
||||||
template<RegType kRegType>
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR RegGroup groupOfT() noexcept { return RegTraits<kRegType>::kGroup; }
|
|
||||||
|
|
||||||
template<RegType kRegType>
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR TypeId typeIdOfT() noexcept { return RegTraits<kRegType>::kTypeId; }
|
|
||||||
|
|
||||||
template<RegType kRegType>
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR OperandSignature signatureOfT() noexcept { return OperandSignature{RegTraits<kRegType>::kSignature}; }
|
|
||||||
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isGpW(const Operand_& op) noexcept { return op.as<Reg>().isGpW(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isGpX(const Operand_& op) noexcept { return op.as<Reg>().isGpX(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecB(const Operand_& op) noexcept { return op.as<Reg>().isVecB(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecH(const Operand_& op) noexcept { return op.as<Reg>().isVecH(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecS(const Operand_& op) noexcept { return op.as<Reg>().isVecS(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecD(const Operand_& op) noexcept { return op.as<Reg>().isVecD(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecQ(const Operand_& op) noexcept { return op.as<Reg>().isVecQ(); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecV(const Operand_& op) noexcept { return op.as<Reg>().isVecV(); }
|
|
||||||
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isGpW(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpW(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isGpX(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isGpX(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecB(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecB(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecH(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecH(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecS(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecS(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecD(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecD(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecQ(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecQ(op)) & unsigned(op.id() == id)); }
|
|
||||||
static ASMJIT_INLINE_NODEBUG bool isVecV(const Operand_& op, uint32_t id) noexcept { return bool(unsigned(isVecV(op)) & unsigned(op.id() == id)); }
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Vector register base - a common base for both AArch32 & AArch64 vector register.
|
|
||||||
class BaseVec : public Reg {
|
|
||||||
public:
|
|
||||||
ASMJIT_DEFINE_ABSTRACT_REG(BaseVec, Reg)
|
|
||||||
|
|
||||||
//! Additional signature bits used by a vector register.
|
|
||||||
enum AdditionalBits : uint32_t {
|
|
||||||
// Register element type (3 bits).
|
|
||||||
// |........|........|.XXX....|........|
|
|
||||||
kSignatureRegElementTypeShift = 12,
|
|
||||||
kSignatureRegElementTypeMask = 0x07 << kSignatureRegElementTypeShift,
|
|
||||||
|
|
||||||
// Register has element index (1 bit).
|
|
||||||
// |........|........|X.......|........|
|
|
||||||
kSignatureRegElementFlagShift = 15,
|
|
||||||
kSignatureRegElementFlagMask = 0x01 << kSignatureRegElementFlagShift,
|
|
||||||
|
|
||||||
// Register element index (4 bits).
|
|
||||||
// |........|....XXXX|........|........|
|
|
||||||
kSignatureRegElementIndexShift = 16,
|
|
||||||
kSignatureRegElementIndexMask = 0x0F << kSignatureRegElementIndexShift
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Returns whether the register has element index (it's an element index access).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool hasElementIndex() const noexcept { return _signature.hasField<kSignatureRegElementFlagMask>(); }
|
|
||||||
//! Returns element index of the register.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR uint32_t elementIndex() const noexcept { return _signature.getField<kSignatureRegElementIndexMask>(); }
|
|
||||||
//! Sets element index of the register to `elementType`.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setElementIndex(uint32_t elementIndex) noexcept {
|
|
||||||
_signature |= kSignatureRegElementFlagMask;
|
|
||||||
_signature.setField<kSignatureRegElementIndexMask>(elementIndex);
|
|
||||||
}
|
|
||||||
//! Resets element index of the register.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void resetElementIndex() noexcept {
|
|
||||||
_signature &= ~(kSignatureRegElementFlagMask | kSignatureRegElementIndexMask);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Memory operand (ARM).
|
|
||||||
class Mem : public BaseMem {
|
|
||||||
public:
|
|
||||||
//! \cond INTERNAL
|
|
||||||
//! Additional bits of operand's signature used by `arm::Mem`.
|
|
||||||
enum AdditionalBits : uint32_t {
|
|
||||||
// Index shift value (5 bits).
|
|
||||||
// |........|.....XXX|XX......|........|
|
|
||||||
kSignatureMemShiftValueShift = 14,
|
|
||||||
kSignatureMemShiftValueMask = 0x1Fu << kSignatureMemShiftValueShift,
|
|
||||||
|
|
||||||
// Index shift operation (4 bits).
|
|
||||||
// |........|XXXX....|........|........|
|
|
||||||
kSignatureMemShiftOpShift = 20,
|
|
||||||
kSignatureMemShiftOpMask = 0x0Fu << kSignatureMemShiftOpShift,
|
|
||||||
|
|
||||||
// Offset mode type (2 bits).
|
|
||||||
// |......XX|........|........|........|
|
|
||||||
kSignatureMemOffsetModeShift = 24,
|
|
||||||
kSignatureMemOffsetModeMask = 0x03u << kSignatureMemOffsetModeShift
|
|
||||||
};
|
|
||||||
//! \endcond
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Construct a default `Mem` operand, that points to [0].
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem() noexcept
|
|
||||||
: BaseMem() {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem(const Mem& other) noexcept
|
|
||||||
: BaseMem(other) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG explicit Mem(Globals::NoInit_) noexcept
|
|
||||||
: BaseMem(Globals::NoInit) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem(const Signature& signature, uint32_t baseId, uint32_t indexId, int32_t offset) noexcept
|
|
||||||
: BaseMem(signature, baseId, indexId, offset) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR explicit Mem(const Label& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
|
|
||||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
||||||
Signature::fromMemBaseType(RegType::kLabelTag) |
|
|
||||||
signature, base.id(), 0, off) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR explicit Mem(const BaseReg& base, int32_t off = 0, Signature signature = Signature{0}) noexcept
|
|
||||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
||||||
Signature::fromMemBaseType(base.type()) |
|
|
||||||
signature, base.id(), 0, off) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem(const BaseReg& base, const BaseReg& index, Signature signature = Signature{0}) noexcept
|
|
||||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
||||||
Signature::fromMemBaseType(base.type()) |
|
|
||||||
Signature::fromMemIndexType(index.type()) |
|
|
||||||
signature, base.id(), index.id(), 0) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem(const BaseReg& base, const BaseReg& index, const Shift& shift, Signature signature = Signature{0}) noexcept
|
|
||||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
||||||
Signature::fromMemBaseType(base.type()) |
|
|
||||||
Signature::fromMemIndexType(index.type()) |
|
|
||||||
Signature::fromValue<kSignatureMemShiftOpMask>(uint32_t(shift.op())) |
|
|
||||||
Signature::fromValue<kSignatureMemShiftValueMask>(shift.value()) |
|
|
||||||
signature, base.id(), index.id(), 0) {}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR explicit Mem(uint64_t base, Signature signature = Signature{0}) noexcept
|
|
||||||
: BaseMem(Signature::fromOpType(OperandType::kMem) |
|
|
||||||
signature, uint32_t(base >> 32), 0, int32_t(uint32_t(base & 0xFFFFFFFFu))) {}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Overloaded Operators
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem& operator=(const Mem& other) noexcept {
|
|
||||||
copyFrom(other);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Clone
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Clones the memory operand.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem clone() const noexcept { return Mem(*this); }
|
|
||||||
|
|
||||||
//! Gets new memory operand adjusted by `off`.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem cloneAdjusted(int64_t off) const noexcept {
|
|
||||||
Mem result(*this);
|
|
||||||
result.addOffset(off);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Clones the memory operand and makes it pre-index.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem pre() const noexcept {
|
|
||||||
Mem result(*this);
|
|
||||||
result.setOffsetMode(OffsetMode::kPreIndex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Clones the memory operand, applies a given offset `off` and makes it pre-index.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem pre(int64_t off) const noexcept {
|
|
||||||
Mem result(*this);
|
|
||||||
result.setOffsetMode(OffsetMode::kPreIndex);
|
|
||||||
result.addOffset(off);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Clones the memory operand and makes it post-index.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem post() const noexcept {
|
|
||||||
Mem result(*this);
|
|
||||||
result.setOffsetMode(OffsetMode::kPostIndex);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Clones the memory operand, applies a given offset `off` and makes it post-index.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR Mem post(int64_t off) const noexcept {
|
|
||||||
Mem result(*this);
|
|
||||||
result.setOffsetMode(OffsetMode::kPostIndex);
|
|
||||||
result.addOffset(off);
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Base & Index
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Converts memory `baseType` and `baseId` to `arm::Reg` instance.
|
|
||||||
//!
|
|
||||||
//! The memory must have a valid base register otherwise the result will be wrong.
|
|
||||||
ASMJIT_INLINE_NODEBUG Reg baseReg() const noexcept { return Reg::fromTypeAndId(baseType(), baseId()); }
|
|
||||||
|
|
||||||
//! Converts memory `indexType` and `indexId` to `arm::Reg` instance.
|
|
||||||
//!
|
|
||||||
//! The memory must have a valid index register otherwise the result will be wrong.
|
|
||||||
ASMJIT_INLINE_NODEBUG Reg indexReg() const noexcept { return Reg::fromTypeAndId(indexType(), indexId()); }
|
|
||||||
|
|
||||||
using BaseMem::setIndex;
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setIndex(const BaseReg& index, uint32_t shift) noexcept {
|
|
||||||
setIndex(index);
|
|
||||||
setShift(shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setIndex(const BaseReg& index, Shift shift) noexcept {
|
|
||||||
setIndex(index);
|
|
||||||
setShift(shift);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name ARM Specific Features
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Gets offset mode.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR OffsetMode offsetMode() const noexcept { return OffsetMode(_signature.getField<kSignatureMemOffsetModeMask>()); }
|
|
||||||
//! Sets offset mode to `mode`.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setOffsetMode(OffsetMode mode) noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(mode)); }
|
|
||||||
//! Resets offset mode to default (fixed offset, without write-back).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void resetOffsetMode() noexcept { _signature.setField<kSignatureMemOffsetModeMask>(uint32_t(OffsetMode::kFixed)); }
|
|
||||||
|
|
||||||
//! Tests whether the current memory offset mode is fixed (see \ref OffsetMode::kFixed).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isFixedOffset() const noexcept { return offsetMode() == OffsetMode::kFixed; }
|
|
||||||
//! Tests whether the current memory offset mode is either pre-index or post-index (write-back is used).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isPreOrPost() const noexcept { return offsetMode() != OffsetMode::kFixed; }
|
|
||||||
//! Tests whether the current memory offset mode is pre-index (write-back is used).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isPreIndex() const noexcept { return offsetMode() == OffsetMode::kPreIndex; }
|
|
||||||
//! Tests whether the current memory offset mode is post-index (write-back is used).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool isPostIndex() const noexcept { return offsetMode() == OffsetMode::kPostIndex; }
|
|
||||||
|
|
||||||
//! Sets offset mode of this memory operand to pre-index (write-back is used).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void makePreIndex() noexcept { setOffsetMode(OffsetMode::kPreIndex); }
|
|
||||||
//! Sets offset mode of this memory operand to post-index (write-back is used).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void makePostIndex() noexcept { setOffsetMode(OffsetMode::kPostIndex); }
|
|
||||||
|
|
||||||
//! Gets shift operation that is used by index register.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR ShiftOp shiftOp() const noexcept { return ShiftOp(_signature.getField<kSignatureMemShiftOpMask>()); }
|
|
||||||
//! Sets shift operation that is used by index register.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setShiftOp(ShiftOp sop) noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(sop)); }
|
|
||||||
//! Resets shift operation that is used by index register to LSL (default value).
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void resetShiftOp() noexcept { _signature.setField<kSignatureMemShiftOpMask>(uint32_t(ShiftOp::kLSL)); }
|
|
||||||
|
|
||||||
//! Gets whether the memory operand has shift (aka scale) constant.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR bool hasShift() const noexcept { return _signature.hasField<kSignatureMemShiftValueMask>(); }
|
|
||||||
//! Gets the memory operand's shift (aka scale) constant.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR uint32_t shift() const noexcept { return _signature.getField<kSignatureMemShiftValueMask>(); }
|
|
||||||
//! Sets the memory operand's shift (aka scale) constant.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setShift(uint32_t shift) noexcept { _signature.setField<kSignatureMemShiftValueMask>(shift); }
|
|
||||||
|
|
||||||
//! Sets the memory operand's shift and shift operation.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void setShift(Shift shift) noexcept {
|
|
||||||
_signature.setField<kSignatureMemShiftOpMask>(uint32_t(shift.op()));
|
|
||||||
_signature.setField<kSignatureMemShiftValueMask>(shift.value());
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Resets the memory operand's shift (aka scale) constant to zero.
|
|
||||||
ASMJIT_INLINE_CONSTEXPR void resetShift() noexcept { _signature.setField<kSignatureMemShiftValueMask>(0); }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Shift Operation Construction
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Constructs a `LSL #value` shift (logical shift left).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
|
|
||||||
//! Constructs a `LSR #value` shift (logical shift right).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
|
|
||||||
//! Constructs a `ASR #value` shift (arithmetic shift right).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
|
|
||||||
//! Constructs a `ROR #value` shift (rotate right).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
|
|
||||||
//! Constructs a `RRX` shift (rotate with carry by 1).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift rrx() noexcept { return Shift(ShiftOp::kRRX, 0); }
|
|
||||||
//! Constructs a `MSL #value` shift (logical shift left filling ones).
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Shift msl(uint32_t value) noexcept { return Shift(ShiftOp::kMSL, value); }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Memory Operand Construction
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Creates `[base]` absolute memory operand (AArch32 or AArch64).
|
|
||||||
//!
|
|
||||||
//! \note The concept of absolute memory operands doesn't exist on ARM, the ISA only provides PC relative addressing.
|
|
||||||
//! Absolute memory operands can only be used if it's known that the PC relative offset is encodable and that it
|
|
||||||
//! would be within the limits. Absolute address is also often output from disassemblers, so AsmJit supports it to
|
|
||||||
//! make it possible to assemble such output back.
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR Mem ptr(uint64_t base) noexcept { return Mem(base); }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
ASMJIT_END_SUB_NAMESPACE
|
|
||||||
|
|
||||||
#endif // ASMJIT_ARM_ARMOPERAND_H_INCLUDED
|
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_ARM_ARMUTILS_H_INCLUDED
|
#ifndef ASMJIT_ARM_ARMUTILS_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
|
|||||||
@@ -24,7 +24,7 @@
|
|||||||
#ifndef ASMJIT_ASMJIT_H_INCLUDED
|
#ifndef ASMJIT_ASMJIT_H_INCLUDED
|
||||||
#define ASMJIT_ASMJIT_H_INCLUDED
|
#define ASMJIT_ASMJIT_H_INCLUDED
|
||||||
|
|
||||||
#pragma message("asmjit/asmjit.h is deprecated! Please use asmjit/core.h, asmjit/x86.h, or asmjit/a64.h")
|
#pragma message("asmjit/asmjit.h is deprecated! Please use asmjit/[core|x86|a64|host].h instead.")
|
||||||
|
|
||||||
#include "./core.h"
|
#include "./core.h"
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,26 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
// Official GitHub Repository: https://github.com/asmjit/asmjit
|
||||||
|
//
|
||||||
|
// Copyright (c) 2008-2025 The AsmJit Authors
|
||||||
|
//
|
||||||
|
// This software is provided 'as-is', without any express or implied
|
||||||
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
// arising from the use of this software.
|
||||||
|
//
|
||||||
|
// Permission is granted to anyone to use this software for any purpose,
|
||||||
|
// including commercial applications, and to alter it and redistribute it
|
||||||
|
// freely, subject to the following restrictions:
|
||||||
|
//
|
||||||
|
// 1. The origin of this software must not be misrepresented; you must not
|
||||||
|
// claim that you wrote the original software. If you use this software
|
||||||
|
// in a product, an acknowledgment in the product documentation would be
|
||||||
|
// appreciated but is not required.
|
||||||
|
// 2. Altered source versions must be plainly marked as such, and must not be
|
||||||
|
// misrepresented as being the original software.
|
||||||
|
// 3. This notice may not be removed or altered from any source distribution.
|
||||||
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_H_INCLUDED
|
#ifndef ASMJIT_CORE_H_INCLUDED
|
||||||
#define ASMJIT_CORE_H_INCLUDED
|
#define ASMJIT_CORE_H_INCLUDED
|
||||||
@@ -265,16 +284,83 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! Useful tips before you start:
|
//! Useful tips before you start:
|
||||||
//!
|
//!
|
||||||
//! - Visit our [Public Gitter Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) if you need a quick help.
|
//! - Visit our [Public Chat](https://app.gitter.im/#/room/#asmjit:gitter.im) if you need a quick help.
|
||||||
//!
|
//!
|
||||||
//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that you are not using deprecated
|
//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that you are not using deprecated
|
||||||
//! functionality at all. Deprecated functions are decorated with `[[deprecated]]` attribute, but sometimes
|
//! functionality at all. Deprecated functions are decorated with `[[deprecated]]` attribute, but sometimes
|
||||||
//! it's not possible to decorate everything like classes, which are used by deprecated functions as well,
|
//! it's not possible to decorate everything like classes, which are used by deprecated functions as well,
|
||||||
//! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED`
|
//! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED`
|
||||||
//! it's not using anything, which was deprecated.
|
//! it's not using anything, which will be definitely removed in the future.
|
||||||
//!
|
//!
|
||||||
//! \section api_changes API Changes
|
//! \section api_changes API Changes
|
||||||
//!
|
//!
|
||||||
|
//! ### Changes committed at 2025-06-15
|
||||||
|
//!
|
||||||
|
//! Core changes:
|
||||||
|
//!
|
||||||
|
//! - No more architecture specific \ref RegTraits - removed `BaseRegTraits` and kept just \ref RegTraits:
|
||||||
|
//!
|
||||||
|
//! - `BaseRegTraits` -> `RegTraits`
|
||||||
|
//! - `arm::RegTraits` -> `RegTraits`
|
||||||
|
//! - `x86::RegTraits` -> `RegTraits`
|
||||||
|
//!
|
||||||
|
//! - Removed register signature and helper functions from ArchTraits. This functionality is now available
|
||||||
|
//! via asmjit::RegTraits and asmjit::RegUtils and doesn't require a valid architecture traits instance.
|
||||||
|
//!
|
||||||
|
//! - No more architecture specific Gp/Vec/Mask register types in \ref RegType and \ref RegGroup:
|
||||||
|
//!
|
||||||
|
//! - `RegGroup::kX86_Rip` -> `RegGroup::kPC`
|
||||||
|
//! - `RegGroup::kX86_KReg` -> `RegGroup::kMask`
|
||||||
|
//! - `RegType::kX86_GpbLo` -> `RegType::kGp8Lo`
|
||||||
|
//! - `RegType::kX86_GpbLo` -> `RegType::kGp8Lo`
|
||||||
|
//! - `RegType::kX86_GpbHi` -> `RegType::kGp8Hi`
|
||||||
|
//! - `RegType::kX86_Gpw` -> `RegType::kGp16`
|
||||||
|
//! - `RegType::kX86_Gpd` -> `RegType::kGp32`
|
||||||
|
//! - `RegType::kX86_Gpq` -> `RegType::kGp64`
|
||||||
|
//! - `RegType::kX86_Xmm` -> `RegType::kVec128`
|
||||||
|
//! - `RegType::kX86_Ymm` -> `RegType::kVec256`
|
||||||
|
//! - `RegType::kX86_Zmm` -> `RegType::kVec512`
|
||||||
|
//! - `RegType::kX86_KReg` -> `RegType::kMask`
|
||||||
|
//! - `RegType::kARM_PC` -> `RegType::kPC`
|
||||||
|
//! - `RegType::kARM_GpW` -> `RegType::kGp32`
|
||||||
|
//! - `RegType::kARM_GpX` -> `RegType::kGp64`
|
||||||
|
//! - `RegType::kARM_VecB` -> `RegType::kVec8`
|
||||||
|
//! - `RegType::kARM_VecH` -> `RegType::kVec16`
|
||||||
|
//! - `RegType::kARM_VecS` -> `RegType::kVec32`
|
||||||
|
//! - `RegType::kARM_VecD` -> `RegType::kVec64`
|
||||||
|
//! - `RegType::kARM_VecQ` -> `RegType::kVec128`
|
||||||
|
//! - `RegType::kARM_VecV` -> `RegType::kVec128`
|
||||||
|
//!
|
||||||
|
//! - Renamed `asmjit::BaseReg` to asmjit::Reg, added `asmjit::UniGp` and `asmjit::UniVec` which are now base
|
||||||
|
//! classes for platform specific `[x86|a64]::Gp` and `[x86|a64]::Vec`
|
||||||
|
//!
|
||||||
|
//! - Renamed some member functions in Operand and Reg:
|
||||||
|
//!
|
||||||
|
//! - `isType(regId)` -> `isReg(regId)`
|
||||||
|
//! - `isGroup(regGroup)` -> `isReg(regGroup)`
|
||||||
|
//! - `regOp.type()` -> `regOp.regType()`
|
||||||
|
//! - `regOp.group()` -> `regOp.regGroup()`
|
||||||
|
//!
|
||||||
|
//! - Removed some static functions from \ref Operand, \reg Reg, etc... in favor of member functions. Most
|
||||||
|
//! of the operand functionality is now provided by \ref Operand_:
|
||||||
|
//!
|
||||||
|
//! - `Operand::isGp(op)` -> op.isGp();
|
||||||
|
//! - `x86::Reg::isGp(op, id)` -> op.isGp(id);
|
||||||
|
//!
|
||||||
|
//! - Removed sub-registers `x86::Gpb`, `x86::GpbLo`, `x86::GpbHi`, `x86::Gpw`, `x86::Gpd`, `x86::Gpq`, `x86::Xmm`,
|
||||||
|
//! `x86::Ymm`, `x86::Zmm` - use just `x86::Gp` and `x86::Vec`, which represent all removed X86 sub-registers.
|
||||||
|
//!
|
||||||
|
//! - Removed sub-registers `a64::GpW` and `a64::GpX`, `a64::VecB`, `a64::VecH`, `a64::VecS`, `a64::VecD`,
|
||||||
|
//! `a64::VecV`, which represent all removed AArch64 sub-registers.
|
||||||
|
//!
|
||||||
|
//! - Renamed some id getters - `Section::id()` -> `Section::sectionId()`, etc...
|
||||||
|
//!
|
||||||
|
//! Builder changes:
|
||||||
|
//!
|
||||||
|
//! - Removed BaseBuilder::deletePass() - this function was most likely never used by user code and it was also
|
||||||
|
//! never used by AsmJit. Passes should be only added and not removed, which simplifies some planned future
|
||||||
|
//! changes.
|
||||||
|
//!
|
||||||
//! ### Changes committed at 2025-05-24
|
//! ### Changes committed at 2025-05-24
|
||||||
//!
|
//!
|
||||||
//! Core changes:
|
//! Core changes:
|
||||||
@@ -534,12 +620,13 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! - \ref Section - stores information about a code or data section.
|
//! - \ref Section - stores information about a code or data section.
|
||||||
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
|
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
|
||||||
//! - \ref LabelEntry - stores information about a label - its name, offset, section where it belongs to, and
|
//! - \ref LabelEntry - stores information about a \ref Label - its name, offset, section where it belongs to,
|
||||||
//! other bits.
|
//! and other bits.
|
||||||
//! - \ref LabelLink - stores information about yet unbound label, which was already used by the assembler.
|
//! - \ref Fixup - stores information about positions in code that needs to be fixed up later, for example
|
||||||
|
//! when referencing a \ref Label, which was not bound to a position in code yet.
|
||||||
//! - \ref RelocEntry - stores information about a relocation.
|
//! - \ref RelocEntry - stores information about a relocation.
|
||||||
//! - \ref AddressTableEntry - stores information about an address, which was used in a jump or call. Such
|
//! - \ref AddressTableEntry - stores information about an absolute address, which was used in a jump or call.
|
||||||
//! address may need relocation.
|
//! Code referencing an absolute address may need relocation or a record in address table.
|
||||||
//!
|
//!
|
||||||
//! To generate code you would need to instantiate at least the following classes:
|
//! To generate code you would need to instantiate at least the following classes:
|
||||||
//!
|
//!
|
||||||
@@ -692,21 +779,21 @@ namespace asmjit {
|
|||||||
//! required if you call external functions from the generated code that cannot be encoded by using a 32-bit
|
//! required if you call external functions from the generated code that cannot be encoded by using a 32-bit
|
||||||
//! displacement (64-bit displacements are not provided by aby supported architecture).
|
//! displacement (64-bit displacements are not provided by aby supported architecture).
|
||||||
//!
|
//!
|
||||||
//! There is also a concept called \ref LabelLink - label link is a lightweight data structure that doesn't have any
|
//! There is also a concept called \ref Fixup - it's a lightweight data structure that doesn't have any identifier and
|
||||||
//! identifier and is stored in \ref LabelEntry as a single-linked list. Label link represents either unbound yet used
|
//! is stored in \ref LabelEntry and \ref CodeHolder as a single-linked list. Fixup represents either a reference to an
|
||||||
//! label and cross-sections links (only relevant to code that uses multiple sections). Since crossing sections is
|
//! unbound label and cross-sections references (only relevant to code that uses multiple sections). Since crossing
|
||||||
//! something that cannot be resolved immediately these links persist until offsets of these sections are assigned and
|
//! sections is something that cannot be resolved immediately these fixups persist until offsets of these sections are
|
||||||
//! until \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end up with code that has
|
//! assigned and until \ref CodeHolder::resolveCrossSectionFixups() is called. It's an error if you end up with code that
|
||||||
//! unresolved label links after flattening. You can verify it by calling \ref CodeHolder::hasUnresolvedLinks(), which
|
//! still has fixups after flattening. You can verify it by calling \ref CodeHolder::hasUnresolvedFixups(), which inspects
|
||||||
//! inspects the value returned by \ref CodeHolder::unresolvedLinkCount().
|
//! the value returned by \ref CodeHolder::unresolvedFixupCount().
|
||||||
//!
|
//!
|
||||||
//! AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects
|
//! AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects
|
||||||
//! its alignment. Use \ref CodeHolder::flatten() to do that. After the sections are flattened their offsets and
|
//! its alignment. Use \ref CodeHolder::flatten() to do that. After the sections are flattened their offsets and
|
||||||
//! virtual sizes are adjusted to respect each section's buffer size and alignment. The \ref
|
//! virtual sizes are adjusted to respect each section's buffer size and alignment. The \ref
|
||||||
//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating the code held by \ref CodeHolder.
|
//! CodeHolder::resolveCrossSectionFixups() function must be called before relocating the code held by \ref CodeHolder.
|
||||||
//! You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to
|
//! You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to
|
||||||
//! base) by your own algorithm. In that case \ref CodeHolder::flatten() should not be called, however,
|
//! base) by your own algorithm. In that case \ref CodeHolder::flatten() should not be called, however,
|
||||||
//! \ref CodeHolder::resolveUnresolvedLinks() should be.
|
//! \ref CodeHolder::resolveCrossSectionFixups() should be.
|
||||||
//!
|
//!
|
||||||
//! The example below shows how to use a built-in virtual memory allocator \ref JitAllocator instead of using \ref
|
//! The example below shows how to use a built-in virtual memory allocator \ref JitAllocator instead of using \ref
|
||||||
//! JitRuntime (just in case you want to use your own memory management) and how to relocate the generated code
|
//! JitRuntime (just in case you want to use your own memory management) and how to relocate the generated code
|
||||||
@@ -775,7 +862,7 @@ namespace asmjit {
|
|||||||
//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify
|
//! // such relocations. You can use `CodeHolder::hasAddressTable()` to verify
|
||||||
//! // whether the address table section does exist.
|
//! // whether the address table section does exist.
|
||||||
//! code.flatten();
|
//! code.flatten();
|
||||||
//! code.resolveUnresolvedLinks();
|
//! code.resolveCrossSectionFixups();
|
||||||
//!
|
//!
|
||||||
//! // After the code was generated it can be relocated manually to any memory
|
//! // After the code was generated it can be relocated manually to any memory
|
||||||
//! // location, however, we need to know it's size before we perform memory
|
//! // location, however, we need to know it's size before we perform memory
|
||||||
@@ -870,9 +957,9 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! \section labels Label Offsets and Links
|
//! \section labels Label Offsets and Links
|
||||||
//!
|
//!
|
||||||
//! When a label that is not yet bound is used by the Assembler, it creates a \ref LabelLink, which is then added to
|
//! When a label that is not yet bound is used by the Assembler, it creates a \ref Fixup, which is then referenced
|
||||||
//! a \ref LabelEntry. These links are also created if a label is used in a different section than in which it was
|
//! by \ref LabelEntry. Fixups are also created if a label is referenced in a different section than in which it was
|
||||||
//! bound. Let's examine some functions that can be used to check whether there are any unresolved links.
|
//! bound. Let's examine some functions that can be used to check whether there are any unresolved fixups.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! #include <asmjit/core.h>
|
//! #include <asmjit/core.h>
|
||||||
@@ -886,11 +973,11 @@ namespace asmjit {
|
|||||||
//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound");
|
//! printf("Label %u is %s\n", label.id(), isBound ? "bound" : "not bound");
|
||||||
//!
|
//!
|
||||||
//! // Returns true if the code contains either referenced, but unbound
|
//! // Returns true if the code contains either referenced, but unbound
|
||||||
//! // labels, or cross-section label links that are not resolved yet.
|
//! // labels, or cross-section fixups that are not resolved yet.
|
||||||
//! bool hasUnresolved = code.hasUnresolvedLinks(); // Boolean answer.
|
//! bool hasUnresolved = code.hasUnresolvedFixups(); // Boolean answer.
|
||||||
//! size_t nUnresolved = code.unresolvedLinkCount(); // Count of unresolved links.
|
//! size_t nUnresolved = code.unresolvedFixupCount(); // Count of unresolved fixups.
|
||||||
//!
|
//!
|
||||||
//! printf("Number of unresolved links: %zu\n", nUnresolved);
|
//! printf("Number of unresolved fixups: %zu\n", nUnresolved);
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@@ -963,17 +1050,16 @@ namespace asmjit {
|
|||||||
//! a.section(text); // Switches to the end of .text section.
|
//! a.section(text); // Switches to the end of .text section.
|
||||||
//! a.add(x86::ebx, x86::eax); // Emits in .text section.
|
//! a.add(x86::ebx, x86::eax); // Emits in .text section.
|
||||||
//!
|
//!
|
||||||
//! // References a label in .text section, which was bound in .data section.
|
//! // References a label in .text section, which was bound in .data section. This would create a
|
||||||
//! // This would create a LabelLink even when the L_Data is already bound,
|
//! // fixup even when the L_Data is already bound, because the reference crosses sections. See below...
|
||||||
//! // because the reference crosses sections. See below...
|
|
||||||
//! a.lea(x86::rsi, x86::ptr(L_Data));
|
//! a.lea(x86::rsi, x86::ptr(L_Data));
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! The last line in the example above shows that a LabelLink would be created even for bound labels that cross
|
//! The last line in the example above shows that a \ref Fixup would be created even for bound labels that cross
|
||||||
//! sections. In this case a referenced label was bound in another section, which means that the link couldn't be
|
//! sections. In this case a referenced label was bound in another section, which means that the reference couldn't
|
||||||
//! resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't
|
//! be resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't
|
||||||
//! plan to flatten them manually) then there is an API for that.
|
//! plan to flatten them manually) then there is a ready API for that.
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! #include <asmjit/x86.h>
|
//! #include <asmjit/x86.h>
|
||||||
@@ -998,18 +1084,18 @@ namespace asmjit {
|
|||||||
//! // guaranteed that the offset cannot be greater than `2^32 - 1`.
|
//! // guaranteed that the offset cannot be greater than `2^32 - 1`.
|
||||||
//! printf("Data section offset %zu", size_t(data->offset()));
|
//! printf("Data section offset %zu", size_t(data->offset()));
|
||||||
//!
|
//!
|
||||||
//! // The flattening doesn't resolve unresolved label links, this
|
//! // The flattening doesn't resolve unresolved fixups, this
|
||||||
//! // has to be done manually as flattening can be done separately.
|
//! // has to be done manually as flattening can be done separately.
|
||||||
//! err = code.resolveUnresolvedLinks();
|
//! err = code.resolveCrossSectionFixups();
|
||||||
//! if (err) {
|
//! if (err) {
|
||||||
//! // This is the kind of error that should always be handled...
|
//! // This is the kind of error that should always be handled...
|
||||||
//! printf("Failed to resolve label links: %s\n", DebugUtils::errorAsString(err));
|
//! printf("Failed to resolve fixups: %s\n", DebugUtils::errorAsString(err));
|
||||||
//! exit(1);
|
//! exit(1);
|
||||||
//! }
|
//! }
|
||||||
//!
|
//!
|
||||||
//! if (code.hasUnresolvedLinks()) {
|
//! if (code.hasUnresolvedFixups()) {
|
||||||
//! // This would mean either unbound label or some other issue.
|
//! // This would mean either unbound label or some other issue.
|
||||||
//! printf("The code has %zu unbound labels\n", code.unresolvedLinkCount());
|
//! printf("The code has %zu unbound labels\n", code.unresolvedFixupCount());
|
||||||
//! exit(1);
|
//! exit(1);
|
||||||
//! }
|
//! }
|
||||||
//! }
|
//! }
|
||||||
@@ -1108,7 +1194,7 @@ namespace asmjit {
|
|||||||
//! // Constructs [src + idx] memory address - referencing [rax + r10].
|
//! // Constructs [src + idx] memory address - referencing [rax + r10].
|
||||||
//! x86::Mem m = x86::ptr(src, idx);
|
//! x86::Mem m = x86::ptr(src, idx);
|
||||||
//!
|
//!
|
||||||
//! // Examine `m`: Returns `RegType::kX86_Gpq`.
|
//! // Examine `m`: Returns `RegType::kGp64`.
|
||||||
//! m.indexType();
|
//! m.indexType();
|
||||||
//! // Examine `m`: Returns 10 (`r10`).
|
//! // Examine `m`: Returns 10 (`r10`).
|
||||||
//! m.indexId();
|
//! m.indexId();
|
||||||
@@ -1882,9 +1968,6 @@ namespace asmjit {
|
|||||||
//! using namespace asmjit;
|
//! using namespace asmjit;
|
||||||
//!
|
//!
|
||||||
//! void example(CodeHolder& code) {
|
//! void example(CodeHolder& code) {
|
||||||
//! // Contains all emitters attached to CodeHolder.
|
|
||||||
//! const ZoneVector<BaseEmitter*>& emitters = code.emitters();
|
|
||||||
//!
|
|
||||||
//! // Contains all section entries managed by CodeHolder.
|
//! // Contains all section entries managed by CodeHolder.
|
||||||
//! const ZoneVector<Section*>& sections = code.sections();
|
//! const ZoneVector<Section*>& sections = code.sections();
|
||||||
//!
|
//!
|
||||||
@@ -2005,7 +2088,6 @@ namespace asmjit {
|
|||||||
//! \defgroup asmjit_a64 AArch64 Backend
|
//! \defgroup asmjit_a64 AArch64 Backend
|
||||||
//! \brief AArch64 backend.
|
//! \brief AArch64 backend.
|
||||||
|
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! \defgroup asmjit_ra RA
|
//! \defgroup asmjit_ra RA
|
||||||
//! \brief Register allocator internals.
|
//! \brief Register allocator internals.
|
||||||
@@ -2017,6 +2099,7 @@ namespace asmjit {
|
|||||||
#include "core/archtraits.h"
|
#include "core/archtraits.h"
|
||||||
#include "core/assembler.h"
|
#include "core/assembler.h"
|
||||||
#include "core/builder.h"
|
#include "core/builder.h"
|
||||||
|
#include "core/codebuffer.h"
|
||||||
#include "core/codeholder.h"
|
#include "core/codeholder.h"
|
||||||
#include "core/compiler.h"
|
#include "core/compiler.h"
|
||||||
#include "core/constpool.h"
|
#include "core/constpool.h"
|
||||||
@@ -2024,6 +2107,7 @@ namespace asmjit {
|
|||||||
#include "core/emitter.h"
|
#include "core/emitter.h"
|
||||||
#include "core/environment.h"
|
#include "core/environment.h"
|
||||||
#include "core/errorhandler.h"
|
#include "core/errorhandler.h"
|
||||||
|
#include "core/fixup.h"
|
||||||
#include "core/formatter.h"
|
#include "core/formatter.h"
|
||||||
#include "core/func.h"
|
#include "core/func.h"
|
||||||
#include "core/globals.h"
|
#include "core/globals.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
||||||
@@ -16,7 +16,7 @@
|
|||||||
#define ASMJIT_LIBRARY_MAKE_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
#define ASMJIT_LIBRARY_MAKE_VERSION(major, minor, patch) ((major << 16) | (minor << 8) | (patch))
|
||||||
|
|
||||||
//! AsmJit library version, see \ref ASMJIT_LIBRARY_MAKE_VERSION for a version format reference.
|
//! AsmJit library version, see \ref ASMJIT_LIBRARY_MAKE_VERSION for a version format reference.
|
||||||
#define ASMJIT_LIBRARY_VERSION ASMJIT_LIBRARY_MAKE_VERSION(1, 16, 0)
|
#define ASMJIT_LIBRARY_VERSION ASMJIT_LIBRARY_MAKE_VERSION(1, 17, 0)
|
||||||
|
|
||||||
//! \def ASMJIT_ABI_NAMESPACE
|
//! \def ASMJIT_ABI_NAMESPACE
|
||||||
//!
|
//!
|
||||||
@@ -27,7 +27,7 @@
|
|||||||
//! AsmJit default, which makes it possible to use multiple AsmJit libraries within a single project, totally
|
//! AsmJit default, which makes it possible to use multiple AsmJit libraries within a single project, totally
|
||||||
//! controlled by users. This is useful especially in cases in which some of such library comes from third party.
|
//! controlled by users. This is useful especially in cases in which some of such library comes from third party.
|
||||||
#if !defined(ASMJIT_ABI_NAMESPACE)
|
#if !defined(ASMJIT_ABI_NAMESPACE)
|
||||||
#define ASMJIT_ABI_NAMESPACE v1_16
|
#define ASMJIT_ABI_NAMESPACE v1_17
|
||||||
#endif // !ASMJIT_ABI_NAMESPACE
|
#endif // !ASMJIT_ABI_NAMESPACE
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -78,23 +78,20 @@ namespace asmjit {
|
|||||||
//! \note Can be defined explicitly to bypass auto-detection.
|
//! \note Can be defined explicitly to bypass auto-detection.
|
||||||
#define ASMJIT_BUILD_RELEASE
|
#define ASMJIT_BUILD_RELEASE
|
||||||
|
|
||||||
|
//! Disables deprecated API at compile time (deprecated API won't be available).
|
||||||
|
#define ASMJIT_NO_DEPRECATED
|
||||||
|
|
||||||
|
//! Disables the use of an inline ABI namespace within asmjit namespace (the inline namespace is used as an ABI tag).
|
||||||
|
#define ASMJIT_NO_ABI_NAMESPACE
|
||||||
|
|
||||||
//! Disables X86/X64 backends.
|
//! Disables X86/X64 backends.
|
||||||
#define ASMJIT_NO_X86
|
#define ASMJIT_NO_X86
|
||||||
|
|
||||||
//! Disables AArch64 backend.
|
//! Disables AArch64 backend.
|
||||||
#define ASMJIT_NO_AARCH64
|
#define ASMJIT_NO_AARCH64
|
||||||
|
|
||||||
//! Disables non-host backends entirely (useful for JIT compilers to minimize the library size).
|
//! Disables the use of `shm_open` on all targets even when it's supported.
|
||||||
#define ASMJIT_NO_FOREIGN
|
#define ASMJIT_NO_SHM_OPEN
|
||||||
|
|
||||||
//! Disables deprecated API at compile time (deprecated API won't be available).
|
|
||||||
#define ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
//! Disables \ref asmjit_builder functionality completely.
|
|
||||||
#define ASMJIT_NO_BUILDER
|
|
||||||
|
|
||||||
//! Disables \ref asmjit_compiler functionality completely.
|
|
||||||
#define ASMJIT_NO_COMPILER
|
|
||||||
|
|
||||||
//! Disables JIT memory management and \ref asmjit::JitRuntime.
|
//! Disables JIT memory management and \ref asmjit::JitRuntime.
|
||||||
#define ASMJIT_NO_JIT
|
#define ASMJIT_NO_JIT
|
||||||
@@ -111,21 +108,36 @@ namespace asmjit {
|
|||||||
//! Disables instruction introspection API.
|
//! Disables instruction introspection API.
|
||||||
#define ASMJIT_NO_INTROSPECTION
|
#define ASMJIT_NO_INTROSPECTION
|
||||||
|
|
||||||
|
//! Disables non-host backends entirely (useful for JIT compilers to minimize the library size).
|
||||||
|
#define ASMJIT_NO_FOREIGN
|
||||||
|
|
||||||
|
//! Disables \ref asmjit_builder functionality completely.
|
||||||
|
#define ASMJIT_NO_BUILDER
|
||||||
|
|
||||||
|
//! Disables \ref asmjit_compiler functionality completely.
|
||||||
|
#define ASMJIT_NO_COMPILER
|
||||||
|
|
||||||
// Avoid doxygen preprocessor using feature-selection definitions.
|
// Avoid doxygen preprocessor using feature-selection definitions.
|
||||||
#undef ASMJIT_BUILD_EMBED
|
#undef ASMJIT_BUILD_EMBED
|
||||||
#undef ASMJIT_BUILD_STATIC
|
#undef ASMJIT_BUILD_STATIC
|
||||||
#undef ASMJIT_BUILD_DEBUG
|
#undef ASMJIT_BUILD_DEBUG
|
||||||
#undef ASMJIT_BUILD_RELEASE
|
#undef ASMJIT_BUILD_RELEASE
|
||||||
#undef ASMJIT_NO_X86
|
|
||||||
#undef ASMJIT_NO_FOREIGN
|
|
||||||
// (keep ASMJIT_NO_DEPRECATED defined, we don't document deprecated APIs).
|
// (keep ASMJIT_NO_DEPRECATED defined, we don't document deprecated APIs).
|
||||||
#undef ASMJIT_NO_BUILDER
|
#undef ASMJIT_NO_ABI_NAMESPACE
|
||||||
#undef ASMJIT_NO_COMPILER
|
|
||||||
|
#undef ASMJIT_NO_X86
|
||||||
|
#undef ASMJIT_NO_AARCH64
|
||||||
|
#undef ASMJIT_NO_FOREIGN
|
||||||
|
|
||||||
#undef ASMJIT_NO_JIT
|
#undef ASMJIT_NO_JIT
|
||||||
#undef ASMJIT_NO_LOGGING
|
#undef ASMJIT_NO_LOGGING
|
||||||
#undef ASMJIT_NO_TEXT
|
#undef ASMJIT_NO_TEXT
|
||||||
#undef ASMJIT_NO_VALIDATION
|
#undef ASMJIT_NO_VALIDATION
|
||||||
#undef ASMJIT_NO_INTROSPECTION
|
#undef ASMJIT_NO_INTROSPECTION
|
||||||
|
#undef ASMJIT_NO_BUILDER
|
||||||
|
#undef ASMJIT_NO_COMPILER
|
||||||
|
#undef ASMJIT_NO_UJIT
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -137,6 +149,11 @@ namespace asmjit {
|
|||||||
#define ASMJIT_NO_COMPILER
|
#define ASMJIT_NO_COMPILER
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
// ASMJIT_NO_COMPILER implies ASMJIT_NO_UJIT.
|
||||||
|
#if defined(ASMJIT_NO_COMPILER) && !defined(ASMJIT_NO_UJIT)
|
||||||
|
#define ASMJIT_NO_UJIT
|
||||||
|
#endif
|
||||||
|
|
||||||
// Prevent compile-time errors caused by misconfiguration.
|
// Prevent compile-time errors caused by misconfiguration.
|
||||||
#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING)
|
#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING)
|
||||||
#pragma message("'ASMJIT_NO_TEXT' can only be defined when 'ASMJIT_NO_LOGGING' is defined.")
|
#pragma message("'ASMJIT_NO_TEXT' can only be defined when 'ASMJIT_NO_LOGGING' is defined.")
|
||||||
@@ -194,6 +211,13 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! Defined to 1 if the target architecture is big endian.
|
//! Defined to 1 if the target architecture is big endian.
|
||||||
|
|
||||||
|
//! \def ASMJIT_HAS_HOST_BACKEND
|
||||||
|
//!
|
||||||
|
//! Defined when AsmJit is built with the target architecture backend.
|
||||||
|
//!
|
||||||
|
//! For example if AsmJit is building for x86 or x86_64 architectures and `ASMJIT_NO_X86` is not defined,
|
||||||
|
//! it would define `ASMJIT_HAS_HOST_BACKEND` when `<asmjit/code.h>` or ``<asmjit/host.h>` is included.
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \cond NONE
|
//! \cond NONE
|
||||||
@@ -259,6 +283,24 @@ namespace asmjit {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if ASMJIT_ARCH_X86 != 0 && !defined(ASMJIT_NO_X86)
|
||||||
|
#define ASMJIT_HAS_HOST_BACKEND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if ASMJIT_ARCH_ARM == 64 && !defined(ASMJIT_NO_AARCH64)
|
||||||
|
#define ASMJIT_HAS_HOST_BACKEND
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ASMJIT_NO_UJIT)
|
||||||
|
#if !defined(ASMJIT_NO_X86) && ASMJIT_ARCH_X86 != 0
|
||||||
|
#define ASMJIT_UJIT_X86
|
||||||
|
#elif !defined(ASMJIT_NO_AARCH64) && ASMJIT_ARCH_ARM == 64
|
||||||
|
#define ASMJIT_UJIT_AARCH64
|
||||||
|
#else
|
||||||
|
#define ASMJIT_NO_UJIT
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
// C++ Compiler and Features Detection
|
// C++ Compiler and Features Detection
|
||||||
@@ -424,11 +466,11 @@ namespace asmjit {
|
|||||||
|
|
||||||
// Type alignment (not allowed by C++17 'alignas' keyword).
|
// Type alignment (not allowed by C++17 'alignas' keyword).
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
#define ASMJIT_ALIGN_TYPE(TYPE, N) __attribute__((__aligned__(N))) TYPE
|
#define ASMJIT_ALIGN_TYPE(N, ...) __attribute__((__aligned__(N))) __VA_ARGS__
|
||||||
#elif defined(_MSC_VER)
|
#elif defined(_MSC_VER)
|
||||||
#define ASMJIT_ALIGN_TYPE(TYPE, N) __declspec(align(N)) TYPE
|
#define ASMJIT_ALIGN_TYPE(N, ...) __declspec(align(N)) __VA_ARGS__
|
||||||
#else
|
#else
|
||||||
#define ASMJIT_ALIGN_TYPE(TYPE, N) TYPE
|
#define ASMJIT_ALIGN_TYPE(N, ...) __VA_ARGS__
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//! \def ASMJIT_MAY_ALIAS
|
//! \def ASMJIT_MAY_ALIAS
|
||||||
@@ -600,4 +642,56 @@ namespace asmjit {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//! Defines a strong type `C` that wraps a value of `T`.
|
||||||
|
#define ASMJIT_DEFINE_STRONG_TYPE(C, T) \
|
||||||
|
struct C { \
|
||||||
|
T v; \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_NODEBUG C() = default; \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR explicit C(T x) noexcept : v(x) {} \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C(const C& other) noexcept = default; \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR T value() const noexcept { return v; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR T* valuePtr() noexcept { return &v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR const T* valuePtr() const noexcept { return &v; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator=(T x) noexcept { v = x; return *this; }; \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator=(const C& x) noexcept { v = x.v; return *this; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator+(T x) const noexcept { return C(v + x); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator-(T x) const noexcept { return C(v - x); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator*(T x) const noexcept { return C(v * x); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator/(T x) const noexcept { return C(v / x); } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator+(const C& x) const noexcept { return C(v + x.v); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator-(const C& x) const noexcept { return C(v - x.v); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator*(const C& x) const noexcept { return C(v * x.v); } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C operator/(const C& x) const noexcept { return C(v / x.v); } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator+=(T x) noexcept { v += x; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator-=(T x) noexcept { v -= x; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator*=(T x) noexcept { v *= x; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator/=(T x) noexcept { v /= x; return *this; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator+=(const C& x) noexcept { v += x.v; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator-=(const C& x) noexcept { v -= x.v; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator*=(const C& x) noexcept { v *= x.v; return *this; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR C& operator/=(const C& x) noexcept { v /= x.v; return *this; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator==(T x) const noexcept { return v == x; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator!=(T x) const noexcept { return v != x; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator> (T x) const noexcept { return v > x; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator>=(T x) const noexcept { return v >= x; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator< (T x) const noexcept { return v < x; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator<=(T x) const noexcept { return v <= x; } \
|
||||||
|
\
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator==(const C& x) const noexcept { return v == x.v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator!=(const C& x) const noexcept { return v != x.v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator> (const C& x) const noexcept { return v > x.v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator>=(const C& x) const noexcept { return v >= x.v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator< (const C& x) const noexcept { return v < x.v; } \
|
||||||
|
ASMJIT_INLINE_CONSTEXPR bool operator<=(const C& x) const noexcept { return v <= x.v; } \
|
||||||
|
};
|
||||||
|
|
||||||
#endif // ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
#endif // ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -20,18 +20,21 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
static const constexpr ArchTraits noArchTraits = {
|
static const constexpr ArchTraits noArchTraits = {
|
||||||
// SP/FP/LR/PC.
|
// SP/FP/LR/PC.
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0xFFu, 0xFFu, 0xFFu, 0xFFu,
|
||||||
|
|
||||||
// Reserved,
|
// Reserved,
|
||||||
{ 0, 0, 0 },
|
{ 0u, 0u, 0u },
|
||||||
|
|
||||||
// HW stack alignment.
|
// HW stack alignment.
|
||||||
0,
|
0u,
|
||||||
|
|
||||||
// Min/Max stack offset.
|
// Min/Max stack offset.
|
||||||
0, 0,
|
0, 0,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// Supported register types.
|
||||||
|
0u,
|
||||||
|
|
||||||
|
// ISA features [Gp, Vec, Mask, Extra].
|
||||||
{{
|
{{
|
||||||
InstHints::kNoHints,
|
InstHints::kNoHints,
|
||||||
InstHints::kNoHints,
|
InstHints::kNoHints,
|
||||||
@@ -39,16 +42,6 @@ static const constexpr ArchTraits noArchTraits = {
|
|||||||
InstHints::kNoHints
|
InstHints::kNoHints
|
||||||
}},
|
}},
|
||||||
|
|
||||||
// RegTypeToSignature.
|
|
||||||
#define V(index) OperandSignature{0}
|
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
|
||||||
#undef V
|
|
||||||
|
|
||||||
// RegTypeToTypeId.
|
|
||||||
#define V(index) TypeId::kVoid
|
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
|
||||||
#undef V
|
|
||||||
|
|
||||||
// TypeIdToRegType.
|
// TypeIdToRegType.
|
||||||
#define V(index) RegType::kNone
|
#define V(index) RegType::kNone
|
||||||
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
@@ -107,7 +100,7 @@ ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegSignature(Arch arch, TypeId typeId
|
|||||||
// TODO: Remove this, should never be used like this.
|
// TODO: Remove this, should never be used like this.
|
||||||
// Passed RegType instead of TypeId?
|
// Passed RegType instead of TypeId?
|
||||||
if (uint32_t(typeId) <= uint32_t(RegType::kMaxValue)) {
|
if (uint32_t(typeId) <= uint32_t(RegType::kMaxValue)) {
|
||||||
typeId = archTraits.regTypeToTypeId(RegType(uint32_t(typeId)));
|
typeId = RegUtils::typeIdOf(RegType(uint32_t(typeId)));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!TypeUtils::isValid(typeId))) {
|
if (ASMJIT_UNLIKELY(!TypeUtils::isValid(typeId))) {
|
||||||
@@ -149,16 +142,16 @@ ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegSignature(Arch arch, TypeId typeId
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (size <= 8 && archTraits._regSignature[RegType::kVec64].isValid()) {
|
if (size <= 8 && archTraits.hasRegType(RegType::kVec64)) {
|
||||||
regType = RegType::kVec64;
|
regType = RegType::kVec64;
|
||||||
}
|
}
|
||||||
else if (size <= 16 && archTraits._regSignature[RegType::kVec128].isValid()) {
|
else if (size <= 16 && archTraits.hasRegType(RegType::kVec128)) {
|
||||||
regType = RegType::kVec128;
|
regType = RegType::kVec128;
|
||||||
}
|
}
|
||||||
else if (size == 32 && archTraits._regSignature[RegType::kVec256].isValid()) {
|
else if (size == 32 && archTraits.hasRegType(RegType::kVec256)) {
|
||||||
regType = RegType::kVec256;
|
regType = RegType::kVec256;
|
||||||
}
|
}
|
||||||
else if (archTraits._regSignature[RegType::kVec512].isValid()) {
|
else if (archTraits.hasRegType(RegType::kVec512)) {
|
||||||
regType = RegType::kVec512;
|
regType = RegType::kVec512;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -167,7 +160,7 @@ ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegSignature(Arch arch, TypeId typeId
|
|||||||
}
|
}
|
||||||
|
|
||||||
*typeIdOut = typeId;
|
*typeIdOut = typeId;
|
||||||
*regSignatureOut = archTraits.regTypeToSignature(regType);
|
*regSignatureOut = RegUtils::signatureOf(regType);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
||||||
@@ -110,13 +110,13 @@ enum class SubArch : uint8_t {
|
|||||||
|
|
||||||
//! Identifier used to represent names of different data types across architectures.
|
//! Identifier used to represent names of different data types across architectures.
|
||||||
enum class ArchTypeNameId : uint8_t {
|
enum class ArchTypeNameId : uint8_t {
|
||||||
//! Describes 'db' (X86/X86_64 convention, always 8-bit quantity).
|
//! Describes 'db' (X86|X86_64 convention, always 8-bit quantity).
|
||||||
kDB = 0,
|
kDB = 0,
|
||||||
//! Describes 'dw' (X86/X86_64 convention, always 16-bit word).
|
//! Describes 'dw' (X86|X86_64 convention, always 16-bit word).
|
||||||
kDW,
|
kDW,
|
||||||
//! Describes 'dd' (X86/X86_64 convention, always 32-bit word).
|
//! Describes 'dd' (X86|X86_64 convention, always 32-bit word).
|
||||||
kDD,
|
kDD,
|
||||||
//! Describes 'dq' (X86/X86_64 convention, always 64-bit word).
|
//! Describes 'dq' (X86|X86_64 convention, always 64-bit word).
|
||||||
kDQ,
|
kDQ,
|
||||||
//! Describes 'byte' (always 8-bit quantity).
|
//! Describes 'byte' (always 8-bit quantity).
|
||||||
kByte,
|
kByte,
|
||||||
@@ -174,7 +174,7 @@ struct ArchTraits {
|
|||||||
//! Link register id.
|
//! Link register id.
|
||||||
uint8_t _linkRegId;
|
uint8_t _linkRegId;
|
||||||
//! Instruction pointer (or program counter) register id, if accessible.
|
//! Instruction pointer (or program counter) register id, if accessible.
|
||||||
uint8_t _ipRegId;
|
uint8_t _pcRegId;
|
||||||
|
|
||||||
// Reserved.
|
// Reserved.
|
||||||
uint8_t _reserved[3];
|
uint8_t _reserved[3];
|
||||||
@@ -186,13 +186,12 @@ struct ArchTraits {
|
|||||||
//! Maximum addressable offset on stack depending on specific instruction.
|
//! Maximum addressable offset on stack depending on specific instruction.
|
||||||
uint32_t _maxStackOffset;
|
uint32_t _maxStackOffset;
|
||||||
|
|
||||||
|
//! Bit-mask indexed by \ref RegType that describes, which register types are supported by the ISA.
|
||||||
|
uint32_t _supportedRegTypes;
|
||||||
|
|
||||||
//! Flags for each virtual register group.
|
//! Flags for each virtual register group.
|
||||||
Support::Array<InstHints, Globals::kNumVirtGroups> _instHints;
|
Support::Array<InstHints, Globals::kNumVirtGroups> _instHints;
|
||||||
|
|
||||||
//! Maps register type into a signature, that provides group, size and can be used to construct register operands.
|
|
||||||
Support::Array<OperandSignature, uint32_t(RegType::kMaxValue) + 1> _regSignature;
|
|
||||||
//! Maps a register to type-id, see \ref TypeId.
|
|
||||||
Support::Array<TypeId, uint32_t(RegType::kMaxValue) + 1> _regTypeToTypeId;
|
|
||||||
//! Maps scalar TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref TypeId.
|
//! Maps scalar TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref TypeId.
|
||||||
Support::Array<RegType, 32> _typeIdToRegType;
|
Support::Array<RegType, 32> _typeIdToRegType;
|
||||||
|
|
||||||
@@ -204,21 +203,21 @@ struct ArchTraits {
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns stack pointer register id.
|
//! Returns stack pointer register id (always GP register).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t spRegId() const noexcept { return _spRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t spRegId() const noexcept { return _spRegId; }
|
||||||
|
|
||||||
//! Returns stack frame register id.
|
//! Returns stack frame register id (always GP register).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t fpRegId() const noexcept { return _fpRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t fpRegId() const noexcept { return _fpRegId; }
|
||||||
|
|
||||||
//! Returns link register id, if the architecture provides it.
|
//! Returns link register id, if the architecture provides it (always GP register).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t linkRegId() const noexcept { return _linkRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t linkRegId() const noexcept { return _linkRegId; }
|
||||||
|
|
||||||
//! Returns instruction pointer register id, if the architecture provides it.
|
//! Returns program counter register id, if the architecture exposes it (always GP register).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t ipRegId() const noexcept { return _ipRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t pcRegId() const noexcept { return _pcRegId; }
|
||||||
|
|
||||||
//! Returns a hardware stack alignment requirement.
|
//! Returns a hardware stack alignment requirement.
|
||||||
//!
|
//!
|
||||||
@@ -230,7 +229,7 @@ struct ArchTraits {
|
|||||||
//! Tests whether the architecture provides link register, which is used across function calls. If the link
|
//! Tests whether the architecture provides link register, which is used across function calls. If the link
|
||||||
//! register is not provided then a function call pushes the return address on stack (X86/X64).
|
//! register is not provided then a function call pushes the return address on stack (X86/X64).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG bool hasLinkReg() const noexcept { return _linkRegId != Reg::kIdBad; }
|
||||||
|
|
||||||
//! Returns minimum addressable offset on stack guaranteed for all instructions.
|
//! Returns minimum addressable offset on stack guaranteed for all instructions.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -258,24 +257,11 @@ struct ArchTraits {
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasRegType(RegType type) const noexcept {
|
ASMJIT_INLINE_NODEBUG bool hasRegType(RegType type) const noexcept {
|
||||||
return type <= RegType::kMaxValue && _regSignature[type].isValid();
|
if (ASMJIT_UNLIKELY(type > RegType::kMaxValue)) {
|
||||||
|
type = RegType::kNone;
|
||||||
|
}
|
||||||
|
return Support::bitTest(_supportedRegTypes, uint32_t(type));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns an operand signature from the given register `type` of this architecture.
|
|
||||||
[[nodiscard]]
|
|
||||||
ASMJIT_INLINE_NODEBUG OperandSignature regTypeToSignature(RegType type) const noexcept { return _regSignature[type]; }
|
|
||||||
|
|
||||||
//! Returns a register from the given register `type` of this architecture.
|
|
||||||
[[nodiscard]]
|
|
||||||
ASMJIT_INLINE_NODEBUG RegGroup regTypeToGroup(RegType type) const noexcept { return _regSignature[type].regGroup(); }
|
|
||||||
|
|
||||||
//! Returns a register size the given register `type` of this architecture.
|
|
||||||
[[nodiscard]]
|
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t regTypeToSize(RegType type) const noexcept { return _regSignature[type].size(); }
|
|
||||||
|
|
||||||
//! Returns a corresponding `TypeId` from the given register `type` of this architecture.
|
|
||||||
[[nodiscard]]
|
|
||||||
ASMJIT_INLINE_NODEBUG TypeId regTypeToTypeId(RegType type) const noexcept { return _regTypeToTypeId[type]; }
|
|
||||||
|
|
||||||
//! Returns a table of ISA word names that appear in formatted text. Word names are ISA dependent.
|
//! Returns a table of ISA word names that appear in formatted text. Word names are ISA dependent.
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -42,13 +42,15 @@ Error BaseAssembler::setOffset(size_t offset) {
|
|||||||
// BaseAssembler - Section Management
|
// BaseAssembler - Section Management
|
||||||
// ==================================
|
// ==================================
|
||||||
|
|
||||||
static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
|
static ASMJIT_INLINE Error BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
|
||||||
uint8_t* p = section->_buffer._data;
|
uint8_t* p = section->_buffer._data;
|
||||||
|
|
||||||
self->_section = section;
|
self->_section = section;
|
||||||
self->_bufferData = p;
|
self->_bufferData = p;
|
||||||
self->_bufferPtr = p + section->_buffer._size;
|
self->_bufferPtr = p + section->_buffer._size;
|
||||||
self->_bufferEnd = p + section->_buffer._capacity;
|
self->_bufferEnd = p + section->_buffer._capacity;
|
||||||
|
|
||||||
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseAssembler::section(Section* section) {
|
Error BaseAssembler::section(Section* section) {
|
||||||
@@ -56,51 +58,50 @@ Error BaseAssembler::section(Section* section) {
|
|||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_code->isSectionValid(section->id()) || _code->_sections[section->id()] != section) {
|
if (!_code->isSectionValid(section->sectionId()) || _code->_sections[section->sectionId()] != section) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidSection));
|
return reportError(DebugUtils::errored(kErrorInvalidSection));
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger) {
|
if (_logger) {
|
||||||
_logger->logf(".section %s {#%u}\n", section->name(), section->id());
|
_logger->logf(".section %s {#%u}\n", section->name(), section->sectionId());
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
BaseAssembler_initSection(this, section);
|
return BaseAssembler_initSection(this, section);
|
||||||
return kErrorOk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// BaseAssembler - Label Management
|
// BaseAssembler - Label Management
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
Label BaseAssembler::newLabel() {
|
Label BaseAssembler::newLabel() {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
Label label;
|
||||||
|
|
||||||
if (ASMJIT_LIKELY(_code)) {
|
if (ASMJIT_LIKELY(_code)) {
|
||||||
LabelEntry* le;
|
Error err = _code->newLabelId(&label._baseId);
|
||||||
Error err = _code->newLabelEntry(&le);
|
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
reportError(err);
|
reportError(err);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
labelId = le->id();
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return Label(labelId);
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
Label label;
|
||||||
|
|
||||||
if (ASMJIT_LIKELY(_code)) {
|
if (ASMJIT_LIKELY(_code)) {
|
||||||
LabelEntry* le;
|
uint32_t labelId;
|
||||||
Error err = _code->newNamedLabelEntry(&le, name, nameSize, type, parentId);
|
Error err = _code->newNamedLabelId(&labelId, name, nameSize, type, parentId);
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
reportError(err);
|
reportError(err);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
labelId = le->id();
|
label.setId(labelId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Label(labelId);
|
|
||||||
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseAssembler::bind(const Label& label) {
|
Error BaseAssembler::bind(const Label& label) {
|
||||||
@@ -108,7 +109,7 @@ Error BaseAssembler::bind(const Label& label) {
|
|||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error err = _code->bindLabel(label, _section->id(), offset());
|
Error err = _code->bindLabel(label, _section->sectionId(), offset());
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger) {
|
if (_logger) {
|
||||||
@@ -258,19 +259,18 @@ Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
|
|||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_ASSERT(_code != nullptr);
|
if (ASMJIT_UNLIKELY(isLabelValid(label))) {
|
||||||
RelocEntry* re;
|
|
||||||
LabelEntry* le = _code->labelEntry(label);
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!le)) {
|
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
RelocEntry* re;
|
||||||
|
LabelEntry& le = _code->labelEntry(label);
|
||||||
|
|
||||||
if (dataSize == 0) {
|
if (dataSize == 0) {
|
||||||
dataSize = registerSize();
|
dataSize = registerSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) {
|
if (ASMJIT_UNLIKELY(!Support::isPowerOf2UpTo(dataSize, 8u))) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
|
return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -294,24 +294,24 @@ Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
|
|||||||
return reportError(err);
|
return reportError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
re->_sourceSectionId = _section->id();
|
re->_sourceSectionId = _section->sectionId();
|
||||||
re->_sourceOffset = offset();
|
re->_sourceOffset = offset();
|
||||||
re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, dataSize);
|
re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, dataSize);
|
||||||
|
|
||||||
if (le->isBound()) {
|
if (le.isBound()) {
|
||||||
re->_targetSectionId = le->section()->id();
|
re->_targetSectionId = le.sectionId();
|
||||||
re->_payload = le->offset();
|
re->_payload = le.offset();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
OffsetFormat of;
|
OffsetFormat of;
|
||||||
of.resetToSimpleValue(OffsetType::kUnsignedOffset, dataSize);
|
of.resetToSimpleValue(OffsetType::kUnsignedOffset, dataSize);
|
||||||
|
|
||||||
LabelLink* link = _code->newLabelLink(le, _section->id(), offset(), 0, of);
|
Fixup* fixup = _code->newFixup(&le, _section->sectionId(), offset(), 0, of);
|
||||||
if (ASMJIT_UNLIKELY(!link)) {
|
if (ASMJIT_UNLIKELY(!fixup)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
link->relocId = re->id();
|
fixup->labelOrRelocId = re->id();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emit dummy DWORD/QWORD depending on the data size.
|
// Emit dummy DWORD/QWORD depending on the data size.
|
||||||
@@ -326,18 +326,18 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelEntry* labelEntry = _code->labelEntry(label);
|
if (ASMJIT_UNLIKELY(!Support::bool_and(_code->isLabelValid(label), _code->isLabelValid(base)))) {
|
||||||
LabelEntry* baseEntry = _code->labelEntry(base);
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!labelEntry || !baseEntry)) {
|
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LabelEntry& labelEntry = _code->labelEntry(label);
|
||||||
|
LabelEntry& baseEntry = _code->labelEntry(base);
|
||||||
|
|
||||||
if (dataSize == 0) {
|
if (dataSize == 0) {
|
||||||
dataSize = registerSize();
|
dataSize = registerSize();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Support::isPowerOf2(dataSize) || dataSize > 8)) {
|
if (ASMJIT_UNLIKELY(!Support::isPowerOf2UpTo(dataSize, 8u))) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
|
return reportError(DebugUtils::errored(kErrorInvalidOperandSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,8 +359,8 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
// If both labels are bound within the same section it means the delta can be calculated now.
|
// If both labels are bound within the same section it means the delta can be calculated now.
|
||||||
if (labelEntry->isBound() && baseEntry->isBound() && labelEntry->section() == baseEntry->section()) {
|
if (labelEntry.isBound() && baseEntry.isBound() && labelEntry.sectionId() == baseEntry.sectionId()) {
|
||||||
uint64_t delta = labelEntry->offset() - baseEntry->offset();
|
uint64_t delta = labelEntry.offset() - baseEntry.offset();
|
||||||
writer.emitValueLE(delta, dataSize);
|
writer.emitValueLE(delta, dataSize);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -377,11 +377,11 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
|
|
||||||
exp->reset();
|
exp->reset();
|
||||||
exp->opType = ExpressionOpType::kSub;
|
exp->opType = ExpressionOpType::kSub;
|
||||||
exp->setValueAsLabel(0, labelEntry);
|
exp->setValueAsLabelId(0, label.id());
|
||||||
exp->setValueAsLabel(1, baseEntry);
|
exp->setValueAsLabelId(1, base.id());
|
||||||
|
|
||||||
re->_format.resetToSimpleValue(OffsetType::kSignedOffset, dataSize);
|
re->_format.resetToSimpleValue(OffsetType::kSignedOffset, dataSize);
|
||||||
re->_sourceSectionId = _section->id();
|
re->_sourceSectionId = _section->sectionId();
|
||||||
re->_sourceOffset = offset();
|
re->_sourceOffset = offset();
|
||||||
re->_payload = (uint64_t)(uintptr_t)exp;
|
re->_payload = (uint64_t)(uintptr_t)exp;
|
||||||
|
|
||||||
@@ -419,16 +419,14 @@ Error BaseAssembler::comment(const char* data, size_t size) {
|
|||||||
// BaseAssembler - Events
|
// BaseAssembler - Events
|
||||||
// ======================
|
// ======================
|
||||||
|
|
||||||
Error BaseAssembler::onAttach(CodeHolder* code) noexcept {
|
Error BaseAssembler::onAttach(CodeHolder& code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|
||||||
// Attach to the end of the .text section.
|
// Attach to the end of the .text section.
|
||||||
BaseAssembler_initSection(this, code->_sections[0]);
|
return BaseAssembler_initSection(this, code._sections[0]);
|
||||||
|
|
||||||
return kErrorOk;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseAssembler::onDetach(CodeHolder* code) noexcept {
|
Error BaseAssembler::onDetach(CodeHolder& code) noexcept {
|
||||||
_section = nullptr;
|
_section = nullptr;
|
||||||
_bufferData = nullptr;
|
_bufferData = nullptr;
|
||||||
_bufferEnd = nullptr;
|
_bufferEnd = nullptr;
|
||||||
@@ -436,4 +434,11 @@ Error BaseAssembler::onDetach(CodeHolder* code) noexcept {
|
|||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error BaseAssembler::onReinit(CodeHolder& code) noexcept {
|
||||||
|
// BaseEmitter::onReinit() never fails.
|
||||||
|
(void)Base::onReinit(code);
|
||||||
|
|
||||||
|
return BaseAssembler_initSection(this, code._sections[0]);
|
||||||
|
}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
||||||
@@ -125,8 +125,9 @@ public:
|
|||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
ASMJIT_API Error onReinit(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -46,8 +46,7 @@ static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
|
|||||||
|
|
||||||
BaseBuilder::BaseBuilder() noexcept
|
BaseBuilder::BaseBuilder() noexcept
|
||||||
: BaseEmitter(EmitterType::kBuilder),
|
: BaseEmitter(EmitterType::kBuilder),
|
||||||
_codeZone(32u * 1024u),
|
_codeZone(64u * 1024u),
|
||||||
_dataZone(16u * 1024u),
|
|
||||||
_passZone(64u * 1024u),
|
_passZone(64u * 1024u),
|
||||||
_allocator(&_codeZone) {}
|
_allocator(&_codeZone) {}
|
||||||
|
|
||||||
@@ -62,16 +61,15 @@ Error BaseBuilder::newInstNode(InstNode** out, InstId instId, InstOptions instOp
|
|||||||
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
||||||
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
||||||
|
|
||||||
InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
|
void* ptr = _codeZone.alloc(InstNode::nodeSizeOfOpCapacity(opCapacity));
|
||||||
if (ASMJIT_UNLIKELY(!node)) {
|
if (ASMJIT_UNLIKELY(!ptr)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = new(Support::PlacementNew{node}) InstNode(this, instId, instOptions, opCount, opCapacity);
|
*out = new(Support::PlacementNew{ptr}) InstNode(instId, instOptions, opCount, opCapacity);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error BaseBuilder::newLabelNode(LabelNode** out) {
|
Error BaseBuilder::newLabelNode(LabelNode** out) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
@@ -97,30 +95,19 @@ Error BaseBuilder::newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const vo
|
|||||||
uint32_t typeSize = TypeUtils::sizeOf(finalTypeId);
|
uint32_t typeSize = TypeUtils::sizeOf(finalTypeId);
|
||||||
Support::FastUInt8 of = 0;
|
Support::FastUInt8 of = 0;
|
||||||
|
|
||||||
size_t dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of);
|
size_t nodeSize = Support::maddOverflow(itemCount, size_t(typeSize), sizeof(EmbedDataNode), &of);
|
||||||
if (ASMJIT_UNLIKELY(of)) {
|
if (ASMJIT_UNLIKELY(of)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
EmbedDataNode* node;
|
EmbedDataNode* node = nullptr;
|
||||||
ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node));
|
ASMJIT_PROPAGATE(_newNodeTWithSize<EmbedDataNode>(
|
||||||
|
&node, Support::alignUp(nodeSize, Globals::kZoneAlignment),
|
||||||
node->_embed._typeId = typeId;
|
typeId, uint8_t(typeSize), itemCount, repeatCount
|
||||||
node->_embed._typeSize = uint8_t(typeSize);
|
));
|
||||||
node->_itemCount = itemCount;
|
|
||||||
node->_repeatCount = repeatCount;
|
|
||||||
|
|
||||||
uint8_t* dstData = node->_inlineData;
|
|
||||||
if (dataSize > EmbedDataNode::kInlineBufferSize) {
|
|
||||||
dstData = static_cast<uint8_t*>(_dataZone.alloc(dataSize, 8));
|
|
||||||
if (ASMJIT_UNLIKELY(!dstData)) {
|
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
|
||||||
}
|
|
||||||
node->_externalData = dstData;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
memcpy(dstData, data, dataSize);
|
memcpy(node->data(), data, node->dataSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
*out = node;
|
*out = node;
|
||||||
@@ -130,7 +117,7 @@ Error BaseBuilder::newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const vo
|
|||||||
Error BaseBuilder::newConstPoolNode(ConstPoolNode** out) {
|
Error BaseBuilder::newConstPoolNode(ConstPoolNode** out) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out));
|
ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out, &_codeZone));
|
||||||
return registerLabelNode(*out);
|
return registerLabelNode(*out);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -143,7 +130,7 @@ Error BaseBuilder::newCommentNode(CommentNode** out, const char* data, size_t si
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (size > 0) {
|
if (size > 0) {
|
||||||
data = static_cast<char*>(_dataZone.dup(data, size, true));
|
data = static_cast<char*>(_codeZone.dup(data, size, true));
|
||||||
if (ASMJIT_UNLIKELY(!data)) {
|
if (ASMJIT_UNLIKELY(!data)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
@@ -184,7 +171,7 @@ BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
node->addFlags(NodeFlags::kIsActive);
|
node->_addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection()) {
|
if (node->isSection()) {
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
}
|
}
|
||||||
@@ -203,7 +190,7 @@ BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept {
|
|||||||
node->_prev = prev;
|
node->_prev = prev;
|
||||||
node->_next = next;
|
node->_next = next;
|
||||||
|
|
||||||
node->addFlags(NodeFlags::kIsActive);
|
node->_addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection()) {
|
if (node->isSection()) {
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
}
|
}
|
||||||
@@ -231,7 +218,7 @@ BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept {
|
|||||||
node->_prev = prev;
|
node->_prev = prev;
|
||||||
node->_next = next;
|
node->_next = next;
|
||||||
|
|
||||||
node->addFlags(NodeFlags::kIsActive);
|
node->_addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection()) {
|
if (node->isSection()) {
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
}
|
}
|
||||||
@@ -271,7 +258,7 @@ BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept {
|
|||||||
|
|
||||||
node->_prev = nullptr;
|
node->_prev = nullptr;
|
||||||
node->_next = nullptr;
|
node->_next = nullptr;
|
||||||
node->clearFlags(NodeFlags::kIsActive);
|
node->_clearFlags(NodeFlags::kIsActive);
|
||||||
|
|
||||||
if (node->isSection()) {
|
if (node->isSection()) {
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
@@ -320,7 +307,7 @@ void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept {
|
|||||||
|
|
||||||
node->_prev = nullptr;
|
node->_prev = nullptr;
|
||||||
node->_next = nullptr;
|
node->_next = nullptr;
|
||||||
node->clearFlags(NodeFlags::kIsActive);
|
node->_clearFlags(NodeFlags::kIsActive);
|
||||||
didRemoveSection |= uint32_t(node->isSection());
|
didRemoveSection |= uint32_t(node->isSection());
|
||||||
|
|
||||||
if (_cursor == node) {
|
if (_cursor == node) {
|
||||||
@@ -388,7 +375,7 @@ Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) {
|
|||||||
|
|
||||||
Error BaseBuilder::section(Section* section) {
|
Error BaseBuilder::section(Section* section) {
|
||||||
SectionNode* node;
|
SectionNode* node;
|
||||||
ASMJIT_PROPAGATE(sectionNodeOf(&node, section->id()));
|
ASMJIT_PROPAGATE(sectionNodeOf(&node, section->sectionId()));
|
||||||
ASMJIT_ASSUME(node != nullptr);
|
ASMJIT_ASSUME(node != nullptr);
|
||||||
|
|
||||||
if (!node->isActive()) {
|
if (!node->isActive()) {
|
||||||
@@ -397,9 +384,8 @@ Error BaseBuilder::section(Section* section) {
|
|||||||
_cursor = node;
|
_cursor = node;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This is a bit tricky. We cache section links to make sure that
|
// This is a bit tricky. We cache section links to make sure that switching sections doesn't involve
|
||||||
// switching sections doesn't involve traversal in linked-list unless
|
// traversal in linked-list unless the position of the section has changed.
|
||||||
// the position of the section has changed.
|
|
||||||
if (hasDirtySectionLinks()) {
|
if (hasDirtySectionLinks()) {
|
||||||
updateSectionLinks();
|
updateSectionLinks();
|
||||||
}
|
}
|
||||||
@@ -474,9 +460,8 @@ Error BaseBuilder::registerLabelNode(LabelNode* node) {
|
|||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelEntry* le;
|
uint32_t labelId;
|
||||||
ASMJIT_PROPAGATE(_code->newLabelEntry(&le));
|
ASMJIT_PROPAGATE(_code->newLabelId(&labelId));
|
||||||
uint32_t labelId = le->id();
|
|
||||||
|
|
||||||
// We just added one label so it must be true.
|
// We just added one label so it must be true.
|
||||||
ASMJIT_ASSERT(_labelNodes.size() < labelId + 1);
|
ASMJIT_ASSERT(_labelNodes.size() < labelId + 1);
|
||||||
@@ -498,7 +483,7 @@ static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) {
|
|||||||
return self->reportError(err);
|
return self->reportError(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
LabelNode* node;
|
LabelNode* node = nullptr;
|
||||||
ASMJIT_PROPAGATE(self->_newNodeT<LabelNode>(&node, labelId));
|
ASMJIT_PROPAGATE(self->_newNodeT<LabelNode>(&node, labelId));
|
||||||
|
|
||||||
// SAFETY: No need to check for error condition as we have already reserved enough space.
|
// SAFETY: No need to check for error condition as we have already reserved enough space.
|
||||||
@@ -509,29 +494,43 @@ static Error BaseBuilder_newLabelInternal(BaseBuilder* self, uint32_t labelId) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Label BaseBuilder::newLabel() {
|
Label BaseBuilder::newLabel() {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
Label label;
|
||||||
LabelEntry* le;
|
|
||||||
|
|
||||||
if (_code &&
|
if (ASMJIT_LIKELY(_code)) {
|
||||||
_code->newLabelEntry(&le) == kErrorOk &&
|
uint32_t labelId;
|
||||||
BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) {
|
Error err = _code->newLabelId(&labelId);
|
||||||
labelId = le->id();
|
|
||||||
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
|
reportError(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ASMJIT_LIKELY(BaseBuilder_newLabelInternal(this, labelId)) == kErrorOk) {
|
||||||
|
label.setId(labelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Label(labelId);
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
Label label;
|
||||||
LabelEntry* le;
|
|
||||||
|
|
||||||
if (_code &&
|
if (ASMJIT_LIKELY(_code)) {
|
||||||
_code->newNamedLabelEntry(&le, name, nameSize, type, parentId) == kErrorOk &&
|
uint32_t labelId;
|
||||||
BaseBuilder_newLabelInternal(this, le->id()) == kErrorOk) {
|
Error err = _code->newNamedLabelId(&labelId, name, nameSize, type, parentId);
|
||||||
labelId = le->id();
|
|
||||||
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
|
reportError(err);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
if (ASMJIT_LIKELY(BaseBuilder_newLabelInternal(this, labelId) == kErrorOk)) {
|
||||||
|
label.setId(labelId);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Label(labelId);
|
return label;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::bind(const Label& label) {
|
Error BaseBuilder::bind(const Label& label) {
|
||||||
@@ -577,31 +576,6 @@ ASMJIT_FAVOR_SIZE Error BaseBuilder::addPass(Pass* pass) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error BaseBuilder::deletePass(Pass* pass) noexcept {
|
|
||||||
if (ASMJIT_UNLIKELY(!_code)) {
|
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(pass == nullptr)) {
|
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pass->_cb != nullptr) {
|
|
||||||
if (pass->_cb != this) {
|
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t index = _passes.indexOf(pass);
|
|
||||||
ASMJIT_ASSERT(index != Globals::kNotFound);
|
|
||||||
|
|
||||||
pass->_cb = nullptr;
|
|
||||||
_passes.removeAt(index);
|
|
||||||
}
|
|
||||||
|
|
||||||
pass->~Pass();
|
|
||||||
return kErrorOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
Error BaseBuilder::runPasses() {
|
Error BaseBuilder::runPasses() {
|
||||||
if (ASMJIT_UNLIKELY(!_code)) {
|
if (ASMJIT_UNLIKELY(!_code)) {
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
@@ -673,18 +647,18 @@ Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1,
|
|||||||
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
||||||
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
||||||
|
|
||||||
InstNode* node = _allocator.allocT<InstNode>(InstNode::nodeSizeOfOpCapacity(opCapacity));
|
void* ptr = _codeZone.alloc(InstNode::nodeSizeOfOpCapacity(opCapacity));
|
||||||
const char* comment = inlineComment();
|
const char* comment = inlineComment();
|
||||||
|
|
||||||
resetInstOptions();
|
resetInstOptions();
|
||||||
resetInlineComment();
|
resetInlineComment();
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!node)) {
|
if (ASMJIT_UNLIKELY(!ptr)) {
|
||||||
resetExtraReg();
|
resetExtraReg();
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
node = new(Support::PlacementNew{node}) InstNode(this, instId, options, opCount, opCapacity);
|
InstNode* node = new(Support::PlacementNew{ptr}) InstNode(instId, options, opCount, opCapacity);
|
||||||
node->setExtraReg(extraReg());
|
node->setExtraReg(extraReg());
|
||||||
node->setOp(0, o0);
|
node->setOp(0, o0);
|
||||||
node->setOp(1, o1);
|
node->setOp(1, o1);
|
||||||
@@ -695,7 +669,7 @@ Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1,
|
|||||||
node->resetOpRange(opCount, opCapacity);
|
node->resetOpRange(opCount, opCapacity);
|
||||||
|
|
||||||
if (comment) {
|
if (comment) {
|
||||||
node->setInlineComment(static_cast<char*>(_dataZone.dup(comment, strlen(comment), true)));
|
node->setInlineComment(static_cast<char*>(_codeZone.dup(comment, strlen(comment), true)));
|
||||||
}
|
}
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
@@ -771,24 +745,13 @@ Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
|
|||||||
|
|
||||||
// BaseBuilder - EmbedLabel & EmbedLabelDelta
|
// BaseBuilder - EmbedLabel & EmbedLabelDelta
|
||||||
// ==========================================
|
// ==========================================
|
||||||
//
|
|
||||||
// If dataSize is zero it means that the size is the same as target register width, however,
|
|
||||||
// if it's provided we really want to validate whether it's within the possible range.
|
|
||||||
|
|
||||||
static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept {
|
|
||||||
return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8);
|
|
||||||
}
|
|
||||||
|
|
||||||
Error BaseBuilder::embedLabel(const Label& label, size_t dataSize) {
|
Error BaseBuilder::embedLabel(const Label& label, size_t dataSize) {
|
||||||
if (ASMJIT_UNLIKELY(!_code)) {
|
if (ASMJIT_UNLIKELY(!Support::bool_and(_code, Support::isZeroOrPowerOf2UpTo(dataSize, 8u)))) {
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return reportError(DebugUtils::errored(!_code ? kErrorNotInitialized : kErrorInvalidArgument));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BaseBuilder_checkDataSize(dataSize)) {
|
EmbedLabelNode* node = nullptr;
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
|
||||||
}
|
|
||||||
|
|
||||||
EmbedLabelNode* node;
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<EmbedLabelNode>(&node, label.id(), uint32_t(dataSize)));
|
ASMJIT_PROPAGATE(_newNodeT<EmbedLabelNode>(&node, label.id(), uint32_t(dataSize)));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
@@ -796,15 +759,11 @@ Error BaseBuilder::embedLabel(const Label& label, size_t dataSize) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) {
|
Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t dataSize) {
|
||||||
if (ASMJIT_UNLIKELY(!_code)) {
|
if (ASMJIT_UNLIKELY(!Support::bool_and(_code, Support::isZeroOrPowerOf2UpTo(dataSize, 8u)))) {
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return reportError(DebugUtils::errored(!_code ? kErrorNotInitialized : kErrorInvalidArgument));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!BaseBuilder_checkDataSize(dataSize)) {
|
EmbedLabelDeltaNode* node = nullptr;
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
|
||||||
}
|
|
||||||
|
|
||||||
EmbedLabelDeltaNode* node;
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<EmbedLabelDeltaNode>(&node, label.id(), base.id(), uint32_t(dataSize)));
|
ASMJIT_PROPAGATE(_newNodeT<EmbedLabelDeltaNode>(&node, label.id(), base.id(), uint32_t(dataSize)));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
@@ -895,7 +854,7 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
|||||||
}
|
}
|
||||||
else if (node_->isSection()) {
|
else if (node_->isSection()) {
|
||||||
SectionNode* node = node_->as<SectionNode>();
|
SectionNode* node = node_->as<SectionNode>();
|
||||||
err = dst->section(_code->sectionById(node->id()));
|
err = dst->section(_code->sectionById(node->sectionId()));
|
||||||
}
|
}
|
||||||
else if (node_->isComment()) {
|
else if (node_->isComment()) {
|
||||||
CommentNode* node = node_->as<CommentNode>();
|
CommentNode* node = node_->as<CommentNode>();
|
||||||
@@ -914,46 +873,58 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
|||||||
// BaseBuilder - Events
|
// BaseBuilder - Events
|
||||||
// ====================
|
// ====================
|
||||||
|
|
||||||
Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
|
static ASMJIT_INLINE void BaseBuilder_clearAll(BaseBuilder* self) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
self->_sectionNodes.reset();
|
||||||
|
self->_labelNodes.reset();
|
||||||
|
|
||||||
|
self->_allocator.reset(&self->_codeZone);
|
||||||
|
self->_codeZone.reset();
|
||||||
|
self->_passZone.reset();
|
||||||
|
|
||||||
|
self->_cursor = nullptr;
|
||||||
|
self->_nodeList.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ASMJIT_INLINE Error BaseBuilder_initSection(BaseBuilder* self) noexcept {
|
||||||
SectionNode* initialSection;
|
SectionNode* initialSection;
|
||||||
Error err = sectionNodeOf(&initialSection, 0);
|
|
||||||
|
|
||||||
if (!err) {
|
ASMJIT_PROPAGATE(self->sectionNodeOf(&initialSection, 0));
|
||||||
err = _passes.willGrow(&_allocator, 8);
|
ASMJIT_PROPAGATE(self->_passes.willGrow(&self->_allocator, 4));
|
||||||
}
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
|
||||||
onDetach(code);
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
ASMJIT_ASSUME(initialSection != nullptr);
|
ASMJIT_ASSUME(initialSection != nullptr);
|
||||||
_cursor = initialSection;
|
self->_cursor = initialSection;
|
||||||
_nodeList.reset(initialSection, initialSection);
|
self->_nodeList.reset(initialSection, initialSection);
|
||||||
initialSection->setFlags(NodeFlags::kIsActive);
|
initialSection->_setFlags(NodeFlags::kIsActive);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
|
Error BaseBuilder::onAttach(CodeHolder& code) noexcept {
|
||||||
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|
||||||
|
Error err = BaseBuilder_initSection(this);
|
||||||
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
|
onDetach(code);
|
||||||
|
}
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error BaseBuilder::onDetach(CodeHolder& code) noexcept {
|
||||||
BaseBuilder_deletePasses(this);
|
BaseBuilder_deletePasses(this);
|
||||||
_sectionNodes.reset();
|
BaseBuilder_clearAll(this);
|
||||||
_labelNodes.reset();
|
|
||||||
|
|
||||||
_allocator.reset(&_codeZone);
|
|
||||||
_codeZone.reset();
|
|
||||||
_dataZone.reset();
|
|
||||||
_passZone.reset();
|
|
||||||
|
|
||||||
_nodeFlags = NodeFlags::kNone;
|
|
||||||
_cursor = nullptr;
|
|
||||||
_nodeList.reset();
|
|
||||||
|
|
||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error BaseBuilder::onReinit(CodeHolder& code) noexcept {
|
||||||
|
// BaseEmitter::onReinit() never fails.
|
||||||
|
(void)Base::onReinit(code);
|
||||||
|
|
||||||
|
BaseBuilder_deletePasses(this);
|
||||||
|
BaseBuilder_clearAll(this);
|
||||||
|
return BaseBuilder_initSection(this);
|
||||||
|
}
|
||||||
|
|
||||||
// Pass - Construction & Destruction
|
// Pass - Construction & Destruction
|
||||||
// =================================
|
// =================================
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_BUILDER_H_INCLUDED
|
#ifndef ASMJIT_CORE_BUILDER_H_INCLUDED
|
||||||
@@ -196,8 +196,6 @@ public:
|
|||||||
|
|
||||||
//! Base zone used to allocate nodes and passes.
|
//! Base zone used to allocate nodes and passes.
|
||||||
Zone _codeZone;
|
Zone _codeZone;
|
||||||
//! Data zone used to allocate data and names.
|
|
||||||
Zone _dataZone;
|
|
||||||
//! Pass zone, passed to `Pass::run()`.
|
//! Pass zone, passed to `Pass::run()`.
|
||||||
Zone _passZone;
|
Zone _passZone;
|
||||||
//! Allocator that uses `_codeZone`.
|
//! Allocator that uses `_codeZone`.
|
||||||
@@ -215,8 +213,6 @@ public:
|
|||||||
//! First and last nodes.
|
//! First and last nodes.
|
||||||
NodeList _nodeList;
|
NodeList _nodeList;
|
||||||
|
|
||||||
//! Flags assigned to each new node.
|
|
||||||
NodeFlags _nodeFlags = NodeFlags::kNone;
|
|
||||||
//! The sections links are dirty (used internally).
|
//! The sections links are dirty (used internally).
|
||||||
bool _dirtySectionLinks = false;
|
bool _dirtySectionLinks = false;
|
||||||
|
|
||||||
@@ -246,6 +242,20 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG BaseNode* lastNode() const noexcept { return _nodeList.last(); }
|
ASMJIT_INLINE_NODEBUG BaseNode* lastNode() const noexcept { return _nodeList.last(); }
|
||||||
|
|
||||||
|
//! Allocates data required for a node.
|
||||||
|
template<typename T, typename... Args>
|
||||||
|
ASMJIT_INLINE Error _newNodeTWithSize(T** ASMJIT_NONNULL(out), size_t size, Args&&... args) {
|
||||||
|
ASMJIT_ASSERT(Support::isAligned(size, Globals::kZoneAlignment));
|
||||||
|
|
||||||
|
void* ptr =_codeZone.alloc(size);
|
||||||
|
if (ASMJIT_UNLIKELY(!ptr)) {
|
||||||
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = new(Support::PlacementNew{ptr}) T(std::forward<Args>(args)...);
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
|
||||||
//! Allocates and instantiates a new node of type `T` and returns its instance. If the allocation fails `nullptr`
|
//! Allocates and instantiates a new node of type `T` and returns its instance. If the allocation fails `nullptr`
|
||||||
//! is returned.
|
//! is returned.
|
||||||
//!
|
//!
|
||||||
@@ -254,10 +264,14 @@ public:
|
|||||||
//! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler
|
//! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler
|
||||||
//! is destroyed it destroys all nodes it created so no manual memory management is required.
|
//! is destroyed it destroys all nodes it created so no manual memory management is required.
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
inline Error _newNodeT(T** ASMJIT_NONNULL(out), Args&&... args) {
|
ASMJIT_INLINE Error _newNodeT(T** ASMJIT_NONNULL(out), Args&&... args) {
|
||||||
*out = _allocator.newT<T>(this, std::forward<Args>(args)...);
|
void* ptr = _codeZone.alloc(Zone::alignedSizeOf<T>());
|
||||||
if (ASMJIT_UNLIKELY(!*out))
|
|
||||||
|
if (ASMJIT_UNLIKELY(!ptr)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
|
}
|
||||||
|
|
||||||
|
*out = new(Support::PlacementNew{ptr}) T(std::forward<Args>(args)...);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -377,6 +391,7 @@ public:
|
|||||||
//!
|
//!
|
||||||
//! This function is used internally to register a newly created `LabelNode` with this instance of Builder/Compiler.
|
//! This function is used internally to register a newly created `LabelNode` with this instance of Builder/Compiler.
|
||||||
//! Use \ref labelNodeOf() functions to get back \ref LabelNode from a label or its identifier.
|
//! Use \ref labelNodeOf() functions to get back \ref LabelNode from a label or its identifier.
|
||||||
|
[[nodiscard]]
|
||||||
ASMJIT_API Error registerLabelNode(LabelNode* ASMJIT_NONNULL(node));
|
ASMJIT_API Error registerLabelNode(LabelNode* ASMJIT_NONNULL(node));
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -427,9 +442,6 @@ public:
|
|||||||
//! Adds `pass` to the list of passes.
|
//! Adds `pass` to the list of passes.
|
||||||
ASMJIT_API Error addPass(Pass* pass) noexcept;
|
ASMJIT_API Error addPass(Pass* pass) noexcept;
|
||||||
|
|
||||||
//! Removes `pass` from the list of passes and delete it.
|
|
||||||
ASMJIT_API Error deletePass(Pass* pass) noexcept;
|
|
||||||
|
|
||||||
//! Runs all passes in order.
|
//! Runs all passes in order.
|
||||||
ASMJIT_API Error runPasses();
|
ASMJIT_API Error runPasses();
|
||||||
|
|
||||||
@@ -482,8 +494,9 @@ public:
|
|||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
ASMJIT_API Error onReinit(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
@@ -508,16 +521,17 @@ public:
|
|||||||
//! Next node.
|
//! Next node.
|
||||||
BaseNode* _next;
|
BaseNode* _next;
|
||||||
};
|
};
|
||||||
//! Links (an alternative view to previous and next nodes).
|
//! Links (an alternative view of previous and next nodes).
|
||||||
BaseNode* _links[2];
|
BaseNode* _links[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Data shared between all types of nodes.
|
|
||||||
struct AnyData {
|
|
||||||
//! Node type.
|
//! Node type.
|
||||||
NodeType _nodeType;
|
NodeType _nodeType;
|
||||||
//! Node flags.
|
//! Node flags.
|
||||||
NodeFlags _nodeFlags;
|
NodeFlags _nodeFlags;
|
||||||
|
|
||||||
|
//! Data shared between all types of nodes.
|
||||||
|
struct AnyData {
|
||||||
//! Not used by BaseNode.
|
//! Not used by BaseNode.
|
||||||
uint8_t _reserved0;
|
uint8_t _reserved0;
|
||||||
//! Not used by BaseNode.
|
//! Not used by BaseNode.
|
||||||
@@ -526,10 +540,6 @@ public:
|
|||||||
|
|
||||||
//! Data used by \ref AlignNode.
|
//! Data used by \ref AlignNode.
|
||||||
struct AlignData {
|
struct AlignData {
|
||||||
//! Node type.
|
|
||||||
NodeType _nodeType;
|
|
||||||
//! Node flags.
|
|
||||||
NodeFlags _nodeFlags;
|
|
||||||
//! Align mode.
|
//! Align mode.
|
||||||
AlignMode _alignMode;
|
AlignMode _alignMode;
|
||||||
//! Not used by AlignNode.
|
//! Not used by AlignNode.
|
||||||
@@ -538,10 +548,6 @@ public:
|
|||||||
|
|
||||||
//! Data used by \ref InstNode.
|
//! Data used by \ref InstNode.
|
||||||
struct InstData {
|
struct InstData {
|
||||||
//! Node type.
|
|
||||||
NodeType _nodeType;
|
|
||||||
//! Node flags.
|
|
||||||
NodeFlags _nodeFlags;
|
|
||||||
//! Instruction operands count (used).
|
//! Instruction operands count (used).
|
||||||
uint8_t _opCount;
|
uint8_t _opCount;
|
||||||
//! Instruction operands capacity (allocated).
|
//! Instruction operands capacity (allocated).
|
||||||
@@ -550,10 +556,6 @@ public:
|
|||||||
|
|
||||||
//! Data used by \ref EmbedDataNode.
|
//! Data used by \ref EmbedDataNode.
|
||||||
struct EmbedData {
|
struct EmbedData {
|
||||||
//! Node type.
|
|
||||||
NodeType _nodeType;
|
|
||||||
//! Node flags.
|
|
||||||
NodeFlags _nodeFlags;
|
|
||||||
//! Type id.
|
//! Type id.
|
||||||
TypeId _typeId;
|
TypeId _typeId;
|
||||||
//! Size of `_typeId`.
|
//! Size of `_typeId`.
|
||||||
@@ -562,10 +564,6 @@ public:
|
|||||||
|
|
||||||
//! Data used by \ref SentinelNode.
|
//! Data used by \ref SentinelNode.
|
||||||
struct SentinelData {
|
struct SentinelData {
|
||||||
//! Node type.
|
|
||||||
NodeType _nodeType;
|
|
||||||
//! Node flags.
|
|
||||||
NodeFlags _nodeFlags;
|
|
||||||
//! Sentinel type.
|
//! Sentinel type.
|
||||||
SentinelType _sentinelType;
|
SentinelType _sentinelType;
|
||||||
//! Not used by BaseNode.
|
//! Not used by BaseNode.
|
||||||
@@ -609,11 +607,11 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `BaseNode` - always use `BaseBuilder` to allocate nodes.
|
//! Creates a new `BaseNode` - always use `BaseBuilder` to allocate nodes.
|
||||||
ASMJIT_INLINE_NODEBUG BaseNode(BaseBuilder* cb, NodeType nodeType, NodeFlags nodeFlags = NodeFlags::kNone) noexcept {
|
ASMJIT_INLINE_NODEBUG explicit BaseNode(NodeType nodeType, NodeFlags nodeFlags = NodeFlags::kNone) noexcept {
|
||||||
_prev = nullptr;
|
_prev = nullptr;
|
||||||
_next = nullptr;
|
_next = nullptr;
|
||||||
_any._nodeType = nodeType;
|
_nodeType = nodeType;
|
||||||
_any._nodeFlags = nodeFlags | cb->_nodeFlags;
|
_nodeFlags = nodeFlags;
|
||||||
_any._reserved0 = 0;
|
_any._reserved0 = 0;
|
||||||
_any._reserved1 = 0;
|
_any._reserved1 = 0;
|
||||||
_position = 0;
|
_position = 0;
|
||||||
@@ -647,13 +645,13 @@ public:
|
|||||||
|
|
||||||
//! Returns the type of the node, see \ref NodeType.
|
//! Returns the type of the node, see \ref NodeType.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG NodeType type() const noexcept { return _any._nodeType; }
|
ASMJIT_INLINE_NODEBUG NodeType type() const noexcept { return _nodeType; }
|
||||||
|
|
||||||
//! Sets the type of the node, see `NodeType` (internal).
|
//! Sets the type of the node, see `NodeType` (internal).
|
||||||
//!
|
//!
|
||||||
//! \remarks You should never set a type of a node to anything else than the initial value. This function is only
|
//! \remarks You should never set a type of a node to anything else than the initial value. This function is only
|
||||||
//! provided for users that use custom nodes and need to change the type either during construction or later.
|
//! provided for users that use custom nodes and need to change the type either during construction or later.
|
||||||
ASMJIT_INLINE_NODEBUG void setType(NodeType type) noexcept { _any._nodeType = type; }
|
ASMJIT_INLINE_NODEBUG void _setType(NodeType type) noexcept { _nodeType = type; }
|
||||||
|
|
||||||
//! Tests whether this node is either `InstNode` or extends it.
|
//! Tests whether this node is either `InstNode` or extends it.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -709,18 +707,20 @@ public:
|
|||||||
|
|
||||||
//! Returns the node flags.
|
//! Returns the node flags.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG NodeFlags flags() const noexcept { return _any._nodeFlags; }
|
ASMJIT_INLINE_NODEBUG NodeFlags flags() const noexcept { return _nodeFlags; }
|
||||||
|
|
||||||
//! Tests whether the node has the given `flag` set.
|
//! Tests whether the node has the given `flag` set.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasFlag(NodeFlags flag) const noexcept { return Support::test(_any._nodeFlags, flag); }
|
ASMJIT_INLINE_NODEBUG bool hasFlag(NodeFlags flag) const noexcept { return Support::test(_nodeFlags, flag); }
|
||||||
|
|
||||||
//! Replaces node flags with `flags`.
|
//! Replaces node flags with `flags`.
|
||||||
ASMJIT_INLINE_NODEBUG void setFlags(NodeFlags flags) noexcept { _any._nodeFlags = flags; }
|
ASMJIT_INLINE_NODEBUG void _setFlags(NodeFlags flags) noexcept { _nodeFlags = flags; }
|
||||||
|
|
||||||
//! Adds the given `flags` to node flags.
|
//! Adds the given `flags` to node flags.
|
||||||
ASMJIT_INLINE_NODEBUG void addFlags(NodeFlags flags) noexcept { _any._nodeFlags |= flags; }
|
ASMJIT_INLINE_NODEBUG void _addFlags(NodeFlags flags) noexcept { _nodeFlags |= flags; }
|
||||||
|
|
||||||
//! Clears the given `flags` from node flags.
|
//! Clears the given `flags` from node flags.
|
||||||
ASMJIT_INLINE_NODEBUG void clearFlags(NodeFlags flags) noexcept { _any._nodeFlags &= ~flags; }
|
ASMJIT_INLINE_NODEBUG void _clearFlags(NodeFlags flags) noexcept { _nodeFlags &= ~flags; }
|
||||||
|
|
||||||
//! Tests whether the node is code that can be executed.
|
//! Tests whether the node is code that can be executed.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -840,13 +840,38 @@ public:
|
|||||||
//! embed 5. The rest (up to 6 operands) is considered extended.
|
//! embed 5. The rest (up to 6 operands) is considered extended.
|
||||||
//!
|
//!
|
||||||
//! The number of operands InstNode holds is decided when \ref InstNode is created.
|
//! The number of operands InstNode holds is decided when \ref InstNode is created.
|
||||||
static inline constexpr uint32_t kBaseOpCapacity = uint32_t((128 - sizeof(BaseNode) - sizeof(BaseInst)) / sizeof(Operand_));
|
static inline constexpr uint32_t kBaseOpCapacity = uint32_t((128u - sizeof(BaseNode) - sizeof(BaseInst)) / sizeof(Operand_));
|
||||||
|
|
||||||
//! Count of maximum number of operands \ref InstNode can hold.
|
//! Count of maximum number of operands \ref InstNode can hold.
|
||||||
static inline constexpr uint32_t kFullOpCapacity = Globals::kMaxOpCount;
|
static inline constexpr uint32_t kFullOpCapacity = Globals::kMaxOpCount;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
//! \name Operand Capacity Utilities
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Returns the capacity required for the given operands count `opCount`.
|
||||||
|
//!
|
||||||
|
//! There are only two capacities used - \ref kBaseOpCapacity and \ref kFullOpCapacity, so this function
|
||||||
|
//! is used to decide between these two. The general rule is that instructions that can be represented with
|
||||||
|
//! \ref kBaseOpCapacity would use this value, and all others would take \ref kFullOpCapacity.
|
||||||
|
[[nodiscard]]
|
||||||
|
static ASMJIT_INLINE_CONSTEXPR uint32_t capacityOfOpCount(uint32_t opCount) noexcept {
|
||||||
|
return opCount <= kBaseOpCapacity ? kBaseOpCapacity : kFullOpCapacity;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Calculates the size of \ref InstNode required to hold at most `opCapacity` operands.
|
||||||
|
//!
|
||||||
|
//! This function is used internally to allocate \ref InstNode.
|
||||||
|
[[nodiscard]]
|
||||||
|
static ASMJIT_INLINE_CONSTEXPR size_t nodeSizeOfOpCapacity(uint32_t opCapacity) noexcept {
|
||||||
|
return Support::alignUp(sizeof(InstNode) + opCapacity * sizeof(Operand), Globals::kZoneAlignment);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! \name Members
|
//! \name Members
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -859,8 +884,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `InstNode` instance.
|
//! Creates a new `InstNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG InstNode(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept
|
ASMJIT_INLINE_NODEBUG InstNode(InstId instId, InstOptions options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept
|
||||||
: BaseNode(cb, NodeType::kInst, NodeFlags::kIsCode | NodeFlags::kIsRemovable | NodeFlags::kActsAsInst),
|
: BaseNode(NodeType::kInst, NodeFlags::kIsCode | NodeFlags::kIsRemovable | NodeFlags::kActsAsInst),
|
||||||
_baseInst(instId, options) {
|
_baseInst(instId, options) {
|
||||||
_inst._opCapacity = uint8_t(opCapacity);
|
_inst._opCapacity = uint8_t(opCapacity);
|
||||||
_inst._opCount = uint8_t(opCount);
|
_inst._opCount = uint8_t(opCount);
|
||||||
@@ -941,7 +966,7 @@ public:
|
|||||||
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _baseInst.extraReg(); }
|
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _baseInst.extraReg(); }
|
||||||
|
|
||||||
//! Sets extra register operand to `reg`.
|
//! Sets extra register operand to `reg`.
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const BaseReg& reg) noexcept { _baseInst.setExtraReg(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const Reg& reg) noexcept { _baseInst.setExtraReg(reg); }
|
||||||
//! Sets extra register operand to `reg`.
|
//! Sets extra register operand to `reg`.
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _baseInst.setExtraReg(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _baseInst.setExtraReg(reg); }
|
||||||
//! Resets extra register operand.
|
//! Resets extra register operand.
|
||||||
@@ -965,15 +990,11 @@ public:
|
|||||||
|
|
||||||
//! Returns operands array.
|
//! Returns operands array.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG Operand* operands() noexcept {
|
ASMJIT_INLINE_NODEBUG Operand* operands() noexcept { return Support::offsetPtr<Operand>(this, sizeof(InstNode)); }
|
||||||
return reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(this) + sizeof(InstNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns operands array (const).
|
//! Returns operands array (const).
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG const Operand* operands() const noexcept {
|
ASMJIT_INLINE_NODEBUG const Operand* operands() const noexcept { return Support::offsetPtr<Operand>(this, sizeof(InstNode)); }
|
||||||
return reinterpret_cast<const Operand*>(reinterpret_cast<const uint8_t*>(this) + sizeof(InstNode));
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns operand at the given `index`.
|
//! Returns operand at the given `index`.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -1025,9 +1046,11 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool hasOpType(OperandType opType) const noexcept {
|
inline bool hasOpType(OperandType opType) const noexcept {
|
||||||
const Operand* ops = operands();
|
const Operand* ops = operands();
|
||||||
for (uint32_t i = 0, count = opCount(); i < count; i++)
|
for (uint32_t i = 0, count = opCount(); i < count; i++) {
|
||||||
if (ops[i].opType() == opType)
|
if (ops[i].opType() == opType) {
|
||||||
return true;
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1080,11 +1103,10 @@ public:
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
//! \name Rewriting
|
//! \name Rewriting
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! \cond INTERNAL
|
|
||||||
|
|
||||||
//! Returns uint32_t[] view that represents BaseInst::RegOnly and instruction operands.
|
//! Returns uint32_t[] view that represents BaseInst::RegOnly and instruction operands.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; }
|
ASMJIT_INLINE_NODEBUG uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; }
|
||||||
@@ -1098,11 +1120,11 @@ public:
|
|||||||
|
|
||||||
//! Returns a rewrite index of the given pointer to `id`.
|
//! Returns a rewrite index of the given pointer to `id`.
|
||||||
//!
|
//!
|
||||||
//! This function returns a value that can be then passed to `\ref rewriteIdAtIndex() function. It can address
|
//! This function returns a value that can be then passed to `\ref _rewriteIdAtIndex() function. It can address
|
||||||
//! any id from any operand that is used by the instruction in addition to \ref BaseInst::regOnly field, which
|
//! any id from any operand that is used by the instruction in addition to \ref BaseInst::regOnly field, which
|
||||||
//! can also be used by the register allocator.
|
//! can also be used by the register allocator.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t getRewriteIndex(const uint32_t* id) const noexcept {
|
inline uint32_t _getRewriteIndex(const uint32_t* id) const noexcept {
|
||||||
const uint32_t* array = _getRewriteArray();
|
const uint32_t* array = _getRewriteArray();
|
||||||
ASMJIT_ASSERT(array <= id);
|
ASMJIT_ASSERT(array <= id);
|
||||||
|
|
||||||
@@ -1119,41 +1141,15 @@ public:
|
|||||||
//! and the given `index` describes a position in this array. For example a single \ref Operand would be
|
//! and the given `index` describes a position in this array. For example a single \ref Operand would be
|
||||||
//! decomposed to 4 uint32_t values, where the first at index 0 would be operand signature, next would be
|
//! decomposed to 4 uint32_t values, where the first at index 0 would be operand signature, next would be
|
||||||
//! base id, etc... This is a comfortable way of patching operands without having to check for their types.
|
//! base id, etc... This is a comfortable way of patching operands without having to check for their types.
|
||||||
inline void rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept {
|
inline void _rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept {
|
||||||
ASMJIT_ASSERT(index <= kMaxRewriteId);
|
ASMJIT_ASSERT(index <= kMaxRewriteId);
|
||||||
|
|
||||||
uint32_t* array = _getRewriteArray();
|
uint32_t* array = _getRewriteArray();
|
||||||
array[index] = id;
|
array[index] = id;
|
||||||
}
|
}
|
||||||
//! \endcond
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Static Functions
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! \cond INTERNAL
|
|
||||||
|
|
||||||
//! Returns the capacity required for the given operands count `opCount`.
|
|
||||||
//!
|
|
||||||
//! There are only two capacities used - \ref kBaseOpCapacity and \ref kFullOpCapacity, so this function
|
|
||||||
//! is used to decide between these two. The general rule is that instructions that can be represented with
|
|
||||||
//! \ref kBaseOpCapacity would use this value, and all others would take \ref kFullOpCapacity.
|
|
||||||
[[nodiscard]]
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR uint32_t capacityOfOpCount(uint32_t opCount) noexcept {
|
|
||||||
return opCount <= kBaseOpCapacity ? kBaseOpCapacity : kFullOpCapacity;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Calculates the size of \ref InstNode required to hold at most `opCapacity` operands.
|
|
||||||
//!
|
|
||||||
//! This function is used internally to allocate \ref InstNode.
|
|
||||||
[[nodiscard]]
|
|
||||||
static ASMJIT_INLINE_CONSTEXPR size_t nodeSizeOfOpCapacity(uint32_t opCapacity) noexcept {
|
|
||||||
return sizeof(InstNode) + opCapacity * sizeof(Operand);
|
|
||||||
}
|
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
//! \}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Instruction node with embedded operands following \ref InstNode layout.
|
//! Instruction node with embedded operands following \ref InstNode layout.
|
||||||
@@ -1167,8 +1163,8 @@ public:
|
|||||||
Operand_ _operands[kN];
|
Operand_ _operands[kN];
|
||||||
|
|
||||||
//! Creates a new `InstNodeWithOperands` instance.
|
//! Creates a new `InstNodeWithOperands` instance.
|
||||||
ASMJIT_INLINE_NODEBUG InstNodeWithOperands(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCount) noexcept
|
ASMJIT_INLINE_NODEBUG InstNodeWithOperands(InstId instId, InstOptions options, uint32_t opCount) noexcept
|
||||||
: InstNode(cb, instId, options, opCount, kN) {}
|
: InstNode(instId, options, opCount, kN) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Section node.
|
//! Section node.
|
||||||
@@ -1180,7 +1176,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Section id.
|
//! Section id.
|
||||||
uint32_t _id;
|
uint32_t _sectionId;
|
||||||
|
|
||||||
//! Next section node that follows this section.
|
//! Next section node that follows this section.
|
||||||
//!
|
//!
|
||||||
@@ -1195,9 +1191,9 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `SectionNode` instance.
|
//! Creates a new `SectionNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG SectionNode(BaseBuilder* cb, uint32_t sectionId = 0) noexcept
|
ASMJIT_INLINE_NODEBUG explicit SectionNode(uint32_t sectionId = 0) noexcept
|
||||||
: BaseNode(cb, NodeType::kSection, NodeFlags::kHasNoEffect),
|
: BaseNode(NodeType::kSection, NodeFlags::kHasNoEffect),
|
||||||
_id(sectionId),
|
_sectionId(sectionId),
|
||||||
_nextSection(nullptr) {}
|
_nextSection(nullptr) {}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -1206,7 +1202,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the section id.
|
//! Returns the section id.
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t id() const noexcept { return _id; }
|
ASMJIT_INLINE_NODEBUG uint32_t sectionId() const noexcept { return _sectionId; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
@@ -1228,8 +1224,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `LabelNode` instance.
|
//! Creates a new `LabelNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept
|
ASMJIT_INLINE_NODEBUG explicit LabelNode(uint32_t labelId = Globals::kInvalidId) noexcept
|
||||||
: BaseNode(cb, NodeType::kLabel, NodeFlags::kHasNoEffect | NodeFlags::kActsAsLabel),
|
: BaseNode(NodeType::kLabel, NodeFlags::kHasNoEffect | NodeFlags::kActsAsLabel),
|
||||||
_labelId(labelId) {}
|
_labelId(labelId) {}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -1267,8 +1263,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `AlignNode` instance.
|
//! Creates a new `AlignNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG AlignNode(BaseBuilder* cb, AlignMode alignMode, uint32_t alignment) noexcept
|
ASMJIT_INLINE_NODEBUG AlignNode(AlignMode alignMode, uint32_t alignment) noexcept
|
||||||
: BaseNode(cb, NodeType::kAlign, NodeFlags::kIsCode | NodeFlags::kHasNoEffect) {
|
: BaseNode(NodeType::kAlign, NodeFlags::kIsCode | NodeFlags::kHasNoEffect) {
|
||||||
|
|
||||||
_alignData._alignMode = alignMode;
|
_alignData._alignMode = alignMode;
|
||||||
_alignment = alignment;
|
_alignment = alignment;
|
||||||
@@ -1304,34 +1300,24 @@ class EmbedDataNode : public BaseNode {
|
|||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(EmbedDataNode)
|
ASMJIT_NONCOPYABLE(EmbedDataNode)
|
||||||
|
|
||||||
//! \cond INTERNAL
|
|
||||||
static inline constexpr uint32_t kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2);
|
|
||||||
//! \endcond
|
|
||||||
|
|
||||||
//! \name Members
|
//! \name Members
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
size_t _itemCount;
|
size_t _itemCount;
|
||||||
size_t _repeatCount;
|
size_t _repeatCount;
|
||||||
|
|
||||||
union {
|
|
||||||
uint8_t* _externalData;
|
|
||||||
uint8_t _inlineData[kInlineBufferSize];
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `EmbedDataNode` instance.
|
//! Creates a new `EmbedDataNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG EmbedDataNode(BaseBuilder* cb) noexcept
|
ASMJIT_INLINE_NODEBUG EmbedDataNode(TypeId typeId, uint8_t typeSize, size_t itemCount, size_t repeatCount) noexcept
|
||||||
: BaseNode(cb, NodeType::kEmbedData, NodeFlags::kIsData),
|
: BaseNode(NodeType::kEmbedData, NodeFlags::kIsData),
|
||||||
_itemCount(0),
|
_itemCount(itemCount),
|
||||||
_repeatCount(0) {
|
_repeatCount(repeatCount) {
|
||||||
_embed._typeId = TypeId::kUInt8;
|
_embed._typeId = typeId;
|
||||||
_embed._typeSize = uint8_t(1);
|
_embed._typeSize = typeSize;
|
||||||
memset(_inlineData, 0, kInlineBufferSize);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -1347,16 +1333,15 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t typeSize() const noexcept { return _embed._typeSize; }
|
ASMJIT_INLINE_NODEBUG uint32_t typeSize() const noexcept { return _embed._typeSize; }
|
||||||
|
|
||||||
//! Returns a pointer to the data casted to `uint8_t`.
|
//! Returns a pointer to the data casted to `T*` - `uint8_t*` by default.
|
||||||
|
template<typename T = uint8_t>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint8_t* data() const noexcept {
|
ASMJIT_INLINE_NODEBUG uint8_t* data() noexcept { return Support::offsetPtr<T>(this, sizeof(EmbedDataNode)); }
|
||||||
return dataSize() <= kInlineBufferSize ? const_cast<uint8_t*>(_inlineData) : _externalData;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns a pointer to the data casted to `T`.
|
//! Returns a pointer to the data casted to `T*` - `const uint8_t*` by default (const).
|
||||||
template<typename T>
|
template<typename T = uint8_t>
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG T* dataAs() const noexcept { return reinterpret_cast<T*>(data()); }
|
ASMJIT_INLINE_NODEBUG const uint8_t* data() const noexcept { return Support::offsetPtr<T>(this, sizeof(EmbedDataNode)); }
|
||||||
|
|
||||||
//! Returns the number of (typed) items in the array.
|
//! Returns the number of (typed) items in the array.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -1372,7 +1357,7 @@ public:
|
|||||||
//!
|
//!
|
||||||
//! \note The returned value is the same as `typeSize() * itemCount()`.
|
//! \note The returned value is the same as `typeSize() * itemCount()`.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG size_t dataSize() const noexcept { return typeSize() * _itemCount; }
|
ASMJIT_INLINE_NODEBUG size_t dataSize() const noexcept { return size_t(typeSize()) * _itemCount; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
@@ -1394,8 +1379,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `EmbedLabelNode` instance.
|
//! Creates a new `EmbedLabelNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t dataSize = 0) noexcept
|
ASMJIT_INLINE_NODEBUG EmbedLabelNode(uint32_t labelId = 0, uint32_t dataSize = 0) noexcept
|
||||||
: BaseNode(cb, NodeType::kEmbedLabel, NodeFlags::kIsData),
|
: BaseNode(NodeType::kEmbedLabel, NodeFlags::kIsData),
|
||||||
_labelId(labelId),
|
_labelId(labelId),
|
||||||
_dataSize(dataSize) {}
|
_dataSize(dataSize) {}
|
||||||
|
|
||||||
@@ -1446,8 +1431,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `EmbedLabelDeltaNode` instance.
|
//! Creates a new `EmbedLabelDeltaNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept
|
ASMJIT_INLINE_NODEBUG EmbedLabelDeltaNode(uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept
|
||||||
: BaseNode(cb, NodeType::kEmbedLabelDelta, NodeFlags::kIsData),
|
: BaseNode(NodeType::kEmbedLabelDelta, NodeFlags::kIsData),
|
||||||
_labelId(labelId),
|
_labelId(labelId),
|
||||||
_baseLabelId(baseLabelId),
|
_baseLabelId(baseLabelId),
|
||||||
_dataSize(dataSize) {}
|
_dataSize(dataSize) {}
|
||||||
@@ -1510,13 +1495,13 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `ConstPoolNode` instance.
|
//! Creates a new `ConstPoolNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG ConstPoolNode(BaseBuilder* cb, uint32_t id = 0) noexcept
|
ASMJIT_INLINE_NODEBUG ConstPoolNode(Zone* zone, uint32_t id = 0) noexcept
|
||||||
: LabelNode(cb, id),
|
: LabelNode(id),
|
||||||
_constPool(&cb->_codeZone) {
|
_constPool(zone) {
|
||||||
|
|
||||||
setType(NodeType::kConstPool);
|
_setType(NodeType::kConstPool);
|
||||||
addFlags(NodeFlags::kIsData);
|
_addFlags(NodeFlags::kIsData);
|
||||||
clearFlags(NodeFlags::kIsCode | NodeFlags::kHasNoEffect);
|
_clearFlags(NodeFlags::kIsCode | NodeFlags::kHasNoEffect);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -1566,8 +1551,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `CommentNode` instance.
|
//! Creates a new `CommentNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG CommentNode(BaseBuilder* cb, const char* comment) noexcept
|
ASMJIT_INLINE_NODEBUG CommentNode(const char* comment) noexcept
|
||||||
: BaseNode(cb, NodeType::kComment, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect | NodeFlags::kIsRemovable) {
|
: BaseNode(NodeType::kComment, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect | NodeFlags::kIsRemovable) {
|
||||||
_inlineComment = comment;
|
_inlineComment = comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1586,8 +1571,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `SentinelNode` instance.
|
//! Creates a new `SentinelNode` instance.
|
||||||
ASMJIT_INLINE_NODEBUG SentinelNode(BaseBuilder* cb, SentinelType sentinelType = SentinelType::kUnknown) noexcept
|
ASMJIT_INLINE_NODEBUG SentinelNode(SentinelType sentinelType = SentinelType::kUnknown) noexcept
|
||||||
: BaseNode(cb, NodeType::kSentinel, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect) {
|
: BaseNode(NodeType::kSentinel, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect) {
|
||||||
|
|
||||||
_sentinel._sentinelType = sentinelType;
|
_sentinel._sentinelType = sentinelType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_BUILDER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_BUILDER_P_H_INCLUDED
|
||||||
@@ -18,8 +18,9 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
static inline void BaseBuilder_assignInlineComment(BaseBuilder* self, BaseNode* node, const char* comment) noexcept {
|
static inline void BaseBuilder_assignInlineComment(BaseBuilder* self, BaseNode* node, const char* comment) noexcept {
|
||||||
if (comment)
|
if (comment) {
|
||||||
node->setInlineComment(static_cast<char*>(self->_dataZone.dup(comment, strlen(comment), true)));
|
node->setInlineComment(static_cast<char*>(self->_codeZone.dup(comment, strlen(comment), true)));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void BaseBuilder_assignInstState(BaseBuilder* self, InstNode* node, const BaseEmitter::State& state) noexcept {
|
static inline void BaseBuilder_assignInstState(BaseBuilder* self, InstNode* node, const BaseEmitter::State& state) noexcept {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -258,7 +258,7 @@ bool CodeWriterUtils::writeOffset(void* dst, int64_t offset64, const OffsetForma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::writeU8(dst, uint8_t(Support::readU8(dst) | mask));
|
Support::store_u8(dst, uint8_t(Support::load_u8(dst) | mask));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -268,7 +268,7 @@ bool CodeWriterUtils::writeOffset(void* dst, int64_t offset64, const OffsetForma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::writeU16uLE(dst, uint16_t(Support::readU16uLE(dst) | mask));
|
Support::storeu_u16_le(dst, uint16_t(Support::loadu_u16_le(dst) | mask));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -278,7 +278,7 @@ bool CodeWriterUtils::writeOffset(void* dst, int64_t offset64, const OffsetForma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::writeU32uLE(dst, Support::readU32uLE(dst) | mask);
|
Support::storeu_u32_le(dst, Support::loadu_u32_le(dst) | mask);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ bool CodeWriterUtils::writeOffset(void* dst, int64_t offset64, const OffsetForma
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::writeU64uLE(dst, Support::readU64uLE(dst) | mask);
|
Support::storeu_u64_le(dst, Support::loadu_u64_le(dst) | mask);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
||||||
@@ -70,28 +70,28 @@ public:
|
|||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit16uLE(T val) noexcept {
|
ASMJIT_INLINE void emit16uLE(T val) noexcept {
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
Support::writeU16uLE(_cursor, uint16_t(U(val) & 0xFFFFu));
|
Support::storeu_u16_le(_cursor, uint16_t(U(val) & 0xFFFFu));
|
||||||
_cursor += 2;
|
_cursor += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit16uBE(T val) noexcept {
|
ASMJIT_INLINE void emit16uBE(T val) noexcept {
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
Support::writeU16uBE(_cursor, uint16_t(U(val) & 0xFFFFu));
|
Support::storeu_u16_be(_cursor, uint16_t(U(val) & 0xFFFFu));
|
||||||
_cursor += 2;
|
_cursor += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit32uLE(T val) noexcept {
|
ASMJIT_INLINE void emit32uLE(T val) noexcept {
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
Support::writeU32uLE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
Support::storeu_u32_le(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
||||||
_cursor += 4;
|
_cursor += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit32uBE(T val) noexcept {
|
ASMJIT_INLINE void emit32uBE(T val) noexcept {
|
||||||
using U = std::make_unsigned_t<T>;
|
using U = std::make_unsigned_t<T>;
|
||||||
Support::writeU32uBE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
Support::storeu_u32_be(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
||||||
_cursor += 4;
|
_cursor += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -51,7 +51,6 @@ public:
|
|||||||
BaseCompiler::BaseCompiler() noexcept
|
BaseCompiler::BaseCompiler() noexcept
|
||||||
: BaseBuilder(),
|
: BaseBuilder(),
|
||||||
_func(nullptr),
|
_func(nullptr),
|
||||||
_vRegZone(4u * 1024u),
|
|
||||||
_vRegArray(),
|
_vRegArray(),
|
||||||
_constPools { nullptr, nullptr } {
|
_constPools { nullptr, nullptr } {
|
||||||
_emitterType = EmitterType::kCompiler;
|
_emitterType = EmitterType::kCompiler;
|
||||||
@@ -66,7 +65,7 @@ Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature)
|
|||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
// Create FuncNode together with all the required surrounding nodes.
|
// Create FuncNode together with all the required surrounding nodes.
|
||||||
FuncNode* funcNode;
|
FuncNode* funcNode = nullptr;
|
||||||
ASMJIT_PROPAGATE(_newNodeT<FuncNode>(&funcNode));
|
ASMJIT_PROPAGATE(_newNodeT<FuncNode>(&funcNode));
|
||||||
ASMJIT_PROPAGATE(newLabelNode(&funcNode->_exitNode));
|
ASMJIT_PROPAGATE(newLabelNode(&funcNode->_exitNode));
|
||||||
ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelType::kFuncEnd));
|
ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelType::kFuncEnd));
|
||||||
@@ -94,7 +93,7 @@ Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature)
|
|||||||
// Allocate space for function arguments.
|
// Allocate space for function arguments.
|
||||||
funcNode->_args = nullptr;
|
funcNode->_args = nullptr;
|
||||||
if (funcNode->argCount() != 0) {
|
if (funcNode->argCount() != 0) {
|
||||||
funcNode->_args = _allocator.allocT<FuncNode::ArgPack>(funcNode->argCount() * sizeof(FuncNode::ArgPack));
|
funcNode->_args = _codeZone.alloc<FuncNode::ArgPack>(funcNode->argCount() * sizeof(FuncNode::ArgPack));
|
||||||
if (ASMJIT_UNLIKELY(!funcNode->_args)) {
|
if (ASMJIT_UNLIKELY(!funcNode->_args)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
@@ -121,7 +120,7 @@ Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature)
|
|||||||
|
|
||||||
Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
|
Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
|
||||||
uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u;
|
uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u;
|
||||||
FuncRetNode* node;
|
FuncRetNode* node = nullptr;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<FuncRetNode>(&node));
|
ASMJIT_PROPAGATE(_newNodeT<FuncRetNode>(&node));
|
||||||
ASMJIT_ASSUME(node != nullptr);
|
ASMJIT_ASSUME(node != nullptr);
|
||||||
@@ -188,7 +187,7 @@ Error BaseCompiler::endFunc() {
|
|||||||
// ==================================
|
// ==================================
|
||||||
|
|
||||||
Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
|
Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
|
||||||
InvokeNode* node;
|
InvokeNode* node = nullptr;
|
||||||
ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, InstOptions::kNone));
|
ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, InstOptions::kNone));
|
||||||
|
|
||||||
node->setOpCount(1);
|
node->setOpCount(1);
|
||||||
@@ -203,7 +202,7 @@ Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand
|
|||||||
// Skip the allocation if there are no arguments.
|
// Skip the allocation if there are no arguments.
|
||||||
uint32_t argCount = signature.argCount();
|
uint32_t argCount = signature.argCount();
|
||||||
if (argCount) {
|
if (argCount) {
|
||||||
node->_args = static_cast<InvokeNode::OperandPack*>(_allocator.alloc(argCount * sizeof(InvokeNode::OperandPack)));
|
node->_args = _codeZone.alloc<InvokeNode::OperandPack>(argCount * sizeof(InvokeNode::OperandPack));
|
||||||
if (!node->_args) {
|
if (!node->_args) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
@@ -228,16 +227,6 @@ Error BaseCompiler::addInvokeNode(InvokeNode** out, InstId instId, const Operand
|
|||||||
// BaseCompiler - Virtual Registers
|
// BaseCompiler - Virtual Registers
|
||||||
// ================================
|
// ================================
|
||||||
|
|
||||||
static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
|
|
||||||
uint32_t index = unsigned(Operand::virtIdToIndex(vReg->_id));
|
|
||||||
|
|
||||||
char buf[64];
|
|
||||||
int size = snprintf(buf, ASMJIT_ARRAY_SIZE(buf), "%%%u", unsigned(index));
|
|
||||||
|
|
||||||
ASMJIT_ASSERT(size > 0 && size < int(ASMJIT_ARRAY_SIZE(buf)));
|
|
||||||
vReg->_name.setData(&self->_dataZone, buf, unsigned(size));
|
|
||||||
}
|
|
||||||
|
|
||||||
Error BaseCompiler::newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name) {
|
Error BaseCompiler::newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
uint32_t index = _vRegArray.size();
|
uint32_t index = _vRegArray.size();
|
||||||
@@ -250,22 +239,18 @@ Error BaseCompiler::newVirtReg(VirtReg** out, TypeId typeId, OperandSignature si
|
|||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtReg* vReg = _vRegZone.allocZeroedT<VirtReg>();
|
void* vRegPtr = _codeZone.alloc(Zone::alignedSizeOf<VirtReg>());
|
||||||
if (ASMJIT_UNLIKELY(!vReg)) {
|
if (ASMJIT_UNLIKELY(!vRegPtr)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t size = TypeUtils::sizeOf(typeId);
|
uint32_t size = TypeUtils::sizeOf(typeId);
|
||||||
uint32_t alignment = Support::min<uint32_t>(size, 64);
|
uint32_t alignment = Support::min<uint32_t>(size, 64);
|
||||||
|
VirtReg* vReg = new(Support::PlacementNew{vRegPtr}) VirtReg(signature, Operand::indexToVirtId(index), size, alignment, typeId);
|
||||||
vReg = new(Support::PlacementNew{vReg}) VirtReg(signature, Operand::indexToVirtId(index), size, alignment, typeId);
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (name && name[0] != '\0') {
|
if (name && name[0] != '\0') {
|
||||||
vReg->_name.setData(&_dataZone, name, SIZE_MAX);
|
vReg->_name.setData(&_codeZone, name, SIZE_MAX);
|
||||||
}
|
|
||||||
else {
|
|
||||||
BaseCompiler_assignGenericName(this, vReg);
|
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
DebugUtils::unused(name);
|
DebugUtils::unused(name);
|
||||||
@@ -277,7 +262,7 @@ Error BaseCompiler::newVirtReg(VirtReg** out, TypeId typeId, OperandSignature si
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) {
|
Error BaseCompiler::_newReg(Reg* out, TypeId typeId, const char* name) {
|
||||||
OperandSignature regSignature;
|
OperandSignature regSignature;
|
||||||
out->reset();
|
out->reset();
|
||||||
|
|
||||||
@@ -294,7 +279,7 @@ Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...) {
|
Error BaseCompiler::_newRegFmt(Reg* out, TypeId typeId, const char* fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
|
|
||||||
@@ -305,7 +290,7 @@ Error BaseCompiler::_newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...
|
|||||||
return _newReg(out, typeId, sb.data());
|
return _newReg(out, typeId, sb.data());
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) {
|
Error BaseCompiler::_newReg(Reg* out, const Reg& ref, const char* name) {
|
||||||
out->reset();
|
out->reset();
|
||||||
|
|
||||||
OperandSignature regSignature;
|
OperandSignature regSignature;
|
||||||
@@ -364,7 +349,7 @@ Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typeId = ArchTraits::byArch(arch()).regTypeToTypeId(ref.type());
|
typeId = RegUtils::typeIdOf(ref.regType());
|
||||||
}
|
}
|
||||||
|
|
||||||
Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
|
Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
|
||||||
@@ -380,7 +365,7 @@ Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name)
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt, ...) {
|
Error BaseCompiler::_newRegFmt(Reg* out, const Reg& ref, const char* fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
|
|
||||||
@@ -394,20 +379,16 @@ Error BaseCompiler::_newRegFmt(BaseReg* out, const BaseReg& ref, const char* fmt
|
|||||||
Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) {
|
Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, const char* name) {
|
||||||
out->reset();
|
out->reset();
|
||||||
|
|
||||||
if (size == 0) {
|
if (ASMJIT_UNLIKELY(Support::bool_or(size == 0, !Support::isZeroOrPowerOf2(alignment)))) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alignment == 0) {
|
if (alignment == 0u) {
|
||||||
alignment = 1;
|
alignment = 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Support::isPowerOf2(alignment)) {
|
if (alignment > 64u) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
alignment = 64u;
|
||||||
}
|
|
||||||
|
|
||||||
if (alignment > 64) {
|
|
||||||
alignment = 64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtReg* vReg;
|
VirtReg* vReg;
|
||||||
@@ -431,12 +412,12 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new
|
|||||||
return DebugUtils::errored(kErrorInvalidVirtId);
|
return DebugUtils::errored(kErrorInvalidVirtId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newAlignment && !Support::isPowerOf2(newAlignment)) {
|
if (!Support::isZeroOrPowerOf2(newAlignment)) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newAlignment > 64) {
|
if (newAlignment > 64u) {
|
||||||
newAlignment = 64;
|
newAlignment = 64u;
|
||||||
}
|
}
|
||||||
|
|
||||||
VirtReg* vReg = virtRegById(virtId);
|
VirtReg* vReg = virtRegById(virtId);
|
||||||
@@ -485,7 +466,7 @@ Error BaseCompiler::_newConst(BaseMem* out, ConstPoolScope scope, const void* da
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
|
void BaseCompiler::rename(const Reg& reg, const char* fmt, ...) {
|
||||||
if (!reg.isVirtReg()) return;
|
if (!reg.isVirtReg()) return;
|
||||||
|
|
||||||
VirtReg* vReg = virtRegById(reg.id());
|
VirtReg* vReg = virtRegById(reg.id());
|
||||||
@@ -501,10 +482,7 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
|
|||||||
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
|
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
vReg->_name.setData(&_dataZone, buf, SIZE_MAX);
|
vReg->_name.setData(&_codeZone, buf, SIZE_MAX);
|
||||||
}
|
|
||||||
else {
|
|
||||||
BaseCompiler_assignGenericName(this, vReg);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -512,15 +490,15 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
|
|||||||
// ===============================
|
// ===============================
|
||||||
|
|
||||||
Error BaseCompiler::newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation) {
|
Error BaseCompiler::newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation) {
|
||||||
JumpNode* node = _allocator.allocT<JumpNode>();
|
JumpNode* node = _codeZone.alloc<JumpNode>();
|
||||||
uint32_t opCount = 1;
|
|
||||||
|
|
||||||
*out = node;
|
*out = node;
|
||||||
if (ASMJIT_UNLIKELY(!node)) {
|
if (ASMJIT_UNLIKELY(!node)) {
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
}
|
}
|
||||||
|
|
||||||
node = new(Support::PlacementNew{node}) JumpNode(this, instId, instOptions, opCount, annotation);
|
uint32_t opCount = 1;
|
||||||
|
node = new(Support::PlacementNew{node}) JumpNode(instId, instOptions, opCount, annotation);
|
||||||
node->setOp(0, o0);
|
node->setOp(0, o0);
|
||||||
node->resetOpRange(opCount, JumpNode::kBaseOpCapacity);
|
node->resetOpRange(opCount, JumpNode::kBaseOpCapacity);
|
||||||
|
|
||||||
@@ -547,7 +525,7 @@ JumpAnnotation* BaseCompiler::newJumpAnnotation() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t id = _jumpAnnotations.size();
|
uint32_t id = _jumpAnnotations.size();
|
||||||
JumpAnnotation* jumpAnnotation = _allocator.newT<JumpAnnotation>(this, id);
|
JumpAnnotation* jumpAnnotation = _codeZone.newT<JumpAnnotation>(this, id);
|
||||||
|
|
||||||
if (!jumpAnnotation) {
|
if (!jumpAnnotation) {
|
||||||
reportError(DebugUtils::errored(kErrorOutOfMemory));
|
reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
@@ -561,33 +539,49 @@ JumpAnnotation* BaseCompiler::newJumpAnnotation() {
|
|||||||
// BaseCompiler - Events
|
// BaseCompiler - Events
|
||||||
// =====================
|
// =====================
|
||||||
|
|
||||||
Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
|
static ASMJIT_INLINE void BaseCompiler_clear(BaseCompiler* self) noexcept {
|
||||||
|
self->_func = nullptr;
|
||||||
|
self->_constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
|
||||||
|
self->_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
|
||||||
|
self->_vRegArray.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
static ASMJIT_INLINE Error BaseCompiler_initDefaultPasses(BaseCompiler* self) noexcept {
|
||||||
|
return self->addPassT<GlobalConstPoolPass>();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Error BaseCompiler::onAttach(CodeHolder& code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
Error err = BaseCompiler_initDefaultPasses(this);
|
||||||
RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
|
|
||||||
_gpSignature = archTraits.regTypeToSignature(nativeRegType);
|
|
||||||
|
|
||||||
Error err = addPassT<GlobalConstPoolPass>();
|
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
onDetach(code);
|
onDetach(code);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
|
Error BaseCompiler::onDetach(CodeHolder& code) noexcept {
|
||||||
_func = nullptr;
|
BaseCompiler_clear(this);
|
||||||
_constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
|
|
||||||
_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
|
|
||||||
|
|
||||||
_vRegArray.reset();
|
|
||||||
_vRegZone.reset();
|
|
||||||
|
|
||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error BaseCompiler::onReinit(CodeHolder& code) noexcept {
|
||||||
|
BaseCompiler_clear(this);
|
||||||
|
Error err = Base::onReinit(code);
|
||||||
|
|
||||||
|
if (ASMJIT_LIKELY(err == kErrorOk)) {
|
||||||
|
err = BaseCompiler_initDefaultPasses(this);
|
||||||
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
|
onDetach(code);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
// FuncPass - Construction & Destruction
|
// FuncPass - Construction & Destruction
|
||||||
// =====================================
|
// =====================================
|
||||||
|
|
||||||
@@ -599,9 +593,8 @@ FuncPass::FuncPass(const char* name) noexcept
|
|||||||
|
|
||||||
Error FuncPass::run(Zone* zone, Logger* logger) {
|
Error FuncPass::run(Zone* zone, Logger* logger) {
|
||||||
BaseNode* node = cb()->firstNode();
|
BaseNode* node = cb()->firstNode();
|
||||||
if (!node) return kErrorOk;
|
|
||||||
|
|
||||||
do {
|
while (node) {
|
||||||
if (node->type() == NodeType::kFunc) {
|
if (node->type() == NodeType::kFunc) {
|
||||||
FuncNode* func = node->as<FuncNode>();
|
FuncNode* func = node->as<FuncNode>();
|
||||||
node = func->endNode();
|
node = func->endNode();
|
||||||
@@ -612,7 +605,7 @@ Error FuncPass::run(Zone* zone, Logger* logger) {
|
|||||||
do {
|
do {
|
||||||
node = node->next();
|
node = node->next();
|
||||||
} while (node && node->type() != NodeType::kFunc);
|
} while (node && node->type() != NodeType::kFunc);
|
||||||
} while (node);
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
|
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
|
||||||
@@ -58,8 +58,6 @@ public:
|
|||||||
|
|
||||||
//! Current function.
|
//! Current function.
|
||||||
FuncNode* _func;
|
FuncNode* _func;
|
||||||
//! Allocates `VirtReg` objects.
|
|
||||||
Zone _vRegZone;
|
|
||||||
//! Stores array of `VirtReg` pointers.
|
//! Stores array of `VirtReg` pointers.
|
||||||
ZoneVector<VirtReg*> _vRegArray;
|
ZoneVector<VirtReg*> _vRegArray;
|
||||||
//! Stores jump annotations.
|
//! Stores jump annotations.
|
||||||
@@ -146,22 +144,22 @@ public:
|
|||||||
ASMJIT_API Error newVirtReg(VirtReg** ASMJIT_NONNULL(out), TypeId typeId, OperandSignature signature, const char* name);
|
ASMJIT_API Error newVirtReg(VirtReg** ASMJIT_NONNULL(out), TypeId typeId, OperandSignature signature, const char* name);
|
||||||
|
|
||||||
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
|
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
|
||||||
ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* name = nullptr);
|
ASMJIT_API Error _newReg(Reg* ASMJIT_NONNULL(out), TypeId typeId, const char* name = nullptr);
|
||||||
|
|
||||||
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
|
//! Creates a new virtual register of the given `typeId` and stores it to `out` operand.
|
||||||
//!
|
//!
|
||||||
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
|
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
|
||||||
ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId, const char* fmt, ...);
|
ASMJIT_API Error _newRegFmt(Reg* ASMJIT_NONNULL(out), TypeId typeId, const char* fmt, ...);
|
||||||
//! \overload
|
//! \overload
|
||||||
inline Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), TypeId typeId) { return _newRegFmt(out, typeId, nullptr); }
|
inline Error _newRegFmt(Reg* ASMJIT_NONNULL(out), TypeId typeId) { return _newRegFmt(out, typeId, nullptr); }
|
||||||
|
|
||||||
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
||||||
ASMJIT_API Error _newReg(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* name = nullptr);
|
ASMJIT_API Error _newReg(Reg* ASMJIT_NONNULL(out), const Reg& ref, const char* name = nullptr);
|
||||||
|
|
||||||
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
//! Creates a new virtual register compatible with the provided reference register `ref`.
|
||||||
//!
|
//!
|
||||||
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
|
//! \note This version accepts a snprintf() format `fmt` followed by a variadic arguments.
|
||||||
ASMJIT_API Error _newRegFmt(BaseReg* ASMJIT_NONNULL(out), const BaseReg& ref, const char* fmt, ...);
|
ASMJIT_API Error _newRegFmt(Reg* ASMJIT_NONNULL(out), const Reg& ref, const char* fmt, ...);
|
||||||
|
|
||||||
//! Tests whether the given `id` is a valid virtual register id.
|
//! Tests whether the given `id` is a valid virtual register id.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -172,7 +170,7 @@ public:
|
|||||||
|
|
||||||
//! Tests whether the given `reg` is a virtual register having a valid id.
|
//! Tests whether the given `reg` is a virtual register having a valid id.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool isVirtRegValid(const BaseReg& reg) const noexcept {
|
ASMJIT_INLINE_NODEBUG bool isVirtRegValid(const Reg& reg) const noexcept {
|
||||||
return isVirtIdValid(reg.id());
|
return isVirtIdValid(reg.id());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,7 +183,7 @@ public:
|
|||||||
|
|
||||||
//! Returns \ref VirtReg associated with the given `reg`.
|
//! Returns \ref VirtReg associated with the given `reg`.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG VirtReg* virtRegByReg(const BaseReg& reg) const noexcept { return virtRegById(reg.id()); }
|
ASMJIT_INLINE_NODEBUG VirtReg* virtRegByReg(const Reg& reg) const noexcept { return virtRegById(reg.id()); }
|
||||||
|
|
||||||
//! Returns \ref VirtReg associated with the given virtual register `index`.
|
//! Returns \ref VirtReg associated with the given virtual register `index`.
|
||||||
//!
|
//!
|
||||||
@@ -231,7 +229,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Rename the given virtual register `reg` to a formatted string `fmt`.
|
//! Rename the given virtual register `reg` to a formatted string `fmt`.
|
||||||
ASMJIT_API void rename(const BaseReg& reg, const char* fmt, ...);
|
ASMJIT_API void rename(const Reg& reg, const char* fmt, ...);
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -256,8 +254,9 @@ public:
|
|||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onAttach(CodeHolder& code) noexcept override;
|
||||||
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
|
ASMJIT_API Error onDetach(CodeHolder& code) noexcept override;
|
||||||
|
ASMJIT_API Error onReinit(CodeHolder& code) noexcept override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
@@ -348,10 +347,10 @@ public:
|
|||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline JumpNode(BaseCompiler* ASMJIT_NONNULL(cc), InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept
|
inline JumpNode(InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept
|
||||||
: InstNodeWithOperands(cc, instId, options, opCount),
|
: InstNodeWithOperands(instId, options, opCount),
|
||||||
_annotation(annotation) {
|
_annotation(annotation) {
|
||||||
setType(NodeType::kJump);
|
_setType(NodeType::kJump);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -452,14 +451,14 @@ public:
|
|||||||
//! Creates a new `FuncNode` instance.
|
//! Creates a new `FuncNode` instance.
|
||||||
//!
|
//!
|
||||||
//! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`.
|
//! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`.
|
||||||
inline FuncNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept
|
inline explicit FuncNode(uint32_t labelId = Globals::kInvalidId) noexcept
|
||||||
: LabelNode(cb),
|
: LabelNode(labelId),
|
||||||
_funcDetail(),
|
_funcDetail(),
|
||||||
_frame(),
|
_frame(),
|
||||||
_exitNode(nullptr),
|
_exitNode(nullptr),
|
||||||
_end(nullptr),
|
_end(nullptr),
|
||||||
_args(nullptr) {
|
_args(nullptr) {
|
||||||
setType(NodeType::kFunc);
|
_setType(NodeType::kFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -522,7 +521,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Sets argument at `argIndex`.
|
//! Sets argument at `argIndex`.
|
||||||
inline void setArg(size_t argIndex, const BaseReg& vReg) noexcept {
|
inline void setArg(size_t argIndex, const Reg& vReg) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
_args[argIndex][0].init(vReg);
|
_args[argIndex][0].init(vReg);
|
||||||
}
|
}
|
||||||
@@ -534,7 +533,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Sets argument at `argIndex` and `valueIndex`.
|
//! Sets argument at `argIndex` and `valueIndex`.
|
||||||
inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& vReg) noexcept {
|
inline void setArg(size_t argIndex, size_t valueIndex, const Reg& vReg) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
_args[argIndex][valueIndex].init(vReg);
|
_args[argIndex][valueIndex].init(vReg);
|
||||||
}
|
}
|
||||||
@@ -569,9 +568,9 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `FuncRetNode` instance.
|
//! Creates a new `FuncRetNode` instance.
|
||||||
inline FuncRetNode(BaseBuilder* ASMJIT_NONNULL(cb)) noexcept
|
inline FuncRetNode() noexcept
|
||||||
: InstNodeWithOperands(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) {
|
: InstNodeWithOperands(BaseInst::kIdAbstract, InstOptions::kNone, 0) {
|
||||||
_any._nodeType = NodeType::kFuncRet;
|
_nodeType = NodeType::kFuncRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -626,14 +625,14 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `InvokeNode` instance.
|
//! Creates a new `InvokeNode` instance.
|
||||||
inline InvokeNode(BaseBuilder* ASMJIT_NONNULL(cb), InstId instId, InstOptions options) noexcept
|
inline InvokeNode(InstId instId, InstOptions options) noexcept
|
||||||
: InstNodeWithOperands(cb, instId, options, 0),
|
: InstNodeWithOperands(instId, options, 0),
|
||||||
_funcDetail(),
|
_funcDetail(),
|
||||||
_args(nullptr) {
|
_args(nullptr) {
|
||||||
setType(NodeType::kInvoke);
|
_setType(NodeType::kInvoke);
|
||||||
_resetOps();
|
_resetOps();
|
||||||
_rets.reset();
|
_rets.reset();
|
||||||
addFlags(NodeFlags::kIsRemovable);
|
_addFlags(NodeFlags::kIsRemovable);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -724,15 +723,15 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Sets the function return value at `valueIndex` to `reg`.
|
//! Sets the function return value at `valueIndex` to `reg`.
|
||||||
ASMJIT_INLINE_NODEBUG void setRet(size_t valueIndex, const BaseReg& reg) noexcept { _setRet(valueIndex, reg); }
|
ASMJIT_INLINE_NODEBUG void setRet(size_t valueIndex, const Reg& reg) noexcept { _setRet(valueIndex, reg); }
|
||||||
|
|
||||||
//! Sets the first function argument in a value-pack at `argIndex` to `reg`.
|
//! Sets the first function argument in a value-pack at `argIndex` to `reg`.
|
||||||
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, const BaseReg& reg) noexcept { _setArg(argIndex, 0, reg); }
|
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, const Reg& reg) noexcept { _setArg(argIndex, 0, reg); }
|
||||||
//! Sets the first function argument in a value-pack at `argIndex` to `imm`.
|
//! Sets the first function argument in a value-pack at `argIndex` to `imm`.
|
||||||
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); }
|
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, const Imm& imm) noexcept { _setArg(argIndex, 0, imm); }
|
||||||
|
|
||||||
//! Sets the function argument at `argIndex` and `valueIndex` to `reg`.
|
//! Sets the function argument at `argIndex` and `valueIndex` to `reg`.
|
||||||
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) noexcept { _setArg(argIndex, valueIndex, reg); }
|
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, size_t valueIndex, const Reg& reg) noexcept { _setArg(argIndex, valueIndex, reg); }
|
||||||
//! Sets the function argument at `argIndex` and `valueIndex` to `imm`.
|
//! Sets the function argument at `argIndex` and `valueIndex` to `imm`.
|
||||||
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); }
|
ASMJIT_INLINE_NODEBUG void setArg(size_t argIndex, size_t valueIndex, const Imm& imm) noexcept { _setArg(argIndex, valueIndex, imm); }
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
||||||
@@ -57,7 +57,7 @@ public:
|
|||||||
uint8_t _hasStackSlot : 1;
|
uint8_t _hasStackSlot : 1;
|
||||||
uint8_t _reservedBits : 5;
|
uint8_t _reservedBits : 5;
|
||||||
//! Home register hint for the register allocator (initially unassigned).
|
//! Home register hint for the register allocator (initially unassigned).
|
||||||
uint8_t _homeIdHint = BaseReg::kIdBad;
|
uint8_t _homeIdHint = Reg::kIdBad;
|
||||||
|
|
||||||
//! Stack offset assigned by the register allocator relative to stack pointer (can be negative as well).
|
//! Stack offset assigned by the register allocator relative to stack pointer (can be negative as well).
|
||||||
int32_t _stackOffset = 0;
|
int32_t _stackOffset = 0;
|
||||||
@@ -65,7 +65,7 @@ public:
|
|||||||
//! Reserved for future use (padding).
|
//! Reserved for future use (padding).
|
||||||
uint32_t _reservedU32 = 0;
|
uint32_t _reservedU32 = 0;
|
||||||
|
|
||||||
//! Virtual register name (user provided or automatically generated).
|
//! Virtual register name (either empty or user provided).
|
||||||
ZoneString<16> _name {};
|
ZoneString<16> _name {};
|
||||||
|
|
||||||
// The following members are used exclusively by RAPass. They are initialized when the VirtReg is created to
|
// The following members are used exclusively by RAPass. They are initialized when the VirtReg is created to
|
||||||
@@ -178,7 +178,7 @@ public:
|
|||||||
|
|
||||||
//! Tests whether this virtual register has assigned a physical register as a hint to the register allocator.
|
//! Tests whether this virtual register has assigned a physical register as a hint to the register allocator.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasHomeIdHint() const noexcept { return _homeIdHint != BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG bool hasHomeIdHint() const noexcept { return _homeIdHint != Reg::kIdBad; }
|
||||||
|
|
||||||
//! Returns a physical register hint, which will be used by the register allocator.
|
//! Returns a physical register hint, which will be used by the register allocator.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -187,7 +187,7 @@ public:
|
|||||||
//! Assigns a physical register hint, which will be used by the register allocator.
|
//! Assigns a physical register hint, which will be used by the register allocator.
|
||||||
ASMJIT_INLINE_NODEBUG void setHomeIdHint(uint32_t homeId) noexcept { _homeIdHint = uint8_t(homeId); }
|
ASMJIT_INLINE_NODEBUG void setHomeIdHint(uint32_t homeId) noexcept { _homeIdHint = uint8_t(homeId); }
|
||||||
//! Resets a physical register hint.
|
//! Resets a physical register hint.
|
||||||
ASMJIT_INLINE_NODEBUG void resetHomeIdHint() noexcept { _homeIdHint = BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG void resetHomeIdHint() noexcept { _homeIdHint = Reg::kIdBad; }
|
||||||
|
|
||||||
//! Returns a stack offset associated with a virtual register or explicit stack allocation.
|
//! Returns a stack offset associated with a virtual register or explicit stack allocation.
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -40,8 +40,9 @@ void ConstPool::reset(Zone* zone) noexcept {
|
|||||||
|
|
||||||
static inline ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
|
static inline ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
|
||||||
ConstPool::Gap* gap = self->_gapPool;
|
ConstPool::Gap* gap = self->_gapPool;
|
||||||
|
|
||||||
if (!gap) {
|
if (!gap) {
|
||||||
return self->_zone->allocT<ConstPool::Gap>();
|
return self->_zone->alloc<ConstPool::Gap>();
|
||||||
}
|
}
|
||||||
|
|
||||||
self->_gapPool = gap->_next;
|
self->_gapPool = gap->_next;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
||||||
@@ -74,9 +74,10 @@ public:
|
|||||||
_offset(uint32_t(offset)) {}
|
_offset(uint32_t(offset)) {}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG void* data() const noexcept {
|
ASMJIT_INLINE_NODEBUG void* data() noexcept { return Support::offsetPtr<void>(this, sizeof(*this)); }
|
||||||
return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
|
|
||||||
}
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG const void* data() const noexcept { return Support::offsetPtr<void>(this, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Data comparer used internally.
|
//! Data comparer used internally.
|
||||||
@@ -175,8 +176,12 @@ public:
|
|||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
static inline Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
|
static inline Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) noexcept {
|
||||||
Node* node = zone->allocT<Node>(Support::alignUp(sizeof(Node) + size, alignof(Node)));
|
size_t nodeSize = Support::alignUp(sizeof(Node) + size, Globals::kZoneAlignment);
|
||||||
if (ASMJIT_UNLIKELY(!node)) return nullptr;
|
Node* node = zone->alloc<Node>(nodeSize);
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(!node)) {
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
node = new(Support::PlacementNew{node}) Node(offset, shared);
|
node = new(Support::PlacementNew{node}) Node(offset, shared);
|
||||||
memcpy(node->data(), data, size);
|
memcpy(node->data(), data, size);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -66,7 +66,7 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
// CPU features detection is a minefield on non-X86 platforms. The following list describes which
|
// CPU features detection is a minefield on non-X86 platforms. The following list describes which
|
||||||
// operating systems and architectures are supported and the status of the implementation:
|
// operating systems and architectures are supported and the status of the implementation:
|
||||||
//
|
//
|
||||||
// * X86, X86_64:
|
// * X86|X86_64:
|
||||||
// - All OSes supported
|
// - All OSes supported
|
||||||
// - Detection is based on using a CPUID instruction, which is a user-space instruction, so there
|
// - Detection is based on using a CPUID instruction, which is a user-space instruction, so there
|
||||||
// is no need to use any OS specific APIs or syscalls to detect all features provided by the CPU.
|
// is no need to use any OS specific APIs or syscalls to detect all features provided by the CPU.
|
||||||
@@ -710,7 +710,7 @@ static inline void populateBaseARMFeatures(CpuInfo& cpu) noexcept {
|
|||||||
|
|
||||||
// Populates mandatory ARMv8.[v]A features.
|
// Populates mandatory ARMv8.[v]A features.
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static ASMJIT_FAVOR_SIZE void populateARMv8AFeatures(CpuFeatures::ARM& features, uint32_t v) noexcept {
|
static ASMJIT_NOINLINE void populateARMv8AFeatures(CpuFeatures::ARM& features, uint32_t v) noexcept {
|
||||||
switch (v) {
|
switch (v) {
|
||||||
default:
|
default:
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
@@ -982,6 +982,9 @@ static inline void detectAArch64FeaturesViaCPUID_AA64ISAR2(CpuInfo& cpu, uint64_
|
|||||||
MERGE_FEATURE_4B("RPRFM bits [51:48]" , isar2, 48, Ext::kRPRFM);
|
MERGE_FEATURE_4B("RPRFM bits [51:48]" , isar2, 48, Ext::kRPRFM);
|
||||||
MERGE_FEATURE_4B("CSSC bits [55:52]" , isar2, 52, Ext::kCSSC);
|
MERGE_FEATURE_4B("CSSC bits [55:52]" , isar2, 52, Ext::kCSSC);
|
||||||
MERGE_FEATURE_4B("LUT bits [59:56]" , isar2, 56, Ext::kLUT);
|
MERGE_FEATURE_4B("LUT bits [59:56]" , isar2, 56, Ext::kLUT);
|
||||||
|
/*
|
||||||
|
MERGE_FEATURE_4B("ATS1A bits [63:60]" , isar2, 60, ...);
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: This register is not accessed at the moment.
|
// TODO: This register is not accessed at the moment.
|
||||||
@@ -995,6 +998,12 @@ static inline void detectAArch64FeaturesViaCPUID_AA64ISAR3(CpuInfo& cpu, uint64_
|
|||||||
MERGE_FEATURE_4B("CPA bits [3:0]" , isar3, 0, Ext::kCPA, Ext::kCPA2);
|
MERGE_FEATURE_4B("CPA bits [3:0]" , isar3, 0, Ext::kCPA, Ext::kCPA2);
|
||||||
MERGE_FEATURE_4B("FAMINMAX bits [7:4]" , isar3, 4, Ext::kFAMINMAX);
|
MERGE_FEATURE_4B("FAMINMAX bits [7:4]" , isar3, 4, Ext::kFAMINMAX);
|
||||||
MERGE_FEATURE_4B("TLBIW bits [11:8]" , isar3, 8, Ext::kTLBIW);
|
MERGE_FEATURE_4B("TLBIW bits [11:8]" , isar3, 8, Ext::kTLBIW);
|
||||||
|
/*
|
||||||
|
MERGE_FEATURE_4B("PACM bits [15:12]" , isar3, 12, ...);
|
||||||
|
*/
|
||||||
|
MERGE_FEATURE_4B("LSFE bits [19:16]" , isar3, 16, Ext::kLSFE);
|
||||||
|
MERGE_FEATURE_4B("OCCMO bits [23:20]" , isar3, 20, Ext::kOCCMO);
|
||||||
|
MERGE_FEATURE_4B("LSUI bits [27:24]" , isar3, 24, Ext::kLSUI);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -1080,11 +1089,12 @@ static inline void detectAArch64FeaturesViaCPUID_AA64MMFR2(CpuInfo& cpu, uint64_
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
// Detects features based on the content of ID_AA64ZFR0_EL1 register.
|
// Detects features based on the content of ID_AA64ZFR0_EL1 (SVE Feature ID register 0).
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static inline void detectAArch64FeaturesViaCPUID_AA64ZFR0(CpuInfo& cpu, uint64_t zfr0) noexcept {
|
static inline void detectAArch64FeaturesViaCPUID_AA64ZFR0(CpuInfo& cpu, uint64_t zfr0) noexcept {
|
||||||
MERGE_FEATURE_4B("SVEver bits [3:0]" , zfr0, 0, Ext::kSVE2, Ext::kSVE2_1);
|
MERGE_FEATURE_4B("SVEver bits [3:0]" , zfr0, 0, Ext::kSVE2, Ext::kSVE2_1, Ext::kSVE2_2);
|
||||||
MERGE_FEATURE_4B("AES bits [7:4]" , zfr0, 4, Ext::kSVE_AES, Ext::kSVE_PMULL128);
|
MERGE_FEATURE_4B("AES bits [7:4]" , zfr0, 4, Ext::kSVE_AES, Ext::kSVE_PMULL128);
|
||||||
|
MERGE_FEATURE_4B("EltPerm bits [15:12]" , zfr0, 12, Ext::kSVE_ELTPERM);
|
||||||
MERGE_FEATURE_4B("BitPerm bits [19:16]" , zfr0, 16, Ext::kSVE_BITPERM);
|
MERGE_FEATURE_4B("BitPerm bits [19:16]" , zfr0, 16, Ext::kSVE_BITPERM);
|
||||||
MERGE_FEATURE_4B("BF16 bits [23:20]" , zfr0, 20, Ext::kSVE_BF16, Ext::kSVE_EBF16);
|
MERGE_FEATURE_4B("BF16 bits [23:20]" , zfr0, 20, Ext::kSVE_BF16, Ext::kSVE_EBF16);
|
||||||
MERGE_FEATURE_4B("B16B16 bits [27:24]" , zfr0, 24, Ext::kSVE_B16B16);
|
MERGE_FEATURE_4B("B16B16 bits [27:24]" , zfr0, 24, Ext::kSVE_B16B16);
|
||||||
@@ -1097,7 +1107,12 @@ static inline void detectAArch64FeaturesViaCPUID_AA64ZFR0(CpuInfo& cpu, uint64_t
|
|||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
static inline void detectAArch64FeaturesViaCPUID_AA64SMFR0(CpuInfo& cpu, uint64_t smfr0) noexcept {
|
static inline void detectAArch64FeaturesViaCPUID_AA64SMFR0(CpuInfo& cpu, uint64_t smfr0) noexcept {
|
||||||
MERGE_FEATURE_1B("SF8DP2 bit [28]" , smfr0, 29, Ext::kSSVE_FP8DOT2);
|
MERGE_FEATURE_1B("SMOP4 bit [0]" , smfr0, 0, Ext::kSME_MOP4);
|
||||||
|
MERGE_FEATURE_1B("STMOP bit [16]" , smfr0, 16, Ext::kSME_TMOP);
|
||||||
|
MERGE_FEATURE_1B("SFEXPA bit [23]" , smfr0, 23, Ext::kSSVE_FEXPA);
|
||||||
|
MERGE_FEATURE_1B("AES bit [24]" , smfr0, 24, Ext::kSSVE_AES);
|
||||||
|
MERGE_FEATURE_1B("SBitPerm bit [25]" , smfr0, 25, Ext::kSSVE_BITPERM);
|
||||||
|
MERGE_FEATURE_1B("SF8DP2 bit [28]" , smfr0, 28, Ext::kSSVE_FP8DOT2);
|
||||||
MERGE_FEATURE_1B("SF8DP4 bit [29]" , smfr0, 29, Ext::kSSVE_FP8DOT4);
|
MERGE_FEATURE_1B("SF8DP4 bit [29]" , smfr0, 29, Ext::kSSVE_FP8DOT4);
|
||||||
MERGE_FEATURE_1B("SF8FMA bit [30]" , smfr0, 30, Ext::kSSVE_FP8FMA);
|
MERGE_FEATURE_1B("SF8FMA bit [30]" , smfr0, 30, Ext::kSSVE_FP8FMA);
|
||||||
MERGE_FEATURE_1B("F32F32 bit [32]" , smfr0, 32, Ext::kSME_F32F32);
|
MERGE_FEATURE_1B("F32F32 bit [32]" , smfr0, 32, Ext::kSME_F32F32);
|
||||||
@@ -1112,7 +1127,7 @@ static inline void detectAArch64FeaturesViaCPUID_AA64SMFR0(CpuInfo& cpu, uint64_
|
|||||||
MERGE_FEATURE_4S("I16I32 bits [47:44]" , smfr0, 44, 0x5, Ext::kSME_I16I32);
|
MERGE_FEATURE_4S("I16I32 bits [47:44]" , smfr0, 44, 0x5, Ext::kSME_I16I32);
|
||||||
MERGE_FEATURE_1B("F64F64 bit [48]" , smfr0, 48, Ext::kSME_F64F64);
|
MERGE_FEATURE_1B("F64F64 bit [48]" , smfr0, 48, Ext::kSME_F64F64);
|
||||||
MERGE_FEATURE_4S("I16I64 bits [55:52]" , smfr0, 52, 0xF, Ext::kSME_I16I64);
|
MERGE_FEATURE_4S("I16I64 bits [55:52]" , smfr0, 52, 0xF, Ext::kSME_I16I64);
|
||||||
MERGE_FEATURE_4B("SMEver bits [59:56]" , smfr0, 56, Ext::kSME2, Ext::kSME2_1);
|
MERGE_FEATURE_4B("SMEver bits [59:56]" , smfr0, 56, Ext::kSME2, Ext::kSME2_1, Ext::kSME2_2);
|
||||||
MERGE_FEATURE_1B("LUTv2 bit [60]" , smfr0, 60, Ext::kSME_LUTv2);
|
MERGE_FEATURE_1B("LUTv2 bit [60]" , smfr0, 60, Ext::kSME_LUTv2);
|
||||||
MERGE_FEATURE_1B("FA64 bit [63]" , smfr0, 63, Ext::kSME_FA64);
|
MERGE_FEATURE_1B("FA64 bit [63]" , smfr0, 63, Ext::kSME_FA64);
|
||||||
}
|
}
|
||||||
@@ -1138,8 +1153,16 @@ enum class AppleFamilyId : uint32_t {
|
|||||||
kVORTEX_TEMPEST = 0x07D34B9Fu, // Apple A12 (ARMv8.3-A).
|
kVORTEX_TEMPEST = 0x07D34B9Fu, // Apple A12 (ARMv8.3-A).
|
||||||
kLIGHTNING_THUNDER = 0x462504D2u, // Apple A13 (ARMv8.4-A).
|
kLIGHTNING_THUNDER = 0x462504D2u, // Apple A13 (ARMv8.4-A).
|
||||||
kFIRESTORM_ICESTORM = 0x1B588BB3u, // Apple A14/M1 (ARMv8.5-A).
|
kFIRESTORM_ICESTORM = 0x1B588BB3u, // Apple A14/M1 (ARMv8.5-A).
|
||||||
kAVALANCHE_BLIZZARD = 0XDA33D83Du, // Apple A15/M2.
|
kAVALANCHE_BLIZZARD = 0XDA33D83Du, // Apple A15/M2 (ARMv8.6-A).
|
||||||
kEVEREST_SAWTOOTH = 0X8765EDEAu // Apple A16.
|
kEVEREST_SAWTOOTH = 0X8765EDEAu, // Apple A16 (ARMv8.6-A).
|
||||||
|
kIBIZA = 0xFA33415Eu, // Apple M3 (ARMv8.6-A).
|
||||||
|
kPALMA = 0x72015832u, // Apple M3 Max (ARMv8.6-A).
|
||||||
|
kLOBOS = 0x5F4DEA93u, // Apple M3 Pro (ARMv8.6-A).
|
||||||
|
kCOLL = 0x2876F5B5u, // Apple A17 Pro (ARMv8.7-A).
|
||||||
|
kDONAN = 0x6F5129ACu, // Apple M4 (ARMv8.7-A).
|
||||||
|
kBRAVA = 0x17D5B93Au, // Apple M4 Max (ARMv8.7-A).
|
||||||
|
kTUPAI = 0x204526D0u, // Apple A18 .
|
||||||
|
kTAHITI = 0x75D4ACB9u // Apple A18 Pro .
|
||||||
};
|
};
|
||||||
|
|
||||||
[[maybe_unused]]
|
[[maybe_unused]]
|
||||||
@@ -1153,55 +1176,93 @@ static ASMJIT_FAVOR_SIZE bool detectARMFeaturesViaAppleFamilyId(CpuInfo& cpu) no
|
|||||||
case uint32_t(Id::kTYPHOON):
|
case uint32_t(Id::kTYPHOON):
|
||||||
case uint32_t(Id::kTWISTER):
|
case uint32_t(Id::kTWISTER):
|
||||||
populateARMv8AFeatures(features, 0);
|
populateARMv8AFeatures(features, 0);
|
||||||
features.add(Ext::kAES, Ext::kPMU, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256);
|
features.add(
|
||||||
|
Ext::kPMU,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A10 (ARMv8.0-A).
|
// Apple A10 (ARMv8.0-A).
|
||||||
case uint32_t(Id::kHURRICANE):
|
case uint32_t(Id::kHURRICANE):
|
||||||
populateARMv8AFeatures(features, 0);
|
populateARMv8AFeatures(features, 0);
|
||||||
features.add(Ext::kAES, Ext::kCRC32, Ext::kLOR, Ext::kPAN, Ext::kPMU, Ext::kPMULL, Ext::kRDM, Ext::kSHA1,
|
features.add(
|
||||||
Ext::kSHA256, Ext::kVHE);
|
Ext::kLOR, Ext::kPAN, Ext::kPMU, Ext::kVHE,
|
||||||
|
Ext::kAES, Ext::kCRC32, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256, Ext::kRDM
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A11 (ARMv8.2-A).
|
// Apple A11 (ARMv8.2-A).
|
||||||
case uint32_t(Id::kMONSOON_MISTRAL):
|
case uint32_t(Id::kMONSOON_MISTRAL):
|
||||||
populateARMv8AFeatures(features, 2);
|
populateARMv8AFeatures(features, 2);
|
||||||
features.add(Ext::kAES, Ext::kFP16, Ext::kFP16CONV, Ext::kPMU, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256);
|
features.add(
|
||||||
|
Ext::kPMU,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A12 (ARMv8.3-A).
|
// Apple A12 (ARMv8.3-A).
|
||||||
case uint32_t(Id::kVORTEX_TEMPEST):
|
case uint32_t(Id::kVORTEX_TEMPEST):
|
||||||
populateARMv8AFeatures(features, 3);
|
populateARMv8AFeatures(features, 3);
|
||||||
features.add(Ext::kAES, Ext::kFP16, Ext::kFP16CONV, Ext::kPMU, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256);
|
features.add(
|
||||||
|
Ext::kPMU,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A13 (ARMv8.4-A).
|
// Apple A13 (ARMv8.4-A).
|
||||||
case uint32_t(Id::kLIGHTNING_THUNDER):
|
case uint32_t(Id::kLIGHTNING_THUNDER):
|
||||||
populateARMv8AFeatures(features, 4);
|
populateARMv8AFeatures(features, 4);
|
||||||
features.add(Ext::kAES, Ext::kFHM, Ext::kFP16, Ext::kFP16CONV, Ext::kPMU, Ext::kPMULL, Ext::kSHA1,
|
features.add(
|
||||||
Ext::kSHA256, Ext::kSHA3, Ext::kSHA512);
|
Ext::kPMU,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV, Ext::kFHM,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A14/M1 (ARMv8.5-A).
|
// Apple A14/M1 (ARMv8.5-A).
|
||||||
case uint32_t(Id::kFIRESTORM_ICESTORM):
|
case uint32_t(Id::kFIRESTORM_ICESTORM):
|
||||||
populateARMv8AFeatures(features, 4);
|
populateARMv8AFeatures(features, 4);
|
||||||
features.add(Ext::kAES, Ext::kCSV2, Ext::kCSV3, Ext::kDPB2, Ext::kECV, Ext::kFHM, Ext::kFLAGM2,
|
features.add(
|
||||||
Ext::kFP16, Ext::kFP16CONV, Ext::kFRINTTS, Ext::kPMU, Ext::kPMULL, Ext::kSB,
|
Ext::kCSV2, Ext::kCSV3, Ext::kDPB2, Ext::kECV, Ext::kFLAGM2, Ext::kPMU, Ext::kSB, Ext::kSSBS,
|
||||||
Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512, Ext::kSSBS);
|
Ext::kFP16, Ext::kFP16CONV, Ext::kFHM,
|
||||||
|
Ext::kFRINTTS,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A15/M2.
|
// Apple A15/M2.
|
||||||
case uint32_t(Id::kAVALANCHE_BLIZZARD):
|
case uint32_t(Id::kAVALANCHE_BLIZZARD):
|
||||||
populateARMv8AFeatures(features, 6);
|
populateARMv8AFeatures(features, 6);
|
||||||
features.add(Ext::kAES, Ext::kFHM, Ext::kFP16, Ext::kFP16CONV, Ext::kPMU, Ext::kPMULL, Ext::kSHA1,
|
features.add(
|
||||||
Ext::kSHA256, Ext::kSHA3, Ext::kSHA512);
|
Ext::kPMU,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV, Ext::kFHM,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
// Apple A16.
|
// Apple A16/M3.
|
||||||
case uint32_t(Id::kEVEREST_SAWTOOTH):
|
case uint32_t(Id::kEVEREST_SAWTOOTH):
|
||||||
|
case uint32_t(Id::kIBIZA):
|
||||||
|
case uint32_t(Id::kPALMA):
|
||||||
|
case uint32_t(Id::kLOBOS):
|
||||||
populateARMv8AFeatures(features, 6);
|
populateARMv8AFeatures(features, 6);
|
||||||
features.add(Ext::kAES, Ext::kFHM, Ext::kFP16, Ext::kFP16CONV, Ext::kHCX, Ext::kPMU, Ext::kPMULL,
|
features.add(
|
||||||
Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512);
|
Ext::kHCX, Ext::kPMU,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV, Ext::kFHM,
|
||||||
|
Ext::kAES, Ext::kPMULL, Ext::kSHA1, Ext::kSHA256, Ext::kSHA3, Ext::kSHA512
|
||||||
|
);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
// Apple A17/M4.
|
||||||
|
case uint32_t(Id::kCOLL):
|
||||||
|
case uint32_t(Id::kDONAN):
|
||||||
|
case uint32_t(Id::kBRAVA):
|
||||||
|
populateARMv8AFeatures(features, 7);
|
||||||
|
features.add(
|
||||||
|
Ext::kPMU,
|
||||||
|
Ext::kFP16, Ext::kFP16CONV, Ext::kFHM,
|
||||||
|
Ext::kAES, Ext::kSHA1, Ext::kSHA3, Ext::kSHA256, Ext::kSHA512,
|
||||||
|
Ext::kSME, Ext::kSME2, Ext::kSME_F64F64, Ext::kSME_I16I64);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@@ -1625,48 +1686,96 @@ static void getAuxValues(unsigned long* vals, const unsigned long* tags, size_t
|
|||||||
#error "[asmjit] getAuxValues() - Unsupported OS."
|
#error "[asmjit] getAuxValues() - Unsupported OS."
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
struct HWCapMapping {
|
|
||||||
uint8_t featureId;
|
|
||||||
uint8_t hwCapBit;
|
|
||||||
};
|
|
||||||
|
|
||||||
static const unsigned long hwCapTags[2] = { AT_HWCAP, AT_HWCAP2 };
|
static const unsigned long hwCapTags[2] = { AT_HWCAP, AT_HWCAP2 };
|
||||||
|
|
||||||
static ASMJIT_FAVOR_SIZE void mergeHWCaps(CpuInfo& cpu, unsigned long mask, const HWCapMapping* mapping, size_t size) noexcept {
|
struct HWCapMapping32 { uint8_t featureId[32]; };
|
||||||
for (size_t i = 0; i < size; i++) {
|
struct HWCapMapping64 { uint8_t featureId[64]; };
|
||||||
cpu.features().addIf(Support::bitTest(mask, mapping[i].hwCapBit), mapping[i].featureId);
|
|
||||||
|
template<typename Mask, typename Map>
|
||||||
|
static ASMJIT_FAVOR_SIZE void mergeHWCaps(CpuInfo& cpu, const Mask& mask, const Map& map) noexcept {
|
||||||
|
static_assert(sizeof(Mask) * 8u == sizeof(Map));
|
||||||
|
|
||||||
|
Support::BitWordIterator<Mask> it(mask);
|
||||||
|
while (it.hasNext()) {
|
||||||
|
uint32_t featureId = map.featureId[it.next()];
|
||||||
|
cpu.features().add(featureId);
|
||||||
}
|
}
|
||||||
|
cpu.features().remove(0xFFu);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASMJIT_ARCH_ARM == 32
|
#if ASMJIT_ARCH_ARM == 32
|
||||||
|
|
||||||
// Reference:
|
// Reference:
|
||||||
// - https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h
|
// - https://github.com/torvalds/linux/blob/master/arch/arm/include/uapi/asm/hwcap.h
|
||||||
static const HWCapMapping hwCapMapping[] = {
|
static constexpr HWCapMapping32 hwCap1Mapping = {{
|
||||||
{ uint8_t(Ext::kEDSP) , 7 }, // HWCAP_EDSP
|
uint8_t(0xFF) , // [ 0]
|
||||||
{ uint8_t(Ext::kASIMD) , 12 }, // HWCAP_NEON
|
uint8_t(0xFF) , // [ 1]
|
||||||
{ uint8_t(Ext::kFP) , 13 }, // HWCAP_VFPv3
|
uint8_t(0xFF) , // [ 2]
|
||||||
{ uint8_t(Ext::kFMAC) , 16 }, // HWCAP_VFPv4
|
uint8_t(0xFF) , // [ 3]
|
||||||
{ uint8_t(Ext::kIDIVA) , 17 }, // HWCAP_IDIVA
|
uint8_t(0xFF) , // [ 4]
|
||||||
{ uint8_t(Ext::kIDIVT) , 18 }, // HWCAP_IDIVT
|
uint8_t(0xFF) , // [ 5]
|
||||||
{ uint8_t(Ext::kVFP_D32) , 19 }, // HWCAP_VFPD32
|
uint8_t(0xFF) , // [ 6]
|
||||||
{ uint8_t(Ext::kFP16CONV) , 22 }, // HWCAP_FPHP
|
uint8_t(Ext::kEDSP) , // [ 7] HWCAP_EDSP
|
||||||
{ uint8_t(Ext::kFP16) , 23 }, // HWCAP_ASIMDHP
|
uint8_t(0xFF) , // [ 8]
|
||||||
{ uint8_t(Ext::kDOTPROD) , 24 }, // HWCAP_ASIMDDP
|
uint8_t(0xFF) , // [ 9]
|
||||||
{ uint8_t(Ext::kFHM) , 25 }, // HWCAP_ASIMDFHM
|
uint8_t(0xFF) , // [10]
|
||||||
{ uint8_t(Ext::kBF16) , 26 }, // HWCAP_ASIMDBF16
|
uint8_t(0xFF) , // [11]
|
||||||
{ uint8_t(Ext::kI8MM) , 27 } // HWCAP_I8MM
|
uint8_t(Ext::kASIMD) , // [12] HWCAP_NEON
|
||||||
};
|
uint8_t(Ext::kFP) , // [13] HWCAP_VFPv3
|
||||||
|
uint8_t(0xFF) , // [14]
|
||||||
|
uint8_t(0xFF) , // [15]
|
||||||
|
uint8_t(Ext::kFMAC) , // [16] HWCAP_VFPv4
|
||||||
|
uint8_t(Ext::kIDIVA) , // [17] HWCAP_IDIVA
|
||||||
|
uint8_t(Ext::kIDIVT) , // [18] HWCAP_IDIVT
|
||||||
|
uint8_t(Ext::kVFP_D32) , // [19] HWCAP_VFPD32
|
||||||
|
uint8_t(0xFF) , // [20]
|
||||||
|
uint8_t(0xFF) , // [21]
|
||||||
|
uint8_t(Ext::kFP16CONV) , // [22] HWCAP_FPHP
|
||||||
|
uint8_t(Ext::kFP16) , // [23] HWCAP_ASIMDHP
|
||||||
|
uint8_t(Ext::kDOTPROD) , // [24] HWCAP_ASIMDDP
|
||||||
|
uint8_t(Ext::kFHM) , // [25] HWCAP_ASIMDFHM
|
||||||
|
uint8_t(Ext::kBF16) , // [26] HWCAP_ASIMDBF16
|
||||||
|
uint8_t(Ext::kI8MM) , // [27] HWCAP_I8MM
|
||||||
|
uint8_t(0xFF) , // [28]
|
||||||
|
uint8_t(0xFF) , // [29]
|
||||||
|
uint8_t(0xFF) , // [30]
|
||||||
|
uint8_t(0xFF) // [31]
|
||||||
|
}};
|
||||||
|
|
||||||
static const HWCapMapping hwCap2Mapping[] = {
|
static constexpr HWCapMapping32 hwCap2Mapping = {{
|
||||||
{ uint8_t(Ext::kAES) , 0 }, // HWCAP2_AES
|
uint8_t(Ext::kAES) , // [ 0] HWCAP2_AES
|
||||||
{ uint8_t(Ext::kPMULL) , 1 }, // HWCAP2_PMULL
|
uint8_t(Ext::kPMULL) , // [ 1] HWCAP2_PMULL
|
||||||
{ uint8_t(Ext::kSHA1) , 2 }, // HWCAP2_SHA1
|
uint8_t(Ext::kSHA1) , // [ 2] HWCAP2_SHA1
|
||||||
{ uint8_t(Ext::kSHA256) , 3 }, // HWCAP2_SHA2
|
uint8_t(Ext::kSHA256) , // [ 3] HWCAP2_SHA2
|
||||||
{ uint8_t(Ext::kCRC32) , 4 }, // HWCAP2_CRC32
|
uint8_t(Ext::kCRC32) , // [ 4] HWCAP2_CRC32
|
||||||
{ uint8_t(Ext::kSB) , 5 }, // HWCAP2_SB
|
uint8_t(Ext::kSB) , // [ 5] HWCAP2_SB
|
||||||
{ uint8_t(Ext::kSSBS) , 6 } // HWCAP2_SSBS
|
uint8_t(Ext::kSSBS) , // [ 6] HWCAP2_SSBS
|
||||||
};
|
uint8_t(0xFF) , // [ 7]
|
||||||
|
uint8_t(0xFF) , // [ 8]
|
||||||
|
uint8_t(0xFF) , // [ 9]
|
||||||
|
uint8_t(0xFF) , // [10]
|
||||||
|
uint8_t(0xFF) , // [11]
|
||||||
|
uint8_t(0xFF) , // [12]
|
||||||
|
uint8_t(0xFF) , // [13]
|
||||||
|
uint8_t(0xFF) , // [14]
|
||||||
|
uint8_t(0xFF) , // [15]
|
||||||
|
uint8_t(0xFF) , // [16]
|
||||||
|
uint8_t(0xFF) , // [17]
|
||||||
|
uint8_t(0xFF) , // [18]
|
||||||
|
uint8_t(0xFF) , // [19]
|
||||||
|
uint8_t(0xFF) , // [20]
|
||||||
|
uint8_t(0xFF) , // [21]
|
||||||
|
uint8_t(0xFF) , // [22]
|
||||||
|
uint8_t(0xFF) , // [23]
|
||||||
|
uint8_t(0xFF) , // [24]
|
||||||
|
uint8_t(0xFF) , // [25]
|
||||||
|
uint8_t(0xFF) , // [26]
|
||||||
|
uint8_t(0xFF) , // [27]
|
||||||
|
uint8_t(0xFF) , // [28]
|
||||||
|
uint8_t(0xFF) , // [29]
|
||||||
|
uint8_t(0xFF) , // [30]
|
||||||
|
uint8_t(0xFF) // [31]
|
||||||
|
}};
|
||||||
|
|
||||||
static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
||||||
cpu._wasDetected = true;
|
cpu._wasDetected = true;
|
||||||
@@ -1675,18 +1784,20 @@ static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
|||||||
unsigned long hwCapMasks[2] {};
|
unsigned long hwCapMasks[2] {};
|
||||||
getAuxValues(hwCapMasks, hwCapTags, 2u);
|
getAuxValues(hwCapMasks, hwCapTags, 2u);
|
||||||
|
|
||||||
mergeHWCaps(cpu, hwCapMasks[0], hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
|
mergeHWCaps(cpu, hwCapMasks[0], hwCap1Mapping);
|
||||||
mergeHWCaps(cpu, hwCapMasks[1], hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
|
mergeHWCaps(cpu, hwCapMasks[1], hwCap2Mapping);
|
||||||
|
|
||||||
CpuFeatures::ARM& features = cpu.features().arm();
|
CpuFeatures::ARM& features = cpu.features().arm();
|
||||||
|
|
||||||
// ARMv7 provides FP|ASIMD.
|
// ARMv7 provides FP|ASIMD.
|
||||||
if (features.hasFP() || features.hasASIMD())
|
if (features.hasFP() || features.hasASIMD()) {
|
||||||
features.add(CpuFeatures::ARM::kARMv7);
|
features.add(CpuFeatures::ARM::kARMv7);
|
||||||
|
}
|
||||||
|
|
||||||
// ARMv8 provives AES, CRC32, PMULL, SHA1, and SHA256.
|
// ARMv8 provives AES, CRC32, PMULL, SHA1, and SHA256.
|
||||||
if (features.hasAES() || features.hasCRC32() || features.hasPMULL() || features.hasSHA1() || features.hasSHA256())
|
if (features.hasAES() || features.hasCRC32() || features.hasPMULL() || features.hasSHA1() || features.hasSHA256()) {
|
||||||
features.add(CpuFeatures::ARM::kARMv8a);
|
features.add(CpuFeatures::ARM::kARMv8a);
|
||||||
|
}
|
||||||
|
|
||||||
postProcessARMCpuInfo(cpu);
|
postProcessARMCpuInfo(cpu);
|
||||||
}
|
}
|
||||||
@@ -1696,95 +1807,139 @@ static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
|||||||
// Reference:
|
// Reference:
|
||||||
// - https://docs.kernel.org/arch/arm64/elf_hwcaps.html
|
// - https://docs.kernel.org/arch/arm64/elf_hwcaps.html
|
||||||
// - https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
|
// - https://github.com/torvalds/linux/blob/master/arch/arm64/include/uapi/asm/hwcap.h
|
||||||
static const HWCapMapping hwCapMapping[] = {
|
static constexpr HWCapMapping64 hwCap1Mapping = {{
|
||||||
{ uint8_t(Ext::kFP) , 0 }, // HWCAP_FP
|
uint8_t(Ext::kFP) , // [ 0] HWCAP_FP
|
||||||
{ uint8_t(Ext::kASIMD) , 1 }, // HWCAP_ASIMD
|
uint8_t(Ext::kASIMD) , // [ 1] HWCAP_ASIMD
|
||||||
/*
|
uint8_t(0xFF) , // [ 2] HWCAP_EVTSTRM
|
||||||
{ uint8_t(Ext::k) , 2 }, // HWCAP_EVTSTRM
|
uint8_t(Ext::kAES) , // [ 3] HWCAP_AES
|
||||||
*/
|
uint8_t(Ext::kPMULL) , // [ 4] HWCAP_PMULL
|
||||||
{ uint8_t(Ext::kAES) , 3 }, // HWCAP_AES
|
uint8_t(Ext::kSHA1) , // [ 5] HWCAP_SHA1
|
||||||
{ uint8_t(Ext::kPMULL) , 4 }, // HWCAP_PMULL
|
uint8_t(Ext::kSHA256) , // [ 6] HWCAP_SHA2
|
||||||
{ uint8_t(Ext::kSHA1) , 5 }, // HWCAP_SHA1
|
uint8_t(Ext::kCRC32) , // [ 7] HWCAP_CRC32
|
||||||
{ uint8_t(Ext::kSHA256) , 6 }, // HWCAP_SHA2
|
uint8_t(Ext::kLSE) , // [ 8] HWCAP_ATOMICS
|
||||||
{ uint8_t(Ext::kCRC32) , 7 }, // HWCAP_CRC32
|
uint8_t(Ext::kFP16CONV) , // [ 9] HWCAP_FPHP
|
||||||
{ uint8_t(Ext::kLSE) , 8 }, // HWCAP_ATOMICS
|
uint8_t(Ext::kFP16) , // [10] HWCAP_ASIMDHP
|
||||||
{ uint8_t(Ext::kFP16CONV) , 9 }, // HWCAP_FPHP
|
uint8_t(Ext::kCPUID) , // [11] HWCAP_CPUID
|
||||||
{ uint8_t(Ext::kFP16) , 10 }, // HWCAP_ASIMDHP
|
uint8_t(Ext::kRDM) , // [12] HWCAP_ASIMDRDM
|
||||||
{ uint8_t(Ext::kCPUID) , 11 }, // HWCAP_CPUID
|
uint8_t(Ext::kJSCVT) , // [13] HWCAP_JSCVT
|
||||||
{ uint8_t(Ext::kRDM) , 12 }, // HWCAP_ASIMDRDM
|
uint8_t(Ext::kFCMA) , // [14] HWCAP_FCMA
|
||||||
{ uint8_t(Ext::kJSCVT) , 13 }, // HWCAP_JSCVT
|
uint8_t(Ext::kLRCPC) , // [15] HWCAP_LRCPC
|
||||||
{ uint8_t(Ext::kFCMA) , 14 }, // HWCAP_FCMA
|
uint8_t(Ext::kDPB) , // [16] HWCAP_DCPOP
|
||||||
{ uint8_t(Ext::kLRCPC) , 15 }, // HWCAP_LRCPC
|
uint8_t(Ext::kSHA3) , // [17] HWCAP_SHA3
|
||||||
{ uint8_t(Ext::kDPB) , 16 }, // HWCAP_DCPOP
|
uint8_t(Ext::kSM3) , // [18] HWCAP_SM3
|
||||||
{ uint8_t(Ext::kSHA3) , 17 }, // HWCAP_SHA3
|
uint8_t(Ext::kSM4) , // [19] HWCAP_SM4
|
||||||
{ uint8_t(Ext::kSM3) , 18 }, // HWCAP_SM3
|
uint8_t(Ext::kDOTPROD) , // [20] HWCAP_ASIMDDP
|
||||||
{ uint8_t(Ext::kSM4) , 19 }, // HWCAP_SM4
|
uint8_t(Ext::kSHA512) , // [21] HWCAP_SHA512
|
||||||
{ uint8_t(Ext::kDOTPROD) , 20 }, // HWCAP_ASIMDDP
|
uint8_t(Ext::kSVE) , // [22] HWCAP_SVE
|
||||||
{ uint8_t(Ext::kSHA512) , 21 }, // HWCAP_SHA512
|
uint8_t(Ext::kFHM) , // [23] HWCAP_ASIMDFHM
|
||||||
{ uint8_t(Ext::kSVE) , 22 }, // HWCAP_SVE
|
uint8_t(Ext::kDIT) , // [24] HWCAP_DIT
|
||||||
{ uint8_t(Ext::kFHM) , 23 }, // HWCAP_ASIMDFHM
|
uint8_t(Ext::kLSE2) , // [25] HWCAP_USCAT
|
||||||
{ uint8_t(Ext::kDIT) , 24 }, // HWCAP_DIT
|
uint8_t(Ext::kLRCPC2) , // [26] HWCAP_ILRCPC
|
||||||
{ uint8_t(Ext::kLSE2) , 25 }, // HWCAP_USCAT
|
uint8_t(Ext::kFLAGM) , // [27] HWCAP_FLAGM
|
||||||
{ uint8_t(Ext::kLRCPC2) , 26 }, // HWCAP_ILRCPC
|
uint8_t(Ext::kSSBS) , // [28] HWCAP_SSBS
|
||||||
{ uint8_t(Ext::kFLAGM) , 27 }, // HWCAP_FLAGM
|
uint8_t(Ext::kSB) , // [29] HWCAP_SB
|
||||||
{ uint8_t(Ext::kSSBS) , 28 }, // HWCAP_SSBS
|
uint8_t(0xFF) , // [30] HWCAP_PACA
|
||||||
{ uint8_t(Ext::kSB) , 29 } // HWCAP_SB
|
uint8_t(0xFF) , // [31] HWCAP_PACG
|
||||||
/*
|
uint8_t(Ext::kGCS) , // [32] HWCAP_GCS
|
||||||
{ uint8_t(Ext::k) , 30 }, // HWCAP_PACA
|
uint8_t(Ext::kCMPBR) , // [33] HWCAP_CMPBR
|
||||||
{ uint8_t(Ext::k) , 31 } // HWCAP_PACG
|
uint8_t(Ext::kFPRCVT) , // [34] HWCAP_FPRCVT
|
||||||
*/
|
uint8_t(Ext::kF8F32MM) , // [35] HWCAP_F8MM8
|
||||||
};
|
uint8_t(Ext::kF8F16MM) , // [36] HWCAP_F8MM4
|
||||||
|
uint8_t(Ext::kSVE_F16MM) , // [37] HWCAP_SVE_F16MM
|
||||||
|
uint8_t(Ext::kSVE_ELTPERM) , // [38] HWCAP_SVE_ELTPERM
|
||||||
|
uint8_t(Ext::kSVE_AES2) , // [39] HWCAP_SVE_AES2
|
||||||
|
uint8_t(Ext::kSVE_BFSCALE) , // [40] HWCAP_SVE_BFSCALE
|
||||||
|
uint8_t(Ext::kSVE2_2) , // [41] HWCAP_SVE2P2
|
||||||
|
uint8_t(Ext::kSME2_2) , // [42] HWCAP_SME2P2
|
||||||
|
uint8_t(Ext::kSSVE_BITPERM) , // [43] HWCAP_SME_SBITPERM
|
||||||
|
uint8_t(Ext::kSME_AES) , // [44] HWCAP_SME_AES
|
||||||
|
uint8_t(Ext::kSSVE_FEXPA) , // [45] HWCAP_SME_SFEXPA
|
||||||
|
uint8_t(Ext::kSME_TMOP) , // [46] HWCAP_SME_STMOP
|
||||||
|
uint8_t(Ext::kSME_MOP4) , // [47] HWCAP_SME_SMOP4
|
||||||
|
uint8_t(0xFF) , // [48]
|
||||||
|
uint8_t(0xFF) , // [49]
|
||||||
|
uint8_t(0xFF) , // [50]
|
||||||
|
uint8_t(0xFF) , // [51]
|
||||||
|
uint8_t(0xFF) , // [52]
|
||||||
|
uint8_t(0xFF) , // [53]
|
||||||
|
uint8_t(0xFF) , // [54]
|
||||||
|
uint8_t(0xFF) , // [55]
|
||||||
|
uint8_t(0xFF) , // [56]
|
||||||
|
uint8_t(0xFF) , // [57]
|
||||||
|
uint8_t(0xFF) , // [58]
|
||||||
|
uint8_t(0xFF) , // [59]
|
||||||
|
uint8_t(0xFF) , // [60]
|
||||||
|
uint8_t(0xFF) , // [61]
|
||||||
|
uint8_t(0xFF) , // [62]
|
||||||
|
uint8_t(0xFF) // [63]
|
||||||
|
}};
|
||||||
|
|
||||||
static const HWCapMapping hwCap2Mapping[] = {
|
static constexpr HWCapMapping64 hwCap2Mapping = {{
|
||||||
{ uint8_t(Ext::kDPB2) , 0 }, // HWCAP2_DCPODP
|
uint8_t(Ext::kDPB2) , // [ 0] HWCAP2_DCPODP
|
||||||
{ uint8_t(Ext::kSVE2) , 1 }, // HWCAP2_SVE2
|
uint8_t(Ext::kSVE2) , // [ 1] HWCAP2_SVE2
|
||||||
{ uint8_t(Ext::kSVE_AES) , 2 }, // HWCAP2_SVEAES
|
uint8_t(Ext::kSVE_AES) , // [ 2] HWCAP2_SVEAES
|
||||||
{ uint8_t(Ext::kSVE_PMULL128) , 3 }, // HWCAP2_SVEPMULL
|
uint8_t(Ext::kSVE_PMULL128) , // [ 3] HWCAP2_SVEPMULL
|
||||||
{ uint8_t(Ext::kSVE_BITPERM) , 4 }, // HWCAP2_SVEBITPERM
|
uint8_t(Ext::kSVE_BITPERM) , // [ 4] HWCAP2_SVEBITPERM
|
||||||
{ uint8_t(Ext::kSVE_SHA3) , 5 }, // HWCAP2_SVESHA3
|
uint8_t(Ext::kSVE_SHA3) , // [ 5] HWCAP2_SVESHA3
|
||||||
{ uint8_t(Ext::kSVE_SM4) , 6 }, // HWCAP2_SVESM4
|
uint8_t(Ext::kSVE_SM4) , // [ 6] HWCAP2_SVESM4
|
||||||
{ uint8_t(Ext::kFLAGM2) , 7 }, // HWCAP2_FLAGM2
|
uint8_t(Ext::kFLAGM2) , // [ 7] HWCAP2_FLAGM2
|
||||||
{ uint8_t(Ext::kFRINTTS) , 8 }, // HWCAP2_FRINT
|
uint8_t(Ext::kFRINTTS) , // [ 8] HWCAP2_FRINT
|
||||||
{ uint8_t(Ext::kSVE_I8MM) , 9 }, // HWCAP2_SVEI8MM
|
uint8_t(Ext::kSVE_I8MM) , // [ 9] HWCAP2_SVEI8MM
|
||||||
{ uint8_t(Ext::kSVE_F32MM) , 10 }, // HWCAP2_SVEF32MM
|
uint8_t(Ext::kSVE_F32MM) , // [10] HWCAP2_SVEF32MM
|
||||||
{ uint8_t(Ext::kSVE_F64MM) , 11 }, // HWCAP2_SVEF64MM
|
uint8_t(Ext::kSVE_F64MM) , // [11] HWCAP2_SVEF64MM
|
||||||
{ uint8_t(Ext::kSVE_BF16) , 12 }, // HWCAP2_SVEBF16
|
uint8_t(Ext::kSVE_BF16) , // [12] HWCAP2_SVEBF16
|
||||||
{ uint8_t(Ext::kI8MM) , 13 }, // HWCAP2_I8MM
|
uint8_t(Ext::kI8MM) , // [13] HWCAP2_I8MM
|
||||||
{ uint8_t(Ext::kBF16) , 14 }, // HWCAP2_BF16
|
uint8_t(Ext::kBF16) , // [14] HWCAP2_BF16
|
||||||
{ uint8_t(Ext::kDGH) , 15 }, // HWCAP2_DGH
|
uint8_t(Ext::kDGH) , // [15] HWCAP2_DGH
|
||||||
{ uint8_t(Ext::kRNG) , 16 }, // HWCAP2_RNG
|
uint8_t(Ext::kRNG) , // [16] HWCAP2_RNG
|
||||||
{ uint8_t(Ext::kBTI) , 17 }, // HWCAP2_BTI
|
uint8_t(Ext::kBTI) , // [17] HWCAP2_BTI
|
||||||
{ uint8_t(Ext::kMTE) , 18 }, // HWCAP2_MTE
|
uint8_t(Ext::kMTE) , // [18] HWCAP2_MTE
|
||||||
{ uint8_t(Ext::kECV) , 19 }, // HWCAP2_ECV
|
uint8_t(Ext::kECV) , // [19] HWCAP2_ECV
|
||||||
{ uint8_t(Ext::kAFP) , 20 }, // HWCAP2_AFP
|
uint8_t(Ext::kAFP) , // [20] HWCAP2_AFP
|
||||||
{ uint8_t(Ext::kRPRES) , 21 }, // HWCAP2_RPRES
|
uint8_t(Ext::kRPRES) , // [21] HWCAP2_RPRES
|
||||||
{ uint8_t(Ext::kMTE3) , 22 }, // HWCAP2_MTE3
|
uint8_t(Ext::kMTE3) , // [22] HWCAP2_MTE3
|
||||||
{ uint8_t(Ext::kSME) , 23 }, // HWCAP2_SME
|
uint8_t(Ext::kSME) , // [23] HWCAP2_SME
|
||||||
{ uint8_t(Ext::kSME_I16I64) , 24 }, // HWCAP2_SME_I16I64
|
uint8_t(Ext::kSME_I16I64) , // [24] HWCAP2_SME_I16I64
|
||||||
{ uint8_t(Ext::kSME_F64F64) , 25 }, // HWCAP2_SME_F64F64
|
uint8_t(Ext::kSME_F64F64) , // [25] HWCAP2_SME_F64F64
|
||||||
{ uint8_t(Ext::kSME_I8I32) , 26 }, // HWCAP2_SME_I8I32
|
uint8_t(Ext::kSME_I8I32) , // [26] HWCAP2_SME_I8I32
|
||||||
{ uint8_t(Ext::kSME_F16F32) , 27 }, // HWCAP2_SME_F16F32
|
uint8_t(Ext::kSME_F16F32) , // [27] HWCAP2_SME_F16F32
|
||||||
{ uint8_t(Ext::kSME_B16F32) , 28 }, // HWCAP2_SME_B16F32
|
uint8_t(Ext::kSME_B16F32) , // [28] HWCAP2_SME_B16F32
|
||||||
{ uint8_t(Ext::kSME_F32F32) , 29 }, // HWCAP2_SME_F32F32
|
uint8_t(Ext::kSME_F32F32) , // [29] HWCAP2_SME_F32F32
|
||||||
{ uint8_t(Ext::kSME_FA64) , 30 }, // HWCAP2_SME_FA64
|
uint8_t(Ext::kSME_FA64) , // [30] HWCAP2_SME_FA64
|
||||||
{ uint8_t(Ext::kWFXT) , 31 }, // HWCAP2_WFXT
|
uint8_t(Ext::kWFXT) , // [31] HWCAP2_WFXT
|
||||||
{ uint8_t(Ext::kEBF16) , 32 }, // HWCAP2_EBF16
|
uint8_t(Ext::kEBF16) , // [32] HWCAP2_EBF16
|
||||||
{ uint8_t(Ext::kSVE_EBF16) , 33 }, // HWCAP2_SVE_EBF16
|
uint8_t(Ext::kSVE_EBF16) , // [33] HWCAP2_SVE_EBF16
|
||||||
{ uint8_t(Ext::kCSSC) , 34 }, // HWCAP2_CSSC
|
uint8_t(Ext::kCSSC) , // [34] HWCAP2_CSSC
|
||||||
{ uint8_t(Ext::kRPRFM) , 35 }, // HWCAP2_RPRFM
|
uint8_t(Ext::kRPRFM) , // [35] HWCAP2_RPRFM
|
||||||
{ uint8_t(Ext::kSVE2_1) , 36 }, // HWCAP2_SVE2P1
|
uint8_t(Ext::kSVE2_1) , // [36] HWCAP2_SVE2P1
|
||||||
{ uint8_t(Ext::kSME2) , 37 }, // HWCAP2_SME2
|
uint8_t(Ext::kSME2) , // [37] HWCAP2_SME2
|
||||||
{ uint8_t(Ext::kSME2_1) , 38 }, // HWCAP2_SME2P1
|
uint8_t(Ext::kSME2_1) , // [38] HWCAP2_SME2P1
|
||||||
{ uint8_t(Ext::kSME_I16I32) , 39 }, // HWCAP2_SME_I16I32
|
uint8_t(Ext::kSME_I16I32) , // [39] HWCAP2_SME_I16I32
|
||||||
{ uint8_t(Ext::kSME_BI32I32) , 40 }, // HWCAP2_SME_BI32I32
|
uint8_t(Ext::kSME_BI32I32) , // [40] HWCAP2_SME_BI32I32
|
||||||
{ uint8_t(Ext::kSME_B16B16) , 41 }, // HWCAP2_SME_B16B16
|
uint8_t(Ext::kSME_B16B16) , // [41] HWCAP2_SME_B16B16
|
||||||
{ uint8_t(Ext::kSME_F16F16) , 42 }, // HWCAP2_SME_F16F16
|
uint8_t(Ext::kSME_F16F16) , // [42] HWCAP2_SME_F16F16
|
||||||
{ uint8_t(Ext::kMOPS) , 43 }, // HWCAP2_MOPS
|
uint8_t(Ext::kMOPS) , // [43] HWCAP2_MOPS
|
||||||
{ uint8_t(Ext::kHBC) , 44 }, // HWCAP2_HBC
|
uint8_t(Ext::kHBC) , // [44] HWCAP2_HBC
|
||||||
{ uint8_t(Ext::kSVE_B16B16) , 45 }, // HWCAP2_SVE_B16B16
|
uint8_t(Ext::kSVE_B16B16) , // [45] HWCAP2_SVE_B16B16
|
||||||
{ uint8_t(Ext::kLRCPC3) , 46 }, // HWCAP2_LRCPC3
|
uint8_t(Ext::kLRCPC3) , // [46] HWCAP2_LRCPC3
|
||||||
{ uint8_t(Ext::kLSE128) , 47 }, // HWCAP2_LSE128
|
uint8_t(Ext::kLSE128) , // [47] HWCAP2_LSE128
|
||||||
};
|
uint8_t(Ext::kFPMR) , // [48] HWCAP2_FPMR
|
||||||
|
uint8_t(Ext::kLUT) , // [49] HWCAP2_LUT
|
||||||
|
uint8_t(Ext::kFAMINMAX) , // [50] HWCAP2_FAMINMAX
|
||||||
|
uint8_t(Ext::kFP8) , // [51] HWCAP2_F8CVT
|
||||||
|
uint8_t(Ext::kFP8FMA) , // [52] HWCAP2_F8FMA
|
||||||
|
uint8_t(Ext::kFP8DOT4) , // [53] HWCAP2_F8DP4
|
||||||
|
uint8_t(Ext::kFP8DOT2) , // [54] HWCAP2_F8DP2
|
||||||
|
uint8_t(Ext::kF8E4M3) , // [55] HWCAP2_F8E4M3
|
||||||
|
uint8_t(Ext::kF8E5M2) , // [56] HWCAP2_F8E5M2
|
||||||
|
uint8_t(Ext::kSME_LUTv2) , // [57] HWCAP2_SME_LUTV2
|
||||||
|
uint8_t(Ext::kSME_F8F16) , // [58] HWCAP2_SME_F8F16
|
||||||
|
uint8_t(Ext::kSME_F8F32) , // [59] HWCAP2_SME_F8F32
|
||||||
|
uint8_t(Ext::kSSVE_FP8FMA) , // [60] HWCAP2_SME_SF8FMA
|
||||||
|
uint8_t(Ext::kSSVE_FP8DOT4) , // [61] HWCAP2_SME_SF8DP4
|
||||||
|
uint8_t(Ext::kSSVE_FP8DOT2) , // [62] HWCAP2_SME_SF8DP2
|
||||||
|
uint8_t(0xFF) // [63] HWCAP2_POE
|
||||||
|
}};
|
||||||
|
|
||||||
static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
||||||
cpu._wasDetected = true;
|
cpu._wasDetected = true;
|
||||||
@@ -1793,8 +1948,8 @@ static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
|
|||||||
unsigned long hwCapMasks[2] {};
|
unsigned long hwCapMasks[2] {};
|
||||||
getAuxValues(hwCapMasks, hwCapTags, 2u);
|
getAuxValues(hwCapMasks, hwCapTags, 2u);
|
||||||
|
|
||||||
mergeHWCaps(cpu, hwCapMasks[0], hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
|
mergeHWCaps(cpu, hwCapMasks[0], hwCap1Mapping);
|
||||||
mergeHWCaps(cpu, hwCapMasks[1], hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
|
mergeHWCaps(cpu, hwCapMasks[1], hwCap2Mapping);
|
||||||
|
|
||||||
#if defined(ASMJIT_ARM_DETECT_VIA_CPUID)
|
#if defined(ASMJIT_ARM_DETECT_VIA_CPUID)
|
||||||
if (cpu.features().arm().hasCPUID()) {
|
if (cpu.features().arm().hasCPUID()) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED
|
#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED
|
||||||
@@ -560,6 +560,7 @@ public:
|
|||||||
kCHK, //!< CPU has CHK (check feature status - CHKFEAT instruction) {A64}.
|
kCHK, //!< CPU has CHK (check feature status - CHKFEAT instruction) {A64}.
|
||||||
kCLRBHB, //!< CPU has CLRBHB (clear BHB instruction).
|
kCLRBHB, //!< CPU has CLRBHB (clear BHB instruction).
|
||||||
kCMOW, //!< CPU has CMOW (control for cache maintenance permission) {A64}.
|
kCMOW, //!< CPU has CMOW (control for cache maintenance permission) {A64}.
|
||||||
|
kCMPBR, //!< CPU has CMPBR (Compare and branch instructions) {A64}.
|
||||||
kCONSTPACFIELD, //!< CPU has CONSTPACFIELD (PAC algorithm enhancement) {A64}.
|
kCONSTPACFIELD, //!< CPU has CONSTPACFIELD (PAC algorithm enhancement) {A64}.
|
||||||
kCPA, //!< CPU has CPA (instruction-only Checked Pointer Arithmetic) {A64}.
|
kCPA, //!< CPU has CPA (instruction-only Checked Pointer Arithmetic) {A64}.
|
||||||
kCPA2, //!< CPU has CPA2 (checked Pointer Arithmetic) {A64}.
|
kCPA2, //!< CPU has CPA2 (checked Pointer Arithmetic) {A64}.
|
||||||
@@ -581,6 +582,10 @@ public:
|
|||||||
kECV, //!< CPU has ECV (enhanced counter virtualization).
|
kECV, //!< CPU has ECV (enhanced counter virtualization).
|
||||||
kEDHSR, //!< CPU has EDHSR (support for EDHSR) {A64}.
|
kEDHSR, //!< CPU has EDHSR (support for EDHSR) {A64}.
|
||||||
kEDSP, //!< CPU has EDSP (ARM/THUMB only).
|
kEDSP, //!< CPU has EDSP (ARM/THUMB only).
|
||||||
|
kF8E4M3, //!< CPU has F8E4M3 {A64}.
|
||||||
|
kF8E5M2, //!< CPU has F8E5M2 {A64}.
|
||||||
|
kF8F16MM, //!< CPU has F8F16MM (8-bit floating-point matrix multiply-accumulate to half-precision) {A64}
|
||||||
|
kF8F32MM, //!< CPU has F8F32MM (8-bit floating-point matrix multiply-accumulate to single-precision) {A64}
|
||||||
kFAMINMAX, //!< CPU has FAMINMAX (floating-point maximum and minimum absolute value instructions) {A64}.
|
kFAMINMAX, //!< CPU has FAMINMAX (floating-point maximum and minimum absolute value instructions) {A64}.
|
||||||
kFCMA, //!< CPU has FCMA (FCADD/FCMLA).
|
kFCMA, //!< CPU has FCMA (FCADD/FCMLA).
|
||||||
kFGT, //!< CPU has FGT (fine-grained traps).
|
kFGT, //!< CPU has FGT (fine-grained traps).
|
||||||
@@ -597,6 +602,7 @@ public:
|
|||||||
kFP8DOT4, //!< CPU has FP8DOT4 (FP8 4-way dot product to single-precision instructions) {A64}.
|
kFP8DOT4, //!< CPU has FP8DOT4 (FP8 4-way dot product to single-precision instructions) {A64}.
|
||||||
kFP8FMA, //!< CPU has FP8FMA (FP8 multiply-accumulate to half-precision and single-precision instructions) {A64}.
|
kFP8FMA, //!< CPU has FP8FMA (FP8 multiply-accumulate to half-precision and single-precision instructions) {A64}.
|
||||||
kFPMR, //!< CPU has FPMR (floating-point Mode Register) {A64}.
|
kFPMR, //!< CPU has FPMR (floating-point Mode Register) {A64}.
|
||||||
|
kFPRCVT, //!< CPU has FPRCVT (floating-point to/from integer in scalar FP register) {A64}.
|
||||||
kFRINTTS, //!< CPU has FRINTTS (FRINT[32|64][X|Z] instructions) {A64}.
|
kFRINTTS, //!< CPU has FRINTTS (FRINT[32|64][X|Z] instructions) {A64}.
|
||||||
kGCS, //!< CPU has GCS (guarded control stack extension) {A64}.
|
kGCS, //!< CPU has GCS (guarded control stack extension) {A64}.
|
||||||
kHACDBS, //!< CPU has HACDBS (hardware accelerator for cleaning Dirty state) {A64}.
|
kHACDBS, //!< CPU has HACDBS (hardware accelerator for cleaning Dirty state) {A64}.
|
||||||
@@ -619,9 +625,12 @@ public:
|
|||||||
kLS64, //!< CPU has LS64 (64 byte loads/stores without return) {A64}.
|
kLS64, //!< CPU has LS64 (64 byte loads/stores without return) {A64}.
|
||||||
kLS64_ACCDATA, //!< CPU has LS64_ACCDATA (64-byte EL0 stores with return) {A64}.
|
kLS64_ACCDATA, //!< CPU has LS64_ACCDATA (64-byte EL0 stores with return) {A64}.
|
||||||
kLS64_V, //!< CPU has LS64_V (64-byte stores with return) {A64}.
|
kLS64_V, //!< CPU has LS64_V (64-byte stores with return) {A64}.
|
||||||
|
kLS64WB, //!< CPU has LS64WB (LS64 for Write-back cacheable memory) {A64}
|
||||||
kLSE, //!< CPU has LSE (large system extensions) {A64}.
|
kLSE, //!< CPU has LSE (large system extensions) {A64}.
|
||||||
kLSE128, //!< CPU has LSE128 (128-bit atomics) {A64}.
|
kLSE128, //!< CPU has LSE128 (128-bit atomics) {A64}.
|
||||||
kLSE2, //!< CPU has LSE2 (large system extensions v2) {A64}.
|
kLSE2, //!< CPU has LSE2 (large system extensions v2) {A64}.
|
||||||
|
kLSFE, //!< CPU has LSFE (large system float extension) {A64}.
|
||||||
|
kLSUI, //!< CPU has LSUI (unprivileged load store) {A64}.
|
||||||
kLUT, //!< CPU has LUT (lookup table instructions with 2-bit and 4-bit indices) {A64}.
|
kLUT, //!< CPU has LUT (lookup table instructions with 2-bit and 4-bit indices) {A64}.
|
||||||
kLVA, //!< CPU has LVA (large VA support) {A64}.
|
kLVA, //!< CPU has LVA (large VA support) {A64}.
|
||||||
kLVA3, //!< CPU has LVA3 (56-bit VA) {A64}.
|
kLVA3, //!< CPU has LVA3 (56-bit VA) {A64}.
|
||||||
@@ -643,6 +652,7 @@ public:
|
|||||||
kNMI, //!< CPU has NMI (non-maskable Interrupt) {A64}.
|
kNMI, //!< CPU has NMI (non-maskable Interrupt) {A64}.
|
||||||
kNV, //!< CPU has NV (nested virtualization enchancement) {A64}.
|
kNV, //!< CPU has NV (nested virtualization enchancement) {A64}.
|
||||||
kNV2, //!< CPU has NV2 (enhanced support for nested virtualization) {A64}.
|
kNV2, //!< CPU has NV2 (enhanced support for nested virtualization) {A64}.
|
||||||
|
kOCCMO, //!< CPU has OCCMO (outer cacheable cache maintenance operation) {A64}.
|
||||||
kPAN, //!< CPU has PAN (privileged access-never extension) {A64}.
|
kPAN, //!< CPU has PAN (privileged access-never extension) {A64}.
|
||||||
kPAN2, //!< CPU has PAN2 (PAN s1e1R and s1e1W variants) {A64}.
|
kPAN2, //!< CPU has PAN2 (PAN s1e1R and s1e1W variants) {A64}.
|
||||||
kPAN3, //!< CPU has PAN3 (support for SCTLR_ELx.EPAN) {A64}.
|
kPAN3, //!< CPU has PAN3 (support for SCTLR_ELx.EPAN) {A64}.
|
||||||
@@ -678,6 +688,8 @@ public:
|
|||||||
kSME, //!< CPU has SME (SME v1 - scalable matrix extension) {A64}.
|
kSME, //!< CPU has SME (SME v1 - scalable matrix extension) {A64}.
|
||||||
kSME2, //!< CPU has SME2 (SME v2) {A64}.
|
kSME2, //!< CPU has SME2 (SME v2) {A64}.
|
||||||
kSME2_1, //!< CPU has SME2p1 (SME v2.1) {A64}.
|
kSME2_1, //!< CPU has SME2p1 (SME v2.1) {A64}.
|
||||||
|
kSME2_2, //!< CPU has SME2p1 (SME v2.2) {A64}.
|
||||||
|
kSME_AES, //!< CPU has SME_AES {A64}.
|
||||||
kSME_B16B16, //!< CPU has SME_B16B16 (SME non-widening BFloat16 to BFloat16 arithmetic) {A64}.
|
kSME_B16B16, //!< CPU has SME_B16B16 (SME non-widening BFloat16 to BFloat16 arithmetic) {A64}.
|
||||||
kSME_B16F32, //!< CPU has SME_B16F32 (BFMOPA and BFMOPS instructions that accumulate BFloat16 outer products into single-precision tiles) {A64}.
|
kSME_B16F32, //!< CPU has SME_B16F32 (BFMOPA and BFMOPS instructions that accumulate BFloat16 outer products into single-precision tiles) {A64}.
|
||||||
kSME_BI32I32, //!< CPU has SME_BI32I32 (BMOPA and BMOPS instructions that accumulate 1-bit binary outer products into 32-bit integer tiles) {A64}.
|
kSME_BI32I32, //!< CPU has SME_BI32I32 (BMOPA and BMOPS instructions that accumulate 1-bit binary outer products into 32-bit integer tiles) {A64}.
|
||||||
@@ -692,6 +704,8 @@ public:
|
|||||||
kSME_I16I64, //!< CPU has SME_I16I64 {A64}.
|
kSME_I16I64, //!< CPU has SME_I16I64 {A64}.
|
||||||
kSME_I8I32, //!< CPU has SME_I8I32 {A64}.
|
kSME_I8I32, //!< CPU has SME_I8I32 {A64}.
|
||||||
kSME_LUTv2, //!< CPU has SME_LUTv2 (lookup table instructions with 4-bit indices and 8-bit elements) {A64}.
|
kSME_LUTv2, //!< CPU has SME_LUTv2 (lookup table instructions with 4-bit indices and 8-bit elements) {A64}.
|
||||||
|
kSME_MOP4, //!< CPU has SME_MOP4 (quarter-tile outer product instructions) {A64}.
|
||||||
|
kSME_TMOP, //!< CPU has SME_TMOP {A64}.
|
||||||
kSPE, //!< CPU has SPE (statistical profiling extension) {A64}.
|
kSPE, //!< CPU has SPE (statistical profiling extension) {A64}.
|
||||||
kSPE1_1, //!< CPU has SPEv1p1 (statistical profiling extensions version 1.1) {A64}.
|
kSPE1_1, //!< CPU has SPEv1p1 (statistical profiling extensions version 1.1) {A64}.
|
||||||
kSPE1_2, //!< CPU has SPEv1p2 (statistical profiling extensions version 1.2) {A64}.
|
kSPE1_2, //!< CPU has SPEv1p2 (statistical profiling extensions version 1.2) {A64}.
|
||||||
@@ -708,17 +722,25 @@ public:
|
|||||||
kSPMU, //!< CPU has SPMU (system performance monitors extension) {A64}.
|
kSPMU, //!< CPU has SPMU (system performance monitors extension) {A64}.
|
||||||
kSSBS, //!< CPU has SSBS (speculative store bypass safe instruction).
|
kSSBS, //!< CPU has SSBS (speculative store bypass safe instruction).
|
||||||
kSSBS2, //!< CPU has SSBS2 (MRS and MSR instructions for SSBS).
|
kSSBS2, //!< CPU has SSBS2 (MRS and MSR instructions for SSBS).
|
||||||
|
kSSVE_AES, //!< CPU has SSVE_AES {A64}.
|
||||||
|
kSSVE_BITPERM, //!< CPU has SSVE_BITPERM {A64}.
|
||||||
|
kSSVE_FEXPA, //!< CPU has SSVE_FEXPA {A64}.
|
||||||
kSSVE_FP8DOT2, //!< CPU has SSVE_FP8DOT2 (SVE2 FP8 2-way dot product to half-precision instructions in Streaming SVE mode) {A64}.
|
kSSVE_FP8DOT2, //!< CPU has SSVE_FP8DOT2 (SVE2 FP8 2-way dot product to half-precision instructions in Streaming SVE mode) {A64}.
|
||||||
kSSVE_FP8DOT4, //!< CPU has SSVE_FP8DOT4 (SVE2 FP8 4-way dot product to single-precision instructions in Streaming SVE mode) {A64}.
|
kSSVE_FP8DOT4, //!< CPU has SSVE_FP8DOT4 (SVE2 FP8 4-way dot product to single-precision instructions in Streaming SVE mode) {A64}.
|
||||||
kSSVE_FP8FMA, //!< CPU has SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) {A64}.
|
kSSVE_FP8FMA, //!< CPU has SSVE_FP8FMA (SVE2 FP8 multiply-accumulate to half-precision and single-precision instructions in Streaming SVE mode) {A64}.
|
||||||
kSVE, //!< CPU has SVE (SVE v1 - scalable vector extension) {A64}.
|
kSVE, //!< CPU has SVE (SVE v1 - scalable vector extension) {A64}.
|
||||||
kSVE2, //!< CPU has SVE2 (SVE v2) {A64}.
|
kSVE2, //!< CPU has SVE2 (SVE v2) {A64}.
|
||||||
kSVE2_1, //!< CPU has SVE2p1 (SVE v2.1) {A64}.
|
kSVE2_1, //!< CPU has SVE2p1 (SVE v2.1) {A64}.
|
||||||
|
kSVE2_2, //!< CPU has SVE2p2 (SVE v2.2) {A64}.
|
||||||
kSVE_AES, //!< CPU has SVE_AES (SVE AES instructions) {A64}.
|
kSVE_AES, //!< CPU has SVE_AES (SVE AES instructions) {A64}.
|
||||||
|
kSVE_AES2, //!< CPU has SVE_AES2 {A64}.
|
||||||
kSVE_B16B16, //!< CPU has SVE_B16B16 (SVE non-widening BFloat16 to BFloat16 arithmetic) {A64}.
|
kSVE_B16B16, //!< CPU has SVE_B16B16 (SVE non-widening BFloat16 to BFloat16 arithmetic) {A64}.
|
||||||
kSVE_BF16, //!< CPU has SVE_BF16 (SVE BF16 instructions) {A64}.
|
kSVE_BF16, //!< CPU has SVE_BF16 (SVE BF16 instructions) {A64}.
|
||||||
|
kSVE_BFSCALE, //!< CPU has SVE_BFSCALE {A64}.
|
||||||
kSVE_BITPERM, //!< CPU has SVE_BITPERM (SVE bit permute) {A64}.
|
kSVE_BITPERM, //!< CPU has SVE_BITPERM (SVE bit permute) {A64}.
|
||||||
kSVE_EBF16, //!< CPU has SVE_EBF16 (SVE extended BFloat16 mode) {A64}.
|
kSVE_EBF16, //!< CPU has SVE_EBF16 (SVE extended BFloat16 mode) {A64}.
|
||||||
|
kSVE_ELTPERM, //!< CPU has SVE_ELTPERM {A64}.
|
||||||
|
kSVE_F16MM, //!< CPU has SVE_F16MM (SVE half-precision floating-point matrix multiply instruction) {A64}.
|
||||||
kSVE_F32MM, //!< CPU has SVE_F32MM (SVE single-precision floating-point matrix multiply instruction) {A64}.
|
kSVE_F32MM, //!< CPU has SVE_F32MM (SVE single-precision floating-point matrix multiply instruction) {A64}.
|
||||||
kSVE_F64MM, //!< CPU has SVE_F64MM (SVE double-precision floating-point matrix multiply instruction) {A64}.
|
kSVE_F64MM, //!< CPU has SVE_F64MM (SVE double-precision floating-point matrix multiply instruction) {A64}.
|
||||||
kSVE_I8MM, //!< CPU has SVE_I8MM (SVE int8 matrix multiplication) {A64}.
|
kSVE_I8MM, //!< CPU has SVE_I8MM (SVE int8 matrix multiplication) {A64}.
|
||||||
@@ -773,6 +795,7 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(CHK)
|
ASMJIT_ARM_FEATURE(CHK)
|
||||||
ASMJIT_ARM_FEATURE(CLRBHB)
|
ASMJIT_ARM_FEATURE(CLRBHB)
|
||||||
ASMJIT_ARM_FEATURE(CMOW)
|
ASMJIT_ARM_FEATURE(CMOW)
|
||||||
|
ASMJIT_ARM_FEATURE(CMPBR)
|
||||||
ASMJIT_ARM_FEATURE(CONSTPACFIELD)
|
ASMJIT_ARM_FEATURE(CONSTPACFIELD)
|
||||||
ASMJIT_ARM_FEATURE(CPA)
|
ASMJIT_ARM_FEATURE(CPA)
|
||||||
ASMJIT_ARM_FEATURE(CPA2)
|
ASMJIT_ARM_FEATURE(CPA2)
|
||||||
@@ -794,6 +817,10 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(ECV)
|
ASMJIT_ARM_FEATURE(ECV)
|
||||||
ASMJIT_ARM_FEATURE(EDHSR)
|
ASMJIT_ARM_FEATURE(EDHSR)
|
||||||
ASMJIT_ARM_FEATURE(EDSP)
|
ASMJIT_ARM_FEATURE(EDSP)
|
||||||
|
ASMJIT_ARM_FEATURE(F8E4M3)
|
||||||
|
ASMJIT_ARM_FEATURE(F8E5M2)
|
||||||
|
ASMJIT_ARM_FEATURE(F8F16MM)
|
||||||
|
ASMJIT_ARM_FEATURE(F8F32MM)
|
||||||
ASMJIT_ARM_FEATURE(FAMINMAX)
|
ASMJIT_ARM_FEATURE(FAMINMAX)
|
||||||
ASMJIT_ARM_FEATURE(FCMA)
|
ASMJIT_ARM_FEATURE(FCMA)
|
||||||
ASMJIT_ARM_FEATURE(FGT)
|
ASMJIT_ARM_FEATURE(FGT)
|
||||||
@@ -810,6 +837,7 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(FP8DOT4)
|
ASMJIT_ARM_FEATURE(FP8DOT4)
|
||||||
ASMJIT_ARM_FEATURE(FP8FMA)
|
ASMJIT_ARM_FEATURE(FP8FMA)
|
||||||
ASMJIT_ARM_FEATURE(FPMR)
|
ASMJIT_ARM_FEATURE(FPMR)
|
||||||
|
ASMJIT_ARM_FEATURE(FPRCVT)
|
||||||
ASMJIT_ARM_FEATURE(FRINTTS)
|
ASMJIT_ARM_FEATURE(FRINTTS)
|
||||||
ASMJIT_ARM_FEATURE(GCS)
|
ASMJIT_ARM_FEATURE(GCS)
|
||||||
ASMJIT_ARM_FEATURE(HACDBS)
|
ASMJIT_ARM_FEATURE(HACDBS)
|
||||||
@@ -832,9 +860,12 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(LS64)
|
ASMJIT_ARM_FEATURE(LS64)
|
||||||
ASMJIT_ARM_FEATURE(LS64_ACCDATA)
|
ASMJIT_ARM_FEATURE(LS64_ACCDATA)
|
||||||
ASMJIT_ARM_FEATURE(LS64_V)
|
ASMJIT_ARM_FEATURE(LS64_V)
|
||||||
|
ASMJIT_ARM_FEATURE(LS64WB)
|
||||||
ASMJIT_ARM_FEATURE(LSE)
|
ASMJIT_ARM_FEATURE(LSE)
|
||||||
ASMJIT_ARM_FEATURE(LSE128)
|
ASMJIT_ARM_FEATURE(LSE128)
|
||||||
ASMJIT_ARM_FEATURE(LSE2)
|
ASMJIT_ARM_FEATURE(LSE2)
|
||||||
|
ASMJIT_ARM_FEATURE(LSFE)
|
||||||
|
ASMJIT_ARM_FEATURE(LSUI)
|
||||||
ASMJIT_ARM_FEATURE(LUT)
|
ASMJIT_ARM_FEATURE(LUT)
|
||||||
ASMJIT_ARM_FEATURE(LVA)
|
ASMJIT_ARM_FEATURE(LVA)
|
||||||
ASMJIT_ARM_FEATURE(LVA3)
|
ASMJIT_ARM_FEATURE(LVA3)
|
||||||
@@ -856,6 +887,7 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(NMI)
|
ASMJIT_ARM_FEATURE(NMI)
|
||||||
ASMJIT_ARM_FEATURE(NV)
|
ASMJIT_ARM_FEATURE(NV)
|
||||||
ASMJIT_ARM_FEATURE(NV2)
|
ASMJIT_ARM_FEATURE(NV2)
|
||||||
|
ASMJIT_ARM_FEATURE(OCCMO)
|
||||||
ASMJIT_ARM_FEATURE(PAN)
|
ASMJIT_ARM_FEATURE(PAN)
|
||||||
ASMJIT_ARM_FEATURE(PAN2)
|
ASMJIT_ARM_FEATURE(PAN2)
|
||||||
ASMJIT_ARM_FEATURE(PAN3)
|
ASMJIT_ARM_FEATURE(PAN3)
|
||||||
@@ -891,6 +923,8 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(SME)
|
ASMJIT_ARM_FEATURE(SME)
|
||||||
ASMJIT_ARM_FEATURE(SME2)
|
ASMJIT_ARM_FEATURE(SME2)
|
||||||
ASMJIT_ARM_FEATURE(SME2_1)
|
ASMJIT_ARM_FEATURE(SME2_1)
|
||||||
|
ASMJIT_ARM_FEATURE(SME2_2)
|
||||||
|
ASMJIT_ARM_FEATURE(SME_AES)
|
||||||
ASMJIT_ARM_FEATURE(SME_B16B16)
|
ASMJIT_ARM_FEATURE(SME_B16B16)
|
||||||
ASMJIT_ARM_FEATURE(SME_B16F32)
|
ASMJIT_ARM_FEATURE(SME_B16F32)
|
||||||
ASMJIT_ARM_FEATURE(SME_BI32I32)
|
ASMJIT_ARM_FEATURE(SME_BI32I32)
|
||||||
@@ -905,6 +939,8 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(SME_I16I64)
|
ASMJIT_ARM_FEATURE(SME_I16I64)
|
||||||
ASMJIT_ARM_FEATURE(SME_I8I32)
|
ASMJIT_ARM_FEATURE(SME_I8I32)
|
||||||
ASMJIT_ARM_FEATURE(SME_LUTv2)
|
ASMJIT_ARM_FEATURE(SME_LUTv2)
|
||||||
|
ASMJIT_ARM_FEATURE(SME_MOP4)
|
||||||
|
ASMJIT_ARM_FEATURE(SME_TMOP)
|
||||||
ASMJIT_ARM_FEATURE(SPE)
|
ASMJIT_ARM_FEATURE(SPE)
|
||||||
ASMJIT_ARM_FEATURE(SPE1_1)
|
ASMJIT_ARM_FEATURE(SPE1_1)
|
||||||
ASMJIT_ARM_FEATURE(SPE1_2)
|
ASMJIT_ARM_FEATURE(SPE1_2)
|
||||||
@@ -921,17 +957,25 @@ public:
|
|||||||
ASMJIT_ARM_FEATURE(SPMU)
|
ASMJIT_ARM_FEATURE(SPMU)
|
||||||
ASMJIT_ARM_FEATURE(SSBS)
|
ASMJIT_ARM_FEATURE(SSBS)
|
||||||
ASMJIT_ARM_FEATURE(SSBS2)
|
ASMJIT_ARM_FEATURE(SSBS2)
|
||||||
|
ASMJIT_ARM_FEATURE(SSVE_AES)
|
||||||
|
ASMJIT_ARM_FEATURE(SSVE_BITPERM)
|
||||||
|
ASMJIT_ARM_FEATURE(SSVE_FEXPA)
|
||||||
ASMJIT_ARM_FEATURE(SSVE_FP8DOT2)
|
ASMJIT_ARM_FEATURE(SSVE_FP8DOT2)
|
||||||
ASMJIT_ARM_FEATURE(SSVE_FP8DOT4)
|
ASMJIT_ARM_FEATURE(SSVE_FP8DOT4)
|
||||||
ASMJIT_ARM_FEATURE(SSVE_FP8FMA)
|
ASMJIT_ARM_FEATURE(SSVE_FP8FMA)
|
||||||
ASMJIT_ARM_FEATURE(SVE)
|
ASMJIT_ARM_FEATURE(SVE)
|
||||||
ASMJIT_ARM_FEATURE(SVE2)
|
ASMJIT_ARM_FEATURE(SVE2)
|
||||||
ASMJIT_ARM_FEATURE(SVE2_1)
|
ASMJIT_ARM_FEATURE(SVE2_1)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2_2)
|
||||||
ASMJIT_ARM_FEATURE(SVE_AES)
|
ASMJIT_ARM_FEATURE(SVE_AES)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_AES2)
|
||||||
ASMJIT_ARM_FEATURE(SVE_B16B16)
|
ASMJIT_ARM_FEATURE(SVE_B16B16)
|
||||||
ASMJIT_ARM_FEATURE(SVE_BF16)
|
ASMJIT_ARM_FEATURE(SVE_BF16)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_BFSCALE)
|
||||||
ASMJIT_ARM_FEATURE(SVE_BITPERM)
|
ASMJIT_ARM_FEATURE(SVE_BITPERM)
|
||||||
ASMJIT_ARM_FEATURE(SVE_EBF16)
|
ASMJIT_ARM_FEATURE(SVE_EBF16)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_ELTPERM)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_F16MM)
|
||||||
ASMJIT_ARM_FEATURE(SVE_F32MM)
|
ASMJIT_ARM_FEATURE(SVE_F32MM)
|
||||||
ASMJIT_ARM_FEATURE(SVE_F64MM)
|
ASMJIT_ARM_FEATURE(SVE_F64MM)
|
||||||
ASMJIT_ARM_FEATURE(SVE_I8MM)
|
ASMJIT_ARM_FEATURE(SVE_I8MM)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -75,12 +75,12 @@ Error BaseEmitHelper::emitRegMove(const Operand_& dst_, const Operand_& src_, Ty
|
|||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitHelper::emitRegSwap(const BaseReg& a, const BaseReg& b, const char* comment) {
|
Error BaseEmitHelper::emitRegSwap(const Reg& a, const Reg& b, const char* comment) {
|
||||||
DebugUtils::unused(a, b, comment);
|
DebugUtils::unused(a, b, comment);
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitHelper::emitArgMove(const BaseReg& dst_, TypeId dstTypeId, const Operand_& src_, TypeId srcTypeId, const char* comment) {
|
Error BaseEmitHelper::emitArgMove(const Reg& dst_, TypeId dstTypeId, const Operand_& src_, TypeId srcTypeId, const char* comment) {
|
||||||
DebugUtils::unused(dst_, dstTypeId, src_, srcTypeId, comment);
|
DebugUtils::unused(dst_, dstTypeId, src_, srcTypeId, comment);
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
@@ -120,8 +120,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
uint32_t varCount = ctx._varCount;
|
uint32_t varCount = ctx._varCount;
|
||||||
uint32_t saVarId = ctx._saVarId;
|
uint32_t saVarId = ctx._saVarId;
|
||||||
|
|
||||||
BaseReg sp = BaseReg(_emitter->_gpSignature, archTraits.spRegId());
|
Reg sp = Reg(_emitter->_gpSignature, archTraits.spRegId());
|
||||||
BaseReg sa = sp;
|
Reg sa = sp;
|
||||||
|
|
||||||
if (frame.hasDynamicAlignment()) {
|
if (frame.hasDynamicAlignment()) {
|
||||||
if (frame.hasPreservedFP()) {
|
if (frame.hasPreservedFP()) {
|
||||||
@@ -151,7 +151,7 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
FuncValue& out = var.out;
|
FuncValue& out = var.out;
|
||||||
|
|
||||||
ASMJIT_ASSERT(cur.isReg() || cur.isStack());
|
ASMJIT_ASSERT(cur.isReg() || cur.isStack());
|
||||||
BaseReg reg;
|
Reg reg;
|
||||||
|
|
||||||
BaseMem dstStackPtr = baseStackPtr.cloneAdjusted(out.stackOffset());
|
BaseMem dstStackPtr = baseStackPtr.cloneAdjusted(out.stackOffset());
|
||||||
BaseMem srcStackPtr = baseArgPtr.cloneAdjusted(cur.stackOffset());
|
BaseMem srcStackPtr = baseArgPtr.cloneAdjusted(cur.stackOffset());
|
||||||
@@ -167,10 +167,10 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (cur.isReg() && !cur.isIndirect()) {
|
if (cur.isReg() && !cur.isIndirect()) {
|
||||||
WorkData& wd = workData[archTraits.regTypeToGroup(cur.regType())];
|
WorkData& wd = workData[RegUtils::groupOf(cur.regType())];
|
||||||
uint32_t regId = cur.regId();
|
uint32_t regId = cur.regId();
|
||||||
|
|
||||||
reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), regId);
|
reg.setSignatureAndId(RegUtils::signatureOf(cur.regType()), regId);
|
||||||
wd.unassign(varId, regId);
|
wd.unassign(varId, regId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -217,8 +217,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
FuncValue& cur = var.cur;
|
FuncValue& cur = var.cur;
|
||||||
FuncValue& out = var.out;
|
FuncValue& out = var.out;
|
||||||
|
|
||||||
RegGroup curGroup = archTraits.regTypeToGroup(cur.regType());
|
RegGroup curGroup = RegUtils::groupOf(cur.regType());
|
||||||
RegGroup outGroup = archTraits.regTypeToGroup(out.regType());
|
RegGroup outGroup = RegUtils::groupOf(out.regType());
|
||||||
|
|
||||||
uint32_t curId = cur.regId();
|
uint32_t curId = cur.regId();
|
||||||
uint32_t outId = out.regId();
|
uint32_t outId = out.regId();
|
||||||
@@ -233,8 +233,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
EmitMove:
|
EmitMove:
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(
|
||||||
emitArgMove(
|
emitArgMove(
|
||||||
BaseReg(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
|
Reg(RegUtils::signatureOf(out.regType()), outId), out.typeId(),
|
||||||
BaseReg(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
|
Reg(RegUtils::signatureOf(cur.regType()), curId), cur.typeId()));
|
||||||
|
|
||||||
// Only reassign if this is not a sign/zero extension that happens on the same in/out register.
|
// Only reassign if this is not a sign/zero extension that happens on the same in/out register.
|
||||||
if (curId != outId) {
|
if (curId != outId) {
|
||||||
@@ -260,8 +260,8 @@ EmitMove:
|
|||||||
highestType = RegType::kGp32;
|
highestType = RegType::kGp32;
|
||||||
}
|
}
|
||||||
|
|
||||||
OperandSignature signature = archTraits.regTypeToSignature(highestType);
|
OperandSignature signature = RegUtils::signatureOf(highestType);
|
||||||
ASMJIT_PROPAGATE(emitRegSwap(BaseReg(signature, outId), BaseReg(signature, curId)));
|
ASMJIT_PROPAGATE(emitRegSwap(Reg(signature, outId), Reg(signature, curId)));
|
||||||
|
|
||||||
wd.swap(varId, curId, altId, outId);
|
wd.swap(varId, curId, altId, outId);
|
||||||
cur.setRegId(outId);
|
cur.setRegId(outId);
|
||||||
@@ -333,7 +333,7 @@ EmitMove:
|
|||||||
uint32_t outId = var.out.regId();
|
uint32_t outId = var.out.regId();
|
||||||
RegType outType = var.out.regType();
|
RegType outType = var.out.regType();
|
||||||
|
|
||||||
RegGroup group = archTraits.regTypeToGroup(outType);
|
RegGroup group = RegUtils::groupOf(outType);
|
||||||
WorkData& wd = workData[group];
|
WorkData& wd = workData[group];
|
||||||
|
|
||||||
if (outId == sa.id() && group == RegGroup::kGp) {
|
if (outId == sa.id() && group == RegGroup::kGp) {
|
||||||
@@ -345,7 +345,7 @@ EmitMove:
|
|||||||
wd.unassign(wd._physToVarId[outId], outId);
|
wd.unassign(wd._physToVarId[outId], outId);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseReg dstReg = BaseReg(archTraits.regTypeToSignature(outType), outId);
|
Reg dstReg = Reg(RegUtils::signatureOf(outType), outId);
|
||||||
BaseMem srcMem = baseArgPtr.cloneAdjusted(var.cur.stackOffset());
|
BaseMem srcMem = baseArgPtr.cloneAdjusted(var.cur.stackOffset());
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(emitArgMove(
|
ASMJIT_PROPAGATE(emitArgMove(
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
||||||
@@ -39,8 +39,8 @@ public:
|
|||||||
|
|
||||||
//! Emits swap between two registers.
|
//! Emits swap between two registers.
|
||||||
virtual Error emitRegSwap(
|
virtual Error emitRegSwap(
|
||||||
const BaseReg& a,
|
const Reg& a,
|
||||||
const BaseReg& b, const char* comment = nullptr);
|
const Reg& b, const char* comment = nullptr);
|
||||||
|
|
||||||
//! Emits move from a function argument (either register or stack) to a register.
|
//! Emits move from a function argument (either register or stack) to a register.
|
||||||
//!
|
//!
|
||||||
@@ -48,7 +48,7 @@ public:
|
|||||||
//! to another, if it's possible. Any attempt of conversion that requires third register of a different group
|
//! to another, if it's possible. Any attempt of conversion that requires third register of a different group
|
||||||
//! (for example conversion from K to MMX on X86/X64) will fail.
|
//! (for example conversion from K to MMX on X86/X64) will fail.
|
||||||
virtual Error emitArgMove(
|
virtual Error emitArgMove(
|
||||||
const BaseReg& dst_, TypeId dstTypeId,
|
const Reg& dst_, TypeId dstTypeId,
|
||||||
const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr);
|
const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr);
|
||||||
|
|
||||||
Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -121,7 +121,9 @@ void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::reportError(Error err, const char* message) {
|
Error BaseEmitter::_reportError(Error err, const char* message) {
|
||||||
|
ASMJIT_ASSERT(err != kErrorOk);
|
||||||
|
|
||||||
ErrorHandler* eh = _errorHandler;
|
ErrorHandler* eh = _errorHandler;
|
||||||
if (eh) {
|
if (eh) {
|
||||||
if (!message) {
|
if (!message) {
|
||||||
@@ -129,6 +131,7 @@ Error BaseEmitter::reportError(Error err, const char* message) {
|
|||||||
}
|
}
|
||||||
eh->handleError(err, message, this);
|
eh->handleError(err, message, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -370,20 +373,22 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) {
|
|||||||
// BaseEmitter - Events
|
// BaseEmitter - Events
|
||||||
// ====================
|
// ====================
|
||||||
|
|
||||||
Error BaseEmitter::onAttach(CodeHolder* code) noexcept {
|
Error BaseEmitter::onAttach(CodeHolder& code) noexcept {
|
||||||
_code = code;
|
_code = &code;
|
||||||
_environment = code->environment();
|
_environment = code.environment();
|
||||||
_addEmitterFlags(EmitterFlags::kAttached);
|
_addEmitterFlags(EmitterFlags::kAttached);
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
_gpSignature.setBits(
|
||||||
RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
|
Environment::is32Bit(code.arch())
|
||||||
_gpSignature = archTraits.regTypeToSignature(nativeRegType);
|
? RegTraits<RegType::kGp32>::kSignature
|
||||||
|
: RegTraits<RegType::kGp64>::kSignature
|
||||||
|
);
|
||||||
|
|
||||||
onSettingsUpdated();
|
onSettingsUpdated();
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
|
Error BaseEmitter::onDetach(CodeHolder& code) noexcept {
|
||||||
DebugUtils::unused(code);
|
DebugUtils::unused(code);
|
||||||
|
|
||||||
if (!hasOwnLogger()) {
|
if (!hasOwnLogger()) {
|
||||||
@@ -405,7 +410,17 @@ Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
|
|||||||
_instOptions = InstOptions::kNone;
|
_instOptions = InstOptions::kNone;
|
||||||
_extraReg.reset();
|
_extraReg.reset();
|
||||||
_inlineComment = nullptr;
|
_inlineComment = nullptr;
|
||||||
_funcs.reset();
|
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error BaseEmitter::onReinit(CodeHolder& code) noexcept {
|
||||||
|
ASMJIT_ASSERT(_code == &code);
|
||||||
|
DebugUtils::unused(code);
|
||||||
|
|
||||||
|
_instOptions = InstOptions::kNone;
|
||||||
|
_extraReg.reset();
|
||||||
|
_inlineComment = nullptr;
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
|
||||||
@@ -186,7 +186,7 @@ enum class DiagnosticOptions : uint32_t {
|
|||||||
kRADebugUnreachable = 0x00000800u,
|
kRADebugUnreachable = 0x00000800u,
|
||||||
|
|
||||||
//! Enable all debug options (Compiler/RA).
|
//! Enable all debug options (Compiler/RA).
|
||||||
kRADebugAll = 0x0000FF00u,
|
kRADebugAll = 0x0000FF00u
|
||||||
};
|
};
|
||||||
ASMJIT_DEFINE_ENUM_FLAGS(DiagnosticOptions)
|
ASMJIT_DEFINE_ENUM_FLAGS(DiagnosticOptions)
|
||||||
|
|
||||||
@@ -196,49 +196,9 @@ public:
|
|||||||
ASMJIT_BASE_CLASS(BaseEmitter)
|
ASMJIT_BASE_CLASS(BaseEmitter)
|
||||||
ASMJIT_NONCOPYABLE(BaseEmitter)
|
ASMJIT_NONCOPYABLE(BaseEmitter)
|
||||||
|
|
||||||
//! \name Members
|
//! \name Types
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! See \ref EmitterType.
|
|
||||||
EmitterType _emitterType = EmitterType::kNone;
|
|
||||||
//! See \ref EmitterFlags.
|
|
||||||
EmitterFlags _emitterFlags = EmitterFlags::kNone;
|
|
||||||
//! Instruction alignment.
|
|
||||||
uint8_t _instructionAlignment = 0u;
|
|
||||||
//! \cond
|
|
||||||
uint8_t _reservedBaseEmitter = 0u;
|
|
||||||
//! \endcond
|
|
||||||
//! Validation flags in case validation is used.
|
|
||||||
//!
|
|
||||||
//! \note Validation flags are specific to the emitter and they are setup at construction time and then never
|
|
||||||
//! changed.
|
|
||||||
ValidationFlags _validationFlags = ValidationFlags::kNone;
|
|
||||||
//! Validation options.
|
|
||||||
DiagnosticOptions _diagnosticOptions = DiagnosticOptions::kNone;
|
|
||||||
|
|
||||||
//! All supported architectures in a bit-mask, where LSB is the bit with a zero index.
|
|
||||||
uint64_t _archMask = 0;
|
|
||||||
|
|
||||||
//! Encoding options.
|
|
||||||
EncodingOptions _encodingOptions = EncodingOptions::kNone;
|
|
||||||
|
|
||||||
//! Forced instruction options, combined with \ref _instOptions by \ref emit().
|
|
||||||
InstOptions _forcedInstOptions = InstOptions::kReserved;
|
|
||||||
//! Internal private data used freely by any emitter.
|
|
||||||
uint32_t _privateData = 0;
|
|
||||||
|
|
||||||
//! CodeHolder the emitter is attached to.
|
|
||||||
CodeHolder* _code = nullptr;
|
|
||||||
//! Attached \ref Logger.
|
|
||||||
Logger* _logger = nullptr;
|
|
||||||
//! Attached \ref ErrorHandler.
|
|
||||||
ErrorHandler* _errorHandler = nullptr;
|
|
||||||
|
|
||||||
//! Describes the target environment, matches \ref CodeHolder::environment().
|
|
||||||
Environment _environment {};
|
|
||||||
//! Native GP register signature and signature related information.
|
|
||||||
OperandSignature _gpSignature {};
|
|
||||||
|
|
||||||
//! Emitter state that can be used to specify options and inline comment of a next node or instruction.
|
//! Emitter state that can be used to specify options and inline comment of a next node or instruction.
|
||||||
struct State {
|
struct State {
|
||||||
InstOptions options;
|
InstOptions options;
|
||||||
@@ -246,14 +206,7 @@ public:
|
|||||||
const char* comment;
|
const char* comment;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Next instruction options (affects the next instruction).
|
//! Functions used by backend-specific emitter implementation.
|
||||||
InstOptions _instOptions = InstOptions::kNone;
|
|
||||||
//! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
|
||||||
RegOnly _extraReg {};
|
|
||||||
//! Inline comment of the next instruction (affects the next instruction).
|
|
||||||
const char* _inlineComment = nullptr;
|
|
||||||
|
|
||||||
//! Function callbacks used by emitter implementation.
|
|
||||||
//!
|
//!
|
||||||
//! These are typically shared between Assembler/Builder/Compiler of a single backend.
|
//! These are typically shared between Assembler/Builder/Compiler of a single backend.
|
||||||
struct Funcs {
|
struct Funcs {
|
||||||
@@ -282,16 +235,73 @@ public:
|
|||||||
ValidateFunc validate;
|
ValidateFunc validate;
|
||||||
|
|
||||||
//! Resets all functions to nullptr.
|
//! Resets all functions to nullptr.
|
||||||
ASMJIT_INLINE_NODEBUG void reset() noexcept {
|
ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = Funcs{}; }
|
||||||
emitProlog = nullptr;
|
|
||||||
emitEpilog = nullptr;
|
|
||||||
emitArgsAssignment = nullptr;
|
|
||||||
validate = nullptr;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! See \ref EmitterType.
|
||||||
|
EmitterType _emitterType = EmitterType::kNone;
|
||||||
|
|
||||||
|
//! See \ref EmitterFlags.
|
||||||
|
EmitterFlags _emitterFlags = EmitterFlags::kNone;
|
||||||
|
|
||||||
|
//! Instruction alignment.
|
||||||
|
uint8_t _instructionAlignment = 0u;
|
||||||
|
|
||||||
|
//! Validation flags in case validation is used.
|
||||||
|
//!
|
||||||
|
//! \note Validation flags are specific to the emitter and they are setup at construction time and then never
|
||||||
|
//! changed.
|
||||||
|
ValidationFlags _validationFlags = ValidationFlags::kNone;
|
||||||
|
|
||||||
|
//! Validation options.
|
||||||
|
DiagnosticOptions _diagnosticOptions = DiagnosticOptions::kNone;
|
||||||
|
|
||||||
|
//! Encoding options.
|
||||||
|
EncodingOptions _encodingOptions = EncodingOptions::kNone;
|
||||||
|
|
||||||
|
//! Forced instruction options, combined with \ref _instOptions by \ref emit().
|
||||||
|
InstOptions _forcedInstOptions = InstOptions::kReserved;
|
||||||
|
|
||||||
|
//! All supported architectures in a bit-mask, where LSB is the bit with a zero index.
|
||||||
|
uint64_t _archMask = 0;
|
||||||
|
|
||||||
|
//! CodeHolder the emitter is attached to.
|
||||||
|
CodeHolder* _code = nullptr;
|
||||||
|
|
||||||
|
//! Attached \ref Logger.
|
||||||
|
Logger* _logger = nullptr;
|
||||||
|
|
||||||
|
//! Attached \ref ErrorHandler.
|
||||||
|
ErrorHandler* _errorHandler = nullptr;
|
||||||
|
|
||||||
|
//! Describes the target environment, matches \ref CodeHolder::environment().
|
||||||
|
Environment _environment {};
|
||||||
|
|
||||||
|
//! Native GP register signature (either a 32-bit or 64-bit GP register signature).
|
||||||
|
OperandSignature _gpSignature {};
|
||||||
|
//! Internal private data used freely by any emitter.
|
||||||
|
uint32_t _privateData = 0;
|
||||||
|
|
||||||
|
//! Next instruction options (affects the next instruction).
|
||||||
|
InstOptions _instOptions = InstOptions::kNone;
|
||||||
|
//! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
||||||
|
RegOnly _extraReg {};
|
||||||
|
//! Inline comment of the next instruction (affects the next instruction).
|
||||||
|
const char* _inlineComment = nullptr;
|
||||||
|
|
||||||
|
//! Pointer to functions used by backend-specific emitter implementation.
|
||||||
Funcs _funcs {};
|
Funcs _funcs {};
|
||||||
|
|
||||||
|
//! Emitter attached before this emitter in \ref CodeHolder, otherwise nullptr if there is no emitter before.
|
||||||
|
BaseEmitter* _attachedPrev = nullptr;
|
||||||
|
//! Emitter attached after this emitter in \ref CodeHolder, otherwise nullptr if there is no emitter after.
|
||||||
|
BaseEmitter* _attachedNext = nullptr;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
@@ -493,11 +503,23 @@ public:
|
|||||||
//! Resets the error handler.
|
//! Resets the error handler.
|
||||||
ASMJIT_INLINE_NODEBUG void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
ASMJIT_INLINE_NODEBUG void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
ASMJIT_API Error _reportError(Error err, const char* message = nullptr);
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! Handles the given error in the following way:
|
//! Handles the given error in the following way:
|
||||||
//! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
|
//! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
|
||||||
//! first, and then returns the error. The `handleError()` function may throw.
|
//! first, and then returns the error. The `handleError()` function may throw.
|
||||||
//! 2. if the emitter doesn't have \ref ErrorHandler, the error is simply returned.
|
//! 2. if the emitter doesn't have \ref ErrorHandler, the error is simply returned.
|
||||||
ASMJIT_API Error reportError(Error err, const char* message = nullptr);
|
ASMJIT_INLINE Error reportError(Error err, const char* message = nullptr) {
|
||||||
|
Error e = _reportError(err, message);
|
||||||
|
|
||||||
|
// Static analysis is not working properly without these assumptions.
|
||||||
|
ASMJIT_ASSUME(e == err);
|
||||||
|
ASMJIT_ASSUME(e != kErrorOk);
|
||||||
|
|
||||||
|
return e;
|
||||||
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -590,7 +612,7 @@ public:
|
|||||||
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _extraReg; }
|
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _extraReg; }
|
||||||
|
|
||||||
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); }
|
||||||
|
|
||||||
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
//! Sets an extra operand that will be used by the next instruction (architecture specific).
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
||||||
@@ -856,10 +878,13 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Called after the emitter was attached to `CodeHolder`.
|
//! Called after the emitter was attached to `CodeHolder`.
|
||||||
ASMJIT_API virtual Error onAttach(CodeHolder* ASMJIT_NONNULL(code)) noexcept;
|
ASMJIT_API virtual Error onAttach(CodeHolder& code) noexcept;
|
||||||
|
|
||||||
//! Called after the emitter was detached from `CodeHolder`.
|
//! Called after the emitter was detached from `CodeHolder`.
|
||||||
ASMJIT_API virtual Error onDetach(CodeHolder* ASMJIT_NONNULL(code)) noexcept;
|
ASMJIT_API virtual Error onDetach(CodeHolder& code) noexcept;
|
||||||
|
|
||||||
|
//! Called when CodeHolder is reinitialized when the emitter is attached.
|
||||||
|
ASMJIT_API virtual Error onReinit(CodeHolder& code) noexcept;
|
||||||
|
|
||||||
//! Called when \ref CodeHolder has updated an important setting, which involves the following:
|
//! Called when \ref CodeHolder has updated an important setting, which involves the following:
|
||||||
//!
|
//!
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
||||||
|
|||||||
282
src/asmjit/core/fixup.h
Normal file
282
src/asmjit/core/fixup.h
Normal file
@@ -0,0 +1,282 @@
|
|||||||
|
// 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_CORE_FIXUP_H_INCLUDED
|
||||||
|
#define ASMJIT_CORE_FIXUP_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../core/globals.h"
|
||||||
|
|
||||||
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
//! \addtogroup asmjit_core
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Offset format type, used by \ref OffsetFormat.
|
||||||
|
enum class OffsetType : uint8_t {
|
||||||
|
// Common Offset Formats
|
||||||
|
// ---------------------
|
||||||
|
|
||||||
|
//! A value having `_immBitCount` bits and shifted by `_immBitShift`.
|
||||||
|
//!
|
||||||
|
//! This offset type is sufficient for many targets that store offset as a continuous set bits within an
|
||||||
|
//! instruction word / sequence of bytes.
|
||||||
|
kSignedOffset,
|
||||||
|
|
||||||
|
//! An unsigned value having `_immBitCount` bits and shifted by `_immBitShift`.
|
||||||
|
kUnsignedOffset,
|
||||||
|
|
||||||
|
// AArch64 Specific Offset Formats
|
||||||
|
// -------------------------------
|
||||||
|
|
||||||
|
//! AArch64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
|
||||||
|
kAArch64_ADR,
|
||||||
|
|
||||||
|
//! AArch64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
|
||||||
|
kAArch64_ADRP,
|
||||||
|
|
||||||
|
// AArch32 Specific Offset Formats (T16 & T32)
|
||||||
|
// -------------------------------------------
|
||||||
|
|
||||||
|
//! AArch32 THUMBv2 immediate encoding of 'ADR' instruction (12-bit payload and sign bit):
|
||||||
|
//!
|
||||||
|
//! `|.....|imm:1|..N.N|......|imm:3|....|imm:8|`
|
||||||
|
//!
|
||||||
|
//! Where `N` is one if the offset is negative. The immediate is encoded as absolute value of the offset if negative.
|
||||||
|
kThumb32_ADR,
|
||||||
|
|
||||||
|
//! AArch32 THUMBv2 immediate encoding of 'BLX' instruction (23-bit immediate payload, multiplied by 4):
|
||||||
|
//!
|
||||||
|
//! `|.....|imm[22]|imm[19:10]|..|ja|1|jb|imm[9:0]|0`
|
||||||
|
//!
|
||||||
|
//! Where:
|
||||||
|
//!
|
||||||
|
//! - `ja` is calculated as imm[22] ^ imm[21] ^ 1.
|
||||||
|
//! - `jb` is calculated as imm[22] ^ imm[20] ^ 1.
|
||||||
|
kThumb32_BLX,
|
||||||
|
|
||||||
|
//! AArch32 THUMBv2 immediate encoding of 'B' instruction without `<cond>` (24-bit immediate payload, multiplied by 2):
|
||||||
|
//!
|
||||||
|
//! `|.....|imm[23]|imm[20:11]|..|ja|1|jb|imm[10:0]`
|
||||||
|
//!
|
||||||
|
//! Where:
|
||||||
|
//!
|
||||||
|
//! - `ja` is calculated as imm[23] ^ imm[22] ^ 1.
|
||||||
|
//! - `jb` is calculated as imm[23] ^ imm[21] ^ 1.
|
||||||
|
kThumb32_B,
|
||||||
|
|
||||||
|
//! AArch32 THUMBv2 immediate encoding of 'B' instruction with `<cond>` (20-bit immediate payload, multiplied by 2).
|
||||||
|
//!
|
||||||
|
//! `|.....|imm[19]|....|imm[16:11]|..|ja|1|jb|imm[10:0]`
|
||||||
|
//!
|
||||||
|
//! Where:
|
||||||
|
//!
|
||||||
|
//! - `ja` is calculated as imm[19] ^ imm[18] ^ 1.
|
||||||
|
//! - `jb` is calculated as imm[19] ^ imm[17] ^ 1.
|
||||||
|
kThumb32_BCond,
|
||||||
|
|
||||||
|
// AArch32 Specific Offset Formats (A32)
|
||||||
|
// -------------------------------------
|
||||||
|
|
||||||
|
//! AArch32 ADR instruction, which uses a standard 12-bit immediate encoding that is used by other ARM instructions.
|
||||||
|
kAArch32_ADR,
|
||||||
|
|
||||||
|
//! AArch32 signed offset that is similar to `kSignedOffset`, however it uses absolute value of the offset and its
|
||||||
|
//! sign is encoded in 23rd bit of the opcode.
|
||||||
|
//!
|
||||||
|
//! `|........|U.......|........|........|`
|
||||||
|
//!
|
||||||
|
kAArch32_U23_SignedOffset,
|
||||||
|
|
||||||
|
//! AArch32 offset format that encodes 8-bit offset as:
|
||||||
|
//!
|
||||||
|
//! `|........|U.......|....|imm[7:4]|....|imm[3:0]|`
|
||||||
|
//!
|
||||||
|
//! in a 32-bit word, where U is a sign of the displacement and the displacement itself is encoded as its absolute
|
||||||
|
//! value.
|
||||||
|
kAArch32_U23_0To3At0_4To7At8,
|
||||||
|
|
||||||
|
//! AArch32 offset format that encodes a signed 25-bit offset as:
|
||||||
|
//!
|
||||||
|
//! `|.......|imm[0]|imm[24:1]|`
|
||||||
|
//!
|
||||||
|
//! in a 32-bit word.
|
||||||
|
kAArch32_1To24At0_0At24,
|
||||||
|
|
||||||
|
//! Maximum value of `OffsetFormatType`.
|
||||||
|
kMaxValue = kAArch32_1To24At0_0At24
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Provides information about formatting offsets, absolute addresses, or their parts. Offset format is used by both
|
||||||
|
//! \ref RelocEntry and \ref Fixup. The illustration below describes the relation of region size and offset size.
|
||||||
|
//! Region size is the size of the whole unit whereas offset size is the size of the unit that will be patched.
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! +-> Code buffer | The subject of the relocation (region) |
|
||||||
|
//! | | (Word-Offset) (Word-Size) |
|
||||||
|
//! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx->
|
||||||
|
//! | |
|
||||||
|
//! [Word Offset points here]----+ +--- [WordOffset + WordSize]
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! Once the offset word has been located it can be patched like this:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! |ImmDiscardLSB (discard LSB bits).
|
||||||
|
//! |..
|
||||||
|
//! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit)
|
||||||
|
//! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB.
|
||||||
|
//! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift.
|
||||||
|
//! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit)
|
||||||
|
//! |...............|
|
||||||
|
//! (ImmBitCount) +- ImmBitShift
|
||||||
|
//! ```
|
||||||
|
struct OffsetFormat {
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Type of the offset.
|
||||||
|
OffsetType _type;
|
||||||
|
//! Encoding flags.
|
||||||
|
uint8_t _flags;
|
||||||
|
//! Size of the region (in bytes) containing the offset value, if the offset value is part of an instruction,
|
||||||
|
//! otherwise it would be the same as `_valueSize`.
|
||||||
|
uint8_t _regionSize;
|
||||||
|
//! Size of the offset value, in bytes (1, 2, 4, or 8).
|
||||||
|
uint8_t _valueSize;
|
||||||
|
//! Offset of the offset value, in bytes, relative to the start of the region or data. Value offset would be
|
||||||
|
//! zero if both region size and value size are equal.
|
||||||
|
uint8_t _valueOffset;
|
||||||
|
//! Size of the offset immediate value in bits.
|
||||||
|
uint8_t _immBitCount;
|
||||||
|
//! Shift of the offset immediate value in bits in the target word.
|
||||||
|
uint8_t _immBitShift;
|
||||||
|
//! Number of least significant bits to discard before writing the immediate to the destination. All discarded
|
||||||
|
//! bits must be zero otherwise the value is invalid.
|
||||||
|
uint8_t _immDiscardLsb;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Accessors
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Returns the type of the offset.
|
||||||
|
ASMJIT_INLINE_NODEBUG OffsetType type() const noexcept { return _type; }
|
||||||
|
|
||||||
|
//! Returns whether the offset is encoded as an absolute value of the offset with additional field(s) that represent
|
||||||
|
//! the sign (AArch32 U/N fields in the opcode).
|
||||||
|
//!
|
||||||
|
//! If true, the offset itself is always positive and a separate U/N field is used to indicate the sign of the offset
|
||||||
|
//! (usually `U==1` means ADD, but sometimes `N==1` means negative offset, which implies SUB).
|
||||||
|
ASMJIT_INLINE_NODEBUG bool hasSignBit() const noexcept {
|
||||||
|
return _type == OffsetType::kThumb32_ADR ||
|
||||||
|
_type == OffsetType::kAArch32_ADR ||
|
||||||
|
_type == OffsetType::kAArch32_U23_SignedOffset ||
|
||||||
|
_type == OffsetType::kAArch32_U23_0To3At0_4To7At8;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Returns flags.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t flags() const noexcept { return _flags; }
|
||||||
|
|
||||||
|
//! Returns the size of the region/instruction where the offset is encoded.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t regionSize() const noexcept { return _regionSize; }
|
||||||
|
|
||||||
|
//! Returns the offset of the word relative to the start of the region where the offset is.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t valueOffset() const noexcept { return _valueOffset; }
|
||||||
|
|
||||||
|
//! Returns the size of the data-type (word) that contains the offset, in bytes.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t valueSize() const noexcept { return _valueSize; }
|
||||||
|
|
||||||
|
//! Returns the count of bits of the offset value in the data it's stored in.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t immBitCount() const noexcept { return _immBitCount; }
|
||||||
|
|
||||||
|
//! Returns the bit-shift of the offset value in the data it's stored in.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t immBitShift() const noexcept { return _immBitShift; }
|
||||||
|
|
||||||
|
//! Returns the number of least significant bits of the offset value, that must be zero and that are not part of
|
||||||
|
//! the encoded data.
|
||||||
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; }
|
||||||
|
|
||||||
|
//! Resets this offset format to a simple data value of `dataSize` bytes.
|
||||||
|
//!
|
||||||
|
//! The region will be the same size as data and immediate bits would correspond to `dataSize * 8`. There will be
|
||||||
|
//! no immediate bit shift or discarded bits.
|
||||||
|
inline void resetToSimpleValue(OffsetType type, size_t valueSize) noexcept {
|
||||||
|
ASMJIT_ASSERT(valueSize <= 8u);
|
||||||
|
|
||||||
|
_type = type;
|
||||||
|
_flags = uint8_t(0);
|
||||||
|
_regionSize = uint8_t(valueSize);
|
||||||
|
_valueSize = uint8_t(valueSize);
|
||||||
|
_valueOffset = uint8_t(0);
|
||||||
|
_immBitCount = uint8_t(valueSize * 8u);
|
||||||
|
_immBitShift = uint8_t(0);
|
||||||
|
_immDiscardLsb = uint8_t(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void resetToImmValue(OffsetType type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept {
|
||||||
|
ASMJIT_ASSERT(valueSize <= 8u);
|
||||||
|
ASMJIT_ASSERT(immBitShift < valueSize * 8u);
|
||||||
|
ASMJIT_ASSERT(immBitCount <= 64u);
|
||||||
|
ASMJIT_ASSERT(immDiscardLsb <= 64u);
|
||||||
|
|
||||||
|
_type = type;
|
||||||
|
_flags = uint8_t(0);
|
||||||
|
_regionSize = uint8_t(valueSize);
|
||||||
|
_valueSize = uint8_t(valueSize);
|
||||||
|
_valueOffset = uint8_t(0);
|
||||||
|
_immBitCount = uint8_t(immBitCount);
|
||||||
|
_immBitShift = uint8_t(immBitShift);
|
||||||
|
_immDiscardLsb = uint8_t(immDiscardLsb);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setRegion(size_t regionSize, size_t valueOffset) noexcept {
|
||||||
|
_regionSize = uint8_t(regionSize);
|
||||||
|
_valueOffset = uint8_t(valueOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept {
|
||||||
|
_regionSize = uint8_t(leadingSize + trailingSize + _valueSize);
|
||||||
|
_valueOffset = uint8_t(leadingSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Data structure used to mark where a fixup in code or data is necessary.
|
||||||
|
//!
|
||||||
|
//! Fixups are generally resolved during machine code generation. For example if a branch instruction is used to
|
||||||
|
//! jump to a label, which hasn't been bound yet, a fixup is created. However, when such label is bound, the fixup
|
||||||
|
//! is processed and removed from a list of fixups.
|
||||||
|
struct Fixup {
|
||||||
|
//! Next fixup in a single-linked list.
|
||||||
|
Fixup* next;
|
||||||
|
//! Section where the fixup comes from.
|
||||||
|
uint32_t sectionId;
|
||||||
|
//! Label id, relocation id, or \ref Globals::kInvalidId.
|
||||||
|
//!
|
||||||
|
//! \note Fixup that is used with a LabelEntry always uses relocation id here, however, when a fixup is turned
|
||||||
|
//! into unresolved and generally detached from LabelEntry, this field becomes a label identifier as unresolved
|
||||||
|
//! fixups won't reference a relocation. This is just a space optimization.
|
||||||
|
uint32_t labelOrRelocId;
|
||||||
|
//! Label offset relative to the start of the section where the unresolved link comes from.
|
||||||
|
size_t offset;
|
||||||
|
//! Inlined rel8/rel32.
|
||||||
|
intptr_t rel;
|
||||||
|
//! Offset format information.
|
||||||
|
OffsetFormat format;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // ASMJIT_CORE_FIXUP_H_INCLUDED
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -32,6 +32,26 @@ class VirtReg;
|
|||||||
|
|
||||||
namespace Formatter {
|
namespace Formatter {
|
||||||
|
|
||||||
|
Error formatVirtRegName(String& sb, const VirtReg* vReg) noexcept {
|
||||||
|
if (vReg->nameSize()) {
|
||||||
|
return sb.append(vReg->name(), vReg->nameSize());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(vReg->id())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Error formatVirtRegNameWithPrefix(String& sb, const char* prefix, size_t prefixSize, const VirtReg* vReg) noexcept {
|
||||||
|
ASMJIT_PROPAGATE(sb.append(prefix, prefixSize));
|
||||||
|
|
||||||
|
if (vReg->nameSize()) {
|
||||||
|
return sb.append(vReg->name(), vReg->nameSize());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(vReg->id())));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static const char wordNameTable[][8] = {
|
static const char wordNameTable[][8] = {
|
||||||
"db",
|
"db",
|
||||||
"dw",
|
"dw",
|
||||||
@@ -128,33 +148,31 @@ Error formatLabel(
|
|||||||
DebugUtils::unused(formatFlags);
|
DebugUtils::unused(formatFlags);
|
||||||
|
|
||||||
if (emitter && emitter->code()) {
|
if (emitter && emitter->code()) {
|
||||||
const LabelEntry* le = emitter->code()->labelEntry(labelId);
|
CodeHolder* code = emitter->code();
|
||||||
if (ASMJIT_UNLIKELY(!le)) {
|
if (ASMJIT_UNLIKELY(!code->isLabelValid(labelId))) {
|
||||||
return sb.appendFormat("<InvalidLabel:%u>", labelId);
|
return sb.appendFormat("<InvalidLabel:%u>", labelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (le->hasName()) {
|
const LabelEntry& le = code->labelEntry(labelId);
|
||||||
if (le->hasParent()) {
|
if (le.hasName()) {
|
||||||
uint32_t parentId = le->parentId();
|
if (le.hasParent()) {
|
||||||
const LabelEntry* pe = emitter->code()->labelEntry(parentId);
|
uint32_t parentId = le.parentId();
|
||||||
|
const LabelEntry& pe = code->labelEntry(parentId);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!pe)) {
|
if (pe.hasName()) {
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("<InvalidLabel:%u>", labelId));
|
ASMJIT_PROPAGATE(sb.append(pe.name()));
|
||||||
}
|
|
||||||
else if (ASMJIT_UNLIKELY(!pe->hasName())) {
|
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId));
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ASMJIT_PROPAGATE(sb.append(pe->name()));
|
ASMJIT_PROPAGATE(sb.appendFormat("L%u", parentId));
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(sb.append('.'));
|
ASMJIT_PROPAGATE(sb.append('.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (le->type() == LabelType::kAnonymous) {
|
if (le.labelType() == LabelType::kAnonymous) {
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("L%u@", labelId));
|
ASMJIT_PROPAGATE(sb.appendFormat("L%u@", labelId));
|
||||||
}
|
}
|
||||||
return sb.append(le->name());
|
return sb.append(le.name());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -241,9 +259,9 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
|
|||||||
|
|
||||||
switch (typeSize) {
|
switch (typeSize) {
|
||||||
case 1: v = data[0]; break;
|
case 1: v = data[0]; break;
|
||||||
case 2: v = Support::readU16u(data); break;
|
case 2: v = Support::loadu_u16(data); break;
|
||||||
case 4: v = Support::readU32u(data); break;
|
case 4: v = Support::loadu_u32(data); break;
|
||||||
case 8: v = Support::readU64u(data); break;
|
case 8: v = Support::loadu_u64(data); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, StringFormatFlags::kAlternate));
|
ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, StringFormatFlags::kAlternate));
|
||||||
@@ -381,7 +399,14 @@ static Error formatFuncValuePack(
|
|||||||
virtReg = cc->virtRegById(vRegs[valueIndex].id());
|
virtReg = cc->virtRegById(vRegs[valueIndex].id());
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat(" %s", virtReg ? virtReg->name() : nullReg));
|
ASMJIT_PROPAGATE(sb.append(' '));
|
||||||
|
|
||||||
|
if (virtReg) {
|
||||||
|
ASMJIT_PROPAGATE(Formatter::formatVirtRegName(sb, virtReg));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
ASMJIT_PROPAGATE(sb.append(nullReg, sizeof(nullReg) - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -448,8 +473,8 @@ Error formatNode(
|
|||||||
|
|
||||||
case NodeType::kSection: {
|
case NodeType::kSection: {
|
||||||
const SectionNode* sectionNode = node->as<SectionNode>();
|
const SectionNode* sectionNode = node->as<SectionNode>();
|
||||||
if (builder->_code->isSectionValid(sectionNode->id())) {
|
if (builder->_code->isSectionValid(sectionNode->sectionId())) {
|
||||||
const Section* section = builder->_code->sectionById(sectionNode->id());
|
const Section* section = builder->_code->sectionById(sectionNode->sectionId());
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name()));
|
ASMJIT_PROPAGATE(sb.appendFormat(".section %s", section->name()));
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED
|
#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED
|
||||||
|
|||||||
@@ -1,12 +1,14 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FORMATTER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_FORMATTER_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_FORMATTER_P_H_INCLUDED
|
#define ASMJIT_CORE_FORMATTER_P_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../core/compilerdefs.h"
|
||||||
#include "../core/formatter.h"
|
#include "../core/formatter.h"
|
||||||
|
#include "../core/operand.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
@@ -16,6 +18,7 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
|
|
||||||
namespace Formatter {
|
namespace Formatter {
|
||||||
|
|
||||||
|
[[maybe_unused]]
|
||||||
static ASMJIT_INLINE size_t paddingFromOptions(const FormatOptions& formatOptions, FormatPaddingGroup group) noexcept {
|
static ASMJIT_INLINE size_t paddingFromOptions(const FormatOptions& formatOptions, FormatPaddingGroup group) noexcept {
|
||||||
static constexpr uint16_t _defaultPaddingTable[uint32_t(FormatPaddingGroup::kMaxValue) + 1] = { 44, 26 };
|
static constexpr uint16_t _defaultPaddingTable[uint32_t(FormatPaddingGroup::kMaxValue) + 1] = { 44, 26 };
|
||||||
static_assert(uint32_t(FormatPaddingGroup::kMaxValue) + 1 == 2, "If a new group is defined it must be added here");
|
static_assert(uint32_t(FormatPaddingGroup::kMaxValue) + 1 == 2, "If a new group is defined it must be added here");
|
||||||
@@ -24,6 +27,9 @@ static ASMJIT_INLINE size_t paddingFromOptions(const FormatOptions& formatOption
|
|||||||
return padding ? padding : size_t(_defaultPaddingTable[uint32_t(group)]);
|
return padding ? padding : size_t(_defaultPaddingTable[uint32_t(group)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Error formatVirtRegName(String& sb, const VirtReg* vReg) noexcept;
|
||||||
|
Error formatVirtRegNameWithPrefix(String& sb, const char* prefix, size_t prefixSize, const VirtReg* vReg) noexcept;
|
||||||
|
|
||||||
} // {Formatter}
|
} // {Formatter}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -106,7 +106,7 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept {
|
|||||||
|
|
||||||
_arch = arch;
|
_arch = arch;
|
||||||
_spRegId = uint8_t(archTraits.spRegId());
|
_spRegId = uint8_t(archTraits.spRegId());
|
||||||
_saRegId = uint8_t(BaseReg::kIdBad);
|
_saRegId = uint8_t(Reg::kIdBad);
|
||||||
|
|
||||||
uint32_t naturalStackAlignment = func.callConv().naturalStackAlignment();
|
uint32_t naturalStackAlignment = func.callConv().naturalStackAlignment();
|
||||||
uint32_t minDynamicAlignment = Support::max<uint32_t>(naturalStackAlignment, 16);
|
uint32_t minDynamicAlignment = Support::max<uint32_t>(naturalStackAlignment, 16);
|
||||||
@@ -172,14 +172,14 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
|
|
||||||
// Currently required by ARM, if this works differently across architectures we would have to generalize most
|
// Currently required by ARM, if this works differently across architectures we would have to generalize most
|
||||||
// likely in CallConv.
|
// likely in CallConv.
|
||||||
if (kLr != BaseReg::kIdBad) {
|
if (kLr != Reg::kIdBad) {
|
||||||
_dirtyRegs[RegGroup::kGp] |= Support::bitMask(kLr);
|
_dirtyRegs[RegGroup::kGp] |= Support::bitMask(kLr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// These two are identical if the function doesn't align its stack dynamically.
|
// These two are identical if the function doesn't align its stack dynamically.
|
||||||
uint32_t saRegId = _saRegId;
|
uint32_t saRegId = _saRegId;
|
||||||
if (saRegId == BaseReg::kIdBad) {
|
if (saRegId == Reg::kIdBad) {
|
||||||
saRegId = kSp;
|
saRegId = kSp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FUNC_H_INCLUDED
|
#ifndef ASMJIT_CORE_FUNC_H_INCLUDED
|
||||||
@@ -49,7 +49,7 @@ enum class CallConvId : uint8_t {
|
|||||||
//! this calling convention it will be replaced by \ref CallConvId::kCDecl.
|
//! this calling convention it will be replaced by \ref CallConvId::kCDecl.
|
||||||
kFastCall = 2,
|
kFastCall = 2,
|
||||||
|
|
||||||
//! `__vectorcall` on targets that support this calling convention (X86/X64).
|
//! `__vectorcall` on targets that support this calling convention (X86|X86_64).
|
||||||
//!
|
//!
|
||||||
//! \note This calling convention is only supported on 32-bit and 64-bit X86 architecture on Windows platform.
|
//! \note This calling convention is only supported on 32-bit and 64-bit X86 architecture on Windows platform.
|
||||||
//! If used on environment that doesn't support this calling it will be replaced by \ref CallConvId::kCDecl.
|
//! If used on environment that doesn't support this calling it will be replaced by \ref CallConvId::kCDecl.
|
||||||
@@ -796,10 +796,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns a register at the given `index` to `reg` and an optional `typeId`.
|
//! Assigns a register at the given `index` to `reg` and an optional `typeId`.
|
||||||
inline void assignReg(size_t index, const BaseReg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignReg(size_t index, const Reg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
ASMJIT_ASSERT(reg.isPhysReg());
|
ASMJIT_ASSERT(reg.isPhysReg());
|
||||||
_values[index].initReg(reg.type(), reg.id(), typeId);
|
_values[index].initReg(reg.regType(), reg.id(), typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns a register at the given `index` to `regType`, `regId`, and an optional `typeId`.
|
//! Assigns a register at the given `index` to `regType`, `regId`, and an optional `typeId`.
|
||||||
@@ -849,7 +849,7 @@ enum class FuncAttributes : uint32_t {
|
|||||||
kAlignedVecSR = 0x00000040u,
|
kAlignedVecSR = 0x00000040u,
|
||||||
//! Function must begin with an instruction that marks a start of a branch or function.
|
//! Function must begin with an instruction that marks a start of a branch or function.
|
||||||
//!
|
//!
|
||||||
//! * `ENDBR32/ENDBR64` instruction is inserted at the beginning of the function (X86, X86_64).
|
//! * `ENDBR32/ENDBR64` instruction is inserted at the beginning of the function (X86|X86_64).
|
||||||
//! * `BTI` instruction is inserted at the beginning of the function (AArch64)
|
//! * `BTI` instruction is inserted at the beginning of the function (AArch64)
|
||||||
kIndirectBranchProtection = 0x00000080u,
|
kIndirectBranchProtection = 0x00000080u,
|
||||||
//! FuncFrame is finalized and can be used by prolog/epilog inserter (PEI).
|
//! FuncFrame is finalized and can be used by prolog/epilog inserter (PEI).
|
||||||
@@ -858,22 +858,22 @@ enum class FuncAttributes : uint32_t {
|
|||||||
// X86 Specific Attributes
|
// X86 Specific Attributes
|
||||||
// -----------------------
|
// -----------------------
|
||||||
|
|
||||||
//! Enables the use of AVX within the function's body, prolog, and epilog (X86).
|
//! Enables the use of AVX within the function's body, prolog, and epilog (X86|X86_64).
|
||||||
//!
|
//!
|
||||||
//! This flag instructs prolog and epilog emitter to use AVX instead of SSE for manipulating XMM registers.
|
//! This flag instructs prolog and epilog emitter to use AVX instead of SSE for manipulating XMM registers.
|
||||||
kX86_AVXEnabled = 0x00010000u,
|
kX86_AVXEnabled = 0x00010000u,
|
||||||
|
|
||||||
//! Enables the use of AVX-512 within the function's body, prolog, and epilog (X86).
|
//! Enables the use of AVX-512 within the function's body, prolog, and epilog (X86|X86_64).
|
||||||
//!
|
//!
|
||||||
//! This flag instructs Compiler register allocator to use additional 16 registers introduced by AVX-512.
|
//! This flag instructs Compiler register allocator to use additional 16 registers introduced by AVX-512.
|
||||||
//! Additionally, if the functions saves full width of ZMM registers (custom calling conventions only) then
|
//! Additionally, if the functions saves full width of ZMM registers (custom calling conventions only) then
|
||||||
//! the prolog/epilog inserter would use AVX-512 move instructions to emit the save and restore sequence.
|
//! the prolog/epilog inserter would use AVX-512 move instructions to emit the save and restore sequence.
|
||||||
kX86_AVX512Enabled = 0x00020000u,
|
kX86_AVX512Enabled = 0x00020000u,
|
||||||
|
|
||||||
//! This flag instructs the epilog writer to emit EMMS instruction before RET (X86).
|
//! This flag instructs the epilog writer to emit EMMS instruction before RET (X86|X86_64).
|
||||||
kX86_MMXCleanup = 0x00040000u,
|
kX86_MMXCleanup = 0x00040000u,
|
||||||
|
|
||||||
//! This flag instructs the epilog writer to emit VZEROUPPER instruction before RET (X86).
|
//! This flag instructs the epilog writer to emit VZEROUPPER instruction before RET (X86|X86_64).
|
||||||
kX86_AVXCleanup = 0x00080000u
|
kX86_AVXCleanup = 0x00080000u
|
||||||
};
|
};
|
||||||
ASMJIT_DEFINE_ENUM_FLAGS(FuncAttributes)
|
ASMJIT_DEFINE_ENUM_FLAGS(FuncAttributes)
|
||||||
@@ -1148,9 +1148,9 @@ public:
|
|||||||
//! Target architecture.
|
//! Target architecture.
|
||||||
Arch _arch {};
|
Arch _arch {};
|
||||||
//! SP register ID (to access call stack and local stack).
|
//! SP register ID (to access call stack and local stack).
|
||||||
uint8_t _spRegId = uint8_t(BaseReg::kIdBad);
|
uint8_t _spRegId = uint8_t(Reg::kIdBad);
|
||||||
//! SA register ID (to access stack arguments).
|
//! SA register ID (to access stack arguments).
|
||||||
uint8_t _saRegId = uint8_t(BaseReg::kIdBad);
|
uint8_t _saRegId = uint8_t(Reg::kIdBad);
|
||||||
|
|
||||||
//! Red zone size (copied from CallConv).
|
//! Red zone size (copied from CallConv).
|
||||||
uint8_t _redZoneSize = 0;
|
uint8_t _redZoneSize = 0;
|
||||||
@@ -1514,14 +1514,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! \overload
|
//! \overload
|
||||||
inline void addDirtyRegs(const BaseReg& reg) noexcept {
|
inline void addDirtyRegs(const Reg& reg) noexcept {
|
||||||
ASMJIT_ASSERT(reg.id() < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(reg.id() < Globals::kMaxPhysRegs);
|
||||||
addDirtyRegs(reg.group(), Support::bitMask(reg.id()));
|
addDirtyRegs(reg.regGroup(), Support::bitMask(reg.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \overload
|
//! \overload
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void addDirtyRegs(const BaseReg& reg, Args&&... args) noexcept {
|
inline void addDirtyRegs(const Reg& reg, Args&&... args) noexcept {
|
||||||
addDirtyRegs(reg);
|
addDirtyRegs(reg);
|
||||||
addDirtyRegs(std::forward<Args>(args)...);
|
addDirtyRegs(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@@ -1583,14 +1583,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Adds a single register to the unavailable set.
|
//! Adds a single register to the unavailable set.
|
||||||
inline void addUnavailableRegs(const BaseReg& reg) noexcept {
|
inline void addUnavailableRegs(const Reg& reg) noexcept {
|
||||||
ASMJIT_ASSERT(reg.id() < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(reg.id() < Globals::kMaxPhysRegs);
|
||||||
addUnavailableRegs(reg.group(), Support::bitMask(reg.id()));
|
addUnavailableRegs(reg.regGroup(), Support::bitMask(reg.id()));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Adds multiple registers to the unavailable set.
|
//! Adds multiple registers to the unavailable set.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void addUnavailableRegs(const BaseReg& reg, Args&&... args) noexcept {
|
inline void addUnavailableRegs(const Reg& reg, Args&&... args) noexcept {
|
||||||
addUnavailableRegs(reg);
|
addUnavailableRegs(reg);
|
||||||
addUnavailableRegs(std::forward<Args>(args)...);
|
addUnavailableRegs(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
@@ -1635,14 +1635,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasSARegId() const noexcept { return _saRegId != BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG bool hasSARegId() const noexcept { return _saRegId != Reg::kIdBad; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t saRegId() const noexcept { return _saRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t saRegId() const noexcept { return _saRegId; }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); }
|
ASMJIT_INLINE_NODEBUG void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void resetSARegId() { setSARegId(BaseReg::kIdBad); }
|
ASMJIT_INLINE_NODEBUG void resetSARegId() { setSARegId(Reg::kIdBad); }
|
||||||
|
|
||||||
//! Returns stack size required to save/restore registers via push/pop.
|
//! Returns stack size required to save/restore registers via push/pop.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
@@ -1694,7 +1694,7 @@ public:
|
|||||||
//! Function detail.
|
//! Function detail.
|
||||||
const FuncDetail* _funcDetail {};
|
const FuncDetail* _funcDetail {};
|
||||||
//! Register that can be used to access arguments passed by stack.
|
//! Register that can be used to access arguments passed by stack.
|
||||||
uint8_t _saRegId = uint8_t(BaseReg::kIdBad);
|
uint8_t _saRegId = uint8_t(Reg::kIdBad);
|
||||||
//! Reserved for future use.
|
//! Reserved for future use.
|
||||||
uint8_t _reserved[3] {};
|
uint8_t _reserved[3] {};
|
||||||
//! Mapping of each function argument.
|
//! Mapping of each function argument.
|
||||||
@@ -1715,7 +1715,7 @@ public:
|
|||||||
//! if non-null.
|
//! if non-null.
|
||||||
inline void reset(const FuncDetail* fd = nullptr) noexcept {
|
inline void reset(const FuncDetail* fd = nullptr) noexcept {
|
||||||
_funcDetail = fd;
|
_funcDetail = fd;
|
||||||
_saRegId = uint8_t(BaseReg::kIdBad);
|
_saRegId = uint8_t(Reg::kIdBad);
|
||||||
memset(_reserved, 0, sizeof(_reserved));
|
memset(_reserved, 0, sizeof(_reserved));
|
||||||
memset(_argPacks, 0, sizeof(_argPacks));
|
memset(_argPacks, 0, sizeof(_argPacks));
|
||||||
}
|
}
|
||||||
@@ -1741,14 +1741,14 @@ public:
|
|||||||
ASMJIT_INLINE_NODEBUG void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; }
|
ASMJIT_INLINE_NODEBUG void setFuncDetail(const FuncDetail* fd) noexcept { _funcDetail = fd; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasSARegId() const noexcept { return _saRegId != BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG bool hasSARegId() const noexcept { return _saRegId != Reg::kIdBad; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t saRegId() const noexcept { return _saRegId; }
|
ASMJIT_INLINE_NODEBUG uint32_t saRegId() const noexcept { return _saRegId; }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); }
|
ASMJIT_INLINE_NODEBUG void setSARegId(uint32_t regId) { _saRegId = uint8_t(regId); }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void resetSARegId() { _saRegId = uint8_t(BaseReg::kIdBad); }
|
ASMJIT_INLINE_NODEBUG void resetSARegId() { _saRegId = uint8_t(Reg::kIdBad); }
|
||||||
|
|
||||||
//! Returns assigned argument at `argIndex` and `valueIndex`.
|
//! Returns assigned argument at `argIndex` and `valueIndex`.
|
||||||
//!
|
//!
|
||||||
@@ -1775,10 +1775,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns register at `argIndex` and value index of 0 to `reg` and an optional `typeId`.
|
//! Assigns register at `argIndex` and value index of 0 to `reg` and an optional `typeId`.
|
||||||
inline void assignReg(size_t argIndex, const BaseReg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignReg(size_t argIndex, const Reg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks));
|
ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks));
|
||||||
ASMJIT_ASSERT(reg.isPhysReg());
|
ASMJIT_ASSERT(reg.isPhysReg());
|
||||||
_argPacks[argIndex][0].initReg(reg.type(), reg.id(), typeId);
|
_argPacks[argIndex][0].initReg(reg.regType(), reg.id(), typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns register at `argIndex` and value index of 0 to `regType`, `regId`, and an optional `typeId`.
|
//! Assigns register at `argIndex` and value index of 0 to `regType`, `regId`, and an optional `typeId`.
|
||||||
@@ -1794,10 +1794,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns register at `argIndex` and `valueIndex` to `reg` and an optional `typeId`.
|
//! Assigns register at `argIndex` and `valueIndex` to `reg` and an optional `typeId`.
|
||||||
inline void assignRegInPack(size_t argIndex, size_t valueIndex, const BaseReg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignRegInPack(size_t argIndex, size_t valueIndex, const Reg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks));
|
ASMJIT_ASSERT(argIndex < ASMJIT_ARRAY_SIZE(_argPacks));
|
||||||
ASMJIT_ASSERT(reg.isPhysReg());
|
ASMJIT_ASSERT(reg.isPhysReg());
|
||||||
_argPacks[argIndex][valueIndex].initReg(reg.type(), reg.id(), typeId);
|
_argPacks[argIndex][valueIndex].initReg(reg.regType(), reg.id(), typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns register at `argIndex` and `valueIndex` to `regType`, `regId`, and an optional `typeId`.
|
//! Assigns register at `argIndex` and `valueIndex` to `regType`, `regId`, and an optional `typeId`.
|
||||||
@@ -1815,12 +1815,12 @@ public:
|
|||||||
// NOTE: All `assignAll()` methods are shortcuts to assign all arguments at once, however, since registers are
|
// NOTE: All `assignAll()` methods are shortcuts to assign all arguments at once, however, since registers are
|
||||||
// passed all at once these initializers don't provide any way to pass TypeId and/or to keep any argument between
|
// passed all at once these initializers don't provide any way to pass TypeId and/or to keep any argument between
|
||||||
// the arguments passed unassigned.
|
// the arguments passed unassigned.
|
||||||
inline void _assignAllInternal(size_t argIndex, const BaseReg& reg) noexcept {
|
inline void _assignAllInternal(size_t argIndex, const Reg& reg) noexcept {
|
||||||
assignReg(argIndex, reg);
|
assignReg(argIndex, reg);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline void _assignAllInternal(size_t argIndex, const BaseReg& reg, Args&&... args) noexcept {
|
inline void _assignAllInternal(size_t argIndex, const Reg& reg, Args&&... args) noexcept {
|
||||||
assignReg(argIndex, reg);
|
assignReg(argIndex, reg);
|
||||||
_assignAllInternal(argIndex + 1, std::forward<Args>(args)...);
|
_assignAllInternal(argIndex + 1, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -58,7 +58,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
FuncValue& dst = var.out;
|
FuncValue& dst = var.out;
|
||||||
|
|
||||||
RegGroup dstGroup = RegGroup::kMaxValue;
|
RegGroup dstGroup = RegGroup::kMaxValue;
|
||||||
uint32_t dstId = BaseReg::kIdBad;
|
uint32_t dstId = Reg::kIdBad;
|
||||||
WorkData* dstWd = nullptr;
|
WorkData* dstWd = nullptr;
|
||||||
|
|
||||||
// Not supported.
|
// Not supported.
|
||||||
@@ -75,10 +75,10 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
// Copy TypeId from source if the destination doesn't have it. The RA used by BaseCompiler would never
|
// Copy TypeId from source if the destination doesn't have it. The RA used by BaseCompiler would never
|
||||||
// leave TypeId undefined, but users of FuncAPI can just assign phys regs without specifying their types.
|
// leave TypeId undefined, but users of FuncAPI can just assign phys regs without specifying their types.
|
||||||
if (!dst.hasTypeId()) {
|
if (!dst.hasTypeId()) {
|
||||||
dst.setTypeId(archTraits().regTypeToTypeId(dst.regType()));
|
dst.setTypeId(RegUtils::typeIdOf(dst.regType()));
|
||||||
}
|
}
|
||||||
|
|
||||||
dstGroup = archTraits().regTypeToGroup(dstType);
|
dstGroup = RegUtils::groupOf(dstType);
|
||||||
if (ASMJIT_UNLIKELY(dstGroup > RegGroup::kMaxVirt)) {
|
if (ASMJIT_UNLIKELY(dstGroup > RegGroup::kMaxVirt)) {
|
||||||
return DebugUtils::errored(kErrorInvalidRegGroup);
|
return DebugUtils::errored(kErrorInvalidRegGroup);
|
||||||
}
|
}
|
||||||
@@ -112,7 +112,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
|
|
||||||
if (src.isReg()) {
|
if (src.isReg()) {
|
||||||
uint32_t srcId = src.regId();
|
uint32_t srcId = src.regId();
|
||||||
RegGroup srcGroup = archTraits().regTypeToGroup(src.regType());
|
RegGroup srcGroup = RegUtils::groupOf(src.regType());
|
||||||
|
|
||||||
if (dstGroup == srcGroup) {
|
if (dstGroup == srcGroup) {
|
||||||
ASMJIT_ASSERT(dstWd != nullptr);
|
ASMJIT_ASSERT(dstWd != nullptr);
|
||||||
@@ -173,14 +173,14 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
uint32_t saCurRegId = frame.saRegId();
|
uint32_t saCurRegId = frame.saRegId();
|
||||||
uint32_t saOutRegId = args.saRegId();
|
uint32_t saOutRegId = args.saRegId();
|
||||||
|
|
||||||
if (saCurRegId != BaseReg::kIdBad) {
|
if (saCurRegId != Reg::kIdBad) {
|
||||||
// Check if the provided `SARegId` doesn't collide with input registers.
|
// Check if the provided `SARegId` doesn't collide with input registers.
|
||||||
if (ASMJIT_UNLIKELY(gpRegs.isAssigned(saCurRegId))) {
|
if (ASMJIT_UNLIKELY(gpRegs.isAssigned(saCurRegId))) {
|
||||||
return DebugUtils::errored(kErrorOverlappedRegs);
|
return DebugUtils::errored(kErrorOverlappedRegs);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (saOutRegId != BaseReg::kIdBad) {
|
if (saOutRegId != Reg::kIdBad) {
|
||||||
// Check if the provided `SARegId` doesn't collide with argument assignments.
|
// Check if the provided `SARegId` doesn't collide with argument assignments.
|
||||||
if (ASMJIT_UNLIKELY(Support::bitTest(gpRegs.dstRegs(), saOutRegId))) {
|
if (ASMJIT_UNLIKELY(Support::bitTest(gpRegs.dstRegs(), saOutRegId))) {
|
||||||
return DebugUtils::errored(kErrorOverlappedRegs);
|
return DebugUtils::errored(kErrorOverlappedRegs);
|
||||||
@@ -198,8 +198,8 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
Var& var = _vars[varId];
|
Var& var = _vars[varId];
|
||||||
var.reset();
|
var.reset();
|
||||||
|
|
||||||
if (saCurRegId == BaseReg::kIdBad) {
|
if (saCurRegId == Reg::kIdBad) {
|
||||||
if (saOutRegId != BaseReg::kIdBad && !gpRegs.isAssigned(saOutRegId)) {
|
if (saOutRegId != Reg::kIdBad && !gpRegs.isAssigned(saOutRegId)) {
|
||||||
saCurRegId = saOutRegId;
|
saCurRegId = saOutRegId;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -220,7 +220,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
gpRegs.assign(varId, saCurRegId);
|
gpRegs.assign(varId, saCurRegId);
|
||||||
gpRegs._workRegs |= Support::bitMask(saCurRegId);
|
gpRegs._workRegs |= Support::bitMask(saCurRegId);
|
||||||
|
|
||||||
if (saOutRegId != BaseReg::kIdBad) {
|
if (saOutRegId != Reg::kIdBad) {
|
||||||
var.out.initReg(ptrRegType, saOutRegId, ptrTypeId);
|
var.out.initReg(ptrRegType, saOutRegId, ptrTypeId);
|
||||||
gpRegs._dstRegs |= Support::bitMask(saOutRegId);
|
gpRegs._dstRegs |= Support::bitMask(saOutRegId);
|
||||||
gpRegs._workRegs |= Support::bitMask(saOutRegId);
|
gpRegs._workRegs |= Support::bitMask(saOutRegId);
|
||||||
@@ -241,15 +241,15 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
uint32_t srcId = var.cur.regId();
|
uint32_t srcId = var.cur.regId();
|
||||||
uint32_t dstId = var.out.regId();
|
uint32_t dstId = var.out.regId();
|
||||||
|
|
||||||
RegGroup group = archTraits().regTypeToGroup(var.cur.regType());
|
RegGroup group = RegUtils::groupOf(var.cur.regType());
|
||||||
if (group != archTraits().regTypeToGroup(var.out.regType())) {
|
if (group != RegUtils::groupOf(var.out.regType())) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkData& wd = _workData[group];
|
WorkData& wd = _workData[group];
|
||||||
if (wd.isAssigned(dstId)) {
|
if (wd.isAssigned(dstId)) {
|
||||||
Var& other = _vars[wd._physToVarId[dstId]];
|
Var& other = _vars[wd._physToVarId[dstId]];
|
||||||
if (archTraits().regTypeToGroup(other.out.regType()) == group && other.out.regId() == srcId) {
|
if (RegUtils::groupOf(other.out.regType()) == group && other.out.regId() == srcId) {
|
||||||
wd._numSwaps++;
|
wd._numSwaps++;
|
||||||
_regSwapsMask = uint8_t(_regSwapsMask | Support::bitMask(group));
|
_regSwapsMask = uint8_t(_regSwapsMask | Support::bitMask(group));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
||||||
@@ -22,30 +22,30 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
static inline OperandSignature getSuitableRegForMemToMemMove(Arch arch, TypeId dstTypeId, TypeId srcTypeId) noexcept {
|
static inline OperandSignature getSuitableRegForMemToMemMove(Arch arch, TypeId dstTypeId, TypeId srcTypeId) noexcept {
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
||||||
|
|
||||||
|
uint32_t signature = 0u;
|
||||||
uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
|
uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
|
||||||
uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
|
uint32_t srcSize = TypeUtils::sizeOf(srcTypeId);
|
||||||
uint32_t maxSize = Support::max<uint32_t>(dstSize, srcSize);
|
uint32_t maxSize = Support::max<uint32_t>(dstSize, srcSize);
|
||||||
uint32_t regSize = Environment::registerSizeFromArch(arch);
|
uint32_t regSize = Environment::registerSizeFromArch(arch);
|
||||||
|
|
||||||
OperandSignature signature{0};
|
|
||||||
if (maxSize <= regSize || (TypeUtils::isInt(dstTypeId) && TypeUtils::isInt(srcTypeId))) {
|
if (maxSize <= regSize || (TypeUtils::isInt(dstTypeId) && TypeUtils::isInt(srcTypeId))) {
|
||||||
signature = maxSize <= 4 ? archTraits.regTypeToSignature(RegType::kGp32)
|
signature = maxSize <= 4 ? RegTraits<RegType::kGp32>::kSignature
|
||||||
: archTraits.regTypeToSignature(RegType::kGp64);
|
: RegTraits<RegType::kGp64>::kSignature;
|
||||||
}
|
}
|
||||||
else if (maxSize <= 8 && archTraits.hasRegType(RegType::kVec64)) {
|
else if (maxSize <= 8 && archTraits.hasRegType(RegType::kVec64)) {
|
||||||
signature = archTraits.regTypeToSignature(RegType::kVec64);
|
signature = RegTraits<RegType::kVec64>::kSignature;
|
||||||
}
|
}
|
||||||
else if (maxSize <= 16 && archTraits.hasRegType(RegType::kVec128)) {
|
else if (maxSize <= 16 && archTraits.hasRegType(RegType::kVec128)) {
|
||||||
signature = archTraits.regTypeToSignature(RegType::kVec128);
|
signature = RegTraits<RegType::kVec128>::kSignature;
|
||||||
}
|
}
|
||||||
else if (maxSize <= 32 && archTraits.hasRegType(RegType::kVec256)) {
|
else if (maxSize <= 32 && archTraits.hasRegType(RegType::kVec256)) {
|
||||||
signature = archTraits.regTypeToSignature(RegType::kVec256);
|
signature = RegTraits<RegType::kVec256>::kSignature;
|
||||||
}
|
}
|
||||||
else if (maxSize <= 64 && archTraits.hasRegType(RegType::kVec512)) {
|
else if (maxSize <= 64 && archTraits.hasRegType(RegType::kVec512)) {
|
||||||
signature = archTraits.regTypeToSignature(RegType::kVec512);
|
signature = RegTraits<RegType::kVec512>::kSignature;
|
||||||
}
|
}
|
||||||
|
|
||||||
return signature;
|
return OperandSignature{signature};
|
||||||
}
|
}
|
||||||
|
|
||||||
class FuncArgsContext {
|
class FuncArgsContext {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED
|
#ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED
|
||||||
@@ -73,13 +73,16 @@ enum class ResetPolicy : uint32_t {
|
|||||||
namespace Globals {
|
namespace Globals {
|
||||||
|
|
||||||
//! Host memory allocator overhead.
|
//! Host memory allocator overhead.
|
||||||
static constexpr uint32_t kAllocOverhead = uint32_t(sizeof(intptr_t) * 4);
|
static constexpr uint32_t kAllocOverhead = uint32_t(sizeof(intptr_t) * 4u);
|
||||||
|
|
||||||
//! Host memory allocator alignment.
|
//! Host memory allocator alignment.
|
||||||
static constexpr uint32_t kAllocAlignment = 8;
|
static constexpr uint32_t kAllocAlignment = 8u;
|
||||||
|
|
||||||
//! Aggressive growing strategy threshold.
|
//! Aggressive growing strategy threshold.
|
||||||
static constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16;
|
static constexpr uint32_t kGrowThreshold = 1024u * 1024u * 16u;
|
||||||
|
|
||||||
|
//! Default alignment of allocation requests to use when using Zone.
|
||||||
|
static constexpr uint32_t kZoneAlignment = 8u;
|
||||||
|
|
||||||
//! Maximum depth of RB-Tree is:
|
//! Maximum depth of RB-Tree is:
|
||||||
//!
|
//!
|
||||||
@@ -212,8 +215,8 @@ enum ErrorCode : uint32_t {
|
|||||||
kErrorLabelNameTooLong,
|
kErrorLabelNameTooLong,
|
||||||
//! Label must always be local if it's anonymous (without a name).
|
//! Label must always be local if it's anonymous (without a name).
|
||||||
kErrorInvalidLabelName,
|
kErrorInvalidLabelName,
|
||||||
//! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was either invalid or parent is not supported
|
//! Parent id passed to \ref CodeHolder::newNamedLabelId() was either invalid or parent is not supported by
|
||||||
//! by the requested `LabelType`.
|
//! the requested `LabelType`.
|
||||||
kErrorInvalidParentLabel,
|
kErrorInvalidParentLabel,
|
||||||
|
|
||||||
//! Invalid section.
|
//! Invalid section.
|
||||||
@@ -278,7 +281,7 @@ enum ErrorCode : uint32_t {
|
|||||||
kErrorInvalidAddress64BitZeroExtension,
|
kErrorInvalidAddress64BitZeroExtension,
|
||||||
//! Invalid displacement (not encodable).
|
//! Invalid displacement (not encodable).
|
||||||
kErrorInvalidDisplacement,
|
kErrorInvalidDisplacement,
|
||||||
//! Invalid segment (X86).
|
//! Invalid segment (X86|X86_64).
|
||||||
kErrorInvalidSegment,
|
kErrorInvalidSegment,
|
||||||
|
|
||||||
//! Invalid immediate (out of bounds on X86 and invalid pattern on ARM).
|
//! Invalid immediate (out of bounds on X86 and invalid pattern on ARM).
|
||||||
@@ -386,14 +389,32 @@ ASMJIT_API void assertionFailed(const char* file, int line, const char* msg) noe
|
|||||||
//!
|
//!
|
||||||
//! AsmJit's own assert macro used in AsmJit code-base.
|
//! AsmJit's own assert macro used in AsmJit code-base.
|
||||||
#if defined(ASMJIT_BUILD_DEBUG)
|
#if defined(ASMJIT_BUILD_DEBUG)
|
||||||
#define ASMJIT_ASSERT(...) \
|
#define ASMJIT_ASSERT(...) \
|
||||||
do { \
|
do { \
|
||||||
if (ASMJIT_UNLIKELY(!(__VA_ARGS__))) { \
|
if (ASMJIT_UNLIKELY(!(__VA_ARGS__))) { \
|
||||||
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \
|
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \
|
||||||
} \
|
} \
|
||||||
} while (0)
|
} while (0)
|
||||||
#else
|
#else
|
||||||
#define ASMJIT_ASSERT(...) ((void)0)
|
#define ASMJIT_ASSERT(...) ((void)0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define ASMJIT_RUNTIME_ASSERT(...) \
|
||||||
|
do { \
|
||||||
|
if (ASMJIT_UNLIKELY(!(__VA_ARGS__))) { \
|
||||||
|
::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__); \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
//! \def ASMJIT_NOT_REACHED()
|
||||||
|
//!
|
||||||
|
//! Run-time assertion used in code that should never be reached.
|
||||||
|
#if defined(ASMJIT_BUILD_DEBUG)
|
||||||
|
#define ASMJIT_NOT_REACHED() ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, "ASMJIT_NOT_REACHED()")
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define ASMJIT_NOT_REACHED() __builtin_unreachable()
|
||||||
|
#else
|
||||||
|
#define ASMJIT_NOT_REACHED() ASMJIT_ASSUME(0)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//! \def ASMJIT_PROPAGATE(...)
|
//! \def ASMJIT_PROPAGATE(...)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_INST_H_INCLUDED
|
#ifndef ASMJIT_CORE_INST_H_INCLUDED
|
||||||
@@ -256,7 +256,7 @@ public:
|
|||||||
_options(options),
|
_options(options),
|
||||||
_extraReg(extraReg) {}
|
_extraReg(extraReg) {}
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG BaseInst(InstId instId, InstOptions options, const BaseReg& extraReg) noexcept
|
ASMJIT_INLINE_NODEBUG BaseInst(InstId instId, InstOptions options, const Reg& extraReg) noexcept
|
||||||
: _id(instId),
|
: _id(instId),
|
||||||
_options(options),
|
_options(options),
|
||||||
_extraReg { extraReg.signature(), extraReg.id() } {}
|
_extraReg { extraReg.signature(), extraReg.id() } {}
|
||||||
@@ -334,7 +334,7 @@ public:
|
|||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _extraReg; }
|
ASMJIT_INLINE_NODEBUG const RegOnly& extraReg() const noexcept { return _extraReg; }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const BaseReg& reg) noexcept { _extraReg.init(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); }
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
ASMJIT_INLINE_NODEBUG void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
|
||||||
|
|
||||||
@@ -414,34 +414,34 @@ enum class CpuRWFlags : uint32_t {
|
|||||||
// X86 Specific RW Flags
|
// X86 Specific RW Flags
|
||||||
// ----------------------------------
|
// ----------------------------------
|
||||||
|
|
||||||
//! Carry flag (X86, X86_64).
|
//! Carry flag (X86|X86_64).
|
||||||
kX86_CF = kCF,
|
kX86_CF = kCF,
|
||||||
//! Overflow flag (X86, X86_64).
|
//! Overflow flag (X86|X86_64).
|
||||||
kX86_OF = kOF,
|
kX86_OF = kOF,
|
||||||
//! Sign flag (X86, X86_64).
|
//! Sign flag (X86|X86_64).
|
||||||
kX86_SF = kSF,
|
kX86_SF = kSF,
|
||||||
//! Zero flag (X86, X86_64).
|
//! Zero flag (X86|X86_64).
|
||||||
kX86_ZF = kZF,
|
kX86_ZF = kZF,
|
||||||
|
|
||||||
//! Adjust flag (X86, X86_64).
|
//! Adjust flag (X86|X86_64).
|
||||||
kX86_AF = 0x00000100u,
|
kX86_AF = 0x00000100u,
|
||||||
//! Parity flag (X86, X86_64).
|
//! Parity flag (X86|X86_64).
|
||||||
kX86_PF = 0x00000200u,
|
kX86_PF = 0x00000200u,
|
||||||
//! Direction flag (X86, X86_64).
|
//! Direction flag (X86|X86_64).
|
||||||
kX86_DF = 0x00000400u,
|
kX86_DF = 0x00000400u,
|
||||||
//! Interrupt enable flag (X86, X86_64).
|
//! Interrupt enable flag (X86|X86_64).
|
||||||
kX86_IF = 0x00000800u,
|
kX86_IF = 0x00000800u,
|
||||||
|
|
||||||
//! Alignment check flag (X86, X86_64).
|
//! Alignment check flag (X86|X86_64).
|
||||||
kX86_AC = 0x00001000u,
|
kX86_AC = 0x00001000u,
|
||||||
|
|
||||||
//! FPU C0 status flag (X86, X86_64).
|
//! FPU C0 status flag (X86|X86_64).
|
||||||
kX86_C0 = 0x00010000u,
|
kX86_C0 = 0x00010000u,
|
||||||
//! FPU C1 status flag (X86, X86_64).
|
//! FPU C1 status flag (X86|X86_64).
|
||||||
kX86_C1 = 0x00020000u,
|
kX86_C1 = 0x00020000u,
|
||||||
//! FPU C2 status flag (X86, X86_64).
|
//! FPU C2 status flag (X86|X86_64).
|
||||||
kX86_C2 = 0x00040000u,
|
kX86_C2 = 0x00040000u,
|
||||||
//! FPU C3 status flag (X86, X86_64).
|
//! FPU C3 status flag (X86|X86_64).
|
||||||
kX86_C3 = 0x00080000u,
|
kX86_C3 = 0x00080000u,
|
||||||
|
|
||||||
// ARM Specific RW Flags
|
// ARM Specific RW Flags
|
||||||
@@ -477,7 +477,7 @@ enum class OpRWFlags : uint32_t {
|
|||||||
//!
|
//!
|
||||||
//! This flag is used by all architectures to describe instructions that use consecutive registers, where only the
|
//! This flag is used by all architectures to describe instructions that use consecutive registers, where only the
|
||||||
//! first one is encoded in the instruction, and the others are just a sequence that starts with the first one. On
|
//! first one is encoded in the instruction, and the others are just a sequence that starts with the first one. On
|
||||||
//! X86/X86_64 architecture this is used by instructions such as VP2INTERSECTD and VP2INTERSECTQ. On ARM/AArch64
|
//! X86|X86_64 architecture this is used by instructions such as VP2INTERSECTD and VP2INTERSECTQ. On ARM/AArch64
|
||||||
//! this is used by vector load and store instructions that can load or store multiple registers at once.
|
//! this is used by vector load and store instructions that can load or store multiple registers at once.
|
||||||
kConsecutive = 0x00000008u,
|
kConsecutive = 0x00000008u,
|
||||||
|
|
||||||
@@ -559,7 +559,7 @@ struct OpRWInfo {
|
|||||||
|
|
||||||
//! Resets this operand info (resets all members) and set common information
|
//! Resets this operand info (resets all members) and set common information
|
||||||
//! to the given `opFlags`, `regSize`, and possibly `physId`.
|
//! to the given `opFlags`, `regSize`, and possibly `physId`.
|
||||||
inline void reset(OpRWFlags opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept {
|
inline void reset(OpRWFlags opFlags, uint32_t regSize, uint32_t physId = Reg::kIdBad) noexcept {
|
||||||
_opFlags = opFlags;
|
_opFlags = opFlags;
|
||||||
_physId = uint8_t(physId);
|
_physId = uint8_t(physId);
|
||||||
_rmSize = Support::test(opFlags, OpRWFlags::kRegMem) ? uint8_t(regSize) : uint8_t(0);
|
_rmSize = Support::test(opFlags, OpRWFlags::kRegMem) ? uint8_t(regSize) : uint8_t(0);
|
||||||
@@ -708,13 +708,13 @@ struct OpRWInfo {
|
|||||||
|
|
||||||
//! Returns a physical id of the register that is fixed for this operand.
|
//! Returns a physical id of the register that is fixed for this operand.
|
||||||
//!
|
//!
|
||||||
//! Returns \ref BaseReg::kIdBad if any register can be used.
|
//! Returns \ref Reg::kIdBad if any register can be used.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG uint32_t physId() const noexcept { return _physId; }
|
ASMJIT_INLINE_NODEBUG uint32_t physId() const noexcept { return _physId; }
|
||||||
|
|
||||||
//! Tests whether \ref physId() would return a valid physical register id.
|
//! Tests whether \ref physId() would return a valid physical register id.
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
ASMJIT_INLINE_NODEBUG bool hasPhysId() const noexcept { return _physId != BaseReg::kIdBad; }
|
ASMJIT_INLINE_NODEBUG bool hasPhysId() const noexcept { return _physId != Reg::kIdBad; }
|
||||||
|
|
||||||
//! Sets physical register id, which would be fixed for this operand.
|
//! Sets physical register id, which would be fixed for this operand.
|
||||||
ASMJIT_INLINE_NODEBUG void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); }
|
ASMJIT_INLINE_NODEBUG void setPhysId(uint32_t physId) noexcept { _physId = uint8_t(physId); }
|
||||||
@@ -878,7 +878,7 @@ struct InstRWInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
//! Validation flags that can be used with \ref InstAPI::validate().
|
//! Validation flags that can be used with \ref InstAPI::validate().
|
||||||
enum class ValidationFlags : uint32_t {
|
enum class ValidationFlags : uint8_t {
|
||||||
//! No flags.
|
//! No flags.
|
||||||
kNone = 0,
|
kNone = 0,
|
||||||
//! Allow virtual registers in the instruction.
|
//! Allow virtual registers in the instruction.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_INSTDB_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_INSTDB_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -15,6 +15,10 @@
|
|||||||
#include "../core/zonelist.h"
|
#include "../core/zonelist.h"
|
||||||
#include "../core/zonetree.h"
|
#include "../core/zonetree.h"
|
||||||
|
|
||||||
|
#if defined(ASMJIT_TEST)
|
||||||
|
#include "../../../test/asmjit_test_random.h"
|
||||||
|
#endif // ASMJIT_TEST
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// JitAllocator - Constants
|
// JitAllocator - Constants
|
||||||
@@ -147,6 +151,9 @@ class JitAllocatorPool {
|
|||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(JitAllocatorPool)
|
ASMJIT_NONCOPYABLE(JitAllocatorPool)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Double linked list of blocks.
|
//! Double linked list of blocks.
|
||||||
ZoneList<JitAllocatorBlock> blocks;
|
ZoneList<JitAllocatorBlock> blocks;
|
||||||
//! Where to start looking first.
|
//! Where to start looking first.
|
||||||
@@ -168,12 +175,14 @@ public:
|
|||||||
//! Overhead of all blocks (in bytes).
|
//! Overhead of all blocks (in bytes).
|
||||||
size_t totalOverheadBytes = 0;
|
size_t totalOverheadBytes = 0;
|
||||||
|
|
||||||
inline JitAllocatorPool(uint32_t granularity) noexcept
|
//! \}
|
||||||
|
|
||||||
|
ASMJIT_INLINE JitAllocatorPool(uint32_t granularity) noexcept
|
||||||
: blocks(),
|
: blocks(),
|
||||||
granularity(uint16_t(granularity)),
|
granularity(uint16_t(granularity)),
|
||||||
granularityLog2(uint8_t(Support::ctz(granularity))) {}
|
granularityLog2(uint8_t(Support::ctz(granularity))) {}
|
||||||
|
|
||||||
inline void reset() noexcept {
|
ASMJIT_INLINE void reset() noexcept {
|
||||||
blocks.reset();
|
blocks.reset();
|
||||||
cursor = nullptr;
|
cursor = nullptr;
|
||||||
blockCount = 0u;
|
blockCount = 0u;
|
||||||
@@ -184,12 +193,11 @@ public:
|
|||||||
totalOverheadBytes = 0u;
|
totalOverheadBytes = 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline size_t byteSizeFromAreaSize(uint32_t areaSize) const noexcept { return size_t(areaSize) * granularity; }
|
ASMJIT_INLINE_NODEBUG size_t byteSizeFromAreaSize(uint32_t areaSize) const noexcept { return size_t(areaSize) * granularity; }
|
||||||
inline uint32_t areaSizeFromByteSize(size_t size) const noexcept { return uint32_t((size + granularity - 1) >> granularityLog2); }
|
ASMJIT_INLINE_NODEBUG uint32_t areaSizeFromByteSize(size_t size) const noexcept { return uint32_t((size + granularity - 1) >> granularityLog2); }
|
||||||
|
|
||||||
inline size_t bitWordCountFromAreaSize(uint32_t areaSize) const noexcept {
|
ASMJIT_INLINE_NODEBUG size_t bitWordCountFromAreaSize(uint32_t areaSize) const noexcept {
|
||||||
using namespace Support;
|
return Support::alignUp<size_t>(areaSize, Support::kBitWordSizeInBits) / Support::kBitWordSizeInBits;
|
||||||
return alignUp<size_t>(areaSize, kBitWordSizeInBits) / kBitWordSizeInBits;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -206,12 +214,14 @@ public:
|
|||||||
kFlagInitialPadding = 0x00000001u,
|
kFlagInitialPadding = 0x00000001u,
|
||||||
//! Block is empty.
|
//! Block is empty.
|
||||||
kFlagEmpty = 0x00000002u,
|
kFlagEmpty = 0x00000002u,
|
||||||
//! Block is dirty (largestUnusedArea, searchStart, searchEnd).
|
//! Block is dirty (dirty largestUnusedArea, searchStart, searchEnd, ...).
|
||||||
kFlagDirty = 0x00000004u,
|
kFlagDirty = 0x00000004u,
|
||||||
|
//! Block is in incremental mode, which means that there is no memory used after searchStart.
|
||||||
|
kFlagIncremental = 0x00000008u,
|
||||||
//! Block represents memory that is using large pages.
|
//! Block represents memory that is using large pages.
|
||||||
kFlagLargePages = 0x00000008u,
|
kFlagLargePages = 0x00000010u,
|
||||||
//! Block represents memory that is dual-mapped.
|
//! Block represents memory that is dual-mapped.
|
||||||
kFlagDualMapped = 0x00000010u
|
kFlagDualMapped = 0x00000020u
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(kFlagInitialPadding == 1, "JitAllocatorBlock::kFlagInitialPadding must be equal to 1");
|
static_assert(kFlagInitialPadding == 1, "JitAllocatorBlock::kFlagInitialPadding must be equal to 1");
|
||||||
@@ -244,7 +254,7 @@ public:
|
|||||||
//! Stop bit-vector (0 = don't care, 1 = stop).
|
//! Stop bit-vector (0 = don't care, 1 = stop).
|
||||||
Support::BitWord* _stopBitVector {};
|
Support::BitWord* _stopBitVector {};
|
||||||
|
|
||||||
inline JitAllocatorBlock(
|
ASMJIT_INLINE JitAllocatorBlock(
|
||||||
JitAllocatorPool* pool,
|
JitAllocatorPool* pool,
|
||||||
VirtMem::DualMapping mapping,
|
VirtMem::DualMapping mapping,
|
||||||
size_t blockSize,
|
size_t blockSize,
|
||||||
@@ -270,58 +280,61 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline JitAllocatorPool* pool() const noexcept { return _pool; }
|
ASMJIT_INLINE_NODEBUG JitAllocatorPool* pool() const noexcept { return _pool; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint8_t* rxPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rx); }
|
ASMJIT_INLINE_NODEBUG uint8_t* rxPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rx); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint8_t* rwPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rw); }
|
ASMJIT_INLINE_NODEBUG uint8_t* rwPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rw); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool hasFlag(uint32_t f) const noexcept { return (_flags & f) != 0; }
|
ASMJIT_INLINE_NODEBUG bool hasFlag(uint32_t f) const noexcept { return (_flags & f) != 0; }
|
||||||
|
|
||||||
inline void addFlags(uint32_t f) noexcept { _flags |= f; }
|
ASMJIT_INLINE_NODEBUG void addFlags(uint32_t f) noexcept { _flags |= f; }
|
||||||
inline void clearFlags(uint32_t f) noexcept { _flags &= ~f; }
|
ASMJIT_INLINE_NODEBUG void clearFlags(uint32_t f) noexcept { _flags &= ~f; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool empty() const noexcept { return hasFlag(kFlagEmpty); }
|
ASMJIT_INLINE_NODEBUG bool isEmpty() const noexcept { return hasFlag(kFlagEmpty); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool isDirty() const noexcept { return hasFlag(kFlagDirty); }
|
ASMJIT_INLINE_NODEBUG bool isDirty() const noexcept { return hasFlag(kFlagDirty); }
|
||||||
|
|
||||||
inline void makeDirty() noexcept { addFlags(kFlagDirty); }
|
ASMJIT_INLINE_NODEBUG void makeDirty() noexcept { addFlags(kFlagDirty); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool hasLargePages() const noexcept { return hasFlag(kFlagLargePages); }
|
ASMJIT_INLINE_NODEBUG bool isIncremental() const noexcept { return hasFlag(kFlagIncremental); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline bool hasInitialPadding() const noexcept { return hasFlag(kFlagInitialPadding); }
|
ASMJIT_INLINE_NODEBUG bool hasLargePages() const noexcept { return hasFlag(kFlagLargePages); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t initialAreaStart() const noexcept { return initialAreaStartByFlags(_flags); }
|
ASMJIT_INLINE_NODEBUG bool hasInitialPadding() const noexcept { return hasFlag(kFlagInitialPadding); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline size_t blockSize() const noexcept { return _blockSize; }
|
ASMJIT_INLINE_NODEBUG uint32_t initialAreaStart() const noexcept { return initialAreaStartByFlags(_flags); }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t areaSize() const noexcept { return _areaSize; }
|
ASMJIT_INLINE_NODEBUG size_t blockSize() const noexcept { return _blockSize; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t areaUsed() const noexcept { return _areaUsed; }
|
ASMJIT_INLINE_NODEBUG uint32_t areaSize() const noexcept { return _areaSize; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t areaAvailable() const noexcept { return _areaSize - _areaUsed; }
|
ASMJIT_INLINE_NODEBUG uint32_t areaUsed() const noexcept { return _areaUsed; }
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
inline uint32_t largestUnusedArea() const noexcept { return _largestUnusedArea; }
|
ASMJIT_INLINE_NODEBUG uint32_t areaAvailable() const noexcept { return _areaSize - _areaUsed; }
|
||||||
|
|
||||||
inline void decreaseUsedArea(uint32_t value) noexcept {
|
[[nodiscard]]
|
||||||
|
ASMJIT_INLINE_NODEBUG uint32_t largestUnusedArea() const noexcept { return _largestUnusedArea; }
|
||||||
|
|
||||||
|
ASMJIT_INLINE void decreaseUsedArea(uint32_t value) noexcept {
|
||||||
_areaUsed -= value;
|
_areaUsed -= value;
|
||||||
_pool->totalAreaUsed[size_t(hasLargePages())] -= value;
|
_pool->totalAreaUsed[size_t(hasLargePages())] -= value;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void clearBlock() noexcept {
|
ASMJIT_INLINE void clearBlock() noexcept {
|
||||||
bool bit = hasInitialPadding();
|
bool bit = hasInitialPadding();
|
||||||
size_t numBitWords = _pool->bitWordCountFromAreaSize(_areaSize);
|
size_t numBitWords = _pool->bitWordCountFromAreaSize(_areaSize);
|
||||||
|
|
||||||
@@ -337,11 +350,11 @@ public:
|
|||||||
_searchStart = start;
|
_searchStart = start;
|
||||||
_searchEnd = _areaSize;
|
_searchEnd = _areaSize;
|
||||||
|
|
||||||
addFlags(JitAllocatorBlock::kFlagEmpty);
|
addFlags(JitAllocatorBlock::kFlagEmpty | JitAllocatorBlock::kFlagIncremental);
|
||||||
clearFlags(JitAllocatorBlock::kFlagDirty);
|
clearFlags(JitAllocatorBlock::kFlagDirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void markAllocatedArea(uint32_t allocatedAreaStart, uint32_t allocatedAreaEnd) noexcept {
|
ASMJIT_INLINE void markAllocatedArea(uint32_t allocatedAreaStart, uint32_t allocatedAreaEnd) noexcept {
|
||||||
uint32_t allocatedAreaSize = allocatedAreaEnd - allocatedAreaStart;
|
uint32_t allocatedAreaSize = allocatedAreaEnd - allocatedAreaStart;
|
||||||
|
|
||||||
// Mark the newly allocated space as occupied and also the sentinel.
|
// Mark the newly allocated space as occupied and also the sentinel.
|
||||||
@@ -373,32 +386,44 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void markReleasedArea(uint32_t releasedAreaStart, uint32_t releasedAreaEnd) noexcept {
|
ASMJIT_INLINE void markReleasedArea(uint32_t releasedAreaStart, uint32_t releasedAreaEnd) noexcept {
|
||||||
uint32_t releasedAreaSize = releasedAreaEnd - releasedAreaStart;
|
uint32_t releasedAreaSize = releasedAreaEnd - releasedAreaStart;
|
||||||
|
|
||||||
// Update the search region and statistics.
|
// Update the search region and statistics.
|
||||||
_pool->totalAreaUsed[size_t(hasLargePages())] -= releasedAreaSize;
|
_pool->totalAreaUsed[size_t(hasLargePages())] -= releasedAreaSize;
|
||||||
_areaUsed -= releasedAreaSize;
|
_areaUsed -= releasedAreaSize;
|
||||||
_searchStart = Support::min(_searchStart, releasedAreaStart);
|
|
||||||
_searchEnd = Support::max(_searchEnd, releasedAreaEnd);
|
|
||||||
|
|
||||||
// Unmark occupied bits and also the sentinel.
|
// Unmark occupied bits and also the sentinel.
|
||||||
Support::bitVectorClear(_usedBitVector, releasedAreaStart, releasedAreaSize);
|
Support::bitVectorClear(_usedBitVector, releasedAreaStart, releasedAreaSize);
|
||||||
Support::bitVectorSetBit(_stopBitVector, releasedAreaEnd - 1, false);
|
Support::bitVectorSetBit(_stopBitVector, releasedAreaEnd - 1, false);
|
||||||
|
|
||||||
|
if (Support::bool_and(isIncremental(), _searchStart == releasedAreaEnd)) {
|
||||||
|
// Incremental mode: If the area released is at the end of the fully used area, we would like to
|
||||||
|
// keep the incremental mode of the block. In order to do that, we are going to use a different
|
||||||
|
// approach - decrement `_searchStart` and increment `_largestUnusedArea`, which are essential
|
||||||
|
// for incremental mode blocks.
|
||||||
|
ASMJIT_ASSERT(_searchStart >= releasedAreaSize);
|
||||||
|
_searchStart -= releasedAreaSize;
|
||||||
|
_largestUnusedArea += releasedAreaSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
_searchStart = Support::min(_searchStart, releasedAreaStart);
|
||||||
|
_searchEnd = Support::max(_searchEnd, releasedAreaEnd);
|
||||||
|
clearFlags(kFlagDirty | kFlagIncremental);
|
||||||
|
|
||||||
if (areaUsed() == initialAreaStart()) {
|
if (areaUsed() == initialAreaStart()) {
|
||||||
_searchStart = initialAreaStart();
|
_searchStart = initialAreaStart();
|
||||||
_searchEnd = _areaSize;
|
_searchEnd = _areaSize;
|
||||||
_largestUnusedArea = _areaSize - initialAreaStart();
|
_largestUnusedArea = _areaSize - initialAreaStart();
|
||||||
addFlags(kFlagEmpty);
|
addFlags(kFlagEmpty);
|
||||||
clearFlags(kFlagDirty);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
addFlags(kFlagDirty);
|
addFlags(kFlagDirty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
inline void markShrunkArea(uint32_t shrunkAreaStart, uint32_t shrunkAreaEnd) noexcept {
|
ASMJIT_INLINE void markShrunkArea(uint32_t shrunkAreaStart, uint32_t shrunkAreaEnd) noexcept {
|
||||||
uint32_t shrunkAreaSize = shrunkAreaEnd - shrunkAreaStart;
|
uint32_t shrunkAreaSize = shrunkAreaEnd - shrunkAreaStart;
|
||||||
|
|
||||||
// Shrunk area cannot start at zero as it would mean that we have shrunk the first
|
// Shrunk area cannot start at zero as it would mean that we have shrunk the first
|
||||||
@@ -409,24 +434,32 @@ public:
|
|||||||
// Update the search region and statistics.
|
// Update the search region and statistics.
|
||||||
_pool->totalAreaUsed[size_t(hasLargePages())] -= shrunkAreaSize;
|
_pool->totalAreaUsed[size_t(hasLargePages())] -= shrunkAreaSize;
|
||||||
_areaUsed -= shrunkAreaSize;
|
_areaUsed -= shrunkAreaSize;
|
||||||
|
|
||||||
|
if (Support::bool_and(isIncremental(), _searchStart == shrunkAreaEnd)) {
|
||||||
|
_searchStart -= shrunkAreaSize;
|
||||||
|
_largestUnusedArea += shrunkAreaSize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
_searchStart = Support::min(_searchStart, shrunkAreaStart);
|
_searchStart = Support::min(_searchStart, shrunkAreaStart);
|
||||||
_searchEnd = Support::max(_searchEnd, shrunkAreaEnd);
|
_searchEnd = Support::max(_searchEnd, shrunkAreaEnd);
|
||||||
|
|
||||||
|
clearFlags(kFlagIncremental);
|
||||||
|
addFlags(kFlagDirty);
|
||||||
|
}
|
||||||
|
|
||||||
// Unmark the released space and move the sentinel.
|
// Unmark the released space and move the sentinel.
|
||||||
Support::bitVectorClear(_usedBitVector, shrunkAreaStart, shrunkAreaSize);
|
Support::bitVectorClear(_usedBitVector, shrunkAreaStart, shrunkAreaSize);
|
||||||
Support::bitVectorSetBit(_stopBitVector, shrunkAreaEnd - 1, false);
|
Support::bitVectorSetBit(_stopBitVector, shrunkAreaEnd - 1, false);
|
||||||
Support::bitVectorSetBit(_stopBitVector, shrunkAreaStart - 1, true);
|
Support::bitVectorSetBit(_stopBitVector, shrunkAreaStart - 1, true);
|
||||||
|
|
||||||
addFlags(kFlagDirty);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// RBTree default CMP uses '<' and '>' operators.
|
// RBTree default CMP uses '<' and '>' operators.
|
||||||
inline bool operator<(const JitAllocatorBlock& other) const noexcept { return rxPtr() < other.rxPtr(); }
|
ASMJIT_INLINE_NODEBUG bool operator<(const JitAllocatorBlock& other) const noexcept { return rxPtr() < other.rxPtr(); }
|
||||||
inline bool operator>(const JitAllocatorBlock& other) const noexcept { return rxPtr() > other.rxPtr(); }
|
ASMJIT_INLINE_NODEBUG bool operator>(const JitAllocatorBlock& other) const noexcept { return rxPtr() > other.rxPtr(); }
|
||||||
|
|
||||||
// Special implementation for querying blocks by `key`, which must be in `[BlockPtr, BlockPtr + BlockSize)` range.
|
// Special implementation for querying blocks by `key`, which must be in `[BlockPtr, BlockPtr + BlockSize)` range.
|
||||||
inline bool operator<(const uint8_t* key) const noexcept { return rxPtr() + _blockSize <= key; }
|
ASMJIT_INLINE_NODEBUG bool operator<(const uint8_t* key) const noexcept { return rxPtr() + _blockSize <= key; }
|
||||||
inline bool operator>(const uint8_t* key) const noexcept { return rxPtr() > key; }
|
ASMJIT_INLINE_NODEBUG bool operator>(const uint8_t* key) const noexcept { return rxPtr() > key; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// JitAllocator - PrivateImpl
|
// JitAllocator - PrivateImpl
|
||||||
@@ -434,6 +467,9 @@ public:
|
|||||||
|
|
||||||
class JitAllocatorPrivateImpl : public JitAllocator::Impl {
|
class JitAllocatorPrivateImpl : public JitAllocator::Impl {
|
||||||
public:
|
public:
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Lock for thread safety.
|
//! Lock for thread safety.
|
||||||
mutable Lock lock;
|
mutable Lock lock;
|
||||||
//! System page size (also a minimum block size).
|
//! System page size (also a minimum block size).
|
||||||
@@ -448,13 +484,15 @@ public:
|
|||||||
//! Number of allocator pools.
|
//! Number of allocator pools.
|
||||||
size_t poolCount;
|
size_t poolCount;
|
||||||
|
|
||||||
inline JitAllocatorPrivateImpl(JitAllocatorPool* pools, size_t poolCount) noexcept
|
//! \}
|
||||||
|
|
||||||
|
ASMJIT_INLINE JitAllocatorPrivateImpl(JitAllocatorPool* pools, size_t poolCount) noexcept
|
||||||
: JitAllocator::Impl {},
|
: JitAllocator::Impl {},
|
||||||
pageSize(0),
|
pageSize(0),
|
||||||
allocationCount(0),
|
allocationCount(0),
|
||||||
pools(pools),
|
pools(pools),
|
||||||
poolCount(poolCount) {}
|
poolCount(poolCount) {}
|
||||||
inline ~JitAllocatorPrivateImpl() noexcept {}
|
ASMJIT_INLINE ~JitAllocatorPrivateImpl() noexcept {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JitAllocator::Impl JitAllocatorImpl_none {};
|
static const JitAllocator::Impl JitAllocatorImpl_none {};
|
||||||
@@ -466,8 +504,9 @@ static const JitAllocator::CreateParams JitAllocatorParams_none {};
|
|||||||
static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::CreateParams* params) noexcept {
|
static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::CreateParams* params) noexcept {
|
||||||
VirtMem::Info vmInfo = VirtMem::info();
|
VirtMem::Info vmInfo = VirtMem::info();
|
||||||
|
|
||||||
if (!params)
|
if (!params) {
|
||||||
params = &JitAllocatorParams_none;
|
params = &JitAllocatorParams_none;
|
||||||
|
}
|
||||||
|
|
||||||
JitAllocatorOptions options = params->options;
|
JitAllocatorOptions options = params->options;
|
||||||
uint32_t blockSize = params->blockSize;
|
uint32_t blockSize = params->blockSize;
|
||||||
@@ -528,12 +567,12 @@ static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::
|
|||||||
return impl;
|
return impl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void JitAllocatorImpl_destroy(JitAllocatorPrivateImpl* impl) noexcept {
|
static ASMJIT_INLINE void JitAllocatorImpl_destroy(JitAllocatorPrivateImpl* impl) noexcept {
|
||||||
impl->~JitAllocatorPrivateImpl();
|
impl->~JitAllocatorPrivateImpl();
|
||||||
::free(impl);
|
::free(impl);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t JitAllocatorImpl_sizeToPoolId(const JitAllocatorPrivateImpl* impl, size_t size) noexcept {
|
static ASMJIT_INLINE size_t JitAllocatorImpl_sizeToPoolId(const JitAllocatorPrivateImpl* impl, size_t size) noexcept {
|
||||||
size_t poolId = impl->poolCount - 1;
|
size_t poolId = impl->poolCount - 1;
|
||||||
size_t granularity = size_t(impl->granularity) << poolId;
|
size_t granularity = size_t(impl->granularity) << poolId;
|
||||||
|
|
||||||
@@ -548,12 +587,12 @@ static inline size_t JitAllocatorImpl_sizeToPoolId(const JitAllocatorPrivateImpl
|
|||||||
return poolId;
|
return poolId;
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t JitAllocatorImpl_bitVectorSizeToByteSize(uint32_t areaSize) noexcept {
|
static ASMJIT_INLINE size_t JitAllocatorImpl_bitVectorSizeToByteSize(uint32_t areaSize) noexcept {
|
||||||
using Support::kBitWordSizeInBits;
|
using Support::kBitWordSizeInBits;
|
||||||
return ((areaSize + kBitWordSizeInBits - 1u) / kBitWordSizeInBits) * sizeof(Support::BitWord);
|
return ((areaSize + kBitWordSizeInBits - 1u) / kBitWordSizeInBits) * sizeof(Support::BitWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline size_t JitAllocatorImpl_calculateIdealBlockSize(JitAllocatorPrivateImpl* impl, JitAllocatorPool* pool, size_t allocationSize) noexcept {
|
static ASMJIT_INLINE size_t JitAllocatorImpl_calculateIdealBlockSize(JitAllocatorPrivateImpl* impl, JitAllocatorPool* pool, size_t allocationSize) noexcept {
|
||||||
JitAllocatorBlock* last = pool->blocks.last();
|
JitAllocatorBlock* last = pool->blocks.last();
|
||||||
size_t blockSize = last ? last->blockSize() : size_t(impl->blockSize);
|
size_t blockSize = last ? last->blockSize() : size_t(impl->blockSize);
|
||||||
|
|
||||||
@@ -617,8 +656,9 @@ static Error JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* impl, JitAllocat
|
|||||||
using Support::kBitWordSizeInBits;
|
using Support::kBitWordSizeInBits;
|
||||||
|
|
||||||
uint32_t blockFlags = 0;
|
uint32_t blockFlags = 0;
|
||||||
if (!Support::test(impl->options, JitAllocatorOptions::kDisableInitialPadding))
|
if (!Support::test(impl->options, JitAllocatorOptions::kDisableInitialPadding)) {
|
||||||
blockFlags |= JitAllocatorBlock::kFlagInitialPadding;
|
blockFlags |= JitAllocatorBlock::kFlagInitialPadding;
|
||||||
|
}
|
||||||
|
|
||||||
VirtMem::DualMapping virtMem {};
|
VirtMem::DualMapping virtMem {};
|
||||||
VirtMem::MemoryFlags memFlags = VirtMem::MemoryFlags::kAccessRWX;
|
VirtMem::MemoryFlags memFlags = VirtMem::MemoryFlags::kAccessRWX;
|
||||||
@@ -852,23 +892,19 @@ JitAllocator::Statistics JitAllocator::statistics() const noexcept {
|
|||||||
// ==============================
|
// ==============================
|
||||||
|
|
||||||
Error JitAllocator::alloc(Span& out, size_t size) noexcept {
|
Error JitAllocator::alloc(Span& out, size_t size) noexcept {
|
||||||
out = Span{};
|
constexpr uint32_t kNoIndex = std::numeric_limits<uint32_t>::max();
|
||||||
|
constexpr size_t kMaxRequestSize = std::numeric_limits<uint32_t>::max() / 2u;
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) {
|
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
||||||
constexpr uint32_t kNoIndex = std::numeric_limits<uint32_t>::max();
|
bool notInitialized = _impl == &JitAllocatorImpl_none;
|
||||||
|
|
||||||
// Align to the minimum granularity by default.
|
// Align to the minimum granularity by default.
|
||||||
size = Support::alignUp<size_t>(size, impl->granularity);
|
size = Support::alignUp<size_t>(size, impl->granularity);
|
||||||
if (ASMJIT_UNLIKELY(size == 0)) {
|
out = Span{};
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(size > std::numeric_limits<uint32_t>::max() / 2)) {
|
if (ASMJIT_UNLIKELY(Support::bool_or(notInitialized, size - 1u >= kMaxRequestSize))) {
|
||||||
return DebugUtils::errored(kErrorTooLarge);
|
return DebugUtils::errored(notInitialized ? kErrorNotInitialized :
|
||||||
|
size == 0u ? kErrorInvalidArgument : kErrorTooLarge);
|
||||||
}
|
}
|
||||||
|
|
||||||
LockGuard guard(impl->lock);
|
LockGuard guard(impl->lock);
|
||||||
@@ -878,13 +914,27 @@ Error JitAllocator::alloc(Span& out, size_t size) noexcept {
|
|||||||
uint32_t areaSize = uint32_t(pool->areaSizeFromByteSize(size));
|
uint32_t areaSize = uint32_t(pool->areaSizeFromByteSize(size));
|
||||||
|
|
||||||
// Try to find the requested memory area in existing blocks.
|
// Try to find the requested memory area in existing blocks.
|
||||||
JitAllocatorBlock* block = pool->blocks.first();
|
JitAllocatorBlock* block = pool->cursor;
|
||||||
|
|
||||||
if (block) {
|
if (block) {
|
||||||
JitAllocatorBlock* initial = block;
|
JitAllocatorBlock* initial = block;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
JitAllocatorBlock* next = block->hasNext() ? block->next() : pool->blocks.first();
|
uint32_t largestUnusedArea = block->largestUnusedArea();
|
||||||
if (block->areaAvailable() >= areaSize) {
|
|
||||||
if (block->isDirty() || block->largestUnusedArea() >= areaSize) {
|
if (Support::bool_and(block->isIncremental(), largestUnusedArea >= areaSize)) {
|
||||||
|
// Fast path: If the block is in incremental mode, which means that it's guaranteed it's full before
|
||||||
|
// `searchStart` and completely empty after it, we can just quickly increment `searchStart` and be
|
||||||
|
// done with the allocation. This is a little bit faster than constructing a BitVectorRangeIterator
|
||||||
|
// and searching for zero bit clusters. When a block is in incremental mode its `largestUnusedArea`
|
||||||
|
// is basically the free space after `searchStart`, so that's the only thing to check.
|
||||||
|
areaIndex = block->_searchStart;
|
||||||
|
block->_largestUnusedArea -= areaSize;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if (block->areaAvailable() >= areaSize) {
|
||||||
|
// Regular path: Search for a cluster of bits that would mark an empty area we want to allocate.
|
||||||
|
if (Support::bool_or(block->isDirty(), largestUnusedArea >= areaSize)) {
|
||||||
BitVectorRangeIterator<Support::BitWord, 0> it(block->_usedBitVector, pool->bitWordCountFromAreaSize(block->areaSize()), block->_searchStart, block->_searchEnd);
|
BitVectorRangeIterator<Support::BitWord, 0> it(block->_usedBitVector, pool->bitWordCountFromAreaSize(block->areaSize()), block->_searchStart, block->_searchEnd);
|
||||||
|
|
||||||
size_t rangeStart = 0;
|
size_t rangeStart = 0;
|
||||||
@@ -921,7 +971,9 @@ Error JitAllocator::alloc(Span& out, size_t size) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
block = next;
|
// The block cursor doesn't have to start with the first block and we want to
|
||||||
|
// iterate all before concluding that there is no free space in any block.
|
||||||
|
block = block->hasNext() ? block->next() : pool->blocks.first();
|
||||||
} while (block != initial);
|
} while (block != initial);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -961,12 +1013,10 @@ Error JitAllocator::alloc(Span& out, size_t size) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error JitAllocator::release(void* rx) noexcept {
|
Error JitAllocator::release(void* rx) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) {
|
bool notInitialized = _impl == &JitAllocatorImpl_none;
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!rx)) {
|
if (ASMJIT_UNLIKELY(Support::bool_or(notInitialized, !rx))) {
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(notInitialized ? kErrorNotInitialized : kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
||||||
@@ -999,7 +1049,7 @@ Error JitAllocator::release(void* rx) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Release the whole block if it became empty.
|
// Release the whole block if it became empty.
|
||||||
if (block->empty()) {
|
if (block->isEmpty()) {
|
||||||
if (pool->emptyBlockCount || Support::test(impl->options, JitAllocatorOptions::kImmediateRelease)) {
|
if (pool->emptyBlockCount || Support::test(impl->options, JitAllocatorOptions::kImmediateRelease)) {
|
||||||
JitAllocatorImpl_removeBlock(impl, block);
|
JitAllocatorImpl_removeBlock(impl, block);
|
||||||
JitAllocatorImpl_deleteBlock(impl, block);
|
JitAllocatorImpl_deleteBlock(impl, block);
|
||||||
@@ -1066,12 +1116,10 @@ static Error JitAllocatorImpl_shrink(JitAllocatorPrivateImpl* impl, JitAllocator
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error JitAllocator::shrink(Span& span, size_t newSize) noexcept {
|
Error JitAllocator::shrink(Span& span, size_t newSize) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none)) {
|
bool notInitialized = _impl == &JitAllocatorImpl_none;
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!span.rx())) {
|
if (ASMJIT_UNLIKELY(Support::bool_or(notInitialized, !span.rx()))) {
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(notInitialized ? kErrorNotInitialized : kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(newSize == 0)) {
|
if (ASMJIT_UNLIKELY(newSize == 0)) {
|
||||||
@@ -1226,56 +1274,6 @@ Error JitAllocator::scopedWrite(WriteScopeData& scope, Span& span, WriteFunc wri
|
|||||||
// ====================
|
// ====================
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
// A pseudo random number generator based on a paper by Sebastiano Vigna:
|
|
||||||
// http://vigna.di.unimi.it/ftp/papers/xorshiftplus.pdf
|
|
||||||
class Random {
|
|
||||||
public:
|
|
||||||
// Constants suggested as `23/18/5`.
|
|
||||||
enum Steps : uint32_t {
|
|
||||||
kStep1_SHL = 23,
|
|
||||||
kStep2_SHR = 18,
|
|
||||||
kStep3_SHR = 5
|
|
||||||
};
|
|
||||||
|
|
||||||
inline explicit Random(uint64_t seed = 0) noexcept { reset(seed); }
|
|
||||||
inline Random(const Random& other) noexcept = default;
|
|
||||||
|
|
||||||
inline void reset(uint64_t seed = 0) noexcept {
|
|
||||||
// The number is arbitrary, it means nothing.
|
|
||||||
constexpr uint64_t kZeroSeed = 0x1F0A2BE71D163FA0u;
|
|
||||||
|
|
||||||
// Generate the state data by using splitmix64.
|
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
|
||||||
seed += 0x9E3779B97F4A7C15u;
|
|
||||||
uint64_t x = seed;
|
|
||||||
x = (x ^ (x >> 30)) * 0xBF58476D1CE4E5B9u;
|
|
||||||
x = (x ^ (x >> 27)) * 0x94D049BB133111EBu;
|
|
||||||
x = (x ^ (x >> 31));
|
|
||||||
_state[i] = x != 0 ? x : kZeroSeed;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t nextUInt32() noexcept {
|
|
||||||
return uint32_t(nextUInt64() >> 32);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint64_t nextUInt64() noexcept {
|
|
||||||
uint64_t x = _state[0];
|
|
||||||
uint64_t y = _state[1];
|
|
||||||
|
|
||||||
x ^= x << kStep1_SHL;
|
|
||||||
y ^= y >> kStep3_SHR;
|
|
||||||
x ^= x >> kStep2_SHR;
|
|
||||||
x ^= y;
|
|
||||||
|
|
||||||
_state[0] = y;
|
|
||||||
_state[1] = x;
|
|
||||||
return x + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint64_t _state[2];
|
|
||||||
};
|
|
||||||
|
|
||||||
namespace JitAllocatorUtils {
|
namespace JitAllocatorUtils {
|
||||||
static void fillPattern64(void* p_, uint64_t pattern, size_t sizeInBytes) noexcept {
|
static void fillPattern64(void* p_, uint64_t pattern, size_t sizeInBytes) noexcept {
|
||||||
uint64_t* p = static_cast<uint64_t*>(p_);
|
uint64_t* p = static_cast<uint64_t*>(p_);
|
||||||
@@ -1343,20 +1341,19 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
Zone _zone;
|
Zone _zone;
|
||||||
ZoneAllocator _heap;
|
ZonePool<Record> _recordPool;
|
||||||
ZoneTree<Record> _records;
|
ZoneTree<Record> _records;
|
||||||
JitAllocator _allocator;
|
JitAllocator _allocator;
|
||||||
Random _rng;
|
TestUtils::Random _rng;
|
||||||
|
|
||||||
explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept
|
explicit JitAllocatorWrapper(const JitAllocator::CreateParams* params) noexcept
|
||||||
: _zone(1024u * 1024u),
|
: _zone(1024u * 1024u),
|
||||||
_heap(&_zone),
|
|
||||||
_allocator(params),
|
_allocator(params),
|
||||||
_rng(0x123456789u) {}
|
_rng(0x123456789u) {}
|
||||||
|
|
||||||
void _insert(void* pRX, void* pRW, size_t size) noexcept {
|
void _insert(void* pRX, void* pRW, size_t size) noexcept {
|
||||||
uint8_t* p = static_cast<uint8_t*>(pRX);
|
uint8_t* p = static_cast<uint8_t*>(pRX);
|
||||||
uint8_t* pEnd = p + size - 1;
|
uint8_t* pEnd = p + size - 1u;
|
||||||
|
|
||||||
Record* record;
|
Record* record;
|
||||||
|
|
||||||
@@ -1369,7 +1366,7 @@ public:
|
|||||||
.message("Address [%p:%p] collides with a newly allocated [%p:%p]\n", record->addr, record->addr + record->size, p, p + size);
|
.message("Address [%p:%p] collides with a newly allocated [%p:%p]\n", record->addr, record->addr + record->size, p, p + size);
|
||||||
|
|
||||||
uint64_t pattern = _rng.nextUInt64();
|
uint64_t pattern = _rng.nextUInt64();
|
||||||
record = _heap.newT<Record>(pRX, pRW, size, pattern);
|
record = new(Support::PlacementNew{_recordPool.alloc(_zone)}) Record(pRX, pRW, size, pattern);
|
||||||
EXPECT_NOT_NULL(record);
|
EXPECT_NOT_NULL(record);
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -1391,7 +1388,7 @@ public:
|
|||||||
EXPECT_TRUE(JitAllocatorUtils::verifyPattern64(record->rw(), record->pattern, record->size));
|
EXPECT_TRUE(JitAllocatorUtils::verifyPattern64(record->rw(), record->pattern, record->size));
|
||||||
|
|
||||||
_records.remove(record);
|
_records.remove(record);
|
||||||
_heap.release(record, sizeof(Record));
|
_recordPool.release(record);
|
||||||
}
|
}
|
||||||
|
|
||||||
void* alloc(size_t size) noexcept {
|
void* alloc(size_t size) noexcept {
|
||||||
@@ -1428,7 +1425,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static void JitAllocatorTest_shuffle(void** ptrArray, size_t count, Random& prng) noexcept {
|
static void JitAllocatorTest_shuffle(void** ptrArray, size_t count, TestUtils::Random& prng) noexcept {
|
||||||
for (size_t i = 0; i < count; ++i)
|
for (size_t i = 0; i < count; ++i)
|
||||||
std::swap(ptrArray[i], ptrArray[size_t(prng.nextUInt32() % count)]);
|
std::swap(ptrArray[i], ptrArray[size_t(prng.nextUInt32() % count)]);
|
||||||
}
|
}
|
||||||
@@ -1442,7 +1439,7 @@ static void JitAllocatorTest_usage(JitAllocator& allocator) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, size_t kPatternSize, bool Bit>
|
template<typename T, size_t kPatternSize, bool Bit>
|
||||||
static void BitVectorRangeIterator_testRandom(Random& rnd, size_t count) noexcept {
|
static void BitVectorRangeIterator_testRandom(TestUtils::Random& rnd, size_t count) noexcept {
|
||||||
for (size_t i = 0; i < count; i++) {
|
for (size_t i = 0; i < count; i++) {
|
||||||
T in[kPatternSize];
|
T in[kPatternSize];
|
||||||
T out[kPatternSize];
|
T out[kPatternSize];
|
||||||
@@ -1508,13 +1505,13 @@ static void test_jit_allocator_alloc_release() noexcept {
|
|||||||
|
|
||||||
INFO("BitVectorRangeIterator<uint32_t>");
|
INFO("BitVectorRangeIterator<uint32_t>");
|
||||||
{
|
{
|
||||||
Random rnd;
|
TestUtils::Random rnd;
|
||||||
BitVectorRangeIterator_testRandom<uint32_t, 64, 0>(rnd, kCount);
|
BitVectorRangeIterator_testRandom<uint32_t, 64, 0>(rnd, kCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
INFO("BitVectorRangeIterator<uint64_t>");
|
INFO("BitVectorRangeIterator<uint64_t>");
|
||||||
{
|
{
|
||||||
Random rnd;
|
TestUtils::Random rnd;
|
||||||
BitVectorRangeIterator_testRandom<uint64_t, 64, 0>(rnd, kCount);
|
BitVectorRangeIterator_testRandom<uint64_t, 64, 0>(rnd, kCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1535,7 +1532,7 @@ static void test_jit_allocator_alloc_release() noexcept {
|
|||||||
size_t fixedBlockSize = 256;
|
size_t fixedBlockSize = 256;
|
||||||
|
|
||||||
JitAllocatorWrapper wrapper(¶ms);
|
JitAllocatorWrapper wrapper(¶ms);
|
||||||
Random prng(100);
|
TestUtils::Random prng(100);
|
||||||
|
|
||||||
size_t i;
|
size_t i;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
#ifndef ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -24,7 +24,7 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
|||||||
*dst = nullptr;
|
*dst = nullptr;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(code->flatten());
|
ASMJIT_PROPAGATE(code->flatten());
|
||||||
ASMJIT_PROPAGATE(code->resolveUnresolvedLinks());
|
ASMJIT_PROPAGATE(code->resolveCrossSectionFixups());
|
||||||
|
|
||||||
size_t estimatedCodeSize = code->codeSize();
|
size_t estimatedCodeSize = code->codeSize();
|
||||||
if (ASMJIT_UNLIKELY(estimatedCodeSize == 0)) {
|
if (ASMJIT_UNLIKELY(estimatedCodeSize == 0)) {
|
||||||
@@ -35,7 +35,8 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
|||||||
ASMJIT_PROPAGATE(_allocator.alloc(span, estimatedCodeSize));
|
ASMJIT_PROPAGATE(_allocator.alloc(span, estimatedCodeSize));
|
||||||
|
|
||||||
// Relocate the code.
|
// Relocate the code.
|
||||||
Error err = code->relocateToBase(uintptr_t(span.rx()));
|
CodeHolder::RelocationSummary relocationSummary;
|
||||||
|
Error err = code->relocateToBase(uintptr_t(span.rx()), &relocationSummary);
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
_allocator.release(span.rx());
|
_allocator.release(span.rx());
|
||||||
return err;
|
return err;
|
||||||
@@ -43,8 +44,10 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
|||||||
|
|
||||||
// Recalculate the final code size and shrink the memory we allocated for it
|
// Recalculate the final code size and shrink the memory we allocated for it
|
||||||
// in case that some relocations didn't require records in an address table.
|
// in case that some relocations didn't require records in an address table.
|
||||||
size_t codeSize = code->codeSize();
|
size_t codeSize = estimatedCodeSize - relocationSummary.codeSizeReduction;
|
||||||
ASMJIT_ASSERT(codeSize <= estimatedCodeSize);
|
|
||||||
|
// If not true it means that `relocateToBase()` filled wrong information in `relocationSummary`.
|
||||||
|
ASMJIT_ASSERT(codeSize == code->codeSize());
|
||||||
|
|
||||||
_allocator.write(span, [&](JitAllocator::Span& span) noexcept -> Error {
|
_allocator.write(span, [&](JitAllocator::Span& span) noexcept -> Error {
|
||||||
uint8_t* rw = static_cast<uint8_t*>(span.rw());
|
uint8_t* rw = static_cast<uint8_t*>(span.rw());
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
#ifndef ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
||||||
@@ -36,6 +36,11 @@ public:
|
|||||||
|
|
||||||
//! Creates a `JitRuntime` instance.
|
//! Creates a `JitRuntime` instance.
|
||||||
ASMJIT_API explicit JitRuntime(const JitAllocator::CreateParams* params = nullptr) noexcept;
|
ASMJIT_API explicit JitRuntime(const JitAllocator::CreateParams* params = nullptr) noexcept;
|
||||||
|
|
||||||
|
//! Creates a `JitRuntime` instance.
|
||||||
|
ASMJIT_INLINE explicit JitRuntime(const JitAllocator::CreateParams& params) noexcept
|
||||||
|
: JitRuntime(¶ms) {}
|
||||||
|
|
||||||
//! Destroys the `JitRuntime` instance.
|
//! Destroys the `JitRuntime` instance.
|
||||||
ASMJIT_API ~JitRuntime() noexcept override;
|
ASMJIT_API ~JitRuntime() noexcept override;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_LOGGING_H_INCLUDED
|
#ifndef ASMJIT_CORE_LOGGING_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_MISC_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_MISC_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
// This file is part of AsmJit project <https://asmjit.com>
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// See asmjit.h or LICENSE.md for license and copyright information
|
// See <asmjit/core.h> or LICENSE.md for license and copyright information
|
||||||
// SPDX-License-Identifier: Zlib
|
// SPDX-License-Identifier: Zlib
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
@@ -20,7 +20,7 @@ enum class StrongEnumForImmTests : uint32_t {
|
|||||||
UNIT(operand) {
|
UNIT(operand) {
|
||||||
INFO("Checking operand sizes");
|
INFO("Checking operand sizes");
|
||||||
EXPECT_EQ(sizeof(Operand), 16u);
|
EXPECT_EQ(sizeof(Operand), 16u);
|
||||||
EXPECT_EQ(sizeof(BaseReg), 16u);
|
EXPECT_EQ(sizeof(Reg), 16u);
|
||||||
EXPECT_EQ(sizeof(BaseMem), 16u);
|
EXPECT_EQ(sizeof(BaseMem), 16u);
|
||||||
EXPECT_EQ(sizeof(Imm), 16u);
|
EXPECT_EQ(sizeof(Imm), 16u);
|
||||||
EXPECT_EQ(sizeof(Label), 16u);
|
EXPECT_EQ(sizeof(Label), 16u);
|
||||||
@@ -43,19 +43,19 @@ UNIT(operand) {
|
|||||||
EXPECT_FALSE(label.isValid());
|
EXPECT_FALSE(label.isValid());
|
||||||
EXPECT_EQ(label.id(), Globals::kInvalidId);
|
EXPECT_EQ(label.id(), Globals::kInvalidId);
|
||||||
|
|
||||||
INFO("Checking basic functionality of BaseReg");
|
INFO("Checking basic functionality of Reg");
|
||||||
EXPECT_TRUE(BaseReg().isReg());
|
EXPECT_TRUE(Reg().isReg());
|
||||||
EXPECT_FALSE(BaseReg().isValid());
|
EXPECT_FALSE(Reg().isValid());
|
||||||
EXPECT_EQ(BaseReg()._data[0], 0u);
|
EXPECT_EQ(Reg()._data[0], 0u);
|
||||||
EXPECT_EQ(BaseReg()._data[1], 0u);
|
EXPECT_EQ(Reg()._data[1], 0u);
|
||||||
EXPECT_FALSE(dummy.as<BaseReg>().isValid());
|
EXPECT_FALSE(dummy.as<Reg>().isValid());
|
||||||
|
|
||||||
// Create some register (not specific to any architecture).
|
// Create some register (not specific to any architecture).
|
||||||
OperandSignature rSig = OperandSignature::fromOpType(OperandType::kReg) |
|
OperandSignature rSig = OperandSignature::fromOpType(OperandType::kReg) |
|
||||||
OperandSignature::fromRegType(RegType::kVec128) |
|
OperandSignature::fromRegType(RegType::kVec128) |
|
||||||
OperandSignature::fromRegGroup(RegGroup::kVec) |
|
OperandSignature::fromRegGroup(RegGroup::kVec) |
|
||||||
OperandSignature::fromSize(8);
|
OperandSignature::fromSize(8);
|
||||||
BaseReg r1(rSig, 5);
|
Reg r1(rSig, 5);
|
||||||
|
|
||||||
EXPECT_TRUE(r1.isValid());
|
EXPECT_TRUE(r1.isValid());
|
||||||
EXPECT_TRUE(r1.isReg());
|
EXPECT_TRUE(r1.isReg());
|
||||||
@@ -63,8 +63,8 @@ UNIT(operand) {
|
|||||||
EXPECT_TRUE(r1.isPhysReg());
|
EXPECT_TRUE(r1.isPhysReg());
|
||||||
EXPECT_FALSE(r1.isVirtReg());
|
EXPECT_FALSE(r1.isVirtReg());
|
||||||
EXPECT_EQ(r1.signature(), rSig);
|
EXPECT_EQ(r1.signature(), rSig);
|
||||||
EXPECT_EQ(r1.type(), RegType::kVec128);
|
EXPECT_EQ(r1.regType(), RegType::kVec128);
|
||||||
EXPECT_EQ(r1.group(), RegGroup::kVec);
|
EXPECT_EQ(r1.regGroup(), RegGroup::kVec);
|
||||||
EXPECT_EQ(r1.size(), 8u);
|
EXPECT_EQ(r1.size(), 8u);
|
||||||
EXPECT_EQ(r1.id(), 5u);
|
EXPECT_EQ(r1.id(), 5u);
|
||||||
EXPECT_TRUE(r1.isReg(RegType::kVec128, 5)); // RegType and Id.
|
EXPECT_TRUE(r1.isReg(RegType::kVec128, 5)); // RegType and Id.
|
||||||
@@ -72,15 +72,15 @@ UNIT(operand) {
|
|||||||
EXPECT_EQ(r1._data[1], 0u);
|
EXPECT_EQ(r1._data[1], 0u);
|
||||||
|
|
||||||
// The same type of register having different id.
|
// The same type of register having different id.
|
||||||
BaseReg r2(r1, 6);
|
Reg r2(r1, 6);
|
||||||
EXPECT_TRUE(r2.isValid());
|
EXPECT_TRUE(r2.isValid());
|
||||||
EXPECT_TRUE(r2.isReg());
|
EXPECT_TRUE(r2.isReg());
|
||||||
EXPECT_TRUE(r2.isReg(RegType::kVec128));
|
EXPECT_TRUE(r2.isReg(RegType::kVec128));
|
||||||
EXPECT_TRUE(r2.isPhysReg());
|
EXPECT_TRUE(r2.isPhysReg());
|
||||||
EXPECT_FALSE(r2.isVirtReg());
|
EXPECT_FALSE(r2.isVirtReg());
|
||||||
EXPECT_EQ(r2.signature(), rSig);
|
EXPECT_EQ(r2.signature(), rSig);
|
||||||
EXPECT_EQ(r2.type(), r1.type());
|
EXPECT_EQ(r2.regType(), r1.regType());
|
||||||
EXPECT_EQ(r2.group(), r1.group());
|
EXPECT_EQ(r2.regGroup(), r1.regGroup());
|
||||||
EXPECT_EQ(r2.size(), r1.size());
|
EXPECT_EQ(r2.size(), r1.size());
|
||||||
EXPECT_EQ(r2.id(), 6u);
|
EXPECT_EQ(r2.id(), 6u);
|
||||||
EXPECT_TRUE(r2.isReg(RegType::kVec128, 6));
|
EXPECT_TRUE(r2.isReg(RegType::kVec128, 6));
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user