mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 04:24:37 +03:00
[ABI] Refactored AsmJit to use strong-typed enums, this breaks both API and ABI
[ABI] Added ABI version as an inline namespace, which forms asmjit::_abi_MAJOR_MINOR
[ABI] Added support for AVX512_FP16, 16-bit broadcast, and AVX512_FP16 tests
[ABI] Added initial support for consecutive registers into instruction database and register allocator
[ABI] Added a possibility to use temporary memory in CodeHolder's zone
[ABI] Compiler::setArg() is now deprecated, use FuncNode::setArg()
[Bug] Fixed correct RW information of instructions that only support implicit zeroing with {k}
[Bug] Fixed broadcast to be able to broadcast bcst16 operands
This commit is contained in:
4
.github/workflows/build-config.json
vendored
4
.github/workflows/build-config.json
vendored
@@ -19,6 +19,10 @@
|
|||||||
"cmd": ["asmjit_test_assembler", "--quiet"],
|
"cmd": ["asmjit_test_assembler", "--quiet"],
|
||||||
"optional": true
|
"optional": true
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"cmd": ["asmjit_test_assembler", "--quiet", "--validate"],
|
||||||
|
"optional": true
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"cmd": ["asmjit_test_emitters"],
|
"cmd": ["asmjit_test_emitters"],
|
||||||
"optional": true
|
"optional": true
|
||||||
|
|||||||
110
.github/workflows/build.yml
vendored
110
.github/workflows/build.yml
vendored
@@ -31,58 +31,59 @@ jobs:
|
|||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
- { title: "linux-lib" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", problem_matcher: "cpp" }
|
- { title: "linux-lib" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", problem_matcher: "cpp" }
|
||||||
- { title: "windows-lib" , os: "windows-latest", cc: "vs2019" , arch: "x86", build_type: "Debug" , problem_matcher: "cpp" }
|
- { title: "windows-lib" , os: "windows-2022" , cc: "vs2022" , arch: "x86", build_type: "Debug" , problem_matcher: "cpp" }
|
||||||
|
|
||||||
- { title: "diag-asan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "address" }
|
- { title: "diag-asan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "address" }
|
||||||
- { title: "diag-ubsan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "undefined" }
|
- { title: "diag-ubsan" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "undefined" }
|
||||||
- { title: "diag-valgrind" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "valgrind" }
|
- { title: "diag-valgrind" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON", diagnostics: "valgrind" }
|
||||||
|
- { title: "diag-scan-build", os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON", diagnostics: "scan-build" }
|
||||||
|
|
||||||
- { title: "no-deprecated" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_DEPRECATED=1" }
|
- { title: "no-deprecated" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_DEPRECATED=1" }
|
||||||
- { title: "no-intrinsics" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_INTRINSICS=1" }
|
- { title: "no-intrinsics" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_INTRINSICS=1" }
|
||||||
- { title: "no-logging" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_LOGGING=1" }
|
- { title: "no-logging" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_LOGGING=1" }
|
||||||
- { title: "no-builder" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_BUILDER=1" }
|
- { title: "no-builder" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_BUILDER=1" }
|
||||||
- { title: "no-compiler" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_COMPILER=1" }
|
- { title: "no-compiler" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON,ASMJIT_NO_COMPILER=1" }
|
||||||
|
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "gcc" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-4.8" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-5" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-5" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-5" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-5" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-6" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-6" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-6" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-18.04" , cc: "gcc-6" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-7" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-7" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-7" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-7" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-8" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-8" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-8" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-8" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-9" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-9" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "gcc-10" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-9" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "linux" , os: "ubuntu-20.04" , cc: "clang-10", arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
|
||||||
- { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "macos-10.15" , os: "macos-10.15" , cc: "gcc-9" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "macos-10.15" , os: "macos-10.15" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "macos-10.15" , os: "macos-10.15" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "macos-10.15" , os: "macos-10.15" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "macos-10.15" , os: "macos-10.15" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
|
||||||
# Disabled, because of GitHub actions infrastructure issues (builds not starting).
|
# Disabled, because of GitHub actions infrastructure issues (builds not starting).
|
||||||
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "gcc-10" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "gcc-10" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
@@ -90,10 +91,15 @@ jobs:
|
|||||||
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "clang" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
#- { title: "macos-11.0" , os: "macos-11.0" , cc: "clang" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
|
||||||
- { title: "windows" , os: "windows-latest", cc: "vs2019" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "windows" , os: "windows-latest", cc: "vs2019" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "windows" , os: "windows-latest", cc: "vs2019" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
- { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
- { title: "windows" , os: "windows-latest", cc: "vs2019" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
- { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
|
||||||
|
- { title: "windows" , os: "windows-2022" , cc: "vs2022" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
|
- { title: "windows" , os: "windows-2022" , cc: "vs2022" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
- { title: "windows" , os: "windows-2022" , cc: "vs2022" , arch: "x64", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
|
||||||
|
- { title: "windows" , os: "windows-2022" , cc: "vs2022" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
|
||||||
|
|
||||||
name: "${{matrix.title}} (${{matrix.cc}}, ${{matrix.arch}}, ${{matrix.build_type}})"
|
name: "${{matrix.title}} (${{matrix.cc}}, ${{matrix.arch}}, ${{matrix.build_type}})"
|
||||||
runs-on: "${{matrix.os}}"
|
runs-on: "${{matrix.os}}"
|
||||||
|
|||||||
@@ -19,9 +19,8 @@ endif()
|
|||||||
include(CheckCXXCompilerFlag)
|
include(CheckCXXCompilerFlag)
|
||||||
include(GNUInstallDirs)
|
include(GNUInstallDirs)
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Deprecated
|
||||||
# [AsmJit - Deprecated]
|
# ===================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
if (DEFINED ASMJIT_BUILD_EMBED)
|
if (DEFINED ASMJIT_BUILD_EMBED)
|
||||||
message(DEPRECATION "ASMJIT_BUILD_EMBED is deprecated, use ASMJIT_EMBED")
|
message(DEPRECATION "ASMJIT_BUILD_EMBED is deprecated, use ASMJIT_EMBED")
|
||||||
@@ -33,9 +32,8 @@ if (DEFINED ASMJIT_BUILD_STATIC)
|
|||||||
set(ASMJIT_STATIC "${ASMJIT_BUILD_STATIC}")
|
set(ASMJIT_STATIC "${ASMJIT_BUILD_STATIC}")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Configuration
|
||||||
# [AsmJit - Configuration]
|
# ======================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
if (NOT DEFINED ASMJIT_TEST)
|
if (NOT DEFINED ASMJIT_TEST)
|
||||||
set(ASMJIT_TEST FALSE)
|
set(ASMJIT_TEST FALSE)
|
||||||
@@ -84,9 +82,8 @@ set(ASMJIT_NO_FOREIGN "${ASMJIT_NO_FOREIGN}" CACHE BOOL "Disable all f
|
|||||||
set(ASMJIT_NO_NATVIS "${ASMJIT_NO_NATVIS}" CACHE BOOL "Disable natvis support (embedding asmjit.natvis in PDB)")
|
set(ASMJIT_NO_NATVIS "${ASMJIT_NO_NATVIS}" CACHE BOOL "Disable natvis support (embedding asmjit.natvis in PDB)")
|
||||||
set(ASMJIT_NO_CUSTOM_FLAGS "${ASMJIT_NO_CUSTOM_FLAGS}" CACHE BOOL "Disable extra compilation flags added by AsmJit to its targets")
|
set(ASMJIT_NO_CUSTOM_FLAGS "${ASMJIT_NO_CUSTOM_FLAGS}" CACHE BOOL "Disable extra compilation flags added by AsmJit to its targets")
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Project
|
||||||
# [AsmJit - Project]
|
# ================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
||||||
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
||||||
@@ -98,9 +95,8 @@ set(ASMJIT_PRIVATE_CFLAGS_REL "") # Private compiler flags used b
|
|||||||
set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers.
|
set(ASMJIT_SANITIZE_CFLAGS "") # Compiler flags required by currently enabled sanitizers.
|
||||||
set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
|
set(ASMJIT_SANITIZE_LFLAGS "") # Linker flags required by currently enabled sanitizers.
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Utilities
|
||||||
# [AsmJit - Utilities]
|
# ==================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
function(asmjit_detect_cflags out)
|
function(asmjit_detect_cflags out)
|
||||||
set(out_array ${${out}})
|
set(out_array ${${out}})
|
||||||
@@ -172,9 +168,8 @@ function(asmjit_add_target target target_type)
|
|||||||
endif()
|
endif()
|
||||||
endfunction()
|
endfunction()
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Compiler Support
|
||||||
# [AsmJit - Compiler Support]
|
# =========================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
|
||||||
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
|
||||||
@@ -283,9 +278,8 @@ foreach(build_option ASMJIT_STATIC
|
|||||||
endif()
|
endif()
|
||||||
endforeach()
|
endforeach()
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Linker Support
|
||||||
# [AsmJit - Linker Support]
|
# =======================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
if (WIN32)
|
if (WIN32)
|
||||||
if(CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
|
if(CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
|
||||||
@@ -293,9 +287,8 @@ if (WIN32)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Source
|
||||||
# [AsmJit - Source]
|
# ===============
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
set(ASMJIT_SRC_LIST
|
set(ASMJIT_SRC_LIST
|
||||||
asmjit/asmjit.h
|
asmjit/asmjit.h
|
||||||
@@ -324,7 +317,6 @@ set(ASMJIT_SRC_LIST
|
|||||||
asmjit/core/constpool.h
|
asmjit/core/constpool.h
|
||||||
asmjit/core/cpuinfo.cpp
|
asmjit/core/cpuinfo.cpp
|
||||||
asmjit/core/cpuinfo.h
|
asmjit/core/cpuinfo.h
|
||||||
asmjit/core/datatypes.h
|
|
||||||
asmjit/core/emithelper.cpp
|
asmjit/core/emithelper.cpp
|
||||||
asmjit/core/emithelper_p.h
|
asmjit/core/emithelper_p.h
|
||||||
asmjit/core/emitter.cpp
|
asmjit/core/emitter.cpp
|
||||||
@@ -335,7 +327,6 @@ 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/features.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
|
||||||
@@ -401,8 +392,6 @@ set(ASMJIT_SRC_LIST
|
|||||||
asmjit/x86/x86emithelper.cpp
|
asmjit/x86/x86emithelper.cpp
|
||||||
asmjit/x86/x86emithelper_p.h
|
asmjit/x86/x86emithelper_p.h
|
||||||
asmjit/x86/x86emitter.h
|
asmjit/x86/x86emitter.h
|
||||||
asmjit/x86/x86features.cpp
|
|
||||||
asmjit/x86/x86features.h
|
|
||||||
asmjit/x86/x86formatter.cpp
|
asmjit/x86/x86formatter.cpp
|
||||||
asmjit/x86/x86formatter_p.h
|
asmjit/x86/x86formatter_p.h
|
||||||
asmjit/x86/x86func.cpp
|
asmjit/x86/x86func.cpp
|
||||||
@@ -439,9 +428,8 @@ if (NOT ${CMAKE_VERSION} VERSION_LESS "3.8.0")
|
|||||||
source_group(TREE "${ASMJIT_DIR}" FILES ${ASMJIT_SRC})
|
source_group(TREE "${ASMJIT_DIR}" FILES ${ASMJIT_SRC})
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Summary
|
||||||
# [AsmJit - Summary]
|
# ================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
message("** AsmJit Summary **")
|
message("** AsmJit Summary **")
|
||||||
message(" ASMJIT_DIR=${ASMJIT_DIR}")
|
message(" ASMJIT_DIR=${ASMJIT_DIR}")
|
||||||
@@ -454,9 +442,8 @@ message(" ASMJIT_PRIVATE_CFLAGS=${ASMJIT_PRIVATE_CFLAGS}")
|
|||||||
message(" ASMJIT_PRIVATE_CFLAGS_DBG=${ASMJIT_PRIVATE_CFLAGS_DBG}")
|
message(" ASMJIT_PRIVATE_CFLAGS_DBG=${ASMJIT_PRIVATE_CFLAGS_DBG}")
|
||||||
message(" ASMJIT_PRIVATE_CFLAGS_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
|
message(" ASMJIT_PRIVATE_CFLAGS_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
|
||||||
|
|
||||||
# =============================================================================
|
# AsmJit - Targets
|
||||||
# [AsmJit - Targets]
|
# ================
|
||||||
# =============================================================================
|
|
||||||
|
|
||||||
if (NOT ASMJIT_EMBED)
|
if (NOT ASMJIT_EMBED)
|
||||||
# Add AsmJit target.
|
# Add AsmJit target.
|
||||||
|
|||||||
@@ -47,12 +47,10 @@ TODO
|
|||||||
|
|
||||||
* [ ] Core:
|
* [ ] Core:
|
||||||
* [ ] Add support for user external buffers in CodeBuffer / CodeHolder.
|
* [ ] Add support for user external buffers in CodeBuffer / CodeHolder.
|
||||||
* [ ] Register allocator doesn't understand register pairs, affected instructions:
|
|
||||||
* [ ] v4fmaddps, v4fmaddss, v4fnmaddps, v4fnmaddss
|
|
||||||
* [ ] vp4dpwssd, vp4dpwssds
|
|
||||||
* [ ] vp2intersectd, vp2intersectq
|
|
||||||
* [ ] Ports:
|
* [ ] Ports:
|
||||||
* [ ] ARM/Thumb/AArch64 support.
|
* [ ] 32-bit ARM/Thumb port.
|
||||||
|
* [ ] 64-bit ARM (AArch64) port.
|
||||||
|
* [ ] RISC-V port.
|
||||||
|
|
||||||
Support
|
Support
|
||||||
-------
|
-------
|
||||||
|
|||||||
@@ -34,50 +34,94 @@
|
|||||||
</Expand>
|
</Expand>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
|
<Type Name="asmjit::OperandSignature">
|
||||||
|
<Intrinsic Name="opType" Expression="(asmjit::OperandType)(_bits & 0x7)" />
|
||||||
|
<Intrinsic Name="opSize" Expression="(_bits >> 24) & 0xFF" />
|
||||||
|
<Intrinsic Name="regType" Expression="(asmjit::RegType)((_bits >> 3) & 0x1F)" />
|
||||||
|
<Intrinsic Name="regGroup" Expression="(asmjit::RegGroup)((_bits >> 8) & 0xF)" />
|
||||||
|
<Intrinsic Name="memBaseType" Expression="(asmjit::RegType)((_bits >> 3) & 0x1F)" />
|
||||||
|
<Intrinsic Name="memIndexType" Expression="(asmjit::RegType)((_bits >> 8) & 0x1F)" />
|
||||||
|
<Intrinsic Name="memRegHome" Expression="(bool)((_bits >> 13) & 0x1)" />
|
||||||
|
<Intrinsic Name="memX86Segment" Expression="(asmjit::x86::SReg::Id)((_bits >> 18) & 0x7)" />
|
||||||
|
<Intrinsic Name="memX86AddrType" Expression="(asmjit::x86::Mem::AddrType)((_bits >> 14) & 0x3)" />
|
||||||
|
<Intrinsic Name="memX86ShiftValue" Expression="((_bits >> 16) & 0x3)" />
|
||||||
|
<Intrinsic Name="memX86Broadcast" Expression="(asmjit::x86::Mem::Broadcast)((_bits >> 21) & 0x7)" />
|
||||||
|
<Intrinsic Name="immType" Expression="(asmjit::ImmType)((_bits >> 3) & 0x1)" />
|
||||||
|
|
||||||
|
<DisplayString Condition="opType() == asmjit::OperandType::kNone">[None]</DisplayString>
|
||||||
|
<DisplayString Condition="opType() == asmjit::OperandType::kReg">[Reg] {{ type={regType()} group={regGroup()} size={opSize(), d} }}</DisplayString>
|
||||||
|
<DisplayString Condition="opType() == asmjit::OperandType::kMem">[Mem] {{ base={memBaseType()} index={memIndexType()} }}</DisplayString>
|
||||||
|
<DisplayString Condition="opType() == asmjit::OperandType::kImm">[Imm] {{ type={immType()} }}</DisplayString>
|
||||||
|
<DisplayString Condition="opType() == asmjit::OperandType::kLabel">[Label]</DisplayString>
|
||||||
|
<DisplayString Condition="opType() > asmjit::OperandType::kMaxValue">[Unknown]</DisplayString>
|
||||||
|
|
||||||
|
<Expand HideRawView="true">
|
||||||
|
<Item Name="bits">_bits, X</Item>
|
||||||
|
<Item Name="op.type">opType()</Item>
|
||||||
|
<Item Name="reg.type" Condition="opType() == asmjit::OperandType::kReg">regType()</Item>
|
||||||
|
<Item Name="reg.group" Condition="opType() == asmjit::OperandType::kReg">regGroup()</Item>
|
||||||
|
<Item Name="reg.size" Condition="opType() == asmjit::OperandType::kReg">opSize(), d</Item>
|
||||||
|
<Item Name="mem.baseType" Condition="opType() == asmjit::OperandType::kMem">memBaseType()</Item>
|
||||||
|
<Item Name="mem.indexType" Condition="opType() == asmjit::OperandType::kMem">memIndexType()</Item>
|
||||||
|
<Item Name="mem.regHome" Condition="opType() == asmjit::OperandType::kMem">memRegHome()</Item>
|
||||||
|
<Item Name="mem.size" Condition="opType() == asmjit::OperandType::kMem">opSize(), d</Item>
|
||||||
|
<Item Name="mem.x86.segment" Condition="opType() == asmjit::OperandType::kMem">memX86Segment()</Item>
|
||||||
|
<Item Name="mem.x86.addrType" Condition="opType() == asmjit::OperandType::kMem">memX86AddrType()</Item>
|
||||||
|
<Item Name="mem.x86.shift" Condition="opType() == asmjit::OperandType::kMem">memX86ShiftValue()</Item>
|
||||||
|
<Item Name="mem.x86.broadcast" Condition="opType() == asmjit::OperandType::kMem">memX86Broadcast()</Item>
|
||||||
|
<Item Name="imm.type" Condition="opType() == asmjit::OperandType::kImm">immType()</Item>
|
||||||
|
</Expand>
|
||||||
|
</Type>
|
||||||
|
|
||||||
<Type Name="asmjit::Operand_">
|
<Type Name="asmjit::Operand_">
|
||||||
<Intrinsic Name="opType" Expression="(unsigned int)(_signature & 0x7)" />
|
<Intrinsic Name="opType" Expression="(asmjit::OperandType)(_signature._bits & 0x7)" />
|
||||||
<Intrinsic Name="opSize" Expression="(_signature >> 24) & 0xFF" />
|
<Intrinsic Name="opSize" Expression="(_signature._bits >> 24) & 0xFF" />
|
||||||
|
<Intrinsic Name="regType" Expression="(asmjit::RegType)((_signature._bits >> 3) & 0x1F)" />
|
||||||
<Intrinsic Name="regType" Expression="(_signature >> 3) & 0x1F" />
|
<Intrinsic Name="regGroup" Expression="(asmjit::RegGroup)((_signature._bits >> 8) & 0xF)" />
|
||||||
<Intrinsic Name="regGroup" Expression="(_signature >> 8) & 0xF" />
|
<Intrinsic Name="memBaseType" Expression="(asmjit::RegType)((_signature._bits >> 3) & 0x1F)" />
|
||||||
|
<Intrinsic Name="memIndexType" Expression="(asmjit::RegType)((_signature._bits >> 8) & 0x1F)" />
|
||||||
<Intrinsic Name="memBaseType" Expression="(_signature >> 3) & 0x1F" />
|
<Intrinsic Name="memRegHome" Expression="(bool)((_signature._bits >> 13) & 0x1)" />
|
||||||
<Intrinsic Name="memIndexType" Expression="(_signature >> 8) & 0x1F" />
|
<Intrinsic Name="memX86Segment" Expression="(asmjit::x86::SReg::Id)((_signature._bits >> 18) & 0x7)" />
|
||||||
<Intrinsic Name="memAddrType" Expression="(_signature >> 13) & 0x3" />
|
<Intrinsic Name="memX86AddrType" Expression="(asmjit::x86::Mem::AddrType)((_signature._bits >> 14) & 0x3)" />
|
||||||
<Intrinsic Name="memRegHome" Expression="(_signature >> 15) & 0x1" />
|
<Intrinsic Name="memX86ShiftValue" Expression="((_signature._bits >> 16) & 0x3)" />
|
||||||
|
<Intrinsic Name="memX86Broadcast" Expression="(asmjit::x86::Mem::Broadcast)((_signature._bits >> 21) & 0x7)" />
|
||||||
<Intrinsic Name="memBaseId" Expression="_baseId" />
|
<Intrinsic Name="memBaseId" Expression="_baseId" />
|
||||||
<Intrinsic Name="memIndexId" Expression="_data[0]" />
|
<Intrinsic Name="memIndexId" Expression="_data[0]" />
|
||||||
|
|
||||||
<Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])" />
|
<Intrinsic Name="memOffset32b" Expression="(__int64)int(_data[1])" />
|
||||||
<Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])" />
|
<Intrinsic Name="memOffset64b" Expression="(__int64) ((unsigned __int64)_baseId << 32) | ((unsigned __int64)_data[1])" />
|
||||||
<Intrinsic Name="memOffset" Expression="memBaseType() != 0 ? memOffset32b() : memOffset64b()" />
|
<Intrinsic Name="memOffset" Expression="memBaseType() != asmjit::RegType::kNone ? memOffset32b() : memOffset64b()" />
|
||||||
|
<Intrinsic Name="immType" Expression="(asmjit::ImmType)((_signature._bits >> 3) & 0x1)" />
|
||||||
<Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]" />
|
<Intrinsic Name="immValue" Expression="((__int64)_data[1] << 32) | (__int64)_data[0]" />
|
||||||
|
|
||||||
<DisplayString Condition="opType() == 0">[None]</DisplayString>
|
<DisplayString Condition="opType() == asmjit::OperandType::kNone">[None]</DisplayString>
|
||||||
<DisplayString Condition="opType() == 1">[Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}</DisplayString>
|
<DisplayString Condition="opType() == asmjit::OperandType::kReg">[Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}</DisplayString>
|
||||||
<DisplayString Condition="opType() == 2">[Mem] {{ baseId={memBaseId(), d} indexId={memIndexId(), d} offset={(__int64)memOffset(), d} }}</DisplayString>
|
<DisplayString Condition="opType() == asmjit::OperandType::kMem">[Mem] {{ baseId={memBaseId(), d} indexId={memIndexId(), d} offset={(__int64)memOffset(), d} }}</DisplayString>
|
||||||
<DisplayString Condition="opType() == 3">[Imm] {{ val={immValue(), d} hex={immValue(), X} }}</DisplayString>
|
<DisplayString Condition="opType() == asmjit::OperandType::kImm">[Imm] {{ val={immValue(), d} hex={immValue(), X} }}</DisplayString>
|
||||||
<DisplayString Condition="opType() == 4">[Label] {{ id={_baseId} }}</DisplayString>
|
<DisplayString Condition="opType() == asmjit::OperandType::kLabel">[Label] {{ id={_baseId} }}</DisplayString>
|
||||||
<DisplayString Condition="opType() > 4">[Unknown]</DisplayString>
|
<DisplayString Condition="opType() > 4">[Unknown]</DisplayString>
|
||||||
<Expand HideRawView="true">
|
<Expand HideRawView="true">
|
||||||
<Item Name="_signature">_signature, X</Item>
|
<Item Name="_signature">_signature._bits, X</Item>
|
||||||
<Item Name="_signature.any.type">(asmjit::Operand_::OpType)opType()</Item>
|
<Item Name="op.type">opType()</Item>
|
||||||
<Item Name="_signature.any.size">opSize(), d</Item>
|
<Item Name="op.size">opSize(), d</Item>
|
||||||
<Item Name="_signature.reg.type" Condition="opType() == 1">(asmjit::BaseReg::RegType)regType()</Item>
|
<Item Name="reg.type" Condition="opType() == asmjit::OperandType::kReg">regType()</Item>
|
||||||
<Item Name="_signature.reg.group" Condition="opType() == 1">(asmjit::BaseReg::RegGroup)regGroup()</Item>
|
<Item Name="reg.group" Condition="opType() == asmjit::OperandType::kReg">regGroup()</Item>
|
||||||
<Item Name="_signature.mem.baseType" Condition="opType() == 2">(asmjit::BaseReg::RegType)memBaseType()</Item>
|
<Item Name="reg.id" Condition="opType() == asmjit::OperandType::kReg">_baseId, d</Item>
|
||||||
<Item Name="_signature.mem.indexType" Condition="opType() == 2">(asmjit::BaseReg::RegType)memIndexType()</Item>
|
<Item Name="mem.baseType" Condition="opType() == asmjit::OperandType::kMem">memBaseType()</Item>
|
||||||
<Item Name="_signature.mem.addrType" Condition="opType() == 2">(asmjit::BaseMem::AddrType)memAddrType()</Item>
|
<Item Name="mem.baseId" Condition="opType() == asmjit::OperandType::kMem && memBaseType() != asmjit::RegType::kNone">memBaseId()</Item>
|
||||||
<Item Name="_signature.mem.regHome" Condition="opType() == 2">(bool)memRegHome()</Item>
|
<Item Name="mem.indexType" Condition="opType() == asmjit::OperandType::kMem">memIndexType()</Item>
|
||||||
<Item Name="_baseId">_baseId</Item>
|
<Item Name="mem.indexId" Condition="opType() == asmjit::OperandType::kMem && memIndexType() != asmjit::RegType::kNone">memIndexId()</Item>
|
||||||
<Item Name="_data[0]" Condition="opType() != 2 && opType() != 3">_data[0]</Item>
|
<Item Name="mem.regHome" Condition="opType() == asmjit::OperandType::kMem">memRegHome()</Item>
|
||||||
<Item Name="_data[1]" Condition="opType() != 2 && opType() != 3">_data[1]</Item>
|
<Item Name="mem.offset" Condition="opType() == asmjit::OperandType::kMem">memOffset(), d</Item>
|
||||||
<Item Name="_data[IndexId]" Condition="opType() == 2">_data[0]</Item>
|
<Item Name="mem.x86.segment" Condition="opType() == asmjit::OperandType::kMem">memX86Segment()</Item>
|
||||||
<Item Name="_data[OffsetLo]" Condition="opType() == 2">_data[1]</Item>
|
<Item Name="mem.x86.addrType" Condition="opType() == asmjit::OperandType::kMem">memX86AddrType()</Item>
|
||||||
<Item Name="_data[ImmHi]" Condition="opType() == 3">_data[0]</Item>
|
<Item Name="mem.x86.shift" Condition="opType() == asmjit::OperandType::kMem">memX86ShiftValue()</Item>
|
||||||
<Item Name="_data[ImmLo]" Condition="opType() == 3">_data[1]</Item>
|
<Item Name="mem.x86.broadcast" Condition="opType() == asmjit::OperandType::kMem">memX86Broadcast()</Item>
|
||||||
|
<Item Name="imm.type" Condition="opType() == asmjit::OperandType::kImm">immType()</Item>
|
||||||
|
<Item Name="imm.value" Condition="opType() == asmjit::OperandType::kImm">immValue(), X</Item>
|
||||||
|
<Item Name="label.id" Condition="opType() == asmjit::OperandType::kLabel">_baseId, d</Item>
|
||||||
|
<Item Name="raw.baseId">_baseId</Item>
|
||||||
|
<Item Name="raw.data[0]">_data[0]</Item>
|
||||||
|
<Item Name="raw.data[1]">_data[1]</Item>
|
||||||
</Expand>
|
</Expand>
|
||||||
</Type>
|
</Type>
|
||||||
|
|
||||||
@@ -98,7 +142,7 @@
|
|||||||
|
|
||||||
<Expand HideRawView="true">
|
<Expand HideRawView="true">
|
||||||
<Item Name="data">_data</Item>
|
<Item Name="data">_data</Item>
|
||||||
<Item Name="typeId">(asmjit::Type::Id)(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::BaseReg::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>
|
||||||
@@ -108,26 +152,26 @@
|
|||||||
<Type Name="asmjit::BaseNode">
|
<Type Name="asmjit::BaseNode">
|
||||||
<Intrinsic Name="nodeType" Expression="_any._nodeType" />
|
<Intrinsic Name="nodeType" Expression="_any._nodeType" />
|
||||||
|
|
||||||
<Intrinsic Name="isInst" Expression="nodeType() == asmjit::BaseNode::kNodeInst"></Intrinsic>
|
<Intrinsic Name="isInst" Expression="nodeType() == asmjit::NodeType::kInst"></Intrinsic>
|
||||||
<Intrinsic Name="isSection" Expression="nodeType() == asmjit::BaseNode::kNodeSection"></Intrinsic>
|
<Intrinsic Name="isSection" Expression="nodeType() == asmjit::NodeType::kSection"></Intrinsic>
|
||||||
<Intrinsic Name="isLabel" Expression="nodeType() == asmjit::BaseNode::kNodeLabel"></Intrinsic>
|
<Intrinsic Name="isLabel" Expression="nodeType() == asmjit::NodeType::kLabel"></Intrinsic>
|
||||||
<Intrinsic Name="isAlign" Expression="nodeType() == asmjit::BaseNode::kNodeAlign"></Intrinsic>
|
<Intrinsic Name="isAlign" Expression="nodeType() == asmjit::NodeType::kAlign"></Intrinsic>
|
||||||
<Intrinsic Name="isEmbedData" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedData"></Intrinsic>
|
<Intrinsic Name="isEmbedData" Expression="nodeType() == asmjit::NodeType::kEmbedData"></Intrinsic>
|
||||||
<Intrinsic Name="isEmbedLabel" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabel"></Intrinsic>
|
<Intrinsic Name="isEmbedLabel" Expression="nodeType() == asmjit::NodeType::kEmbedLabel"></Intrinsic>
|
||||||
<Intrinsic Name="isEmbedLabelDelta" Expression="nodeType() == asmjit::BaseNode::kNodeEmbedLabelDelta"></Intrinsic>
|
<Intrinsic Name="isEmbedLabelDelta" Expression="nodeType() == asmjit::NodeType::kEmbedLabelDelta"></Intrinsic>
|
||||||
<Intrinsic Name="isConstPool" Expression="nodeType() == asmjit::BaseNode::kNodeConstPool"></Intrinsic>
|
<Intrinsic Name="isConstPool" Expression="nodeType() == asmjit::NodeType::kConstPool"></Intrinsic>
|
||||||
<Intrinsic Name="isComment" Expression="nodeType() == asmjit::BaseNode::kNodeComment"></Intrinsic>
|
<Intrinsic Name="isComment" Expression="nodeType() == asmjit::NodeType::kComment"></Intrinsic>
|
||||||
<Intrinsic Name="isSentinel" Expression="nodeType() == asmjit::BaseNode::kNodeSentinel"></Intrinsic>
|
<Intrinsic Name="isSentinel" Expression="nodeType() == asmjit::NodeType::kSentinel"></Intrinsic>
|
||||||
<Intrinsic Name="isJump" Expression="nodeType() == asmjit::BaseNode::kNodeJump"></Intrinsic>
|
<Intrinsic Name="isJump" Expression="nodeType() == asmjit::NodeType::kJump"></Intrinsic>
|
||||||
<Intrinsic Name="isFunc" Expression="nodeType() == asmjit::BaseNode::kNodeFunc"></Intrinsic>
|
<Intrinsic Name="isFunc" Expression="nodeType() == asmjit::NodeType::kFunc"></Intrinsic>
|
||||||
<Intrinsic Name="isFuncRet" Expression="nodeType() == asmjit::BaseNode::kNodeFuncRet"></Intrinsic>
|
<Intrinsic Name="isFuncRet" Expression="nodeType() == asmjit::NodeType::kFuncRet"></Intrinsic>
|
||||||
<Intrinsic Name="isInvoke" Expression="nodeType() == asmjit::BaseNode::kNodeInvoke"></Intrinsic>
|
<Intrinsic Name="isInvoke" Expression="nodeType() == asmjit::NodeType::kInvoke"></Intrinsic>
|
||||||
|
|
||||||
<Intrinsic Name="actsAsInst" Expression="isInst() || isJump() || isFunc() || isFuncRet() || isInvoke()" />
|
<Intrinsic Name="actsAsInst" Expression="isInst() || isJump() || isFunc() || isFuncRet() || isInvoke()" />
|
||||||
<Intrinsic Name="actsAsLabel" Expression="isLabel() || isFunc()" />
|
<Intrinsic Name="actsAsLabel" Expression="isLabel() || isFunc()" />
|
||||||
|
|
||||||
<DisplayString Condition="isInst()">[InstNode]</DisplayString>
|
<DisplayString Condition="isInst()">[InstNode]</DisplayString>
|
||||||
<DisplayString Condition="isSentinel()">[SectionNode]</DisplayString>
|
<DisplayString Condition="isSection()">[SectionNode]</DisplayString>
|
||||||
<DisplayString Condition="isLabel()">[LabelNode]</DisplayString>
|
<DisplayString Condition="isLabel()">[LabelNode]</DisplayString>
|
||||||
<DisplayString Condition="isAlign()">[AlignNode]</DisplayString>
|
<DisplayString Condition="isAlign()">[AlignNode]</DisplayString>
|
||||||
<DisplayString Condition="isEmbedData()">[EmbedDataNode]</DisplayString>
|
<DisplayString Condition="isEmbedData()">[EmbedDataNode]</DisplayString>
|
||||||
@@ -140,14 +184,14 @@
|
|||||||
<DisplayString Condition="isFunc()">[FuncNode]</DisplayString>
|
<DisplayString Condition="isFunc()">[FuncNode]</DisplayString>
|
||||||
<DisplayString Condition="isFuncRet()">[FuncRetNode]</DisplayString>
|
<DisplayString Condition="isFuncRet()">[FuncRetNode]</DisplayString>
|
||||||
<DisplayString Condition="isInvoke()">[InvokeNode]</DisplayString>
|
<DisplayString Condition="isInvoke()">[InvokeNode]</DisplayString>
|
||||||
<DisplayString Condition="nodeType() == 0 || nodeType() > 18">[UnknownNode {nodeType(), d}]</DisplayString>
|
<DisplayString Condition="nodeType() == asmjit::NodeType::kNone || nodeType() > 18">[UnknownNode {nodeType(), d}]</DisplayString>
|
||||||
|
|
||||||
<Expand HideRawView="true">
|
<Expand HideRawView="true">
|
||||||
<Item Name="prev">_prev</Item>
|
<Item Name="prev">_prev</Item>
|
||||||
<Item Name="next">_next</Item>
|
<Item Name="next">_next</Item>
|
||||||
|
|
||||||
<Item Name="nodeType">(asmjit::BaseNode::NodeType)_any._nodeType</Item>
|
<Item Name="nodeType">_any._nodeType</Item>
|
||||||
<Item Name="nodeFlags">(asmjit::BaseNode::Flags)_any._nodeFlags</Item>
|
<Item Name="nodeFlags">_any._nodeFlags</Item>
|
||||||
|
|
||||||
<Item Name="position">_position</Item>
|
<Item Name="position">_position</Item>
|
||||||
<Item Name="userData.u64">_userDataU64</Item>
|
<Item Name="userData.u64">_userDataU64</Item>
|
||||||
@@ -163,9 +207,9 @@
|
|||||||
<Item Name="sectionId" Condition="isSection()">((asmjit::SectionNode*)this)->_id</Item>
|
<Item Name="sectionId" Condition="isSection()">((asmjit::SectionNode*)this)->_id</Item>
|
||||||
<Item Name="nextSection" Condition="isSection()">((asmjit::SectionNode*)this)->_nextSection</Item>
|
<Item Name="nextSection" Condition="isSection()">((asmjit::SectionNode*)this)->_nextSection</Item>
|
||||||
|
|
||||||
<Item Name="labelId" Condition="isLabel()">((asmjit::LabelNode*)this)->_id</Item>
|
<Item Name="labelId" Condition="isLabel()">((asmjit::LabelNode*)this)->_labelId</Item>
|
||||||
|
|
||||||
<Item Name="alignMode" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignMode</Item>
|
<Item Name="alignMode" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignData._alignMode</Item>
|
||||||
<Item Name="alignment" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignment</Item>
|
<Item Name="alignment" Condition="isAlign()">((asmjit::AlignNode*)this)->_alignment</Item>
|
||||||
|
|
||||||
<Item Name="typeId" Condition="isEmbedData()">_embed._typeId, d</Item>
|
<Item Name="typeId" Condition="isEmbedData()">_embed._typeId, d</Item>
|
||||||
@@ -175,15 +219,15 @@
|
|||||||
<Item Name="inlineData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_inlineData</Item>
|
<Item Name="inlineData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_inlineData</Item>
|
||||||
<Item Name="externalData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_externalData</Item>
|
<Item Name="externalData" Condition="isEmbedData()">((asmjit::EmbedDataNode*)this)->_externalData</Item>
|
||||||
|
|
||||||
<Item Name="labelId" Condition="isEmbedLabel()">((asmjit::EmbedLabelNode*)this)->_id</Item>
|
<Item Name="labelId" Condition="isEmbedLabel()">((asmjit::EmbedLabelNode*)this)->_labelId</Item>
|
||||||
|
|
||||||
<Item Name="labelId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_id</Item>
|
<Item Name="labelId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_labelId</Item>
|
||||||
<Item Name="baseId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_baseId</Item>
|
<Item Name="baseLabelId" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_baseLabelId</Item>
|
||||||
<Item Name="dataSize" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_dataSize</Item>
|
<Item Name="dataSize" Condition="isEmbedLabelDelta()">((asmjit::EmbedLabelDeltaNode*)this)->_dataSize</Item>
|
||||||
|
|
||||||
<Item Name="constPool" Condition="isConstPool()">((asmjit::ConstPoolNode*)this)->_constPool</Item>
|
<Item Name="constPool" Condition="isConstPool()">((asmjit::ConstPoolNode*)this)->_constPool</Item>
|
||||||
|
|
||||||
<Item Name="sentinel.sentinelType" Condition="isSentinel()">(asmjit::SentinelNode::SentinelType)_sentinel._sentinelType</Item>
|
<Item Name="sentinel.sentinelType" Condition="isSentinel()">_sentinel._sentinelType</Item>
|
||||||
|
|
||||||
<Item Name="annotation" Condition="isJump()">((asmjit::JumpNode*)this)->_annotation</Item>
|
<Item Name="annotation" Condition="isJump()">((asmjit::JumpNode*)this)->_annotation</Item>
|
||||||
|
|
||||||
@@ -194,7 +238,7 @@
|
|||||||
<Item Name="args" Condition="isFunc()">((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount]</Item>
|
<Item Name="args" Condition="isFunc()">((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount]</Item>
|
||||||
|
|
||||||
<Item Name="funcDetail" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_funcDetail</Item>
|
<Item Name="funcDetail" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_funcDetail</Item>
|
||||||
<Item Name="rets" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_rets, [((asmjit::InvokeNode*)this)->_funcDetail._retCount]</Item>
|
<Item Name="rets" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_rets</Item>
|
||||||
<Item Name="args" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount]</Item>
|
<Item Name="args" Condition="isInvoke()">((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount]</Item>
|
||||||
</Expand>
|
</Expand>
|
||||||
</Type>
|
</Type>
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma push_macro("min")
|
#pragma push_macro("min")
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma pop_macro("min")
|
#pragma pop_macro("min")
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// SPDX-License-Identifier: Zlib
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// Official GitHub Repository: https://github.com/asmjit/asmjit
|
||||||
//
|
//
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
// Copyright (c) 2008-2021 The AsmJit Authors
|
||||||
//
|
//
|
||||||
// This software is provided 'as-is', without any express or implied
|
// This software is provided 'as-is', without any express or implied
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
// warranty. In no event will the authors be held liable for any damages
|
||||||
|
|||||||
1313
src/asmjit/core.h
1313
src/asmjit/core.h
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
#define ASMJIT_CORE_API_BUILD_P_H_INCLUDED
|
||||||
@@ -47,10 +29,6 @@
|
|||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Build - Globals - Build-Only]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#include "./api-config.h"
|
#include "./api-config.h"
|
||||||
|
|
||||||
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__)
|
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__)
|
||||||
|
|||||||
@@ -1,48 +1,59 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
||||||
#define ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
#define ASMJIT_CORE_API_CONFIG_H_INCLUDED
|
||||||
|
|
||||||
// ============================================================================
|
// AsmJit Library & ABI Version
|
||||||
// [asmjit::Version]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format.
|
//! AsmJit library version in `(Major << 16) | (Minor << 8) | (Patch)` format.
|
||||||
#define ASMJIT_LIBRARY_VERSION 0x010400 /* 1.4.0 */
|
#define ASMJIT_LIBRARY_VERSION 0x010800 /* 1.8.0 */
|
||||||
|
|
||||||
|
//! \def ASMJIT_ABI_NAMESPACE
|
||||||
|
//!
|
||||||
|
//! AsmJit ABI namespace is an inline namespace within \ref asmjit namespace.
|
||||||
|
//!
|
||||||
|
//! It's used to make sure that when user links to an incompatible version of AsmJit, it won't link. It has also some
|
||||||
|
//! additional properties as well. When `ASMJIT_ABI_NAMESPACE` is defined by the user it would override the AsmJit
|
||||||
|
//! default, which makes it possible to use use multiple AsmJit libraries within a single project, totally controlled
|
||||||
|
//! by the users. This is useful especially in cases in which some of such library comes from a third party.
|
||||||
|
#ifndef ASMJIT_ABI_NAMESPACE
|
||||||
|
#define ASMJIT_ABI_NAMESPACE _abi_1_8
|
||||||
|
#endif
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
// ============================================================================
|
// Global Dependencies
|
||||||
// [asmjit::Build - Documentation]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// NOTE: Doxygen cannot document macros that are not defined, that's why we have
|
#include <stdarg.h>
|
||||||
// to define them and then undefine them, so it won't use the macros with its
|
#include <stddef.h>
|
||||||
// own preprocessor.
|
#include <stdint.h> // We really want std types as globals, not under 'std' namespace.
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <iterator>
|
||||||
|
#include <limits>
|
||||||
|
#include <new>
|
||||||
|
#include <type_traits>
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
|
||||||
|
#include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Build Options
|
||||||
|
// =============
|
||||||
|
|
||||||
|
// NOTE: Doxygen cannot document macros that are not defined, that's why we have to define them and then undefine
|
||||||
|
// them immediately, so it won't use the macros with its own preprocessor.
|
||||||
#ifdef _DOXYGEN
|
#ifdef _DOXYGEN
|
||||||
namespace asmjit {
|
namespace asmjit {
|
||||||
|
|
||||||
@@ -80,10 +91,10 @@ namespace asmjit {
|
|||||||
//! Disables \ref asmjit_compiler functionality completely.
|
//! Disables \ref asmjit_compiler functionality completely.
|
||||||
#define ASMJIT_NO_COMPILER
|
#define ASMJIT_NO_COMPILER
|
||||||
|
|
||||||
//! Disables JIT memory management and \ref JitRuntime.
|
//! Disables JIT memory management and \ref asmjit::JitRuntime.
|
||||||
#define ASMJIT_NO_JIT
|
#define ASMJIT_NO_JIT
|
||||||
|
|
||||||
//! Disables \ref Logger and \ref Formatter.
|
//! Disables \ref asmjit::Logger and \ref asmjit::Formatter.
|
||||||
#define ASMJIT_NO_LOGGING
|
#define ASMJIT_NO_LOGGING
|
||||||
|
|
||||||
//! Disables everything that contains text.
|
//! Disables everything that contains text.
|
||||||
@@ -116,33 +127,6 @@ namespace asmjit {
|
|||||||
} // {asmjit}
|
} // {asmjit}
|
||||||
#endif // _DOXYGEN
|
#endif // _DOXYGEN
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Dependencies]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// We really want std-types as globals.
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <iterator>
|
|
||||||
#include <limits>
|
|
||||||
#include <new>
|
|
||||||
#include <type_traits>
|
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
|
|
||||||
#include <pthread.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Options]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER.
|
// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER.
|
||||||
#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER)
|
#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER)
|
||||||
#define ASMJIT_NO_COMPILER
|
#define ASMJIT_NO_COMPILER
|
||||||
@@ -150,37 +134,17 @@ namespace asmjit {
|
|||||||
|
|
||||||
// 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 "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.")
|
||||||
#undef ASMJIT_NO_TEXT
|
#undef ASMJIT_NO_TEXT
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER)
|
#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER)
|
||||||
#pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined")
|
#pragma message("'ASMJIT_NO_INTROSPECTION' can only be defined when 'ASMJIT_NO_COMPILER' is defined")
|
||||||
#undef ASMJIT_NO_INTROSPECTION
|
#undef ASMJIT_NO_INTROSPECTION
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// Build Mode
|
||||||
// [asmjit::Build - Globals - Deprecated]
|
// ==========
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
#if defined(ASMJIT_BUILD_EMBED) || defined(ASMJIT_BUILD_STATIC)
|
|
||||||
#if defined(ASMJIT_BUILD_EMBED)
|
|
||||||
#pragma message("'ASMJIT_BUILD_EMBED' is deprecated, use 'ASMJIT_STATIC'")
|
|
||||||
#endif
|
|
||||||
#if defined(ASMJIT_BUILD_STATIC)
|
|
||||||
#pragma message("'ASMJIT_BUILD_STATIC' is deprecated, use 'ASMJIT_STATIC'")
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#if !defined(ASMJIT_STATIC)
|
|
||||||
#define ASMJIT_STATIC
|
|
||||||
#endif
|
|
||||||
#endif
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Build - Globals - Build Mode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Detect ASMJIT_BUILD_DEBUG and ASMJIT_BUILD_RELEASE if not defined.
|
// Detect ASMJIT_BUILD_DEBUG and ASMJIT_BUILD_RELEASE if not defined.
|
||||||
#if !defined(ASMJIT_BUILD_DEBUG) && !defined(ASMJIT_BUILD_RELEASE)
|
#if !defined(ASMJIT_BUILD_DEBUG) && !defined(ASMJIT_BUILD_RELEASE)
|
||||||
@@ -191,9 +155,8 @@ namespace asmjit {
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// Target Architecture Detection
|
||||||
// [asmjit::Build - Globals - Target Architecture Information]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(_M_X64) || defined(__x86_64__)
|
#if defined(_M_X64) || defined(__x86_64__)
|
||||||
#define ASMJIT_ARCH_X86 64
|
#define ASMJIT_ARCH_X86 64
|
||||||
@@ -239,19 +202,15 @@ namespace asmjit {
|
|||||||
#define ASMJIT_ARCH_BE 0
|
#define ASMJIT_ARCH_BE 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Build - Globals - Backends]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_NO_FOREIGN)
|
#if defined(ASMJIT_NO_FOREIGN)
|
||||||
#if !ASMJIT_ARCH_X86 && !defined(ASMJIT_NO_X86)
|
#if !ASMJIT_ARCH_X86 && !defined(ASMJIT_NO_X86)
|
||||||
#define ASMJIT_NO_X86
|
#define ASMJIT_NO_X86
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Build - Globals - C++ Compiler and Features Detection]
|
// C++ Compiler and Features Detection
|
||||||
// ============================================================================
|
// ===================================
|
||||||
|
|
||||||
#define ASMJIT_CXX_GNU 0
|
#define ASMJIT_CXX_GNU 0
|
||||||
#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR))
|
#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR))
|
||||||
@@ -293,9 +252,12 @@ namespace asmjit {
|
|||||||
#define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK)))
|
#define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK)))
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// API Decorators & C++ Extensions
|
||||||
// [asmjit::Build - Globals - API Decorators & Language Extensions]
|
// ===============================
|
||||||
// ============================================================================
|
|
||||||
|
//! \def ASMJIT_API
|
||||||
|
//!
|
||||||
|
//! A decorator that is used to decorate API that AsmJit exports when built as a shared library.
|
||||||
|
|
||||||
// API (Export / Import).
|
// API (Export / Import).
|
||||||
#if !defined(ASMJIT_STATIC)
|
#if !defined(ASMJIT_STATIC)
|
||||||
@@ -324,12 +286,12 @@ namespace asmjit {
|
|||||||
#define ASMJIT_VARAPI extern ASMJIT_API
|
#define ASMJIT_VARAPI extern ASMJIT_API
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// This is basically a workaround. When using MSVC and marking class as DLL
|
//! \def ASMJIT_VIRTAPI
|
||||||
// export everything gets exported, which is unwanted in most projects. MSVC
|
//!
|
||||||
// automatically exports typeinfo and vtable if at least one symbol of the
|
//! This is basically a workaround. When using MSVC and marking class as DLL export everything gets exported, which
|
||||||
// class is exported. However, GCC has some strange behavior that even if
|
//! is unwanted in most projects. MSVC automatically exports typeinfo and vtable if at least one symbol of the class
|
||||||
// one or more symbol is exported it doesn't export typeinfo unless the
|
//! is exported. However, GCC has some strange behavior that even if one or more symbol is exported it doesn't export
|
||||||
// class itself is decorated with "visibility(default)" (i.e. ASMJIT_API).
|
//! typeinfo unless the class itself is decorated with "visibility(default)" (i.e. ASMJIT_API).
|
||||||
#if !defined(_WIN32) && defined(__GNUC__)
|
#if !defined(_WIN32) && defined(__GNUC__)
|
||||||
#define ASMJIT_VIRTAPI ASMJIT_API
|
#define ASMJIT_VIRTAPI ASMJIT_API
|
||||||
#else
|
#else
|
||||||
@@ -338,11 +300,11 @@ namespace asmjit {
|
|||||||
|
|
||||||
// Function attributes.
|
// Function attributes.
|
||||||
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__)
|
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__)
|
||||||
#define ASMJIT_INLINE inline __attribute__((__always_inline__))
|
#define ASMJIT_FORCE_INLINE inline __attribute__((__always_inline__))
|
||||||
#elif !defined(ASMJIT_BUILD_DEBUG) && defined(_MSC_VER)
|
#elif !defined(ASMJIT_BUILD_DEBUG) && defined(_MSC_VER)
|
||||||
#define ASMJIT_INLINE __forceinline
|
#define ASMJIT_FORCE_INLINE __forceinline
|
||||||
#else
|
#else
|
||||||
#define ASMJIT_INLINE inline
|
#define ASMJIT_FORCE_INLINE inline
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(__GNUC__)
|
#if defined(__GNUC__)
|
||||||
@@ -401,6 +363,17 @@ namespace asmjit {
|
|||||||
#define ASMJIT_MAY_ALIAS
|
#define ASMJIT_MAY_ALIAS
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//! \def ASMJIT_MAYBE_UNUSED
|
||||||
|
//!
|
||||||
|
//! Expands to `[[maybe_unused]]` if supported or a compiler attribute instead.
|
||||||
|
#if __cplusplus >= 201703L
|
||||||
|
#define ASMJIT_MAYBE_UNUSED [[maybe_unused]]
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
#define ASMJIT_MAYBE_UNUSED __attribute__((unused))
|
||||||
|
#else
|
||||||
|
#define ASMJIT_MAYBE_UNUSED
|
||||||
|
#endif
|
||||||
|
|
||||||
//! \def ASMJIT_LIKELY(...)
|
//! \def ASMJIT_LIKELY(...)
|
||||||
//!
|
//!
|
||||||
//! Condition is likely to be taken (mostly error handling and edge cases).
|
//! Condition is likely to be taken (mostly error handling and edge cases).
|
||||||
@@ -457,49 +430,51 @@ namespace asmjit {
|
|||||||
#define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF
|
#define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// Begin-Namespace & End-Namespace Macros
|
||||||
// [asmjit::Build - Globals - Begin-Namespace / End-Namespace]
|
// ======================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(__clang__)
|
#if defined _DOXYGEN
|
||||||
|
#define ASMJIT_BEGIN_NAMESPACE namespace asmjit {
|
||||||
|
#define ASMJIT_END_NAMESPACE }
|
||||||
|
#elif defined(__clang__)
|
||||||
#define ASMJIT_BEGIN_NAMESPACE \
|
#define ASMJIT_BEGIN_NAMESPACE \
|
||||||
namespace asmjit { \
|
namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
|
||||||
_Pragma("clang diagnostic push") \
|
_Pragma("clang diagnostic push") \
|
||||||
_Pragma("clang diagnostic ignored \"-Wconstant-logical-operand\"") \
|
_Pragma("clang diagnostic ignored \"-Wconstant-logical-operand\"") \
|
||||||
_Pragma("clang diagnostic ignored \"-Wunnamed-type-template-args\"")
|
_Pragma("clang diagnostic ignored \"-Wunnamed-type-template-args\"")
|
||||||
#define ASMJIT_END_NAMESPACE \
|
#define ASMJIT_END_NAMESPACE \
|
||||||
_Pragma("clang diagnostic pop") \
|
_Pragma("clang diagnostic pop") \
|
||||||
}
|
}}
|
||||||
#elif defined(__GNUC__) && __GNUC__ == 4
|
#elif defined(__GNUC__) && __GNUC__ == 4
|
||||||
#define ASMJIT_BEGIN_NAMESPACE \
|
#define ASMJIT_BEGIN_NAMESPACE \
|
||||||
namespace asmjit { \
|
namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
|
||||||
_Pragma("GCC diagnostic push") \
|
_Pragma("GCC diagnostic push") \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
|
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
|
||||||
#define ASMJIT_END_NAMESPACE \
|
#define ASMJIT_END_NAMESPACE \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
}
|
}}
|
||||||
#elif defined(__GNUC__) && __GNUC__ >= 8
|
#elif defined(__GNUC__) && __GNUC__ >= 8
|
||||||
#define ASMJIT_BEGIN_NAMESPACE \
|
#define ASMJIT_BEGIN_NAMESPACE \
|
||||||
namespace asmjit { \
|
namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
|
||||||
_Pragma("GCC diagnostic push") \
|
_Pragma("GCC diagnostic push") \
|
||||||
_Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
|
_Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
|
||||||
#define ASMJIT_END_NAMESPACE \
|
#define ASMJIT_END_NAMESPACE \
|
||||||
_Pragma("GCC diagnostic pop") \
|
_Pragma("GCC diagnostic pop") \
|
||||||
}
|
}}
|
||||||
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER)
|
||||||
#define ASMJIT_BEGIN_NAMESPACE \
|
#define ASMJIT_BEGIN_NAMESPACE \
|
||||||
namespace asmjit { \
|
namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
|
||||||
__pragma(warning(push)) \
|
__pragma(warning(push)) \
|
||||||
__pragma(warning(disable: 4127)) /* conditional expression is const */ \
|
__pragma(warning(disable: 4127)) /* conditional expression is const */ \
|
||||||
__pragma(warning(disable: 4201)) /* nameless struct/union */
|
__pragma(warning(disable: 4201)) /* nameless struct/union */
|
||||||
#define ASMJIT_END_NAMESPACE \
|
#define ASMJIT_END_NAMESPACE \
|
||||||
__pragma(warning(pop)) \
|
__pragma(warning(pop)) \
|
||||||
}
|
}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if !defined(ASMJIT_BEGIN_NAMESPACE) && !defined(ASMJIT_END_NAMESPACE)
|
#if !defined(ASMJIT_BEGIN_NAMESPACE) && !defined(ASMJIT_END_NAMESPACE)
|
||||||
#define ASMJIT_BEGIN_NAMESPACE namespace asmjit {
|
#define ASMJIT_BEGIN_NAMESPACE namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE {
|
||||||
#define ASMJIT_END_NAMESPACE }
|
#define ASMJIT_END_NAMESPACE }}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define ASMJIT_BEGIN_SUB_NAMESPACE(NAMESPACE) \
|
#define ASMJIT_BEGIN_SUB_NAMESPACE(NAMESPACE) \
|
||||||
@@ -510,9 +485,8 @@ namespace asmjit {
|
|||||||
} \
|
} \
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// C++ Utilities
|
||||||
// [asmjit::Build - Globals - Utilities]
|
// =============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define ASMJIT_NONCOPYABLE(Type) \
|
#define ASMJIT_NONCOPYABLE(Type) \
|
||||||
Type(const Type& other) = delete; \
|
Type(const Type& other) = delete; \
|
||||||
@@ -523,11 +497,71 @@ namespace asmjit {
|
|||||||
Type(const Type& other) = delete; \
|
Type(const Type& other) = delete; \
|
||||||
Type& operator=(const Type& other) = delete;
|
Type& operator=(const Type& other) = delete;
|
||||||
|
|
||||||
// ============================================================================
|
//! \def ASMJIT_DEFINE_ENUM_FLAGS(T)
|
||||||
// [asmjit::Build - Globals - Cleanup]
|
//!
|
||||||
// ============================================================================
|
//! Defines bit operations for enumeration flags.
|
||||||
|
#ifdef _DOXYGEN
|
||||||
|
#define ASMJIT_DEFINE_ENUM_FLAGS(T)
|
||||||
|
#else
|
||||||
|
#define ASMJIT_DEFINE_ENUM_FLAGS(T) \
|
||||||
|
static ASMJIT_FORCE_INLINE constexpr T operator~(T a) noexcept { \
|
||||||
|
return T(~(std::underlying_type<T>::type)(a)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static ASMJIT_FORCE_INLINE constexpr T operator|(T a, T b) noexcept { \
|
||||||
|
return T((std::underlying_type<T>::type)(a) | \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE constexpr T operator&(T a, T b) noexcept { \
|
||||||
|
return T((std::underlying_type<T>::type)(a) & \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE constexpr T operator^(T a, T b) noexcept { \
|
||||||
|
return T((std::underlying_type<T>::type)(a) ^ \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
} \
|
||||||
|
\
|
||||||
|
static ASMJIT_FORCE_INLINE T& operator|=(T& a, T b) noexcept { \
|
||||||
|
a = T((std::underlying_type<T>::type)(a) | \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE T& operator&=(T& a, T b) noexcept { \
|
||||||
|
a = T((std::underlying_type<T>::type)(a) & \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
return a; \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE T& operator^=(T& a, T b) noexcept { \
|
||||||
|
a = T((std::underlying_type<T>::type)(a) ^ \
|
||||||
|
(std::underlying_type<T>::type)(b)); \
|
||||||
|
return a; \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//! \def ASMJIT_DEFINE_ENUM_COMPARE(T)
|
||||||
|
//!
|
||||||
|
//! Defines comparison operations for enumeration flags.
|
||||||
|
#ifdef _DOXYGEN
|
||||||
|
#define ASMJIT_DEFINE_ENUM_COMPARE(T)
|
||||||
|
#else
|
||||||
|
#define ASMJIT_DEFINE_ENUM_COMPARE(T) \
|
||||||
|
static ASMJIT_FORCE_INLINE bool operator<(T a, T b) noexcept { \
|
||||||
|
return (std::underlying_type<T>::type)(a) < (std::underlying_type<T>::type)(b); \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE bool operator<=(T a, T b) noexcept { \
|
||||||
|
return (std::underlying_type<T>::type)(a) <= (std::underlying_type<T>::type)(b); \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE bool operator>(T a, T b) noexcept { \
|
||||||
|
return (std::underlying_type<T>::type)(a) > (std::underlying_type<T>::type)(b); \
|
||||||
|
} \
|
||||||
|
static ASMJIT_FORCE_INLINE bool operator>=(T a, T b) noexcept { \
|
||||||
|
return (std::underlying_type<T>::type)(a) >= (std::underlying_type<T>::type)(b); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Cleanup Api-Config Specific Macros
|
||||||
|
// ==================================
|
||||||
|
|
||||||
// Cleanup definitions that are only used within this header file.
|
|
||||||
#undef ASMJIT_CXX_GNU
|
#undef ASMJIT_CXX_GNU
|
||||||
#undef ASMJIT_CXX_MAKE_VER
|
#undef ASMJIT_CXX_MAKE_VER
|
||||||
|
|
||||||
|
|||||||
@@ -1,106 +1,82 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
#define ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
|
||||||
|
|
||||||
// This file provides architecture-specific classes that are required in the
|
// This file provides architecture-specific classes that are required in the core library. For example Imm operand
|
||||||
// core library. For example Imm operand allows to be created from arm::Shift
|
// allows to be created from arm::Shift in a const-expr way, so the arm::Shift must be provided. So this header file
|
||||||
// in a const-expr way, so the arm::Shift must be provided. So this header
|
// provides everything architecture-specific that is used by the Core API.
|
||||||
// file provides everything architecture-specific that is used by the Core API.
|
|
||||||
|
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::arm]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
ASMJIT_BEGIN_SUB_NAMESPACE(arm)
|
||||||
|
|
||||||
//! \addtogroup asmjit_arm
|
//! \addtogroup asmjit_arm
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Shift operation predicate (ARM) describes either SHIFT or EXTEND operation.
|
||||||
|
//!
|
||||||
|
//! \note The constants are AsmJit specific. The first 5 values describe real constants on ARM32 and AArch64 hardware,
|
||||||
|
//! however, the addition constants that describe extend modes are specific to AsmJit and would be translated to the
|
||||||
|
//! AArch64 specific constants by the assembler.
|
||||||
|
enum class ShiftOp {
|
||||||
|
//! Shift left logical operation (default).
|
||||||
|
//!
|
||||||
|
//! Available to all ARM architectures.
|
||||||
|
kLSL = 0x00u,
|
||||||
|
|
||||||
|
//! Shift right logical operation.
|
||||||
|
//!
|
||||||
|
//! Available to all ARM architectures.
|
||||||
|
kLSR = 0x01u,
|
||||||
|
|
||||||
|
//! Shift right arithmetic operation.
|
||||||
|
//!
|
||||||
|
//! Available to all ARM architectures.
|
||||||
|
kASR = 0x02u,
|
||||||
|
|
||||||
|
//! Rotate right operation.
|
||||||
|
//!
|
||||||
|
//! \note Not available in AArch64 mode.
|
||||||
|
kROR = 0x03u,
|
||||||
|
|
||||||
|
//! Rotate right with carry operation (encoded as `kShiftROR` with zero).
|
||||||
|
//!
|
||||||
|
//! \note Not available in AArch64 mode.
|
||||||
|
kRRX = 0x04u,
|
||||||
|
|
||||||
|
//! Shift left by filling low order bits with ones.
|
||||||
|
kMSL = 0x05u,
|
||||||
|
|
||||||
|
//! UXTN extend register operation (AArch64 only).
|
||||||
|
kUXTB = 0x06u,
|
||||||
|
//! UXTH extend register operation (AArch64 only).
|
||||||
|
kUXTH = 0x07u,
|
||||||
|
//! UXTW extend register operation (AArch64 only).
|
||||||
|
kUXTW = 0x08u,
|
||||||
|
//! UXTX extend register operation (AArch64 only).
|
||||||
|
kUXTX = 0x09u,
|
||||||
|
|
||||||
|
//! SXTB extend register operation (AArch64 only).
|
||||||
|
kSXTB = 0x0Au,
|
||||||
|
//! SXTH extend register operation (AArch64 only).
|
||||||
|
kSXTH = 0x0Bu,
|
||||||
|
//! SXTW extend register operation (AArch64 only).
|
||||||
|
kSXTW = 0x0Cu,
|
||||||
|
//! SXTX extend register operation (AArch64 only).
|
||||||
|
kSXTX = 0x0Du
|
||||||
|
|
||||||
|
// NOTE: 0xE and 0xF are used by memory operand to specify POST|PRE offset mode.
|
||||||
|
};
|
||||||
|
|
||||||
//! Represents ARM immediate shift operation type and value.
|
//! Represents ARM immediate shift operation type and value.
|
||||||
class Shift {
|
class Shift {
|
||||||
public:
|
public:
|
||||||
//! Operation predicate (ARM) describes either SHIFT or EXTEND operation.
|
|
||||||
//!
|
|
||||||
//! \note The constants are AsmJit specific. The first 5 values describe real
|
|
||||||
//! constants on ARM32 and AArch64 hardware, however, the addition constants
|
|
||||||
//! that describe extend modes are specific to AsmJit and would be translated
|
|
||||||
//! to the AArch64 specific constants by the assembler.
|
|
||||||
enum Op : uint32_t {
|
|
||||||
//! Shift left logical operation (default).
|
|
||||||
//!
|
|
||||||
//! Available to all ARM architectures.
|
|
||||||
kOpLSL = 0x00u,
|
|
||||||
|
|
||||||
//! Shift right logical operation.
|
|
||||||
//!
|
|
||||||
//! Available to all ARM architectures.
|
|
||||||
kOpLSR = 0x01u,
|
|
||||||
|
|
||||||
//! Shift right arithmetic operation.
|
|
||||||
//!
|
|
||||||
//! Available to all ARM architectures.
|
|
||||||
kOpASR = 0x02u,
|
|
||||||
|
|
||||||
//! Rotate right operation.
|
|
||||||
//!
|
|
||||||
//! \note Not available in AArch64 mode.
|
|
||||||
kOpROR = 0x03u,
|
|
||||||
|
|
||||||
//! Rotate right with carry operation (encoded as `kShiftROR` with zero).
|
|
||||||
//!
|
|
||||||
//! \note Not available in AArch64 mode.
|
|
||||||
kOpRRX = 0x04u,
|
|
||||||
|
|
||||||
//! Shift left by filling low order bits with ones.
|
|
||||||
kOpMSL = 0x05u,
|
|
||||||
|
|
||||||
//! UXTN extend register operation (AArch64 only).
|
|
||||||
kOpUXTB = 0x06u,
|
|
||||||
//! UXTH extend register operation (AArch64 only).
|
|
||||||
kOpUXTH = 0x07u,
|
|
||||||
//! UXTW extend register operation (AArch64 only).
|
|
||||||
kOpUXTW = 0x08u,
|
|
||||||
//! UXTX extend register operation (AArch64 only).
|
|
||||||
kOpUXTX = 0x09u,
|
|
||||||
|
|
||||||
//! SXTB extend register operation (AArch64 only).
|
|
||||||
kOpSXTB = 0x0Au,
|
|
||||||
//! SXTH extend register operation (AArch64 only).
|
|
||||||
kOpSXTH = 0x0Bu,
|
|
||||||
//! SXTW extend register operation (AArch64 only).
|
|
||||||
kOpSXTW = 0x0Cu,
|
|
||||||
//! SXTX extend register operation (AArch64 only).
|
|
||||||
kOpSXTX = 0x0Du
|
|
||||||
|
|
||||||
// NOTE: 0xE and 0xF are used by memory operand to specify POST|PRE offset mode.
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Shift operation.
|
//! Shift operation.
|
||||||
uint32_t _op;
|
ShiftOp _op;
|
||||||
//! Shift Value.
|
//! Shift Value.
|
||||||
uint32_t _value;
|
uint32_t _value;
|
||||||
|
|
||||||
@@ -111,51 +87,51 @@ public:
|
|||||||
constexpr Shift(const Shift& other) noexcept = default;
|
constexpr Shift(const Shift& other) noexcept = default;
|
||||||
|
|
||||||
//! Constructs Shift from operation `op` and shift `value`.
|
//! Constructs Shift from operation `op` and shift `value`.
|
||||||
constexpr Shift(uint32_t op, uint32_t value) noexcept
|
constexpr Shift(ShiftOp op, uint32_t value) noexcept
|
||||||
: _op(op),
|
: _op(op),
|
||||||
_value(value) {}
|
_value(value) {}
|
||||||
|
|
||||||
//! Returns the shift operation.
|
//! Returns the shift operation.
|
||||||
constexpr uint32_t op() const noexcept { return _op; }
|
constexpr ShiftOp op() const noexcept { return _op; }
|
||||||
|
//! Sets shift operation to `op`.
|
||||||
|
inline void setOp(ShiftOp op) noexcept { _op = op; }
|
||||||
|
|
||||||
//! Returns the shift smount.
|
//! Returns the shift smount.
|
||||||
constexpr uint32_t value() const noexcept { return _value; }
|
constexpr uint32_t value() const noexcept { return _value; }
|
||||||
|
|
||||||
//! Sets shift operation to `op`.
|
|
||||||
inline void setOp(uint32_t op) noexcept { _op = op; }
|
|
||||||
//! Sets shift amount to `value`.
|
//! Sets shift amount to `value`.
|
||||||
inline void setValue(uint32_t value) noexcept { _value = value; }
|
inline void setValue(uint32_t value) noexcept { _value = value; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Constructs a `LSL #value` shift (logical shift left).
|
//! Constructs a `LSL #value` shift (logical shift left).
|
||||||
static constexpr Shift lsl(uint32_t value) noexcept { return Shift(Shift::kOpLSL, value); }
|
static constexpr Shift lsl(uint32_t value) noexcept { return Shift(ShiftOp::kLSL, value); }
|
||||||
//! Constructs a `LSR #value` shift (logical shift right).
|
//! Constructs a `LSR #value` shift (logical shift right).
|
||||||
static constexpr Shift lsr(uint32_t value) noexcept { return Shift(Shift::kOpLSR, value); }
|
static constexpr Shift lsr(uint32_t value) noexcept { return Shift(ShiftOp::kLSR, value); }
|
||||||
//! Constructs a `ASR #value` shift (arithmetic shift right).
|
//! Constructs a `ASR #value` shift (arithmetic shift right).
|
||||||
static constexpr Shift asr(uint32_t value) noexcept { return Shift(Shift::kOpASR, value); }
|
static constexpr Shift asr(uint32_t value) noexcept { return Shift(ShiftOp::kASR, value); }
|
||||||
//! Constructs a `ROR #value` shift (rotate right).
|
//! Constructs a `ROR #value` shift (rotate right).
|
||||||
static constexpr Shift ror(uint32_t value) noexcept { return Shift(Shift::kOpROR, value); }
|
static constexpr Shift ror(uint32_t value) noexcept { return Shift(ShiftOp::kROR, value); }
|
||||||
//! Constructs a `RRX` shift (rotate with carry by 1).
|
//! Constructs a `RRX` shift (rotate with carry by 1).
|
||||||
static constexpr Shift rrx() noexcept { return Shift(Shift::kOpRRX, 0); }
|
static constexpr Shift rrx() noexcept { return Shift(ShiftOp::kRRX, 0); }
|
||||||
//! Constructs a `MSL #value` shift (logical shift left filling ones).
|
//! Constructs a `MSL #value` shift (logical shift left filling ones).
|
||||||
static constexpr Shift msl(uint32_t value) noexcept { return Shift(Shift::kOpMSL, value); }
|
static constexpr Shift msl(uint32_t value) noexcept { return Shift(ShiftOp::kMSL, value); }
|
||||||
|
|
||||||
//! Constructs a `UXTB #value` extend and shift (unsigned byte extend).
|
//! Constructs a `UXTB #value` extend and shift (unsigned byte extend).
|
||||||
static constexpr Shift uxtb(uint32_t value) noexcept { return Shift(Shift::kOpUXTB, value); }
|
static constexpr Shift uxtb(uint32_t value) noexcept { return Shift(ShiftOp::kUXTB, value); }
|
||||||
//! Constructs a `UXTH #value` extend and shift (unsigned hword extend).
|
//! Constructs a `UXTH #value` extend and shift (unsigned hword extend).
|
||||||
static constexpr Shift uxth(uint32_t value) noexcept { return Shift(Shift::kOpUXTH, value); }
|
static constexpr Shift uxth(uint32_t value) noexcept { return Shift(ShiftOp::kUXTH, value); }
|
||||||
//! Constructs a `UXTW #value` extend and shift (unsigned word extend).
|
//! Constructs a `UXTW #value` extend and shift (unsigned word extend).
|
||||||
static constexpr Shift uxtw(uint32_t value) noexcept { return Shift(Shift::kOpUXTW, value); }
|
static constexpr Shift uxtw(uint32_t value) noexcept { return Shift(ShiftOp::kUXTW, value); }
|
||||||
//! Constructs a `UXTX #value` extend and shift (unsigned dword extend).
|
//! Constructs a `UXTX #value` extend and shift (unsigned dword extend).
|
||||||
static constexpr Shift uxtx(uint32_t value) noexcept { return Shift(Shift::kOpUXTX, value); }
|
static constexpr Shift uxtx(uint32_t value) noexcept { return Shift(ShiftOp::kUXTX, value); }
|
||||||
|
|
||||||
//! Constructs a `SXTB #value` extend and shift (signed byte extend).
|
//! Constructs a `SXTB #value` extend and shift (signed byte extend).
|
||||||
static constexpr Shift sxtb(uint32_t value) noexcept { return Shift(Shift::kOpSXTB, value); }
|
static constexpr Shift sxtb(uint32_t value) noexcept { return Shift(ShiftOp::kSXTB, value); }
|
||||||
//! Constructs a `SXTH #value` extend and shift (signed hword extend).
|
//! Constructs a `SXTH #value` extend and shift (signed hword extend).
|
||||||
static constexpr Shift sxth(uint32_t value) noexcept { return Shift(Shift::kOpSXTH, value); }
|
static constexpr Shift sxth(uint32_t value) noexcept { return Shift(ShiftOp::kSXTH, value); }
|
||||||
//! Constructs a `SXTW #value` extend and shift (signed word extend).
|
//! Constructs a `SXTW #value` extend and shift (signed word extend).
|
||||||
static constexpr Shift sxtw(uint32_t value) noexcept { return Shift(Shift::kOpSXTW, value); }
|
static constexpr Shift sxtw(uint32_t value) noexcept { return Shift(ShiftOp::kSXTW, value); }
|
||||||
//! Constructs a `SXTX #value` extend and shift (signed dword extend).
|
//! Constructs a `SXTX #value` extend and shift (signed dword extend).
|
||||||
static constexpr Shift sxtx(uint32_t value) noexcept { return Shift(Shift::kOpSXTX, value); }
|
static constexpr Shift sxtx(uint32_t value) noexcept { return Shift(ShiftOp::kSXTX, value); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/archtraits.h"
|
#include "../core/archtraits.h"
|
||||||
@@ -35,10 +17,6 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ArchTraits]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const constexpr ArchTraits noArchTraits = {
|
static const constexpr ArchTraits noArchTraits = {
|
||||||
// SP/FP/LR/PC.
|
// SP/FP/LR/PC.
|
||||||
0xFF, 0xFF, 0xFF, 0xFF,
|
0xFF, 0xFF, 0xFF, 0xFF,
|
||||||
@@ -53,27 +31,38 @@ static const constexpr ArchTraits noArchTraits = {
|
|||||||
0, 0,
|
0, 0,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
{ 0, 0, 0, 0},
|
{{
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints
|
||||||
|
}},
|
||||||
|
|
||||||
// RegTypeToSignature.
|
// RegTypeToSignature.
|
||||||
{ { 0 } },
|
#define V(index) { OperandSignature(0) }
|
||||||
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
|
#undef V
|
||||||
|
|
||||||
// RegTypeToTypeId.
|
// RegTypeToTypeId.
|
||||||
{ 0 },
|
#define V(index) TypeId::kVoid
|
||||||
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
|
#undef V
|
||||||
|
|
||||||
// TypeIdToRegType.
|
// TypeIdToRegType.
|
||||||
{ 0 },
|
#define V(index) RegType::kNone
|
||||||
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
|
#undef V
|
||||||
|
|
||||||
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
{
|
{
|
||||||
ISAWordNameId::kByte,
|
ArchTypeNameId::kByte,
|
||||||
ISAWordNameId::kHalf,
|
ArchTypeNameId::kHalf,
|
||||||
ISAWordNameId::kWord,
|
ArchTypeNameId::kWord,
|
||||||
ISAWordNameId::kQuad
|
ArchTypeNameId::kQuad
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
|
ASMJIT_VARAPI const ArchTraits _archTraits[uint32_t(Arch::kMaxValue) + 1] = {
|
||||||
// No architecture.
|
// No architecture.
|
||||||
noArchTraits,
|
noArchTraits,
|
||||||
|
|
||||||
@@ -111,63 +100,60 @@ ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
|
|||||||
noArchTraits
|
noArchTraits
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegSignature(Arch arch, TypeId typeId, TypeId* typeIdOut, OperandSignature* regSignatureOut) noexcept {
|
||||||
// [asmjit::ArchUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept {
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
||||||
|
|
||||||
|
// TODO: Remove this, should never be used like this.
|
||||||
// Passed RegType instead of TypeId?
|
// Passed RegType instead of TypeId?
|
||||||
if (typeId <= BaseReg::kTypeMax)
|
if (uint32_t(typeId) <= uint32_t(RegType::kMaxValue))
|
||||||
typeId = archTraits.regTypeToTypeId(typeId);
|
typeId = archTraits.regTypeToTypeId(RegType(uint32_t(typeId)));
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Type::isValid(typeId)))
|
if (ASMJIT_UNLIKELY(!TypeUtils::isValid(typeId)))
|
||||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||||
|
|
||||||
// First normalize architecture dependent types.
|
// First normalize architecture dependent types.
|
||||||
if (Type::isAbstract(typeId)) {
|
if (TypeUtils::isAbstract(typeId)) {
|
||||||
bool is32Bit = Environment::is32Bit(arch);
|
bool is32Bit = Environment::is32Bit(arch);
|
||||||
if (typeId == Type::kIdIntPtr)
|
if (typeId == TypeId::kIntPtr)
|
||||||
typeId = is32Bit ? Type::kIdI32 : Type::kIdI64;
|
typeId = is32Bit ? TypeId::kInt32 : TypeId::kInt64;
|
||||||
else
|
else
|
||||||
typeId = is32Bit ? Type::kIdU32 : Type::kIdU64;
|
typeId = is32Bit ? TypeId::kUInt32 : TypeId::kUInt64;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Type size helps to construct all groups of registers.
|
// Type size helps to construct all groups of registers.
|
||||||
// TypeId is invalid if the size is zero.
|
// TypeId is invalid if the size is zero.
|
||||||
uint32_t size = Type::sizeOf(typeId);
|
uint32_t size = TypeUtils::sizeOf(typeId);
|
||||||
if (ASMJIT_UNLIKELY(!size))
|
if (ASMJIT_UNLIKELY(!size))
|
||||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(typeId == Type::kIdF80))
|
if (ASMJIT_UNLIKELY(typeId == TypeId::kFloat80))
|
||||||
return DebugUtils::errored(kErrorInvalidUseOfF80);
|
return DebugUtils::errored(kErrorInvalidUseOfF80);
|
||||||
|
|
||||||
uint32_t regType = 0;
|
RegType regType = RegType::kNone;
|
||||||
if (typeId >= Type::_kIdBaseStart && typeId < Type::_kIdVec32Start) {
|
if (TypeUtils::isBetween(typeId, TypeId::_kBaseStart, TypeId::_kVec32Start)) {
|
||||||
regType = archTraits._typeIdToRegType[typeId - Type::_kIdBaseStart];
|
regType = archTraits._typeIdToRegType[uint32_t(typeId) - uint32_t(TypeId::_kBaseStart)];
|
||||||
if (!regType) {
|
if (regType == RegType::kNone) {
|
||||||
if (typeId == Type::kIdI64 || typeId == Type::kIdU64)
|
if (typeId == TypeId::kInt64 || typeId == TypeId::kUInt64)
|
||||||
return DebugUtils::errored(kErrorInvalidUseOfGpq);
|
return DebugUtils::errored(kErrorInvalidUseOfGpq);
|
||||||
else
|
else
|
||||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (size <= 8 && archTraits._regInfo[BaseReg::kTypeVec64].isValid())
|
if (size <= 8 && archTraits._regSignature[RegType::kVec64].isValid())
|
||||||
regType = BaseReg::kTypeVec64;
|
regType = RegType::kVec64;
|
||||||
else if (size <= 16 && archTraits._regInfo[BaseReg::kTypeVec128].isValid())
|
else if (size <= 16 && archTraits._regSignature[RegType::kVec128].isValid())
|
||||||
regType = BaseReg::kTypeVec128;
|
regType = RegType::kVec128;
|
||||||
else if (size == 32 && archTraits._regInfo[BaseReg::kTypeVec256].isValid())
|
else if (size == 32 && archTraits._regSignature[RegType::kVec256].isValid())
|
||||||
regType = BaseReg::kTypeVec256;
|
regType = RegType::kVec256;
|
||||||
else if (archTraits._regInfo[BaseReg::kTypeVec512].isValid())
|
else if (archTraits._regSignature[RegType::kVec512].isValid())
|
||||||
regType = BaseReg::kTypeVec512;
|
regType = RegType::kVec512;
|
||||||
else
|
else
|
||||||
return DebugUtils::errored(kErrorInvalidTypeId);
|
return DebugUtils::errored(kErrorInvalidTypeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
*typeIdOut = typeId;
|
*typeIdOut = typeId;
|
||||||
regInfoOut->reset(archTraits.regTypeToSignature(regType));
|
*regSignatureOut = archTraits.regTypeToSignature(regType);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,31 +1,13 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
#define ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/environment.h"
|
|
||||||
#include "../core/operand.h"
|
#include "../core/operand.h"
|
||||||
|
#include "../core/support.h"
|
||||||
#include "../core/type.h"
|
#include "../core/type.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
@@ -33,8 +15,98 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Instruction set architecture (ISA).
|
||||||
|
enum class Arch : uint8_t {
|
||||||
|
//! Unknown or uninitialized ISA.
|
||||||
|
kUnknown = 0,
|
||||||
|
|
||||||
|
//! 32-bit X86 ISA.
|
||||||
|
kX86 = 1,
|
||||||
|
//! 64-bit X86 ISA also known as X64, X86_64, and AMD64.
|
||||||
|
kX64 = 2,
|
||||||
|
|
||||||
|
//! 32-bit RISC-V ISA.
|
||||||
|
kRISCV32 = 3,
|
||||||
|
//! 64-bit RISC-V ISA.
|
||||||
|
kRISCV64 = 4,
|
||||||
|
|
||||||
|
//! 32-bit ARM ISA (little endian).
|
||||||
|
kARM = 5,
|
||||||
|
//! 64-bit ARM ISA in (little endian).
|
||||||
|
kAArch64 = 6,
|
||||||
|
//! 32-bit ARM ISA in Thumb mode (little endian).
|
||||||
|
kThumb = 7,
|
||||||
|
|
||||||
|
// 8 is not used at the moment, even numbers are 64-bit architectures.
|
||||||
|
|
||||||
|
//! 32-bit MIPS ISA in (little endian).
|
||||||
|
kMIPS32_LE = 9,
|
||||||
|
//! 64-bit MIPS ISA in (little endian).
|
||||||
|
kMIPS64_LE = 10,
|
||||||
|
|
||||||
|
//! 32-bit ARM ISA (big endian).
|
||||||
|
kARM_BE = 11,
|
||||||
|
//! 64-bit ARM ISA in (big endian).
|
||||||
|
kAArch64_BE = 12,
|
||||||
|
//! 32-bit ARM ISA in Thumb mode (big endian).
|
||||||
|
kThumb_BE = 13,
|
||||||
|
|
||||||
|
// 14 is not used at the moment, even numbers are 64-bit architectures.
|
||||||
|
|
||||||
|
//! 32-bit MIPS ISA in (big endian).
|
||||||
|
kMIPS32_BE = 15,
|
||||||
|
//! 64-bit MIPS ISA in (big endian).
|
||||||
|
kMIPS64_BE = 16,
|
||||||
|
|
||||||
|
//! Maximum value of `Arch`.
|
||||||
|
kMaxValue = kMIPS64_BE,
|
||||||
|
|
||||||
|
//! Mask used by 32-bit ISAs (odd are 32-bit, even are 64-bit).
|
||||||
|
k32BitMask = 0x01,
|
||||||
|
//! First big-endian architecture.
|
||||||
|
kBigEndian = kARM_BE,
|
||||||
|
|
||||||
|
//! ISA detected at compile-time (ISA of the host).
|
||||||
|
kHost =
|
||||||
|
#if defined(_DOXYGEN)
|
||||||
|
DETECTED_AT_COMPILE_TIME
|
||||||
|
#else
|
||||||
|
ASMJIT_ARCH_X86 == 32 ? kX86 :
|
||||||
|
ASMJIT_ARCH_X86 == 64 ? kX64 :
|
||||||
|
|
||||||
|
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kARM :
|
||||||
|
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kARM_BE :
|
||||||
|
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kAArch64 :
|
||||||
|
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kAArch64_BE :
|
||||||
|
|
||||||
|
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kMIPS32_LE :
|
||||||
|
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kMIPS32_BE :
|
||||||
|
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kMIPS64_LE :
|
||||||
|
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kMIPS64_BE :
|
||||||
|
|
||||||
|
kUnknown
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Sub-architecture.
|
||||||
|
enum class SubArch : uint8_t {
|
||||||
|
//! Unknown or uninitialized architecture sub-type.
|
||||||
|
kUnknown = 0,
|
||||||
|
|
||||||
|
//! Maximum value of `SubArch`.
|
||||||
|
kMaxValue = kUnknown,
|
||||||
|
|
||||||
|
//! Sub-architecture detected at compile-time (sub-architecture of the host).
|
||||||
|
kHost =
|
||||||
|
#if defined(_DOXYGEN)
|
||||||
|
DETECTED_AT_COMPILE_TIME
|
||||||
|
#else
|
||||||
|
kUnknown
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
//! Identifier used to represent names of different data types across architectures.
|
//! Identifier used to represent names of different data types across architectures.
|
||||||
enum class ISAWordNameId : 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).
|
||||||
@@ -64,23 +136,33 @@ enum class ISAWordNameId : uint8_t {
|
|||||||
//! Describes 'quad' (64-bit word).
|
//! Describes 'quad' (64-bit word).
|
||||||
kQuad,
|
kQuad,
|
||||||
|
|
||||||
//! Maximum value.
|
//! Maximum value of `ArchTypeNameId`.
|
||||||
kMaxValue = kQuad
|
kMaxValue = kQuad
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! Instruction feature hints for each register group provided by \ref ArchTraits.
|
||||||
// [asmjit::ArchTraits]
|
//!
|
||||||
// ============================================================================
|
//! Instruction feature hints describe miscellaneous instructions provided by the architecture that can be used by
|
||||||
|
//! register allocator to make certain things simpler - like register swaps or emitting register push/pop sequences.
|
||||||
|
//!
|
||||||
|
//! \remarks Instruction feature hints are only defined for register groups that can be used with \ref
|
||||||
|
//! asmjit_compiler infrastructure. Register groups that are not managed by Compiler are not provided by
|
||||||
|
//! \ref ArchTraits and cannot be queried.
|
||||||
|
enum class InstHints : uint8_t {
|
||||||
|
//! No feature hints.
|
||||||
|
kNoHints = 0,
|
||||||
|
|
||||||
|
//! Architecture supports a register swap by using a single instructio.
|
||||||
|
kRegSwap = 0x01u,
|
||||||
|
//! Architecture provides push/pop instructions.
|
||||||
|
kPushPop = 0x02u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(InstHints)
|
||||||
|
|
||||||
//! Architecture traits used by Function API and Compiler's register allocator.
|
//! Architecture traits used by Function API and Compiler's register allocator.
|
||||||
struct ArchTraits {
|
struct ArchTraits {
|
||||||
//! ISA features for each register group.
|
//! \name Members
|
||||||
enum IsaFeatures : uint32_t {
|
//! \{
|
||||||
//! ISA features a register swap by using a single instruction.
|
|
||||||
kIsaFeatureSwap = 0x01u,
|
|
||||||
//! ISA features a push/pop like instruction for this register group.
|
|
||||||
kIsaFeaturePushPop = 0x02u,
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Stack pointer register id.
|
//! Stack pointer register id.
|
||||||
uint8_t _spRegId;
|
uint8_t _spRegId;
|
||||||
@@ -101,84 +183,69 @@ 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;
|
||||||
|
|
||||||
//! Flags for each virtual register group (always covers GP and Vec groups).
|
//! Flags for each virtual register group.
|
||||||
uint8_t _isaFlags[BaseReg::kGroupVirt];
|
Support::Array<InstHints, Globals::kNumVirtGroups> _instHints;
|
||||||
|
|
||||||
//! Maps register type into a signature, that provides group, size and can
|
//! Maps register type into a signature, that provides group, size and can be used to construct register operands.
|
||||||
//! be used to construct register operands.
|
Support::Array<OperandSignature, uint32_t(RegType::kMaxValue) + 1> _regSignature;
|
||||||
RegInfo _regInfo[BaseReg::kTypeMax + 1];
|
//! Maps a register to type-id, see \ref TypeId.
|
||||||
//! Maps a register to type-id, see \ref Type::Id.
|
Support::Array<TypeId, uint32_t(RegType::kMaxValue) + 1> _regTypeToTypeId;
|
||||||
uint8_t _regTypeToTypeId[BaseReg::kTypeMax + 1];
|
//! Maps scalar TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref TypeId.
|
||||||
//! Maps base TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref Type::Id.
|
Support::Array<RegType, 32> _typeIdToRegType;
|
||||||
uint8_t _typeIdToRegType[32];
|
|
||||||
|
|
||||||
//! Word name identifiers of 8-bit, 16-bit, 32-biit, and 64-bit quantities that appear in formatted text.
|
//! Word name identifiers of 8-bit, 16-bit, 32-biit, and 64-bit quantities that appear in formatted text.
|
||||||
ISAWordNameId _isaWordNameIdTable[4];
|
ArchTypeNameId _typeNameIdTable[4];
|
||||||
|
|
||||||
//! Resets all members to zeros.
|
//! \}
|
||||||
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
|
||||||
|
|
||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns stack pointer register id.
|
//! Returns stack pointer register id.
|
||||||
inline constexpr uint32_t spRegId() const noexcept { return _spRegId; }
|
inline uint32_t spRegId() const noexcept { return _spRegId; }
|
||||||
//! Returns stack frame register id.
|
//! Returns stack frame register id.
|
||||||
inline constexpr uint32_t fpRegId() const noexcept { return _fpRegId; }
|
inline 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.
|
||||||
inline constexpr uint32_t linkRegId() const noexcept { return _linkRegId; }
|
inline uint32_t linkRegId() const noexcept { return _linkRegId; }
|
||||||
//! Returns instruction pointer register id, if the architecture provides it.
|
//! Returns instruction pointer register id, if the architecture provides it.
|
||||||
inline constexpr uint32_t ipRegId() const noexcept { return _ipRegId; }
|
inline uint32_t ipRegId() const noexcept { return _ipRegId; }
|
||||||
|
|
||||||
//! Returns a hardware stack alignment requirement.
|
//! Returns a hardware stack alignment requirement.
|
||||||
//!
|
//!
|
||||||
//! \note This is a hardware constraint. Architectures that don't constrain
|
//! \note This is a hardware constraint. Architectures that don't constrain it would return the lowest alignment
|
||||||
//! it would return the lowest alignment (1), however, some architectures may
|
//! (1), however, some architectures may constrain the alignment, for example AArch64 requires 16-byte alignment.
|
||||||
//! constrain the alignment, for example AArch64 requires 16-byte alignment.
|
inline uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; }
|
||||||
inline constexpr uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; }
|
|
||||||
|
|
||||||
//! Tests whether the architecture provides link register, which is used across
|
//! Tests whether the architecture provides link register, which is used across function calls. If the link
|
||||||
//! function calls. If the link register is not provided then a function call
|
//! register is not provided then a function call pushes the return address on stack (X86/X64).
|
||||||
//! pushes the return address on stack (X86/X64).
|
inline bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
|
||||||
inline constexpr bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
|
|
||||||
|
|
||||||
//! Returns minimum addressable offset on stack guaranteed for all instructions.
|
//! Returns minimum addressable offset on stack guaranteed for all instructions.
|
||||||
inline constexpr uint32_t minStackOffset() const noexcept { return _minStackOffset; }
|
inline uint32_t minStackOffset() const noexcept { return _minStackOffset; }
|
||||||
//! Returns maximum addressable offset on stack depending on specific instruction.
|
//! Returns maximum addressable offset on stack depending on specific instruction.
|
||||||
inline constexpr uint32_t maxStackOffset() const noexcept { return _maxStackOffset; }
|
inline uint32_t maxStackOffset() const noexcept { return _maxStackOffset; }
|
||||||
|
|
||||||
//! Returns ISA flags of the given register `group`.
|
//! Returns ISA flags of the given register `group`.
|
||||||
inline constexpr uint32_t isaFlags(uint32_t group) const noexcept { return _isaFlags[group]; }
|
inline InstHints instFeatureHints(RegGroup group) const noexcept { return _instHints[group]; }
|
||||||
//! Tests whether the given register `group` has the given `flag` set.
|
//! Tests whether the given register `group` has the given `flag` set.
|
||||||
inline constexpr bool hasIsaFlag(uint32_t group, uint32_t flag) const noexcept { return (_isaFlags[group] & flag) != 0; }
|
inline bool hasInstHint(RegGroup group, InstHints feature) const noexcept { return Support::test(_instHints[group], feature); }
|
||||||
//! Tests whether the ISA provides register swap instruction for the given register `group`.
|
//! Tests whether the ISA provides register swap instruction for the given register `group`.
|
||||||
inline constexpr bool hasSwap(uint32_t group) const noexcept { return hasIsaFlag(group, kIsaFeatureSwap); }
|
inline bool hasInstRegSwap(RegGroup group) const noexcept { return hasInstHint(group, InstHints::kRegSwap); }
|
||||||
//! Tests whether the ISA provides push/pop instructions for the given register `group`.
|
//! Tests whether the ISA provides push/pop instructions for the given register `group`.
|
||||||
inline constexpr bool hasPushPop(uint32_t group) const noexcept { return hasIsaFlag(group, kIsaFeaturePushPop); }
|
inline bool hasInstPushPop(RegGroup group) const noexcept { return hasInstHint(group, InstHints::kPushPop); }
|
||||||
|
|
||||||
inline uint32_t hasRegType(uint32_t rType) const noexcept {
|
inline bool hasRegType(RegType type) const noexcept {
|
||||||
return rType <= BaseReg::kTypeMax && _regInfo[rType].signature() != 0;
|
return type <= RegType::kMaxValue && _regSignature[type].isValid();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t regTypeToSignature(uint32_t rType) const noexcept {
|
//! Returns an operand signature from the given register `type` of this architecture.
|
||||||
ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
|
inline OperandSignature regTypeToSignature(RegType type) const noexcept { return _regSignature[type]; }
|
||||||
return _regInfo[rType].signature();
|
//! Returns a register from the given register `type` of this architecture.
|
||||||
}
|
inline RegGroup regTypeToGroup(RegType type) const noexcept { return _regSignature[type].regGroup(); }
|
||||||
|
//! Returns a register size the given register `type` of this architecture.
|
||||||
inline uint32_t regTypeToGroup(uint32_t rType) const noexcept {
|
inline uint32_t regTypeToSize(RegType type) const noexcept { return _regSignature[type].size(); }
|
||||||
ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
|
//! Returns a corresponding `TypeId` from the given register `type` of this architecture.
|
||||||
return _regInfo[rType].group();
|
inline TypeId regTypeToTypeId(RegType type) const noexcept { return _regTypeToTypeId[type]; }
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t regTypeToSize(uint32_t rType) const noexcept {
|
|
||||||
ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
|
|
||||||
return _regInfo[rType].size();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline uint32_t regTypeToTypeId(uint32_t rType) const noexcept {
|
|
||||||
ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
|
|
||||||
return _regTypeToTypeId[rType];
|
|
||||||
}
|
|
||||||
|
|
||||||
//! 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.
|
||||||
//!
|
//!
|
||||||
@@ -187,10 +254,10 @@ struct ArchTraits {
|
|||||||
//! - [1] 16-bits
|
//! - [1] 16-bits
|
||||||
//! - [2] 32-bits
|
//! - [2] 32-bits
|
||||||
//! - [3] 64-bits
|
//! - [3] 64-bits
|
||||||
inline const ISAWordNameId* isaWordNameIdTable() const noexcept { return _isaWordNameIdTable; }
|
inline const ArchTypeNameId* typeNameIdTable() const noexcept { return _typeNameIdTable; }
|
||||||
|
|
||||||
//! Returns an ISA word name identifier of the given `index`, see \ref isaWordNameIdTable() for more details.
|
//! Returns an ISA word name identifier of the given `index`, see \ref typeNameIdTable() for more details.
|
||||||
inline ISAWordNameId isaWordNameId(uint32_t index) const noexcept { return _isaWordNameIdTable[index]; }
|
inline ArchTypeNameId typeNameIdByIndex(uint32_t index) const noexcept { return _typeNameIdTable[index]; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -198,23 +265,21 @@ struct ArchTraits {
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns a const reference to `ArchTraits` for the given architecture `arch`.
|
//! Returns a const reference to `ArchTraits` for the given architecture `arch`.
|
||||||
static inline const ArchTraits& byArch(uint32_t arch) noexcept;
|
static inline const ArchTraits& byArch(Arch arch) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount];
|
ASMJIT_VARAPI const ArchTraits _archTraits[uint32_t(Arch::kMaxValue) + 1];
|
||||||
|
|
||||||
inline const ArchTraits& ArchTraits::byArch(uint32_t arch) noexcept { return _archTraits[arch & ~Environment::kArchBigEndianMask]; }
|
//! \cond
|
||||||
|
inline const ArchTraits& ArchTraits::byArch(Arch arch) noexcept { return _archTraits[uint32_t(arch)]; }
|
||||||
// ============================================================================
|
//! \endcond
|
||||||
// [asmjit::ArchUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Architecture utilities.
|
//! Architecture utilities.
|
||||||
namespace ArchUtils {
|
namespace ArchUtils {
|
||||||
|
|
||||||
ASMJIT_API Error typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfo) noexcept;
|
ASMJIT_API Error typeIdToRegSignature(Arch arch, TypeId typeId, TypeId* typeIdOut, OperandSignature* regSignatureOut) noexcept;
|
||||||
|
|
||||||
} // {ArchUtils}
|
} // {ArchUtils}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/assembler.h"
|
#include "../core/assembler.h"
|
||||||
@@ -32,18 +14,16 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Construction & Destruction
|
||||||
// [asmjit::BaseAssembler - Construction / Destruction]
|
// ==========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
BaseAssembler::BaseAssembler() noexcept
|
BaseAssembler::BaseAssembler() noexcept
|
||||||
: BaseEmitter(kTypeAssembler) {}
|
: BaseEmitter(EmitterType::kAssembler) {}
|
||||||
|
|
||||||
BaseAssembler::~BaseAssembler() noexcept {}
|
BaseAssembler::~BaseAssembler() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Buffer Management
|
||||||
// [asmjit::BaseAssembler - Buffer Management]
|
// =================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseAssembler::setOffset(size_t offset) {
|
Error BaseAssembler::setOffset(size_t offset) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
@@ -57,9 +37,8 @@ Error BaseAssembler::setOffset(size_t offset) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Section Management
|
||||||
// [asmjit::BaseAssembler - Section Management]
|
// ==================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
|
static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
|
||||||
uint8_t* p = section->_buffer._data;
|
uint8_t* p = section->_buffer._data;
|
||||||
@@ -86,9 +65,8 @@ Error BaseAssembler::section(Section* section) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Label Management
|
||||||
// [asmjit::BaseAssembler - Label Management]
|
// ================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Label BaseAssembler::newLabel() {
|
Label BaseAssembler::newLabel() {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
uint32_t labelId = Globals::kInvalidId;
|
||||||
@@ -103,7 +81,7 @@ Label BaseAssembler::newLabel() {
|
|||||||
return Label(labelId);
|
return Label(labelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) {
|
Label BaseAssembler::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
uint32_t labelId = Globals::kInvalidId;
|
||||||
if (ASMJIT_LIKELY(_code)) {
|
if (ASMJIT_LIKELY(_code)) {
|
||||||
LabelEntry* le;
|
LabelEntry* le;
|
||||||
@@ -134,9 +112,8 @@ Error BaseAssembler::bind(const Label& label) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Embed
|
||||||
// [asmjit::BaseAssembler - Embed]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
@@ -154,7 +131,7 @@ Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
|||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (_logger) {
|
if (_logger) {
|
||||||
StringTmp<512> sb;
|
StringTmp<512> sb;
|
||||||
Formatter::formatData(sb, _logger->flags(), arch(), Type::kIdU8, data, dataSize, 1);
|
Formatter::formatData(sb, _logger->flags(), arch(), TypeId::kUInt8, data, dataSize, 1);
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
_logger->log(sb);
|
_logger->log(sb);
|
||||||
}
|
}
|
||||||
@@ -163,17 +140,17 @@ Error BaseAssembler::embed(const void* data, size_t dataSize) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) {
|
Error BaseAssembler::embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) {
|
||||||
uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
|
uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize());
|
||||||
uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
|
TypeId finalTypeId = TypeUtils::deabstract(typeId, deabstractDelta);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
|
if (ASMJIT_UNLIKELY(!TypeUtils::isValid(finalTypeId)))
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
|
|
||||||
if (itemCount == 0 || repeatCount == 0)
|
if (itemCount == 0 || repeatCount == 0)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
uint32_t typeSize = Type::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 dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of);
|
||||||
@@ -203,16 +180,16 @@ Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t it
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
static const uint8_t dataTypeIdBySize[9] = {
|
static const TypeId dataTypeIdBySize[9] = {
|
||||||
Type::kIdVoid, // [0] (invalid)
|
TypeId::kVoid, // [0] (invalid)
|
||||||
Type::kIdU8, // [1] (uint8_t)
|
TypeId::kUInt8, // [1] (uint8_t)
|
||||||
Type::kIdU16, // [2] (uint16_t)
|
TypeId::kUInt16, // [2] (uint16_t)
|
||||||
Type::kIdVoid, // [3] (invalid)
|
TypeId::kVoid, // [3] (invalid)
|
||||||
Type::kIdU32, // [4] (uint32_t)
|
TypeId::kUInt32, // [4] (uint32_t)
|
||||||
Type::kIdVoid, // [5] (invalid)
|
TypeId::kVoid, // [5] (invalid)
|
||||||
Type::kIdVoid, // [6] (invalid)
|
TypeId::kVoid, // [6] (invalid)
|
||||||
Type::kIdVoid, // [7] (invalid)
|
TypeId::kVoid, // [7] (invalid)
|
||||||
Type::kIdU64 // [8] (uint64_t)
|
TypeId::kUInt64 // [8] (uint64_t)
|
||||||
};
|
};
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -223,7 +200,7 @@ Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
|
|||||||
if (ASMJIT_UNLIKELY(!isLabelValid(label)))
|
if (ASMJIT_UNLIKELY(!isLabelValid(label)))
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment())));
|
ASMJIT_PROPAGATE(align(AlignMode::kData, uint32_t(pool.alignment())));
|
||||||
ASMJIT_PROPAGATE(bind(label));
|
ASMJIT_PROPAGATE(bind(label));
|
||||||
|
|
||||||
size_t size = pool.size();
|
size_t size = pool.size();
|
||||||
@@ -282,13 +259,13 @@ Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
|
|||||||
sb.append('.');
|
sb.append('.');
|
||||||
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
Formatter::formatLabel(sb, 0, this, label.id());
|
Formatter::formatLabel(sb, FormatFlags::kNone, this, label.id());
|
||||||
sb.append('\n');
|
sb.append('\n');
|
||||||
_logger->log(sb);
|
_logger->log(sb);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs);
|
Error err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
@@ -343,9 +320,9 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
sb.append('.');
|
sb.append('.');
|
||||||
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
|
||||||
sb.append(" (");
|
sb.append(" (");
|
||||||
Formatter::formatLabel(sb, 0, this, label.id());
|
Formatter::formatLabel(sb, FormatFlags::kNone, this, label.id());
|
||||||
sb.append(" - ");
|
sb.append(" - ");
|
||||||
Formatter::formatLabel(sb, 0, this, base.id());
|
Formatter::formatLabel(sb, FormatFlags::kNone, this, base.id());
|
||||||
sb.append(")\n");
|
sb.append(")\n");
|
||||||
_logger->log(sb);
|
_logger->log(sb);
|
||||||
}
|
}
|
||||||
@@ -358,7 +335,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
RelocEntry* re;
|
RelocEntry* re;
|
||||||
Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression);
|
Error err = _code->newRelocEntry(&re, RelocType::kExpression);
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
@@ -367,7 +344,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
|
|
||||||
exp->reset();
|
exp->reset();
|
||||||
exp->opType = Expression::kOpSub;
|
exp->opType = ExpressionOpType::kSub;
|
||||||
exp->setValueAsLabel(0, labelEntry);
|
exp->setValueAsLabel(0, labelEntry);
|
||||||
exp->setValueAsLabel(1, baseEntry);
|
exp->setValueAsLabel(1, baseEntry);
|
||||||
|
|
||||||
@@ -383,19 +360,18 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Comment
|
||||||
// [asmjit::BaseAssembler - Comment]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseAssembler::comment(const char* data, size_t size) {
|
Error BaseAssembler::comment(const char* data, size_t size) {
|
||||||
if (!hasEmitterFlag(kFlagLogComments)) {
|
if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
|
||||||
if (!hasEmitterFlag(kFlagAttached))
|
if (!hasEmitterFlag(EmitterFlags::kAttached))
|
||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
// Logger cannot be NULL if `kFlagLogComments` is set.
|
// Logger cannot be NULL if `EmitterFlags::kLogComments` is set.
|
||||||
ASMJIT_ASSERT(_logger != nullptr);
|
ASMJIT_ASSERT(_logger != nullptr);
|
||||||
|
|
||||||
_logger->log(data, size);
|
_logger->log(data, size);
|
||||||
@@ -407,9 +383,8 @@ Error BaseAssembler::comment(const char* data, size_t size) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseAssembler - Events
|
||||||
// [asmjit::BaseAssembler - Events]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseAssembler::onAttach(CodeHolder* code) noexcept {
|
Error BaseAssembler::onAttach(CodeHolder* code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|||||||
@@ -1,31 +1,12 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
#define ASMJIT_CORE_ASSEMBLER_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/codeholder.h"
|
#include "../core/codeholder.h"
|
||||||
#include "../core/datatypes.h"
|
|
||||||
#include "../core/emitter.h"
|
#include "../core/emitter.h"
|
||||||
#include "../core/operand.h"
|
#include "../core/operand.h"
|
||||||
|
|
||||||
@@ -34,10 +15,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_assembler
|
//! \addtogroup asmjit_assembler
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::BaseAssembler]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Base assembler.
|
//! Base assembler.
|
||||||
//!
|
//!
|
||||||
//! This is a base class that provides interface used by architecture specific
|
//! This is a base class that provides interface used by architecture specific
|
||||||
@@ -112,7 +89,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Label newLabel() override;
|
ASMJIT_API Label newLabel() override;
|
||||||
ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override;
|
ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) override;
|
||||||
ASMJIT_API Error bind(const Label& label) override;
|
ASMJIT_API Error bind(const Label& label) override;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -121,7 +98,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
|
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
|
||||||
ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) override;
|
ASMJIT_API Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) override;
|
||||||
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
|
||||||
|
|
||||||
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
|
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_BUILDER
|
#ifndef ASMJIT_NO_BUILDER
|
||||||
@@ -33,9 +15,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// PostponedErrorHandler (Internal)
|
||||||
// [asmjit::PostponedErrorHandler (Internal)]
|
// ================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Postponed error handler that never throws. Used as a temporal error handler
|
//! Postponed error handler that never throws. Used as a temporal error handler
|
||||||
//! to run passes. If error occurs, the caller is notified and will call the
|
//! to run passes. If error occurs, the caller is notified and will call the
|
||||||
@@ -50,9 +31,8 @@ public:
|
|||||||
StringTmp<128> _message;
|
StringTmp<128> _message;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Utilities
|
||||||
// [asmjit::BaseBuilder - Utilities]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
|
static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
|
||||||
for (Pass* pass : self->_passes)
|
for (Pass* pass : self->_passes)
|
||||||
@@ -60,12 +40,11 @@ static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
|
|||||||
self->_passes.reset();
|
self->_passes.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Construction & Destruction
|
||||||
// [asmjit::BaseBuilder - Construction / Destruction]
|
// ========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
BaseBuilder::BaseBuilder() noexcept
|
BaseBuilder::BaseBuilder() noexcept
|
||||||
: BaseEmitter(kTypeBuilder),
|
: BaseEmitter(EmitterType::kBuilder),
|
||||||
_codeZone(32768 - Zone::kBlockOverhead),
|
_codeZone(32768 - Zone::kBlockOverhead),
|
||||||
_dataZone(16384 - Zone::kBlockOverhead),
|
_dataZone(16384 - Zone::kBlockOverhead),
|
||||||
_passZone(65536 - Zone::kBlockOverhead),
|
_passZone(65536 - Zone::kBlockOverhead),
|
||||||
@@ -75,11 +54,10 @@ BaseBuilder::~BaseBuilder() noexcept {
|
|||||||
BaseBuilder_deletePasses(this);
|
BaseBuilder_deletePasses(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Node Management
|
||||||
// [asmjit::BaseBuilder - Node Management]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::_newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount) {
|
Error BaseBuilder::newInstNode(InstNode** out, InstId instId, InstOptions instOptions, uint32_t opCount) {
|
||||||
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
||||||
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
ASMJIT_ASSERT(opCapacity >= InstNode::kBaseOpCapacity);
|
||||||
|
|
||||||
@@ -92,28 +70,28 @@ Error BaseBuilder::_newInstNode(InstNode** out, uint32_t instId, uint32_t instOp
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error BaseBuilder::_newLabelNode(LabelNode** out) {
|
Error BaseBuilder::newLabelNode(LabelNode** out) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<LabelNode>(out));
|
ASMJIT_PROPAGATE(_newNodeT<LabelNode>(out));
|
||||||
return registerLabelNode(*out);
|
return registerLabelNode(*out);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::_newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment) {
|
Error BaseBuilder::newAlignNode(AlignNode** out, AlignMode alignMode, uint32_t alignment) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
return _newNodeT<AlignNode>(out, alignMode, alignment);
|
return _newNodeT<AlignNode>(out, alignMode, alignment);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) {
|
Error BaseBuilder::newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
|
uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize());
|
||||||
uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
|
TypeId finalTypeId = TypeUtils::deabstract(typeId, deabstractDelta);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
|
if (ASMJIT_UNLIKELY(!TypeUtils::isValid(finalTypeId)))
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
|
|
||||||
uint32_t typeSize = Type::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 dataSize = Support::mulOverflow(itemCount, size_t(typeSize), &of);
|
||||||
@@ -123,7 +101,7 @@ Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const
|
|||||||
EmbedDataNode* node;
|
EmbedDataNode* node;
|
||||||
ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node));
|
ASMJIT_PROPAGATE(_newNodeT<EmbedDataNode>(&node));
|
||||||
|
|
||||||
node->_embed._typeId = uint8_t(typeId);
|
node->_embed._typeId = typeId;
|
||||||
node->_embed._typeSize = uint8_t(typeSize);
|
node->_embed._typeSize = uint8_t(typeSize);
|
||||||
node->_itemCount = itemCount;
|
node->_itemCount = itemCount;
|
||||||
node->_repeatCount = repeatCount;
|
node->_repeatCount = repeatCount;
|
||||||
@@ -143,14 +121,14 @@ Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::_newConstPoolNode(ConstPoolNode** out) {
|
Error BaseBuilder::newConstPoolNode(ConstPoolNode** out) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out));
|
ASMJIT_PROPAGATE(_newNodeT<ConstPoolNode>(out));
|
||||||
return registerLabelNode(*out);
|
return registerLabelNode(*out);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::_newCommentNode(CommentNode** out, const char* data, size_t size) {
|
Error BaseBuilder::newCommentNode(CommentNode** out, const char* data, size_t size) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
@@ -198,7 +176,7 @@ BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept {
|
|||||||
_lastNode = node;
|
_lastNode = node;
|
||||||
}
|
}
|
||||||
|
|
||||||
node->addFlags(BaseNode::kFlagIsActive);
|
node->addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection())
|
if (node->isSection())
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
|
|
||||||
@@ -219,7 +197,7 @@ BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept {
|
|||||||
node->_prev = prev;
|
node->_prev = prev;
|
||||||
node->_next = next;
|
node->_next = next;
|
||||||
|
|
||||||
node->addFlags(BaseNode::kFlagIsActive);
|
node->addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection())
|
if (node->isSection())
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
|
|
||||||
@@ -246,7 +224,7 @@ BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept {
|
|||||||
node->_prev = prev;
|
node->_prev = prev;
|
||||||
node->_next = next;
|
node->_next = next;
|
||||||
|
|
||||||
node->addFlags(BaseNode::kFlagIsActive);
|
node->addFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection())
|
if (node->isSection())
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
|
|
||||||
@@ -278,7 +256,7 @@ BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept {
|
|||||||
|
|
||||||
node->_prev = nullptr;
|
node->_prev = nullptr;
|
||||||
node->_next = nullptr;
|
node->_next = nullptr;
|
||||||
node->clearFlags(BaseNode::kFlagIsActive);
|
node->clearFlags(NodeFlags::kIsActive);
|
||||||
if (node->isSection())
|
if (node->isSection())
|
||||||
_dirtySectionLinks = true;
|
_dirtySectionLinks = true;
|
||||||
|
|
||||||
@@ -319,7 +297,7 @@ void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept {
|
|||||||
|
|
||||||
node->_prev = nullptr;
|
node->_prev = nullptr;
|
||||||
node->_next = nullptr;
|
node->_next = nullptr;
|
||||||
node->clearFlags(BaseNode::kFlagIsActive);
|
node->clearFlags(NodeFlags::kIsActive);
|
||||||
didRemoveSection |= uint32_t(node->isSection());
|
didRemoveSection |= uint32_t(node->isSection());
|
||||||
|
|
||||||
if (_cursor == node)
|
if (_cursor == node)
|
||||||
@@ -340,9 +318,8 @@ BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept {
|
|||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Sections
|
||||||
// [asmjit::BaseBuilder - Section]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) {
|
Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
@@ -424,9 +401,8 @@ void BaseBuilder::updateSectionLinks() noexcept {
|
|||||||
_dirtySectionLinks = false;
|
_dirtySectionLinks = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Labels
|
||||||
// [asmjit::BaseBuilder - Labels]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) {
|
Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) {
|
||||||
*out = nullptr;
|
*out = nullptr;
|
||||||
@@ -500,7 +476,7 @@ Label BaseBuilder::newLabel() {
|
|||||||
return Label(labelId);
|
return Label(labelId);
|
||||||
}
|
}
|
||||||
|
|
||||||
Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, uint32_t type, uint32_t parentId) {
|
Label BaseBuilder::newNamedLabel(const char* name, size_t nameSize, LabelType type, uint32_t parentId) {
|
||||||
uint32_t labelId = Globals::kInvalidId;
|
uint32_t labelId = Globals::kInvalidId;
|
||||||
LabelEntry* le;
|
LabelEntry* le;
|
||||||
|
|
||||||
@@ -521,9 +497,8 @@ Error BaseBuilder::bind(const Label& label) {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Passes
|
||||||
// [asmjit::BaseBuilder - Passes]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept {
|
ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept {
|
||||||
for (Pass* pass : _passes)
|
for (Pass* pass : _passes)
|
||||||
@@ -603,21 +578,20 @@ Error BaseBuilder::runPasses() {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Emit
|
||||||
// [asmjit::BaseBuilder - Emit]
|
// ==================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
|
Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
|
||||||
uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt);
|
uint32_t opCount = EmitterUtils::opCountFromEmitArgs(o0, o1, o2, opExt);
|
||||||
uint32_t options = instOptions() | forcedInstOptions();
|
InstOptions options = instOptions() | forcedInstOptions();
|
||||||
|
|
||||||
if (options & BaseInst::kOptionReserved) {
|
if (Support::test(options, InstOptions::kReserved)) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_VALIDATION
|
#ifndef ASMJIT_NO_VALIDATION
|
||||||
// Strict validation.
|
// Strict validation.
|
||||||
if (hasValidationOption(kValidationOptionIntermediate)) {
|
if (hasDiagnosticOption(DiagnosticOptions::kValidateIntermediate)) {
|
||||||
Operand_ opArray[Globals::kMaxOpCount];
|
Operand_ opArray[Globals::kMaxOpCount];
|
||||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||||
|
|
||||||
@@ -631,8 +605,8 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Clear options that should never be part of `InstNode`.
|
// Clear instruction options that should never be part of a regular instruction.
|
||||||
options &= ~BaseInst::kOptionReserved;
|
options &= ~InstOptions::kReserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
|
||||||
@@ -666,42 +640,40 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Align
|
||||||
// [asmjit::BaseBuilder - Align]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) {
|
Error BaseBuilder::align(AlignMode alignMode, uint32_t alignment) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
AlignNode* node;
|
AlignNode* node;
|
||||||
ASMJIT_PROPAGATE(_newAlignNode(&node, alignMode, alignment));
|
ASMJIT_PROPAGATE(newAlignNode(&node, alignMode, alignment));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Embed
|
||||||
// [asmjit::BaseBuilder - Embed]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::embed(const void* data, size_t dataSize) {
|
Error BaseBuilder::embed(const void* data, size_t dataSize) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
EmbedDataNode* node;
|
EmbedDataNode* node;
|
||||||
ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, data, dataSize));
|
ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, data, dataSize));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseBuilder::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t itemRepeat) {
|
Error BaseBuilder::embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t itemRepeat) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
EmbedDataNode* node;
|
EmbedDataNode* node;
|
||||||
ASMJIT_PROPAGATE(_newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat));
|
ASMJIT_PROPAGATE(newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -714,23 +686,22 @@ Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
|
|||||||
if (!isLabelValid(label))
|
if (!isLabelValid(label))
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
return reportError(DebugUtils::errored(kErrorInvalidLabel));
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(align(kAlignData, uint32_t(pool.alignment())));
|
ASMJIT_PROPAGATE(align(AlignMode::kData, uint32_t(pool.alignment())));
|
||||||
ASMJIT_PROPAGATE(bind(label));
|
ASMJIT_PROPAGATE(bind(label));
|
||||||
|
|
||||||
EmbedDataNode* node;
|
EmbedDataNode* node;
|
||||||
ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, nullptr, pool.size()));
|
ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, nullptr, pool.size()));
|
||||||
|
|
||||||
pool.fill(node->data());
|
pool.fill(node->data());
|
||||||
addNode(node);
|
addNode(node);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmbedLabel / EmbedLabelDelta
|
// BaseBuilder - EmbedLabel & EmbedLabelDelta
|
||||||
// ----------------------------
|
// ==========================================
|
||||||
//
|
//
|
||||||
// If dataSize is zero it means that the size is the same as target register
|
// If dataSize is zero it means that the size is the same as target register width, however,
|
||||||
// width, however, if it's provided we really want to validate whether it's
|
// if it's provided we really want to validate whether it's within the possible range.
|
||||||
// within the possible range.
|
|
||||||
|
|
||||||
static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept {
|
static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept {
|
||||||
return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8);
|
return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8);
|
||||||
@@ -764,24 +735,22 @@ Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Comment
|
||||||
// [asmjit::BaseBuilder - Comment]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::comment(const char* data, size_t size) {
|
Error BaseBuilder::comment(const char* data, size_t size) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
CommentNode* node;
|
CommentNode* node;
|
||||||
ASMJIT_PROPAGATE(_newCommentNode(&node, data, size));
|
ASMJIT_PROPAGATE(newCommentNode(&node, data, size));
|
||||||
|
|
||||||
addNode(node);
|
addNode(node);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - SerializeTo
|
||||||
// [asmjit::BaseBuilder - Serialize]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
||||||
Error err = kErrorOk;
|
Error err = kErrorOk;
|
||||||
@@ -796,7 +765,7 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
|||||||
InstNode* node = node_->as<InstNode>();
|
InstNode* node = node_->as<InstNode>();
|
||||||
|
|
||||||
// NOTE: Inlined to remove one additional call per instruction.
|
// NOTE: Inlined to remove one additional call per instruction.
|
||||||
dst->setInstOptions(node->instOptions());
|
dst->setInstOptions(node->options());
|
||||||
dst->setExtraReg(node->extraReg());
|
dst->setExtraReg(node->extraReg());
|
||||||
|
|
||||||
const Operand_* op = node->operands();
|
const Operand_* op = node->operands();
|
||||||
@@ -862,9 +831,8 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseBuilder - Events
|
||||||
// [asmjit::BaseBuilder - Events]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
|
Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
@@ -883,7 +851,7 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
|
|||||||
_cursor = initialSection;
|
_cursor = initialSection;
|
||||||
_firstNode = initialSection;
|
_firstNode = initialSection;
|
||||||
_lastNode = initialSection;
|
_lastNode = initialSection;
|
||||||
initialSection->setFlags(BaseNode::kFlagIsActive);
|
initialSection->setFlags(NodeFlags::kIsActive);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
@@ -898,8 +866,7 @@ Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
|
|||||||
_dataZone.reset();
|
_dataZone.reset();
|
||||||
_passZone.reset();
|
_passZone.reset();
|
||||||
|
|
||||||
_nodeFlags = 0;
|
_nodeFlags = NodeFlags::kNone;
|
||||||
|
|
||||||
_cursor = nullptr;
|
_cursor = nullptr;
|
||||||
_firstNode = nullptr;
|
_firstNode = nullptr;
|
||||||
_lastNode = nullptr;
|
_lastNode = nullptr;
|
||||||
@@ -907,9 +874,8 @@ Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
|
|||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// Pass - Construction & Destruction
|
||||||
// [asmjit::Pass - Construction / Destruction]
|
// =================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Pass::Pass(const char* name) noexcept
|
Pass::Pass(const char* name) noexcept
|
||||||
: _name(name) {}
|
: _name(name) {}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,42 +1,35 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
|
#include "../core/support.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Flags used by \ref CodeBuffer.
|
||||||
// [asmjit::CodeBuffer]
|
enum class CodeBufferFlags : uint32_t {
|
||||||
// ============================================================================
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
//! Buffer is external (not allocated by asmjit).
|
||||||
|
kIsExternal = 0x00000001u,
|
||||||
|
//! Buffer is fixed (cannot be reallocated).
|
||||||
|
kIsFixed = 0x00000002u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(CodeBufferFlags)
|
||||||
|
|
||||||
//! Code or data buffer.
|
//! Code or data buffer.
|
||||||
struct CodeBuffer {
|
struct CodeBuffer {
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! The content of the buffer (data).
|
//! The content of the buffer (data).
|
||||||
uint8_t* _data;
|
uint8_t* _data;
|
||||||
//! Number of bytes of `data` used.
|
//! Number of bytes of `data` used.
|
||||||
@@ -44,15 +37,9 @@ struct CodeBuffer {
|
|||||||
//! Buffer capacity (in bytes).
|
//! Buffer capacity (in bytes).
|
||||||
size_t _capacity;
|
size_t _capacity;
|
||||||
//! Buffer flags.
|
//! Buffer flags.
|
||||||
uint32_t _flags;
|
CodeBufferFlags _flags;
|
||||||
|
|
||||||
//! Code buffer flags.
|
//! \}
|
||||||
enum Flags : uint32_t {
|
|
||||||
//! Buffer is external (not allocated by asmjit).
|
|
||||||
kFlagIsExternal = 0x00000001u,
|
|
||||||
//! Buffer is fixed (cannot be reallocated).
|
|
||||||
kFlagIsFixed = 0x00000002u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Overloaded Operators
|
//! \name Overloaded Operators
|
||||||
//! \{
|
//! \{
|
||||||
@@ -73,20 +60,20 @@ struct CodeBuffer {
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns code buffer flags, see \ref Flags.
|
//! Returns code buffer flags.
|
||||||
inline uint32_t flags() const noexcept { return _flags; }
|
inline CodeBufferFlags flags() const noexcept { return _flags; }
|
||||||
//! Tests whether the code buffer has the given `flag` set.
|
//! Tests whether the code buffer has the given `flag` set.
|
||||||
inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
|
inline bool hasFlag(CodeBufferFlags flag) const noexcept { return Support::test(_flags, flag); }
|
||||||
|
|
||||||
//! Tests whether this code buffer has a fixed size.
|
//! Tests whether this code buffer has a fixed size.
|
||||||
//!
|
//!
|
||||||
//! Fixed size means that the code buffer is fixed and cannot grow.
|
//! Fixed size means that the code buffer is fixed and cannot grow.
|
||||||
inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); }
|
inline bool isFixed() const noexcept { return hasFlag(CodeBufferFlags::kIsFixed); }
|
||||||
|
|
||||||
//! Tests whether the data in this code buffer is external.
|
//! Tests whether the data in this code buffer is external.
|
||||||
//!
|
//!
|
||||||
//! External data can only be provided by users, it's never used by AsmJit.
|
//! External data can only be provided by users, it's never used by AsmJit.
|
||||||
inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); }
|
inline bool isExternal() const noexcept { return hasFlag(CodeBufferFlags::kIsExternal); }
|
||||||
|
|
||||||
//! Tests whether the data in this code buffer is allocated (non-null).
|
//! Tests whether the data in this code buffer is allocated (non-null).
|
||||||
inline bool isAllocated() const noexcept { return _data != nullptr; }
|
inline bool isAllocated() const noexcept { return _data != nullptr; }
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/assembler.h"
|
#include "../core/assembler.h"
|
||||||
@@ -32,9 +14,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// Globals
|
||||||
// [Globals]
|
// =======
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const char CodeHolder_addrTabName[] = ".addrtab";
|
static const char CodeHolder_addrTabName[] = ".addrtab";
|
||||||
|
|
||||||
@@ -43,31 +24,30 @@ static inline uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcep
|
|||||||
return (m << 6) | (o << 3) | rm;
|
return (m << 6) | (o << 3) | rm;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// LabelLinkIterator
|
||||||
// [asmjit::LabelLinkIterator]
|
// =================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class LabelLinkIterator {
|
class LabelLinkIterator {
|
||||||
public:
|
public:
|
||||||
ASMJIT_INLINE LabelLinkIterator(LabelEntry* le) noexcept { reset(le); }
|
inline LabelLinkIterator(LabelEntry* le) noexcept { reset(le); }
|
||||||
|
|
||||||
ASMJIT_INLINE explicit operator bool() const noexcept { return isValid(); }
|
inline explicit operator bool() const noexcept { return isValid(); }
|
||||||
ASMJIT_INLINE bool isValid() const noexcept { return _link != nullptr; }
|
inline bool isValid() const noexcept { return _link != nullptr; }
|
||||||
|
|
||||||
ASMJIT_INLINE LabelLink* link() const noexcept { return _link; }
|
inline LabelLink* link() const noexcept { return _link; }
|
||||||
ASMJIT_INLINE LabelLink* operator->() const noexcept { return _link; }
|
inline LabelLink* operator->() const noexcept { return _link; }
|
||||||
|
|
||||||
ASMJIT_INLINE void reset(LabelEntry* le) noexcept {
|
inline void reset(LabelEntry* le) noexcept {
|
||||||
_pPrev = &le->_links;
|
_pPrev = &le->_links;
|
||||||
_link = *_pPrev;
|
_link = *_pPrev;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void next() noexcept {
|
inline void next() noexcept {
|
||||||
_pPrev = &_link->next;
|
_pPrev = &_link->next;
|
||||||
_link = *_pPrev;
|
_link = *_pPrev;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void resolveAndNext(CodeHolder* code) noexcept {
|
inline void resolveAndNext(CodeHolder* code) noexcept {
|
||||||
LabelLink* linkToDelete = _link;
|
LabelLink* linkToDelete = _link;
|
||||||
|
|
||||||
_link = _link->next;
|
_link = _link->next;
|
||||||
@@ -81,11 +61,10 @@ public:
|
|||||||
LabelLink* _link;
|
LabelLink* _link;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Utilities
|
||||||
// [asmjit::CodeHolder - Utilities]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noexcept {
|
static void CodeHolder_resetInternal(CodeHolder* self, ResetPolicy resetPolicy) noexcept {
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
const ZoneVector<BaseEmitter*>& emitters = self->emitters();
|
const ZoneVector<BaseEmitter*>& emitters = self->emitters();
|
||||||
|
|
||||||
@@ -134,27 +113,25 @@ static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Construction & Destruction
|
||||||
// [asmjit::CodeHolder - Construction / Destruction]
|
// =======================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
CodeHolder::CodeHolder() noexcept
|
CodeHolder::CodeHolder(const Support::Temporary* temporary) noexcept
|
||||||
: _environment(),
|
: _environment(),
|
||||||
_baseAddress(Globals::kNoBaseAddress),
|
_baseAddress(Globals::kNoBaseAddress),
|
||||||
_logger(nullptr),
|
_logger(nullptr),
|
||||||
_errorHandler(nullptr),
|
_errorHandler(nullptr),
|
||||||
_zone(16384 - Zone::kBlockOverhead),
|
_zone(16384 - Zone::kBlockOverhead, 1, temporary),
|
||||||
_allocator(&_zone),
|
_allocator(&_zone),
|
||||||
_unresolvedLinkCount(0),
|
_unresolvedLinkCount(0),
|
||||||
_addressTableSection(nullptr) {}
|
_addressTableSection(nullptr) {}
|
||||||
|
|
||||||
CodeHolder::~CodeHolder() noexcept {
|
CodeHolder::~CodeHolder() noexcept {
|
||||||
CodeHolder_resetInternal(this, Globals::kResetHard);
|
CodeHolder_resetInternal(this, ResetPolicy::kHard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Init & Reset
|
||||||
// [asmjit::CodeHolder - Init / Reset]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
inline void CodeHolder_setSectionDefaultName(
|
inline void CodeHolder_setSectionDefaultName(
|
||||||
Section* section,
|
Section* section,
|
||||||
@@ -179,7 +156,7 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe
|
|||||||
if (err == kErrorOk) {
|
if (err == kErrorOk) {
|
||||||
Section* section = _allocator.allocZeroedT<Section>();
|
Section* section = _allocator.allocZeroedT<Section>();
|
||||||
if (ASMJIT_LIKELY(section)) {
|
if (ASMJIT_LIKELY(section)) {
|
||||||
section->_flags = Section::kFlagExec | Section::kFlagConst;
|
section->_flags = SectionFlags::kExecutable | SectionFlags::kReadOnly;
|
||||||
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
|
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
|
||||||
_sections.appendUnsafe(section);
|
_sections.appendUnsafe(section);
|
||||||
_sectionsByOrder.appendUnsafe(section);
|
_sectionsByOrder.appendUnsafe(section);
|
||||||
@@ -200,13 +177,12 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CodeHolder::reset(uint32_t resetPolicy) noexcept {
|
void CodeHolder::reset(ResetPolicy resetPolicy) noexcept {
|
||||||
CodeHolder_resetInternal(this, resetPolicy);
|
CodeHolder_resetInternal(this, resetPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Attach / Detach
|
||||||
// [asmjit::CodeHolder - Attach / Detach]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
|
Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
|
||||||
// Catch a possible misuse of the API.
|
// Catch a possible misuse of the API.
|
||||||
@@ -214,8 +190,8 @@ Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
|
|||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
// Invalid emitter, this should not be possible.
|
// Invalid emitter, this should not be possible.
|
||||||
uint32_t type = emitter->emitterType();
|
EmitterType type = emitter->emitterType();
|
||||||
if (ASMJIT_UNLIKELY(type == BaseEmitter::kTypeNone || type >= BaseEmitter::kTypeCount))
|
if (ASMJIT_UNLIKELY(type == EmitterType::kNone || uint32_t(type) > uint32_t(EmitterType::kMaxValue)))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
// This is suspicious, but don't fail if `emitter` is already attached
|
// This is suspicious, but don't fail if `emitter` is already attached
|
||||||
@@ -261,9 +237,8 @@ Error CodeHolder::detach(BaseEmitter* emitter) noexcept {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Logging
|
||||||
// [asmjit::CodeHolder - Logging]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void CodeHolder::setLogger(Logger* logger) noexcept {
|
void CodeHolder::setLogger(Logger* logger) noexcept {
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
@@ -274,18 +249,16 @@ void CodeHolder::setLogger(Logger* logger) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Error Handling
|
||||||
// [asmjit::CodeHolder - Error Handling]
|
// ===========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept {
|
void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept {
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
CodeHolder_onSettingsUpdated(this);
|
CodeHolder_onSettingsUpdated(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Code Buffer
|
||||||
// [asmjit::CodeHolder - Code Buffer]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
|
static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
|
||||||
uint8_t* oldData = cb->_data;
|
uint8_t* oldData = cb->_data;
|
||||||
@@ -368,11 +341,10 @@ Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
|
|||||||
return CodeHolder_reserveInternal(this, cb, n);
|
return CodeHolder_reserveInternal(this, cb, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Sections
|
||||||
// [asmjit::CodeHolder - Sections]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, uint32_t flags, uint32_t alignment, int32_t order) noexcept {
|
Error CodeHolder::newSection(Section** sectionOut, const char* name, size_t nameSize, SectionFlags flags, uint32_t alignment, int32_t order) noexcept {
|
||||||
*sectionOut = nullptr;
|
*sectionOut = nullptr;
|
||||||
|
|
||||||
if (nameSize == SIZE_MAX)
|
if (nameSize == SIZE_MAX)
|
||||||
@@ -435,7 +407,12 @@ Section* CodeHolder::ensureAddressTableSection() noexcept {
|
|||||||
if (_addressTableSection)
|
if (_addressTableSection)
|
||||||
return _addressTableSection;
|
return _addressTableSection;
|
||||||
|
|
||||||
newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize(), std::numeric_limits<int32_t>::max());
|
newSection(&_addressTableSection,
|
||||||
|
CodeHolder_addrTabName,
|
||||||
|
sizeof(CodeHolder_addrTabName) - 1,
|
||||||
|
SectionFlags::kNone,
|
||||||
|
_environment.registerSize(),
|
||||||
|
std::numeric_limits<int32_t>::max());
|
||||||
return _addressTableSection;
|
return _addressTableSection;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -458,9 +435,8 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Labels & Symbols
|
||||||
// [asmjit::CodeHolder - Labels / Symbols]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Only used to lookup a label from `_namedLabels`.
|
//! Only used to lookup a label from `_namedLabels`.
|
||||||
class LabelByName {
|
class LabelByName {
|
||||||
@@ -547,32 +523,66 @@ Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId) noexcept {
|
Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, LabelType type, uint32_t parentId) noexcept {
|
||||||
*entryOut = nullptr;
|
*entryOut = nullptr;
|
||||||
uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize);
|
uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(nameSize == 0))
|
if (ASMJIT_UNLIKELY(nameSize == 0)) {
|
||||||
return DebugUtils::errored(kErrorInvalidLabelName);
|
if (type == LabelType::kAnonymous)
|
||||||
|
return newLabelEntry(entryOut);
|
||||||
|
else
|
||||||
|
return DebugUtils::errored(kErrorInvalidLabelName);
|
||||||
|
}
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxLabelNameSize))
|
if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxLabelNameSize))
|
||||||
return DebugUtils::errored(kErrorLabelNameTooLong);
|
return DebugUtils::errored(kErrorLabelNameTooLong);
|
||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Label::kTypeLocal:
|
case LabelType::kAnonymous: {
|
||||||
|
// Anonymous labels cannot have a parent (or more specifically, parent is useless here).
|
||||||
|
if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
|
||||||
|
return DebugUtils::errored(kErrorInvalidParentLabel);
|
||||||
|
|
||||||
|
uint32_t labelId = _labelEntries.size();
|
||||||
|
if (ASMJIT_UNLIKELY(labelId == Globals::kInvalidId))
|
||||||
|
return DebugUtils::errored(kErrorTooManyLabels);
|
||||||
|
|
||||||
|
ASMJIT_PROPAGATE(_labelEntries.willGrow(&_allocator));
|
||||||
|
LabelEntry* le = _allocator.allocZeroedT<LabelEntry>();
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(!le))
|
||||||
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
|
// NOTE: This LabelEntry has a name, but we leave its hashCode as zero as it's anonymous.
|
||||||
|
le->_setId(labelId);
|
||||||
|
le->_parentId = Globals::kInvalidId;
|
||||||
|
le->_offset = 0;
|
||||||
|
ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize));
|
||||||
|
|
||||||
|
_labelEntries.appendUnsafe(le);
|
||||||
|
|
||||||
|
*entryOut = le;
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
|
||||||
|
case LabelType::kLocal: {
|
||||||
if (ASMJIT_UNLIKELY(parentId >= _labelEntries.size()))
|
if (ASMJIT_UNLIKELY(parentId >= _labelEntries.size()))
|
||||||
return DebugUtils::errored(kErrorInvalidParentLabel);
|
return DebugUtils::errored(kErrorInvalidParentLabel);
|
||||||
|
|
||||||
hashCode ^= parentId;
|
hashCode ^= parentId;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Label::kTypeGlobal:
|
case LabelType::kGlobal:
|
||||||
case Label::kTypeExternal:
|
case LabelType::kExternal: {
|
||||||
if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
|
if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
|
||||||
return DebugUtils::errored(kErrorNonLocalLabelCannotHaveParent);
|
return DebugUtils::errored(kErrorInvalidParentLabel);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default: {
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Don't allow to insert duplicates. Local labels allow duplicates that have
|
// Don't allow to insert duplicates. Local labels allow duplicates that have
|
||||||
@@ -596,7 +606,7 @@ Error CodeHolder::newNamedLabelEntry(LabelEntry** entryOut, const char* name, si
|
|||||||
|
|
||||||
le->_hashCode = hashCode;
|
le->_hashCode = hashCode;
|
||||||
le->_setId(labelId);
|
le->_setId(labelId);
|
||||||
le->_type = uint8_t(type);
|
le->_type = type;
|
||||||
le->_parentId = parentId;
|
le->_parentId = parentId;
|
||||||
le->_offset = 0;
|
le->_offset = 0;
|
||||||
ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize));
|
ASMJIT_PROPAGATE(le->_name.setData(&_zone, name, nameSize));
|
||||||
@@ -733,11 +743,10 @@ ASMJIT_API Error CodeHolder::bindLabel(const Label& label, uint32_t toSectionId,
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Relocations
|
||||||
// [asmjit::BaseEmitter - Relocations]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
|
Error CodeHolder::newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept {
|
||||||
ASMJIT_PROPAGATE(_relocations.willGrow(&_allocator));
|
ASMJIT_PROPAGATE(_relocations.willGrow(&_allocator));
|
||||||
|
|
||||||
uint32_t relocId = _relocations.size();
|
uint32_t relocId = _relocations.size();
|
||||||
@@ -749,7 +758,7 @@ Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
|
|||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
re->_id = relocId;
|
re->_id = relocId;
|
||||||
re->_relocType = uint8_t(relocType);
|
re->_relocType = relocType;
|
||||||
re->_sourceSectionId = Globals::kInvalidId;
|
re->_sourceSectionId = Globals::kInvalidId;
|
||||||
re->_targetSectionId = Globals::kInvalidId;
|
re->_targetSectionId = Globals::kInvalidId;
|
||||||
_relocations.appendUnsafe(re);
|
_relocations.appendUnsafe(re);
|
||||||
@@ -758,26 +767,25 @@ Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Expression Evaluation
|
||||||
// [asmjit::BaseEmitter - Expression Evaluation]
|
// ==================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, uint64_t* out) noexcept {
|
static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, uint64_t* out) noexcept {
|
||||||
uint64_t value[2];
|
uint64_t value[2];
|
||||||
for (size_t i = 0; i < 2; i++) {
|
for (size_t i = 0; i < 2; i++) {
|
||||||
uint64_t v;
|
uint64_t v;
|
||||||
switch (exp->valueType[i]) {
|
switch (exp->valueType[i]) {
|
||||||
case Expression::kValueNone: {
|
case ExpressionValueType::kNone: {
|
||||||
v = 0;
|
v = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Expression::kValueConstant: {
|
case ExpressionValueType::kConstant: {
|
||||||
v = exp->value[i].constant;
|
v = exp->value[i].constant;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Expression::kValueLabel: {
|
case ExpressionValueType::kLabel: {
|
||||||
LabelEntry* le = exp->value[i].label;
|
LabelEntry* le = exp->value[i].label;
|
||||||
if (!le->isBound())
|
if (!le->isBound())
|
||||||
return DebugUtils::errored(kErrorExpressionLabelNotBound);
|
return DebugUtils::errored(kErrorExpressionLabelNotBound);
|
||||||
@@ -785,7 +793,7 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case Expression::kValueExpression: {
|
case ExpressionValueType::kExpression: {
|
||||||
Expression* nested = exp->value[i].expression;
|
Expression* nested = exp->value[i].expression;
|
||||||
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(self, nested, &v));
|
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(self, nested, &v));
|
||||||
break;
|
break;
|
||||||
@@ -803,27 +811,27 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
|
|||||||
uint64_t& b = value[1];
|
uint64_t& b = value[1];
|
||||||
|
|
||||||
switch (exp->opType) {
|
switch (exp->opType) {
|
||||||
case Expression::kOpAdd:
|
case ExpressionOpType::kAdd:
|
||||||
result = a + b;
|
result = a + b;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expression::kOpSub:
|
case ExpressionOpType::kSub:
|
||||||
result = a - b;
|
result = a - b;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expression::kOpMul:
|
case ExpressionOpType::kMul:
|
||||||
result = a * b;
|
result = a * b;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expression::kOpSll:
|
case ExpressionOpType::kSll:
|
||||||
result = (b > 63) ? uint64_t(0) : uint64_t(a << b);
|
result = (b > 63) ? uint64_t(0) : uint64_t(a << b);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expression::kOpSrl:
|
case ExpressionOpType::kSrl:
|
||||||
result = (b > 63) ? uint64_t(0) : uint64_t(a >> b);
|
result = (b > 63) ? uint64_t(0) : uint64_t(a >> b);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case Expression::kOpSra:
|
case ExpressionOpType::kSra:
|
||||||
result = Support::sar(a, Support::min<uint64_t>(b, 63));
|
result = Support::sar(a, Support::min<uint64_t>(b, 63));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -835,9 +843,8 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Utilities
|
||||||
// [asmjit::BaseEmitter - Utilities]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error CodeHolder::flatten() noexcept {
|
Error CodeHolder::flatten() noexcept {
|
||||||
uint64_t offset = 0;
|
uint64_t offset = 0;
|
||||||
@@ -917,7 +924,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
|
|||||||
// Relocate all recorded locations.
|
// Relocate all recorded locations.
|
||||||
for (const RelocEntry* re : _relocations) {
|
for (const RelocEntry* re : _relocations) {
|
||||||
// Possibly deleted or optimized-out entry.
|
// Possibly deleted or optimized-out entry.
|
||||||
if (re->relocType() == RelocEntry::kTypeNone)
|
if (re->relocType() == RelocType::kNone)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
Section* sourceSection = sectionById(re->sourceSectionId());
|
Section* sourceSection = sectionById(re->sourceSectionId());
|
||||||
@@ -940,17 +947,17 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
|
|||||||
size_t valueOffset = size_t(re->sourceOffset()) + re->format().valueOffset();
|
size_t valueOffset = size_t(re->sourceOffset()) + re->format().valueOffset();
|
||||||
|
|
||||||
switch (re->relocType()) {
|
switch (re->relocType()) {
|
||||||
case RelocEntry::kTypeExpression: {
|
case RelocType::kExpression: {
|
||||||
Expression* expression = (Expression*)(uintptr_t(value));
|
Expression* expression = (Expression*)(uintptr_t(value));
|
||||||
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(this, expression, &value));
|
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(this, expression, &value));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RelocEntry::kTypeAbsToAbs: {
|
case RelocType::kAbsToAbs: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RelocEntry::kTypeRelToAbs: {
|
case RelocType::kRelToAbs: {
|
||||||
// Value is currently a relative offset from the start of its section.
|
// Value is currently a relative offset from the start of its section.
|
||||||
// We have to convert it to an absolute offset (including base address).
|
// We have to convert it to an absolute offset (including base address).
|
||||||
if (ASMJIT_UNLIKELY(!targetSection))
|
if (ASMJIT_UNLIKELY(!targetSection))
|
||||||
@@ -961,14 +968,14 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RelocEntry::kTypeAbsToRel: {
|
case RelocType::kAbsToRel: {
|
||||||
value -= baseAddress + sectionOffset + sourceOffset + regionSize;
|
value -= baseAddress + sectionOffset + sourceOffset + regionSize;
|
||||||
if (addressSize > 4 && !Support::isInt32(int64_t(value)))
|
if (addressSize > 4 && !Support::isInt32(int64_t(value)))
|
||||||
return DebugUtils::errored(kErrorRelocOffsetOutOfRange);
|
return DebugUtils::errored(kErrorRelocOffsetOutOfRange);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case RelocEntry::kTypeX64AddressEntry: {
|
case RelocType::kX64AddressEntry: {
|
||||||
if (re->format().valueSize() != 4 || valueOffset < 2)
|
if (re->format().valueSize() != 4 || valueOffset < 2)
|
||||||
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
return DebugUtils::errored(kErrorInvalidRelocEntry);
|
||||||
|
|
||||||
@@ -1055,7 +1062,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions) noexcept {
|
Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId, CopySectionFlags copyFlags) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(!isSectionValid(sectionId)))
|
if (ASMJIT_UNLIKELY(!isSectionValid(sectionId)))
|
||||||
return DebugUtils::errored(kErrorInvalidSection);
|
return DebugUtils::errored(kErrorInvalidSection);
|
||||||
|
|
||||||
@@ -1067,7 +1074,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId,
|
|||||||
|
|
||||||
memcpy(dst, section->data(), bufferSize);
|
memcpy(dst, section->data(), bufferSize);
|
||||||
|
|
||||||
if (bufferSize < dstSize && (copyOptions & kCopyPadSectionBuffer)) {
|
if (bufferSize < dstSize && Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer)) {
|
||||||
size_t paddingSize = dstSize - bufferSize;
|
size_t paddingSize = dstSize - bufferSize;
|
||||||
memset(static_cast<uint8_t*>(dst) + bufferSize, 0, paddingSize);
|
memset(static_cast<uint8_t*>(dst) + bufferSize, 0, paddingSize);
|
||||||
}
|
}
|
||||||
@@ -1075,7 +1082,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId,
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions) noexcept {
|
Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, CopySectionFlags copyFlags) noexcept {
|
||||||
size_t end = 0;
|
size_t end = 0;
|
||||||
for (Section* section : _sectionsByOrder) {
|
for (Section* section : _sectionsByOrder) {
|
||||||
if (section->offset() > dstSize)
|
if (section->offset() > dstSize)
|
||||||
@@ -1091,7 +1098,7 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOpti
|
|||||||
size_t paddingSize = 0;
|
size_t paddingSize = 0;
|
||||||
memcpy(dstTarget, section->data(), bufferSize);
|
memcpy(dstTarget, section->data(), bufferSize);
|
||||||
|
|
||||||
if ((copyOptions & kCopyPadSectionBuffer) && bufferSize < section->virtualSize()) {
|
if (Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer) && bufferSize < section->virtualSize()) {
|
||||||
paddingSize = Support::min<size_t>(dstSize - offset, size_t(section->virtualSize())) - bufferSize;
|
paddingSize = Support::min<size_t>(dstSize - offset, size_t(section->virtualSize())) - bufferSize;
|
||||||
memset(dstTarget + bufferSize, 0, paddingSize);
|
memset(dstTarget + bufferSize, 0, paddingSize);
|
||||||
}
|
}
|
||||||
@@ -1099,16 +1106,15 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOpti
|
|||||||
end = Support::max(end, offset + bufferSize + paddingSize);
|
end = Support::max(end, offset + bufferSize + paddingSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (end < dstSize && (copyOptions & kCopyPadTargetBuffer)) {
|
if (end < dstSize && Support::test(copyFlags, CopySectionFlags::kPadTargetBuffer)) {
|
||||||
memset(static_cast<uint8_t*>(dst) + end, 0, dstSize - end);
|
memset(static_cast<uint8_t*>(dst) + end, 0, dstSize - end);
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// CodeHolder - Tests
|
||||||
// [asmjit::CodeHolder - Unit]
|
// ==================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
UNIT(code_holder) {
|
UNIT(code_holder) {
|
||||||
@@ -1116,34 +1122,33 @@ UNIT(code_holder) {
|
|||||||
|
|
||||||
INFO("Verifying CodeHolder::init()");
|
INFO("Verifying CodeHolder::init()");
|
||||||
Environment env;
|
Environment env;
|
||||||
env.init(Environment::kArchX86);
|
env.init(Arch::kX86);
|
||||||
|
|
||||||
code.init(env);
|
code.init(env);
|
||||||
EXPECT(code.arch() == Environment::kArchX86);
|
EXPECT(code.arch() == Arch::kX86);
|
||||||
|
|
||||||
INFO("Verifying named labels");
|
INFO("Verifying named labels");
|
||||||
LabelEntry* le;
|
LabelEntry* le;
|
||||||
EXPECT(code.newNamedLabelEntry(&le, "NamedLabel", SIZE_MAX, Label::kTypeGlobal) == kErrorOk);
|
EXPECT(code.newNamedLabelEntry(&le, "NamedLabel", SIZE_MAX, LabelType::kGlobal) == kErrorOk);
|
||||||
EXPECT(strcmp(le->name(), "NamedLabel") == 0);
|
EXPECT(strcmp(le->name(), "NamedLabel") == 0);
|
||||||
EXPECT(code.labelIdByName("NamedLabel") == le->id());
|
EXPECT(code.labelIdByName("NamedLabel") == le->id());
|
||||||
|
|
||||||
INFO("Verifying section ordering");
|
INFO("Verifying section ordering");
|
||||||
Section* section1;
|
Section* section1;
|
||||||
EXPECT(code.newSection(§ion1, "high-priority", SIZE_MAX, 0, 1, -1) == kErrorOk);
|
EXPECT(code.newSection(§ion1, "high-priority", SIZE_MAX, SectionFlags::kNone, 1, -1) == kErrorOk);
|
||||||
EXPECT(code.sections()[1] == section1);
|
EXPECT(code.sections()[1] == section1);
|
||||||
EXPECT(code.sectionsByOrder()[0] == section1);
|
EXPECT(code.sectionsByOrder()[0] == section1);
|
||||||
|
|
||||||
Section* section0;
|
Section* section0;
|
||||||
EXPECT(code.newSection(§ion0, "higher-priority", SIZE_MAX, 0, 1, -2) == kErrorOk);
|
EXPECT(code.newSection(§ion0, "higher-priority", SIZE_MAX, SectionFlags::kNone, 1, -2) == kErrorOk);
|
||||||
EXPECT(code.sections()[2] == section0);
|
EXPECT(code.sections()[2] == section0);
|
||||||
EXPECT(code.sectionsByOrder()[0] == section0);
|
EXPECT(code.sectionsByOrder()[0] == section0);
|
||||||
EXPECT(code.sectionsByOrder()[1] == section1);
|
EXPECT(code.sectionsByOrder()[1] == section1);
|
||||||
|
|
||||||
Section* section3;
|
Section* section3;
|
||||||
EXPECT(code.newSection(§ion3, "low-priority", SIZE_MAX, 0, 1, 2) == kErrorOk);
|
EXPECT(code.newSection(§ion3, "low-priority", SIZE_MAX, SectionFlags::kNone, 1, 2) == kErrorOk);
|
||||||
EXPECT(code.sections()[3] == section3);
|
EXPECT(code.sections()[3] == section3);
|
||||||
EXPECT(code.sectionsByOrder()[3] == section3);
|
EXPECT(code.sectionsByOrder()[3] == section3);
|
||||||
|
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/codeholder.h"
|
#include "../core/codeholder.h"
|
||||||
@@ -50,13 +32,13 @@ bool CodeWriterUtils::encodeOffset32(uint32_t* dst, int64_t offset64, const Offs
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (format.type()) {
|
switch (format.type()) {
|
||||||
case OffsetFormat::kTypeCommon: {
|
case OffsetType::kCommon: {
|
||||||
*dst = (uint32_t(offset32) & Support::lsbMask<uint32_t>(bitCount)) << bitShift;
|
*dst = (uint32_t(offset32) & Support::lsbMask<uint32_t>(bitCount)) << bitShift;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
case OffsetFormat::kTypeAArch64_ADR:
|
case OffsetType::kAArch64_ADR:
|
||||||
case OffsetFormat::kTypeAArch64_ADRP: {
|
case OffsetType::kAArch64_ADRP: {
|
||||||
// Sanity checks.
|
// Sanity checks.
|
||||||
if (format.valueSize() != 4 || bitCount != 21 || bitShift != 5)
|
if (format.valueSize() != 4 || bitCount != 21 || bitShift != 5)
|
||||||
return false;
|
return false;
|
||||||
@@ -91,7 +73,7 @@ bool CodeWriterUtils::encodeOffset64(uint64_t* dst, int64_t offset64, const Offs
|
|||||||
return false;
|
return false;
|
||||||
|
|
||||||
switch (format.type()) {
|
switch (format.type()) {
|
||||||
case OffsetFormat::kTypeCommon: {
|
case OffsetType::kCommon: {
|
||||||
*dst = (uint64_t(offset64) & Support::lsbMask<uint64_t>(bitCount)) << format.immBitShift();
|
*dst = (uint64_t(offset64) & Support::lsbMask<uint64_t>(bitCount)) << format.immBitShift();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
#define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
|
||||||
@@ -34,25 +16,17 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_assembler
|
//! \addtogroup asmjit_assembler
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
struct OffsetFormat;
|
struct OffsetFormat;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::CodeWriter]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Helper that is used to write into a \ref CodeBuffer held by \ref BaseAssembler.
|
//! Helper that is used to write into a \ref CodeBuffer held by \ref BaseAssembler.
|
||||||
class CodeWriter {
|
class CodeWriter {
|
||||||
public:
|
public:
|
||||||
uint8_t* _cursor;
|
uint8_t* _cursor;
|
||||||
|
|
||||||
ASMJIT_INLINE explicit CodeWriter(BaseAssembler* a) noexcept
|
ASMJIT_FORCE_INLINE explicit CodeWriter(BaseAssembler* a) noexcept
|
||||||
: _cursor(a->_bufferPtr) {}
|
: _cursor(a->_bufferPtr) {}
|
||||||
|
|
||||||
ASMJIT_INLINE Error ensureSpace(BaseAssembler* a, size_t n) noexcept {
|
ASMJIT_FORCE_INLINE Error ensureSpace(BaseAssembler* a, size_t n) noexcept {
|
||||||
size_t remainingSpace = (size_t)(a->_bufferEnd - _cursor);
|
size_t remainingSpace = (size_t)(a->_bufferEnd - _cursor);
|
||||||
if (ASMJIT_UNLIKELY(remainingSpace < n)) {
|
if (ASMJIT_UNLIKELY(remainingSpace < n)) {
|
||||||
CodeBuffer& buffer = a->_section->_buffer;
|
CodeBuffer& buffer = a->_section->_buffer;
|
||||||
@@ -64,24 +38,24 @@ public:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE uint8_t* cursor() const noexcept { return _cursor; }
|
ASMJIT_FORCE_INLINE uint8_t* cursor() const noexcept { return _cursor; }
|
||||||
ASMJIT_INLINE void setCursor(uint8_t* cursor) noexcept { _cursor = cursor; }
|
ASMJIT_FORCE_INLINE void setCursor(uint8_t* cursor) noexcept { _cursor = cursor; }
|
||||||
ASMJIT_INLINE void advance(size_t n) noexcept { _cursor += n; }
|
ASMJIT_FORCE_INLINE void advance(size_t n) noexcept { _cursor += n; }
|
||||||
|
|
||||||
ASMJIT_INLINE size_t offsetFrom(uint8_t* from) const noexcept {
|
ASMJIT_FORCE_INLINE size_t offsetFrom(uint8_t* from) const noexcept {
|
||||||
ASMJIT_ASSERT(_cursor >= from);
|
ASMJIT_ASSERT(_cursor >= from);
|
||||||
return (size_t)(_cursor - from);
|
return (size_t)(_cursor - from);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit8(T val) noexcept {
|
ASMJIT_FORCE_INLINE void emit8(T val) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
_cursor[0] = uint8_t(U(val) & U(0xFF));
|
_cursor[0] = uint8_t(U(val) & U(0xFF));
|
||||||
_cursor++;
|
_cursor++;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T, typename Y>
|
template<typename T, typename Y>
|
||||||
ASMJIT_INLINE void emit8If(T val, Y cond) noexcept {
|
ASMJIT_FORCE_INLINE void emit8If(T val, Y cond) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
ASMJIT_ASSERT(size_t(cond) <= 1u);
|
ASMJIT_ASSERT(size_t(cond) <= 1u);
|
||||||
|
|
||||||
@@ -90,41 +64,41 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit16uLE(T val) noexcept {
|
ASMJIT_FORCE_INLINE void emit16uLE(T val) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
Support::writeU16uLE(_cursor, uint32_t(U(val) & 0xFFFFu));
|
Support::writeU16uLE(_cursor, uint32_t(U(val) & 0xFFFFu));
|
||||||
_cursor += 2;
|
_cursor += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit16uBE(T val) noexcept {
|
ASMJIT_FORCE_INLINE void emit16uBE(T val) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
Support::writeU16uBE(_cursor, uint32_t(U(val) & 0xFFFFu));
|
Support::writeU16uBE(_cursor, uint32_t(U(val) & 0xFFFFu));
|
||||||
_cursor += 2;
|
_cursor += 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit32uLE(T val) noexcept {
|
ASMJIT_FORCE_INLINE void emit32uLE(T val) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
Support::writeU32uLE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
Support::writeU32uLE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
||||||
_cursor += 4;
|
_cursor += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emit32uBE(T val) noexcept {
|
ASMJIT_FORCE_INLINE void emit32uBE(T val) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
Support::writeU32uBE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
Support::writeU32uBE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
|
||||||
_cursor += 4;
|
_cursor += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void emitData(const void* data, size_t size) noexcept {
|
ASMJIT_FORCE_INLINE void emitData(const void* data, size_t size) noexcept {
|
||||||
ASMJIT_ASSERT(size != 0);
|
ASMJIT_ASSERT(size != 0);
|
||||||
memcpy(_cursor, data, size);
|
memcpy(_cursor, data, size);
|
||||||
_cursor += size;
|
_cursor += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emitValueLE(const T& value, size_t size) noexcept {
|
ASMJIT_FORCE_INLINE void emitValueLE(const T& value, size_t size) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
ASMJIT_ASSERT(size <= sizeof(T));
|
ASMJIT_ASSERT(size <= sizeof(T));
|
||||||
|
|
||||||
@@ -137,7 +111,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void emitValueBE(const T& value, size_t size) noexcept {
|
ASMJIT_FORCE_INLINE void emitValueBE(const T& value, size_t size) noexcept {
|
||||||
typedef typename std::make_unsigned<T>::type U;
|
typedef typename std::make_unsigned<T>::type U;
|
||||||
ASMJIT_ASSERT(size <= sizeof(T));
|
ASMJIT_ASSERT(size <= sizeof(T));
|
||||||
|
|
||||||
@@ -149,13 +123,13 @@ public:
|
|||||||
_cursor += size;
|
_cursor += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void emitZeros(size_t size) noexcept {
|
ASMJIT_FORCE_INLINE void emitZeros(size_t size) noexcept {
|
||||||
ASMJIT_ASSERT(size != 0);
|
ASMJIT_ASSERT(size != 0);
|
||||||
memset(_cursor, 0, size);
|
memset(_cursor, 0, size);
|
||||||
_cursor += size;
|
_cursor += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void remove8(uint8_t* where) noexcept {
|
ASMJIT_FORCE_INLINE void remove8(uint8_t* where) noexcept {
|
||||||
ASMJIT_ASSERT(where < _cursor);
|
ASMJIT_ASSERT(where < _cursor);
|
||||||
|
|
||||||
uint8_t* p = where;
|
uint8_t* p = where;
|
||||||
@@ -165,7 +139,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void insert8(uint8_t* where, T val) noexcept {
|
ASMJIT_FORCE_INLINE void insert8(uint8_t* where, T val) noexcept {
|
||||||
uint8_t* p = _cursor;
|
uint8_t* p = _cursor;
|
||||||
|
|
||||||
while (p != where) {
|
while (p != where) {
|
||||||
@@ -177,7 +151,7 @@ public:
|
|||||||
_cursor++;
|
_cursor++;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void done(BaseAssembler* a) noexcept {
|
ASMJIT_FORCE_INLINE void done(BaseAssembler* a) noexcept {
|
||||||
CodeBuffer& buffer = a->_section->_buffer;
|
CodeBuffer& buffer = a->_section->_buffer;
|
||||||
size_t newSize = (size_t)(_cursor - a->_bufferData);
|
size_t newSize = (size_t)(_cursor - a->_bufferData);
|
||||||
ASMJIT_ASSERT(newSize <= buffer.capacity());
|
ASMJIT_ASSERT(newSize <= buffer.capacity());
|
||||||
@@ -187,10 +161,7 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! Code writer utilities.
|
||||||
// [asmjit::CodeWriterUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
namespace CodeWriterUtils {
|
namespace CodeWriterUtils {
|
||||||
|
|
||||||
bool encodeOffset32(uint32_t* dst, int64_t offset64, const OffsetFormat& format) noexcept;
|
bool encodeOffset32(uint32_t* dst, int64_t offset64, const OffsetFormat& format) noexcept;
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
#ifndef ASMJIT_NO_COMPILER
|
||||||
@@ -35,11 +17,11 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// GlobalConstPoolPass
|
||||||
// [asmjit::GlobalConstPoolPass]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class GlobalConstPoolPass : public Pass {
|
class GlobalConstPoolPass : public Pass {
|
||||||
|
public:
|
||||||
typedef Pass Base;
|
typedef Pass Base;
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(GlobalConstPoolPass)
|
ASMJIT_NONCOPYABLE(GlobalConstPoolPass)
|
||||||
@@ -51,53 +33,50 @@ public:
|
|||||||
|
|
||||||
// Flush the global constant pool.
|
// Flush the global constant pool.
|
||||||
BaseCompiler* compiler = static_cast<BaseCompiler*>(_cb);
|
BaseCompiler* compiler = static_cast<BaseCompiler*>(_cb);
|
||||||
if (compiler->_globalConstPool) {
|
ConstPoolNode* globalConstPool = compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)];
|
||||||
compiler->addAfter(compiler->_globalConstPool, compiler->lastNode());
|
|
||||||
compiler->_globalConstPool = nullptr;
|
if (globalConstPool) {
|
||||||
|
compiler->addAfter(globalConstPool, compiler->lastNode());
|
||||||
|
compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// BaseCompiler - Construction & Destruction
|
||||||
// [asmjit::BaseCompiler - Construction / Destruction]
|
// =========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
BaseCompiler::BaseCompiler() noexcept
|
BaseCompiler::BaseCompiler() noexcept
|
||||||
: BaseBuilder(),
|
: BaseBuilder(),
|
||||||
_func(nullptr),
|
_func(nullptr),
|
||||||
_vRegZone(4096 - Zone::kBlockOverhead),
|
_vRegZone(4096 - Zone::kBlockOverhead),
|
||||||
_vRegArray(),
|
_vRegArray(),
|
||||||
_localConstPool(nullptr),
|
_constPools { nullptr, nullptr } {
|
||||||
_globalConstPool(nullptr) {
|
_emitterType = EmitterType::kCompiler;
|
||||||
|
_validationFlags = ValidationFlags::kEnableVirtRegs;
|
||||||
_emitterType = uint8_t(kTypeCompiler);
|
|
||||||
_validationFlags = uint8_t(InstAPI::kValidationFlagVirtRegs);
|
|
||||||
}
|
}
|
||||||
BaseCompiler::~BaseCompiler() noexcept {}
|
BaseCompiler::~BaseCompiler() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseCompiler - Function Management
|
||||||
// [asmjit::BaseCompiler - Function Management]
|
// ==================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature) {
|
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;
|
||||||
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, SentinelNode::kSentinelFuncEnd));
|
ASMJIT_PROPAGATE(_newNodeT<SentinelNode>(&funcNode->_end, SentinelType::kFuncEnd));
|
||||||
|
|
||||||
// Initialize the function's detail info.
|
// Initialize the function's detail info.
|
||||||
Error err = funcNode->detail().init(signature, environment());
|
Error err = funcNode->detail().init(signature, environment());
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
// If the Target guarantees greater stack alignment than required by the
|
// If the Target guarantees greater stack alignment than required by the calling convention
|
||||||
// calling convention then override it as we can prevent having to perform
|
// then override it as we can prevent having to perform dynamic stack alignment
|
||||||
// dynamic stack alignment
|
|
||||||
uint32_t environmentStackAlignment = _environment.stackAlignment();
|
uint32_t environmentStackAlignment = _environment.stackAlignment();
|
||||||
|
|
||||||
if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment)
|
if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment)
|
||||||
@@ -123,13 +102,13 @@ Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature)
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_addFuncNode(FuncNode** out, const FuncSignature& signature) {
|
Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature) {
|
||||||
ASMJIT_PROPAGATE(_newFuncNode(out, signature));
|
ASMJIT_PROPAGATE(newFuncNode(out, signature));
|
||||||
addFunc(*out);
|
addFunc(*out);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newRetNode(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;
|
||||||
|
|
||||||
@@ -143,8 +122,8 @@ Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Ope
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
|
Error BaseCompiler::addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
|
||||||
ASMJIT_PROPAGATE(_newRetNode(out, o0, o1));
|
ASMJIT_PROPAGATE(newFuncRetNode(out, o0, o1));
|
||||||
addNode(*out);
|
addNode(*out);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
@@ -169,10 +148,11 @@ Error BaseCompiler::endFunc() {
|
|||||||
return reportError(DebugUtils::errored(kErrorInvalidState));
|
return reportError(DebugUtils::errored(kErrorInvalidState));
|
||||||
|
|
||||||
// Add the local constant pool at the end of the function (if exists).
|
// Add the local constant pool at the end of the function (if exists).
|
||||||
if (_localConstPool) {
|
ConstPoolNode* localConstPool = _constPools[uint32_t(ConstPoolScope::kLocal)];
|
||||||
|
if (localConstPool) {
|
||||||
setCursor(func->endNode()->prev());
|
setCursor(func->endNode()->prev());
|
||||||
addNode(_localConstPool);
|
addNode(localConstPool);
|
||||||
_localConstPool = nullptr;
|
_constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark as finished.
|
// Mark as finished.
|
||||||
@@ -184,28 +164,12 @@ Error BaseCompiler::endFunc() {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_setArg(size_t argIndex, size_t valueIndex, const BaseReg& r) {
|
// BaseCompiler - Function Invocation
|
||||||
FuncNode* func = _func;
|
// ==================================
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!func))
|
Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidState));
|
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!isVirtRegValid(r)))
|
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidVirtId));
|
|
||||||
|
|
||||||
VirtReg* vReg = virtRegByReg(r);
|
|
||||||
func->setArg(argIndex, valueIndex, vReg);
|
|
||||||
|
|
||||||
return kErrorOk;
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::BaseCompiler - Function Invocation]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
|
|
||||||
InvokeNode* node;
|
InvokeNode* node;
|
||||||
ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, 0u));
|
ASMJIT_PROPAGATE(_newNodeT<InvokeNode>(&node, instId, InstOptions::kNone));
|
||||||
|
|
||||||
node->setOpCount(1);
|
node->setOpCount(1);
|
||||||
node->setOp(0, o0);
|
node->setOp(0, o0);
|
||||||
@@ -228,15 +192,14 @@ Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Oper
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
|
Error BaseCompiler::addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
|
||||||
ASMJIT_PROPAGATE(_newInvokeNode(out, instId, o0, signature));
|
ASMJIT_PROPAGATE(newInvokeNode(out, instId, o0, signature));
|
||||||
addNode(*out);
|
addNode(*out);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseCompiler - Virtual Registers
|
||||||
// [asmjit::BaseCompiler - Virtual Registers]
|
// ================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
|
static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
|
||||||
uint32_t index = unsigned(Operand::virtIdToIndex(vReg->_id));
|
uint32_t index = unsigned(Operand::virtIdToIndex(vReg->_id));
|
||||||
@@ -248,7 +211,7 @@ static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
|
|||||||
vReg->_name.setData(&self->_dataZone, buf, unsigned(size));
|
vReg->_name.setData(&self->_dataZone, buf, unsigned(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t 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();
|
||||||
|
|
||||||
@@ -262,10 +225,10 @@ Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signatur
|
|||||||
if (ASMJIT_UNLIKELY(!vReg))
|
if (ASMJIT_UNLIKELY(!vReg))
|
||||||
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
return reportError(DebugUtils::errored(kErrorOutOfMemory));
|
||||||
|
|
||||||
uint32_t size = Type::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);
|
||||||
|
|
||||||
vReg = new(vReg) VirtReg(Operand::indexToVirtId(index), signature, size, alignment, typeId);
|
vReg = new(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')
|
||||||
@@ -282,22 +245,22 @@ Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signatur
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newReg(BaseReg* out, uint32_t typeId, const char* name) {
|
Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) {
|
||||||
RegInfo regInfo;
|
OperandSignature regSignature;
|
||||||
out->reset();
|
out->reset();
|
||||||
|
|
||||||
Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info);
|
Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
VirtReg* vReg;
|
VirtReg* vReg;
|
||||||
ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name));
|
ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name));
|
||||||
|
|
||||||
out->_initReg(regInfo.signature(), vReg->id());
|
out->_initReg(regSignature, vReg->id());
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...) {
|
Error BaseCompiler::_newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...) {
|
||||||
va_list ap;
|
va_list ap;
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
|
|
||||||
@@ -311,75 +274,72 @@ Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, .
|
|||||||
Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) {
|
Error BaseCompiler::_newReg(BaseReg* out, const BaseReg& ref, const char* name) {
|
||||||
out->reset();
|
out->reset();
|
||||||
|
|
||||||
RegInfo regInfo;
|
OperandSignature regSignature;
|
||||||
uint32_t typeId;
|
TypeId typeId;
|
||||||
|
|
||||||
if (isVirtRegValid(ref)) {
|
if (isVirtRegValid(ref)) {
|
||||||
VirtReg* vRef = virtRegByReg(ref);
|
VirtReg* vRef = virtRegByReg(ref);
|
||||||
typeId = vRef->typeId();
|
typeId = vRef->typeId();
|
||||||
|
|
||||||
// NOTE: It's possible to cast one register type to another if it's the
|
// NOTE: It's possible to cast one register type to another if it's the same register group. However, VirtReg
|
||||||
// same register group. However, VirtReg always contains the TypeId that
|
// always contains the TypeId that was used to create the register. This means that in some cases we may end
|
||||||
// was used to create the register. This means that in some cases we may
|
// up having different size of `ref` and `vRef`. In such case we adjust the TypeId to match the `ref` register
|
||||||
// end up having different size of `ref` and `vRef`. In such case we
|
// type instead of the original register type, which should be the expected behavior.
|
||||||
// adjust the TypeId to match the `ref` register type instead of the
|
uint32_t typeSize = TypeUtils::sizeOf(typeId);
|
||||||
// original register type, which should be the expected behavior.
|
|
||||||
uint32_t typeSize = Type::sizeOf(typeId);
|
|
||||||
uint32_t refSize = ref.size();
|
uint32_t refSize = ref.size();
|
||||||
|
|
||||||
if (typeSize != refSize) {
|
if (typeSize != refSize) {
|
||||||
if (Type::isInt(typeId)) {
|
if (TypeUtils::isInt(typeId)) {
|
||||||
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
|
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
|
||||||
switch (refSize) {
|
switch (refSize) {
|
||||||
case 1: typeId = Type::kIdI8 | (typeId & 1); break;
|
case 1: typeId = TypeId(uint32_t(TypeId::kInt8 ) | (uint32_t(typeId) & 1)); break;
|
||||||
case 2: typeId = Type::kIdI16 | (typeId & 1); break;
|
case 2: typeId = TypeId(uint32_t(TypeId::kInt16) | (uint32_t(typeId) & 1)); break;
|
||||||
case 4: typeId = Type::kIdI32 | (typeId & 1); break;
|
case 4: typeId = TypeId(uint32_t(TypeId::kInt32) | (uint32_t(typeId) & 1)); break;
|
||||||
case 8: typeId = Type::kIdI64 | (typeId & 1); break;
|
case 8: typeId = TypeId(uint32_t(TypeId::kInt64) | (uint32_t(typeId) & 1)); break;
|
||||||
default: typeId = Type::kIdVoid; break;
|
default: typeId = TypeId::kVoid; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (Type::isMmx(typeId)) {
|
else if (TypeUtils::isMmx(typeId)) {
|
||||||
// MMX register - always use 64-bit.
|
// MMX register - always use 64-bit.
|
||||||
typeId = Type::kIdMmx64;
|
typeId = TypeId::kMmx64;
|
||||||
}
|
}
|
||||||
else if (Type::isMask(typeId)) {
|
else if (TypeUtils::isMask(typeId)) {
|
||||||
// Mask register - change TypeId to match `ref` size.
|
// Mask register - change TypeId to match `ref` size.
|
||||||
switch (refSize) {
|
switch (refSize) {
|
||||||
case 1: typeId = Type::kIdMask8; break;
|
case 1: typeId = TypeId::kMask8; break;
|
||||||
case 2: typeId = Type::kIdMask16; break;
|
case 2: typeId = TypeId::kMask16; break;
|
||||||
case 4: typeId = Type::kIdMask32; break;
|
case 4: typeId = TypeId::kMask32; break;
|
||||||
case 8: typeId = Type::kIdMask64; break;
|
case 8: typeId = TypeId::kMask64; break;
|
||||||
default: typeId = Type::kIdVoid; break;
|
default: typeId = TypeId::kVoid; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// VEC register - change TypeId to match `ref` size, keep vector metadata.
|
// Vector register - change TypeId to match `ref` size, keep vector metadata.
|
||||||
uint32_t elementTypeId = Type::baseOf(typeId);
|
TypeId scalarTypeId = TypeUtils::scalarOf(typeId);
|
||||||
|
|
||||||
switch (refSize) {
|
switch (refSize) {
|
||||||
case 16: typeId = Type::_kIdVec128Start + (elementTypeId - Type::kIdI8); break;
|
case 16: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec128Start); break;
|
||||||
case 32: typeId = Type::_kIdVec256Start + (elementTypeId - Type::kIdI8); break;
|
case 32: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec256Start); break;
|
||||||
case 64: typeId = Type::_kIdVec512Start + (elementTypeId - Type::kIdI8); break;
|
case 64: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec512Start); break;
|
||||||
default: typeId = Type::kIdVoid; break;
|
default: typeId = TypeId::kVoid; break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (typeId == Type::kIdVoid)
|
if (typeId == TypeId::kVoid)
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidState));
|
return reportError(DebugUtils::errored(kErrorInvalidState));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
typeId = ref.type();
|
typeId = ArchTraits::byArch(arch()).regTypeToTypeId(ref.type());
|
||||||
}
|
}
|
||||||
|
|
||||||
Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info);
|
Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
VirtReg* vReg;
|
VirtReg* vReg;
|
||||||
ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regInfo.signature(), name));
|
ASMJIT_PROPAGATE(newVirtReg(&vReg, typeId, regSignature, name));
|
||||||
|
|
||||||
out->_initReg(regInfo.signature(), vReg->id());
|
out->_initReg(regSignature, vReg->id());
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -410,14 +370,17 @@ Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, c
|
|||||||
alignment = 64;
|
alignment = 64;
|
||||||
|
|
||||||
VirtReg* vReg;
|
VirtReg* vReg;
|
||||||
ASMJIT_PROPAGATE(newVirtReg(&vReg, 0, 0, name));
|
ASMJIT_PROPAGATE(newVirtReg(&vReg, TypeId::kVoid, OperandSignature(0), name));
|
||||||
|
|
||||||
vReg->_virtSize = size;
|
vReg->_virtSize = size;
|
||||||
vReg->_isStack = true;
|
vReg->_isStack = true;
|
||||||
vReg->_alignment = uint8_t(alignment);
|
vReg->_alignment = uint8_t(alignment);
|
||||||
|
|
||||||
// Set the memory operand to GPD/GPQ and its id to VirtReg.
|
// Set the memory operand to GPD/GPQ and its id to VirtReg.
|
||||||
*out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag });
|
*out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
|
||||||
|
OperandSignature::fromMemBaseType(_gpSignature.regType()) |
|
||||||
|
OperandSignature::fromBits(OperandSignature::kMemRegHomeFlag),
|
||||||
|
vReg->id(), 0, 0);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -438,9 +401,8 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new
|
|||||||
if (newAlignment)
|
if (newAlignment)
|
||||||
vReg->_alignment = uint8_t(newAlignment);
|
vReg->_alignment = uint8_t(newAlignment);
|
||||||
|
|
||||||
// This is required if the RAPass is already running. There is a chance that
|
// This is required if the RAPass is already running. There is a chance that a stack-slot has been already
|
||||||
// a stack-slot has been already allocated and in that case it has to be
|
// allocated and in that case it has to be updated as well, otherwise we would allocate wrong amount of memory.
|
||||||
// updated as well, otherwise we would allocate wrong amount of memory.
|
|
||||||
RAWorkReg* workReg = vReg->_workReg;
|
RAWorkReg* workReg = vReg->_workReg;
|
||||||
if (workReg && workReg->_stackSlot) {
|
if (workReg && workReg->_stackSlot) {
|
||||||
workReg->_stackSlot->_size = vReg->_virtSize;
|
workReg->_stackSlot->_size = vReg->_virtSize;
|
||||||
@@ -450,37 +412,26 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::_newConst(BaseMem* out, uint32_t scope, const void* data, size_t size) {
|
Error BaseCompiler::_newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size) {
|
||||||
out->reset();
|
out->reset();
|
||||||
ConstPoolNode** pPool;
|
|
||||||
|
|
||||||
if (scope == ConstPool::kScopeLocal)
|
if (uint32_t(scope) > 1)
|
||||||
pPool = &_localConstPool;
|
|
||||||
else if (scope == ConstPool::kScopeGlobal)
|
|
||||||
pPool = &_globalConstPool;
|
|
||||||
else
|
|
||||||
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
return reportError(DebugUtils::errored(kErrorInvalidArgument));
|
||||||
|
|
||||||
if (!*pPool)
|
if (!_constPools[uint32_t(scope)])
|
||||||
ASMJIT_PROPAGATE(_newConstPoolNode(pPool));
|
ASMJIT_PROPAGATE(newConstPoolNode(&_constPools[uint32_t(scope)]));
|
||||||
|
|
||||||
ConstPoolNode* pool = *pPool;
|
ConstPoolNode* pool = _constPools[uint32_t(scope)];
|
||||||
size_t off;
|
size_t off;
|
||||||
Error err = pool->add(data, size, off);
|
Error err = pool->add(data, size, off);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(err))
|
if (ASMJIT_UNLIKELY(err))
|
||||||
return reportError(err);
|
return reportError(err);
|
||||||
|
|
||||||
*out = BaseMem(BaseMem::Decomposed {
|
*out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
|
||||||
Label::kLabelTag, // Base type.
|
OperandSignature::fromMemBaseType(RegType::kLabelTag) |
|
||||||
pool->labelId(), // Base id.
|
OperandSignature::fromSize(uint32_t(size)),
|
||||||
0, // Index type.
|
pool->labelId(), 0, int32_t(off));
|
||||||
0, // Index id.
|
|
||||||
int32_t(off), // Offset.
|
|
||||||
uint32_t(size), // Size.
|
|
||||||
0 // Flags.
|
|
||||||
});
|
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -505,11 +456,10 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseCompiler - Jump Annotations
|
||||||
// [asmjit::BaseCompiler - Jump Annotations]
|
// ===============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t 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 = _allocator.allocT<JumpNode>();
|
||||||
uint32_t opCount = 1;
|
uint32_t opCount = 1;
|
||||||
|
|
||||||
@@ -524,8 +474,8 @@ Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOp
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseCompiler::emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation) {
|
Error BaseCompiler::emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation) {
|
||||||
uint32_t options = instOptions() | forcedInstOptions();
|
InstOptions options = instOptions() | forcedInstOptions();
|
||||||
RegOnly extra = extraReg();
|
RegOnly extra = extraReg();
|
||||||
const char* comment = inlineComment();
|
const char* comment = inlineComment();
|
||||||
|
|
||||||
@@ -562,16 +512,15 @@ JumpAnnotation* BaseCompiler::newJumpAnnotation() {
|
|||||||
return jumpAnnotation;
|
return jumpAnnotation;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseCompiler - Events
|
||||||
// [asmjit::BaseCompiler - Events]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
|
Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
|
||||||
ASMJIT_PROPAGATE(Base::onAttach(code));
|
ASMJIT_PROPAGATE(Base::onAttach(code));
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
||||||
uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
|
RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
|
||||||
_gpRegInfo.setSignature(archTraits.regTypeToSignature(nativeRegType));
|
_gpSignature = archTraits.regTypeToSignature(nativeRegType);
|
||||||
|
|
||||||
Error err = addPassT<GlobalConstPoolPass>();
|
Error err = addPassT<GlobalConstPoolPass>();
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
@@ -584,8 +533,8 @@ Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
|
|||||||
|
|
||||||
Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
|
Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
|
||||||
_func = nullptr;
|
_func = nullptr;
|
||||||
_localConstPool = nullptr;
|
_constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
|
||||||
_globalConstPool = nullptr;
|
_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
|
||||||
|
|
||||||
_vRegArray.reset();
|
_vRegArray.reset();
|
||||||
_vRegZone.reset();
|
_vRegZone.reset();
|
||||||
@@ -593,32 +542,30 @@ Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
|
|||||||
return Base::onDetach(code);
|
return Base::onDetach(code);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// FuncPass - Construction & Destruction
|
||||||
// [asmjit::FuncPass - Construction / Destruction]
|
// =====================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
FuncPass::FuncPass(const char* name) noexcept
|
FuncPass::FuncPass(const char* name) noexcept
|
||||||
: Pass(name) {}
|
: Pass(name) {}
|
||||||
|
|
||||||
// ============================================================================
|
// FuncPass - Run
|
||||||
// [asmjit::FuncPass - Run]
|
// ==============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
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;
|
if (!node) return kErrorOk;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
if (node->type() == BaseNode::kNodeFunc) {
|
if (node->type() == NodeType::kFunc) {
|
||||||
FuncNode* func = node->as<FuncNode>();
|
FuncNode* func = node->as<FuncNode>();
|
||||||
node = func->endNode();
|
node = func->endNode();
|
||||||
ASMJIT_PROPAGATE(runOnFunction(zone, logger, func));
|
ASMJIT_PROPAGATE(runOnFunction(zone, logger, func));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find a function by skipping all nodes that are not `kNodeFunc`.
|
// Find a function by skipping all nodes that are not `NodeType::kFunc`.
|
||||||
do {
|
do {
|
||||||
node = node->next();
|
node = node->next();
|
||||||
} while (node && node->type() != BaseNode::kNodeFunc);
|
} while (node && node->type() != NodeType::kFunc);
|
||||||
} while (node);
|
} while (node);
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
|
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_COMPILER_H_INCLUDED
|
#define ASMJIT_CORE_COMPILER_H_INCLUDED
|
||||||
@@ -40,10 +22,6 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class JumpAnnotation;
|
class JumpAnnotation;
|
||||||
class JumpNode;
|
class JumpNode;
|
||||||
class FuncNode;
|
class FuncNode;
|
||||||
@@ -53,25 +31,18 @@ class InvokeNode;
|
|||||||
//! \addtogroup asmjit_compiler
|
//! \addtogroup asmjit_compiler
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::BaseCompiler]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Code emitter that uses virtual registers and performs register allocation.
|
//! Code emitter that uses virtual registers and performs register allocation.
|
||||||
//!
|
//!
|
||||||
//! Compiler is a high-level code-generation tool that provides register
|
//! Compiler is a high-level code-generation tool that provides register allocation and automatic handling of function
|
||||||
//! allocation and automatic handling of function calling conventions. It was
|
//! calling conventions. It was primarily designed for merging multiple parts of code into a function without worrying
|
||||||
//! primarily designed for merging multiple parts of code into a function
|
//! about registers and function calling conventions.
|
||||||
//! without worrying about registers and function calling conventions.
|
|
||||||
//!
|
//!
|
||||||
//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and
|
//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit code generation within a single code
|
||||||
//! 64-bit code generation within a single code base.
|
//! base.
|
||||||
//!
|
//!
|
||||||
//! BaseCompiler is based on BaseBuilder and contains all the features it
|
//! BaseCompiler is based on BaseBuilder and contains all the features it provides. It means that the code it stores
|
||||||
//! provides. It means that the code it stores can be modified (removed, added,
|
//! can be modified (removed, added, injected) and analyzed. When the code is finalized the compiler can emit the code
|
||||||
//! injected) and analyzed. When the code is finalized the compiler can emit
|
//! into an Assembler to translate the abstract representation into a machine code.
|
||||||
//! the code into an Assembler to translate the abstract representation into a
|
|
||||||
//! machine code.
|
|
||||||
//!
|
//!
|
||||||
//! Check out architecture specific compilers for more details and examples:
|
//! Check out architecture specific compilers for more details and examples:
|
||||||
//!
|
//!
|
||||||
@@ -81,6 +52,9 @@ public:
|
|||||||
ASMJIT_NONCOPYABLE(BaseCompiler)
|
ASMJIT_NONCOPYABLE(BaseCompiler)
|
||||||
typedef BaseBuilder Base;
|
typedef BaseBuilder Base;
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Current function.
|
//! Current function.
|
||||||
FuncNode* _func;
|
FuncNode* _func;
|
||||||
//! Allocates `VirtReg` objects.
|
//! Allocates `VirtReg` objects.
|
||||||
@@ -90,10 +64,12 @@ public:
|
|||||||
//! Stores jump annotations.
|
//! Stores jump annotations.
|
||||||
ZoneVector<JumpAnnotation*> _jumpAnnotations;
|
ZoneVector<JumpAnnotation*> _jumpAnnotations;
|
||||||
|
|
||||||
//! Local constant pool, flushed at the end of each function.
|
//! Local and global constant pools.
|
||||||
ConstPoolNode* _localConstPool;
|
//!
|
||||||
//! Global constant pool, flushed by `finalize()`.
|
//! Local constant pool is flushed with each function, global constant pool is flushed only by \ref finalize().
|
||||||
ConstPoolNode* _globalConstPool;
|
ConstPoolNode* _constPools[2];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -108,31 +84,31 @@ public:
|
|||||||
//! \name Function Management
|
//! \name Function Management
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the current function.
|
|
||||||
inline FuncNode* func() const noexcept { return _func; }
|
|
||||||
|
|
||||||
//! Creates a new \ref FuncNode.
|
//! Creates a new \ref FuncNode.
|
||||||
ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature);
|
ASMJIT_API Error newFuncNode(FuncNode** out, const FuncSignature& signature);
|
||||||
//! Creates a new \ref FuncNode adds it to the compiler.
|
//! Creates a new \ref FuncNode adds it to the instruction stream.
|
||||||
ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature);
|
ASMJIT_API Error addFuncNode(FuncNode** out, const FuncSignature& signature);
|
||||||
|
|
||||||
//! Creates a new \ref FuncRetNode.
|
//! Creates a new \ref FuncRetNode.
|
||||||
ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
|
ASMJIT_API Error newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
|
||||||
//! Creates a new \ref FuncRetNode and adds it to the compiler.
|
//! Creates a new \ref FuncRetNode and adds it to the instruction stream.
|
||||||
ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
|
ASMJIT_API Error addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
|
||||||
|
|
||||||
|
//! Returns the current function.
|
||||||
|
inline FuncNode* func() const noexcept { return _func; }
|
||||||
|
|
||||||
//! Creates a new \ref FuncNode with the given `signature` and returns it.
|
//! Creates a new \ref FuncNode with the given `signature` and returns it.
|
||||||
inline FuncNode* newFunc(const FuncSignature& signature) {
|
inline FuncNode* newFunc(const FuncSignature& signature) {
|
||||||
FuncNode* node;
|
FuncNode* node;
|
||||||
_newFuncNode(&node, signature);
|
newFuncNode(&node, signature);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Creates a new \ref FuncNode with the given `signature`, adds it to the
|
//! Creates a new \ref FuncNode with the given `signature`, adds it to the instruction stream by using
|
||||||
//! compiler by using the \ref addFunc(FuncNode*) overload, and returns it.
|
//! the \ref addFunc(FuncNode*) overload, and returns it.
|
||||||
inline FuncNode* addFunc(const FuncSignature& signature) {
|
inline FuncNode* addFunc(const FuncSignature& signature) {
|
||||||
FuncNode* node;
|
FuncNode* node;
|
||||||
_addFuncNode(&node, signature);
|
addFuncNode(&node, signature);
|
||||||
return node;
|
return node;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -141,23 +117,21 @@ public:
|
|||||||
//! Emits a sentinel that marks the end of the current function.
|
//! Emits a sentinel that marks the end of the current function.
|
||||||
ASMJIT_API Error endFunc();
|
ASMJIT_API Error endFunc();
|
||||||
|
|
||||||
ASMJIT_API Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg);
|
#if !defined(ASMJIT_NO_DEPRECATED)
|
||||||
|
inline Error _setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg);
|
||||||
|
|
||||||
//! Sets a function argument at `argIndex` to `reg`.
|
//! Sets a function argument at `argIndex` to `reg`.
|
||||||
|
ASMJIT_DEPRECATED("Setting arguments through Compiler is deprecated, use FuncNode->setArg() instead")
|
||||||
inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); }
|
inline Error setArg(size_t argIndex, const BaseReg& reg) { return _setArg(argIndex, 0, reg); }
|
||||||
|
|
||||||
//! Sets a function argument at `argIndex` at `valueIndex` to `reg`.
|
//! Sets a function argument at `argIndex` at `valueIndex` to `reg`.
|
||||||
|
ASMJIT_DEPRECATED("Setting arguments through Compiler is deprecated, use FuncNode->setArg() instead")
|
||||||
inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); }
|
inline Error setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) { return _setArg(argIndex, valueIndex, reg); }
|
||||||
|
#endif
|
||||||
|
|
||||||
inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) {
|
inline Error addRet(const Operand_& o0, const Operand_& o1) {
|
||||||
FuncRetNode* node;
|
FuncRetNode* node;
|
||||||
_newRetNode(&node, o0, o1);
|
return addFuncRetNode(&node, o0, o1);
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) {
|
|
||||||
FuncRetNode* node;
|
|
||||||
_addRetNode(&node, o0, o1);
|
|
||||||
return node;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -166,23 +140,9 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new \ref InvokeNode.
|
//! Creates a new \ref InvokeNode.
|
||||||
ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
|
ASMJIT_API Error newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature);
|
||||||
//! Creates a new \ref InvokeNode and adds it to Compiler.
|
//! Creates a new \ref InvokeNode and adds it to the instruction stream.
|
||||||
ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
|
ASMJIT_API Error addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature);
|
||||||
|
|
||||||
//! Creates a new `InvokeNode`.
|
|
||||||
inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
|
|
||||||
InvokeNode* node;
|
|
||||||
_newInvokeNode(&node, instId, o0, signature);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Adds a new `InvokeNode`.
|
|
||||||
inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
|
|
||||||
InvokeNode* node;
|
|
||||||
_addInvokeNode(&node, instId, o0, signature);
|
|
||||||
return node;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -191,18 +151,17 @@ public:
|
|||||||
|
|
||||||
//! Creates a new virtual register representing the given `typeId` and `signature`.
|
//! Creates a new virtual register representing the given `typeId` and `signature`.
|
||||||
//!
|
//!
|
||||||
//! \note This function is public, but it's not generally recommended to be used
|
//! \note This function is public, but it's not generally recommended to be used by AsmJit users, use architecture
|
||||||
//! by AsmJit users, use architecture-specific `newReg()` functionality instead
|
//! specific `newReg()` functionality instead or functions like \ref _newReg() and \ref _newRegFmt().
|
||||||
//! or functions like \ref _newReg() and \ref _newRegFmt().
|
ASMJIT_API Error newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name);
|
||||||
ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t 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* out, uint32_t typeId, const char* name = nullptr);
|
ASMJIT_API Error _newReg(BaseReg* 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* out, uint32_t typeId, const char* fmt, ...);
|
ASMJIT_API Error _newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...);
|
||||||
|
|
||||||
//! 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* out, const BaseReg& ref, const char* name = nullptr);
|
ASMJIT_API Error _newReg(BaseReg* out, const BaseReg& ref, const char* name = nullptr);
|
||||||
@@ -233,9 +192,8 @@ public:
|
|||||||
|
|
||||||
//! Returns \ref VirtReg associated with the given virtual register `index`.
|
//! Returns \ref VirtReg associated with the given virtual register `index`.
|
||||||
//!
|
//!
|
||||||
//! \note This is not the same as virtual register id. The conversion between
|
//! \note This is not the same as virtual register id. The conversion between id and its index is implemented
|
||||||
//! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref
|
//! by \ref Operand_::virtIdToIndex() and \ref Operand_::indexToVirtId() functions.
|
||||||
//! Operand_::indexToVirtId() functions.
|
|
||||||
inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
|
inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
|
||||||
|
|
||||||
//! Returns an array of all virtual registers managed by the Compiler.
|
//! Returns an array of all virtual registers managed by the Compiler.
|
||||||
@@ -262,11 +220,11 @@ public:
|
|||||||
//! \name Constants
|
//! \name Constants
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new constant of the given `scope` (see \ref ConstPool::Scope).
|
//! Creates a new constant of the given `scope` (see \ref ConstPoolScope).
|
||||||
//!
|
//!
|
||||||
//! This function adds a constant of the given `size` to the built-in \ref
|
//! This function adds a constant of the given `size` to the built-in \ref ConstPool and stores the reference to that
|
||||||
//! ConstPool and stores the reference to that constant to the `out` operand.
|
//! constant to the `out` operand.
|
||||||
ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size);
|
ASMJIT_API Error _newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size);
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -285,23 +243,15 @@ public:
|
|||||||
return _jumpAnnotations;
|
return _jumpAnnotations;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation);
|
ASMJIT_API Error newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, const Operand_& o0, JumpAnnotation* annotation);
|
||||||
ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation);
|
ASMJIT_API Error emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation);
|
||||||
|
|
||||||
//! Returns a new `JumpAnnotation` instance, which can be used to aggregate
|
//! Returns a new `JumpAnnotation` instance, which can be used to aggregate possible targets of a jump where the
|
||||||
//! possible targets of a jump where the target is not a label, for example
|
//! target is not a label, for example to implement jump tables.
|
||||||
//! to implement jump tables.
|
|
||||||
ASMJIT_API JumpAnnotation* newJumpAnnotation();
|
ASMJIT_API JumpAnnotation* newJumpAnnotation();
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
ASMJIT_DEPRECATED("alloc() has no effect, it will be removed in the future")
|
|
||||||
inline void alloc(BaseReg&) {}
|
|
||||||
ASMJIT_DEPRECATED("spill() has no effect, it will be removed in the future")
|
|
||||||
inline void spill(BaseReg&) {}
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
//! \name Events
|
//! \name Events
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -311,22 +261,19 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::JumpAnnotation]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Jump annotation used to annotate jumps.
|
//! Jump annotation used to annotate jumps.
|
||||||
//!
|
//!
|
||||||
//! \ref BaseCompiler allows to emit jumps where the target is either register
|
//! \ref BaseCompiler allows to emit jumps where the target is either register or memory operand. Such jumps cannot be
|
||||||
//! or memory operand. Such jumps cannot be trivially inspected, so instead of
|
//! trivially inspected, so instead of doing heuristics AsmJit allows to annotate such jumps with possible targets.
|
||||||
//! doing heuristics AsmJit allows to annotate such jumps with possible targets.
|
//! Register allocator then uses the annotation to construct control-flow, which is then used by liveness analysis and
|
||||||
//! Register allocator then use the annotation to construct control-flow, which
|
//! other tools to prepare ground for register allocation.
|
||||||
//! is then used by liveness analysis and other tools to prepare ground for
|
|
||||||
//! register allocation.
|
|
||||||
class JumpAnnotation {
|
class JumpAnnotation {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(JumpAnnotation)
|
ASMJIT_NONCOPYABLE(JumpAnnotation)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Compiler that owns this JumpAnnotation.
|
//! Compiler that owns this JumpAnnotation.
|
||||||
BaseCompiler* _compiler;
|
BaseCompiler* _compiler;
|
||||||
//! Annotation identifier.
|
//! Annotation identifier.
|
||||||
@@ -334,10 +281,20 @@ public:
|
|||||||
//! Vector of label identifiers, see \ref labelIds().
|
//! Vector of label identifiers, see \ref labelIds().
|
||||||
ZoneVector<uint32_t> _labelIds;
|
ZoneVector<uint32_t> _labelIds;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
|
//! \{
|
||||||
|
|
||||||
inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept
|
inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept
|
||||||
: _compiler(compiler),
|
: _compiler(compiler),
|
||||||
_annotationId(annotationId) {}
|
_annotationId(annotationId) {}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Accessors
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Returns the compiler that owns this JumpAnnotation.
|
//! Returns the compiler that owns this JumpAnnotation.
|
||||||
inline BaseCompiler* compiler() const noexcept { return _compiler; }
|
inline BaseCompiler* compiler() const noexcept { return _compiler; }
|
||||||
//! Returns the annotation id.
|
//! Returns the annotation id.
|
||||||
@@ -350,35 +307,42 @@ public:
|
|||||||
//! Tests whether the given `labelId` is a target of this JumpAnnotation.
|
//! Tests whether the given `labelId` is a target of this JumpAnnotation.
|
||||||
inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); }
|
inline bool hasLabelId(uint32_t labelId) const noexcept { return _labelIds.contains(labelId); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Annotation Building API
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Adds the `label` to the list of targets of this JumpAnnotation.
|
//! Adds the `label` to the list of targets of this JumpAnnotation.
|
||||||
inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); }
|
inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); }
|
||||||
//! Adds the `labelId` to the list of targets of this JumpAnnotation.
|
//! Adds the `labelId` to the list of targets of this JumpAnnotation.
|
||||||
inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); }
|
inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); }
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
//! \}
|
||||||
// [asmjit::JumpNode]
|
};
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Jump instruction with \ref JumpAnnotation.
|
//! Jump instruction with \ref JumpAnnotation.
|
||||||
//!
|
//!
|
||||||
//! \note This node should be only used to represent jump where the jump target
|
//! \note This node should be only used to represent jump where the jump target cannot be deduced by examining
|
||||||
//! cannot be deduced by examining instruction operands. For example if the jump
|
//! instruction operands. For example if the jump target is register or memory location. This pattern is often
|
||||||
//! target is register or memory location. This pattern is often used to perform
|
//! used to perform indirect jumps that use jump table, e.g. to implement `switch{}` statement.
|
||||||
//! indirect jumps that use jump table, e.g. to implement `switch{}` statement.
|
|
||||||
class JumpNode : public InstNode {
|
class JumpNode : public InstNode {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(JumpNode)
|
ASMJIT_NONCOPYABLE(JumpNode)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
JumpAnnotation* _annotation;
|
JumpAnnotation* _annotation;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE JumpNode(BaseCompiler* cc, uint32_t instId, uint32_t options, uint32_t opCount, JumpAnnotation* annotation) noexcept
|
inline JumpNode(BaseCompiler* cc, InstId instId, InstOptions options, uint32_t opCount, JumpAnnotation* annotation) noexcept
|
||||||
: InstNode(cc, instId, options, opCount, kBaseOpCapacity),
|
: InstNode(cc, instId, options, opCount, kBaseOpCapacity),
|
||||||
_annotation(annotation) {
|
_annotation(annotation) {
|
||||||
setType(kNodeJump);
|
setType(NodeType::kJump);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -396,31 +360,24 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FuncNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Function node represents a function used by \ref BaseCompiler.
|
//! Function node represents a function used by \ref BaseCompiler.
|
||||||
//!
|
//!
|
||||||
//! A function is composed of the following:
|
//! A function is composed of the following:
|
||||||
//!
|
//!
|
||||||
//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit.
|
//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. To get the entry, simply use
|
||||||
//! To get the entry, simply use \ref FuncNode::label(), which is the same
|
//! \ref FuncNode::label(), which is the same as \ref LabelNode::label().
|
||||||
//! as \ref LabelNode::label().
|
|
||||||
//!
|
//!
|
||||||
//! - Function exit, which is represented by \ref FuncNode::exitNode(). A
|
//! - Function exit, which is represented by \ref FuncNode::exitNode(). A helper function
|
||||||
//! helper function \ref FuncNode::exitLabel() exists and returns an exit
|
//! \ref FuncNode::exitLabel() exists and returns an exit label instead of node.
|
||||||
//! label instead of node.
|
|
||||||
//!
|
//!
|
||||||
//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of
|
//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of a function - there should be no
|
||||||
//! a function - there should be no code that belongs to the function after
|
//! code that belongs to the function after this node, but the Compiler doesn't enforce that at the moment.
|
||||||
//! this node, but the Compiler doesn't enforce that at the moment.
|
|
||||||
//!
|
//!
|
||||||
//! - Function detail, see \ref FuncNode::detail().
|
//! - Function detail, see \ref FuncNode::detail().
|
||||||
//!
|
//!
|
||||||
//! - Function frame, see \ref FuncNode::frame().
|
//! - Function frame, see \ref FuncNode::frame().
|
||||||
//!
|
//!
|
||||||
//! - Function arguments mapped to virtual registers, see \ref FuncNode::args().
|
//! - Function arguments mapped to virtual registers, see \ref FuncNode::argPacks().
|
||||||
//!
|
//!
|
||||||
//! In a node list, the function and its body looks like the following:
|
//! In a node list, the function and its body looks like the following:
|
||||||
//!
|
//!
|
||||||
@@ -439,29 +396,30 @@ public:
|
|||||||
//! [...] - Anything after the function.
|
//! [...] - Anything after the function.
|
||||||
//! \endcode
|
//! \endcode
|
||||||
//!
|
//!
|
||||||
//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it
|
//! When a function is added to the instruction stream by \ref BaseCompiler::addFunc() it actually inserts 3 nodes
|
||||||
//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the
|
//! (FuncNode, ExitLabel, and FuncEnd) and sets the current cursor to be FuncNode. When \ref BaseCompiler::endFunc()
|
||||||
//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called
|
//! is called the cursor is set to FuncEnd. This guarantees that user can use ExitLabel as a marker after additional
|
||||||
//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel
|
//! code or data can be placed, which is a common practice.
|
||||||
//! as a marker after additional code or data can be placed, and it's a common
|
|
||||||
//! practice.
|
|
||||||
class FuncNode : public LabelNode {
|
class FuncNode : public LabelNode {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(FuncNode)
|
ASMJIT_NONCOPYABLE(FuncNode)
|
||||||
|
|
||||||
//! Arguments pack.
|
//! Arguments pack.
|
||||||
struct ArgPack {
|
struct ArgPack {
|
||||||
VirtReg* _data[Globals::kMaxValuePack];
|
RegOnly _data[Globals::kMaxValuePack];
|
||||||
|
|
||||||
inline void reset() noexcept {
|
inline void reset() noexcept {
|
||||||
for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
|
for (size_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++)
|
||||||
_data[valueIndex] = nullptr;
|
_data[valueIndex].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline VirtReg*& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; }
|
inline RegOnly& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; }
|
||||||
inline VirtReg* const& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
|
inline const RegOnly& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Function detail.
|
//! Function detail.
|
||||||
FuncDetail _funcDetail;
|
FuncDetail _funcDetail;
|
||||||
//! Function frame.
|
//! Function frame.
|
||||||
@@ -470,24 +428,25 @@ public:
|
|||||||
LabelNode* _exitNode;
|
LabelNode* _exitNode;
|
||||||
//! Function end (sentinel).
|
//! Function end (sentinel).
|
||||||
SentinelNode* _end;
|
SentinelNode* _end;
|
||||||
|
|
||||||
//! Argument packs.
|
//! Argument packs.
|
||||||
ArgPack* _args;
|
ArgPack* _args;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `FuncNode` instance.
|
//! Creates a new `FuncNode` instance.
|
||||||
//!
|
//!
|
||||||
//! Always use `BaseCompiler::addFunc()` to create `FuncNode`.
|
//! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`.
|
||||||
ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept
|
inline FuncNode(BaseBuilder* cb) noexcept
|
||||||
: LabelNode(cb),
|
: LabelNode(cb),
|
||||||
_funcDetail(),
|
_funcDetail(),
|
||||||
_frame(),
|
_frame(),
|
||||||
_exitNode(nullptr),
|
_exitNode(nullptr),
|
||||||
_end(nullptr),
|
_end(nullptr),
|
||||||
_args(nullptr) {
|
_args(nullptr) {
|
||||||
setType(kNodeFunc);
|
setType(NodeType::kFunc);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -500,12 +459,12 @@ public:
|
|||||||
//! Returns function exit label.
|
//! Returns function exit label.
|
||||||
inline Label exitLabel() const noexcept { return _exitNode->label(); }
|
inline Label exitLabel() const noexcept { return _exitNode->label(); }
|
||||||
|
|
||||||
//! Returns "End of Func" sentinel.
|
//! Returns "End of Func" sentinel node.
|
||||||
inline SentinelNode* endNode() const noexcept { return _end; }
|
inline SentinelNode* endNode() const noexcept { return _end; }
|
||||||
|
|
||||||
//! Returns function declaration.
|
//! Returns function detail.
|
||||||
inline FuncDetail& detail() noexcept { return _funcDetail; }
|
inline FuncDetail& detail() noexcept { return _funcDetail; }
|
||||||
//! Returns function declaration.
|
//! Returns function detail.
|
||||||
inline const FuncDetail& detail() const noexcept { return _funcDetail; }
|
inline const FuncDetail& detail() const noexcept { return _funcDetail; }
|
||||||
|
|
||||||
//! Returns function frame.
|
//! Returns function frame.
|
||||||
@@ -513,14 +472,19 @@ public:
|
|||||||
//! Returns function frame.
|
//! Returns function frame.
|
||||||
inline const FuncFrame& frame() const noexcept { return _frame; }
|
inline const FuncFrame& frame() const noexcept { return _frame; }
|
||||||
|
|
||||||
//! Tests whether the function has a return value.
|
//! Returns function attributes.
|
||||||
inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
|
inline FuncAttributes attributes() const noexcept { return _frame.attributes(); }
|
||||||
|
//! Adds `attrs` to the function attributes.
|
||||||
|
inline void addAttributes(FuncAttributes attrs) noexcept { _frame.addAttributes(attrs); }
|
||||||
|
|
||||||
//! Returns arguments count.
|
//! Returns arguments count.
|
||||||
inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
|
inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
|
||||||
|
|
||||||
//! Returns argument packs.
|
//! Returns argument packs.
|
||||||
inline ArgPack* argPacks() const noexcept { return _args; }
|
inline ArgPack* argPacks() const noexcept { return _args; }
|
||||||
|
|
||||||
|
//! Tests whether the function has a return value.
|
||||||
|
inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
|
||||||
|
|
||||||
//! Returns argument pack at `argIndex`.
|
//! Returns argument pack at `argIndex`.
|
||||||
inline ArgPack& argPack(size_t argIndex) const noexcept {
|
inline ArgPack& argPack(size_t argIndex) const noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
@@ -528,15 +492,27 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Sets argument at `argIndex`.
|
//! Sets argument at `argIndex`.
|
||||||
inline void setArg(size_t argIndex, VirtReg* vReg) noexcept {
|
inline void setArg(size_t argIndex, const BaseReg& vReg) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
_args[argIndex][0] = vReg;
|
_args[argIndex][0].init(vReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \overload
|
||||||
|
inline void setArg(size_t argIndex, const RegOnly& vReg) noexcept {
|
||||||
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
|
_args[argIndex][0].init(vReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Sets argument at `argIndex` and `valueIndex`.
|
//! Sets argument at `argIndex` and `valueIndex`.
|
||||||
inline void setArg(size_t argIndex, size_t valueIndex, VirtReg* vReg) noexcept {
|
inline void setArg(size_t argIndex, size_t valueIndex, const BaseReg& vReg) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
_args[argIndex][valueIndex] = vReg;
|
_args[argIndex][valueIndex].init(vReg);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \overload
|
||||||
|
inline void setArg(size_t argIndex, size_t valueIndex, const RegOnly& vReg) noexcept {
|
||||||
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
|
_args[argIndex][valueIndex].init(vReg);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Resets argument pack at `argIndex`.
|
//! Resets argument pack at `argIndex`.
|
||||||
@@ -548,21 +524,12 @@ public:
|
|||||||
//! Resets argument pack at `argIndex`.
|
//! Resets argument pack at `argIndex`.
|
||||||
inline void resetArg(size_t argIndex, size_t valueIndex) noexcept {
|
inline void resetArg(size_t argIndex, size_t valueIndex) noexcept {
|
||||||
ASMJIT_ASSERT(argIndex < argCount());
|
ASMJIT_ASSERT(argIndex < argCount());
|
||||||
_args[argIndex][valueIndex] = nullptr;
|
_args[argIndex][valueIndex].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns function attributes.
|
|
||||||
inline uint32_t attributes() const noexcept { return _frame.attributes(); }
|
|
||||||
//! Adds `attrs` to the function attributes.
|
|
||||||
inline void addAttributes(uint32_t attrs) noexcept { _frame.addAttributes(attrs); }
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FuncRetNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Function return, used by \ref BaseCompiler.
|
//! Function return, used by \ref BaseCompiler.
|
||||||
class FuncRetNode : public InstNode {
|
class FuncRetNode : public InstNode {
|
||||||
public:
|
public:
|
||||||
@@ -572,27 +539,21 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `FuncRetNode` instance.
|
//! Creates a new `FuncRetNode` instance.
|
||||||
inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) {
|
inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) {
|
||||||
_any._nodeType = kNodeFuncRet;
|
_any._nodeType = NodeType::kFuncRet;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::InvokeNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Function invocation, used by \ref BaseCompiler.
|
//! Function invocation, used by \ref BaseCompiler.
|
||||||
class InvokeNode : public InstNode {
|
class InvokeNode : public InstNode {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(InvokeNode)
|
ASMJIT_NONCOPYABLE(InvokeNode)
|
||||||
|
|
||||||
//! Operand pack provides multiple operands that can be associated with a
|
//! Operand pack provides multiple operands that can be associated with a single return value of function
|
||||||
//! single return value of function argument. Sometimes this is necessary to
|
//! argument. Sometims this is necessary to express an argument or return value that requires multiple
|
||||||
//! express an argument or return value that requires multiple registers, for
|
//! registers, for example 64-bit value in 32-bit mode or passing / returning homogeneous data structures.
|
||||||
//! example 64-bit value in 32-bit mode or passing / returning homogeneous data
|
|
||||||
//! structures.
|
|
||||||
struct OperandPack {
|
struct OperandPack {
|
||||||
//! Operands.
|
//! Operands.
|
||||||
Operand_ _data[Globals::kMaxValuePack];
|
Operand_ _data[Globals::kMaxValuePack];
|
||||||
@@ -616,6 +577,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Function detail.
|
//! Function detail.
|
||||||
FuncDetail _funcDetail;
|
FuncDetail _funcDetail;
|
||||||
//! Function return value(s).
|
//! Function return value(s).
|
||||||
@@ -623,18 +587,20 @@ public:
|
|||||||
//! Function arguments.
|
//! Function arguments.
|
||||||
OperandPack* _args;
|
OperandPack* _args;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new `InvokeNode` instance.
|
//! Creates a new `InvokeNode` instance.
|
||||||
inline InvokeNode(BaseBuilder* cb, uint32_t instId, uint32_t options) noexcept
|
inline InvokeNode(BaseBuilder* cb, InstId instId, InstOptions options) noexcept
|
||||||
: InstNode(cb, instId, options, kBaseOpCapacity),
|
: InstNode(cb, instId, options, kBaseOpCapacity),
|
||||||
_funcDetail(),
|
_funcDetail(),
|
||||||
_args(nullptr) {
|
_args(nullptr) {
|
||||||
setType(kNodeInvoke);
|
setType(NodeType::kInvoke);
|
||||||
_resetOps();
|
_resetOps();
|
||||||
_rets.reset();
|
_rets.reset();
|
||||||
addFlags(kFlagIsRemovable);
|
addFlags(NodeFlags::kIsRemovable);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -718,10 +684,6 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FuncPass]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction().
|
//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction().
|
||||||
class ASMJIT_VIRTAPI FuncPass : public Pass {
|
class ASMJIT_VIRTAPI FuncPass : public Pass {
|
||||||
public:
|
public:
|
||||||
@@ -743,7 +705,7 @@ public:
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Run
|
//! \name Pass Interface
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Calls `runOnFunction()` on each `FuncNode` node found.
|
//! Calls `runOnFunction()` on each `FuncNode` node found.
|
||||||
@@ -755,6 +717,18 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if !defined(ASMJIT_NO_DEPRECATED)
|
||||||
|
inline Error BaseCompiler::_setArg(size_t argIndex, size_t valueIndex, const BaseReg& reg) {
|
||||||
|
FuncNode* func = _func;
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(!func))
|
||||||
|
return reportError(DebugUtils::errored(kErrorInvalidState));
|
||||||
|
|
||||||
|
func->setArg(argIndex, valueIndex, reg);
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|||||||
@@ -1,63 +1,41 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
||||||
#define ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
#define ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/api-config.h"
|
#include "../core/api-config.h"
|
||||||
#include "../core/operand.h"
|
#include "../core/operand.h"
|
||||||
|
#include "../core/type.h"
|
||||||
#include "../core/zonestring.h"
|
#include "../core/zonestring.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class RAWorkReg;
|
class RAWorkReg;
|
||||||
|
|
||||||
//! \addtogroup asmjit_compiler
|
//! \addtogroup asmjit_compiler
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::VirtReg]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Virtual register data, managed by \ref BaseCompiler.
|
//! Virtual register data, managed by \ref BaseCompiler.
|
||||||
class VirtReg {
|
class VirtReg {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(VirtReg)
|
ASMJIT_NONCOPYABLE(VirtReg)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Virtual register signature.
|
||||||
|
OperandSignature _signature {};
|
||||||
//! Virtual register id.
|
//! Virtual register id.
|
||||||
uint32_t _id = 0;
|
uint32_t _id = 0;
|
||||||
//! Virtual register info (signature).
|
//! Virtual register size (can be smaller than `_signature._size`).
|
||||||
RegInfo _info = {};
|
|
||||||
//! Virtual register size (can be smaller than `regInfo._size`).
|
|
||||||
uint32_t _virtSize = 0;
|
uint32_t _virtSize = 0;
|
||||||
//! Virtual register alignment (for spilling).
|
//! Virtual register alignment (for spilling).
|
||||||
uint8_t _alignment = 0;
|
uint8_t _alignment = 0;
|
||||||
//! Type-id.
|
//! Type-id.
|
||||||
uint8_t _typeId = 0;
|
TypeId _typeId = TypeId::kVoid;
|
||||||
//! Virtual register weight for alloc/spill decisions.
|
//! Virtual register weight for alloc/spill decisions.
|
||||||
uint8_t _weight = 1;
|
uint8_t _weight = 1;
|
||||||
//! True if this is a fixed register, never reallocated.
|
//! True if this is a fixed register, never reallocated.
|
||||||
@@ -69,24 +47,23 @@ public:
|
|||||||
//! Virtual register name (user provided or automatically generated).
|
//! Virtual register name (user provided or automatically generated).
|
||||||
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
|
// null pointers and then changed during RAPass execution. RAPass sets them back to NULL before it returns.
|
||||||
// when the VirtReg is created to NULL pointers and then changed during RAPass
|
|
||||||
// execution. RAPass sets them back to NULL before it returns.
|
|
||||||
// -------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//! Reference to `RAWorkReg`, used during register allocation.
|
//! Reference to `RAWorkReg`, used during register allocation.
|
||||||
RAWorkReg* _workReg = nullptr;
|
RAWorkReg* _workReg = nullptr;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept
|
inline VirtReg(const OperandSignature& signature, uint32_t id, uint32_t virtSize, uint32_t alignment, TypeId typeId) noexcept
|
||||||
: _id(id),
|
: _signature(signature),
|
||||||
_info { signature },
|
_id(id),
|
||||||
_virtSize(virtSize),
|
_virtSize(virtSize),
|
||||||
_alignment(uint8_t(alignment)),
|
_alignment(uint8_t(alignment)),
|
||||||
_typeId(uint8_t(typeId)),
|
_typeId(typeId),
|
||||||
_isFixed(false),
|
_isFixed(false),
|
||||||
_isStack(false),
|
_isStack(false),
|
||||||
_reserved(0) {}
|
_reserved(0) {}
|
||||||
@@ -104,56 +81,50 @@ public:
|
|||||||
//! Returns the size of the virtual register name.
|
//! Returns the size of the virtual register name.
|
||||||
inline uint32_t nameSize() const noexcept { return _name.size(); }
|
inline uint32_t nameSize() const noexcept { return _name.size(); }
|
||||||
|
|
||||||
//! Returns a register information that wraps the register signature.
|
//! Returns a register signature of this virtual register.
|
||||||
inline const RegInfo& info() const noexcept { return _info; }
|
inline OperandSignature signature() const noexcept { return _signature; }
|
||||||
//! Returns a virtual register type (maps to the physical register type as well).
|
//! Returns a virtual register type (maps to the physical register type as well).
|
||||||
inline uint32_t type() const noexcept { return _info.type(); }
|
inline RegType type() const noexcept { return _signature.regType(); }
|
||||||
//! Returns a virtual register group (maps to the physical register group as well).
|
//! Returns a virtual register group (maps to the physical register group as well).
|
||||||
inline uint32_t group() const noexcept { return _info.group(); }
|
inline RegGroup group() const noexcept { return _signature.regGroup(); }
|
||||||
|
|
||||||
//! Returns a real size of the register this virtual register maps to.
|
//! Returns a real size of the register this virtual register maps to.
|
||||||
//!
|
//!
|
||||||
//! For example if this is a 128-bit SIMD register used for a scalar single
|
//! For example if this is a 128-bit SIMD register used for a scalar single precision floating point value then
|
||||||
//! precision floating point value then its virtSize would be 4, however, the
|
//! its virtSize would be 4, however, the `regSize` would still say 16 (128-bits), because it's the smallest size
|
||||||
//! `regSize` would still say 16 (128-bits), because it's the smallest size
|
|
||||||
//! of that register type.
|
//! of that register type.
|
||||||
inline uint32_t regSize() const noexcept { return _info.size(); }
|
inline uint32_t regSize() const noexcept { return _signature.size(); }
|
||||||
|
|
||||||
//! Returns a register signature of this virtual register.
|
|
||||||
inline uint32_t signature() const noexcept { return _info.signature(); }
|
|
||||||
|
|
||||||
//! Returns the virtual register size.
|
//! Returns the virtual register size.
|
||||||
//!
|
//!
|
||||||
//! The virtual register size describes how many bytes the virtual register
|
//! The virtual register size describes how many bytes the virtual register needs to store its content. It can be
|
||||||
//! needs to store its content. It can be smaller than the physical register
|
//! smaller than the physical register size, see `regSize()`.
|
||||||
//! size, see `regSize()`.
|
|
||||||
inline uint32_t virtSize() const noexcept { return _virtSize; }
|
inline uint32_t virtSize() const noexcept { return _virtSize; }
|
||||||
|
|
||||||
//! Returns the virtual register alignment.
|
//! Returns the virtual register alignment.
|
||||||
inline uint32_t alignment() const noexcept { return _alignment; }
|
inline uint32_t alignment() const noexcept { return _alignment; }
|
||||||
|
|
||||||
//! Returns the virtual register type id, see `Type::Id`.
|
//! Returns the virtual register type id.
|
||||||
inline uint32_t typeId() const noexcept { return _typeId; }
|
inline TypeId typeId() const noexcept { return _typeId; }
|
||||||
|
|
||||||
//! Returns the virtual register weight - the register allocator can use it
|
//! Returns the virtual register weight - the register allocator can use it as explicit hint for alloc/spill
|
||||||
//! as explicit hint for alloc/spill decisions.
|
//! decisions.
|
||||||
inline uint32_t weight() const noexcept { return _weight; }
|
inline uint32_t weight() const noexcept { return _weight; }
|
||||||
//! Sets the virtual register weight (0 to 255) - the register allocator can
|
//! Sets the virtual register weight (0 to 255) - the register allocator can use it as explicit hint for
|
||||||
//! use it as explicit hint for alloc/spill decisions and initial bin-packing.
|
//! alloc/spill decisions and initial bin-packing.
|
||||||
inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); }
|
inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); }
|
||||||
|
|
||||||
//! Returns whether the virtual register is always allocated to a fixed
|
//! Returns whether the virtual register is always allocated to a fixed physical register (and never reallocated).
|
||||||
//! physical register (and never reallocated).
|
|
||||||
//!
|
//!
|
||||||
//! \note This is only used for special purposes and it's mostly internal.
|
//! \note This is only used for special purposes and it's mostly internal.
|
||||||
inline bool isFixed() const noexcept { return bool(_isFixed); }
|
inline bool isFixed() const noexcept { return bool(_isFixed); }
|
||||||
|
|
||||||
//! Returns whether the virtual register is indeed a stack that only uses
|
//! Tests whether the virtual register is in fact a stack that only uses the virtual register id.
|
||||||
//! the virtual register id for making it accessible.
|
|
||||||
//!
|
//!
|
||||||
//! \note It's an error if a stack is accessed as a register.
|
//! \note It's an error if a stack is accessed as a register.
|
||||||
inline bool isStack() const noexcept { return bool(_isStack); }
|
inline bool isStack() const noexcept { return bool(_isStack); }
|
||||||
|
|
||||||
|
//! Tests whether the virtual register has an associated `RAWorkReg` at the moment.
|
||||||
inline bool hasWorkReg() const noexcept { return _workReg != nullptr; }
|
inline bool hasWorkReg() const noexcept { return _workReg != nullptr; }
|
||||||
inline RAWorkReg* workReg() const noexcept { return _workReg; }
|
inline RAWorkReg* workReg() const noexcept { return _workReg; }
|
||||||
inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; }
|
inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; }
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/constpool.h"
|
#include "../core/constpool.h"
|
||||||
@@ -27,16 +9,14 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ConstPool - Construction & Destruction
|
||||||
// [asmjit::ConstPool - Construction / Destruction]
|
// ======================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); }
|
ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); }
|
||||||
ConstPool::~ConstPool() noexcept {}
|
ConstPool::~ConstPool() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
// ConstPool - Reset
|
||||||
// [asmjit::ConstPool - Reset]
|
// =================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void ConstPool::reset(Zone* zone) noexcept {
|
void ConstPool::reset(Zone* zone) noexcept {
|
||||||
_zone = zone;
|
_zone = zone;
|
||||||
@@ -55,11 +35,10 @@ void ConstPool::reset(Zone* zone) noexcept {
|
|||||||
_minItemSize = 0;
|
_minItemSize = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ConstPool - Operations
|
||||||
// [asmjit::ConstPool - Ops]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static ASMJIT_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->allocT<ConstPool::Gap>();
|
||||||
@@ -68,7 +47,7 @@ static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcep
|
|||||||
return gap;
|
return gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept {
|
static inline void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) noexcept {
|
||||||
gap->_next = self->_gapPool;
|
gap->_next = self->_gapPool;
|
||||||
self->_gapPool = gap;
|
self->_gapPool = gap;
|
||||||
}
|
}
|
||||||
@@ -80,7 +59,11 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t size) noexce
|
|||||||
size_t gapIndex;
|
size_t gapIndex;
|
||||||
size_t gapSize;
|
size_t gapSize;
|
||||||
|
|
||||||
if (size >= 16 && Support::isAligned<size_t>(offset, 16)) {
|
if (size >= 32 && Support::isAligned<size_t>(offset, 32)) {
|
||||||
|
gapIndex = ConstPool::kIndex32;
|
||||||
|
gapSize = 32;
|
||||||
|
}
|
||||||
|
else if (size >= 16 && Support::isAligned<size_t>(offset, 16)) {
|
||||||
gapIndex = ConstPool::kIndex16;
|
gapIndex = ConstPool::kIndex16;
|
||||||
gapSize = 16;
|
gapSize = 16;
|
||||||
}
|
}
|
||||||
@@ -101,9 +84,8 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t size) noexce
|
|||||||
gapSize = 1;
|
gapSize = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We don't have to check for errors here, if this failed nothing really
|
// We don't have to check for errors here, if this failed nothing really happened (just the gap won't be
|
||||||
// happened (just the gap won't be visible) and it will fail again at
|
// visible) and it will fail again at place where the same check would generate `kErrorOutOfMemory` error.
|
||||||
// place where the same check would generate `kErrorOutOfMemory` error.
|
|
||||||
ConstPool::Gap* gap = ConstPool_allocGap(self);
|
ConstPool::Gap* gap = ConstPool_allocGap(self);
|
||||||
if (!gap)
|
if (!gap)
|
||||||
return;
|
return;
|
||||||
@@ -122,7 +104,9 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t size) noexce
|
|||||||
Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept {
|
Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept {
|
||||||
size_t treeIndex;
|
size_t treeIndex;
|
||||||
|
|
||||||
if (size == 32)
|
if (size == 64)
|
||||||
|
treeIndex = kIndex64;
|
||||||
|
else if (size == 32)
|
||||||
treeIndex = kIndex32;
|
treeIndex = kIndex32;
|
||||||
else if (size == 16)
|
else if (size == 16)
|
||||||
treeIndex = kIndex16;
|
treeIndex = kIndex16;
|
||||||
@@ -143,8 +127,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Before incrementing the current offset try if there is a gap that can
|
// Before incrementing the current offset try if there is a gap that can be used for the requested data.
|
||||||
// be used for the requested data.
|
|
||||||
size_t offset = ~size_t(0);
|
size_t offset = ~size_t(0);
|
||||||
size_t gapIndex = treeIndex;
|
size_t gapIndex = treeIndex;
|
||||||
|
|
||||||
@@ -172,8 +155,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (offset == ~size_t(0)) {
|
if (offset == ~size_t(0)) {
|
||||||
// Get how many bytes have to be skipped so the address is aligned accordingly
|
// Get how many bytes have to be skipped so the address is aligned accordingly to the 'size'.
|
||||||
// to the 'size'.
|
|
||||||
size_t diff = Support::alignUpDiff<size_t>(_size, size);
|
size_t diff = Support::alignUpDiff<size_t>(_size, size);
|
||||||
|
|
||||||
if (diff != 0) {
|
if (diff != 0) {
|
||||||
@@ -195,9 +177,8 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
|
|
||||||
dstOffset = offset;
|
dstOffset = offset;
|
||||||
|
|
||||||
// Now create a bunch of shared constants that are based on the data pattern.
|
// Now create a bunch of shared constants that are based on the data pattern. We stop at size 4,
|
||||||
// We stop at size 4, it probably doesn't make sense to split constants down
|
// it probably doesn't make sense to split constants down to 1 byte.
|
||||||
// to 1 byte.
|
|
||||||
size_t pCount = 1;
|
size_t pCount = 1;
|
||||||
size_t smallerSize = size;
|
size_t smallerSize = size;
|
||||||
|
|
||||||
@@ -226,9 +207,8 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ConstPool - Reset
|
||||||
// [asmjit::ConstPool - Reset]
|
// =================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
struct ConstPoolFill {
|
struct ConstPoolFill {
|
||||||
inline ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept :
|
inline ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept :
|
||||||
@@ -255,9 +235,8 @@ void ConstPool::fill(void* dst) const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ConstPool - Tests
|
||||||
// [asmjit::ConstPool - Unit]
|
// =================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
UNIT(const_pool) {
|
UNIT(const_pool) {
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
||||||
#define ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
#define ASMJIT_CORE_CONSTPOOL_H_INCLUDED
|
||||||
@@ -33,23 +15,22 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_utilities
|
//! \addtogroup asmjit_utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Constant pool scope.
|
||||||
// [asmjit::ConstPool]
|
enum class ConstPoolScope : uint32_t {
|
||||||
// ============================================================================
|
//! Local constant, always embedded right after the current function.
|
||||||
|
kLocal = 0,
|
||||||
|
//! Global constant, embedded at the end of the currently compiled code.
|
||||||
|
kGlobal = 1,
|
||||||
|
|
||||||
|
//! Maximum value of `ConstPoolScope`.
|
||||||
|
kMaxValue = kGlobal
|
||||||
|
};
|
||||||
|
|
||||||
//! Constant pool.
|
//! Constant pool.
|
||||||
class ConstPool {
|
class ConstPool {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ConstPool)
|
ASMJIT_NONCOPYABLE(ConstPool)
|
||||||
|
|
||||||
//! Constant pool scope.
|
|
||||||
enum Scope : uint32_t {
|
|
||||||
//! Local constant, always embedded right after the current function.
|
|
||||||
kScopeLocal = 0,
|
|
||||||
//! Global constant, embedded at the end of the currently compiled code.
|
|
||||||
kScopeGlobal = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
|
|
||||||
//! Index of a given size in const-pool table.
|
//! Index of a given size in const-pool table.
|
||||||
@@ -60,7 +41,8 @@ public:
|
|||||||
kIndex8 = 3,
|
kIndex8 = 3,
|
||||||
kIndex16 = 4,
|
kIndex16 = 4,
|
||||||
kIndex32 = 5,
|
kIndex32 = 5,
|
||||||
kIndexCount = 6
|
kIndex64 = 6,
|
||||||
|
kIndexCount = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Zone-allocated const-pool gap created by two differently aligned constants.
|
//! Zone-allocated const-pool gap created by two differently aligned constants.
|
||||||
@@ -193,6 +175,9 @@ public:
|
|||||||
|
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Zone allocator.
|
//! Zone allocator.
|
||||||
Zone* _zone;
|
Zone* _zone;
|
||||||
//! Tree per size.
|
//! Tree per size.
|
||||||
@@ -209,6 +194,8 @@ public:
|
|||||||
//! Minimum item size in the pool.
|
//! Minimum item size in the pool.
|
||||||
size_t _minItemSize;
|
size_t _minItemSize;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -238,21 +225,18 @@ public:
|
|||||||
|
|
||||||
//! Adds a constant to the constant pool.
|
//! Adds a constant to the constant pool.
|
||||||
//!
|
//!
|
||||||
//! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes.
|
//! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes. The constant is added to the pool only
|
||||||
//! The constant is added to the pool only if it doesn't not exist, otherwise
|
//! if it doesn't not exist, otherwise cached value is returned.
|
||||||
//! cached value is returned.
|
|
||||||
//!
|
//!
|
||||||
//! AsmJit is able to subdivide added constants, so for example if you add
|
//! AsmJit is able to subdivide added constants, so for example if you add 8-byte constant 0x1122334455667788 it
|
||||||
//! 8-byte constant 0x1122334455667788 it will create the following slots:
|
//! will create the following slots:
|
||||||
//!
|
//!
|
||||||
//! 8-byte: 0x1122334455667788
|
//! 8-byte: 0x1122334455667788
|
||||||
//! 4-byte: 0x11223344, 0x55667788
|
//! 4-byte: 0x11223344, 0x55667788
|
||||||
//!
|
//!
|
||||||
//! The reason is that when combining MMX/SSE/AVX code some patterns are used
|
//! The reason is that when combining MMX/SSE/AVX code some patterns are used frequently. However, AsmJit is not
|
||||||
//! frequently. However, AsmJit is not able to reallocate a constant that has
|
//! able to reallocate a constant that has been already added. For example if you try to add 4-byte constant and
|
||||||
//! been already added. For example if you try to add 4-byte constant and then
|
//! then 8-byte constant having the same 4-byte pattern as the previous one, two independent slots will be used.
|
||||||
//! 8-byte constant having the same 4-byte pattern as the previous one, two
|
|
||||||
//! independent slots will be generated by the pool.
|
|
||||||
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
|
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
|
||||||
|
|
||||||
//! Fills the destination with the content of this constant pool.
|
//! Fills the destination with the content of this constant pool.
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,52 +1,679 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED
|
#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED
|
||||||
#define ASMJIT_CORE_CPUINFO_H_INCLUDED
|
#define ASMJIT_CORE_CPUINFO_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/archtraits.h"
|
#include "../core/archtraits.h"
|
||||||
#include "../core/features.h"
|
#include "../core/environment.h"
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
#include "../core/string.h"
|
#include "../core/string.h"
|
||||||
|
#include "../core/support.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! CPU features information.
|
||||||
// [asmjit::CpuInfo]
|
//!
|
||||||
// ============================================================================
|
//! Each feature is represented by a single bit in an embedded bit array.
|
||||||
|
class CpuFeatures {
|
||||||
|
public:
|
||||||
|
//! A word that is used to represents feature bits.
|
||||||
|
typedef Support::BitWord BitWord;
|
||||||
|
//! Iterator that can iterate all CPU features set.
|
||||||
|
typedef Support::BitVectorIterator<BitWord> Iterator;
|
||||||
|
|
||||||
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
enum : uint32_t {
|
||||||
|
kMaxFeatures = 256,
|
||||||
|
kNumBitWords = kMaxFeatures / Support::kBitWordSizeInBits
|
||||||
|
};
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Data
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! CPU features data.
|
||||||
|
struct Data {
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Data bits.
|
||||||
|
Support::Array<BitWord, kNumBitWords> _bits;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Overloaded Operators
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
inline bool operator==(const Data& other) noexcept { return eq(other); }
|
||||||
|
inline bool operator!=(const Data& other) noexcept { return !eq(other); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Accessors
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Returns true if there are no features set.
|
||||||
|
inline bool empty() const noexcept { return _bits.aggregate<Support::Or>(0) == 0; }
|
||||||
|
|
||||||
|
//! Returns all features as array of bitwords (see \ref Support::BitWord).
|
||||||
|
inline BitWord* bits() noexcept { return _bits.data(); }
|
||||||
|
//! Returns all features as array of bitwords (const).
|
||||||
|
inline const BitWord* bits() const noexcept { return _bits.data(); }
|
||||||
|
|
||||||
|
//! Returns the number of BitWords returned by \ref bits().
|
||||||
|
inline size_t bitWordCount() const noexcept { return kNumBitWords; }
|
||||||
|
|
||||||
|
//! Returns \ref Support::BitVectorIterator, that can be used to iterate over all features efficiently.
|
||||||
|
inline Iterator iterator() const noexcept { return Iterator(_bits.data(), kNumBitWords); }
|
||||||
|
|
||||||
|
//! Tests whether the feature `featureId` is present.
|
||||||
|
template<typename FeatureId>
|
||||||
|
ASMJIT_FORCE_INLINE bool has(const FeatureId& featureId) const noexcept {
|
||||||
|
ASMJIT_ASSERT(uint32_t(featureId) < kMaxFeatures);
|
||||||
|
|
||||||
|
uint32_t idx = uint32_t(featureId) / Support::kBitWordSizeInBits;
|
||||||
|
uint32_t bit = uint32_t(featureId) % Support::kBitWordSizeInBits;
|
||||||
|
|
||||||
|
return bool((_bits[idx] >> bit) & 0x1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Tests whether all features as defined by `other` are present.
|
||||||
|
ASMJIT_FORCE_INLINE bool hasAll(const Data& other) const noexcept {
|
||||||
|
for (uint32_t i = 0; i < kNumBitWords; i++)
|
||||||
|
if ((_bits[i] & other._bits[i]) != other._bits[i])
|
||||||
|
return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Manipulation
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
inline void reset() noexcept { _bits.fill(0); }
|
||||||
|
|
||||||
|
//! Adds the given CPU `featureId` to the list of features.
|
||||||
|
template<typename FeatureId>
|
||||||
|
ASMJIT_FORCE_INLINE void add(const FeatureId& featureId) noexcept {
|
||||||
|
ASMJIT_ASSERT(uint32_t(featureId) < kMaxFeatures);
|
||||||
|
|
||||||
|
uint32_t idx = uint32_t(featureId) / Support::kBitWordSizeInBits;
|
||||||
|
uint32_t bit = uint32_t(featureId) % Support::kBitWordSizeInBits;
|
||||||
|
|
||||||
|
_bits[idx] |= BitWord(1) << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FeatureId, typename... Args>
|
||||||
|
ASMJIT_FORCE_INLINE void add(const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
|
||||||
|
add(featureId);
|
||||||
|
add(std::forward<Args>(otherFeatureIds)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FeatureId>
|
||||||
|
ASMJIT_FORCE_INLINE void addIf(bool condition, const FeatureId& featureId) noexcept {
|
||||||
|
ASMJIT_ASSERT(uint32_t(featureId) < kMaxFeatures);
|
||||||
|
|
||||||
|
uint32_t idx = uint32_t(featureId) / Support::kBitWordSizeInBits;
|
||||||
|
uint32_t bit = uint32_t(featureId) % Support::kBitWordSizeInBits;
|
||||||
|
|
||||||
|
_bits[idx] |= BitWord(condition) << bit;
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FeatureId, typename... Args>
|
||||||
|
ASMJIT_FORCE_INLINE void addIf(bool condition, const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
|
||||||
|
addIf(condition, featureId);
|
||||||
|
addIf(condition, std::forward<Args>(otherFeatureIds)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Removes the given CPU `featureId` from the list of features.
|
||||||
|
template<typename FeatureId>
|
||||||
|
ASMJIT_FORCE_INLINE void remove(const FeatureId& featureId) noexcept {
|
||||||
|
ASMJIT_ASSERT(uint32_t(featureId) < kMaxFeatures);
|
||||||
|
|
||||||
|
uint32_t idx = uint32_t(featureId) / Support::kBitWordSizeInBits;
|
||||||
|
uint32_t bit = uint32_t(featureId) % Support::kBitWordSizeInBits;
|
||||||
|
|
||||||
|
_bits[idx] &= ~(BitWord(1) << bit);
|
||||||
|
}
|
||||||
|
|
||||||
|
template<typename FeatureId, typename... Args>
|
||||||
|
ASMJIT_FORCE_INLINE void remove(const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
|
||||||
|
remove(featureId);
|
||||||
|
remove(std::forward<Args>(otherFeatureIds)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Tests whether this CPU features data matches `other`.
|
||||||
|
ASMJIT_FORCE_INLINE bool eq(const Data& other) const noexcept { return _bits == other._bits; }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
//! X86 specific features data.
|
||||||
|
struct X86 : public Data {
|
||||||
|
//! X86 CPU feature identifiers.
|
||||||
|
enum Id : uint8_t {
|
||||||
|
// @EnumValuesBegin{"enum": "CpuFeatures::X86"}@
|
||||||
|
kNone, //!< No feature (never set, used internally).
|
||||||
|
|
||||||
|
kMT, //!< CPU has multi-threading capabilities.
|
||||||
|
kNX, //!< CPU has Not-Execute-Bit aka DEP (data-execution prevention).
|
||||||
|
k3DNOW, //!< CPU has 3DNOW (3DNOW base instructions) [AMD].
|
||||||
|
k3DNOW2, //!< CPU has 3DNOW2 (enhanced 3DNOW) [AMD].
|
||||||
|
kADX, //!< CPU has ADX (multi-precision add-carry instruction extensions).
|
||||||
|
kAESNI, //!< CPU has AESNI (AES encode/decode instructions).
|
||||||
|
kALTMOVCR8, //!< CPU has LOCK MOV R<->CR0 (supports `MOV R<->CR8` via `LOCK MOV R<->CR0` in 32-bit mode) [AMD].
|
||||||
|
kAMX_BF16, //!< CPU has AMX_BF16 (advanced matrix extensions - BF16 instructions).
|
||||||
|
kAMX_INT8, //!< CPU has AMX_INT8 (advanced matrix extensions - INT8 instructions).
|
||||||
|
kAMX_TILE, //!< CPU has AMX_TILE (advanced matrix extensions).
|
||||||
|
kAVX, //!< CPU has AVX (advanced vector extensions).
|
||||||
|
kAVX2, //!< CPU has AVX2 (advanced vector extensions 2).
|
||||||
|
kAVX512_4FMAPS, //!< CPU has AVX512_FMAPS (FMA packed single).
|
||||||
|
kAVX512_4VNNIW, //!< CPU has AVX512_VNNIW (vector NN instructions word variable precision).
|
||||||
|
kAVX512_BF16, //!< CPU has AVX512_BF16 (BFLOAT16 support instruction).
|
||||||
|
kAVX512_BITALG, //!< CPU has AVX512_BITALG (VPOPCNT[B|W], VPSHUFBITQMB).
|
||||||
|
kAVX512_BW, //!< CPU has AVX512_BW (packed BYTE|WORD).
|
||||||
|
kAVX512_CDI, //!< CPU has AVX512_CDI (conflict detection).
|
||||||
|
kAVX512_DQ, //!< CPU has AVX512_DQ (packed DWORD|QWORD).
|
||||||
|
kAVX512_ERI, //!< CPU has AVX512_ERI (exponential and reciprocal).
|
||||||
|
kAVX512_F, //!< CPU has AVX512_F (AVX512 foundation).
|
||||||
|
kAVX512_FP16, //!< CPU has AVX512_FP16 (FP16 extensions).
|
||||||
|
kAVX512_IFMA, //!< CPU has AVX512_IFMA (integer fused-multiply-add using 52-bit precision).
|
||||||
|
kAVX512_PFI, //!< CPU has AVX512_PFI (prefetch instructions).
|
||||||
|
kAVX512_VBMI, //!< CPU has AVX512_VBMI (vector byte manipulation).
|
||||||
|
kAVX512_VBMI2, //!< CPU has AVX512_VBMI2 (vector byte manipulation 2).
|
||||||
|
kAVX512_VL, //!< CPU has AVX512_VL (vector length extensions).
|
||||||
|
kAVX512_VNNI, //!< CPU has AVX512_VNNI (vector neural network instructions).
|
||||||
|
kAVX512_VP2INTERSECT, //!< CPU has AVX512_VP2INTERSECT
|
||||||
|
kAVX512_VPOPCNTDQ, //!< CPU has AVX512_VPOPCNTDQ (VPOPCNT[D|Q] instructions).
|
||||||
|
kAVX_VNNI, //!< CPU has AVX_VNNI (VEX encoding of vpdpbusd/vpdpbusds/vpdpwssd/vpdpwssds).
|
||||||
|
kBMI, //!< CPU has BMI (bit manipulation instructions #1).
|
||||||
|
kBMI2, //!< CPU has BMI2 (bit manipulation instructions #2).
|
||||||
|
kCET_IBT, //!< CPU has CET-IBT (indirect branch tracking).
|
||||||
|
kCET_SS, //!< CPU has CET-SS.
|
||||||
|
kCLDEMOTE, //!< CPU has CLDEMOTE (cache line demote).
|
||||||
|
kCLFLUSH, //!< CPU has CLFUSH (Cache Line flush).
|
||||||
|
kCLFLUSHOPT, //!< CPU has CLFUSHOPT (Cache Line flush - optimized).
|
||||||
|
kCLWB, //!< CPU has CLWB.
|
||||||
|
kCLZERO, //!< CPU has CLZERO.
|
||||||
|
kCMOV, //!< CPU has CMOV (CMOV and FCMOV instructions).
|
||||||
|
kCMPXCHG16B, //!< CPU has CMPXCHG16B (compare-exchange 16 bytes) [X86_64].
|
||||||
|
kCMPXCHG8B, //!< CPU has CMPXCHG8B (compare-exchange 8 bytes).
|
||||||
|
kENCLV, //!< CPU has ENCLV.
|
||||||
|
kENQCMD, //!< CPU has ENQCMD (enqueue stores).
|
||||||
|
kERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
|
||||||
|
kF16C, //!< CPU has F16C.
|
||||||
|
kFMA, //!< CPU has FMA (fused-multiply-add 3 operand form).
|
||||||
|
kFMA4, //!< CPU has FMA4 (fused-multiply-add 4 operand form).
|
||||||
|
kFPU, //!< CPU has FPU (FPU support).
|
||||||
|
kFSGSBASE, //!< CPU has FSGSBASE.
|
||||||
|
kFXSR, //!< CPU has FXSR (FXSAVE/FXRSTOR instructions).
|
||||||
|
kFXSROPT, //!< CPU has FXSROTP (FXSAVE/FXRSTOR is optimized).
|
||||||
|
kGEODE, //!< CPU has GEODE extensions (3DNOW additions).
|
||||||
|
kGFNI, //!< CPU has GFNI (Galois field instructions).
|
||||||
|
kHLE, //!< CPU has HLE.
|
||||||
|
kHRESET, //!< CPU has HRESET.
|
||||||
|
kI486, //!< CPU has I486 features (I486+ support).
|
||||||
|
kLAHFSAHF, //!< CPU has LAHF/SAHF (LAHF/SAHF in 64-bit mode) [X86_64].
|
||||||
|
kLWP, //!< CPU has LWP (lightweight profiling) [AMD].
|
||||||
|
kLZCNT, //!< CPU has LZCNT (LZCNT instruction).
|
||||||
|
kMCOMMIT, //!< CPU has MCOMMIT (MCOMMIT instruction).
|
||||||
|
kMMX, //!< CPU has MMX (MMX base instructions).
|
||||||
|
kMMX2, //!< CPU has MMX2 (MMX extensions or MMX2).
|
||||||
|
kMONITOR, //!< CPU has MONITOR (MONITOR/MWAIT instructions).
|
||||||
|
kMONITORX, //!< CPU has MONITORX (MONITORX/MWAITX instructions).
|
||||||
|
kMOVBE, //!< CPU has MOVBE (move with byte-order swap).
|
||||||
|
kMOVDIR64B, //!< CPU has MOVDIR64B (move 64 bytes as direct store).
|
||||||
|
kMOVDIRI, //!< CPU has MOVDIRI (move dword/qword as direct store).
|
||||||
|
kMPX, //!< CPU has MPX (memory protection extensions).
|
||||||
|
kMSR, //!< CPU has MSR (RDMSR/WRMSR instructions).
|
||||||
|
kMSSE, //!< CPU has MSSE (misaligned SSE support).
|
||||||
|
kOSXSAVE, //!< CPU has OSXSAVE (XSAVE enabled by OS).
|
||||||
|
kOSPKE, //!< CPU has OSPKE (PKE enabled by OS).
|
||||||
|
kPCLMULQDQ, //!< CPU has PCLMULQDQ (packed carry-less multiplication).
|
||||||
|
kPCONFIG, //!< CPU has PCONFIG (PCONFIG instruction).
|
||||||
|
kPOPCNT, //!< CPU has POPCNT (POPCNT instruction).
|
||||||
|
kPREFETCHW, //!< CPU has PREFETCHW.
|
||||||
|
kPREFETCHWT1, //!< CPU has PREFETCHWT1.
|
||||||
|
kPTWRITE, //!< CPU has PTWRITE.
|
||||||
|
kRDPID, //!< CPU has RDPID.
|
||||||
|
kRDPRU, //!< CPU has RDPRU.
|
||||||
|
kRDRAND, //!< CPU has RDRAND.
|
||||||
|
kRDSEED, //!< CPU has RDSEED.
|
||||||
|
kRDTSC, //!< CPU has RDTSC.
|
||||||
|
kRDTSCP, //!< CPU has RDTSCP.
|
||||||
|
kRTM, //!< CPU has RTM.
|
||||||
|
kSERIALIZE, //!< CPU has SERIALIZE.
|
||||||
|
kSHA, //!< CPU has SHA (SHA-1 and SHA-256 instructions).
|
||||||
|
kSKINIT, //!< CPU has SKINIT (SKINIT/STGI instructions) [AMD].
|
||||||
|
kSMAP, //!< CPU has SMAP (supervisor-mode access prevention).
|
||||||
|
kSMEP, //!< CPU has SMEP (supervisor-mode execution prevention).
|
||||||
|
kSMX, //!< CPU has SMX (safer mode extensions).
|
||||||
|
kSNP, //!< CPU has SNP.
|
||||||
|
kSSE, //!< CPU has SSE.
|
||||||
|
kSSE2, //!< CPU has SSE2.
|
||||||
|
kSSE3, //!< CPU has SSE3.
|
||||||
|
kSSE4_1, //!< CPU has SSE4.1.
|
||||||
|
kSSE4_2, //!< CPU has SSE4.2.
|
||||||
|
kSSE4A, //!< CPU has SSE4A [AMD].
|
||||||
|
kSSSE3, //!< CPU has SSSE3.
|
||||||
|
kSVM, //!< CPU has SVM (virtualization) [AMD].
|
||||||
|
kTBM, //!< CPU has TBM (trailing bit manipulation) [AMD].
|
||||||
|
kTSX, //!< CPU has TSX.
|
||||||
|
kTSXLDTRK, //!< CPU has TSXLDTRK.
|
||||||
|
kUINTR, //!< CPU has UINTR (user interrupts).
|
||||||
|
kVAES, //!< CPU has VAES (vector AES 256|512 bit support).
|
||||||
|
kVMX, //!< CPU has VMX (virtualization) [INTEL].
|
||||||
|
kVPCLMULQDQ, //!< CPU has VPCLMULQDQ (vector PCLMULQDQ 256|512-bit support).
|
||||||
|
kWAITPKG, //!< CPU has WAITPKG (UMONITOR, UMWAIT, TPAUSE).
|
||||||
|
kWBNOINVD, //!< CPU has WBNOINVD.
|
||||||
|
kXOP, //!< CPU has XOP (XOP instructions) [AMD].
|
||||||
|
kXSAVE, //!< CPU has XSAVE.
|
||||||
|
kXSAVEC, //!< CPU has XSAVEC.
|
||||||
|
kXSAVEOPT, //!< CPU has XSAVEOPT.
|
||||||
|
kXSAVES, //!< CPU has XSAVES.
|
||||||
|
// @EnumValuesEnd@
|
||||||
|
|
||||||
|
kMaxValue = kXSAVES
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ASMJIT_X86_FEATURE(FEATURE) \
|
||||||
|
inline bool has##FEATURE() const noexcept { return has(X86::k##FEATURE); }
|
||||||
|
|
||||||
|
ASMJIT_X86_FEATURE(MT)
|
||||||
|
ASMJIT_X86_FEATURE(NX)
|
||||||
|
ASMJIT_X86_FEATURE(3DNOW)
|
||||||
|
ASMJIT_X86_FEATURE(3DNOW2)
|
||||||
|
ASMJIT_X86_FEATURE(ADX)
|
||||||
|
ASMJIT_X86_FEATURE(AESNI)
|
||||||
|
ASMJIT_X86_FEATURE(ALTMOVCR8)
|
||||||
|
ASMJIT_X86_FEATURE(AMX_BF16)
|
||||||
|
ASMJIT_X86_FEATURE(AMX_INT8)
|
||||||
|
ASMJIT_X86_FEATURE(AMX_TILE)
|
||||||
|
ASMJIT_X86_FEATURE(AVX)
|
||||||
|
ASMJIT_X86_FEATURE(AVX2)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_4FMAPS)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_4VNNIW)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_BF16)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_BITALG)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_BW)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_CDI)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_DQ)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_ERI)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_F)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_FP16)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_IFMA)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_PFI)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VBMI)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VBMI2)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VL)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VNNI)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VP2INTERSECT)
|
||||||
|
ASMJIT_X86_FEATURE(AVX512_VPOPCNTDQ)
|
||||||
|
ASMJIT_X86_FEATURE(AVX_VNNI)
|
||||||
|
ASMJIT_X86_FEATURE(BMI)
|
||||||
|
ASMJIT_X86_FEATURE(BMI2)
|
||||||
|
ASMJIT_X86_FEATURE(CET_IBT)
|
||||||
|
ASMJIT_X86_FEATURE(CET_SS)
|
||||||
|
ASMJIT_X86_FEATURE(CLDEMOTE)
|
||||||
|
ASMJIT_X86_FEATURE(CLFLUSH)
|
||||||
|
ASMJIT_X86_FEATURE(CLFLUSHOPT)
|
||||||
|
ASMJIT_X86_FEATURE(CLWB)
|
||||||
|
ASMJIT_X86_FEATURE(CLZERO)
|
||||||
|
ASMJIT_X86_FEATURE(CMOV)
|
||||||
|
ASMJIT_X86_FEATURE(CMPXCHG16B)
|
||||||
|
ASMJIT_X86_FEATURE(CMPXCHG8B)
|
||||||
|
ASMJIT_X86_FEATURE(ENCLV)
|
||||||
|
ASMJIT_X86_FEATURE(ENQCMD)
|
||||||
|
ASMJIT_X86_FEATURE(ERMS)
|
||||||
|
ASMJIT_X86_FEATURE(F16C)
|
||||||
|
ASMJIT_X86_FEATURE(FMA)
|
||||||
|
ASMJIT_X86_FEATURE(FMA4)
|
||||||
|
ASMJIT_X86_FEATURE(FPU)
|
||||||
|
ASMJIT_X86_FEATURE(FSGSBASE)
|
||||||
|
ASMJIT_X86_FEATURE(FXSR)
|
||||||
|
ASMJIT_X86_FEATURE(FXSROPT)
|
||||||
|
ASMJIT_X86_FEATURE(GEODE)
|
||||||
|
ASMJIT_X86_FEATURE(GFNI)
|
||||||
|
ASMJIT_X86_FEATURE(HLE)
|
||||||
|
ASMJIT_X86_FEATURE(HRESET)
|
||||||
|
ASMJIT_X86_FEATURE(I486)
|
||||||
|
ASMJIT_X86_FEATURE(LAHFSAHF)
|
||||||
|
ASMJIT_X86_FEATURE(LWP)
|
||||||
|
ASMJIT_X86_FEATURE(LZCNT)
|
||||||
|
ASMJIT_X86_FEATURE(MCOMMIT)
|
||||||
|
ASMJIT_X86_FEATURE(MMX)
|
||||||
|
ASMJIT_X86_FEATURE(MMX2)
|
||||||
|
ASMJIT_X86_FEATURE(MONITOR)
|
||||||
|
ASMJIT_X86_FEATURE(MONITORX)
|
||||||
|
ASMJIT_X86_FEATURE(MOVBE)
|
||||||
|
ASMJIT_X86_FEATURE(MOVDIR64B)
|
||||||
|
ASMJIT_X86_FEATURE(MOVDIRI)
|
||||||
|
ASMJIT_X86_FEATURE(MPX)
|
||||||
|
ASMJIT_X86_FEATURE(MSR)
|
||||||
|
ASMJIT_X86_FEATURE(MSSE)
|
||||||
|
ASMJIT_X86_FEATURE(OSXSAVE)
|
||||||
|
ASMJIT_X86_FEATURE(OSPKE)
|
||||||
|
ASMJIT_X86_FEATURE(PCLMULQDQ)
|
||||||
|
ASMJIT_X86_FEATURE(PCONFIG)
|
||||||
|
ASMJIT_X86_FEATURE(POPCNT)
|
||||||
|
ASMJIT_X86_FEATURE(PREFETCHW)
|
||||||
|
ASMJIT_X86_FEATURE(PREFETCHWT1)
|
||||||
|
ASMJIT_X86_FEATURE(PTWRITE)
|
||||||
|
ASMJIT_X86_FEATURE(RDPID)
|
||||||
|
ASMJIT_X86_FEATURE(RDPRU)
|
||||||
|
ASMJIT_X86_FEATURE(RDRAND)
|
||||||
|
ASMJIT_X86_FEATURE(RDSEED)
|
||||||
|
ASMJIT_X86_FEATURE(RDTSC)
|
||||||
|
ASMJIT_X86_FEATURE(RDTSCP)
|
||||||
|
ASMJIT_X86_FEATURE(RTM)
|
||||||
|
ASMJIT_X86_FEATURE(SERIALIZE)
|
||||||
|
ASMJIT_X86_FEATURE(SHA)
|
||||||
|
ASMJIT_X86_FEATURE(SKINIT)
|
||||||
|
ASMJIT_X86_FEATURE(SMAP)
|
||||||
|
ASMJIT_X86_FEATURE(SMEP)
|
||||||
|
ASMJIT_X86_FEATURE(SMX)
|
||||||
|
ASMJIT_X86_FEATURE(SNP)
|
||||||
|
ASMJIT_X86_FEATURE(SSE)
|
||||||
|
ASMJIT_X86_FEATURE(SSE2)
|
||||||
|
ASMJIT_X86_FEATURE(SSE3)
|
||||||
|
ASMJIT_X86_FEATURE(SSE4_1)
|
||||||
|
ASMJIT_X86_FEATURE(SSE4_2)
|
||||||
|
ASMJIT_X86_FEATURE(SSE4A)
|
||||||
|
ASMJIT_X86_FEATURE(SSSE3)
|
||||||
|
ASMJIT_X86_FEATURE(SVM)
|
||||||
|
ASMJIT_X86_FEATURE(TBM)
|
||||||
|
ASMJIT_X86_FEATURE(TSX)
|
||||||
|
ASMJIT_X86_FEATURE(TSXLDTRK)
|
||||||
|
ASMJIT_X86_FEATURE(UINTR)
|
||||||
|
ASMJIT_X86_FEATURE(VAES)
|
||||||
|
ASMJIT_X86_FEATURE(VMX)
|
||||||
|
ASMJIT_X86_FEATURE(VPCLMULQDQ)
|
||||||
|
ASMJIT_X86_FEATURE(WAITPKG)
|
||||||
|
ASMJIT_X86_FEATURE(WBNOINVD)
|
||||||
|
ASMJIT_X86_FEATURE(XOP)
|
||||||
|
ASMJIT_X86_FEATURE(XSAVE)
|
||||||
|
ASMJIT_X86_FEATURE(XSAVEC)
|
||||||
|
ASMJIT_X86_FEATURE(XSAVEOPT)
|
||||||
|
ASMJIT_X86_FEATURE(XSAVES)
|
||||||
|
|
||||||
|
#undef ASMJIT_X86_FEATURE
|
||||||
|
};
|
||||||
|
|
||||||
|
//! ARM specific features data.
|
||||||
|
struct ARM : public Data {
|
||||||
|
//! ARM CPU feature identifiers.
|
||||||
|
enum Id : uint8_t {
|
||||||
|
// @EnumValuesBegin{"enum": "CpuFeatures::ARM"}@
|
||||||
|
kNone = 0, //!< No feature (never set, used internally).
|
||||||
|
kTHUMB, //!< THUMB v1 ISA.
|
||||||
|
kTHUMBv2, //!< THUMB v2 ISA.
|
||||||
|
|
||||||
|
kARMv6, //!< ARMv6 ISA.
|
||||||
|
kARMv7, //!< ARMv7 ISA.
|
||||||
|
kARMv8a, //!< ARMv8-A ISA.
|
||||||
|
kARMv8_1a, //!< ARMv8.1-A ISA.
|
||||||
|
kARMv8_2a, //!< ARMv8.2-A ISA.
|
||||||
|
kARMv8_3a, //!< ARMv8.3-A ISA.
|
||||||
|
kARMv8_4a, //!< ARMv8.4-A ISA.
|
||||||
|
kARMv8_5a, //!< ARMv8.5-A ISA.
|
||||||
|
kARMv8_6a, //!< ARMv8.6-A ISA.
|
||||||
|
kARMv8_7a, //!< ARMv8.6-A ISA.
|
||||||
|
|
||||||
|
kVFPv2, //!< CPU has VFPv2 instruction set.
|
||||||
|
kVFPv3, //!< CPU has VFPv3 instruction set.
|
||||||
|
kVFPv4, //!< CPU has VFPv4 instruction set.
|
||||||
|
kVFP_D32, //!< CPU has 32 VFP-D (64-bit) registers.
|
||||||
|
|
||||||
|
kAES, //!< CPU has AES (AArch64 only).
|
||||||
|
kALTNZCV, //!< CPU has ALTNZCV (AArch64 only).
|
||||||
|
kASIMD, //!< CPU has Advanced SIMD (NEON on ARM/THUMB).
|
||||||
|
kBF16, //!< CPU has BF16 (AArch64 only).
|
||||||
|
kBTI, //!< CPU has BTI (branch target identification).
|
||||||
|
kCPUID, //!< CPU has accessible CPUID register (ID_AA64ZFR0_EL1).
|
||||||
|
kCRC32, //!< CPU has CRC32 .
|
||||||
|
kDGH, //!< CPU has DGH (AArch64 only).
|
||||||
|
kDIT, //!< CPU has data independent timing instructions (DIT).
|
||||||
|
kDOTPROD, //!< CPU has DOTPROD (SDOT/UDOT).
|
||||||
|
kEDSP, //!< CPU has EDSP (ARM/THUMB only).
|
||||||
|
kFCMA, //!< CPU has FCMA (FCADD/FCMLA).
|
||||||
|
kFJCVTZS, //!< CPU has FJCVTZS (AArch64 only).
|
||||||
|
kFLAGM, //!< CPU has FLAGM (AArch64 only).
|
||||||
|
kFP16CONV, //!< CPU has FP16 (half-float) conversion.
|
||||||
|
kFP16FML, //!< CPU has FMLAL{2}/FMLSL{2}
|
||||||
|
kFP16FULL, //!< CPU has full support for FP16.
|
||||||
|
kFRINT, //!< CPU has FRINT[32|64][X|Z] (AArch64 only).
|
||||||
|
kI8MM, //!< CPU has I8MM (AArch64 only).
|
||||||
|
kIDIVA, //!< CPU has hardware SDIV and UDIV (ARM mode).
|
||||||
|
kIDIVT, //!< CPU has hardware SDIV and UDIV (THUMB mode).
|
||||||
|
kLSE, //!< CPU has large system extensions (LSE) (AArch64 only).
|
||||||
|
kMTE, //!< CPU has MTE (AArch64 only).
|
||||||
|
kRCPC_IMMO, //!< CPU has RCPC_IMMO (AArch64 only).
|
||||||
|
kRDM, //!< CPU has RDM (AArch64 only).
|
||||||
|
kPMU, //!< CPU has PMU (AArch64 only).
|
||||||
|
kPMULL, //!< CPU has PMULL (AArch64 only).
|
||||||
|
kRNG, //!< CPU has random number generation (RNG).
|
||||||
|
kSB, //!< CPU has speculative barrier SB (AArch64 only).
|
||||||
|
kSHA1, //!< CPU has SHA1.
|
||||||
|
kSHA2, //!< CPU has SHA2.
|
||||||
|
kSHA3, //!< CPU has SHA3.
|
||||||
|
kSHA512, //!< CPU has SHA512.
|
||||||
|
kSM3, //!< CPU has SM3.
|
||||||
|
kSM4, //!< CPU has SM4.
|
||||||
|
kSSBS, //!< CPU has SSBS.
|
||||||
|
kSVE, //!< CPU has SVE (AArch64 only).
|
||||||
|
kSVE_BF16, //!< CPU has SVE-BF16 (AArch64 only).
|
||||||
|
kSVE_F32MM, //!< CPU has SVE-F32MM (AArch64 only).
|
||||||
|
kSVE_F64MM, //!< CPU has SVE-F64MM (AArch64 only).
|
||||||
|
kSVE_I8MM, //!< CPU has SVE-I8MM (AArch64 only).
|
||||||
|
kSVE_PMULL, //!< CPU has SVE-PMULL (AArch64 only).
|
||||||
|
kSVE2, //!< CPU has SVE2 (AArch64 only).
|
||||||
|
kSVE2_AES, //!< CPU has SVE2-AES (AArch64 only).
|
||||||
|
kSVE2_BITPERM, //!< CPU has SVE2-BITPERM (AArch64 only).
|
||||||
|
kSVE2_SHA3, //!< CPU has SVE2-SHA3 (AArch64 only).
|
||||||
|
kSVE2_SM4, //!< CPU has SVE2-SM4 (AArch64 only).
|
||||||
|
kTME, //!< CPU has transactional memory extensions (TME).
|
||||||
|
// @EnumValuesEnd@
|
||||||
|
|
||||||
|
kMaxValue = kTME
|
||||||
|
};
|
||||||
|
|
||||||
|
#define ASMJIT_ARM_FEATURE(FEATURE) \
|
||||||
|
inline bool has##FEATURE() const noexcept { return has(ARM::k##FEATURE); }
|
||||||
|
|
||||||
|
ASMJIT_ARM_FEATURE(THUMB)
|
||||||
|
ASMJIT_ARM_FEATURE(THUMBv2)
|
||||||
|
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv6)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv7)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_1a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_2a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_3a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_4a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_5a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_6a)
|
||||||
|
ASMJIT_ARM_FEATURE(ARMv8_7a)
|
||||||
|
|
||||||
|
ASMJIT_ARM_FEATURE(VFPv2)
|
||||||
|
ASMJIT_ARM_FEATURE(VFPv3)
|
||||||
|
ASMJIT_ARM_FEATURE(VFPv4)
|
||||||
|
ASMJIT_ARM_FEATURE(VFP_D32)
|
||||||
|
|
||||||
|
ASMJIT_ARM_FEATURE(AES)
|
||||||
|
ASMJIT_ARM_FEATURE(ALTNZCV)
|
||||||
|
ASMJIT_ARM_FEATURE(ASIMD)
|
||||||
|
ASMJIT_ARM_FEATURE(BF16)
|
||||||
|
ASMJIT_ARM_FEATURE(BTI)
|
||||||
|
ASMJIT_ARM_FEATURE(CPUID)
|
||||||
|
ASMJIT_ARM_FEATURE(CRC32)
|
||||||
|
ASMJIT_ARM_FEATURE(DGH)
|
||||||
|
ASMJIT_ARM_FEATURE(DIT)
|
||||||
|
ASMJIT_ARM_FEATURE(DOTPROD)
|
||||||
|
ASMJIT_ARM_FEATURE(EDSP)
|
||||||
|
ASMJIT_ARM_FEATURE(FCMA)
|
||||||
|
ASMJIT_ARM_FEATURE(FLAGM)
|
||||||
|
ASMJIT_ARM_FEATURE(FP16CONV)
|
||||||
|
ASMJIT_ARM_FEATURE(FP16FML)
|
||||||
|
ASMJIT_ARM_FEATURE(FP16FULL)
|
||||||
|
ASMJIT_ARM_FEATURE(FRINT)
|
||||||
|
ASMJIT_ARM_FEATURE(IDIVA)
|
||||||
|
ASMJIT_ARM_FEATURE(IDIVT)
|
||||||
|
ASMJIT_ARM_FEATURE(LSE)
|
||||||
|
ASMJIT_ARM_FEATURE(MTE)
|
||||||
|
ASMJIT_ARM_FEATURE(FJCVTZS)
|
||||||
|
ASMJIT_ARM_FEATURE(I8MM)
|
||||||
|
ASMJIT_ARM_FEATURE(RCPC_IMMO)
|
||||||
|
ASMJIT_ARM_FEATURE(RDM)
|
||||||
|
ASMJIT_ARM_FEATURE(PMU)
|
||||||
|
ASMJIT_ARM_FEATURE(PMULL)
|
||||||
|
ASMJIT_ARM_FEATURE(RNG)
|
||||||
|
ASMJIT_ARM_FEATURE(SB)
|
||||||
|
ASMJIT_ARM_FEATURE(SHA1)
|
||||||
|
ASMJIT_ARM_FEATURE(SHA2)
|
||||||
|
ASMJIT_ARM_FEATURE(SHA3)
|
||||||
|
ASMJIT_ARM_FEATURE(SHA512)
|
||||||
|
ASMJIT_ARM_FEATURE(SM3)
|
||||||
|
ASMJIT_ARM_FEATURE(SM4)
|
||||||
|
ASMJIT_ARM_FEATURE(SSBS)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_BF16)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_F32MM)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_F64MM)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_I8MM)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE_PMULL)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2_AES)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2_BITPERM)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2_SHA3)
|
||||||
|
ASMJIT_ARM_FEATURE(SVE2_SM4)
|
||||||
|
ASMJIT_ARM_FEATURE(TME)
|
||||||
|
|
||||||
|
#undef ASMJIT_ARM_FEATURE
|
||||||
|
};
|
||||||
|
|
||||||
|
static_assert(uint32_t(X86::kMaxValue) < kMaxFeatures, "The number of X86 CPU features cannot exceed CpuFeatures::kMaxFeatures");
|
||||||
|
static_assert(uint32_t(ARM::kMaxValue) < kMaxFeatures, "The number of ARM CPU features cannot exceed CpuFeatures::kMaxFeatures");
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
Data _data {};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
inline CpuFeatures() noexcept {}
|
||||||
|
inline CpuFeatures(const CpuFeatures& other) noexcept = default;
|
||||||
|
inline explicit CpuFeatures(Globals::NoInit_) noexcept {}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Overloaded Operators
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
inline CpuFeatures& operator=(const CpuFeatures& other) noexcept = default;
|
||||||
|
|
||||||
|
inline bool operator==(const CpuFeatures& other) noexcept { return eq(other); }
|
||||||
|
inline bool operator!=(const CpuFeatures& other) noexcept { return !eq(other); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Accessors
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Returns true if there are no features set.
|
||||||
|
inline bool empty() const noexcept { return _data.empty(); }
|
||||||
|
|
||||||
|
//! Casts this base class into a derived type `T`.
|
||||||
|
template<typename T = Data>
|
||||||
|
inline T& data() noexcept { return static_cast<T&>(_data); }
|
||||||
|
|
||||||
|
//! Casts this base class into a derived type `T` (const).
|
||||||
|
template<typename T = Data>
|
||||||
|
inline const T& data() const noexcept { return static_cast<const T&>(_data); }
|
||||||
|
|
||||||
|
//! Returns CpuFeatures::Data as \ref CpuFeatures::X86.
|
||||||
|
inline X86& x86() noexcept { return data<X86>(); }
|
||||||
|
//! Returns CpuFeatures::Data as \ref CpuFeatures::X86 (const).
|
||||||
|
inline const X86& x86() const noexcept { return data<X86>(); }
|
||||||
|
|
||||||
|
//! Returns CpuFeatures::Data as \ref CpuFeatures::ARM.
|
||||||
|
inline ARM& arm() noexcept { return data<ARM>(); }
|
||||||
|
//! Returns CpuFeatures::Data as \ref CpuFeatures::ARM (const).
|
||||||
|
inline const ARM& arm() const noexcept { return data<ARM>(); }
|
||||||
|
|
||||||
|
//! Returns all features as array of bitwords (see \ref Support::BitWord).
|
||||||
|
inline BitWord* bits() noexcept { return _data.bits(); }
|
||||||
|
//! Returns all features as array of bitwords (const).
|
||||||
|
inline const BitWord* bits() const noexcept { return _data.bits(); }
|
||||||
|
//! Returns the number of BitWords returned by \ref bits().
|
||||||
|
inline size_t bitWordCount() const noexcept { return _data.bitWordCount(); }
|
||||||
|
|
||||||
|
//! Returns \ref Support::BitVectorIterator, that can be used to iterate over all features efficiently.
|
||||||
|
inline Iterator iterator() const noexcept { return _data.iterator(); }
|
||||||
|
|
||||||
|
//! Tests whether the feature `featureId` is present.
|
||||||
|
template<typename FeatureId>
|
||||||
|
inline bool has(const FeatureId& featureId) const noexcept { return _data.has(featureId); }
|
||||||
|
|
||||||
|
//! Tests whether all features as defined by `other` are present.
|
||||||
|
inline bool hasAll(const CpuFeatures& other) const noexcept { return _data.hasAll(other._data); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Manipulation
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
inline void reset() noexcept { _data.reset(); }
|
||||||
|
|
||||||
|
//! Adds the given CPU `featureId` to the list of features.
|
||||||
|
template<typename... Args>
|
||||||
|
inline void add(Args&&... args) noexcept { return _data.add(std::forward<Args>(args)...); }
|
||||||
|
|
||||||
|
//! Adds the given CPU `featureId` to the list of features if `condition` is true.
|
||||||
|
template<typename... Args>
|
||||||
|
inline void addIf(bool condition, Args&&... args) noexcept { return _data.addIf(condition, std::forward<Args>(args)...); }
|
||||||
|
|
||||||
|
//! Removes the given CPU `featureId` from the list of features.
|
||||||
|
template<typename... Args>
|
||||||
|
inline void remove(Args&&... args) noexcept { return _data.remove(std::forward<Args>(args)...); }
|
||||||
|
|
||||||
|
//! Tests whether this CPU features matches `other`.
|
||||||
|
inline bool eq(const CpuFeatures& other) const noexcept { return _data.eq(other._data); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
};
|
||||||
|
|
||||||
//! CPU information.
|
//! CPU information.
|
||||||
class CpuInfo {
|
class CpuInfo {
|
||||||
public:
|
public:
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Architecture.
|
//! Architecture.
|
||||||
uint8_t _arch;
|
Arch _arch;
|
||||||
//! Sub-architecture.
|
//! Sub-architecture.
|
||||||
uint8_t _subArch;
|
SubArch _subArch;
|
||||||
|
//! True if the CPU was detected, false if the detection failed or it's not available.
|
||||||
|
bool _wasDetected;
|
||||||
//! Reserved for future use.
|
//! Reserved for future use.
|
||||||
uint16_t _reserved;
|
uint8_t _reserved;
|
||||||
//! CPU family ID.
|
//! CPU family ID.
|
||||||
uint32_t _familyId;
|
uint32_t _familyId;
|
||||||
//! CPU model ID.
|
//! CPU model ID.
|
||||||
@@ -69,7 +696,9 @@ public:
|
|||||||
//! CPU brand string.
|
//! CPU brand string.
|
||||||
FixedString<64> _brand;
|
FixedString<64> _brand;
|
||||||
//! CPU features.
|
//! CPU features.
|
||||||
BaseFeatures _features;
|
CpuFeatures _features;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -83,10 +712,10 @@ public:
|
|||||||
//! Returns the host CPU information.
|
//! Returns the host CPU information.
|
||||||
ASMJIT_API static const CpuInfo& host() noexcept;
|
ASMJIT_API static const CpuInfo& host() noexcept;
|
||||||
|
|
||||||
//! Initializes CpuInfo to the given architecture, see \ref Environment.
|
//! Initializes CpuInfo architecture and sub-architecture members to `arch` and `subArch`, respectively.
|
||||||
inline void initArch(uint32_t arch, uint32_t subArch = 0u) noexcept {
|
inline void initArch(Arch arch, SubArch subArch = SubArch::kUnknown) noexcept {
|
||||||
_arch = uint8_t(arch);
|
_arch = arch;
|
||||||
_subArch = uint8_t(subArch);
|
_subArch = subArch;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
||||||
@@ -103,46 +732,76 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the CPU architecture id, see \ref Environment::Arch.
|
//! Returns the CPU architecture this information relates to.
|
||||||
inline uint32_t arch() const noexcept { return _arch; }
|
inline Arch arch() const noexcept { return _arch; }
|
||||||
//! Returns the CPU architecture sub-id, see \ref Environment::SubArch.
|
|
||||||
inline uint32_t subArch() const noexcept { return _subArch; }
|
//! Returns the CPU sub-architecture this information relates to.
|
||||||
|
inline SubArch subArch() const noexcept { return _subArch; }
|
||||||
|
|
||||||
|
//! Returns whether the CPU was detected successfully.
|
||||||
|
//!
|
||||||
|
//! If the returned value is false it means that AsmJit either failed to detect the CPU or it doesn't have
|
||||||
|
//! implementation targeting the host architecture and operating system.
|
||||||
|
inline bool wasDetected() const noexcept { return _wasDetected; }
|
||||||
|
|
||||||
//! Returns the CPU family ID.
|
//! Returns the CPU family ID.
|
||||||
|
//!
|
||||||
|
//! Family identifier matches the FamilyId read by using CPUID on X86 architecture.
|
||||||
inline uint32_t familyId() const noexcept { return _familyId; }
|
inline uint32_t familyId() const noexcept { return _familyId; }
|
||||||
|
|
||||||
//! Returns the CPU model ID.
|
//! Returns the CPU model ID.
|
||||||
|
//!
|
||||||
|
//! Family identifier matches the ModelId read by using CPUID on X86 architecture.
|
||||||
|
|
||||||
inline uint32_t modelId() const noexcept { return _modelId; }
|
inline uint32_t modelId() const noexcept { return _modelId; }
|
||||||
//! Returns the CPU brand id.
|
//! Returns the CPU brand id.
|
||||||
|
//!
|
||||||
|
//! Family identifier matches the BrandId read by using CPUID on X86 architecture.
|
||||||
inline uint32_t brandId() const noexcept { return _brandId; }
|
inline uint32_t brandId() const noexcept { return _brandId; }
|
||||||
|
|
||||||
//! Returns the CPU stepping.
|
//! Returns the CPU stepping.
|
||||||
|
//!
|
||||||
|
//! Family identifier matches the Stepping information read by using CPUID on X86 architecture.
|
||||||
inline uint32_t stepping() const noexcept { return _stepping; }
|
inline uint32_t stepping() const noexcept { return _stepping; }
|
||||||
|
|
||||||
//! Returns the processor type.
|
//! Returns the processor type.
|
||||||
|
//!
|
||||||
|
//! Family identifier matches the ProcessorType read by using CPUID on X86 architecture.
|
||||||
inline uint32_t processorType() const noexcept { return _processorType; }
|
inline uint32_t processorType() const noexcept { return _processorType; }
|
||||||
//! Returns the number of maximum logical processors.
|
|
||||||
|
//! Returns the maximum number of logical processors.
|
||||||
inline uint32_t maxLogicalProcessors() const noexcept { return _maxLogicalProcessors; }
|
inline uint32_t maxLogicalProcessors() const noexcept { return _maxLogicalProcessors; }
|
||||||
|
|
||||||
//! Returns the size of a cache line flush.
|
//! Returns the size of a cache line flush.
|
||||||
inline uint32_t cacheLineSize() const noexcept { return _cacheLineSize; }
|
inline uint32_t cacheLineSize() const noexcept { return _cacheLineSize; }
|
||||||
|
|
||||||
//! Returns number of hardware threads available.
|
//! Returns number of hardware threads available.
|
||||||
inline uint32_t hwThreadCount() const noexcept { return _hwThreadCount; }
|
inline uint32_t hwThreadCount() const noexcept { return _hwThreadCount; }
|
||||||
|
|
||||||
//! Returns the CPU vendor.
|
//! Returns a CPU vendor string.
|
||||||
inline const char* vendor() const noexcept { return _vendor.str; }
|
inline const char* vendor() const noexcept { return _vendor.str; }
|
||||||
//! Tests whether the CPU vendor is equal to `s`.
|
//! Tests whether the CPU vendor string is equal to `s`.
|
||||||
inline bool isVendor(const char* s) const noexcept { return _vendor.eq(s); }
|
inline bool isVendor(const char* s) const noexcept { return _vendor.eq(s); }
|
||||||
|
|
||||||
//! Returns the CPU brand string.
|
//! Returns a CPU brand string.
|
||||||
inline const char* brand() const noexcept { return _brand.str; }
|
inline const char* brand() const noexcept { return _brand.str; }
|
||||||
|
|
||||||
//! Returns all CPU features as `BaseFeatures`, cast to your arch-specific class
|
//! Returns CPU features.
|
||||||
//! if needed.
|
inline CpuFeatures& features() noexcept { return _features; }
|
||||||
template<typename T = BaseFeatures>
|
//! Returns CPU features (const).
|
||||||
inline const T& features() const noexcept { return _features.as<T>(); }
|
inline const CpuFeatures& features() const noexcept { return _features; }
|
||||||
|
|
||||||
//! Tests whether the CPU has the given `feature`.
|
//! Tests whether the CPU has the given `feature`.
|
||||||
inline bool hasFeature(uint32_t featureId) const noexcept { return _features.has(featureId); }
|
template<typename FeatureId>
|
||||||
//! Adds the given CPU `feature` to the list of this CpuInfo features.
|
inline bool hasFeature(const FeatureId& featureId) const noexcept { return _features.has(featureId); }
|
||||||
inline CpuInfo& addFeature(uint32_t featureId) noexcept { _features.add(featureId); return *this; }
|
|
||||||
|
//! Adds the given CPU `featureId` to the list of features.
|
||||||
|
template<typename... Args>
|
||||||
|
inline void addFeature(Args&&... args) noexcept { return _features.add(std::forward<Args>(args)...); }
|
||||||
|
|
||||||
|
//! Removes the given CPU `featureId` from the list of features.
|
||||||
|
template<typename... Args>
|
||||||
|
inline void removeFeature(Args&&... args) noexcept { return _features.remove(std::forward<Args>(args)...); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/archtraits.h"
|
#include "../core/archtraits.h"
|
||||||
@@ -33,12 +15,11 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitHelper - Formatting
|
||||||
// [asmjit::BaseEmitHelper - Formatting]
|
// ===========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT
|
#ifdef ASMJIT_DUMP_ARGS_ASSIGNMENT
|
||||||
static void dumpFuncValue(String& sb, uint32_t arch, const FuncValue& value) noexcept {
|
static void dumpFuncValue(String& sb, Arch arch, const FuncValue& value) noexcept {
|
||||||
Formatter::formatTypeId(sb, value.typeId());
|
Formatter::formatTypeId(sb, value.typeId());
|
||||||
sb.append('@');
|
sb.append('@');
|
||||||
|
|
||||||
@@ -59,7 +40,7 @@ static void dumpFuncValue(String& sb, uint32_t arch, const FuncValue& value) noe
|
|||||||
static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept {
|
static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept {
|
||||||
typedef FuncArgsContext::Var Var;
|
typedef FuncArgsContext::Var Var;
|
||||||
|
|
||||||
uint32_t arch = ctx.arch();
|
Arch arch = ctx.arch();
|
||||||
uint32_t varCount = ctx.varCount();
|
uint32_t varCount = ctx.varCount();
|
||||||
|
|
||||||
for (uint32_t i = 0; i < varCount; i++) {
|
for (uint32_t i = 0; i < varCount; i++) {
|
||||||
@@ -80,9 +61,8 @@ static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitHelper - EmitArgsAssignment
|
||||||
// [asmjit::BaseEmitHelper - EmitArgsAssignment]
|
// ===================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) {
|
ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) {
|
||||||
typedef FuncArgsContext::Var Var;
|
typedef FuncArgsContext::Var Var;
|
||||||
@@ -95,7 +75,7 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
kWorkPostponed = 0x04
|
kWorkPostponed = 0x04
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t arch = frame.arch();
|
Arch arch = frame.arch();
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
||||||
|
|
||||||
RAConstraints constraints;
|
RAConstraints constraints;
|
||||||
@@ -112,11 +92,11 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
auto& workData = ctx._workData;
|
||||||
uint32_t varCount = ctx._varCount;
|
uint32_t varCount = ctx._varCount;
|
||||||
WorkData* workData = ctx._workData;
|
|
||||||
|
|
||||||
uint32_t saVarId = ctx._saVarId;
|
uint32_t saVarId = ctx._saVarId;
|
||||||
BaseReg sp = BaseReg::fromSignatureAndId(_emitter->_gpRegInfo.signature(), archTraits.spRegId());
|
|
||||||
|
BaseReg sp = BaseReg(_emitter->_gpSignature, archTraits.spRegId());
|
||||||
BaseReg sa = sp;
|
BaseReg sa = sp;
|
||||||
|
|
||||||
if (frame.hasDynamicAlignment()) {
|
if (frame.hasDynamicAlignment()) {
|
||||||
@@ -126,10 +106,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
sa.setId(saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId());
|
sa.setId(saVarId < varCount ? ctx._vars[saVarId].cur.regId() : frame.saRegId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
// Register to stack and stack to stack moves must be first as now we have
|
// Register to stack and stack to stack moves must be first as now we have
|
||||||
// the biggest chance of having as many as possible unassigned registers.
|
// the biggest chance of having as many as possible unassigned registers.
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (ctx._stackDstMask) {
|
if (ctx._stackDstMask) {
|
||||||
// Base address of all arguments passed by stack.
|
// Base address of all arguments passed by stack.
|
||||||
@@ -163,33 +141,32 @@ 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[archTraits.regTypeToGroup(cur.regType())];
|
||||||
uint32_t rId = cur.regId();
|
uint32_t regId = cur.regId();
|
||||||
|
|
||||||
reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), rId);
|
reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), regId);
|
||||||
wd.unassign(varId, rId);
|
wd.unassign(varId, regId);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Stack to reg move - tricky since we move stack to stack we can decide which
|
// Stack to reg move - tricky since we move stack to stack we can decide which register to use. In general
|
||||||
// register to use. In general we follow the rule that IntToInt moves will use
|
// we follow the rule that IntToInt moves will use GP regs with possibility to signature or zero extend,
|
||||||
// GP regs with possibility to signature or zero extend, and all other moves will
|
// and all other moves will either use GP or VEC regs depending on the size of the move.
|
||||||
// either use GP or VEC regs depending on the size of the move.
|
OperandSignature signature = getSuitableRegForMemToMemMove(arch, out.typeId(), cur.typeId());
|
||||||
RegInfo rInfo = getSuitableRegForMemToMemMove(arch, out.typeId(), cur.typeId());
|
if (ASMJIT_UNLIKELY(!signature.isValid()))
|
||||||
if (ASMJIT_UNLIKELY(!rInfo.isValid()))
|
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
WorkData& wd = workData[rInfo.group()];
|
WorkData& wd = workData[signature.regGroup()];
|
||||||
uint32_t availableRegs = wd.availableRegs();
|
RegMask availableRegs = wd.availableRegs();
|
||||||
if (ASMJIT_UNLIKELY(!availableRegs))
|
if (ASMJIT_UNLIKELY(!availableRegs))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
uint32_t rId = Support::ctz(availableRegs);
|
uint32_t availableId = Support::ctz(availableRegs);
|
||||||
reg.setSignatureAndId(rInfo.signature(), rId);
|
reg.setSignatureAndId(signature, availableId);
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(emitArgMove(reg, out.typeId(), srcStackPtr, cur.typeId()));
|
ASMJIT_PROPAGATE(emitArgMove(reg, out.typeId(), srcStackPtr, cur.typeId()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cur.isIndirect() && cur.isReg())
|
if (cur.isIndirect() && cur.isReg())
|
||||||
workData[BaseReg::kGroupGp].unassign(varId, cur.regId());
|
workData[RegGroup::kGp].unassign(varId, cur.regId());
|
||||||
|
|
||||||
// Register to stack move.
|
// Register to stack move.
|
||||||
ASMJIT_PROPAGATE(emitRegMove(dstStackPtr, reg, cur.typeId()));
|
ASMJIT_PROPAGATE(emitRegMove(dstStackPtr, reg, cur.typeId()));
|
||||||
@@ -197,10 +174,7 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Shuffle all registers that are currently assigned accordingly to target assignment.
|
||||||
// Shuffle all registers that are currently assigned accordingly to target
|
|
||||||
// assignment.
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
uint32_t workFlags = kWorkNone;
|
uint32_t workFlags = kWorkNone;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -212,8 +186,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;
|
||||||
|
|
||||||
uint32_t curGroup = archTraits.regTypeToGroup(cur.regType());
|
RegGroup curGroup = archTraits.regTypeToGroup(cur.regType());
|
||||||
uint32_t outGroup = archTraits.regTypeToGroup(out.regType());
|
RegGroup outGroup = archTraits.regTypeToGroup(out.regType());
|
||||||
|
|
||||||
uint32_t curId = cur.regId();
|
uint32_t curId = cur.regId();
|
||||||
uint32_t outId = out.regId();
|
uint32_t outId = out.regId();
|
||||||
@@ -228,8 +202,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
|
|||||||
EmitMove:
|
EmitMove:
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(
|
||||||
emitArgMove(
|
emitArgMove(
|
||||||
BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
|
BaseReg(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
|
||||||
BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
|
BaseReg(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
|
||||||
|
|
||||||
wd.reassign(varId, outId, curId);
|
wd.reassign(varId, outId, curId);
|
||||||
cur.initReg(out.regType(), outId, out.typeId());
|
cur.initReg(out.regType(), outId, out.typeId());
|
||||||
@@ -244,15 +218,15 @@ EmitMove:
|
|||||||
|
|
||||||
if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) {
|
if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) {
|
||||||
// Only few architectures provide swap operations, and only for few register groups.
|
// Only few architectures provide swap operations, and only for few register groups.
|
||||||
if (archTraits.hasSwap(curGroup)) {
|
if (archTraits.hasInstRegSwap(curGroup)) {
|
||||||
uint32_t highestType = Support::max(cur.regType(), altVar.cur.regType());
|
RegType highestType = Support::max(cur.regType(), altVar.cur.regType());
|
||||||
if (Support::isBetween<uint32_t>(highestType, BaseReg::kTypeGp8Lo, BaseReg::kTypeGp16))
|
if (Support::isBetween(highestType, RegType::kGp8Lo, RegType::kGp16))
|
||||||
highestType = BaseReg::kTypeGp32;
|
highestType = RegType::kGp32;
|
||||||
|
|
||||||
uint32_t signature = archTraits.regTypeToSignature(highestType);
|
OperandSignature signature = archTraits.regTypeToSignature(highestType);
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(
|
||||||
emitRegSwap(BaseReg::fromSignatureAndId(signature, outId),
|
emitRegSwap(BaseReg(signature, outId), BaseReg(signature, curId)));
|
||||||
BaseReg::fromSignatureAndId(signature, curId)));
|
|
||||||
wd.swap(varId, curId, altId, outId);
|
wd.swap(varId, curId, altId, outId);
|
||||||
cur.setRegId(outId);
|
cur.setRegId(outId);
|
||||||
var.markDone();
|
var.markDone();
|
||||||
@@ -264,9 +238,9 @@ EmitMove:
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// If there is a scratch register it can be used to perform the swap.
|
// If there is a scratch register it can be used to perform the swap.
|
||||||
uint32_t availableRegs = wd.availableRegs();
|
RegMask availableRegs = wd.availableRegs();
|
||||||
if (availableRegs) {
|
if (availableRegs) {
|
||||||
uint32_t inOutRegs = wd.dstRegs();
|
RegMask inOutRegs = wd.dstRegs();
|
||||||
if (availableRegs & ~inOutRegs)
|
if (availableRegs & ~inOutRegs)
|
||||||
availableRegs &= ~inOutRegs;
|
availableRegs &= ~inOutRegs;
|
||||||
outId = Support::ctz(availableRegs);
|
outId = Support::ctz(availableRegs);
|
||||||
@@ -294,10 +268,8 @@ EmitMove:
|
|||||||
workFlags = (workFlags & kWorkDidSome) ? kWorkNone : kWorkPostponed;
|
workFlags = (workFlags & kWorkDidSome) ? kWorkNone : kWorkPostponed;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
// Load arguments passed by stack into registers. This is pretty simple and
|
// Load arguments passed by stack into registers. This is pretty simple and
|
||||||
// it never requires multiple iterations like the previous phase.
|
// it never requires multiple iterations like the previous phase.
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (ctx._hasStackSrc) {
|
if (ctx._hasStackSrc) {
|
||||||
uint32_t iterCount = 1;
|
uint32_t iterCount = 1;
|
||||||
@@ -317,12 +289,12 @@ EmitMove:
|
|||||||
ASMJIT_ASSERT(var.out.isReg());
|
ASMJIT_ASSERT(var.out.isReg());
|
||||||
|
|
||||||
uint32_t outId = var.out.regId();
|
uint32_t outId = var.out.regId();
|
||||||
uint32_t outType = var.out.regType();
|
RegType outType = var.out.regType();
|
||||||
|
|
||||||
uint32_t group = archTraits.regTypeToGroup(outType);
|
RegGroup group = archTraits.regTypeToGroup(outType);
|
||||||
WorkData& wd = ctx._workData[group];
|
WorkData& wd = workData[group];
|
||||||
|
|
||||||
if (outId == sa.id() && group == BaseReg::kGroupGp) {
|
if (outId == sa.id() && group == RegGroup::kGp) {
|
||||||
// This register will be processed last as we still need `saRegId`.
|
// This register will be processed last as we still need `saRegId`.
|
||||||
if (iterCount == 1) {
|
if (iterCount == 1) {
|
||||||
iterCount++;
|
iterCount++;
|
||||||
@@ -331,7 +303,7 @@ EmitMove:
|
|||||||
wd.unassign(wd._physToVarId[outId], outId);
|
wd.unassign(wd._physToVarId[outId], outId);
|
||||||
}
|
}
|
||||||
|
|
||||||
BaseReg dstReg = BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(outType), outId);
|
BaseReg dstReg = BaseReg(archTraits.regTypeToSignature(outType), outId);
|
||||||
BaseMem srcMem = baseArgPtr.cloneAdjusted(var.cur.stackOffset());
|
BaseMem srcMem = baseArgPtr.cloneAdjusted(var.cur.stackOffset());
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(emitArgMove(
|
ASMJIT_PROPAGATE(emitArgMove(
|
||||||
|
|||||||
@@ -1,26 +1,7 @@
|
|||||||
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
// AsmJit - Machine code generation for C++
|
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
#define ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
|
||||||
@@ -35,10 +16,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::BaseEmitHelper]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Helper class that provides utilities for each supported architecture.
|
//! Helper class that provides utilities for each supported architecture.
|
||||||
class BaseEmitHelper {
|
class BaseEmitHelper {
|
||||||
public:
|
public:
|
||||||
@@ -50,12 +27,11 @@ public:
|
|||||||
inline BaseEmitter* emitter() const noexcept { return _emitter; }
|
inline BaseEmitter* emitter() const noexcept { return _emitter; }
|
||||||
inline void setEmitter(BaseEmitter* emitter) noexcept { _emitter = emitter; }
|
inline void setEmitter(BaseEmitter* emitter) noexcept { _emitter = emitter; }
|
||||||
|
|
||||||
//! Emits a pure move operation between two registers or the same type or
|
//! Emits a pure move operation between two registers or the same type or between a register and its home
|
||||||
//! between a register and its home slot. This function does not handle
|
//! slot. This function does not handle register conversion.
|
||||||
//! register conversion.
|
|
||||||
virtual Error emitRegMove(
|
virtual Error emitRegMove(
|
||||||
const Operand_& dst_,
|
const Operand_& dst_,
|
||||||
const Operand_& src_, uint32_t typeId, const char* comment = nullptr) = 0;
|
const Operand_& src_, TypeId typeId, const char* comment = nullptr) = 0;
|
||||||
|
|
||||||
//! Emits swap between two registers.
|
//! Emits swap between two registers.
|
||||||
virtual Error emitRegSwap(
|
virtual Error emitRegSwap(
|
||||||
@@ -64,13 +40,12 @@ public:
|
|||||||
|
|
||||||
//! 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.
|
||||||
//!
|
//!
|
||||||
//! This function can handle the necessary conversion from one argument to
|
//! This function can handle the necessary conversion from one argument to another, and from one register type
|
||||||
//! another, and from one register type to another, if it's possible. Any
|
//! to another, if it's possible. Any attempt of conversion that requires third register of a different group
|
||||||
//! 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_, uint32_t dstTypeId,
|
const BaseReg& dst_, TypeId dstTypeId,
|
||||||
const Operand_& src_, uint32_t srcTypeId, const char* comment = nullptr) = 0;
|
const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr) = 0;
|
||||||
|
|
||||||
Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/emitterutils_p.h"
|
#include "../core/emitterutils_p.h"
|
||||||
@@ -39,91 +21,85 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Construction & Destruction
|
||||||
// [asmjit::BaseEmitter - Construction / Destruction]
|
// ========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept
|
BaseEmitter::BaseEmitter(EmitterType emitterType) noexcept
|
||||||
: _emitterType(uint8_t(emitterType)) {}
|
: _emitterType(emitterType) {}
|
||||||
|
|
||||||
BaseEmitter::~BaseEmitter() noexcept {
|
BaseEmitter::~BaseEmitter() noexcept {
|
||||||
if (_code) {
|
if (_code) {
|
||||||
_addEmitterFlags(kFlagDestroyed);
|
_addEmitterFlags(EmitterFlags::kDestroyed);
|
||||||
_code->detach(this);
|
_code->detach(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Finalize
|
||||||
// [asmjit::BaseEmitter - Finalize]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseEmitter::finalize() {
|
Error BaseEmitter::finalize() {
|
||||||
// Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`.
|
// Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`.
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Internals
|
||||||
// [asmjit::BaseEmitter - Internals]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static constexpr uint32_t kEmitterPreservedFlags = BaseEmitter::kFlagOwnLogger | BaseEmitter::kFlagOwnErrorHandler;
|
static constexpr EmitterFlags kEmitterPreservedFlags = EmitterFlags::kOwnLogger | EmitterFlags::kOwnErrorHandler;
|
||||||
|
|
||||||
static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept {
|
static ASMJIT_NOINLINE void BaseEmitter_updateForcedOptions(BaseEmitter* self) noexcept {
|
||||||
bool emitComments = false;
|
bool emitComments = false;
|
||||||
bool hasValidationOptions = false;
|
bool hasDiagnosticOptions = false;
|
||||||
|
|
||||||
if (self->emitterType() == BaseEmitter::kTypeAssembler) {
|
if (self->emitterType() == EmitterType::kAssembler) {
|
||||||
// Assembler: Don't emit comments if logger is not attached.
|
// Assembler: Don't emit comments if logger is not attached.
|
||||||
emitComments = self->_code != nullptr && self->_logger != nullptr;
|
emitComments = self->_code != nullptr && self->_logger != nullptr;
|
||||||
hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler);
|
hasDiagnosticOptions = self->hasDiagnosticOption(DiagnosticOptions::kValidateAssembler);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Builder/Compiler: Always emit comments, we cannot assume they won't be used.
|
// Builder/Compiler: Always emit comments, we cannot assume they won't be used.
|
||||||
emitComments = self->_code != nullptr;
|
emitComments = self->_code != nullptr;
|
||||||
hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate);
|
hasDiagnosticOptions = self->hasDiagnosticOption(DiagnosticOptions::kValidateIntermediate);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (emitComments)
|
if (emitComments)
|
||||||
self->_addEmitterFlags(BaseEmitter::kFlagLogComments);
|
self->_addEmitterFlags(EmitterFlags::kLogComments);
|
||||||
else
|
else
|
||||||
self->_clearEmitterFlags(BaseEmitter::kFlagLogComments);
|
self->_clearEmitterFlags(EmitterFlags::kLogComments);
|
||||||
|
|
||||||
// The reserved option tells emitter (Assembler/Builder/Compiler) that there
|
// The reserved option tells emitter (Assembler/Builder/Compiler) that there may be either a border
|
||||||
// may be either a border case (CodeHolder not attached, for example) or that
|
// case (CodeHolder not attached, for example) or that logging or validation is required.
|
||||||
// logging or validation is required.
|
if (self->_code == nullptr || self->_logger || hasDiagnosticOptions)
|
||||||
if (self->_code == nullptr || self->_logger || hasValidationOptions)
|
self->_forcedInstOptions |= InstOptions::kReserved;
|
||||||
self->_forcedInstOptions |= BaseInst::kOptionReserved;
|
|
||||||
else
|
else
|
||||||
self->_forcedInstOptions &= ~BaseInst::kOptionReserved;
|
self->_forcedInstOptions &= ~InstOptions::kReserved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Diagnostic Options
|
||||||
// [asmjit::BaseEmitter - Validation Options]
|
// ================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void BaseEmitter::addValidationOptions(uint32_t options) noexcept {
|
void BaseEmitter::addDiagnosticOptions(DiagnosticOptions options) noexcept {
|
||||||
_validationOptions = uint8_t(_validationOptions | options);
|
_diagnosticOptions |= options;
|
||||||
BaseEmitter_updateForcedOptions(this);
|
BaseEmitter_updateForcedOptions(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void BaseEmitter::clearValidationOptions(uint32_t options) noexcept {
|
void BaseEmitter::clearDiagnosticOptions(DiagnosticOptions options) noexcept {
|
||||||
_validationOptions = uint8_t(_validationOptions | options);
|
_diagnosticOptions &= ~options;
|
||||||
BaseEmitter_updateForcedOptions(this);
|
BaseEmitter_updateForcedOptions(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Logging
|
||||||
// [asmjit::BaseEmitter - Logging]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void BaseEmitter::setLogger(Logger* logger) noexcept {
|
void BaseEmitter::setLogger(Logger* logger) noexcept {
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
if (logger) {
|
if (logger) {
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_addEmitterFlags(kFlagOwnLogger);
|
_addEmitterFlags(EmitterFlags::kOwnLogger);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_logger = nullptr;
|
_logger = nullptr;
|
||||||
_clearEmitterFlags(kFlagOwnLogger);
|
_clearEmitterFlags(EmitterFlags::kOwnLogger);
|
||||||
if (_code)
|
if (_code)
|
||||||
_logger = _code->logger();
|
_logger = _code->logger();
|
||||||
}
|
}
|
||||||
@@ -133,18 +109,17 @@ void BaseEmitter::setLogger(Logger* logger) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Error Handling
|
||||||
// [asmjit::BaseEmitter - Error Handling]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept {
|
void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept {
|
||||||
if (errorHandler) {
|
if (errorHandler) {
|
||||||
_errorHandler = errorHandler;
|
_errorHandler = errorHandler;
|
||||||
_addEmitterFlags(kFlagOwnErrorHandler);
|
_addEmitterFlags(EmitterFlags::kOwnErrorHandler);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
_errorHandler = nullptr;
|
_errorHandler = nullptr;
|
||||||
_clearEmitterFlags(kFlagOwnErrorHandler);
|
_clearEmitterFlags(EmitterFlags::kOwnErrorHandler);
|
||||||
if (_code)
|
if (_code)
|
||||||
_errorHandler = _code->errorHandler();
|
_errorHandler = _code->errorHandler();
|
||||||
}
|
}
|
||||||
@@ -160,58 +135,55 @@ Error BaseEmitter::reportError(Error err, const char* message) {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Labels
|
||||||
// [asmjit::BaseEmitter - Labels]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept {
|
Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept {
|
||||||
return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId));
|
return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : Globals::kInvalidId);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept {
|
bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept {
|
||||||
return _code && labelId < _code->labelCount();
|
return _code && labelId < _code->labelCount();
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Emit (Low-Level)
|
||||||
// [asmjit::BaseEmitter - Emit (Low-Level)]
|
// ==============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
using EmitterUtils::noExt;
|
using EmitterUtils::noExt;
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId) {
|
Error BaseEmitter::_emitI(InstId instId) {
|
||||||
return _emit(instId, noExt[0], noExt[1], noExt[2], noExt);
|
return _emit(instId, noExt[0], noExt[1], noExt[2], noExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0) {
|
||||||
return _emit(instId, o0, noExt[1], noExt[2], noExt);
|
return _emit(instId, o0, noExt[1], noExt[2], noExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1) {
|
||||||
return _emit(instId, o0, o1, noExt[2], noExt);
|
return _emit(instId, o0, o1, noExt[2], noExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2) {
|
||||||
return _emit(instId, o0, o1, o2, noExt);
|
return _emit(instId, o0, o1, o2, noExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
|
||||||
Operand_ opExt[3] = { o3 };
|
Operand_ opExt[3] = { o3 };
|
||||||
return _emit(instId, o0, o1, o2, opExt);
|
return _emit(instId, o0, o1, o2, opExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4) {
|
||||||
Operand_ opExt[3] = { o3, o4 };
|
Operand_ opExt[3] = { o3, o4 };
|
||||||
return _emit(instId, o0, o1, o2, opExt);
|
return _emit(instId, o0, o1, o2, opExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
|
Error BaseEmitter::_emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
|
||||||
Operand_ opExt[3] = { o3, o4, o5 };
|
Operand_ opExt[3] = { o3, o4, o5 };
|
||||||
return _emit(instId, o0, o1, o2, opExt);
|
return _emit(instId, o0, o1, o2, opExt);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) {
|
Error BaseEmitter::_emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
|
||||||
const Operand_* op = operands;
|
const Operand_* op = operands;
|
||||||
|
|
||||||
Operand_ opExt[3];
|
Operand_ opExt[3];
|
||||||
|
|
||||||
switch (opCount) {
|
switch (opCount) {
|
||||||
@@ -247,9 +219,8 @@ Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Emit (High-Level)
|
||||||
// [asmjit::BaseEmitter - Emit (High-Level)]
|
// ===============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) {
|
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) {
|
||||||
if (ASMJIT_UNLIKELY(!_code))
|
if (ASMJIT_UNLIKELY(!_code))
|
||||||
@@ -314,13 +285,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame,
|
|||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Comment
|
||||||
// [asmjit::BaseEmitter - Comment]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error BaseEmitter::commentf(const char* fmt, ...) {
|
Error BaseEmitter::commentf(const char* fmt, ...) {
|
||||||
if (!hasEmitterFlag(kFlagLogComments)) {
|
if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
|
||||||
if (!hasEmitterFlag(kFlagAttached))
|
if (!hasEmitterFlag(EmitterFlags::kAttached))
|
||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
@@ -342,8 +312,8 @@ Error BaseEmitter::commentf(const char* fmt, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error BaseEmitter::commentv(const char* fmt, va_list ap) {
|
Error BaseEmitter::commentv(const char* fmt, va_list ap) {
|
||||||
if (!hasEmitterFlag(kFlagLogComments)) {
|
if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
|
||||||
if (!hasEmitterFlag(kFlagAttached))
|
if (!hasEmitterFlag(EmitterFlags::kAttached))
|
||||||
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
return reportError(DebugUtils::errored(kErrorNotInitialized));
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
@@ -360,18 +330,17 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// BaseEmitter - Events
|
||||||
// [asmjit::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(kFlagAttached);
|
_addEmitterFlags(EmitterFlags::kAttached);
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
|
||||||
uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
|
RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
|
||||||
_gpRegInfo.setSignature(archTraits._regInfo[nativeRegType].signature());
|
_gpSignature = archTraits.regTypeToSignature(nativeRegType);
|
||||||
|
|
||||||
onSettingsUpdated();
|
onSettingsUpdated();
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -387,13 +356,13 @@ Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
|
|||||||
_errorHandler = nullptr;
|
_errorHandler = nullptr;
|
||||||
|
|
||||||
_clearEmitterFlags(~kEmitterPreservedFlags);
|
_clearEmitterFlags(~kEmitterPreservedFlags);
|
||||||
_forcedInstOptions = BaseInst::kOptionReserved;
|
_forcedInstOptions = InstOptions::kReserved;
|
||||||
_privateData = 0;
|
_privateData = 0;
|
||||||
|
|
||||||
_environment.reset();
|
_environment.reset();
|
||||||
_gpRegInfo.reset();
|
_gpSignature.reset();
|
||||||
|
|
||||||
_instOptions = 0;
|
_instOptions = InstOptions::kNone;
|
||||||
_extraReg.reset();
|
_extraReg.reset();
|
||||||
_inlineComment = nullptr;
|
_inlineComment = nullptr;
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_EMITTER_H_INCLUDED
|
#define ASMJIT_CORE_EMITTER_H_INCLUDED
|
||||||
@@ -35,41 +17,203 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class ConstPool;
|
class ConstPool;
|
||||||
class FuncFrame;
|
class FuncFrame;
|
||||||
class FuncArgsAssignment;
|
class FuncArgsAssignment;
|
||||||
|
|
||||||
// ============================================================================
|
//! Align mode, used by \ref BaseEmitter::align().
|
||||||
// [asmjit::BaseEmitter]
|
enum class AlignMode : uint8_t {
|
||||||
// ============================================================================
|
//! Align executable code.
|
||||||
|
kCode = 0,
|
||||||
|
//! Align non-executable code.
|
||||||
|
kData = 1,
|
||||||
|
//! Align by a sequence of zeros.
|
||||||
|
kZero = 2,
|
||||||
|
|
||||||
//! Provides a base foundation to emit code - specialized by `Assembler` and
|
//! Maximum value of `AlignMode`.
|
||||||
//! `BaseBuilder`.
|
kMaxValue = kZero
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Emitter type used by \ref BaseEmitter.
|
||||||
|
enum class EmitterType : uint8_t {
|
||||||
|
//! Unknown or uninitialized.
|
||||||
|
kNone = 0,
|
||||||
|
//! Emitter inherits from \ref BaseAssembler.
|
||||||
|
kAssembler = 1,
|
||||||
|
//! Emitter inherits from \ref BaseBuilder.
|
||||||
|
kBuilder = 2,
|
||||||
|
//! Emitter inherits from \ref BaseCompiler.
|
||||||
|
kCompiler = 3,
|
||||||
|
|
||||||
|
//! Maximum value of `EmitterType`.
|
||||||
|
kMaxValue = kCompiler
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Emitter flags, used by \ref BaseEmitter.
|
||||||
|
enum class EmitterFlags : uint8_t {
|
||||||
|
//! No flags.
|
||||||
|
kNone = 0u,
|
||||||
|
//! Emitter is attached to CodeHolder.
|
||||||
|
kAttached = 0x01u,
|
||||||
|
//! The emitter must emit comments.
|
||||||
|
kLogComments = 0x08u,
|
||||||
|
//! The emitter has its own \ref Logger (not propagated from \ref CodeHolder).
|
||||||
|
kOwnLogger = 0x10u,
|
||||||
|
//! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder).
|
||||||
|
kOwnErrorHandler = 0x20u,
|
||||||
|
//! The emitter was finalized.
|
||||||
|
kFinalized = 0x40u,
|
||||||
|
//! The emitter was destroyed.
|
||||||
|
//!
|
||||||
|
//! This flag is used for a very short time when an emitter is being destroyed by
|
||||||
|
//! CodeHolder.
|
||||||
|
kDestroyed = 0x80u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(EmitterFlags)
|
||||||
|
|
||||||
|
//! Encoding options.
|
||||||
|
enum class EncodingOptions : uint32_t {
|
||||||
|
//! No encoding options.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Emit instructions that are optimized for size, if possible.
|
||||||
|
//!
|
||||||
|
//! Default: false.
|
||||||
|
//!
|
||||||
|
//! X86 Specific
|
||||||
|
//! ------------
|
||||||
|
//!
|
||||||
|
//! When this option is set it the assembler will try to fix instructions if possible into operation equivalent
|
||||||
|
//! instructions that take less bytes by taking advantage of implicit zero extension. For example instruction
|
||||||
|
//! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm` and `and r32, imm` when the
|
||||||
|
//! immediate constant is lesser than `2^31`.
|
||||||
|
kOptimizeForSize = 0x00000001u,
|
||||||
|
|
||||||
|
//! Emit optimized code-alignment sequences.
|
||||||
|
//!
|
||||||
|
//! Default: false.
|
||||||
|
//!
|
||||||
|
//! X86 Specific
|
||||||
|
//! ------------
|
||||||
|
//!
|
||||||
|
//! Default align sequence used by X86 architecture is one-byte (0x90) opcode that is often shown by disassemblers
|
||||||
|
//! as NOP. However there are more optimized align sequences for 2-11 bytes that may execute faster on certain CPUs.
|
||||||
|
//! If this feature is enabled AsmJit will generate specialized sequences for alignment between 2 to 11 bytes.
|
||||||
|
kOptimizedAlign = 0x00000002u,
|
||||||
|
|
||||||
|
//! Emit jump-prediction hints.
|
||||||
|
//!
|
||||||
|
//! Default: false.
|
||||||
|
//!
|
||||||
|
//! X86 Specific
|
||||||
|
//! ------------
|
||||||
|
//!
|
||||||
|
//! Jump prediction is usually based on the direction of the jump. If the jump is backward it is usually predicted as
|
||||||
|
//! taken; and if the jump is forward it is usually predicted as not-taken. The reason is that loops generally use
|
||||||
|
//! backward jumps and conditions usually use forward jumps. However this behavior can be overridden by using
|
||||||
|
//! instruction prefixes. If this option is enabled these hints will be emitted.
|
||||||
|
//!
|
||||||
|
//! This feature is disabled by default, because the only processor that used to take into consideration prediction
|
||||||
|
//! hints was P4. Newer processors implement heuristics for branch prediction and ignore static hints. This means
|
||||||
|
//! that this feature can be only used for annotation purposes.
|
||||||
|
kPredictedJumps = 0x00000010u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(EncodingOptions)
|
||||||
|
|
||||||
|
//! Diagnostic options are used to tell emitters and their passes to perform diagnostics when emitting or processing
|
||||||
|
//! user code. These options control validation and extra diagnostics that can be performed by higher level emitters.
|
||||||
|
//!
|
||||||
|
//! Instruction Validation
|
||||||
|
//! ----------------------
|
||||||
|
//!
|
||||||
|
//! \ref BaseAssembler implementation perform by default only basic checks that are necessary to identify all
|
||||||
|
//! variations of an instruction so the correct encoding can be selected. This is fine for production-ready code
|
||||||
|
//! as the assembler doesn't have to perform checks that would slow it down. However, sometimes these checks are
|
||||||
|
//! beneficial especially when the project that uses AsmJit is in a development phase, in which mistakes happen
|
||||||
|
//! often. To make the experience of using AsmJit seamless it offers validation features that can be controlled
|
||||||
|
//! by \ref DiagnosticOptions.
|
||||||
|
//!
|
||||||
|
//! Compiler Diagnostics
|
||||||
|
//! --------------------
|
||||||
|
//!
|
||||||
|
//! Diagnostic options work with \ref BaseCompiler passes (precisely with its register allocation pass). These options
|
||||||
|
//! can be used to enable logging of all operations that the Compiler does.
|
||||||
|
enum class DiagnosticOptions : uint32_t {
|
||||||
|
//! No validation options.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Perform strict validation in \ref BaseAssembler::emit() implementations.
|
||||||
|
//!
|
||||||
|
//! This flag ensures that each instruction is checked before it's encoded into a binary representation. This flag
|
||||||
|
//! is only relevant for \ref BaseAssembler implementations, but can be set in any other emitter type, in that case
|
||||||
|
//! if that emitter needs to create an assembler on its own, for the purpose of \ref BaseEmitter::finalize() it
|
||||||
|
//! would propagate this flag to such assembler so all instructions passed to it are explicitly validated.
|
||||||
|
//!
|
||||||
|
//! Default: false.
|
||||||
|
kValidateAssembler = 0x00000001u,
|
||||||
|
|
||||||
|
//! Perform strict validation in \ref BaseBuilder::emit() and \ref BaseCompiler::emit() implementations.
|
||||||
|
//!
|
||||||
|
//! This flag ensures that each instruction is checked before an \ref InstNode representing the instruction is
|
||||||
|
//! created by \ref BaseBuilder or \ref BaseCompiler. This option could be more useful than \ref kValidateAssembler
|
||||||
|
//! in cases in which there is an invalid instruction passed to an assembler, which was invalid much earlier, most
|
||||||
|
//! likely when such instruction was passed to Builder/Compiler.
|
||||||
|
//!
|
||||||
|
//! This is a separate option that was introduced, because it's possible to manipulate the instruction stream
|
||||||
|
//! emitted by \ref BaseBuilder and \ref BaseCompiler - this means that it's allowed to emit invalid instructions
|
||||||
|
//! (for example with missing operands) that will be fixed later before finalizing it.
|
||||||
|
//!
|
||||||
|
//! Default: false.
|
||||||
|
kValidateIntermediate = 0x00000002u,
|
||||||
|
|
||||||
|
//! Annotate all nodes processed by register allocator (Compiler/RA).
|
||||||
|
//!
|
||||||
|
//! \note Annotations don't need debug options, however, some debug options like `kRADebugLiveness` may influence
|
||||||
|
//! their output (for example the mentioned option would add liveness information to per-instruction annotation).
|
||||||
|
kRAAnnotate = 0x00000080u,
|
||||||
|
|
||||||
|
//! Debug CFG generation and other related algorithms / operations (Compiler/RA).
|
||||||
|
kRADebugCFG = 0x00000100u,
|
||||||
|
|
||||||
|
//! Debug liveness analysis (Compiler/RA).
|
||||||
|
kRADebugLiveness = 0x00000200u,
|
||||||
|
|
||||||
|
//! Debug register allocation assignment (Compiler/RA).
|
||||||
|
kRADebugAssignment = 0x00000400u,
|
||||||
|
|
||||||
|
//! Debug the removal of code part of unreachable blocks.
|
||||||
|
kRADebugUnreachable = 0x00000800u,
|
||||||
|
|
||||||
|
//! Enable all debug options (Compiler/RA).
|
||||||
|
kRADebugAll = 0x0000FF00u,
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(DiagnosticOptions)
|
||||||
|
|
||||||
|
//! Provides a base foundation to emitting code - specialized by \ref BaseAssembler and \ref BaseBuilder.
|
||||||
class ASMJIT_VIRTAPI BaseEmitter {
|
class ASMJIT_VIRTAPI BaseEmitter {
|
||||||
public:
|
public:
|
||||||
ASMJIT_BASE_CLASS(BaseEmitter)
|
ASMJIT_BASE_CLASS(BaseEmitter)
|
||||||
|
|
||||||
//! See \ref EmitterType.
|
//! \name Members
|
||||||
uint8_t _emitterType = 0;
|
//! \{
|
||||||
//! See \ref BaseEmitter::EmitterFlags.
|
|
||||||
uint8_t _emitterFlags = 0;
|
|
||||||
//! Validation flags in case validation is used, see \ref InstAPI::ValidationFlags.
|
|
||||||
//!
|
|
||||||
//! \note Validation flags are specific to the emitter and they are setup at
|
|
||||||
//! construction time and then never changed.
|
|
||||||
uint8_t _validationFlags = 0;
|
|
||||||
//! Validation options, see \ref ValidationOptions.
|
|
||||||
uint8_t _validationOptions = 0;
|
|
||||||
|
|
||||||
//! Encoding options, see \ref EncodingOptions.
|
//! See \ref EmitterType.
|
||||||
uint32_t _encodingOptions = 0;
|
EmitterType _emitterType = EmitterType::kNone;
|
||||||
|
//! See \ref EmitterFlags.
|
||||||
|
EmitterFlags _emitterFlags = EmitterFlags::kNone;
|
||||||
|
//! 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().
|
//! Forced instruction options, combined with \ref _instOptions by \ref emit().
|
||||||
uint32_t _forcedInstOptions = BaseInst::kOptionReserved;
|
InstOptions _forcedInstOptions = InstOptions::kReserved;
|
||||||
//! Internal private data used freely by any emitter.
|
//! Internal private data used freely by any emitter.
|
||||||
uint32_t _privateData = 0;
|
uint32_t _privateData = 0;
|
||||||
|
|
||||||
@@ -83,143 +227,21 @@ public:
|
|||||||
//! Describes the target environment, matches \ref CodeHolder::environment().
|
//! Describes the target environment, matches \ref CodeHolder::environment().
|
||||||
Environment _environment {};
|
Environment _environment {};
|
||||||
//! Native GP register signature and signature related information.
|
//! Native GP register signature and signature related information.
|
||||||
RegInfo _gpRegInfo {};
|
OperandSignature _gpSignature {};
|
||||||
|
|
||||||
//! Next instruction options (affects the next instruction).
|
//! Next instruction options (affects the next instruction).
|
||||||
uint32_t _instOptions = 0;
|
InstOptions _instOptions = InstOptions::kNone;
|
||||||
//! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
//! Extra register (op-mask {k} on AVX-512) (affects the next instruction).
|
||||||
RegOnly _extraReg {};
|
RegOnly _extraReg {};
|
||||||
//! Inline comment of the next instruction (affects the next instruction).
|
//! Inline comment of the next instruction (affects the next instruction).
|
||||||
const char* _inlineComment = nullptr;
|
const char* _inlineComment = nullptr;
|
||||||
|
|
||||||
//! Emitter type.
|
//! \}
|
||||||
enum EmitterType : uint32_t {
|
|
||||||
//! Unknown or uninitialized.
|
|
||||||
kTypeNone = 0,
|
|
||||||
//! Emitter inherits from \ref BaseAssembler.
|
|
||||||
kTypeAssembler = 1,
|
|
||||||
//! Emitter inherits from \ref BaseBuilder.
|
|
||||||
kTypeBuilder = 2,
|
|
||||||
//! Emitter inherits from \ref BaseCompiler.
|
|
||||||
kTypeCompiler = 3,
|
|
||||||
|
|
||||||
//! Count of emitter types.
|
|
||||||
kTypeCount = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Emitter flags.
|
|
||||||
enum EmitterFlags : uint32_t {
|
|
||||||
//! Emitter is attached to CodeHolder.
|
|
||||||
kFlagAttached = 0x01u,
|
|
||||||
//! The emitter must emit comments.
|
|
||||||
kFlagLogComments = 0x08u,
|
|
||||||
//! The emitter has its own \ref Logger (not propagated from \ref CodeHolder).
|
|
||||||
kFlagOwnLogger = 0x10u,
|
|
||||||
//! The emitter has its own \ref ErrorHandler (not propagated from \ref CodeHolder).
|
|
||||||
kFlagOwnErrorHandler = 0x20u,
|
|
||||||
//! The emitter was finalized.
|
|
||||||
kFlagFinalized = 0x40u,
|
|
||||||
//! The emitter was destroyed.
|
|
||||||
kFlagDestroyed = 0x80u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Encoding options.
|
|
||||||
enum EncodingOptions : uint32_t {
|
|
||||||
//! Emit instructions that are optimized for size, if possible.
|
|
||||||
//!
|
|
||||||
//! Default: false.
|
|
||||||
//!
|
|
||||||
//! X86 Specific
|
|
||||||
//! ------------
|
|
||||||
//!
|
|
||||||
//! When this option is set it the assembler will try to fix instructions
|
|
||||||
//! if possible into operation equivalent instructions that take less bytes
|
|
||||||
//! by taking advantage of implicit zero extension. For example instruction
|
|
||||||
//! like `mov r64, imm` and `and r64, imm` can be translated to `mov r32, imm`
|
|
||||||
//! and `and r32, imm` when the immediate constant is lesser than `2^31`.
|
|
||||||
kEncodingOptionOptimizeForSize = 0x00000001u,
|
|
||||||
|
|
||||||
//! Emit optimized code-alignment sequences.
|
|
||||||
//!
|
|
||||||
//! Default: false.
|
|
||||||
//!
|
|
||||||
//! X86 Specific
|
|
||||||
//! ------------
|
|
||||||
//!
|
|
||||||
//! Default align sequence used by X86 architecture is one-byte (0x90)
|
|
||||||
//! opcode that is often shown by disassemblers as NOP. However there are
|
|
||||||
//! more optimized align sequences for 2-11 bytes that may execute faster
|
|
||||||
//! on certain CPUs. If this feature is enabled AsmJit will generate
|
|
||||||
//! specialized sequences for alignment between 2 to 11 bytes.
|
|
||||||
kEncodingOptionOptimizedAlign = 0x00000002u,
|
|
||||||
|
|
||||||
//! Emit jump-prediction hints.
|
|
||||||
//!
|
|
||||||
//! Default: false.
|
|
||||||
//!
|
|
||||||
//! X86 Specific
|
|
||||||
//! ------------
|
|
||||||
//!
|
|
||||||
//! Jump prediction is usually based on the direction of the jump. If the
|
|
||||||
//! jump is backward it is usually predicted as taken; and if the jump is
|
|
||||||
//! forward it is usually predicted as not-taken. The reason is that loops
|
|
||||||
//! generally use backward jumps and conditions usually use forward jumps.
|
|
||||||
//! However this behavior can be overridden by using instruction prefixes.
|
|
||||||
//! If this option is enabled these hints will be emitted.
|
|
||||||
//!
|
|
||||||
//! This feature is disabled by default, because the only processor that
|
|
||||||
//! used to take into consideration prediction hints was P4. Newer processors
|
|
||||||
//! implement heuristics for branch prediction and ignore static hints. This
|
|
||||||
//! means that this feature can be only used for annotation purposes.
|
|
||||||
kEncodingOptionPredictedJumps = 0x00000010u
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
enum EmitterOptions : uint32_t {
|
|
||||||
kOptionOptimizedForSize = kEncodingOptionOptimizeForSize,
|
|
||||||
kOptionOptimizedAlign = kEncodingOptionOptimizedAlign,
|
|
||||||
kOptionPredictedJumps = kEncodingOptionPredictedJumps
|
|
||||||
};
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//! Validation options are used to tell emitters to perform strict validation
|
|
||||||
//! of instructions passed to \ref emit().
|
|
||||||
//!
|
|
||||||
//! \ref BaseAssembler implementation perform by default only basic checks
|
|
||||||
//! that are necessary to identify all variations of an instruction so the
|
|
||||||
//! correct encoding can be selected. This is fine for production-ready code
|
|
||||||
//! as the assembler doesn't have to perform checks that would slow it down.
|
|
||||||
//! However, sometimes these checks are beneficial especially when the project
|
|
||||||
//! that uses AsmJit is in a development phase, in which mistakes happen often.
|
|
||||||
//! To make the experience of using AsmJit seamless it offers validation
|
|
||||||
//! features that can be controlled by `ValidationOptions`.
|
|
||||||
enum ValidationOptions : uint32_t {
|
|
||||||
//! Perform strict validation in \ref BaseAssembler::emit() implementations.
|
|
||||||
//!
|
|
||||||
//! This flag ensures that each instruction is checked before it's encoded
|
|
||||||
//! into a binary representation. This flag is only relevant for \ref
|
|
||||||
//! BaseAssembler implementations, but can be set in any other emitter type,
|
|
||||||
//! in that case if that emitter needs to create an assembler on its own,
|
|
||||||
//! for the purpose of \ref finalize() it would propagate this flag to such
|
|
||||||
//! assembler so all instructions passed to it are explicitly validated.
|
|
||||||
//!
|
|
||||||
//! Default: false.
|
|
||||||
kValidationOptionAssembler = 0x00000001u,
|
|
||||||
|
|
||||||
//! Perform strict validation in \ref BaseBuilder::emit() and \ref
|
|
||||||
//! BaseCompiler::emit() implementations.
|
|
||||||
//!
|
|
||||||
//! This flag ensures that each instruction is checked before an \ref
|
|
||||||
//! InstNode representing the instruction is created by Builder or Compiler.
|
|
||||||
//!
|
|
||||||
//! Default: false.
|
|
||||||
kValidationOptionIntermediate = 0x00000002u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_API explicit BaseEmitter(uint32_t emitterType) noexcept;
|
ASMJIT_API explicit BaseEmitter(EmitterType emitterType) noexcept;
|
||||||
ASMJIT_API virtual ~BaseEmitter() noexcept;
|
ASMJIT_API virtual ~BaseEmitter() noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -239,28 +261,28 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the type of this emitter, see `EmitterType`.
|
//! Returns the type of this emitter, see `EmitterType`.
|
||||||
inline uint32_t emitterType() const noexcept { return _emitterType; }
|
inline EmitterType emitterType() const noexcept { return _emitterType; }
|
||||||
//! Returns emitter flags , see `Flags`.
|
//! Returns emitter flags , see `Flags`.
|
||||||
inline uint32_t emitterFlags() const noexcept { return _emitterFlags; }
|
inline EmitterFlags emitterFlags() const noexcept { return _emitterFlags; }
|
||||||
|
|
||||||
//! Tests whether the emitter inherits from `BaseAssembler`.
|
//! Tests whether the emitter inherits from `BaseAssembler`.
|
||||||
inline bool isAssembler() const noexcept { return _emitterType == kTypeAssembler; }
|
inline bool isAssembler() const noexcept { return _emitterType == EmitterType::kAssembler; }
|
||||||
//! Tests whether the emitter inherits from `BaseBuilder`.
|
//! Tests whether the emitter inherits from `BaseBuilder`.
|
||||||
//!
|
//!
|
||||||
//! \note Both Builder and Compiler emitters would return `true`.
|
//! \note Both Builder and Compiler emitters would return `true`.
|
||||||
inline bool isBuilder() const noexcept { return _emitterType >= kTypeBuilder; }
|
inline bool isBuilder() const noexcept { return uint32_t(_emitterType) >= uint32_t(EmitterType::kBuilder); }
|
||||||
//! Tests whether the emitter inherits from `BaseCompiler`.
|
//! Tests whether the emitter inherits from `BaseCompiler`.
|
||||||
inline bool isCompiler() const noexcept { return _emitterType == kTypeCompiler; }
|
inline bool isCompiler() const noexcept { return _emitterType == EmitterType::kCompiler; }
|
||||||
|
|
||||||
//! Tests whether the emitter has the given `flag` enabled.
|
//! Tests whether the emitter has the given `flag` enabled.
|
||||||
inline bool hasEmitterFlag(uint32_t flag) const noexcept { return (_emitterFlags & flag) != 0; }
|
inline bool hasEmitterFlag(EmitterFlags flag) const noexcept { return Support::test(_emitterFlags, flag); }
|
||||||
//! Tests whether the emitter is finalized.
|
//! Tests whether the emitter is finalized.
|
||||||
inline bool isFinalized() const noexcept { return hasEmitterFlag(kFlagFinalized); }
|
inline bool isFinalized() const noexcept { return hasEmitterFlag(EmitterFlags::kFinalized); }
|
||||||
//! Tests whether the emitter is destroyed (only used during destruction).
|
//! Tests whether the emitter is destroyed (only used during destruction).
|
||||||
inline bool isDestroyed() const noexcept { return hasEmitterFlag(kFlagDestroyed); }
|
inline bool isDestroyed() const noexcept { return hasEmitterFlag(EmitterFlags::kDestroyed); }
|
||||||
|
|
||||||
inline void _addEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags | flags); }
|
inline void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
|
||||||
inline void _clearEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags & ~flags); }
|
inline void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -270,7 +292,7 @@ public:
|
|||||||
//! Returns the CodeHolder this emitter is attached to.
|
//! Returns the CodeHolder this emitter is attached to.
|
||||||
inline CodeHolder* code() const noexcept { return _code; }
|
inline CodeHolder* code() const noexcept { return _code; }
|
||||||
|
|
||||||
//! Returns the target environment, see \ref Environment.
|
//! Returns the target environment.
|
||||||
//!
|
//!
|
||||||
//! The returned \ref Environment reference matches \ref CodeHolder::environment().
|
//! The returned \ref Environment reference matches \ref CodeHolder::environment().
|
||||||
inline const Environment& environment() const noexcept { return _environment; }
|
inline const Environment& environment() const noexcept { return _environment; }
|
||||||
@@ -281,9 +303,9 @@ public:
|
|||||||
inline bool is64Bit() const noexcept { return environment().is64Bit(); }
|
inline bool is64Bit() const noexcept { return environment().is64Bit(); }
|
||||||
|
|
||||||
//! Returns the target architecture type.
|
//! Returns the target architecture type.
|
||||||
inline uint32_t arch() const noexcept { return environment().arch(); }
|
inline Arch arch() const noexcept { return environment().arch(); }
|
||||||
//! Returns the target architecture sub-type.
|
//! Returns the target architecture sub-type.
|
||||||
inline uint32_t subArch() const noexcept { return environment().subArch(); }
|
inline SubArch subArch() const noexcept { return environment().subArch(); }
|
||||||
|
|
||||||
//! Returns the target architecture's GP register size (4 or 8 bytes).
|
//! Returns the target architecture's GP register size (4 or 8 bytes).
|
||||||
inline uint32_t registerSize() const noexcept { return environment().registerSize(); }
|
inline uint32_t registerSize() const noexcept { return environment().registerSize(); }
|
||||||
@@ -298,12 +320,10 @@ public:
|
|||||||
|
|
||||||
//! Finalizes this emitter.
|
//! Finalizes this emitter.
|
||||||
//!
|
//!
|
||||||
//! Materializes the content of the emitter by serializing it to the attached
|
//! Materializes the content of the emitter by serializing it to the attached \ref CodeHolder through an architecture
|
||||||
//! \ref CodeHolder through an architecture specific \ref BaseAssembler. This
|
//! specific \ref BaseAssembler. This function won't do anything if the emitter inherits from \ref BaseAssembler as
|
||||||
//! function won't do anything if the emitter inherits from \ref BaseAssembler
|
//! assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. However, if this is an emitter that
|
||||||
//! as assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder.
|
//! inherits from \ref BaseBuilder or \ref BaseCompiler then these emitters need the materialization phase as they
|
||||||
//! However, if this is an emitter that inherits from \ref BaseBuilder or \ref
|
|
||||||
//! BaseCompiler then these emitters need the materialization phase as they
|
|
||||||
//! store their content in a representation not visible to \ref CodeHolder.
|
//! store their content in a representation not visible to \ref CodeHolder.
|
||||||
ASMJIT_API virtual Error finalize();
|
ASMJIT_API virtual Error finalize();
|
||||||
|
|
||||||
@@ -317,29 +337,27 @@ public:
|
|||||||
|
|
||||||
//! Tests whether the emitter has its own logger.
|
//! Tests whether the emitter has its own logger.
|
||||||
//!
|
//!
|
||||||
//! Own logger means that it overrides the possible logger that may be used
|
//! Own logger means that it overrides the possible logger that may be used by \ref CodeHolder this emitter is
|
||||||
//! by \ref CodeHolder this emitter is attached to.
|
//! attached to.
|
||||||
inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(kFlagOwnLogger); }
|
inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnLogger); }
|
||||||
|
|
||||||
//! Returns the logger this emitter uses.
|
//! Returns the logger this emitter uses.
|
||||||
//!
|
//!
|
||||||
//! The returned logger is either the emitter's own logger or it's logger
|
//! The returned logger is either the emitter's own logger or it's logger used by \ref CodeHolder this emitter
|
||||||
//! used by \ref CodeHolder this emitter is attached to.
|
//! is attached to.
|
||||||
inline Logger* logger() const noexcept { return _logger; }
|
inline Logger* logger() const noexcept { return _logger; }
|
||||||
|
|
||||||
//! Sets or resets the logger of the emitter.
|
//! Sets or resets the logger of the emitter.
|
||||||
//!
|
//!
|
||||||
//! If the `logger` argument is non-null then the logger will be considered
|
//! If the `logger` argument is non-null then the logger will be considered emitter's own logger, see \ref
|
||||||
//! emitter's own logger, see \ref hasOwnLogger() for more details. If the
|
//! hasOwnLogger() for more details. If the given `logger` is null then the emitter will automatically use logger
|
||||||
//! given `logger` is null then the emitter will automatically use logger
|
|
||||||
//! that is attached to the \ref CodeHolder this emitter is attached to.
|
//! that is attached to the \ref CodeHolder this emitter is attached to.
|
||||||
ASMJIT_API void setLogger(Logger* logger) noexcept;
|
ASMJIT_API void setLogger(Logger* logger) noexcept;
|
||||||
|
|
||||||
//! Resets the logger of this emitter.
|
//! Resets the logger of this emitter.
|
||||||
//!
|
//!
|
||||||
//! The emitter will bail to using a logger attached to \ref CodeHolder this
|
//! The emitter will bail to using a logger attached to \ref CodeHolder this emitter is attached to, or no logger
|
||||||
//! emitter is attached to, or no logger at all if \ref CodeHolder doesn't
|
//! at all if \ref CodeHolder doesn't have one.
|
||||||
//! have one.
|
|
||||||
inline void resetLogger() noexcept { return setLogger(nullptr); }
|
inline void resetLogger() noexcept { return setLogger(nullptr); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -352,14 +370,14 @@ public:
|
|||||||
|
|
||||||
//! Tests whether the emitter has its own error handler.
|
//! Tests whether the emitter has its own error handler.
|
||||||
//!
|
//!
|
||||||
//! Own error handler means that it overrides the possible error handler that
|
//! Own error handler means that it overrides the possible error handler that may be used by \ref CodeHolder this
|
||||||
//! may be used by \ref CodeHolder this emitter is attached to.
|
//! emitter is attached to.
|
||||||
inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(kFlagOwnErrorHandler); }
|
inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnErrorHandler); }
|
||||||
|
|
||||||
//! Returns the error handler this emitter uses.
|
//! Returns the error handler this emitter uses.
|
||||||
//!
|
//!
|
||||||
//! The returned error handler is either the emitter's own error handler or
|
//! The returned error handler is either the emitter's own error handler or it's error handler used by
|
||||||
//! it's error handler used by \ref CodeHolder this emitter is attached to.
|
//! \ref CodeHolder this emitter is attached to.
|
||||||
inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
|
inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
|
||||||
|
|
||||||
//! Sets or resets the error handler of the emitter.
|
//! Sets or resets the error handler of the emitter.
|
||||||
@@ -369,11 +387,9 @@ public:
|
|||||||
inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
|
||||||
|
|
||||||
//! 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
|
//! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
|
||||||
//! \ref ErrorHandler::handleError() member function first, and
|
//! first, and then returns the error. The `handleError()` function may throw.
|
||||||
//! 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_API Error reportError(Error err, const char* message = nullptr);
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -381,61 +397,51 @@ public:
|
|||||||
//! \name Encoding Options
|
//! \name Encoding Options
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns encoding options, see \ref EncodingOptions.
|
//! Returns encoding options.
|
||||||
inline uint32_t encodingOptions() const noexcept { return _encodingOptions; }
|
inline EncodingOptions encodingOptions() const noexcept { return _encodingOptions; }
|
||||||
//! Tests whether the encoding `option` is set.
|
//! Tests whether the encoding `option` is set.
|
||||||
inline bool hasEncodingOption(uint32_t option) const noexcept { return (_encodingOptions & option) != 0; }
|
inline bool hasEncodingOption(EncodingOptions option) const noexcept { return Support::test(_encodingOptions, option); }
|
||||||
|
|
||||||
//! Enables the given encoding `options`, see \ref EncodingOptions.
|
//! Enables the given encoding `options`.
|
||||||
inline void addEncodingOptions(uint32_t options) noexcept { _encodingOptions |= options; }
|
inline void addEncodingOptions(EncodingOptions options) noexcept { _encodingOptions |= options; }
|
||||||
//! Disables the given encoding `options`, see \ref EncodingOptions.
|
//! Disables the given encoding `options`.
|
||||||
inline void clearEncodingOptions(uint32_t options) noexcept { _encodingOptions &= ~options; }
|
inline void clearEncodingOptions(EncodingOptions options) noexcept { _encodingOptions &= ~options; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Validation Options
|
//! \name Diagnostic Options
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the emitter's validation options, see \ref ValidationOptions.
|
//! Returns the emitter's diagnostic options.
|
||||||
inline uint32_t validationOptions() const noexcept {
|
inline DiagnosticOptions diagnosticOptions() const noexcept { return _diagnosticOptions; }
|
||||||
return _validationOptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Tests whether the given `option` is present in validation options.
|
//! Tests whether the given `option` is present in the emitter's diagnostic options.
|
||||||
inline bool hasValidationOption(uint32_t option) const noexcept {
|
inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
|
||||||
return (_validationOptions & option) != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Activates the given validation `options`, see \ref ValidationOptions.
|
//! Activates the given diagnostic `options`.
|
||||||
//!
|
//!
|
||||||
//! This function is used to activate explicit validation options that will
|
//! This function is used to activate explicit validation options that will be then used by all emitter
|
||||||
//! be then used by all emitter implementations. There are in general two
|
//! implementations. There are in general two possibilities:
|
||||||
//! possibilities:
|
|
||||||
//!
|
//!
|
||||||
//! - Architecture specific assembler is used. In this case a
|
//! - Architecture specific assembler is used. In this case a \ref DiagnosticOptions::kValidateAssembler can be
|
||||||
//! \ref kValidationOptionAssembler can be used to turn on explicit
|
//! used to turn on explicit validation that will be used before an instruction is emitted. This means that
|
||||||
//! validation that will be used before an instruction is emitted.
|
//! internally an extra step will be performed to make sure that the instruction is correct. This is needed,
|
||||||
//! This means that internally an extra step will be performed to
|
//! because by default assemblers prefer speed over strictness.
|
||||||
//! make sure that the instruction is correct. This is needed, because
|
|
||||||
//! by default assemblers prefer speed over strictness.
|
|
||||||
//!
|
//!
|
||||||
//! This option should be used in debug builds as it's pretty expensive.
|
//! This option should be used in debug builds as it's pretty expensive.
|
||||||
//!
|
//!
|
||||||
//! - Architecture specific builder or compiler is used. In this case
|
//! - Architecture specific builder or compiler is used. In this case the user can turn on
|
||||||
//! the user can turn on \ref kValidationOptionIntermediate option
|
//! \ref DiagnosticOptions::kValidateIntermediate option that adds explicit validation step before the Builder
|
||||||
//! that adds explicit validation step before the Builder or Compiler
|
//! or Compiler creates an \ref InstNode to represent an emitted instruction. Error will be returned if the
|
||||||
//! creates an \ref InstNode to represent an emitted instruction. Error
|
//! instruction is ill-formed. In addition, also \ref DiagnosticOptions::kValidateAssembler can be used, which
|
||||||
//! will be returned if the instruction is ill-formed. In addition,
|
//! would not be consumed by Builder / Compiler directly, but it would be propagated to an architecture specific
|
||||||
//! also \ref kValidationOptionAssembler can be used, which would not be
|
//! \ref BaseAssembler implementation it creates during \ref BaseEmitter::finalize().
|
||||||
//! consumed by Builder / Compiler directly, but it would be propagated
|
ASMJIT_API void addDiagnosticOptions(DiagnosticOptions options) noexcept;
|
||||||
//! to an architecture specific \ref BaseAssembler implementation it
|
|
||||||
//! creates during \ref BaseEmitter::finalize().
|
|
||||||
ASMJIT_API void addValidationOptions(uint32_t options) noexcept;
|
|
||||||
|
|
||||||
//! Deactivates the given validation `options`.
|
//! Deactivates the given validation `options`.
|
||||||
//!
|
//!
|
||||||
//! See \ref addValidationOptions() and \ref ValidationOptions for more details.
|
//! See \ref addDiagnosticOptions() and \ref DiagnosticOptions for more details.
|
||||||
ASMJIT_API void clearValidationOptions(uint32_t options) noexcept;
|
ASMJIT_API void clearDiagnosticOptions(DiagnosticOptions options) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -444,20 +450,19 @@ public:
|
|||||||
|
|
||||||
//! Returns forced instruction options.
|
//! Returns forced instruction options.
|
||||||
//!
|
//!
|
||||||
//! Forced instruction options are merged with next instruction options before
|
//! Forced instruction options are merged with next instruction options before the instruction is encoded. These
|
||||||
//! the instruction is encoded. These options have some bits reserved that are
|
//! options have some bits reserved that are used by error handling, logging, and instruction validation purposes.
|
||||||
//! used by error handling, logging, and instruction validation purposes. Other
|
//! Other options are globals that affect each instruction.
|
||||||
//! options are globals that affect each instruction.
|
inline InstOptions forcedInstOptions() const noexcept { return _forcedInstOptions; }
|
||||||
inline uint32_t forcedInstOptions() const noexcept { return _forcedInstOptions; }
|
|
||||||
|
|
||||||
//! Returns options of the next instruction.
|
//! Returns options of the next instruction.
|
||||||
inline uint32_t instOptions() const noexcept { return _instOptions; }
|
inline InstOptions instOptions() const noexcept { return _instOptions; }
|
||||||
//! Returns options of the next instruction.
|
//! Returns options of the next instruction.
|
||||||
inline void setInstOptions(uint32_t options) noexcept { _instOptions = options; }
|
inline void setInstOptions(InstOptions options) noexcept { _instOptions = options; }
|
||||||
//! Adds options of the next instruction.
|
//! Adds options of the next instruction.
|
||||||
inline void addInstOptions(uint32_t options) noexcept { _instOptions |= options; }
|
inline void addInstOptions(InstOptions options) noexcept { _instOptions |= options; }
|
||||||
//! Resets options of the next instruction.
|
//! Resets options of the next instruction.
|
||||||
inline void resetInstOptions() noexcept { _instOptions = 0; }
|
inline void resetInstOptions() noexcept { _instOptions = InstOptions::kNone; }
|
||||||
|
|
||||||
//! Tests whether the extra register operand is valid.
|
//! Tests whether the extra register operand is valid.
|
||||||
inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
|
inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
|
||||||
@@ -474,9 +479,8 @@ public:
|
|||||||
inline const char* inlineComment() const noexcept { return _inlineComment; }
|
inline const char* inlineComment() const noexcept { return _inlineComment; }
|
||||||
//! Sets comment/annotation of the next instruction.
|
//! Sets comment/annotation of the next instruction.
|
||||||
//!
|
//!
|
||||||
//! \note This string is set back to null by `_emit()`, but until that it has
|
//! \note This string is set back to null by `_emit()`, but until that it has to remain valid as the Emitter is not
|
||||||
//! to remain valid as the Emitter is not required to make a copy of it (and
|
//! required to make a copy of it (and it would be slow to do that for each instruction).
|
||||||
//! it would be slow to do that for each instruction).
|
|
||||||
inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
|
||||||
//! Resets the comment/annotation to nullptr.
|
//! Resets the comment/annotation to nullptr.
|
||||||
inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
|
||||||
@@ -496,19 +500,19 @@ public:
|
|||||||
//! Creates a new label.
|
//! Creates a new label.
|
||||||
virtual Label newLabel() = 0;
|
virtual Label newLabel() = 0;
|
||||||
//! Creates a new named label.
|
//! Creates a new named label.
|
||||||
virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) = 0;
|
virtual Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, LabelType type = LabelType::kGlobal, uint32_t parentId = Globals::kInvalidId) = 0;
|
||||||
|
|
||||||
|
//! Creates a new anonymous label with a name, which can only be used for debugging purposes.
|
||||||
|
inline Label newAnonymousLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kAnonymous); }
|
||||||
//! Creates a new external label.
|
//! Creates a new external label.
|
||||||
inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) {
|
inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kExternal); }
|
||||||
return newNamedLabel(name, nameSize, Label::kTypeExternal);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns `Label` by `name`.
|
//! Returns `Label` by `name`.
|
||||||
//!
|
//!
|
||||||
//! Returns invalid Label in case that the name is invalid or label was not found.
|
//! Returns invalid Label in case that the name is invalid or label was not found.
|
||||||
//!
|
//!
|
||||||
//! \note This function doesn't trigger ErrorHandler in case the name is invalid
|
//! \note This function doesn't trigger ErrorHandler in case the name is invalid or no such label exist. You must
|
||||||
//! or no such label exist. You must always check the validity of the `Label` returned.
|
//! always check the validity of the `Label` returned.
|
||||||
ASMJIT_API Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
|
ASMJIT_API Label labelByName(const char* name, size_t nameSize = SIZE_MAX, uint32_t parentId = Globals::kInvalidId) noexcept;
|
||||||
|
|
||||||
//! Binds the `label` to the current position of the current section.
|
//! Binds the `label` to the current position of the current section.
|
||||||
@@ -526,41 +530,39 @@ public:
|
|||||||
//! \name Emit
|
//! \name Emit
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// NOTE: These `emit()` helpers are designed to address a code-bloat generated
|
// NOTE: These `emit()` helpers are designed to address a code-bloat generated by C++ compilers to call a function
|
||||||
// by C++ compilers to call a function having many arguments. Each parameter to
|
// having many arguments. Each parameter to `_emit()` requires some code to pass it, which means that if we default
|
||||||
// `_emit()` requires some code to pass it, which means that if we default to
|
// to 5 arguments in `_emit()` and instId the C++ compiler would have to generate a virtual function call having 5
|
||||||
// 5 arguments in `_emit()` and instId the C++ compiler would have to generate
|
// parameters and additional `this` argument, which is quite a lot. Since by default most instructions have 2 to 3
|
||||||
// a virtual function call having 5 parameters and additional `this` argument,
|
// operands it's better to introduce helpers that pass from 0 to 6 operands that help to reduce the size of emit(...)
|
||||||
// which is quite a lot. Since by default most instructions have 2 to 3 operands
|
// function call.
|
||||||
// it's better to introduce helpers that pass from 0 to 6 operands that help to
|
|
||||||
// reduce the size of emit(...) function call.
|
|
||||||
|
|
||||||
//! Emits an instruction (internal).
|
//! Emits an instruction (internal).
|
||||||
ASMJIT_API Error _emitI(uint32_t instId);
|
ASMJIT_API Error _emitI(InstId instId);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
|
||||||
//! \overload
|
//! \overload
|
||||||
ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
||||||
|
|
||||||
//! Emits an instruction `instId` with the given `operands`.
|
//! Emits an instruction `instId` with the given `operands`.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ASMJIT_INLINE Error emit(uint32_t instId, Args&&... operands) {
|
ASMJIT_FORCE_INLINE Error emit(InstId instId, Args&&... operands) {
|
||||||
return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
|
return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount) {
|
ASMJIT_FORCE_INLINE Error emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
|
||||||
return _emitOpArray(instId, operands, opCount);
|
return _emitOpArray(instId, operands, opCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
|
ASMJIT_FORCE_INLINE Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
|
||||||
setInstOptions(inst.options());
|
setInstOptions(inst.options());
|
||||||
setExtraReg(inst.extraReg());
|
setExtraReg(inst.extraReg());
|
||||||
return _emitOpArray(inst.id(), operands, opCount);
|
return _emitOpArray(inst.id(), operands, opCount);
|
||||||
@@ -568,9 +570,9 @@ public:
|
|||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! Emits an instruction - all 6 operands must be defined.
|
//! Emits an instruction - all 6 operands must be defined.
|
||||||
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0;
|
virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt) = 0;
|
||||||
//! Emits instruction having operands stored in array.
|
//! Emits instruction having operands stored in array.
|
||||||
ASMJIT_API virtual Error _emitOpArray(uint32_t instId, const Operand_* operands, size_t opCount);
|
ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount);
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -589,9 +591,10 @@ public:
|
|||||||
|
|
||||||
//! Aligns the current CodeBuffer position to the `alignment` specified.
|
//! Aligns the current CodeBuffer position to the `alignment` specified.
|
||||||
//!
|
//!
|
||||||
//! The sequence that is used to fill the gap between the aligned location
|
//! The sequence that is used to fill the gap between the aligned location and the current location depends on the
|
||||||
//! and the current location depends on the align `mode`, see \ref AlignMode.
|
//! align `mode`, see \ref AlignMode. The `alignment` argument specifies alignment in bytes, so for example when
|
||||||
virtual Error align(uint32_t alignMode, uint32_t alignment) = 0;
|
//! it's `32` it means that the code buffer will be aligned to `32` bytes.
|
||||||
|
virtual Error align(AlignMode alignMode, uint32_t alignment) = 0;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -604,49 +607,49 @@ public:
|
|||||||
//! Embeds a typed data array.
|
//! Embeds a typed data array.
|
||||||
//!
|
//!
|
||||||
//! This is the most flexible function for embedding data as it allows to:
|
//! This is the most flexible function for embedding data as it allows to:
|
||||||
//! - Assign a `typeId` to the data, so the emitter knows the type of
|
//!
|
||||||
//! items stored in `data`. Binary data should use \ref Type::kIdU8.
|
//! - Assign a `typeId` to the data, so the emitter knows the type of items stored in `data`. Binary data should
|
||||||
//! - Repeat the given data `repeatCount` times, so the data can be used
|
//! use \ref TypeId::kUInt8.
|
||||||
//! as a fill pattern for example, or as a pattern used by SIMD instructions.
|
//!
|
||||||
virtual Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0;
|
//! - Repeat the given data `repeatCount` times, so the data can be used as a fill pattern for example, or as a
|
||||||
|
//! pattern used by SIMD instructions.
|
||||||
|
virtual Error embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0;
|
||||||
|
|
||||||
//! Embeds int8_t `value` repeated by `repeatCount`.
|
//! Embeds int8_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI8, &value, 1, repeatCount); }
|
inline Error embedInt8(int8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt8, &value, 1, repeatCount); }
|
||||||
//! Embeds uint8_t `value` repeated by `repeatCount`.
|
//! Embeds uint8_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU8, &value, 1, repeatCount); }
|
inline Error embedUInt8(uint8_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt8, &value, 1, repeatCount); }
|
||||||
//! Embeds int16_t `value` repeated by `repeatCount`.
|
//! Embeds int16_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI16, &value, 1, repeatCount); }
|
inline Error embedInt16(int16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt16, &value, 1, repeatCount); }
|
||||||
//! Embeds uint16_t `value` repeated by `repeatCount`.
|
//! Embeds uint16_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU16, &value, 1, repeatCount); }
|
inline Error embedUInt16(uint16_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt16, &value, 1, repeatCount); }
|
||||||
//! Embeds int32_t `value` repeated by `repeatCount`.
|
//! Embeds int32_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI32, &value, 1, repeatCount); }
|
inline Error embedInt32(int32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt32, &value, 1, repeatCount); }
|
||||||
//! Embeds uint32_t `value` repeated by `repeatCount`.
|
//! Embeds uint32_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU32, &value, 1, repeatCount); }
|
inline Error embedUInt32(uint32_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt32, &value, 1, repeatCount); }
|
||||||
//! Embeds int64_t `value` repeated by `repeatCount`.
|
//! Embeds int64_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdI64, &value, 1, repeatCount); }
|
inline Error embedInt64(int64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kInt64, &value, 1, repeatCount); }
|
||||||
//! Embeds uint64_t `value` repeated by `repeatCount`.
|
//! Embeds uint64_t `value` repeated by `repeatCount`.
|
||||||
inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(Type::kIdU64, &value, 1, repeatCount); }
|
inline Error embedUInt64(uint64_t value, size_t repeatCount = 1) { return embedDataArray(TypeId::kUInt64, &value, 1, repeatCount); }
|
||||||
//! Embeds a floating point `value` repeated by `repeatCount`.
|
//! Embeds a floating point `value` repeated by `repeatCount`.
|
||||||
inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(Type::kIdF32, &value, 1, repeatCount); }
|
inline Error embedFloat(float value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<float>::kTypeId), &value, 1, repeatCount); }
|
||||||
//! Embeds a floating point `value` repeated by `repeatCount`.
|
//! Embeds a floating point `value` repeated by `repeatCount`.
|
||||||
inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(Type::IdOfT<double>::kTypeId, &value, 1, repeatCount); }
|
inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT<double>::kTypeId), &value, 1, repeatCount); }
|
||||||
|
|
||||||
//! Embeds a constant pool at the current offset by performing the following:
|
//! Embeds a constant pool at the current offset by performing the following:
|
||||||
//! 1. Aligns by using kAlignData to the minimum `pool` alignment.
|
//! 1. Aligns by using AlignMode::kData to the minimum `pool` alignment.
|
||||||
//! 2. Binds the ConstPool label so it's bound to an aligned location.
|
//! 2. Binds the ConstPool label so it's bound to an aligned location.
|
||||||
//! 3. Emits ConstPool content.
|
//! 3. Emits ConstPool content.
|
||||||
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
|
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
|
||||||
|
|
||||||
//! Embeds an absolute `label` address as data.
|
//! Embeds an absolute `label` address as data.
|
||||||
//!
|
//!
|
||||||
//! The `dataSize` is an optional argument that can be used to specify the
|
//! The `dataSize` is an optional argument that can be used to specify the size of the address data. If it's zero
|
||||||
//! size of the address data. If it's zero (default) the address size is
|
//! (default) the address size is deduced from the target architecture (either 4 or 8 bytes).
|
||||||
//! deduced from the target architecture (either 4 or 8 bytes).
|
|
||||||
virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0;
|
virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0;
|
||||||
|
|
||||||
//! Embeds a delta (distance) between the `label` and `base` calculating it
|
//! Embeds a delta (distance) between the `label` and `base` calculating it as `label - base`. This function was
|
||||||
//! as `label - base`. This function was designed to make it easier to embed
|
//! designed to make it easier to embed lookup tables where each index is a relative distance of two labels.
|
||||||
//! lookup tables where each index is a relative distance of two labels.
|
|
||||||
virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0;
|
virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -672,48 +675,20 @@ public:
|
|||||||
//! Called after the emitter was detached from `CodeHolder`.
|
//! Called after the emitter was detached from `CodeHolder`.
|
||||||
virtual Error onDetach(CodeHolder* code) noexcept = 0;
|
virtual Error onDetach(CodeHolder* code) noexcept = 0;
|
||||||
|
|
||||||
//! Called when \ref CodeHolder has updated an important setting, which
|
//! Called when \ref CodeHolder has updated an important setting, which involves the following:
|
||||||
//! involves the following:
|
|
||||||
//!
|
//!
|
||||||
//! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been
|
//! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been called).
|
||||||
//! called).
|
|
||||||
//! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler()
|
|
||||||
//! has been called).
|
|
||||||
//!
|
//!
|
||||||
//! This function ensures that the settings are properly propagated from
|
//! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() has been called).
|
||||||
//! \ref CodeHolder to the emitter.
|
|
||||||
//!
|
//!
|
||||||
//! \note This function is virtual and can be overridden, however, if you
|
//! This function ensures that the settings are properly propagated from \ref CodeHolder to the emitter.
|
||||||
//! do so, always call \ref BaseEmitter::onSettingsUpdated() within your
|
//!
|
||||||
//! own implementation to ensure that the emitter is in a consistent state.
|
//! \note This function is virtual and can be overridden, however, if you do so, always call \ref
|
||||||
|
//! BaseEmitter::onSettingsUpdated() within your own implementation to ensure that the emitter is
|
||||||
|
//! in a consistent state.
|
||||||
ASMJIT_API virtual void onSettingsUpdated() noexcept;
|
ASMJIT_API virtual void onSettingsUpdated() noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
ASMJIT_DEPRECATED("Use environment() instead")
|
|
||||||
inline CodeInfo codeInfo() const noexcept {
|
|
||||||
return CodeInfo(_environment, _code ? _code->baseAddress() : Globals::kNoBaseAddress);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use arch() instead")
|
|
||||||
inline uint32_t archId() const noexcept { return arch(); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use registerSize() instead")
|
|
||||||
inline uint32_t gpSize() const noexcept { return registerSize(); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use encodingOptions() instead")
|
|
||||||
inline uint32_t emitterOptions() const noexcept { return encodingOptions(); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use addEncodingOptions() instead")
|
|
||||||
inline void addEmitterOptions(uint32_t options) noexcept { addEncodingOptions(options); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use clearEncodingOptions() instead")
|
|
||||||
inline void clearEmitterOptions(uint32_t options) noexcept { clearEncodingOptions(options); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use forcedInstOptions() instead")
|
|
||||||
inline uint32_t globalInstOptions() const noexcept { return forcedInstOptions(); }
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -1,57 +1,33 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/assembler.h"
|
#include "../core/assembler.h"
|
||||||
#include "../core/emitterutils_p.h"
|
#include "../core/emitterutils_p.h"
|
||||||
#include "../core/formatter.h"
|
#include "../core/formatter_p.h"
|
||||||
#include "../core/logger.h"
|
#include "../core/logger.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::EmitterUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
namespace EmitterUtils {
|
namespace EmitterUtils {
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
|
||||||
Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept {
|
Error finishFormattedLine(String& sb, const FormatOptions& formatOptions, const uint8_t* binData, size_t binSize, size_t offsetSize, size_t immSize, const char* comment) noexcept {
|
||||||
size_t currentSize = sb.size();
|
ASMJIT_ASSERT(binSize >= offsetSize);
|
||||||
size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0;
|
|
||||||
|
|
||||||
ASMJIT_ASSERT(binSize >= dispSize);
|
|
||||||
const size_t kNoBinSize = SIZE_MAX;
|
const size_t kNoBinSize = SIZE_MAX;
|
||||||
|
|
||||||
|
size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0;
|
||||||
|
|
||||||
if ((binSize != 0 && binSize != kNoBinSize) || commentSize) {
|
if ((binSize != 0 && binSize != kNoBinSize) || commentSize) {
|
||||||
size_t align = kMaxInstLineSize;
|
|
||||||
char sep = ';';
|
char sep = ';';
|
||||||
|
size_t padding = Formatter::paddingFromOptions(formatOptions, FormatPaddingGroup::kRegularLine);
|
||||||
|
|
||||||
for (size_t i = (binSize == kNoBinSize); i < 2; i++) {
|
for (size_t i = (binSize == kNoBinSize); i < 2; i++) {
|
||||||
size_t begin = sb.size();
|
ASMJIT_PROPAGATE(sb.padEnd(padding));
|
||||||
ASMJIT_PROPAGATE(sb.padEnd(align));
|
|
||||||
|
|
||||||
if (sep) {
|
if (sep) {
|
||||||
ASMJIT_PROPAGATE(sb.append(sep));
|
ASMJIT_PROPAGATE(sb.append(sep));
|
||||||
@@ -60,8 +36,8 @@ Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t disp
|
|||||||
|
|
||||||
// Append binary data or comment.
|
// Append binary data or comment.
|
||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize));
|
ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - offsetSize - immSize));
|
||||||
ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2));
|
ASMJIT_PROPAGATE(sb.appendChars('.', offsetSize * 2));
|
||||||
ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize));
|
ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize));
|
||||||
if (commentSize == 0) break;
|
if (commentSize == 0) break;
|
||||||
}
|
}
|
||||||
@@ -69,9 +45,8 @@ Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t disp
|
|||||||
ASMJIT_PROPAGATE(sb.append(comment, commentSize));
|
ASMJIT_PROPAGATE(sb.append(comment, commentSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
currentSize += sb.size() - begin;
|
|
||||||
align += kMaxBinarySize;
|
|
||||||
sep = '|';
|
sep = '|';
|
||||||
|
padding += Formatter::paddingFromOptions(formatOptions, FormatPaddingGroup::kMachineCode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -82,55 +57,59 @@ void logLabelBound(BaseAssembler* self, const Label& label) noexcept {
|
|||||||
Logger* logger = self->logger();
|
Logger* logger = self->logger();
|
||||||
|
|
||||||
StringTmp<512> sb;
|
StringTmp<512> sb;
|
||||||
size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : SIZE_MAX;
|
size_t binSize = logger->hasFlag(FormatFlags::kMachineCode) ? size_t(0) : SIZE_MAX;
|
||||||
|
|
||||||
sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationLabel));
|
sb.appendChars(' ', logger->indentation(FormatIndentationGroup::kLabel));
|
||||||
Formatter::formatLabel(sb, logger->flags(), self, label.id());
|
Formatter::formatLabel(sb, logger->flags(), self, label.id());
|
||||||
sb.append(':');
|
sb.append(':');
|
||||||
EmitterUtils::formatLine(sb, nullptr, binSize, 0, 0, self->_inlineComment);
|
finishFormattedLine(sb, logger->options(), nullptr, binSize, 0, 0, self->_inlineComment);
|
||||||
logger->log(sb.data(), sb.size());
|
logger->log(sb.data(), sb.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void logInstructionEmitted(
|
void logInstructionEmitted(
|
||||||
BaseAssembler* self,
|
BaseAssembler* self,
|
||||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt,
|
InstId instId,
|
||||||
|
InstOptions options,
|
||||||
|
const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt,
|
||||||
uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) {
|
uint32_t relSize, uint32_t immSize, uint8_t* afterCursor) {
|
||||||
|
|
||||||
Logger* logger = self->logger();
|
Logger* logger = self->logger();
|
||||||
ASMJIT_ASSERT(logger != nullptr);
|
ASMJIT_ASSERT(logger != nullptr);
|
||||||
|
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
uint32_t flags = logger->flags();
|
FormatFlags formatFlags = logger->flags();
|
||||||
|
|
||||||
uint8_t* beforeCursor = self->bufferPtr();
|
uint8_t* beforeCursor = self->bufferPtr();
|
||||||
intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
|
intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
|
||||||
|
|
||||||
Operand_ opArray[Globals::kMaxOpCount];
|
Operand_ opArray[Globals::kMaxOpCount];
|
||||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||||
|
|
||||||
sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode));
|
sb.appendChars(' ', logger->indentation(FormatIndentationGroup::kCode));
|
||||||
Formatter::formatInstruction(sb, flags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
|
Formatter::formatInstruction(sb, formatFlags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
|
||||||
|
|
||||||
if ((flags & FormatOptions::kFlagMachineCode) != 0)
|
if (Support::test(formatFlags, FormatFlags::kMachineCode))
|
||||||
EmitterUtils::formatLine(sb, self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment());
|
finishFormattedLine(sb, logger->options(), self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment());
|
||||||
else
|
else
|
||||||
EmitterUtils::formatLine(sb, nullptr, SIZE_MAX, 0, 0, self->inlineComment());
|
finishFormattedLine(sb, logger->options(), nullptr, SIZE_MAX, 0, 0, self->inlineComment());
|
||||||
logger->log(sb);
|
logger->log(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error logInstructionFailed(
|
Error logInstructionFailed(
|
||||||
BaseAssembler* self,
|
BaseAssembler* self,
|
||||||
Error err,
|
Error err,
|
||||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
|
InstId instId,
|
||||||
|
InstOptions options,
|
||||||
|
const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
|
||||||
|
|
||||||
StringTmp<256> sb;
|
StringTmp<256> sb;
|
||||||
sb.append(DebugUtils::errorAsString(err));
|
sb.append(DebugUtils::errorAsString(err));
|
||||||
sb.append(": ");
|
sb.append(": ");
|
||||||
|
|
||||||
Operand_ opArray[Globals::kMaxOpCount];
|
Operand_ opArray[Globals::kMaxOpCount];
|
||||||
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
|
||||||
|
|
||||||
Formatter::formatInstruction(sb, 0, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
|
Formatter::formatInstruction(sb, FormatFlags::kNone, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
|
||||||
|
|
||||||
if (self->inlineComment()) {
|
if (self->inlineComment()) {
|
||||||
sb.append(" ; ");
|
sb.append(" ; ");
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
|
||||||
@@ -30,26 +12,26 @@
|
|||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
class BaseAssembler;
|
class BaseAssembler;
|
||||||
|
class FormatOptions;
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Utilities used by various emitters, mostly Assembler implementations.
|
||||||
// [asmjit::EmitterUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
namespace EmitterUtils {
|
namespace EmitterUtils {
|
||||||
|
|
||||||
static const Operand_ noExt[3] {};
|
//! Default paddings used by Emitter utils and Formatter.
|
||||||
|
|
||||||
enum kOpIndex {
|
static constexpr Operand noExt[3];
|
||||||
|
|
||||||
|
enum kOpIndex : uint32_t {
|
||||||
kOp3 = 0,
|
kOp3 = 0,
|
||||||
kOp4 = 1,
|
kOp4 = 1,
|
||||||
kOp5 = 2
|
kOp5 = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept {
|
static ASMJIT_FORCE_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept {
|
||||||
uint32_t opCount = 0;
|
uint32_t opCount = 0;
|
||||||
|
|
||||||
if (opExt[kOp3].isNone()) {
|
if (opExt[kOp3].isNone()) {
|
||||||
@@ -67,7 +49,7 @@ static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Oper
|
|||||||
return opCount;
|
return opCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount], const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept {
|
static ASMJIT_FORCE_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount], const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) noexcept {
|
||||||
dst[0].copyFrom(o0);
|
dst[0].copyFrom(o0);
|
||||||
dst[1].copyFrom(o1);
|
dst[1].copyFrom(o1);
|
||||||
dst[2].copyFrom(o2);
|
dst[2].copyFrom(o2);
|
||||||
@@ -77,25 +59,23 @@ static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount]
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
enum : uint32_t {
|
Error finishFormattedLine(String& sb, const FormatOptions& formatOptions, const uint8_t* binData, size_t binSize, size_t offsetSize, size_t immSize, const char* comment) noexcept;
|
||||||
// Has to be big to be able to hold all metadata compiler can assign to a
|
|
||||||
// single instruction.
|
|
||||||
kMaxInstLineSize = 44,
|
|
||||||
kMaxBinarySize = 26
|
|
||||||
};
|
|
||||||
|
|
||||||
Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept;
|
|
||||||
|
|
||||||
void logLabelBound(BaseAssembler* self, const Label& label) noexcept;
|
void logLabelBound(BaseAssembler* self, const Label& label) noexcept;
|
||||||
|
|
||||||
void logInstructionEmitted(
|
void logInstructionEmitted(
|
||||||
BaseAssembler* self,
|
BaseAssembler* self,
|
||||||
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt,
|
InstId instId,
|
||||||
|
InstOptions options,
|
||||||
|
const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt,
|
||||||
uint32_t relSize, uint32_t immSize, uint8_t* afterCursor);
|
uint32_t relSize, uint32_t immSize, uint8_t* afterCursor);
|
||||||
|
|
||||||
Error logInstructionFailed(
|
Error logInstructionFailed(
|
||||||
BaseAssembler* self,
|
BaseAssembler* self,
|
||||||
Error err, uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt);
|
Error err,
|
||||||
|
InstId instId,
|
||||||
|
InstOptions options,
|
||||||
|
const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/environment.h"
|
#include "../core/environment.h"
|
||||||
|
|||||||
@@ -1,30 +1,12 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/globals.h"
|
#include "../core/archtraits.h"
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
@@ -35,301 +17,222 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Vendor.
|
||||||
// [asmjit::Environment]
|
//!
|
||||||
// ============================================================================
|
//! \note AsmJit doesn't use vendor information at the moment. It's provided for future use, if required.
|
||||||
|
enum class Vendor : uint8_t {
|
||||||
|
//! Unknown or uninitialized platform vendor.
|
||||||
|
kUnknown = 0,
|
||||||
|
|
||||||
|
//! Maximum value of `PlatformVendor`.
|
||||||
|
kMaxValue = kUnknown,
|
||||||
|
|
||||||
|
//! Platform vendor detected at compile-time.
|
||||||
|
kHost =
|
||||||
|
#if defined(_DOXYGEN)
|
||||||
|
DETECTED_AT_COMPILE_TIME
|
||||||
|
#else
|
||||||
|
kUnknown
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Platform - runtime environment or operating system.
|
||||||
|
enum class Platform : uint8_t {
|
||||||
|
//! Unknown or uninitialized platform.
|
||||||
|
kUnknown = 0,
|
||||||
|
|
||||||
|
//! Windows OS.
|
||||||
|
kWindows,
|
||||||
|
|
||||||
|
//! Other platform that is not Windows, most likely POSIX based.
|
||||||
|
kOther,
|
||||||
|
|
||||||
|
//! Linux OS.
|
||||||
|
kLinux,
|
||||||
|
//! GNU/Hurd OS.
|
||||||
|
kHurd,
|
||||||
|
|
||||||
|
//! FreeBSD OS.
|
||||||
|
kFreeBSD,
|
||||||
|
//! OpenBSD OS.
|
||||||
|
kOpenBSD,
|
||||||
|
//! NetBSD OS.
|
||||||
|
kNetBSD,
|
||||||
|
//! DragonFly BSD OS.
|
||||||
|
kDragonFlyBSD,
|
||||||
|
|
||||||
|
//! Haiku OS.
|
||||||
|
kHaiku,
|
||||||
|
|
||||||
|
//! Apple OSX.
|
||||||
|
kOSX,
|
||||||
|
//! Apple iOS.
|
||||||
|
kIOS,
|
||||||
|
//! Apple TVOS.
|
||||||
|
kTVOS,
|
||||||
|
//! Apple WatchOS.
|
||||||
|
kWatchOS,
|
||||||
|
|
||||||
|
//! Emscripten platform.
|
||||||
|
kEmscripten,
|
||||||
|
|
||||||
|
//! Maximum value of `Platform`.
|
||||||
|
kMaxValue = kEmscripten,
|
||||||
|
|
||||||
|
//! Platform detected at compile-time (platform of the host).
|
||||||
|
kHost =
|
||||||
|
#if defined(_DOXYGEN)
|
||||||
|
DETECTED_AT_COMPILE_TIME
|
||||||
|
#elif defined(__EMSCRIPTEN__)
|
||||||
|
kEmscripten
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
kWindows
|
||||||
|
#elif defined(__linux__)
|
||||||
|
kLinux
|
||||||
|
#elif defined(__gnu_hurd__)
|
||||||
|
kHurd
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
kFreeBSD
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
kOpenBSD
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
kNetBSD
|
||||||
|
#elif defined(__DragonFly__)
|
||||||
|
kDragonFlyBSD
|
||||||
|
#elif defined(__HAIKU__)
|
||||||
|
kHaiku
|
||||||
|
#elif defined(__APPLE__) && TARGET_OS_OSX
|
||||||
|
kOSX
|
||||||
|
#elif defined(__APPLE__) && TARGET_OS_TV
|
||||||
|
kTVOS
|
||||||
|
#elif defined(__APPLE__) && TARGET_OS_WATCH
|
||||||
|
kWatchOS
|
||||||
|
#elif defined(__APPLE__) && TARGET_OS_IPHONE
|
||||||
|
kIOS
|
||||||
|
#else
|
||||||
|
kOther
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Platform ABI (application binary interface).
|
||||||
|
enum class PlatformABI : uint8_t {
|
||||||
|
//! Unknown or uninitialied environment.
|
||||||
|
kUnknown = 0,
|
||||||
|
//! Microsoft ABI.
|
||||||
|
kMSVC,
|
||||||
|
//! GNU ABI.
|
||||||
|
kGNU,
|
||||||
|
//! Android Environment / ABI.
|
||||||
|
kAndroid,
|
||||||
|
//! Cygwin ABI.
|
||||||
|
kCygwin,
|
||||||
|
|
||||||
|
//! Maximum value of `PlatformABI`.
|
||||||
|
kMaxValue,
|
||||||
|
|
||||||
|
//! Host ABI detected at compile-time.
|
||||||
|
kHost =
|
||||||
|
#if defined(_DOXYGEN)
|
||||||
|
DETECTED_AT_COMPILE_TIME
|
||||||
|
#elif defined(_MSC_VER)
|
||||||
|
kMSVC
|
||||||
|
#elif defined(__CYGWIN__)
|
||||||
|
kCygwin
|
||||||
|
#elif defined(__MINGW32__) || defined(__GLIBC__)
|
||||||
|
kGNU
|
||||||
|
#elif defined(__ANDROID__)
|
||||||
|
kAndroid
|
||||||
|
#else
|
||||||
|
kUnknown
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Object format.
|
||||||
|
//!
|
||||||
|
//! \note AsmJit doesn't really use anything except \ref ObjectFormat::kUnknown and \ref ObjectFormat::kJIT at
|
||||||
|
//! the moment. Object file formats are provided for future extensibility and a possibility to generate object
|
||||||
|
//! files at some point.
|
||||||
|
enum class ObjectFormat : uint8_t {
|
||||||
|
//! Unknown or uninitialized object format.
|
||||||
|
kUnknown = 0,
|
||||||
|
|
||||||
|
//! JIT code generation object, most likely \ref JitRuntime or a custom
|
||||||
|
//! \ref Target implementation.
|
||||||
|
kJIT,
|
||||||
|
|
||||||
|
//! Executable and linkable format (ELF).
|
||||||
|
kELF,
|
||||||
|
//! Common object file format.
|
||||||
|
kCOFF,
|
||||||
|
//! Extended COFF object format.
|
||||||
|
kXCOFF,
|
||||||
|
//! Mach object file format.
|
||||||
|
kMachO,
|
||||||
|
|
||||||
|
//! Maximum value of `ObjectFormat`.
|
||||||
|
kMaxValue
|
||||||
|
};
|
||||||
|
|
||||||
//! Represents an environment, which is usually related to a \ref Target.
|
//! Represents an environment, which is usually related to a \ref Target.
|
||||||
//!
|
//!
|
||||||
//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is
|
//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is sometimes called "Triple" (historically
|
||||||
//! sometimes called "Triple" (historically it used to be 3 only parts) or
|
//! it used to be 3 only parts) or "Tuple", which is a convention used by Debian Linux.
|
||||||
//! "Tuple", which is a convention used by Debian Linux.
|
|
||||||
//!
|
//!
|
||||||
//! AsmJit doesn't support all possible combinations or architectures and ABIs,
|
//! AsmJit doesn't support all possible combinations or architectures and ABIs, however, it models the environment
|
||||||
//! however, it models the environment similarly to other compilers for future
|
//! similarly to other compilers for future extensibility.
|
||||||
//! extensibility.
|
|
||||||
class Environment {
|
class Environment {
|
||||||
public:
|
public:
|
||||||
//! Architecture type, see \ref Arch.
|
//! \name Members
|
||||||
uint8_t _arch;
|
|
||||||
//! Sub-architecture type, see \ref SubArch.
|
|
||||||
uint8_t _subArch;
|
|
||||||
//! Vendor type, see \ref Vendor.
|
|
||||||
uint8_t _vendor;
|
|
||||||
//! Platform type, see \ref Platform.
|
|
||||||
uint8_t _platform;
|
|
||||||
//! ABI type, see \ref Abi.
|
|
||||||
uint8_t _abi;
|
|
||||||
//! Object format, see \ref Format.
|
|
||||||
uint8_t _format;
|
|
||||||
//! Reserved for future use, must be zero.
|
|
||||||
uint16_t _reserved;
|
|
||||||
|
|
||||||
//! Architecture.
|
|
||||||
enum Arch : uint32_t {
|
|
||||||
//! Unknown or uninitialized architecture.
|
|
||||||
kArchUnknown = 0,
|
|
||||||
|
|
||||||
//! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit).
|
|
||||||
kArch32BitMask = 0x01,
|
|
||||||
//! Mask used by big-endian architectures.
|
|
||||||
kArchBigEndianMask = 0x80u,
|
|
||||||
|
|
||||||
//! 32-bit X86 architecture.
|
|
||||||
kArchX86 = 1,
|
|
||||||
//! 64-bit X86 architecture also known as X86_64 and AMD64.
|
|
||||||
kArchX64 = 2,
|
|
||||||
|
|
||||||
//! 32-bit RISC-V architecture.
|
|
||||||
kArchRISCV32 = 3,
|
|
||||||
//! 64-bit RISC-V architecture.
|
|
||||||
kArchRISCV64 = 4,
|
|
||||||
|
|
||||||
//! 32-bit ARM architecture (little endian).
|
|
||||||
kArchARM = 5,
|
|
||||||
//! 32-bit ARM architecture (big endian).
|
|
||||||
kArchARM_BE = kArchARM | kArchBigEndianMask,
|
|
||||||
//! 64-bit ARM architecture in (little endian).
|
|
||||||
kArchAArch64 = 6,
|
|
||||||
//! 64-bit ARM architecture in (big endian).
|
|
||||||
kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask,
|
|
||||||
//! 32-bit ARM in Thumb mode (little endian).
|
|
||||||
kArchThumb = 7,
|
|
||||||
//! 32-bit ARM in Thumb mode (big endian).
|
|
||||||
kArchThumb_BE = kArchThumb | kArchBigEndianMask,
|
|
||||||
|
|
||||||
// 8 is not used, even numbers are 64-bit architectures.
|
|
||||||
|
|
||||||
//! 32-bit MIPS architecture in (little endian).
|
|
||||||
kArchMIPS32_LE = 9,
|
|
||||||
//! 32-bit MIPS architecture in (big endian).
|
|
||||||
kArchMIPS32_BE = kArchMIPS32_LE | kArchBigEndianMask,
|
|
||||||
//! 64-bit MIPS architecture in (little endian).
|
|
||||||
kArchMIPS64_LE = 10,
|
|
||||||
//! 64-bit MIPS architecture in (big endian).
|
|
||||||
kArchMIPS64_BE = kArchMIPS64_LE | kArchBigEndianMask,
|
|
||||||
|
|
||||||
//! Count of architectures.
|
|
||||||
kArchCount = 11
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Sub-architecture.
|
|
||||||
enum SubArch : uint32_t {
|
|
||||||
//! Unknown or uninitialized architecture sub-type.
|
|
||||||
kSubArchUnknown = 0,
|
|
||||||
|
|
||||||
//! Count of sub-architectures.
|
|
||||||
kSubArchCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Vendor.
|
|
||||||
//!
|
|
||||||
//! \note AsmJit doesn't use vendor information at the moment. It's provided
|
|
||||||
//! for future use, if required.
|
|
||||||
enum Vendor : uint32_t {
|
|
||||||
//! Unknown or uninitialized vendor.
|
|
||||||
kVendorUnknown = 0,
|
|
||||||
|
|
||||||
//! Count of vendor identifiers.
|
|
||||||
kVendorCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Platform / OS.
|
|
||||||
enum Platform : uint32_t {
|
|
||||||
//! Unknown or uninitialized platform.
|
|
||||||
kPlatformUnknown = 0,
|
|
||||||
|
|
||||||
//! Windows OS.
|
|
||||||
kPlatformWindows,
|
|
||||||
|
|
||||||
//! Other platform, most likely POSIX based.
|
|
||||||
kPlatformOther,
|
|
||||||
|
|
||||||
//! Linux OS.
|
|
||||||
kPlatformLinux,
|
|
||||||
//! GNU/Hurd OS.
|
|
||||||
kPlatformHurd,
|
|
||||||
|
|
||||||
//! FreeBSD OS.
|
|
||||||
kPlatformFreeBSD,
|
|
||||||
//! OpenBSD OS.
|
|
||||||
kPlatformOpenBSD,
|
|
||||||
//! NetBSD OS.
|
|
||||||
kPlatformNetBSD,
|
|
||||||
//! DragonFly BSD OS.
|
|
||||||
kPlatformDragonFlyBSD,
|
|
||||||
|
|
||||||
//! Haiku OS.
|
|
||||||
kPlatformHaiku,
|
|
||||||
|
|
||||||
//! Apple OSX.
|
|
||||||
kPlatformOSX,
|
|
||||||
//! Apple iOS.
|
|
||||||
kPlatformIOS,
|
|
||||||
//! Apple TVOS.
|
|
||||||
kPlatformTVOS,
|
|
||||||
//! Apple WatchOS.
|
|
||||||
kPlatformWatchOS,
|
|
||||||
|
|
||||||
//! Emscripten platform.
|
|
||||||
kPlatformEmscripten,
|
|
||||||
|
|
||||||
//! Count of platform identifiers.
|
|
||||||
kPlatformCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//! ABI.
|
|
||||||
enum Abi : uint32_t {
|
|
||||||
//! Unknown or uninitialied environment.
|
|
||||||
kAbiUnknown = 0,
|
|
||||||
//! Microsoft ABI.
|
|
||||||
kAbiMSVC,
|
|
||||||
//! GNU ABI.
|
|
||||||
kAbiGNU,
|
|
||||||
//! Android Environment / ABI.
|
|
||||||
kAbiAndroid,
|
|
||||||
//! Cygwin ABI.
|
|
||||||
kAbiCygwin,
|
|
||||||
|
|
||||||
//! Count of known ABI types.
|
|
||||||
kAbiCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Object format.
|
|
||||||
//!
|
|
||||||
//! \note AsmJit doesn't really use anything except \ref kFormatUnknown and
|
|
||||||
//! \ref kFormatJIT at the moment. Object file formats are provided for
|
|
||||||
//! future extensibility and a possibility to generate object files at some
|
|
||||||
//! point.
|
|
||||||
enum Format : uint32_t {
|
|
||||||
//! Unknown or uninitialized object format.
|
|
||||||
kFormatUnknown = 0,
|
|
||||||
|
|
||||||
//! JIT code generation object, most likely \ref JitRuntime or a custom
|
|
||||||
//! \ref Target implementation.
|
|
||||||
kFormatJIT,
|
|
||||||
|
|
||||||
//! Executable and linkable format (ELF).
|
|
||||||
kFormatELF,
|
|
||||||
//! Common object file format.
|
|
||||||
kFormatCOFF,
|
|
||||||
//! Extended COFF object format.
|
|
||||||
kFormatXCOFF,
|
|
||||||
//! Mach object file format.
|
|
||||||
kFormatMachO,
|
|
||||||
|
|
||||||
//! Count of object format types.
|
|
||||||
kFormatCount
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Environment Detection
|
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
#ifdef _DOXYGEN
|
//! Architecture.
|
||||||
//! Architecture detected at compile-time (architecture of the host).
|
Arch _arch;
|
||||||
static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME;
|
//! Sub-architecture type.
|
||||||
//! Sub-architecture detected at compile-time (sub-architecture of the host).
|
SubArch _subArch;
|
||||||
static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME;
|
//! Vendor type.
|
||||||
//! Vendor detected at compile-time (vendor of the host).
|
Vendor _vendor;
|
||||||
static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME;
|
//! Platform.
|
||||||
//! Platform detected at compile-time (platform of the host).
|
Platform _platform;
|
||||||
static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME;
|
//! Platform ABI.
|
||||||
//! ABI detected at compile-time (ABI of the host).
|
PlatformABI _platformABI;
|
||||||
static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME;
|
//! Object format.
|
||||||
#else
|
ObjectFormat _objectFormat;
|
||||||
static constexpr Arch kArchHost =
|
//! Reserved for future use, must be zero.
|
||||||
ASMJIT_ARCH_X86 == 32 ? kArchX86 :
|
uint8_t _reserved[2];
|
||||||
ASMJIT_ARCH_X86 == 64 ? kArchX64 :
|
|
||||||
|
|
||||||
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM :
|
|
||||||
ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE :
|
|
||||||
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 :
|
|
||||||
ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE :
|
|
||||||
|
|
||||||
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? kArchMIPS32_LE :
|
|
||||||
ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_BE ? kArchMIPS32_BE :
|
|
||||||
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_LE ? kArchMIPS64_LE :
|
|
||||||
ASMJIT_ARCH_MIPS == 64 && ASMJIT_ARCH_BE ? kArchMIPS64_BE :
|
|
||||||
|
|
||||||
kArchUnknown;
|
|
||||||
|
|
||||||
static constexpr SubArch kSubArchHost =
|
|
||||||
kSubArchUnknown;
|
|
||||||
|
|
||||||
static constexpr Vendor kVendorHost =
|
|
||||||
kVendorUnknown;
|
|
||||||
|
|
||||||
static constexpr Platform kPlatformHost =
|
|
||||||
#if defined(__EMSCRIPTEN__)
|
|
||||||
kPlatformEmscripten
|
|
||||||
#elif defined(_WIN32)
|
|
||||||
kPlatformWindows
|
|
||||||
#elif defined(__linux__)
|
|
||||||
kPlatformLinux
|
|
||||||
#elif defined(__gnu_hurd__)
|
|
||||||
kPlatformHurd
|
|
||||||
#elif defined(__FreeBSD__)
|
|
||||||
kPlatformFreeBSD
|
|
||||||
#elif defined(__OpenBSD__)
|
|
||||||
kPlatformOpenBSD
|
|
||||||
#elif defined(__NetBSD__)
|
|
||||||
kPlatformNetBSD
|
|
||||||
#elif defined(__DragonFly__)
|
|
||||||
kPlatformDragonFlyBSD
|
|
||||||
#elif defined(__HAIKU__)
|
|
||||||
kPlatformHaiku
|
|
||||||
#elif defined(__APPLE__) && TARGET_OS_OSX
|
|
||||||
kPlatformOSX
|
|
||||||
#elif defined(__APPLE__) && TARGET_OS_TV
|
|
||||||
kPlatformTVOS
|
|
||||||
#elif defined(__APPLE__) && TARGET_OS_WATCH
|
|
||||||
kPlatformWatchOS
|
|
||||||
#elif defined(__APPLE__) && TARGET_OS_IPHONE
|
|
||||||
kPlatformIOS
|
|
||||||
#else
|
|
||||||
kPlatformOther
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
static constexpr Abi kAbiHost =
|
|
||||||
#if defined(_MSC_VER)
|
|
||||||
kAbiMSVC
|
|
||||||
#elif defined(__CYGWIN__)
|
|
||||||
kAbiCygwin
|
|
||||||
#elif defined(__MINGW32__) || defined(__GLIBC__)
|
|
||||||
kAbiGNU
|
|
||||||
#elif defined(__ANDROID__)
|
|
||||||
kAbiAndroid
|
|
||||||
#else
|
|
||||||
kAbiUnknown
|
|
||||||
#endif
|
|
||||||
;
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Construction / Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline Environment() noexcept :
|
inline Environment() noexcept :
|
||||||
_arch(uint8_t(kArchUnknown)),
|
_arch(Arch::kUnknown),
|
||||||
_subArch(uint8_t(kSubArchUnknown)),
|
_subArch(SubArch::kUnknown),
|
||||||
_vendor(uint8_t(kVendorUnknown)),
|
_vendor(Vendor::kUnknown),
|
||||||
_platform(uint8_t(kPlatformUnknown)),
|
_platform(Platform::kUnknown),
|
||||||
_abi(uint8_t(kAbiUnknown)),
|
_platformABI(PlatformABI::kUnknown),
|
||||||
_format(uint8_t(kFormatUnknown)),
|
_objectFormat(ObjectFormat::kUnknown),
|
||||||
_reserved(0) {}
|
_reserved { 0, 0 } {}
|
||||||
|
|
||||||
|
inline explicit Environment(
|
||||||
|
Arch arch,
|
||||||
|
SubArch subArch = SubArch::kUnknown,
|
||||||
|
Vendor vendor = Vendor::kUnknown,
|
||||||
|
Platform platform = Platform::kUnknown,
|
||||||
|
PlatformABI abi = PlatformABI::kUnknown,
|
||||||
|
ObjectFormat objectFormat = ObjectFormat::kUnknown) noexcept {
|
||||||
|
|
||||||
|
init(arch, subArch, vendor, platform, abi, objectFormat);
|
||||||
|
}
|
||||||
|
|
||||||
inline Environment(const Environment& other) noexcept = default;
|
inline Environment(const Environment& other) noexcept = default;
|
||||||
|
|
||||||
inline explicit Environment(uint32_t arch,
|
//! Returns the host environment constructed from preprocessor macros defined by the compiler.
|
||||||
uint32_t subArch = kSubArchUnknown,
|
//!
|
||||||
uint32_t vendor = kVendorUnknown,
|
//! The returned environment should precisely match the target host architecture, sub-architecture, platform,
|
||||||
uint32_t platform = kPlatformUnknown,
|
//! and ABI.
|
||||||
uint32_t abi = kAbiUnknown,
|
static inline Environment host() noexcept {
|
||||||
uint32_t format = kFormatUnknown) noexcept {
|
return Environment(Arch::kHost, SubArch::kHost, Vendor::kHost, Platform::kHost, PlatformABI::kHost, ObjectFormat::kUnknown);
|
||||||
init(arch, subArch, vendor, platform, abi, format);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -358,7 +261,7 @@ public:
|
|||||||
//! Tests whether the environment is initialized, which means it must have
|
//! Tests whether the environment is initialized, which means it must have
|
||||||
//! a valid architecture.
|
//! a valid architecture.
|
||||||
inline bool isInitialized() const noexcept {
|
inline bool isInitialized() const noexcept {
|
||||||
return _arch != kArchUnknown;
|
return _arch != Arch::kUnknown;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint64_t _packed() const noexcept {
|
inline uint64_t _packed() const noexcept {
|
||||||
@@ -369,56 +272,60 @@ public:
|
|||||||
|
|
||||||
//! Resets all members of the environment to zero / unknown.
|
//! Resets all members of the environment to zero / unknown.
|
||||||
inline void reset() noexcept {
|
inline void reset() noexcept {
|
||||||
_arch = uint8_t(kArchUnknown);
|
_arch = Arch::kUnknown;
|
||||||
_subArch = uint8_t(kSubArchUnknown);
|
_subArch = SubArch::kUnknown;
|
||||||
_vendor = uint8_t(kVendorUnknown);
|
_vendor = Vendor::kUnknown;
|
||||||
_platform = uint8_t(kPlatformUnknown);
|
_platform = Platform::kUnknown;
|
||||||
_abi = uint8_t(kAbiUnknown);
|
_platformABI = PlatformABI::kUnknown;
|
||||||
_format = uint8_t(kFormatUnknown);
|
_objectFormat = ObjectFormat::kUnknown;
|
||||||
_reserved = 0;
|
_reserved[0] = 0;
|
||||||
|
_reserved[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool equals(const Environment& other) const noexcept {
|
inline bool equals(const Environment& other) const noexcept {
|
||||||
return _packed() == other._packed();
|
return _packed() == other._packed();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns the architecture, see \ref Arch.
|
//! Returns the architecture.
|
||||||
inline uint32_t arch() const noexcept { return _arch; }
|
inline Arch arch() const noexcept { return _arch; }
|
||||||
//! Returns the sub-architecture, see \ref SubArch.
|
//! Returns the sub-architecture.
|
||||||
inline uint32_t subArch() const noexcept { return _subArch; }
|
inline SubArch subArch() const noexcept { return _subArch; }
|
||||||
//! Returns vendor, see \ref Vendor.
|
//! Returns vendor.
|
||||||
inline uint32_t vendor() const noexcept { return _vendor; }
|
inline Vendor vendor() const noexcept { return _vendor; }
|
||||||
//! Returns target's platform or operating system, see \ref Platform.
|
//! Returns target's platform or operating system.
|
||||||
inline uint32_t platform() const noexcept { return _platform; }
|
inline Platform platform() const noexcept { return _platform; }
|
||||||
//! Returns target's ABI, see \ref Abi.
|
//! Returns target's ABI.
|
||||||
inline uint32_t abi() const noexcept { return _abi; }
|
inline PlatformABI platformABI() const noexcept { return _platformABI; }
|
||||||
//! Returns target's object format, see \ref Format.
|
//! Returns target's object format.
|
||||||
inline uint32_t format() const noexcept { return _format; }
|
inline ObjectFormat objectFormat() const noexcept { return _objectFormat; }
|
||||||
|
|
||||||
inline void init(uint32_t arch,
|
inline void init(
|
||||||
uint32_t subArch = kSubArchUnknown,
|
Arch arch,
|
||||||
uint32_t vendor = kVendorUnknown,
|
SubArch subArch = SubArch::kUnknown,
|
||||||
uint32_t platform = kPlatformUnknown,
|
Vendor vendor = Vendor::kUnknown,
|
||||||
uint32_t abi = kAbiUnknown,
|
Platform platform = Platform::kUnknown,
|
||||||
uint32_t format = kFormatUnknown) noexcept {
|
PlatformABI platformABI = PlatformABI::kUnknown,
|
||||||
_arch = uint8_t(arch);
|
ObjectFormat objectFormat = ObjectFormat::kUnknown) noexcept {
|
||||||
_subArch = uint8_t(subArch);
|
|
||||||
_vendor = uint8_t(vendor);
|
_arch = arch;
|
||||||
_platform = uint8_t(platform);
|
_subArch = subArch;
|
||||||
_abi = uint8_t(abi);
|
_vendor = vendor;
|
||||||
_format = uint8_t(format);
|
_platform = platform;
|
||||||
_reserved = 0;
|
_platformABI = platformABI;
|
||||||
|
_objectFormat = objectFormat;
|
||||||
|
_reserved[0] = 0;
|
||||||
|
_reserved[1] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isArchX86() const noexcept { return _arch == kArchX86; }
|
inline bool isArchX86() const noexcept { return _arch == Arch::kX86; }
|
||||||
inline bool isArchX64() const noexcept { return _arch == kArchX64; }
|
inline bool isArchX64() const noexcept { return _arch == Arch::kX64; }
|
||||||
inline bool isArchRISCV32() const noexcept { return _arch == kArchRISCV32; }
|
inline bool isArchARM() const noexcept { return isArchARM(_arch); }
|
||||||
inline bool isArchRISCV64() const noexcept { return _arch == kArchRISCV64; }
|
inline bool isArchThumb() const noexcept { return isArchThumb(_arch); }
|
||||||
inline bool isArchARM() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchARM; }
|
inline bool isArchAArch64() const noexcept { return isArchAArch64(_arch); }
|
||||||
inline bool isArchThumb() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchThumb; }
|
inline bool isArchMIPS32() const noexcept { return isArchMIPS32(_arch); }
|
||||||
inline bool isArchAArch64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchAArch64; }
|
inline bool isArchMIPS64() const noexcept { return isArchMIPS64(_arch); }
|
||||||
inline bool isArchMIPS32() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS32_LE; }
|
inline bool isArchRISCV32() const noexcept { return _arch == Arch::kRISCV32; }
|
||||||
inline bool isArchMIPS64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS64_LE; }
|
inline bool isArchRISCV64() const noexcept { return _arch == Arch::kRISCV64; }
|
||||||
|
|
||||||
//! Tests whether the architecture is 32-bit.
|
//! Tests whether the architecture is 32-bit.
|
||||||
inline bool is32Bit() const noexcept { return is32Bit(_arch); }
|
inline bool is32Bit() const noexcept { return is32Bit(_arch); }
|
||||||
@@ -432,45 +339,45 @@ public:
|
|||||||
|
|
||||||
//! Tests whether this architecture is of X86 family.
|
//! Tests whether this architecture is of X86 family.
|
||||||
inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); }
|
inline bool isFamilyX86() const noexcept { return isFamilyX86(_arch); }
|
||||||
//! Tests whether this architecture family is RISC-V (both 32-bit and 64-bit).
|
|
||||||
inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); }
|
|
||||||
//! Tests whether this architecture family is ARM, Thumb, or AArch64.
|
//! Tests whether this architecture family is ARM, Thumb, or AArch64.
|
||||||
inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); }
|
inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); }
|
||||||
//! Tests whether this architecture family is MISP or MIPS64.
|
//! Tests whether this architecture family is MISP or MIPS64.
|
||||||
inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); }
|
inline bool isFamilyMIPS() const noexcept { return isFamilyMIPS(_arch); }
|
||||||
|
//! Tests whether this architecture family is RISC-V (both 32-bit and 64-bit).
|
||||||
|
inline bool isFamilyRISCV() const noexcept { return isFamilyRISCV(_arch); }
|
||||||
|
|
||||||
//! Tests whether the environment platform is Windows.
|
//! Tests whether the environment platform is Windows.
|
||||||
inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; }
|
inline bool isPlatformWindows() const noexcept { return _platform == Platform::kWindows; }
|
||||||
|
|
||||||
//! Tests whether the environment platform is Linux.
|
//! Tests whether the environment platform is Linux.
|
||||||
inline bool isPlatformLinux() const noexcept { return _platform == kPlatformLinux; }
|
inline bool isPlatformLinux() const noexcept { return _platform == Platform::kLinux; }
|
||||||
|
|
||||||
//! Tests whether the environment platform is Hurd.
|
//! Tests whether the environment platform is Hurd.
|
||||||
inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; }
|
inline bool isPlatformHurd() const noexcept { return _platform == Platform::kHurd; }
|
||||||
|
|
||||||
//! Tests whether the environment platform is Haiku.
|
//! Tests whether the environment platform is Haiku.
|
||||||
inline bool isPlatformHaiku() const noexcept { return _platform == kPlatformHaiku; }
|
inline bool isPlatformHaiku() const noexcept { return _platform == Platform::kHaiku; }
|
||||||
|
|
||||||
//! Tests whether the environment platform is any BSD.
|
//! Tests whether the environment platform is any BSD.
|
||||||
inline bool isPlatformBSD() const noexcept {
|
inline bool isPlatformBSD() const noexcept {
|
||||||
return _platform == kPlatformFreeBSD ||
|
return _platform == Platform::kFreeBSD ||
|
||||||
_platform == kPlatformOpenBSD ||
|
_platform == Platform::kOpenBSD ||
|
||||||
_platform == kPlatformNetBSD ||
|
_platform == Platform::kNetBSD ||
|
||||||
_platform == kPlatformDragonFlyBSD;
|
_platform == Platform::kDragonFlyBSD;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS).
|
//! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS).
|
||||||
inline bool isPlatformApple() const noexcept {
|
inline bool isPlatformApple() const noexcept {
|
||||||
return _platform == kPlatformOSX ||
|
return _platform == Platform::kOSX ||
|
||||||
_platform == kPlatformIOS ||
|
_platform == Platform::kIOS ||
|
||||||
_platform == kPlatformTVOS ||
|
_platform == Platform::kTVOS ||
|
||||||
_platform == kPlatformWatchOS;
|
_platform == Platform::kWatchOS;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the ABI is MSVC.
|
//! Tests whether the ABI is MSVC.
|
||||||
inline bool isAbiMSVC() const noexcept { return _abi == kAbiMSVC; }
|
inline bool isMSVC() const noexcept { return _platformABI == PlatformABI::kMSVC; }
|
||||||
//! Tests whether the ABI is GNU.
|
//! Tests whether the ABI is GNU.
|
||||||
inline bool isAbiGNU() const noexcept { return _abi == kAbiGNU; }
|
inline bool isGNU() const noexcept { return _platformABI == PlatformABI::kGNU; }
|
||||||
|
|
||||||
//! Returns a calculated stack alignment for this environment.
|
//! Returns a calculated stack alignment for this environment.
|
||||||
ASMJIT_API uint32_t stackAlignment() const noexcept;
|
ASMJIT_API uint32_t stackAlignment() const noexcept;
|
||||||
@@ -479,134 +386,109 @@ public:
|
|||||||
uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); }
|
uint32_t registerSize() const noexcept { return registerSizeFromArch(_arch); }
|
||||||
|
|
||||||
//! Sets the architecture to `arch`.
|
//! Sets the architecture to `arch`.
|
||||||
inline void setArch(uint32_t arch) noexcept { _arch = uint8_t(arch); }
|
inline void setArch(Arch arch) noexcept { _arch = arch; }
|
||||||
//! Sets the sub-architecture to `subArch`.
|
//! Sets the sub-architecture to `subArch`.
|
||||||
inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); }
|
inline void setSubArch(SubArch subArch) noexcept { _subArch = subArch; }
|
||||||
//! Sets the vendor to `vendor`.
|
//! Sets the vendor to `vendor`.
|
||||||
inline void setVendor(uint32_t vendor) noexcept { _vendor = uint8_t(vendor); }
|
inline void setVendor(Vendor vendor) noexcept { _vendor = vendor; }
|
||||||
//! Sets the platform to `platform`.
|
//! Sets the platform to `platform`.
|
||||||
inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); }
|
inline void setPlatform(Platform platform) noexcept { _platform = platform; }
|
||||||
//! Sets the ABI to `abi`.
|
//! Sets the ABI to `platformABI`.
|
||||||
inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); }
|
inline void setPlatformABI(PlatformABI platformABI) noexcept { _platformABI = platformABI; }
|
||||||
//! Sets the object format to `format`.
|
//! Sets the object format to `objectFormat`.
|
||||||
inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); }
|
inline void setObjectFormat(ObjectFormat objectFormat) noexcept { _objectFormat = objectFormat; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Static Utilities
|
//! \name Static Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
static inline bool isValidArch(uint32_t arch) noexcept {
|
static inline bool isDefinedArch(Arch arch) noexcept {
|
||||||
return (arch & ~kArchBigEndianMask) != 0 &&
|
return uint32_t(arch) <= uint32_t(Arch::kMaxValue);
|
||||||
(arch & ~kArchBigEndianMask) < kArchCount;
|
}
|
||||||
|
|
||||||
|
static inline bool isValidArch(Arch arch) noexcept {
|
||||||
|
return arch != Arch::kUnknown && uint32_t(arch) <= uint32_t(Arch::kMaxValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture `arch` is 32-bit.
|
//! Tests whether the given architecture `arch` is 32-bit.
|
||||||
static inline bool is32Bit(uint32_t arch) noexcept {
|
static inline bool is32Bit(Arch arch) noexcept {
|
||||||
return (arch & kArch32BitMask) == kArch32BitMask;
|
return (uint32_t(arch) & uint32_t(Arch::k32BitMask)) == uint32_t(Arch::k32BitMask);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture `arch` is 64-bit.
|
//! Tests whether the given architecture `arch` is 64-bit.
|
||||||
static inline bool is64Bit(uint32_t arch) noexcept {
|
static inline bool is64Bit(Arch arch) noexcept {
|
||||||
return (arch & kArch32BitMask) == 0;
|
return (uint32_t(arch) & uint32_t(Arch::k32BitMask)) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture `arch` is little endian.
|
//! Tests whether the given architecture `arch` is little endian.
|
||||||
static inline bool isLittleEndian(uint32_t arch) noexcept {
|
static inline bool isLittleEndian(Arch arch) noexcept {
|
||||||
return (arch & kArchBigEndianMask) == 0;
|
return uint32_t(arch) < uint32_t(Arch::kBigEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture `arch` is big endian.
|
//! Tests whether the given architecture `arch` is big endian.
|
||||||
static inline bool isBigEndian(uint32_t arch) noexcept {
|
static inline bool isBigEndian(Arch arch) noexcept {
|
||||||
return (arch & kArchBigEndianMask) == kArchBigEndianMask;
|
return uint32_t(arch) >= uint32_t(Arch::kBigEndian);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture is AArch64.
|
//! Tests whether the given architecture is ARM or ARM_BE.
|
||||||
static inline bool isArchAArch64(uint32_t arch) noexcept {
|
static inline bool isArchARM(Arch arch) noexcept {
|
||||||
arch &= ~kArchBigEndianMask;
|
return arch == Arch::kARM || arch == Arch::kARM_BE;
|
||||||
return arch == kArchAArch64;
|
}
|
||||||
|
|
||||||
|
//! Tests whether the given architecture is Thumb or Thumb_BE.
|
||||||
|
static inline bool isArchThumb(Arch arch) noexcept {
|
||||||
|
return arch == Arch::kThumb || arch == Arch::kThumb_BE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Tests whether the given architecture is AArch64 or AArch64_BE.
|
||||||
|
static inline bool isArchAArch64(Arch arch) noexcept {
|
||||||
|
return arch == Arch::kAArch64 || arch == Arch::kAArch64_BE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Tests whether the given architecture is MIPS32_LE or MIPS32_BE.
|
||||||
|
static inline bool isArchMIPS32(Arch arch) noexcept {
|
||||||
|
return arch == Arch::kMIPS32_LE || arch == Arch::kMIPS32_BE;
|
||||||
|
}
|
||||||
|
|
||||||
|
//! Tests whether the given architecture is MIPS64_LE or MIPS64_BE.
|
||||||
|
static inline bool isArchMIPS64(Arch arch) noexcept {
|
||||||
|
return arch == Arch::kMIPS64_LE || arch == Arch::kMIPS64_BE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture family is X86 or X64.
|
//! Tests whether the given architecture family is X86 or X64.
|
||||||
static inline bool isFamilyX86(uint32_t arch) noexcept {
|
static inline bool isFamilyX86(Arch arch) noexcept {
|
||||||
return arch == kArchX86 ||
|
return arch == Arch::kX86 || arch == Arch::kX64;
|
||||||
arch == kArchX64;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit).
|
|
||||||
static inline bool isFamilyRISCV(uint32_t arch) noexcept {
|
|
||||||
return arch == kArchRISCV32 ||
|
|
||||||
arch == kArchRISCV64;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture family is ARM, Thumb, or AArch64.
|
//! Tests whether the given architecture family is ARM, Thumb, or AArch64.
|
||||||
static inline bool isFamilyARM(uint32_t arch) noexcept {
|
static inline bool isFamilyARM(Arch arch) noexcept {
|
||||||
arch &= ~kArchBigEndianMask;
|
return isArchARM(arch) || isArchAArch64(arch) || isArchThumb(arch);
|
||||||
return arch == kArchARM ||
|
|
||||||
arch == kArchAArch64 ||
|
|
||||||
arch == kArchThumb;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Tests whether the given architecture family is MISP or MIPS64.
|
//! Tests whether the given architecture family is MISP or MIPS64.
|
||||||
static inline bool isFamilyMIPS(uint32_t arch) noexcept {
|
static inline bool isFamilyMIPS(Arch arch) noexcept {
|
||||||
arch &= ~kArchBigEndianMask;
|
return isArchMIPS32(arch) || isArchMIPS64(arch);
|
||||||
return arch == kArchMIPS32_LE ||
|
}
|
||||||
arch == kArchMIPS64_LE;
|
|
||||||
|
//! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit).
|
||||||
|
static inline bool isFamilyRISCV(Arch arch) noexcept {
|
||||||
|
return arch == Arch::kRISCV32 || arch == Arch::kRISCV64;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Returns a native general purpose register size from the given architecture.
|
//! Returns a native general purpose register size from the given architecture.
|
||||||
static uint32_t registerSizeFromArch(uint32_t arch) noexcept {
|
static inline uint32_t registerSizeFromArch(Arch arch) noexcept {
|
||||||
return is32Bit(arch) ? 4u : 8u;
|
return is32Bit(arch) ? 4u : 8u;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Returns the host environment constructed from preprocessor macros defined
|
|
||||||
//! by the compiler.
|
|
||||||
//!
|
|
||||||
//! The returned environment should precisely match the target host architecture,
|
|
||||||
//! sub-architecture, platform, and ABI.
|
|
||||||
static ASMJIT_INLINE Environment hostEnvironment() noexcept {
|
|
||||||
return Environment(Environment::kArchHost,
|
|
||||||
Environment::kSubArchHost,
|
|
||||||
Environment::kVendorHost,
|
|
||||||
Environment::kPlatformHost,
|
|
||||||
Environment::kAbiHost,
|
|
||||||
Environment::kFormatUnknown);
|
|
||||||
}
|
|
||||||
|
|
||||||
static_assert(sizeof(Environment) == 8,
|
static_assert(sizeof(Environment) == 8,
|
||||||
"Environment must occupy exactly 8 bytes.");
|
"Environment must occupy exactly 8 bytes.");
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment {
|
|
||||||
public:
|
|
||||||
inline ArchInfo() noexcept : Environment() {}
|
|
||||||
|
|
||||||
inline ArchInfo(const Environment& other) noexcept : Environment(other) {}
|
|
||||||
inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept
|
|
||||||
: Environment(arch, subArch) {}
|
|
||||||
|
|
||||||
enum Id : uint32_t {
|
|
||||||
kIdNone = Environment::kArchUnknown,
|
|
||||||
kIdX86 = Environment::kArchX86,
|
|
||||||
kIdX64 = Environment::kArchX64,
|
|
||||||
kIdA32 = Environment::kArchARM,
|
|
||||||
kIdA64 = Environment::kArchAArch64,
|
|
||||||
kIdHost = Environment::kArchHost
|
|
||||||
};
|
|
||||||
|
|
||||||
enum SubType : uint32_t {
|
|
||||||
kSubIdNone = Environment::kSubArchUnknown
|
|
||||||
};
|
|
||||||
|
|
||||||
static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); }
|
|
||||||
};
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
|
||||||
|
|||||||
@@ -1,36 +1,13 @@
|
|||||||
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
// AsmJit - Machine code generation for C++
|
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/errorhandler.h"
|
#include "../core/errorhandler.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ErrorHandler]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ErrorHandler::ErrorHandler() noexcept {}
|
ErrorHandler::ErrorHandler() noexcept {}
|
||||||
ErrorHandler::~ErrorHandler() noexcept {}
|
ErrorHandler::~ErrorHandler() noexcept {}
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
|
||||||
@@ -31,41 +13,28 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_error_handling
|
//! \addtogroup asmjit_error_handling
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class BaseEmitter;
|
class BaseEmitter;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ErrorHandler]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Error handler can be used to override the default behavior of error handling.
|
//! Error handler can be used to override the default behavior of error handling.
|
||||||
//!
|
//!
|
||||||
//! It's available to all classes that inherit `BaseEmitter`. Override
|
//! It's available to all classes that inherit `BaseEmitter`. Override \ref ErrorHandler::handleError() to implement
|
||||||
//! \ref ErrorHandler::handleError() to implement your own error handler.
|
//! your own error handler.
|
||||||
//!
|
//!
|
||||||
//! The following use-cases are supported:
|
//! The following use-cases are supported:
|
||||||
//!
|
//!
|
||||||
//! - Record the error and continue code generation. This is the simplest
|
//! - Record the error and continue code generation. This is the simplest approach that can be used to at least log
|
||||||
//! approach that can be used to at least log possible errors.
|
//! possible errors.
|
||||||
//! - Throw an exception. AsmJit doesn't use exceptions and is completely
|
//! - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
|
||||||
//! exception-safe, but it's perfectly legal to throw an exception from
|
//! to throw an exception from the error handler.
|
||||||
//! the error handler.
|
//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to
|
||||||
//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler,
|
//! a consistent state before calling \ref handleError(), so `longjmp()` can be used without issues to cancel the
|
||||||
//! Builder and Compiler to a consistent state before calling \ref handleError(),
|
//! code generation if an error occurred. This method can be used if exception handling in your project is turned
|
||||||
//! so `longjmp()` can be used without issues to cancel the code-generation if
|
//! off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref Zone memory and the
|
||||||
//! an error occurred. This method can be used if exception handling in your
|
//! ownership of memory it allocates always ends with the instance that allocated it. If using this approach please
|
||||||
//! project is turned off and you still want some comfort. In most cases it
|
//! never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
|
||||||
//! should be safe as AsmJit uses \ref Zone memory and the ownership of memory
|
|
||||||
//! it allocates always ends with the instance that allocated it. If using this
|
|
||||||
//! approach please never jump outside the life-time of \ref CodeHolder and
|
|
||||||
//! \ref BaseEmitter.
|
|
||||||
//!
|
//!
|
||||||
//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter,
|
//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, which has a priority. The example below
|
||||||
//! which has a priority. The example below uses error handler that just prints
|
//! uses error handler that just prints the error, but lets AsmJit continue:
|
||||||
//! the error, but lets AsmJit continue:
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! // Error Handling #1 - Logging and returning Error.
|
//! // Error Handling #1 - Logging and returning Error.
|
||||||
@@ -108,12 +77,10 @@ class BaseEmitter;
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! If error happens during instruction emitting / encoding the assembler behaves
|
//! If error happens during instruction emitting / encoding the assembler behaves transactionally - the output buffer
|
||||||
//! transactionally - the output buffer won't advance if encoding failed, thus
|
//! won't advance if encoding failed, thus either a fully encoded instruction or nothing is emitted. The error handling
|
||||||
//! either a fully encoded instruction or nothing is emitted. The error handling
|
//! shown above is useful, but it's still not the best way of dealing with errors in AsmJit. The following example
|
||||||
//! shown above is useful, but it's still not the best way of dealing with errors
|
//! shows how to use exception handling to handle errors in a more C++ way:
|
||||||
//! in AsmJit. The following example shows how to use exception handling to handle
|
|
||||||
//! errors in a more C++ way:
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! // Error Handling #2 - Throwing an exception.
|
//! // Error Handling #2 - Throwing an exception.
|
||||||
@@ -168,13 +135,10 @@ class BaseEmitter;
|
|||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! If C++ exceptions are not what you like or your project turns off them
|
//! If C++ exceptions are not what you like or your project turns off them completely there is still a way of reducing
|
||||||
//! completely there is still a way of reducing the error handling to a minimum
|
//! the error handling to a minimum by using a standard setjmp/longjmp approach. AsmJit is exception-safe and cleans
|
||||||
//! by using a standard setjmp/longjmp approach. AsmJit is exception-safe and
|
//! up everything before calling the ErrorHandler, so any approach is safe. You can simply jump from the error handler
|
||||||
//! cleans up everything before calling the ErrorHandler, so any approach is
|
//! without causing any side-effects or memory leaks. The following example demonstrates how it could be done:
|
||||||
//! safe. You can simply jump from the error handler without causing any
|
|
||||||
//! side-effects or memory leaks. The following example demonstrates how it
|
|
||||||
//! could be done:
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed.
|
//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed.
|
||||||
@@ -223,40 +187,37 @@ class ASMJIT_VIRTAPI ErrorHandler {
|
|||||||
public:
|
public:
|
||||||
ASMJIT_BASE_CLASS(ErrorHandler)
|
ASMJIT_BASE_CLASS(ErrorHandler)
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Construction & Destruction
|
||||||
// [Construction / Destruction]
|
//! \{
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//! Creates a new `ErrorHandler` instance.
|
//! Creates a new `ErrorHandler` instance.
|
||||||
ASMJIT_API ErrorHandler() noexcept;
|
ASMJIT_API ErrorHandler() noexcept;
|
||||||
//! Destroys the `ErrorHandler` instance.
|
//! Destroys the `ErrorHandler` instance.
|
||||||
ASMJIT_API virtual ~ErrorHandler() noexcept;
|
ASMJIT_API virtual ~ErrorHandler() noexcept;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \}
|
||||||
// [Handle Error]
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Interface
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Error handler (must be reimplemented).
|
//! Error handler (must be reimplemented).
|
||||||
//!
|
//!
|
||||||
//! Error handler is called after an error happened and before it's propagated
|
//! Error handler is called after an error happened and before it's propagated to the caller. There are multiple
|
||||||
//! to the caller. There are multiple ways how the error handler can be used:
|
//! ways how the error handler can be used:
|
||||||
//!
|
//!
|
||||||
//! 1. User-based error handling without throwing exception or using C's
|
//! 1. User-based error handling without throwing exception or using C's`longjmp()`. This is for users that don't
|
||||||
//! `longjmp()`. This is for users that don't use exceptions and want
|
//! use exceptions and want customized error handling.
|
||||||
//! customized error handling.
|
|
||||||
//!
|
//!
|
||||||
//! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely
|
//! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely exception-safe, but you can throw
|
||||||
//! exception-safe, but you can throw exception from your error handler if
|
//! exception from your error handler if this way is the preferred way of handling errors in your project.
|
||||||
//! this way is the preferred way of handling errors in your project.
|
|
||||||
//!
|
//!
|
||||||
//! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts
|
//! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts `BaseEmitter` to a consistent state before
|
||||||
//! `BaseEmitter` to a consistent state before calling `handleError()`
|
//! calling `handleError()` so `longjmp()` can be used without any issues to cancel the code generation if an
|
||||||
//! so `longjmp()` can be used without any issues to cancel the code
|
//! error occurred. There is no difference between exceptions and `longjmp()` from AsmJit's perspective, however,
|
||||||
//! generation if an error occurred. There is no difference between
|
//! never jump outside of `CodeHolder` and `BaseEmitter` scope as you would leak memory.
|
||||||
//! exceptions and `longjmp()` from AsmJit's perspective, however,
|
|
||||||
//! never jump outside of `CodeHolder` and `BaseEmitter` scope as you
|
|
||||||
//! would leak memory.
|
|
||||||
virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0;
|
virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0;
|
||||||
|
|
||||||
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
|
||||||
//
|
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FEATURES_H_INCLUDED
|
|
||||||
#define ASMJIT_CORE_FEATURES_H_INCLUDED
|
|
||||||
|
|
||||||
#include "../core/globals.h"
|
|
||||||
#include "../core/support.h"
|
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::BaseFeatures]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Base class that provides information about CPU features.
|
|
||||||
//!
|
|
||||||
//! Internally each feature is represented by a single bit in an embedded
|
|
||||||
//! bit-array, however, feature bits are defined by an architecture specific
|
|
||||||
//! implementations, like \ref x86::Features.
|
|
||||||
class BaseFeatures {
|
|
||||||
public:
|
|
||||||
typedef Support::BitWord BitWord;
|
|
||||||
typedef Support::BitVectorIterator<BitWord> Iterator;
|
|
||||||
|
|
||||||
enum : uint32_t {
|
|
||||||
kMaxFeatures = 256,
|
|
||||||
kNumBitWords = kMaxFeatures / Support::kBitWordSizeInBits
|
|
||||||
};
|
|
||||||
|
|
||||||
BitWord _bits[kNumBitWords];
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
inline BaseFeatures() noexcept { reset(); }
|
|
||||||
inline BaseFeatures(const BaseFeatures& other) noexcept = default;
|
|
||||||
inline explicit BaseFeatures(Globals::NoInit_) noexcept {}
|
|
||||||
|
|
||||||
inline void reset() noexcept {
|
|
||||||
for (size_t i = 0; i < kNumBitWords; i++)
|
|
||||||
_bits[i] = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Overloaded Operators
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
inline BaseFeatures& operator=(const BaseFeatures& other) noexcept = default;
|
|
||||||
|
|
||||||
inline bool operator==(const BaseFeatures& other) noexcept { return eq(other); }
|
|
||||||
inline bool operator!=(const BaseFeatures& other) noexcept { return !eq(other); }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Cast
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Casts this base class into a derived type `T`.
|
|
||||||
template<typename T>
|
|
||||||
inline T& as() noexcept { return static_cast<T&>(*this); }
|
|
||||||
|
|
||||||
//! Casts this base class into a derived type `T` (const).
|
|
||||||
template<typename T>
|
|
||||||
inline const T& as() const noexcept { return static_cast<const T&>(*this); }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Accessors
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
inline bool empty() const noexcept {
|
|
||||||
for (uint32_t i = 0; i < kNumBitWords; i++)
|
|
||||||
if (_bits[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns all features as array of bitwords (see \ref Support::BitWord).
|
|
||||||
inline BitWord* bits() noexcept { return _bits; }
|
|
||||||
//! Returns all features as array of bitwords (const).
|
|
||||||
inline const BitWord* bits() const noexcept { return _bits; }
|
|
||||||
|
|
||||||
//! Returns the number of BitWords returned by \ref bits().
|
|
||||||
inline size_t bitWordCount() const noexcept { return kNumBitWords; }
|
|
||||||
|
|
||||||
//! Returns \ref Support::BitVectorIterator, that can be used to iterate
|
|
||||||
//! all features efficiently
|
|
||||||
inline Iterator iterator() const noexcept {
|
|
||||||
return Iterator(_bits, kNumBitWords);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Tests whether the feature `featureId` is present.
|
|
||||||
inline bool has(uint32_t featureId) const noexcept {
|
|
||||||
ASMJIT_ASSERT(featureId < kMaxFeatures);
|
|
||||||
|
|
||||||
uint32_t idx = featureId / Support::kBitWordSizeInBits;
|
|
||||||
uint32_t bit = featureId % Support::kBitWordSizeInBits;
|
|
||||||
|
|
||||||
return bool((_bits[idx] >> bit) & 0x1);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Tests whether all features as defined by `other` are present.
|
|
||||||
inline bool hasAll(const BaseFeatures& other) const noexcept {
|
|
||||||
for (uint32_t i = 0; i < kNumBitWords; i++)
|
|
||||||
if ((_bits[i] & other._bits[i]) != other._bits[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Utilities
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Adds the given CPU `featureId` to the list of features.
|
|
||||||
inline void add(uint32_t featureId) noexcept {
|
|
||||||
ASMJIT_ASSERT(featureId < kMaxFeatures);
|
|
||||||
|
|
||||||
uint32_t idx = featureId / Support::kBitWordSizeInBits;
|
|
||||||
uint32_t bit = featureId % Support::kBitWordSizeInBits;
|
|
||||||
|
|
||||||
_bits[idx] |= BitWord(1) << bit;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
inline void add(uint32_t featureId, Args... otherIds) noexcept {
|
|
||||||
add(featureId);
|
|
||||||
add(otherIds...);
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Removes the given CPU `featureId` from the list of features.
|
|
||||||
inline void remove(uint32_t featureId) noexcept {
|
|
||||||
ASMJIT_ASSERT(featureId < kMaxFeatures);
|
|
||||||
|
|
||||||
uint32_t idx = featureId / Support::kBitWordSizeInBits;
|
|
||||||
uint32_t bit = featureId % Support::kBitWordSizeInBits;
|
|
||||||
|
|
||||||
_bits[idx] &= ~(BitWord(1) << bit);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename... Args>
|
|
||||||
inline void remove(uint32_t featureId, Args... otherIds) noexcept {
|
|
||||||
remove(featureId);
|
|
||||||
remove(otherIds...);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline bool eq(const BaseFeatures& other) const noexcept {
|
|
||||||
for (size_t i = 0; i < kNumBitWords; i++)
|
|
||||||
if (_bits[i] != other._bits[i])
|
|
||||||
return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
|
||||||
|
|
||||||
#endif // ASMJIT_CORE_FEATURES_H_INCLUDED
|
|
||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
@@ -29,7 +11,7 @@
|
|||||||
#include "../core/codeholder.h"
|
#include "../core/codeholder.h"
|
||||||
#include "../core/compiler.h"
|
#include "../core/compiler.h"
|
||||||
#include "../core/emitter.h"
|
#include "../core/emitter.h"
|
||||||
#include "../core/formatter.h"
|
#include "../core/formatter_p.h"
|
||||||
#include "../core/string.h"
|
#include "../core/string.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
#include "../core/type.h"
|
#include "../core/type.h"
|
||||||
@@ -48,10 +30,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
class VirtReg;
|
class VirtReg;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Formatter]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
namespace Formatter {
|
namespace Formatter {
|
||||||
|
|
||||||
static const char wordNameTable[][8] = {
|
static const char wordNameTable[][8] = {
|
||||||
@@ -72,40 +50,44 @@ static const char wordNameTable[][8] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
Error formatTypeId(String& sb, uint32_t typeId) noexcept {
|
Error formatTypeId(String& sb, TypeId typeId) noexcept {
|
||||||
if (typeId == Type::kIdVoid)
|
if (typeId == TypeId::kVoid)
|
||||||
return sb.append("void");
|
return sb.append("void");
|
||||||
|
|
||||||
if (!Type::isValid(typeId))
|
if (!TypeUtils::isValid(typeId))
|
||||||
return sb.append("unknown");
|
return sb.append("unknown");
|
||||||
|
|
||||||
const char* typeName = "unknown";
|
const char* typeName = "unknown";
|
||||||
uint32_t typeSize = Type::sizeOf(typeId);
|
uint32_t typeSize = TypeUtils::sizeOf(typeId);
|
||||||
|
TypeId scalarType = TypeUtils::scalarOf(typeId);
|
||||||
|
|
||||||
uint32_t baseId = Type::baseOf(typeId);
|
switch (scalarType) {
|
||||||
switch (baseId) {
|
case TypeId::kIntPtr : typeName = "intptr" ; break;
|
||||||
case Type::kIdIntPtr : typeName = "iptr" ; break;
|
case TypeId::kUIntPtr: typeName = "uintptr"; break;
|
||||||
case Type::kIdUIntPtr: typeName = "uptr" ; break;
|
case TypeId::kInt8 : typeName = "int8" ; break;
|
||||||
case Type::kIdI8 : typeName = "i8" ; break;
|
case TypeId::kUInt8 : typeName = "uint8" ; break;
|
||||||
case Type::kIdU8 : typeName = "u8" ; break;
|
case TypeId::kInt16 : typeName = "int16" ; break;
|
||||||
case Type::kIdI16 : typeName = "i16" ; break;
|
case TypeId::kUInt16 : typeName = "uint16" ; break;
|
||||||
case Type::kIdU16 : typeName = "u16" ; break;
|
case TypeId::kInt32 : typeName = "int32" ; break;
|
||||||
case Type::kIdI32 : typeName = "i32" ; break;
|
case TypeId::kUInt32 : typeName = "uint32" ; break;
|
||||||
case Type::kIdU32 : typeName = "u32" ; break;
|
case TypeId::kInt64 : typeName = "int64" ; break;
|
||||||
case Type::kIdI64 : typeName = "i64" ; break;
|
case TypeId::kUInt64 : typeName = "uint64" ; break;
|
||||||
case Type::kIdU64 : typeName = "u64" ; break;
|
case TypeId::kFloat32: typeName = "float32"; break;
|
||||||
case Type::kIdF32 : typeName = "f32" ; break;
|
case TypeId::kFloat64: typeName = "float64"; break;
|
||||||
case Type::kIdF64 : typeName = "f64" ; break;
|
case TypeId::kFloat80: typeName = "float80"; break;
|
||||||
case Type::kIdF80 : typeName = "f80" ; break;
|
case TypeId::kMask8 : typeName = "mask8" ; break;
|
||||||
case Type::kIdMask8 : typeName = "mask8" ; break;
|
case TypeId::kMask16 : typeName = "mask16" ; break;
|
||||||
case Type::kIdMask16 : typeName = "mask16"; break;
|
case TypeId::kMask32 : typeName = "mask32" ; break;
|
||||||
case Type::kIdMask32 : typeName = "mask32"; break;
|
case TypeId::kMask64 : typeName = "mask64" ; break;
|
||||||
case Type::kIdMask64 : typeName = "mask64"; break;
|
case TypeId::kMmx32 : typeName = "mmx32" ; break;
|
||||||
case Type::kIdMmx32 : typeName = "mmx32" ; break;
|
case TypeId::kMmx64 : typeName = "mmx64" ; break;
|
||||||
case Type::kIdMmx64 : typeName = "mmx64" ; break;
|
|
||||||
|
default:
|
||||||
|
typeName = "unknown";
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t baseSize = Type::sizeOf(baseId);
|
uint32_t baseSize = TypeUtils::sizeOf(scalarType);
|
||||||
if (typeSize > baseSize) {
|
if (typeSize > baseSize) {
|
||||||
uint32_t count = typeSize / baseSize;
|
uint32_t count = typeSize / baseSize;
|
||||||
return sb.appendFormat("%sx%u", typeName, unsigned(count));
|
return sb.appendFormat("%sx%u", typeName, unsigned(count));
|
||||||
@@ -117,7 +99,7 @@ Error formatTypeId(String& sb, uint32_t typeId) noexcept {
|
|||||||
|
|
||||||
Error formatFeature(
|
Error formatFeature(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t featureId) noexcept {
|
uint32_t featureId) noexcept {
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
@@ -135,7 +117,7 @@ Error formatFeature(
|
|||||||
|
|
||||||
Error formatLabel(
|
Error formatLabel(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t labelId) noexcept {
|
uint32_t labelId) noexcept {
|
||||||
|
|
||||||
@@ -159,6 +141,9 @@ Error formatLabel(
|
|||||||
|
|
||||||
ASMJIT_PROPAGATE(sb.append('.'));
|
ASMJIT_PROPAGATE(sb.append('.'));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (le->type() == LabelType::kAnonymous)
|
||||||
|
ASMJIT_PROPAGATE(sb.append("L%u@", labelId));
|
||||||
return sb.append(le->name());
|
return sb.append(le->name());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -168,10 +153,10 @@ Error formatLabel(
|
|||||||
|
|
||||||
Error formatRegister(
|
Error formatRegister(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t regType,
|
RegType regType,
|
||||||
uint32_t regId) noexcept {
|
uint32_t regId) noexcept {
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
@@ -189,9 +174,9 @@ Error formatRegister(
|
|||||||
|
|
||||||
Error formatOperand(
|
Error formatOperand(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
const Operand_& op) noexcept {
|
const Operand_& op) noexcept {
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
@@ -209,21 +194,21 @@ Error formatOperand(
|
|||||||
|
|
||||||
ASMJIT_API Error formatDataType(
|
ASMJIT_API Error formatDataType(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t typeId) noexcept
|
TypeId typeId) noexcept
|
||||||
{
|
{
|
||||||
DebugUtils::unused(formatFlags);
|
DebugUtils::unused(formatFlags);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
|
if (ASMJIT_UNLIKELY(uint32_t(arch) > uint32_t(Arch::kMaxValue)))
|
||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
uint32_t typeSize = Type::sizeOf(typeId);
|
uint32_t typeSize = TypeUtils::sizeOf(typeId);
|
||||||
if (typeSize == 0 || typeSize > 8)
|
if (typeSize == 0 || typeSize > 8)
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
||||||
return sb.append(wordNameTable[size_t(_archTraits[arch].isaWordNameId(typeSizeLog2))]);
|
return sb.append(wordNameTable[size_t(ArchTraits::byArch(arch).typeNameIdByIndex(typeSizeLog2))]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSize, const uint8_t* data, size_t itemCount) noexcept {
|
static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSize, const uint8_t* data, size_t itemCount) noexcept {
|
||||||
@@ -232,7 +217,7 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
|
|||||||
sb.append(' ');
|
sb.append(' ');
|
||||||
|
|
||||||
for (size_t i = 0; i < itemCount; i++) {
|
for (size_t i = 0; i < itemCount; i++) {
|
||||||
uint64_t v;
|
uint64_t v = 0;
|
||||||
|
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
ASMJIT_PROPAGATE(sb.append(", ", 2));
|
ASMJIT_PROPAGATE(sb.append(", ", 2));
|
||||||
@@ -244,7 +229,7 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
|
|||||||
case 8: v = Support::readU64u(data); break;
|
case 8: v = Support::readU64u(data); break;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, String::kFormatAlternate));
|
ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, StringFormatFlags::kAlternate));
|
||||||
data += typeSize;
|
data += typeSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -253,16 +238,16 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
|
|||||||
|
|
||||||
Error formatData(
|
Error formatData(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) noexcept
|
TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) noexcept
|
||||||
{
|
{
|
||||||
DebugUtils::unused(formatFlags);
|
DebugUtils::unused(formatFlags);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
|
if (ASMJIT_UNLIKELY(!Environment::isDefinedArch(arch)))
|
||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
uint32_t typeSize = Type::sizeOf(typeId);
|
uint32_t typeSize = TypeUtils::sizeOf(typeId);
|
||||||
if (typeSize == 0)
|
if (typeSize == 0)
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
@@ -277,7 +262,7 @@ Error formatData(
|
|||||||
}
|
}
|
||||||
|
|
||||||
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
uint32_t typeSizeLog2 = Support::ctz(typeSize);
|
||||||
const char* wordName = wordNameTable[size_t(_archTraits[arch].isaWordNameId(typeSizeLog2))];
|
const char* wordName = wordNameTable[size_t(ArchTraits::byArch(arch).typeNameIdByIndex(typeSizeLog2))];
|
||||||
|
|
||||||
if (repeatCount > 1)
|
if (repeatCount > 1)
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat(".repeat %zu ", repeatCount));
|
ASMJIT_PROPAGATE(sb.appendFormat(".repeat %zu ", repeatCount));
|
||||||
@@ -287,9 +272,9 @@ Error formatData(
|
|||||||
|
|
||||||
Error formatInstruction(
|
Error formatInstruction(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
|
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
@@ -308,8 +293,8 @@ Error formatInstruction(
|
|||||||
#ifndef ASMJIT_NO_BUILDER
|
#ifndef ASMJIT_NO_BUILDER
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
#ifndef ASMJIT_NO_COMPILER
|
||||||
static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept {
|
static Error formatFuncValue(String& sb, FormatFlags formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept {
|
||||||
uint32_t typeId = value.typeId();
|
TypeId typeId = value.typeId();
|
||||||
ASMJIT_PROPAGATE(formatTypeId(sb, typeId));
|
ASMJIT_PROPAGATE(formatTypeId(sb, typeId));
|
||||||
|
|
||||||
if (value.isAssigned()) {
|
if (value.isAssigned()) {
|
||||||
@@ -338,10 +323,10 @@ static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter
|
|||||||
|
|
||||||
static Error formatFuncValuePack(
|
static Error formatFuncValuePack(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseCompiler* cc,
|
||||||
const FuncValuePack& pack,
|
const FuncValuePack& pack,
|
||||||
VirtReg* const* vRegs) noexcept {
|
const RegOnly* vRegs) noexcept {
|
||||||
|
|
||||||
size_t count = pack.count();
|
size_t count = pack.count();
|
||||||
if (!count)
|
if (!count)
|
||||||
@@ -358,11 +343,16 @@ static Error formatFuncValuePack(
|
|||||||
if (valueIndex)
|
if (valueIndex)
|
||||||
ASMJIT_PROPAGATE(sb.append(", "));
|
ASMJIT_PROPAGATE(sb.append(", "));
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, value));
|
ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, cc, value));
|
||||||
|
|
||||||
if (vRegs) {
|
if (vRegs) {
|
||||||
static const char nullRet[] = "<none>";
|
const VirtReg* virtReg = nullptr;
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[valueIndex] ? vRegs[valueIndex]->name() : nullRet));
|
static const char nullReg[] = "<none>";
|
||||||
|
|
||||||
|
if (vRegs[valueIndex].isReg() && cc->isVirtIdValid(vRegs[valueIndex].id()))
|
||||||
|
virtReg = cc->virtRegById(vRegs[valueIndex].id());
|
||||||
|
|
||||||
|
ASMJIT_PROPAGATE(sb.appendFormat(" %s", virtReg ? virtReg->name() : nullReg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -374,17 +364,17 @@ static Error formatFuncValuePack(
|
|||||||
|
|
||||||
static Error formatFuncRets(
|
static Error formatFuncRets(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseCompiler* cc,
|
||||||
const FuncDetail& fd) noexcept {
|
const FuncDetail& fd) noexcept {
|
||||||
|
|
||||||
return formatFuncValuePack(sb, formatFlags, emitter, fd.retPack(), nullptr);
|
return formatFuncValuePack(sb, formatFlags, cc, fd.retPack(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Error formatFuncArgs(
|
static Error formatFuncArgs(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseCompiler* cc,
|
||||||
const FuncDetail& fd,
|
const FuncDetail& fd,
|
||||||
const FuncNode::ArgPack* argPacks) noexcept {
|
const FuncNode::ArgPack* argPacks) noexcept {
|
||||||
|
|
||||||
@@ -396,7 +386,7 @@ static Error formatFuncArgs(
|
|||||||
if (argIndex)
|
if (argIndex)
|
||||||
ASMJIT_PROPAGATE(sb.append(", "));
|
ASMJIT_PROPAGATE(sb.append(", "));
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(formatFuncValuePack(sb, formatFlags, emitter, fd.argPack(argIndex), argPacks[argIndex]._data));
|
ASMJIT_PROPAGATE(formatFuncValuePack(sb, formatFlags, cc, fd.argPack(argIndex), argPacks[argIndex]._data));
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -405,25 +395,26 @@ static Error formatFuncArgs(
|
|||||||
|
|
||||||
Error formatNode(
|
Error formatNode(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder,
|
const BaseBuilder* builder,
|
||||||
const BaseNode* node) noexcept {
|
const BaseNode* node) noexcept {
|
||||||
|
|
||||||
if (node->hasPosition() && (formatFlags & FormatOptions::kFlagPositions) != 0)
|
if (node->hasPosition() && formatOptions.hasFlag(FormatFlags::kPositions))
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node->position()));
|
ASMJIT_PROPAGATE(sb.appendFormat("<%05u> ", node->position()));
|
||||||
|
|
||||||
|
size_t startLineIndex = sb.size();
|
||||||
|
|
||||||
switch (node->type()) {
|
switch (node->type()) {
|
||||||
case BaseNode::kNodeInst:
|
case NodeType::kInst:
|
||||||
case BaseNode::kNodeJump: {
|
case NodeType::kJump: {
|
||||||
const InstNode* instNode = node->as<InstNode>();
|
const InstNode* instNode = node->as<InstNode>();
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(formatInstruction(sb, formatOptions.flags(), builder,
|
||||||
formatInstruction(sb, formatFlags, builder,
|
builder->arch(),
|
||||||
builder->arch(),
|
instNode->baseInst(), instNode->operands(), instNode->opCount()));
|
||||||
instNode->baseInst(), instNode->operands(), instNode->opCount()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeSection: {
|
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->id())) {
|
||||||
const Section* section = builder->_code->sectionById(sectionNode->id());
|
const Section* section = builder->_code->sectionById(sectionNode->id());
|
||||||
@@ -432,65 +423,64 @@ Error formatNode(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeLabel: {
|
case NodeType::kLabel: {
|
||||||
const LabelNode* labelNode = node->as<LabelNode>();
|
const LabelNode* labelNode = node->as<LabelNode>();
|
||||||
ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, labelNode->labelId()));
|
ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, labelNode->labelId()));
|
||||||
ASMJIT_PROPAGATE(sb.append(":"));
|
ASMJIT_PROPAGATE(sb.append(":"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeAlign: {
|
case NodeType::kAlign: {
|
||||||
const AlignNode* alignNode = node->as<AlignNode>();
|
const AlignNode* alignNode = node->as<AlignNode>();
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(sb.appendFormat(".align %u (%s)",
|
||||||
sb.appendFormat(".align %u (%s)",
|
alignNode->alignment(),
|
||||||
alignNode->alignment(),
|
alignNode->alignMode() == AlignMode::kCode ? "code" : "data"));
|
||||||
alignNode->alignMode() == kAlignCode ? "code" : "data"));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeEmbedData: {
|
case NodeType::kEmbedData: {
|
||||||
const EmbedDataNode* embedNode = node->as<EmbedDataNode>();
|
const EmbedDataNode* embedNode = node->as<EmbedDataNode>();
|
||||||
ASMJIT_PROPAGATE(sb.append('.'));
|
ASMJIT_PROPAGATE(sb.append('.'));
|
||||||
ASMJIT_PROPAGATE(formatDataType(sb, formatFlags, builder->arch(), embedNode->typeId()));
|
ASMJIT_PROPAGATE(formatDataType(sb, formatOptions.flags(), builder->arch(), embedNode->typeId()));
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat(" {Count=%zu Repeat=%zu TotalSize=%zu}", embedNode->itemCount(), embedNode->repeatCount(), embedNode->dataSize()));
|
ASMJIT_PROPAGATE(sb.appendFormat(" {Count=%zu Repeat=%zu TotalSize=%zu}", embedNode->itemCount(), embedNode->repeatCount(), embedNode->dataSize()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeEmbedLabel: {
|
case NodeType::kEmbedLabel: {
|
||||||
const EmbedLabelNode* embedNode = node->as<EmbedLabelNode>();
|
const EmbedLabelNode* embedNode = node->as<EmbedLabelNode>();
|
||||||
ASMJIT_PROPAGATE(sb.append(".label "));
|
ASMJIT_PROPAGATE(sb.append(".label "));
|
||||||
ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId()));
|
ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, embedNode->labelId()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeEmbedLabelDelta: {
|
case NodeType::kEmbedLabelDelta: {
|
||||||
const EmbedLabelDeltaNode* embedNode = node->as<EmbedLabelDeltaNode>();
|
const EmbedLabelDeltaNode* embedNode = node->as<EmbedLabelDeltaNode>();
|
||||||
ASMJIT_PROPAGATE(sb.append(".label ("));
|
ASMJIT_PROPAGATE(sb.append(".label ("));
|
||||||
ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId()));
|
ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, embedNode->labelId()));
|
||||||
ASMJIT_PROPAGATE(sb.append(" - "));
|
ASMJIT_PROPAGATE(sb.append(" - "));
|
||||||
ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->baseLabelId()));
|
ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, embedNode->baseLabelId()));
|
||||||
ASMJIT_PROPAGATE(sb.append(")"));
|
ASMJIT_PROPAGATE(sb.append(")"));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeConstPool: {
|
case NodeType::kConstPool: {
|
||||||
const ConstPoolNode* constPoolNode = node->as<ConstPoolNode>();
|
const ConstPoolNode* constPoolNode = node->as<ConstPoolNode>();
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("[ConstPool Size=%zu Alignment=%zu]", constPoolNode->size(), constPoolNode->alignment()));
|
ASMJIT_PROPAGATE(sb.appendFormat("[ConstPool Size=%zu Alignment=%zu]", constPoolNode->size(), constPoolNode->alignment()));
|
||||||
break;
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
case BaseNode::kNodeComment: {
|
case NodeType::kComment: {
|
||||||
const CommentNode* commentNode = node->as<CommentNode>();
|
const CommentNode* commentNode = node->as<CommentNode>();
|
||||||
ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment()));
|
ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment()));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeSentinel: {
|
case NodeType::kSentinel: {
|
||||||
const SentinelNode* sentinelNode = node->as<SentinelNode>();
|
const SentinelNode* sentinelNode = node->as<SentinelNode>();
|
||||||
const char* sentinelName = nullptr;
|
const char* sentinelName = nullptr;
|
||||||
|
|
||||||
switch (sentinelNode->sentinelType()) {
|
switch (sentinelNode->sentinelType()) {
|
||||||
case SentinelNode::kSentinelFuncEnd:
|
case SentinelType::kFuncEnd:
|
||||||
sentinelName = "[FuncEnd]";
|
sentinelName = "[FuncEnd]";
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@@ -504,20 +494,22 @@ Error formatNode(
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
#ifndef ASMJIT_NO_COMPILER
|
||||||
case BaseNode::kNodeFunc: {
|
case NodeType::kFunc: {
|
||||||
const FuncNode* funcNode = node->as<FuncNode>();
|
const FuncNode* funcNode = node->as<FuncNode>();
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, funcNode->labelId()));
|
if (builder->isCompiler()) {
|
||||||
ASMJIT_PROPAGATE(sb.append(": "));
|
ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, funcNode->labelId()));
|
||||||
|
ASMJIT_PROPAGATE(sb.append(": "));
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(formatFuncRets(sb, formatFlags, builder, funcNode->detail()));
|
ASMJIT_PROPAGATE(formatFuncRets(sb, formatOptions.flags(), static_cast<const BaseCompiler*>(builder), funcNode->detail()));
|
||||||
ASMJIT_PROPAGATE(sb.append(" Func("));
|
ASMJIT_PROPAGATE(sb.append(" Func("));
|
||||||
ASMJIT_PROPAGATE(formatFuncArgs(sb, formatFlags, builder, funcNode->detail(), funcNode->argPacks()));
|
ASMJIT_PROPAGATE(formatFuncArgs(sb, formatOptions.flags(), static_cast<const BaseCompiler*>(builder), funcNode->detail(), funcNode->argPacks()));
|
||||||
ASMJIT_PROPAGATE(sb.append(")"));
|
ASMJIT_PROPAGATE(sb.append(")"));
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeFuncRet: {
|
case NodeType::kFuncRet: {
|
||||||
const FuncRetNode* retNode = node->as<FuncRetNode>();
|
const FuncRetNode* retNode = node->as<FuncRetNode>();
|
||||||
ASMJIT_PROPAGATE(sb.append("[FuncRet]"));
|
ASMJIT_PROPAGATE(sb.append("[FuncRet]"));
|
||||||
|
|
||||||
@@ -525,18 +517,17 @@ Error formatNode(
|
|||||||
const Operand_& op = retNode->_opArray[i];
|
const Operand_& op = retNode->_opArray[i];
|
||||||
if (!op.isNone()) {
|
if (!op.isNone()) {
|
||||||
ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
|
ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
|
||||||
ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, builder, builder->arch(), op));
|
ASMJIT_PROPAGATE(formatOperand(sb, formatOptions.flags(), builder, builder->arch(), op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case BaseNode::kNodeInvoke: {
|
case NodeType::kInvoke: {
|
||||||
const InvokeNode* invokeNode = node->as<InvokeNode>();
|
const InvokeNode* invokeNode = node->as<InvokeNode>();
|
||||||
ASMJIT_PROPAGATE(
|
ASMJIT_PROPAGATE(formatInstruction(sb, formatOptions.flags(), builder,
|
||||||
formatInstruction(sb, formatFlags, builder,
|
builder->arch(),
|
||||||
builder->arch(),
|
invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount()));
|
||||||
invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount()));
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@@ -547,28 +538,38 @@ Error formatNode(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (node->hasInlineComment()) {
|
||||||
|
size_t requiredPadding = paddingFromOptions(formatOptions, FormatPaddingGroup::kRegularLine);
|
||||||
|
size_t currentPadding = sb.size() - startLineIndex;
|
||||||
|
|
||||||
|
if (currentPadding < requiredPadding)
|
||||||
|
ASMJIT_PROPAGATE(sb.appendChars(' ', requiredPadding - currentPadding));
|
||||||
|
|
||||||
|
ASMJIT_PROPAGATE(sb.append("; "));
|
||||||
|
ASMJIT_PROPAGATE(sb.append(node->inlineComment()));
|
||||||
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error formatNodeList(
|
Error formatNodeList(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder) noexcept {
|
const BaseBuilder* builder) noexcept {
|
||||||
|
|
||||||
return formatNodeList(sb, formatFlags, builder, builder->firstNode(), nullptr);
|
return formatNodeList(sb, formatOptions, builder, builder->firstNode(), nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error formatNodeList(
|
Error formatNodeList(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder,
|
const BaseBuilder* builder,
|
||||||
const BaseNode* begin,
|
const BaseNode* begin,
|
||||||
const BaseNode* end) noexcept {
|
const BaseNode* end) noexcept {
|
||||||
|
|
||||||
const BaseNode* node = begin;
|
const BaseNode* node = begin;
|
||||||
while (node != end) {
|
while (node != end) {
|
||||||
ASMJIT_PROPAGATE(formatNode(sb, formatFlags, builder, node));
|
ASMJIT_PROPAGATE(formatNode(sb, formatOptions, builder, node));
|
||||||
ASMJIT_PROPAGATE(sb.append('\n'));
|
ASMJIT_PROPAGATE(sb.append('\n'));
|
||||||
node = node->next();
|
node = node->next();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,126 +1,98 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED
|
#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED
|
||||||
#define ASMJIT_CORE_FORMATTER_H_INCLUDED
|
#define ASMJIT_CORE_FORMATTER_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../core/globals.h"
|
||||||
#include "../core/inst.h"
|
#include "../core/inst.h"
|
||||||
#include "../core/string.h"
|
#include "../core/string.h"
|
||||||
|
#include "../core/support.h"
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//! \addtogroup asmjit_logging
|
//! \addtogroup asmjit_logging
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
class BaseBuilder;
|
||||||
// [Forward Declarations]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class BaseEmitter;
|
class BaseEmitter;
|
||||||
|
class BaseNode;
|
||||||
struct Operand_;
|
struct Operand_;
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_BUILDER
|
//! Format flags used by \ref Logger and \ref FormatOptions.
|
||||||
class BaseBuilder;
|
enum class FormatFlags : uint32_t {
|
||||||
class BaseNode;
|
//! No formatting flags.
|
||||||
#endif
|
kNone = 0u,
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
//! Show also binary form of each logged instruction (Assembler).
|
||||||
class BaseCompiler;
|
kMachineCode = 0x00000001u,
|
||||||
#endif
|
//! Show a text explanation of some immediate values.
|
||||||
|
kExplainImms = 0x00000002u,
|
||||||
|
//! Use hexadecimal notation of immediate values.
|
||||||
|
kHexImms = 0x00000004u,
|
||||||
|
//! Use hexadecimal notation of addresses and offsets in addresses.
|
||||||
|
kHexOffsets = 0x00000008u,
|
||||||
|
//! Show casts between virtual register types (Compiler output).
|
||||||
|
kRegCasts = 0x00000010u,
|
||||||
|
//! Show positions associated with nodes (Compiler output).
|
||||||
|
kPositions = 0x00000020u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(FormatFlags)
|
||||||
|
|
||||||
// ============================================================================
|
//! Format indentation group, used by \ref FormatOptions.
|
||||||
// [asmjit::FormatOptions]
|
enum class FormatIndentationGroup : uint32_t {
|
||||||
// ============================================================================
|
//! Indentation used for instructions and directives.
|
||||||
|
kCode = 0u,
|
||||||
|
//! Indentation used for labels and function nodes.
|
||||||
|
kLabel = 1u,
|
||||||
|
//! Indentation used for comments (not inline comments).
|
||||||
|
kComment = 2u,
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
//! Reserved for future use.
|
||||||
|
kReserved = 3u,
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
|
//! Maximum value of `FormatIndentationGroup`.
|
||||||
|
kMaxValue = kReserved
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Format padding group, used by \ref FormatOptions.
|
||||||
|
enum class FormatPaddingGroup : uint32_t {
|
||||||
|
//! Describes padding of a regular line, which can represent instruction, data, or assembler directives.
|
||||||
|
kRegularLine = 0,
|
||||||
|
//! Describes padding of machine code dump that is visible next to the instruction, if enabled.
|
||||||
|
kMachineCode = 1,
|
||||||
|
|
||||||
|
//! Maximum value of `FormatPaddingGroup`.
|
||||||
|
kMaxValue = kMachineCode
|
||||||
|
};
|
||||||
|
|
||||||
//! Formatting options used by \ref Logger and \ref Formatter.
|
//! Formatting options used by \ref Logger and \ref Formatter.
|
||||||
class FormatOptions {
|
class FormatOptions {
|
||||||
public:
|
public:
|
||||||
//! Format flags, see \ref Flags.
|
//! \name Members
|
||||||
uint32_t _flags;
|
|
||||||
//! Indentation by type, see \ref IndentationType.
|
|
||||||
uint8_t _indentation[4];
|
|
||||||
|
|
||||||
//! Flags can enable a logging feature.
|
|
||||||
enum Flags : uint32_t {
|
|
||||||
//! No flags.
|
|
||||||
kNoFlags = 0u,
|
|
||||||
|
|
||||||
//! Show also binary form of each logged instruction (Assembler).
|
|
||||||
kFlagMachineCode = 0x00000001u,
|
|
||||||
//! Show a text explanation of some immediate values.
|
|
||||||
kFlagExplainImms = 0x00000002u,
|
|
||||||
//! Use hexadecimal notation of immediate values.
|
|
||||||
kFlagHexImms = 0x00000004u,
|
|
||||||
//! Use hexadecimal notation of address offsets.
|
|
||||||
kFlagHexOffsets = 0x00000008u,
|
|
||||||
//! Show casts between virtual register types (Compiler).
|
|
||||||
kFlagRegCasts = 0x00000010u,
|
|
||||||
//! Show positions associated with nodes (Compiler).
|
|
||||||
kFlagPositions = 0x00000020u,
|
|
||||||
//! Annotate nodes that are lowered by passes.
|
|
||||||
kFlagAnnotations = 0x00000040u,
|
|
||||||
|
|
||||||
// TODO: These must go, keep this only for formatting.
|
|
||||||
//! Show an additional output from passes.
|
|
||||||
kFlagDebugPasses = 0x00000080u,
|
|
||||||
//! Show an additional output from RA.
|
|
||||||
kFlagDebugRA = 0x00000100u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Describes indentation type of code, label, or comment in logger output.
|
|
||||||
enum IndentationType : uint32_t {
|
|
||||||
//! Indentation used for instructions and directives.
|
|
||||||
kIndentationCode = 0u,
|
|
||||||
//! Indentation used for labels and function nodes.
|
|
||||||
kIndentationLabel = 1u,
|
|
||||||
//! Indentation used for comments (not inline comments).
|
|
||||||
kIndentationComment = 2u,
|
|
||||||
//! \cond INTERNAL
|
|
||||||
//! Reserved for future use.
|
|
||||||
kIndentationReserved = 3u
|
|
||||||
//! \endcond
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a default-initialized FormatOptions.
|
//! Format flags.
|
||||||
constexpr FormatOptions() noexcept
|
FormatFlags _flags = FormatFlags::kNone;
|
||||||
: _flags(0),
|
//! Indentations for each indentation group.
|
||||||
_indentation { 0, 0, 0, 0 } {}
|
Support::Array<uint8_t, uint32_t(FormatIndentationGroup::kMaxValue) + 1> _indentation {};
|
||||||
|
//! Paddings for each padding group.
|
||||||
|
Support::Array<uint16_t, uint32_t(FormatPaddingGroup::kMaxValue) + 1> _padding {};
|
||||||
|
|
||||||
constexpr FormatOptions(const FormatOptions& other) noexcept = default;
|
//! \}
|
||||||
inline FormatOptions& operator=(const FormatOptions& other) noexcept = default;
|
|
||||||
|
//! \name Reset
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Resets FormatOptions to its default initialized state.
|
//! Resets FormatOptions to its default initialized state.
|
||||||
inline void reset() noexcept {
|
inline void reset() noexcept {
|
||||||
_flags = 0;
|
_flags = FormatFlags::kNone;
|
||||||
_indentation[0] = 0;
|
_indentation.fill(uint8_t(0));
|
||||||
_indentation[1] = 0;
|
_padding.fill(uint16_t(0));
|
||||||
_indentation[2] = 0;
|
|
||||||
_indentation[3] = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -129,104 +101,109 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns format flags.
|
//! Returns format flags.
|
||||||
constexpr uint32_t flags() const noexcept { return _flags; }
|
inline FormatFlags flags() const noexcept { return _flags; }
|
||||||
//! Tests whether the given `flag` is set in format flags.
|
//! Tests whether the given `flag` is set in format flags.
|
||||||
constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
|
inline bool hasFlag(FormatFlags flag) const noexcept { return Support::test(_flags, flag); }
|
||||||
//! Resets all format flags to `flags`.
|
|
||||||
inline void setFlags(uint32_t flags) noexcept { _flags = flags; }
|
|
||||||
//! Adds `flags` to format flags.
|
|
||||||
inline void addFlags(uint32_t flags) noexcept { _flags |= flags; }
|
|
||||||
//! Removes `flags` from format flags.
|
|
||||||
inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
|
|
||||||
|
|
||||||
//! Returns indentation for the given `type`, see \ref IndentationType.
|
//! Resets all format flags to `flags`.
|
||||||
constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; }
|
inline void setFlags(FormatFlags flags) noexcept { _flags = flags; }
|
||||||
//! Sets indentation for the given `type`, see \ref IndentationType.
|
//! Adds `flags` to format flags.
|
||||||
inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); }
|
inline void addFlags(FormatFlags flags) noexcept { _flags |= flags; }
|
||||||
//! Resets indentation for the given `type` to zero.
|
//! Removes `flags` from format flags.
|
||||||
inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); }
|
inline void clearFlags(FormatFlags flags) noexcept { _flags &= ~flags; }
|
||||||
|
|
||||||
|
//! Returns indentation for the given indentation `group`.
|
||||||
|
inline uint8_t indentation(FormatIndentationGroup group) const noexcept { return _indentation[group]; }
|
||||||
|
//! Sets indentation for the given indentation `group`.
|
||||||
|
inline void setIndentation(FormatIndentationGroup group, uint32_t n) noexcept { _indentation[group] = uint8_t(n); }
|
||||||
|
//! Resets indentation for the given indentation `group` to zero.
|
||||||
|
inline void resetIndentation(FormatIndentationGroup group) noexcept { _indentation[group] = uint8_t(0); }
|
||||||
|
|
||||||
|
//! Returns pading for the given padding `group`.
|
||||||
|
inline size_t padding(FormatPaddingGroup group) const noexcept { return _padding[group]; }
|
||||||
|
//! Sets pading for the given padding `group`.
|
||||||
|
inline void setPadding(FormatPaddingGroup group, size_t n) noexcept { _padding[group] = uint16_t(n); }
|
||||||
|
//! Resets pading for the given padding `group` to zero, which means that a default padding will be used
|
||||||
|
//! based on the target architecture properties.
|
||||||
|
inline void resetPadding(FormatPaddingGroup group) noexcept { _padding[group] = uint16_t(0); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Formatter]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Provides formatting functionality to format operands, instructions, and nodes.
|
//! Provides formatting functionality to format operands, instructions, and nodes.
|
||||||
namespace Formatter {
|
namespace Formatter {
|
||||||
|
|
||||||
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
|
|
||||||
//! Appends a formatted `typeId` to the output string `sb`.
|
//! Appends a formatted `typeId` to the output string `sb`.
|
||||||
ASMJIT_API Error formatTypeId(
|
ASMJIT_API Error formatTypeId(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t typeId) noexcept;
|
TypeId typeId) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted `featureId` to the output string `sb`.
|
//! Appends a formatted `featureId` to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! See \ref BaseFeatures.
|
//! See \ref CpuFeatures.
|
||||||
ASMJIT_API Error formatFeature(
|
ASMJIT_API Error formatFeature(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t featureId) noexcept;
|
uint32_t featureId) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted register to the output string `sb`.
|
//! Appends a formatted register to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! \note Emitter is optional, but it's required to format virtual registers,
|
//! \note Emitter is optional, but it's required to format virtual registers, which won't be formatted properly
|
||||||
//! which won't be formatted properly if the `emitter` is not provided.
|
//! if the `emitter` is not provided.
|
||||||
ASMJIT_API Error formatRegister(
|
ASMJIT_API Error formatRegister(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t regType,
|
RegType regType,
|
||||||
uint32_t regId) noexcept;
|
uint32_t regId) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted label to the output string `sb`.
|
//! Appends a formatted label to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! \note Emitter is optional, but it's required to format named labels
|
//! \note Emitter is optional, but it's required to format named labels properly, otherwise the formatted as
|
||||||
//! properly, otherwise the formatted as it is an anonymous label.
|
//! it is an anonymous label.
|
||||||
ASMJIT_API Error formatLabel(
|
ASMJIT_API Error formatLabel(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t labelId) noexcept;
|
uint32_t labelId) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted operand to the output string `sb`.
|
//! Appends a formatted operand to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! \note Emitter is optional, but it's required to format named labels and
|
//! \note Emitter is optional, but it's required to format named labels and virtual registers. See
|
||||||
//! virtual registers. See \ref formatRegister() and \ref formatLabel() for
|
//! \ref formatRegister() and \ref formatLabel() for more details.
|
||||||
//! more details.
|
|
||||||
ASMJIT_API Error formatOperand(
|
ASMJIT_API Error formatOperand(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
const Operand_& op) noexcept;
|
const Operand_& op) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted data-type to the output string `sb`.
|
//! Appends a formatted data-type to the output string `sb`.
|
||||||
ASMJIT_API Error formatDataType(
|
ASMJIT_API Error formatDataType(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t typeId) noexcept;
|
TypeId typeId) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted data to the output string `sb`.
|
//! Appends a formatted data to the output string `sb`.
|
||||||
ASMJIT_API Error formatData(
|
ASMJIT_API Error formatData(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) noexcept;
|
TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) noexcept;
|
||||||
|
|
||||||
//! Appends a formatted instruction to the output string `sb`.
|
//! Appends a formatted instruction to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! \note Emitter is optional, but it's required to format named labels and
|
//! \note Emitter is optional, but it's required to format named labels and virtual registers. See
|
||||||
//! virtual registers. See \ref formatRegister() and \ref formatLabel() for
|
//! \ref formatRegister() and \ref formatLabel() for more details.
|
||||||
//! more details.
|
|
||||||
ASMJIT_API Error formatInstruction(
|
ASMJIT_API Error formatInstruction(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
FormatFlags formatFlags,
|
||||||
const BaseEmitter* emitter,
|
const BaseEmitter* emitter,
|
||||||
uint32_t arch,
|
Arch arch,
|
||||||
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept;
|
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept;
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_BUILDER
|
#ifndef ASMJIT_NO_BUILDER
|
||||||
@@ -235,7 +212,7 @@ ASMJIT_API Error formatInstruction(
|
|||||||
//! The `node` must belong to the provided `builder`.
|
//! The `node` must belong to the provided `builder`.
|
||||||
ASMJIT_API Error formatNode(
|
ASMJIT_API Error formatNode(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder,
|
const BaseBuilder* builder,
|
||||||
const BaseNode* node) noexcept;
|
const BaseNode* node) noexcept;
|
||||||
|
|
||||||
@@ -244,27 +221,27 @@ ASMJIT_API Error formatNode(
|
|||||||
//! All nodes that are part of the given `builder` will be appended.
|
//! All nodes that are part of the given `builder` will be appended.
|
||||||
ASMJIT_API Error formatNodeList(
|
ASMJIT_API Error formatNodeList(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder) noexcept;
|
const BaseBuilder* builder) noexcept;
|
||||||
|
|
||||||
//! Appends formatted nodes to the output string `sb`.
|
//! Appends formatted nodes to the output string `sb`.
|
||||||
//!
|
//!
|
||||||
//! This function works the same as \ref formatNode(), but appends more nodes
|
//! This function works the same as \ref formatNode(), but appends more nodes to the output string,
|
||||||
//! to the output string, separating each node with a newline '\n' character.
|
//! separating each node with a newline '\n' character.
|
||||||
ASMJIT_API Error formatNodeList(
|
ASMJIT_API Error formatNodeList(
|
||||||
String& sb,
|
String& sb,
|
||||||
uint32_t formatFlags,
|
const FormatOptions& formatOptions,
|
||||||
const BaseBuilder* builder,
|
const BaseBuilder* builder,
|
||||||
const BaseNode* begin,
|
const BaseNode* begin,
|
||||||
const BaseNode* end) noexcept;
|
const BaseNode* end) noexcept;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
} // {Formatter}
|
} // {Formatter}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED
|
#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED
|
||||||
|
|||||||
34
src/asmjit/core/formatter_p.h
Normal file
34
src/asmjit/core/formatter_p.h
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
// 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_CORE_FORMATTER_P_H_INCLUDED
|
||||||
|
#define ASMJIT_CORE_FORMATTER_P_H_INCLUDED
|
||||||
|
|
||||||
|
#include "../core/formatter.h"
|
||||||
|
|
||||||
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
//! \addtogroup asmjit_logging
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
namespace Formatter {
|
||||||
|
|
||||||
|
static ASMJIT_FORCE_INLINE size_t paddingFromOptions(const FormatOptions& formatOptions, FormatPaddingGroup group) noexcept {
|
||||||
|
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");
|
||||||
|
|
||||||
|
size_t padding = formatOptions.padding(group);
|
||||||
|
return padding ? padding : size_t(_defaultPaddingTable[uint32_t(group)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // {Formatter}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif // ASMJIT_CORE_FORMATTER_H_P_INCLUDED
|
||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/archtraits.h"
|
#include "../core/archtraits.h"
|
||||||
@@ -38,11 +20,10 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// CallConv - Init & Reset
|
||||||
// [asmjit::CallConv - Init / Reset]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId, const Environment& environment) noexcept {
|
ASMJIT_FAVOR_SIZE Error CallConv::init(CallConvId ccId, const Environment& environment) noexcept {
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
@@ -58,12 +39,11 @@ ASMJIT_FAVOR_SIZE Error CallConv::init(uint32_t ccId, const Environment& environ
|
|||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// FuncDetail - Init / Reset
|
||||||
// [asmjit::FuncDetail - Init / Reset]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const Environment& environment) noexcept {
|
||||||
uint32_t ccId = signature.callConv();
|
CallConvId ccId = signature.callConvId();
|
||||||
uint32_t argCount = signature.argCount();
|
uint32_t argCount = signature.argCount();
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs))
|
if (ASMJIT_UNLIKELY(argCount > Globals::kMaxFuncArgs))
|
||||||
@@ -73,19 +53,20 @@ ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const E
|
|||||||
ASMJIT_PROPAGATE(cc.init(ccId, environment));
|
ASMJIT_PROPAGATE(cc.init(ccId, environment));
|
||||||
|
|
||||||
uint32_t registerSize = Environment::registerSizeFromArch(cc.arch());
|
uint32_t registerSize = Environment::registerSizeFromArch(cc.arch());
|
||||||
uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize);
|
uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize);
|
||||||
|
|
||||||
const uint8_t* signatureArgs = signature.args();
|
const TypeId* signatureArgs = signature.args();
|
||||||
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
|
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
|
||||||
FuncValuePack& argPack = _args[argIndex];
|
FuncValuePack& argPack = _args[argIndex];
|
||||||
argPack[0].initTypeId(Type::deabstract(signatureArgs[argIndex], deabstractDelta));
|
argPack[0].initTypeId(TypeUtils::deabstract(signatureArgs[argIndex], deabstractDelta));
|
||||||
}
|
}
|
||||||
|
|
||||||
_argCount = uint8_t(argCount);
|
_argCount = uint8_t(argCount);
|
||||||
_vaIndex = uint8_t(signature.vaIndex());
|
_vaIndex = uint8_t(signature.vaIndex());
|
||||||
|
|
||||||
uint32_t ret = signature.ret();
|
TypeId ret = signature.ret();
|
||||||
if (ret != Type::kIdVoid)
|
if (ret != TypeId::kVoid)
|
||||||
_rets[0].initTypeId(Type::deabstract(ret, deabstractDelta));
|
_rets[0].initTypeId(TypeUtils::deabstract(ret, deabstractDelta));
|
||||||
|
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
if (environment.isFamilyX86())
|
if (environment.isFamilyX86())
|
||||||
@@ -97,28 +78,26 @@ ASMJIT_FAVOR_SIZE Error FuncDetail::init(const FuncSignature& signature, const E
|
|||||||
return arm::FuncInternal::initFuncDetail(*this, signature, registerSize);
|
return arm::FuncInternal::initFuncDetail(*this, signature, registerSize);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// We should never bubble here as if `cc.init()` succeeded then there has to
|
// We should never bubble here as if `cc.init()` succeeded then there has to be an implementation for the current
|
||||||
// be an implementation for the current architecture. However, stay safe.
|
// architecture. However, stay safe.
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// FuncFrame - Init
|
||||||
// [asmjit::FuncFrame - Init / Finalize]
|
// ================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept {
|
||||||
uint32_t arch = func.callConv().arch();
|
Arch arch = func.callConv().arch();
|
||||||
if (!Environment::isValidArch(arch))
|
if (!Environment::isValidArch(arch))
|
||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
||||||
|
|
||||||
// Initializing FuncFrame means making a copy of some properties of `func`.
|
// Initializing FuncFrame means making a copy of some properties of `func`. Properties like `_localStackSize` will
|
||||||
// Properties like `_localStackSize` will be set by the user before the frame
|
// be set by the user before the frame is finalized.
|
||||||
// is finalized.
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
_arch = uint8_t(arch);
|
_arch = arch;
|
||||||
_spRegId = uint8_t(archTraits.spRegId());
|
_spRegId = uint8_t(archTraits.spRegId());
|
||||||
_saRegId = uint8_t(BaseReg::kIdBad);
|
_saRegId = uint8_t(BaseReg::kIdBad);
|
||||||
|
|
||||||
@@ -134,34 +113,37 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::init(const FuncDetail& func) noexcept {
|
|||||||
_spillZoneSize = uint8_t(func.spillZoneSize());
|
_spillZoneSize = uint8_t(func.spillZoneSize());
|
||||||
_finalStackAlignment = uint8_t(_naturalStackAlignment);
|
_finalStackAlignment = uint8_t(_naturalStackAlignment);
|
||||||
|
|
||||||
if (func.hasFlag(CallConv::kFlagCalleePopsStack)) {
|
if (func.hasFlag(CallConvFlags::kCalleePopsStack)) {
|
||||||
_calleeStackCleanup = uint16_t(func.argStackSize());
|
_calleeStackCleanup = uint16_t(func.argStackSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initial masks of dirty and preserved registers.
|
// Initial masks of dirty and preserved registers.
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
_dirtyRegs[group] = func.usedRegs(group);
|
_dirtyRegs[group] = func.usedRegs(group);
|
||||||
_preservedRegs[group] = func.preservedRegs(group);
|
_preservedRegs[group] = func.preservedRegs(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exclude stack pointer - this register is never included in saved GP regs.
|
// Exclude stack pointer - this register is never included in saved GP regs.
|
||||||
_preservedRegs[BaseReg::kGroupGp] &= ~Support::bitMask(archTraits.spRegId());
|
_preservedRegs[RegGroup::kGp] &= ~Support::bitMask(archTraits.spRegId());
|
||||||
|
|
||||||
// The size and alignment of save/restore area of registers for each significant register group.
|
// The size and alignment of save/restore area of registers for each virtual register group
|
||||||
memcpy(_saveRestoreRegSize, func.callConv()._saveRestoreRegSize, sizeof(_saveRestoreRegSize));
|
_saveRestoreRegSize = func.callConv()._saveRestoreRegSize;
|
||||||
memcpy(_saveRestoreAlignment, func.callConv()._saveRestoreAlignment, sizeof(_saveRestoreAlignment));
|
_saveRestoreAlignment = func.callConv()._saveRestoreAlignment;
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FuncFrame - Finalize
|
||||||
|
// ====================
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
||||||
if (!Environment::isValidArch(arch()))
|
if (!Environment::isValidArch(arch()))
|
||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch());
|
const ArchTraits& archTraits = ArchTraits::byArch(arch());
|
||||||
|
|
||||||
uint32_t registerSize = _saveRestoreRegSize[BaseReg::kGroupGp];
|
uint32_t registerSize = _saveRestoreRegSize[RegGroup::kGp];
|
||||||
uint32_t vectorSize = _saveRestoreRegSize[BaseReg::kGroupVec];
|
uint32_t vectorSize = _saveRestoreRegSize[RegGroup::kVec];
|
||||||
uint32_t returnAddressSize = archTraits.hasLinkReg() ? 0u : registerSize;
|
uint32_t returnAddressSize = archTraits.hasLinkReg() ? 0u : registerSize;
|
||||||
|
|
||||||
// The final stack alignment must be updated accordingly to call and local stack alignments.
|
// The final stack alignment must be updated accordingly to call and local stack alignments.
|
||||||
@@ -179,12 +161,12 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
|
|
||||||
// Make frame pointer dirty if the function uses it.
|
// Make frame pointer dirty if the function uses it.
|
||||||
if (hasFP) {
|
if (hasFP) {
|
||||||
_dirtyRegs[BaseReg::kGroupGp] |= Support::bitMask(kFp);
|
_dirtyRegs[RegGroup::kGp] |= Support::bitMask(kFp);
|
||||||
|
|
||||||
// Currently required by ARM, if this works differently across architectures
|
// Currently required by ARM, if this works differently across architectures we would have to generalize most
|
||||||
// we would have to generalize most likely in CallConv.
|
// likely in CallConv.
|
||||||
if (kLr != BaseReg::kIdBad)
|
if (kLr != BaseReg::kIdBad)
|
||||||
_dirtyRegs[BaseReg::kGroupGp] |= 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.
|
||||||
@@ -192,22 +174,22 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
if (saRegId == BaseReg::kIdBad)
|
if (saRegId == BaseReg::kIdBad)
|
||||||
saRegId = kSp;
|
saRegId = kSp;
|
||||||
|
|
||||||
// Fix stack arguments base-register from SP to FP in case it was not picked
|
// Fix stack arguments base-register from SP to FP in case it was not picked before and the function performs
|
||||||
// before and the function performs dynamic stack alignment.
|
// dynamic stack alignment.
|
||||||
if (hasDA && saRegId == kSp)
|
if (hasDA && saRegId == kSp)
|
||||||
saRegId = kFp;
|
saRegId = kFp;
|
||||||
|
|
||||||
// Mark as dirty any register but SP if used as SA pointer.
|
// Mark as dirty any register but SP if used as SA pointer.
|
||||||
if (saRegId != kSp)
|
if (saRegId != kSp)
|
||||||
_dirtyRegs[BaseReg::kGroupGp] |= Support::bitMask(saRegId);
|
_dirtyRegs[RegGroup::kGp] |= Support::bitMask(saRegId);
|
||||||
|
|
||||||
_spRegId = uint8_t(kSp);
|
_spRegId = uint8_t(kSp);
|
||||||
_saRegId = uint8_t(saRegId);
|
_saRegId = uint8_t(saRegId);
|
||||||
|
|
||||||
// Setup stack size used to save preserved registers.
|
// Setup stack size used to save preserved registers.
|
||||||
uint32_t saveRestoreSizes[2] {};
|
uint32_t saveRestoreSizes[2] {};
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++)
|
for (RegGroup group : RegGroupVirtValues{})
|
||||||
saveRestoreSizes[size_t(!archTraits.hasPushPop(group))]
|
saveRestoreSizes[size_t(!archTraits.hasInstPushPop(group))]
|
||||||
+= Support::alignUp(Support::popcnt(savedRegs(group)) * saveRestoreRegSize(group), saveRestoreAlignment(group));
|
+= Support::alignUp(Support::popcnt(savedRegs(group)) * saveRestoreRegSize(group), saveRestoreAlignment(group));
|
||||||
|
|
||||||
_pushPopSaveSize = uint16_t(saveRestoreSizes[0]);
|
_pushPopSaveSize = uint16_t(saveRestoreSizes[0]);
|
||||||
@@ -220,11 +202,10 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
_localStackOffset = v; // Store 'localStackOffset' <- Function's local stack starts here.
|
_localStackOffset = v; // Store 'localStackOffset' <- Function's local stack starts here.
|
||||||
v += localStackSize(); // Count 'localStackSize' <- Function's local stack ends here.
|
v += localStackSize(); // Count 'localStackSize' <- Function's local stack ends here.
|
||||||
|
|
||||||
// If the function's stack must be aligned, calculate the alignment necessary
|
// If the function's stack must be aligned, calculate the alignment necessary to store vector registers, and set
|
||||||
// to store vector registers, and set `FuncFrame::kAttrAlignedVecSR` to inform
|
// `FuncAttributes::kAlignedVecSR` to inform PEI that it can use instructions that perform aligned stores/loads.
|
||||||
// PEI that it can use instructions that perform aligned stores/loads.
|
|
||||||
if (stackAlignment >= vectorSize && _extraRegSaveSize) {
|
if (stackAlignment >= vectorSize && _extraRegSaveSize) {
|
||||||
addAttributes(FuncFrame::kAttrAlignedVecSR);
|
addAttributes(FuncAttributes::kAlignedVecSR);
|
||||||
v = Support::alignUp(v, vectorSize); // Align 'extraRegSaveOffset'.
|
v = Support::alignUp(v, vectorSize); // Align 'extraRegSaveOffset'.
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,23 +224,19 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
// Link Register
|
// Link Register
|
||||||
// -------------
|
// -------------
|
||||||
//
|
//
|
||||||
// The stack is aligned after the function call as the return address is
|
// The stack is aligned after the function call as the return address is stored in a link register. Some
|
||||||
// stored in a link register. Some architectures may require to always
|
// architectures may require to always have aligned stack after PUSH/POP operation, which is represented
|
||||||
// have aligned stack after PUSH/POP operation, which is represented by
|
// by ArchTraits::stackAlignmentConstraint().
|
||||||
// ArchTraits::stackAlignmentConstraint().
|
|
||||||
//
|
//
|
||||||
// No Link Register (X86/X64)
|
// No Link Register (X86/X64)
|
||||||
// --------------------------
|
// --------------------------
|
||||||
//
|
//
|
||||||
// The return address should be stored after GP save/restore regs. It has
|
// The return address should be stored after GP save/restore regs. It has the same size as `registerSize`
|
||||||
// the same size as `registerSize` (basically the native register/pointer
|
// (basically the native register/pointer size). We don't adjust it now as `v` now contains the exact size
|
||||||
// size). We don't adjust it now as `v` now contains the exact size that the
|
// that the function requires to adjust (call frame + stack frame, vec stack size). The stack (if we consider
|
||||||
// function requires to adjust (call frame + stack frame, vec stack size).
|
// this size) is misaligned now, as it's always aligned before the function call - when `call()` is executed
|
||||||
// The stack (if we consider this size) is misaligned now, as it's always
|
// it pushes the current EIP|RIP onto the stack, and misaligns it by 12 or 8 bytes (depending on the
|
||||||
// aligned before the function call - when `call()` is executed it pushes
|
// architecture). So count number of bytes needed to align it up to the function's CallFrame (the beginning).
|
||||||
// the current EIP|RIP onto the stack, and misaligns it by 12 or 8 bytes
|
|
||||||
// (depending on the architecture). So count number of bytes needed to align
|
|
||||||
// it up to the function's CallFrame (the beginning).
|
|
||||||
if (v || hasFuncCalls() || !returnAddressSize)
|
if (v || hasFuncCalls() || !returnAddressSize)
|
||||||
v += Support::alignUpDiff(v + pushPopSaveSize() + returnAddressSize, stackAlignment);
|
v += Support::alignUpDiff(v + pushPopSaveSize() + returnAddressSize, stackAlignment);
|
||||||
|
|
||||||
@@ -285,12 +262,11 @@ ASMJIT_FAVOR_SIZE Error FuncFrame::finalize() noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// FuncArgsAssignment - UpdateFuncFrame
|
||||||
// [asmjit::FuncArgsAssignment]
|
// ====================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncArgsAssignment::updateFuncFrame(FuncFrame& frame) const noexcept {
|
||||||
uint32_t arch = frame.arch();
|
Arch arch = frame.arch();
|
||||||
const FuncDetail* func = funcDetail();
|
const FuncDetail* func = funcDetail();
|
||||||
|
|
||||||
if (!func)
|
if (!func)
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/funcargscontext_p.h"
|
#include "../core/funcargscontext_p.h"
|
||||||
@@ -31,29 +13,24 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
FuncArgsContext::FuncArgsContext() noexcept {
|
FuncArgsContext::FuncArgsContext() noexcept {
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++)
|
for (RegGroup group : RegGroupVirtValues{})
|
||||||
_workData[group].reset();
|
_workData[size_t(group)].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args, const RAConstraints* constraints) noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, const FuncArgsAssignment& args, const RAConstraints* constraints) noexcept {
|
||||||
// The code has to be updated if this changes.
|
Arch arch = frame.arch();
|
||||||
ASMJIT_ASSERT(BaseReg::kGroupVirt == 4);
|
|
||||||
|
|
||||||
uint32_t i;
|
|
||||||
|
|
||||||
uint32_t arch = frame.arch();
|
|
||||||
const FuncDetail& func = *args.funcDetail();
|
const FuncDetail& func = *args.funcDetail();
|
||||||
|
|
||||||
_archTraits = &ArchTraits::byArch(arch);
|
_archTraits = &ArchTraits::byArch(arch);
|
||||||
_constraints = constraints;
|
_constraints = constraints;
|
||||||
_arch = uint8_t(arch);
|
_arch = arch;
|
||||||
|
|
||||||
// Initialize `_archRegs`.
|
// Initialize `_archRegs`.
|
||||||
for (i = 0; i < BaseReg::kGroupVirt; i++)
|
for (RegGroup group : RegGroupVirtValues{})
|
||||||
_workData[i]._archRegs = _constraints->availableRegs(i);
|
_workData[group]._archRegs = _constraints->availableRegs(group);
|
||||||
|
|
||||||
if (frame.hasPreservedFP())
|
if (frame.hasPreservedFP())
|
||||||
_workData[BaseReg::kGroupGp]._archRegs &= ~Support::bitMask(archTraits().fpRegId());
|
_workData[size_t(RegGroup::kGp)]._archRegs &= ~Support::bitMask(archTraits().fpRegId());
|
||||||
|
|
||||||
// Extract information from all function arguments/assignments and build Var[] array.
|
// Extract information from all function arguments/assignments and build Var[] array.
|
||||||
uint32_t varId = 0;
|
uint32_t varId = 0;
|
||||||
@@ -73,7 +50,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
FuncValue& src = var.cur;
|
FuncValue& src = var.cur;
|
||||||
FuncValue& dst = var.out;
|
FuncValue& dst = var.out;
|
||||||
|
|
||||||
uint32_t dstGroup = 0xFFFFFFFFu;
|
RegGroup dstGroup = RegGroup::kMaxValue;
|
||||||
uint32_t dstId = BaseReg::kIdBad;
|
uint32_t dstId = BaseReg::kIdBad;
|
||||||
WorkData* dstWd = nullptr;
|
WorkData* dstWd = nullptr;
|
||||||
|
|
||||||
@@ -82,18 +59,17 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
return DebugUtils::errored(kErrorInvalidAssignment);
|
return DebugUtils::errored(kErrorInvalidAssignment);
|
||||||
|
|
||||||
if (dst.isReg()) {
|
if (dst.isReg()) {
|
||||||
uint32_t dstType = dst.regType();
|
RegType dstType = dst.regType();
|
||||||
if (ASMJIT_UNLIKELY(!archTraits().hasRegType(dstType)))
|
if (ASMJIT_UNLIKELY(!archTraits().hasRegType(dstType)))
|
||||||
return DebugUtils::errored(kErrorInvalidRegType);
|
return DebugUtils::errored(kErrorInvalidRegType);
|
||||||
|
|
||||||
// Copy TypeId from source if the destination doesn't have it. The RA
|
// Copy TypeId from source if the destination doesn't have it. The RA used by BaseCompiler would never
|
||||||
// used by BaseCompiler would never leave TypeId undefined, but users
|
// leave TypeId undefined, but users of FuncAPI can just assign phys regs without specifying the type.
|
||||||
// of FuncAPI can just assign phys regs without specifying the type.
|
|
||||||
if (!dst.hasTypeId())
|
if (!dst.hasTypeId())
|
||||||
dst.setTypeId(archTraits().regTypeToTypeId(dst.regType()));
|
dst.setTypeId(archTraits().regTypeToTypeId(dst.regType()));
|
||||||
|
|
||||||
dstGroup = archTraits().regTypeToGroup(dstType);
|
dstGroup = archTraits().regTypeToGroup(dstType);
|
||||||
if (ASMJIT_UNLIKELY(dstGroup >= BaseReg::kGroupVirt))
|
if (ASMJIT_UNLIKELY(dstGroup > RegGroup::kMaxVirt))
|
||||||
return DebugUtils::errored(kErrorInvalidRegGroup);
|
return DebugUtils::errored(kErrorInvalidRegGroup);
|
||||||
|
|
||||||
dstWd = &_workData[dstGroup];
|
dstWd = &_workData[dstGroup];
|
||||||
@@ -112,15 +88,15 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
if (!dst.hasTypeId())
|
if (!dst.hasTypeId())
|
||||||
dst.setTypeId(src.typeId());
|
dst.setTypeId(src.typeId());
|
||||||
|
|
||||||
RegInfo regInfo = getSuitableRegForMemToMemMove(arch, dst.typeId(), src.typeId());
|
OperandSignature signature = getSuitableRegForMemToMemMove(arch, dst.typeId(), src.typeId());
|
||||||
if (ASMJIT_UNLIKELY(!regInfo.isValid()))
|
if (ASMJIT_UNLIKELY(!signature.isValid()))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
_stackDstMask = uint8_t(_stackDstMask | Support::bitMask(regInfo.group()));
|
_stackDstMask = uint8_t(_stackDstMask | Support::bitMask(signature.regGroup()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src.isReg()) {
|
if (src.isReg()) {
|
||||||
uint32_t srcId = src.regId();
|
uint32_t srcId = src.regId();
|
||||||
uint32_t srcGroup = archTraits().regTypeToGroup(src.regType());
|
RegGroup srcGroup = archTraits().regTypeToGroup(src.regType());
|
||||||
|
|
||||||
if (dstGroup == srcGroup) {
|
if (dstGroup == srcGroup) {
|
||||||
dstWd->assign(varId, srcId);
|
dstWd->assign(varId, srcId);
|
||||||
@@ -130,10 +106,10 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
var.markDone();
|
var.markDone();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (ASMJIT_UNLIKELY(srcGroup >= BaseReg::kGroupVirt))
|
if (ASMJIT_UNLIKELY(srcGroup > RegGroup::kMaxVirt))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
WorkData& srcData = _workData[srcGroup];
|
WorkData& srcData = _workData[size_t(srcGroup)];
|
||||||
srcData.assign(varId, srcId);
|
srcData.assign(varId, srcId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -148,14 +124,15 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Initialize WorkData::workRegs.
|
// Initialize WorkData::workRegs.
|
||||||
for (i = 0; i < BaseReg::kGroupVirt; i++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
_workData[i]._workRegs = (_workData[i].archRegs() & (frame.dirtyRegs(i) | ~frame.preservedRegs(i))) | _workData[i].dstRegs() | _workData[i].assignedRegs();
|
_workData[group]._workRegs =
|
||||||
|
(_workData[group].archRegs() & (frame.dirtyRegs(group) | ~frame.preservedRegs(group))) | _workData[group].dstRegs() | _workData[group].assignedRegs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a variable that represents `SARegId` if necessary.
|
// Create a variable that represents `SARegId` if necessary.
|
||||||
bool saRegRequired = _hasStackSrc && frame.hasDynamicAlignment() && !frame.hasPreservedFP();
|
bool saRegRequired = _hasStackSrc && frame.hasDynamicAlignment() && !frame.hasPreservedFP();
|
||||||
|
|
||||||
WorkData& gpRegs = _workData[BaseReg::kGroupGp];
|
WorkData& gpRegs = _workData[RegGroup::kGp];
|
||||||
uint32_t saCurRegId = frame.saRegId();
|
uint32_t saCurRegId = frame.saRegId();
|
||||||
uint32_t saOutRegId = args.saRegId();
|
uint32_t saOutRegId = args.saRegId();
|
||||||
|
|
||||||
@@ -173,8 +150,8 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (saRegRequired) {
|
if (saRegRequired) {
|
||||||
uint32_t ptrTypeId = Environment::is32Bit(arch) ? Type::kIdU32 : Type::kIdU64;
|
TypeId ptrTypeId = Environment::is32Bit(arch) ? TypeId::kUInt32 : TypeId::kUInt64;
|
||||||
uint32_t ptrRegType = Environment::is32Bit(arch) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
|
RegType ptrRegType = Environment::is32Bit(arch) ? RegType::kGp32 : RegType::kGp64;
|
||||||
|
|
||||||
_saVarId = uint8_t(varId);
|
_saVarId = uint8_t(varId);
|
||||||
_hasPreservedFP = frame.hasPreservedFP();
|
_hasPreservedFP = frame.hasPreservedFP();
|
||||||
@@ -187,7 +164,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
saCurRegId = saOutRegId;
|
saCurRegId = saOutRegId;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint32_t availableRegs = gpRegs.availableRegs();
|
RegMask availableRegs = gpRegs.availableRegs();
|
||||||
if (!availableRegs)
|
if (!availableRegs)
|
||||||
availableRegs = gpRegs.archRegs() & ~gpRegs.workRegs();
|
availableRegs = gpRegs.archRegs() & ~gpRegs.workRegs();
|
||||||
|
|
||||||
@@ -223,7 +200,7 @@ 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();
|
||||||
|
|
||||||
uint32_t group = archTraits().regTypeToGroup(var.cur.regType());
|
RegGroup group = archTraits().regTypeToGroup(var.cur.regType());
|
||||||
if (group != archTraits().regTypeToGroup(var.out.regType()))
|
if (group != archTraits().regTypeToGroup(var.out.regType()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
@@ -242,12 +219,12 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::initWorkData(const FuncFrame& frame, co
|
|||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error FuncArgsContext::markDstRegsDirty(FuncFrame& frame) noexcept {
|
ASMJIT_FAVOR_SIZE Error FuncArgsContext::markDstRegsDirty(FuncFrame& frame) noexcept {
|
||||||
for (uint32_t i = 0; i < BaseReg::kGroupVirt; i++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
WorkData& wd = _workData[i];
|
WorkData& wd = _workData[group];
|
||||||
uint32_t regs = wd.usedRegs() | wd._dstShuf;
|
uint32_t regs = wd.usedRegs() | wd._dstShuf;
|
||||||
|
|
||||||
wd._workRegs |= regs;
|
wd._workRegs |= regs;
|
||||||
frame.addDirtyRegs(i, regs);
|
frame.addDirtyRegs(group, regs);
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -260,19 +237,19 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::markScratchRegs(FuncFrame& frame) noexc
|
|||||||
groupMask |= _stackDstMask;
|
groupMask |= _stackDstMask;
|
||||||
|
|
||||||
// Handle register swaps.
|
// Handle register swaps.
|
||||||
groupMask |= _regSwapsMask & ~Support::bitMask(BaseReg::kGroupGp);
|
groupMask |= _regSwapsMask & ~Support::bitMask(RegGroup::kGp);
|
||||||
|
|
||||||
if (!groupMask)
|
if (!groupMask)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
// Selects one dirty register per affected group that can be used as a scratch register.
|
// Selects one dirty register per affected group that can be used as a scratch register.
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
if (Support::bitTest(groupMask, group)) {
|
if (Support::bitTest(groupMask, group)) {
|
||||||
WorkData& wd = _workData[group];
|
WorkData& wd = _workData[group];
|
||||||
|
|
||||||
// Initially, pick some clobbered or dirty register.
|
// Initially, pick some clobbered or dirty register.
|
||||||
uint32_t workRegs = wd.workRegs();
|
RegMask workRegs = wd.workRegs();
|
||||||
uint32_t regs = workRegs & ~(wd.usedRegs() | wd._dstShuf);
|
RegMask regs = workRegs & ~(wd.usedRegs() | wd._dstShuf);
|
||||||
|
|
||||||
// If that didn't work out pick some register which is not in 'used'.
|
// If that didn't work out pick some register which is not in 'used'.
|
||||||
if (!regs)
|
if (!regs)
|
||||||
@@ -288,7 +265,7 @@ ASMJIT_FAVOR_SIZE Error FuncArgsContext::markScratchRegs(FuncFrame& frame) noexc
|
|||||||
if (!regs)
|
if (!regs)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32_t regMask = Support::blsi(regs);
|
RegMask regMask = Support::blsi(regs);
|
||||||
wd._workRegs |= regMask;
|
wd._workRegs |= regMask;
|
||||||
frame.addDirtyRegs(group, regMask);
|
frame.addDirtyRegs(group, regMask);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
#define ASMJIT_CORE_FUNCARGSCONTEXT_P_H_INCLUDED
|
||||||
@@ -37,38 +19,30 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
static inline OperandSignature getSuitableRegForMemToMemMove(Arch arch, TypeId dstTypeId, TypeId srcTypeId) noexcept {
|
||||||
// [TODO: Place somewhere else]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static inline RegInfo getSuitableRegForMemToMemMove(uint32_t arch, uint32_t dstTypeId, uint32_t srcTypeId) noexcept {
|
|
||||||
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
const ArchTraits& archTraits = ArchTraits::byArch(arch);
|
||||||
|
|
||||||
uint32_t dstSize = Type::sizeOf(dstTypeId);
|
uint32_t dstSize = TypeUtils::sizeOf(dstTypeId);
|
||||||
uint32_t srcSize = Type::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);
|
||||||
|
|
||||||
uint32_t signature = 0;
|
OperandSignature signature(0);
|
||||||
if (maxSize <= regSize || (Type::isInt(dstTypeId) && Type::isInt(srcTypeId)))
|
if (maxSize <= regSize || (TypeUtils::isInt(dstTypeId) && TypeUtils::isInt(srcTypeId)))
|
||||||
signature = maxSize <= 4 ? archTraits.regTypeToSignature(BaseReg::kTypeGp32)
|
signature = maxSize <= 4 ? archTraits.regTypeToSignature(RegType::kGp32)
|
||||||
: archTraits.regTypeToSignature(BaseReg::kTypeGp64);
|
: archTraits.regTypeToSignature(RegType::kGp64);
|
||||||
else if (maxSize <= 8 && archTraits.hasRegType(BaseReg::kTypeVec64))
|
else if (maxSize <= 8 && archTraits.hasRegType(RegType::kVec64))
|
||||||
signature = archTraits.regTypeToSignature(BaseReg::kTypeVec64);
|
signature = archTraits.regTypeToSignature(RegType::kVec64);
|
||||||
else if (maxSize <= 16 && archTraits.hasRegType(BaseReg::kTypeVec128))
|
else if (maxSize <= 16 && archTraits.hasRegType(RegType::kVec128))
|
||||||
signature = archTraits.regTypeToSignature(BaseReg::kTypeVec128);
|
signature = archTraits.regTypeToSignature(RegType::kVec128);
|
||||||
else if (maxSize <= 32 && archTraits.hasRegType(BaseReg::kTypeVec256))
|
else if (maxSize <= 32 && archTraits.hasRegType(RegType::kVec256))
|
||||||
signature = archTraits.regTypeToSignature(BaseReg::kTypeVec256);
|
signature = archTraits.regTypeToSignature(RegType::kVec256);
|
||||||
else if (maxSize <= 64 && archTraits.hasRegType(BaseReg::kTypeVec512))
|
else if (maxSize <= 64 && archTraits.hasRegType(RegType::kVec512))
|
||||||
signature = archTraits.regTypeToSignature(BaseReg::kTypeVec512);
|
signature = archTraits.regTypeToSignature(RegType::kVec512);
|
||||||
|
|
||||||
return RegInfo { signature };
|
return signature;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FuncArgsContext]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class FuncArgsContext {
|
class FuncArgsContext {
|
||||||
public:
|
public:
|
||||||
enum VarId : uint32_t {
|
enum VarId : uint32_t {
|
||||||
@@ -97,17 +71,17 @@ public:
|
|||||||
|
|
||||||
struct WorkData {
|
struct WorkData {
|
||||||
//! All allocable registers provided by the architecture.
|
//! All allocable registers provided by the architecture.
|
||||||
uint32_t _archRegs;
|
RegMask _archRegs;
|
||||||
//! All registers that can be used by the shuffler.
|
//! All registers that can be used by the shuffler.
|
||||||
uint32_t _workRegs;
|
RegMask _workRegs;
|
||||||
//! Registers used by the shuffler (all).
|
//! Registers used by the shuffler (all).
|
||||||
uint32_t _usedRegs;
|
RegMask _usedRegs;
|
||||||
//! Assigned registers.
|
//! Assigned registers.
|
||||||
uint32_t _assignedRegs;
|
RegMask _assignedRegs;
|
||||||
//! Destination registers assigned to arguments or SA.
|
//! Destination registers assigned to arguments or SA.
|
||||||
uint32_t _dstRegs;
|
RegMask _dstRegs;
|
||||||
//! Destination registers that require shuffling.
|
//! Destination registers that require shuffling.
|
||||||
uint32_t _dstShuf;
|
RegMask _dstShuf;
|
||||||
//! Number of register swaps.
|
//! Number of register swaps.
|
||||||
uint8_t _numSwaps;
|
uint8_t _numSwaps;
|
||||||
//! Number of stack loads.
|
//! Number of stack loads.
|
||||||
@@ -173,19 +147,20 @@ public:
|
|||||||
_assignedRegs ^= Support::bitMask(regId);
|
_assignedRegs ^= Support::bitMask(regId);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t archRegs() const noexcept { return _archRegs; }
|
inline RegMask archRegs() const noexcept { return _archRegs; }
|
||||||
inline uint32_t workRegs() const noexcept { return _workRegs; }
|
inline RegMask workRegs() const noexcept { return _workRegs; }
|
||||||
inline uint32_t usedRegs() const noexcept { return _usedRegs; }
|
inline RegMask usedRegs() const noexcept { return _usedRegs; }
|
||||||
inline uint32_t assignedRegs() const noexcept { return _assignedRegs; }
|
inline RegMask assignedRegs() const noexcept { return _assignedRegs; }
|
||||||
inline uint32_t dstRegs() const noexcept { return _dstRegs; }
|
inline RegMask dstRegs() const noexcept { return _dstRegs; }
|
||||||
inline uint32_t availableRegs() const noexcept { return _workRegs & ~_assignedRegs; }
|
inline RegMask availableRegs() const noexcept { return _workRegs & ~_assignedRegs; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Architecture traits.
|
//! Architecture traits.
|
||||||
const ArchTraits* _archTraits = nullptr;
|
const ArchTraits* _archTraits = nullptr;
|
||||||
|
//! Architecture constraints.
|
||||||
const RAConstraints* _constraints = nullptr;
|
const RAConstraints* _constraints = nullptr;
|
||||||
//! Architecture identifier.
|
//! Target architecture.
|
||||||
uint8_t _arch = 0;
|
Arch _arch = Arch::kUnknown;
|
||||||
//! Has arguments passed via stack (SRC).
|
//! Has arguments passed via stack (SRC).
|
||||||
bool _hasStackSrc = false;
|
bool _hasStackSrc = false;
|
||||||
//! Has preserved frame-pointer (FP).
|
//! Has preserved frame-pointer (FP).
|
||||||
@@ -196,13 +171,13 @@ public:
|
|||||||
uint8_t _regSwapsMask = 0;
|
uint8_t _regSwapsMask = 0;
|
||||||
uint8_t _saVarId = kVarIdNone;
|
uint8_t _saVarId = kVarIdNone;
|
||||||
uint32_t _varCount = 0;
|
uint32_t _varCount = 0;
|
||||||
WorkData _workData[BaseReg::kGroupVirt];
|
Support::Array<WorkData, Globals::kNumVirtGroups> _workData;
|
||||||
Var _vars[Globals::kMaxFuncArgs * Globals::kMaxValuePack + 1];
|
Var _vars[Globals::kMaxFuncArgs * Globals::kMaxValuePack + 1];
|
||||||
|
|
||||||
FuncArgsContext() noexcept;
|
FuncArgsContext() noexcept;
|
||||||
|
|
||||||
inline const ArchTraits& archTraits() const noexcept { return *_archTraits; }
|
inline const ArchTraits& archTraits() const noexcept { return *_archTraits; }
|
||||||
inline uint32_t arch() const noexcept { return _arch; }
|
inline Arch arch() const noexcept { return _arch; }
|
||||||
|
|
||||||
inline uint32_t varCount() const noexcept { return _varCount; }
|
inline uint32_t varCount() const noexcept { return _varCount; }
|
||||||
inline size_t indexOf(const Var* var) const noexcept { return (size_t)(var - _vars); }
|
inline size_t indexOf(const Var* var) const noexcept { return (size_t)(var - _vars); }
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
@@ -27,9 +9,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// DebugUtils - Error As String
|
||||||
// [asmjit::DebugUtils]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
||||||
#ifndef ASMJIT_NO_TEXT
|
#ifndef ASMJIT_NO_TEXT
|
||||||
@@ -54,7 +35,6 @@ ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
|||||||
"LabelNameTooLong\0"
|
"LabelNameTooLong\0"
|
||||||
"InvalidLabelName\0"
|
"InvalidLabelName\0"
|
||||||
"InvalidParentLabel\0"
|
"InvalidParentLabel\0"
|
||||||
"NonLocalLabelCannotHaveParent\0"
|
|
||||||
"InvalidSection\0"
|
"InvalidSection\0"
|
||||||
"TooManySections\0"
|
"TooManySections\0"
|
||||||
"InvalidSectionName\0"
|
"InvalidSectionName\0"
|
||||||
@@ -97,6 +77,7 @@ ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
|||||||
"InvalidUseOfGpq\0"
|
"InvalidUseOfGpq\0"
|
||||||
"InvalidUseOfF80\0"
|
"InvalidUseOfF80\0"
|
||||||
"NotConsecutiveRegs\0"
|
"NotConsecutiveRegs\0"
|
||||||
|
"ConsecutiveRegsAllocation\0"
|
||||||
"IllegalVirtReg\0"
|
"IllegalVirtReg\0"
|
||||||
"TooManyVirtRegs\0"
|
"TooManyVirtRegs\0"
|
||||||
"NoMorePhysRegs\0"
|
"NoMorePhysRegs\0"
|
||||||
@@ -109,10 +90,10 @@ ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
|||||||
|
|
||||||
static const uint16_t sErrorIndex[] = {
|
static const uint16_t sErrorIndex[] = {
|
||||||
0, 3, 15, 31, 44, 56, 71, 90, 108, 123, 132, 148, 165, 178, 192, 210, 230,
|
0, 3, 15, 31, 44, 56, 71, 90, 108, 123, 132, 148, 165, 178, 192, 210, 230,
|
||||||
247, 264, 283, 313, 328, 344, 363, 382, 400, 422, 440, 459, 474, 490, 504,
|
247, 264, 283, 298, 314, 333, 352, 370, 392, 410, 429, 444, 460, 474, 488,
|
||||||
518, 538, 563, 581, 603, 625, 642, 659, 675, 691, 707, 724, 739, 754, 774,
|
508, 533, 551, 573, 595, 612, 629, 645, 661, 677, 694, 709, 724, 744, 764,
|
||||||
794, 814, 847, 867, 882, 899, 918, 939, 959, 973, 994, 1008, 1026, 1042,
|
784, 817, 837, 852, 869, 888, 909, 929, 943, 964, 978, 996, 1012, 1028, 1047,
|
||||||
1058, 1077, 1092, 1108, 1123, 1138, 1168, 1192, 1211, 1239
|
1073, 1088, 1104, 1119, 1134, 1164, 1188, 1207, 1235
|
||||||
};
|
};
|
||||||
// @EnumStringEnd@
|
// @EnumStringEnd@
|
||||||
|
|
||||||
@@ -124,6 +105,9 @@ ASMJIT_FAVOR_SIZE const char* DebugUtils::errorAsString(Error err) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DebugUtils - Debug Output
|
||||||
|
// =========================
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept {
|
ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
::OutputDebugStringA(str);
|
::OutputDebugStringA(str);
|
||||||
@@ -132,6 +116,9 @@ ASMJIT_FAVOR_SIZE void DebugUtils::debugOutput(const char* str) noexcept {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// DebugUtils - Fatal Errors
|
||||||
|
// =========================
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept {
|
ASMJIT_FAVOR_SIZE void DebugUtils::assertionFailed(const char* file, int line, const char* msg) noexcept {
|
||||||
char str[1024];
|
char str[1024];
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED
|
#ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED
|
||||||
#define ASMJIT_CORE_GLOBALS_H_INCLUDED
|
#define ASMJIT_CORE_GLOBALS_H_INCLUDED
|
||||||
@@ -28,10 +10,6 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Support]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! \addtogroup asmjit_utilities
|
//! \addtogroup asmjit_utilities
|
||||||
//! \{
|
//! \{
|
||||||
@@ -43,21 +21,21 @@ namespace Support {
|
|||||||
|
|
||||||
#if defined(ASMJIT_NO_STDCXX)
|
#if defined(ASMJIT_NO_STDCXX)
|
||||||
namespace Support {
|
namespace Support {
|
||||||
ASMJIT_INLINE void* operatorNew(size_t n) noexcept { return malloc(n); }
|
ASMJIT_FORCE_INLINE void* operatorNew(size_t n) noexcept { return malloc(n); }
|
||||||
ASMJIT_INLINE void operatorDelete(void* p) noexcept { if (p) free(p); }
|
ASMJIT_FORCE_INLINE void operatorDelete(void* p) noexcept { if (p) free(p); }
|
||||||
} // {Support}
|
} // {Support}
|
||||||
|
|
||||||
#define ASMJIT_BASE_CLASS(TYPE) \
|
#define ASMJIT_BASE_CLASS(TYPE) \
|
||||||
ASMJIT_INLINE void* operator new(size_t n) noexcept { \
|
ASMJIT_FORCE_INLINE void* operator new(size_t n) noexcept { \
|
||||||
return Support::operatorNew(n); \
|
return Support::operatorNew(n); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ASMJIT_INLINE void operator delete(void* p) noexcept { \
|
ASMJIT_FORCE_INLINE void operator delete(void* p) noexcept { \
|
||||||
Support::operatorDelete(p); \
|
Support::operatorDelete(p); \
|
||||||
} \
|
} \
|
||||||
\
|
\
|
||||||
ASMJIT_INLINE void* operator new(size_t, void* p) noexcept { return p; } \
|
ASMJIT_FORCE_INLINE void* operator new(size_t, void* p) noexcept { return p; } \
|
||||||
ASMJIT_INLINE void operator delete(void*, void*) noexcept {}
|
ASMJIT_FORCE_INLINE void operator delete(void*, void*) noexcept {}
|
||||||
#else
|
#else
|
||||||
#define ASMJIT_BASE_CLASS(TYPE)
|
#define ASMJIT_BASE_CLASS(TYPE)
|
||||||
#endif
|
#endif
|
||||||
@@ -65,20 +43,32 @@ namespace Support {
|
|||||||
//! \}
|
//! \}
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Globals]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Byte order.
|
||||||
|
enum class ByteOrder {
|
||||||
|
//! Little endian.
|
||||||
|
kLE = 0,
|
||||||
|
//! Big endian.
|
||||||
|
kBE = 1,
|
||||||
|
//! Native byte order of the target architecture.
|
||||||
|
kNative = ASMJIT_ARCH_LE ? kLE : kBE,
|
||||||
|
//! Swapped byte order of the target architecture.
|
||||||
|
kSwapped = ASMJIT_ARCH_LE ? kBE : kLE
|
||||||
|
};
|
||||||
|
|
||||||
|
//! A policy that can be used with some `reset()` member functions.
|
||||||
|
enum class ResetPolicy : uint32_t {
|
||||||
|
//! Soft reset, doesn't deallocate memory (default).
|
||||||
|
kSoft = 0,
|
||||||
|
//! Hard reset, releases all memory used, if any.
|
||||||
|
kHard = 1
|
||||||
|
};
|
||||||
|
|
||||||
//! Contains typedefs, constants, and variables used globally by AsmJit.
|
//! Contains typedefs, constants, and variables used globally by AsmJit.
|
||||||
namespace Globals {
|
namespace Globals {
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Globals::<global>]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! 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) * 4);
|
||||||
|
|
||||||
@@ -92,13 +82,11 @@ static constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16;
|
|||||||
//!
|
//!
|
||||||
//! `2 * log2(n + 1)`
|
//! `2 * log2(n + 1)`
|
||||||
//!
|
//!
|
||||||
//! Size of RB node is at least two pointers (without data),
|
//! Size of RB node is at least two pointers (without data), so a theoretical architecture limit would be:
|
||||||
//! so a theoretical architecture limit would be:
|
|
||||||
//!
|
//!
|
||||||
//! `2 * log2(addressableMemorySize / sizeof(Node) + 1)`
|
//! `2 * log2(addressableMemorySize / sizeof(Node) + 1)`
|
||||||
//!
|
//!
|
||||||
//! Which yields 30 on 32-bit arch and 61 on 64-bit arch.
|
//! Which yields 30 on 32-bit arch and 61 on 64-bit arch. The final value was adjusted by +1 for safety reasons.
|
||||||
//! The final value was adjusted by +1 for safety reasons.
|
|
||||||
static constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1;
|
static constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1;
|
||||||
|
|
||||||
//! Maximum number of operands per a single instruction.
|
//! Maximum number of operands per a single instruction.
|
||||||
@@ -135,34 +123,8 @@ static constexpr uint32_t kNotFound = 0xFFFFFFFFu;
|
|||||||
//! Invalid base address.
|
//! Invalid base address.
|
||||||
static constexpr uint64_t kNoBaseAddress = ~uint64_t(0);
|
static constexpr uint64_t kNoBaseAddress = ~uint64_t(0);
|
||||||
|
|
||||||
// ============================================================================
|
//! Number of virtual register groups.
|
||||||
// [asmjit::Globals::ResetPolicy]
|
static constexpr uint32_t kNumVirtGroups = 4;
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Reset policy used by most `reset()` functions.
|
|
||||||
enum ResetPolicy : uint32_t {
|
|
||||||
//! Soft reset, doesn't deallocate memory (default).
|
|
||||||
kResetSoft = 0,
|
|
||||||
//! Hard reset, releases all memory used, if any.
|
|
||||||
kResetHard = 1
|
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Globals::Link]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
enum Link : uint32_t {
|
|
||||||
kLinkLeft = 0,
|
|
||||||
kLinkRight = 1,
|
|
||||||
|
|
||||||
kLinkPrev = 0,
|
|
||||||
kLinkNext = 1,
|
|
||||||
|
|
||||||
kLinkFirst = 0,
|
|
||||||
kLinkLast = 1,
|
|
||||||
|
|
||||||
kLinkCount = 2
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Init_ {};
|
struct Init_ {};
|
||||||
struct NoInit_ {};
|
struct NoInit_ {};
|
||||||
@@ -172,24 +134,6 @@ static const constexpr NoInit_ NoInit {};
|
|||||||
|
|
||||||
} // {Globals}
|
} // {Globals}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ByteOrder]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Byte order.
|
|
||||||
namespace ByteOrder {
|
|
||||||
enum : uint32_t {
|
|
||||||
kLE = 0,
|
|
||||||
kBE = 1,
|
|
||||||
kNative = ASMJIT_ARCH_LE ? kLE : kBE,
|
|
||||||
kSwapped = ASMJIT_ARCH_LE ? kBE : kLE
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ptr_as_func / func_as_ptr]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); }
|
static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); }
|
||||||
|
|
||||||
@@ -198,10 +142,6 @@ static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_i
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Error]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \addtogroup asmjit_error_handling
|
//! \addtogroup asmjit_error_handling
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -223,9 +163,8 @@ enum ErrorCode : uint32_t {
|
|||||||
|
|
||||||
//! Invalid state.
|
//! Invalid state.
|
||||||
//!
|
//!
|
||||||
//! If this error is returned it means that either you are doing something
|
//! If this error is returned it means that either you are doing something wrong or AsmJit caught itself by
|
||||||
//! wrong or AsmJit caught itself by doing something wrong. This error should
|
//! doing something wrong. This error should never be ignored.
|
||||||
//! never be ignored.
|
|
||||||
kErrorInvalidState,
|
kErrorInvalidState,
|
||||||
|
|
||||||
//! Invalid or incompatible architecture.
|
//! Invalid or incompatible architecture.
|
||||||
@@ -253,9 +192,8 @@ enum ErrorCode : uint32_t {
|
|||||||
kErrorInvalidDirective,
|
kErrorInvalidDirective,
|
||||||
//! Attempt to use uninitialized label.
|
//! Attempt to use uninitialized label.
|
||||||
kErrorInvalidLabel,
|
kErrorInvalidLabel,
|
||||||
//! Label index overflow - a single \ref BaseAssembler instance can hold
|
//! Label index overflow - a single \ref BaseAssembler instance can hold almost 2^32 (4 billion) labels. If
|
||||||
//! almost 2^32 (4 billion) labels. If there is an attempt to create more
|
//! there is an attempt to create more labels then this error is returned.
|
||||||
//! labels then this error is returned.
|
|
||||||
kErrorTooManyLabels,
|
kErrorTooManyLabels,
|
||||||
//! Label is already bound.
|
//! Label is already bound.
|
||||||
kErrorLabelAlreadyBound,
|
kErrorLabelAlreadyBound,
|
||||||
@@ -265,10 +203,9 @@ 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 invalid.
|
//! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was either invalid or parent is not supported
|
||||||
|
//! by the requested `LabelType`.
|
||||||
kErrorInvalidParentLabel,
|
kErrorInvalidParentLabel,
|
||||||
//! Parent id specified for a non-local (global) label.
|
|
||||||
kErrorNonLocalLabelCannotHaveParent,
|
|
||||||
|
|
||||||
//! Invalid section.
|
//! Invalid section.
|
||||||
kErrorInvalidSection,
|
kErrorInvalidSection,
|
||||||
@@ -356,11 +293,12 @@ enum ErrorCode : uint32_t {
|
|||||||
kErrorInvalidUseOfGpbHi,
|
kErrorInvalidUseOfGpbHi,
|
||||||
//! Invalid use of a 64-bit GPQ register in 32-bit mode.
|
//! Invalid use of a 64-bit GPQ register in 32-bit mode.
|
||||||
kErrorInvalidUseOfGpq,
|
kErrorInvalidUseOfGpq,
|
||||||
//! Invalid use of an 80-bit float (\ref Type::kIdF80).
|
//! Invalid use of an 80-bit float (\ref TypeId::kFloat80).
|
||||||
kErrorInvalidUseOfF80,
|
kErrorInvalidUseOfF80,
|
||||||
//! Some registers in the instruction muse be consecutive (some ARM and AVX512
|
//! Instruction requires the use of consecutive registers, but registers in operands weren't (AVX512, ASIMD load/store, etc...).
|
||||||
//! neural-net instructions).
|
|
||||||
kErrorNotConsecutiveRegs,
|
kErrorNotConsecutiveRegs,
|
||||||
|
//! Failed to allocate consecutive registers - allocable registers either too restricted or a bug in RW info.
|
||||||
|
kErrorConsecutiveRegsAllocation,
|
||||||
|
|
||||||
//! Illegal virtual register - reported by instruction validation.
|
//! Illegal virtual register - reported by instruction validation.
|
||||||
kErrorIllegalVirtReg,
|
kErrorIllegalVirtReg,
|
||||||
@@ -388,23 +326,19 @@ enum ErrorCode : uint32_t {
|
|||||||
kErrorCount
|
kErrorCount
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::DebugUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Debugging utilities.
|
//! Debugging utilities.
|
||||||
namespace DebugUtils {
|
namespace DebugUtils {
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! Used to silence warnings about unused arguments or variables.
|
//! Used to silence warnings about unused arguments or variables.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
static ASMJIT_INLINE void unused(Args&&...) noexcept {}
|
static inline void unused(Args&&...) noexcept {}
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
//! Returns the error `err` passed.
|
//! Returns the error `err` passed.
|
||||||
//!
|
//!
|
||||||
//! Provided for debugging purposes. Putting a breakpoint inside `errored` can
|
//! Provided for debugging purposes. Putting a breakpoint inside `errored` can help with tracing the origin of any
|
||||||
//! help with tracing the origin of any error reported / returned by AsmJit.
|
//! error reported / returned by AsmJit.
|
||||||
static constexpr Error errored(Error err) noexcept { return err; }
|
static constexpr Error errored(Error err) noexcept { return err; }
|
||||||
|
|
||||||
//! Returns a printable version of `asmjit::Error` code.
|
//! Returns a printable version of `asmjit::Error` code.
|
||||||
@@ -419,12 +353,10 @@ ASMJIT_API void debugOutput(const char* str) noexcept;
|
|||||||
//! \param line Line in the source file.
|
//! \param line Line in the source file.
|
||||||
//! \param msg Message to display.
|
//! \param msg Message to display.
|
||||||
//!
|
//!
|
||||||
//! If you have problems with assertion failures a breakpoint can be put
|
//! If you have problems with assertion failures a breakpoint can be put at \ref assertionFailed() function
|
||||||
//! at \ref assertionFailed() function (asmjit/core/globals.cpp). A call stack
|
//! (asmjit/core/globals.cpp). A call stack will be available when such assertion failure is triggered. AsmJit
|
||||||
//! will be available when such assertion failure is triggered. AsmJit always
|
//! always returns errors on failures, assertions are a last resort and usually mean unrecoverable state due to out
|
||||||
//! returns errors on failures, assertions are a last resort and usually mean
|
//! of range array access or totally invalid arguments like nullptr where a valid pointer should be provided, etc...
|
||||||
//! unrecoverable state due to out of range array access or totally invalid
|
|
||||||
//! arguments like nullptr where a valid pointer should be provided, etc...
|
|
||||||
ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept;
|
ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept;
|
||||||
|
|
||||||
} // {DebugUtils}
|
} // {DebugUtils}
|
||||||
@@ -445,9 +377,8 @@ ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, cons
|
|||||||
|
|
||||||
//! \def ASMJIT_PROPAGATE(...)
|
//! \def ASMJIT_PROPAGATE(...)
|
||||||
//!
|
//!
|
||||||
//! Propagates a possible `Error` produced by `...` to the caller by returning
|
//! Propagates a possible `Error` produced by `...` to the caller by returning the error immediately. Used by AsmJit
|
||||||
//! the error immediately. Used by AsmJit internally, but kept public for users
|
//! internally, but kept public for users that want to use the same technique to propagate errors to the caller.
|
||||||
//! that want to use the same technique to propagate errors to the caller.
|
|
||||||
#define ASMJIT_PROPAGATE(...) \
|
#define ASMJIT_PROPAGATE(...) \
|
||||||
do { \
|
do { \
|
||||||
::asmjit::Error _err = __VA_ARGS__; \
|
::asmjit::Error _err = __VA_ARGS__; \
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/archtraits.h"
|
#include "../core/archtraits.h"
|
||||||
@@ -35,12 +17,11 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// InstAPI - InstId <-> String
|
||||||
// [asmjit::InstAPI - Text]
|
// ===========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_TEXT
|
#ifndef ASMJIT_NO_TEXT
|
||||||
Error InstAPI::instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept {
|
Error InstAPI::instIdToString(Arch arch, InstId instId, String& output) noexcept {
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
if (Environment::isFamilyX86(arch))
|
if (Environment::isFamilyX86(arch))
|
||||||
return x86::InstInternal::instIdToString(arch, instId, output);
|
return x86::InstInternal::instIdToString(arch, instId, output);
|
||||||
@@ -54,7 +35,7 @@ Error InstAPI::instIdToString(uint32_t arch, uint32_t instId, String& output) no
|
|||||||
return DebugUtils::errored(kErrorInvalidArch);
|
return DebugUtils::errored(kErrorInvalidArch);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t InstAPI::stringToInstId(uint32_t arch, const char* s, size_t len) noexcept {
|
InstId InstAPI::stringToInstId(Arch arch, const char* s, size_t len) noexcept {
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
if (Environment::isFamilyX86(arch))
|
if (Environment::isFamilyX86(arch))
|
||||||
return x86::InstInternal::stringToInstId(arch, s, len);
|
return x86::InstInternal::stringToInstId(arch, s, len);
|
||||||
@@ -69,12 +50,11 @@ uint32_t InstAPI::stringToInstId(uint32_t arch, const char* s, size_t len) noexc
|
|||||||
}
|
}
|
||||||
#endif // !ASMJIT_NO_TEXT
|
#endif // !ASMJIT_NO_TEXT
|
||||||
|
|
||||||
// ============================================================================
|
// InstAPI - Validate
|
||||||
// [asmjit::InstAPI - Validate]
|
// ==================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_VALIDATION
|
#ifndef ASMJIT_NO_VALIDATION
|
||||||
Error InstAPI::validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags) noexcept {
|
Error InstAPI::validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags) noexcept {
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
if (Environment::isFamilyX86(arch))
|
if (Environment::isFamilyX86(arch))
|
||||||
return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags);
|
return x86::InstInternal::validate(arch, inst, operands, opCount, validationFlags);
|
||||||
@@ -89,12 +69,11 @@ Error InstAPI::validate(uint32_t arch, const BaseInst& inst, const Operand_* ope
|
|||||||
}
|
}
|
||||||
#endif // !ASMJIT_NO_VALIDATION
|
#endif // !ASMJIT_NO_VALIDATION
|
||||||
|
|
||||||
// ============================================================================
|
// InstAPI - QueryRWInfo
|
||||||
// [asmjit::InstAPI - QueryRWInfo]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_INTROSPECTION
|
#ifndef ASMJIT_NO_INTROSPECTION
|
||||||
Error InstAPI::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
Error InstAPI::queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(opCount > Globals::kMaxOpCount))
|
if (ASMJIT_UNLIKELY(opCount > Globals::kMaxOpCount))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
@@ -112,12 +91,11 @@ Error InstAPI::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_*
|
|||||||
}
|
}
|
||||||
#endif // !ASMJIT_NO_INTROSPECTION
|
#endif // !ASMJIT_NO_INTROSPECTION
|
||||||
|
|
||||||
// ============================================================================
|
// InstAPI - QueryFeatures
|
||||||
// [asmjit::InstAPI - QueryFeatures]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_INTROSPECTION
|
#ifndef ASMJIT_NO_INTROSPECTION
|
||||||
Error InstAPI::queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept {
|
Error InstAPI::queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept {
|
||||||
#if !defined(ASMJIT_NO_X86)
|
#if !defined(ASMJIT_NO_X86)
|
||||||
if (Environment::isFamilyX86(arch))
|
if (Environment::isFamilyX86(arch))
|
||||||
return x86::InstInternal::queryFeatures(arch, inst, operands, opCount, out);
|
return x86::InstInternal::queryFeatures(arch, inst, operands, opCount, out);
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_INST_H_INCLUDED
|
#ifndef ASMJIT_CORE_INST_H_INCLUDED
|
||||||
#define ASMJIT_CORE_INST_H_INCLUDED
|
#define ASMJIT_CORE_INST_H_INCLUDED
|
||||||
@@ -34,20 +16,179 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_instruction_db
|
//! \addtogroup asmjit_instruction_db
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Describes an instruction.
|
||||||
// [asmjit::BaseInst]
|
//!
|
||||||
// ============================================================================
|
//! Each architecture has a set of valid instructions indexed from 0. Instruction with 0 id is, however, a special
|
||||||
|
//! instruction that describes an invalid instruction. Different architectures can share the same instruction id,
|
||||||
|
//! which would describe a different instruction per architecture.
|
||||||
|
//!
|
||||||
|
//! Instruction identifiers listed by architecture:
|
||||||
|
//!
|
||||||
|
//! - \ref x86::Inst (X86 and X86_64)
|
||||||
|
typedef uint32_t InstId;
|
||||||
|
|
||||||
//! Instruction id, options, and extraReg in a single structure. This structure
|
//! Instruction options.
|
||||||
//! exists mainly to simplify analysis and validation API that requires `BaseInst`
|
//!
|
||||||
//! and `Operand[]` array.
|
//! Instruction options complement instruction identifier and attributes.
|
||||||
|
enum class InstOptions : uint32_t {
|
||||||
|
//! No options.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Used internally by emitters for handling errors and rare cases.
|
||||||
|
kReserved = 0x00000001u,
|
||||||
|
|
||||||
|
//! Prevents following a jump during compilation (Compiler).
|
||||||
|
kUnfollow = 0x00000002u,
|
||||||
|
|
||||||
|
//! Overwrite the destination operand(s) (Compiler).
|
||||||
|
//!
|
||||||
|
//! Hint that is important for register liveness analysis. It tells the compiler that the destination operand will
|
||||||
|
//! be overwritten now or by adjacent instructions. Compiler knows when a register is completely overwritten by a
|
||||||
|
//! single instruction, for example you don't have to mark "movaps" or "pxor x, x", however, if a pair of
|
||||||
|
//! instructions is used and the first of them doesn't completely overwrite the content of the destination,
|
||||||
|
//! Compiler fails to mark that register as dead.
|
||||||
|
//!
|
||||||
|
//! X86 Specific
|
||||||
|
//! ------------
|
||||||
|
//!
|
||||||
|
//! - All instructions that always overwrite at least the size of the register the virtual-register uses, for
|
||||||
|
//! example "mov", "movq", "movaps" don't need the overwrite option to be used - conversion, shuffle, and
|
||||||
|
//! other miscellaneous instructions included.
|
||||||
|
//!
|
||||||
|
//! - All instructions that clear the destination register if all operands are the same, for example "xor x, x",
|
||||||
|
//! "pcmpeqb x x", etc...
|
||||||
|
//!
|
||||||
|
//! - Consecutive instructions that partially overwrite the variable until there is no old content require
|
||||||
|
//! `BaseCompiler::overwrite()` to be used. Some examples (not always the best use cases thought):
|
||||||
|
//!
|
||||||
|
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
|
||||||
|
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
|
||||||
|
//! - `mov al, ?` followed by `and ax, 0xFF`
|
||||||
|
//! - `mov al, ?` followed by `mov ah, al`
|
||||||
|
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
|
||||||
|
//!
|
||||||
|
//! - If the allocated virtual register is used temporarily for scalar operations. For example if you allocate a
|
||||||
|
//! full vector like `x86::Compiler::newXmm()` and then use that vector for scalar operations you should use
|
||||||
|
//! `overwrite()` directive:
|
||||||
|
//!
|
||||||
|
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't
|
||||||
|
//! use HI elements, use `compiler.overwrite().sqrtss(x, y)`.
|
||||||
|
kOverwrite = 0x00000004u,
|
||||||
|
|
||||||
|
//! Emit short-form of the instruction.
|
||||||
|
kShortForm = 0x00000010u,
|
||||||
|
//! Emit long-form of the instruction.
|
||||||
|
kLongForm = 0x00000020u,
|
||||||
|
|
||||||
|
//! Conditional jump is likely to be taken.
|
||||||
|
kTaken = 0x00000040u,
|
||||||
|
//! Conditional jump is unlikely to be taken.
|
||||||
|
kNotTaken = 0x00000080u,
|
||||||
|
|
||||||
|
// X86 & X64 Options
|
||||||
|
// -----------------
|
||||||
|
|
||||||
|
//! Use ModMR instead of ModRM if applicable.
|
||||||
|
kX86_ModMR = 0x00000100u,
|
||||||
|
//! Use ModRM instead of ModMR if applicable.
|
||||||
|
kX86_ModRM = 0x00000200u,
|
||||||
|
//! Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400).
|
||||||
|
kX86_Vex3 = 0x00000400u,
|
||||||
|
//! Use VEX prefix when both VEX|EVEX prefixes are available (HINT: AVX_VNNI).
|
||||||
|
kX86_Vex = 0x00000800u,
|
||||||
|
//! Use 4-byte EVEX prefix if possible (AVX-512) (must be 0x00001000).
|
||||||
|
kX86_Evex = 0x00001000u,
|
||||||
|
|
||||||
|
//! LOCK prefix (lock-enabled instructions only).
|
||||||
|
kX86_Lock = 0x00002000u,
|
||||||
|
//! REP prefix (string instructions only).
|
||||||
|
kX86_Rep = 0x00004000u,
|
||||||
|
//! REPNE prefix (string instructions only).
|
||||||
|
kX86_Repne = 0x00008000u,
|
||||||
|
|
||||||
|
//! XACQUIRE prefix (only allowed instructions).
|
||||||
|
kX86_XAcquire = 0x00010000u,
|
||||||
|
//! XRELEASE prefix (only allowed instructions).
|
||||||
|
kX86_XRelease = 0x00020000u,
|
||||||
|
|
||||||
|
//! AVX-512: embedded-rounding {er} and implicit {sae}.
|
||||||
|
kX86_ER = 0x00040000u,
|
||||||
|
//! AVX-512: suppress-all-exceptions {sae}.
|
||||||
|
kX86_SAE = 0x00080000u,
|
||||||
|
//! AVX-512: round-to-nearest (even) {rn-sae} (bits 00).
|
||||||
|
kX86_RN_SAE = 0x00000000u,
|
||||||
|
//! AVX-512: round-down (toward -inf) {rd-sae} (bits 01).
|
||||||
|
kX86_RD_SAE = 0x00200000u,
|
||||||
|
//! AVX-512: round-up (toward +inf) {ru-sae} (bits 10).
|
||||||
|
kX86_RU_SAE = 0x00400000u,
|
||||||
|
//! AVX-512: round-toward-zero (truncate) {rz-sae} (bits 11).
|
||||||
|
kX86_RZ_SAE = 0x00600000u,
|
||||||
|
//! AVX-512: Use zeroing {k}{z} instead of merging {k}.
|
||||||
|
kX86_ZMask = 0x00800000u,
|
||||||
|
|
||||||
|
//! AVX-512: Mask to get embedded rounding bits (2 bits).
|
||||||
|
kX86_ERMask = kX86_RZ_SAE,
|
||||||
|
//! AVX-512: Mask of all possible AVX-512 options except EVEX prefix flag.
|
||||||
|
kX86_AVX512Mask = 0x00FC0000u,
|
||||||
|
|
||||||
|
//! Force REX.B and/or VEX.B field (X64 only).
|
||||||
|
kX86_OpCodeB = 0x01000000u,
|
||||||
|
//! Force REX.X and/or VEX.X field (X64 only).
|
||||||
|
kX86_OpCodeX = 0x02000000u,
|
||||||
|
//! Force REX.R and/or VEX.R field (X64 only).
|
||||||
|
kX86_OpCodeR = 0x04000000u,
|
||||||
|
//! Force REX.W and/or VEX.W field (X64 only).
|
||||||
|
kX86_OpCodeW = 0x08000000u,
|
||||||
|
//! Force REX prefix (X64 only).
|
||||||
|
kX86_Rex = 0x40000000u,
|
||||||
|
//! Invalid REX prefix (set by X86 or when AH|BH|CH|DH regs are used on X64).
|
||||||
|
kX86_InvalidRex = 0x80000000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(InstOptions)
|
||||||
|
|
||||||
|
//! Instruction control flow.
|
||||||
|
enum class InstControlFlow : uint32_t {
|
||||||
|
//! Regular instruction.
|
||||||
|
kRegular = 0u,
|
||||||
|
//! Unconditional jump.
|
||||||
|
kJump = 1u,
|
||||||
|
//! Conditional jump (branch).
|
||||||
|
kBranch = 2u,
|
||||||
|
//! Function call.
|
||||||
|
kCall = 3u,
|
||||||
|
//! Function return.
|
||||||
|
kReturn = 4u,
|
||||||
|
|
||||||
|
//! Maximum value of `InstType`.
|
||||||
|
kMaxValue = kReturn
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Hint that is used when both input operands to the instruction are the same.
|
||||||
|
//!
|
||||||
|
//! Provides hints to the instrution RW query regarding special cases in which two or more operands are the same
|
||||||
|
//! registers. This is required by instructions such as XOR, AND, OR, SUB, etc... These hints will influence the
|
||||||
|
//! RW operations query.
|
||||||
|
enum class InstSameRegHint : uint8_t {
|
||||||
|
//! No special handling.
|
||||||
|
kNone = 0,
|
||||||
|
//! Operands become read-only, the operation doesn't change the content - `X & X` and similar.
|
||||||
|
kRO = 1,
|
||||||
|
//! Operands become write-only, the content of the input(s) don't matter - `X ^ X`, `X - X`, and similar.
|
||||||
|
kWO = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Instruction id, options, and extraReg in a single structure. This structure exists mainly to simplify analysis
|
||||||
|
//! and validation API that requires `BaseInst` and `Operand[]` array.
|
||||||
class BaseInst {
|
class BaseInst {
|
||||||
public:
|
public:
|
||||||
//! Instruction id, see \ref BaseInst::Id or {arch-specific}::Inst::Id.
|
//! \name Members
|
||||||
uint32_t _id;
|
//! \{
|
||||||
//! Instruction options, see \ref BaseInst::Options or {arch-specific}::Inst::Options.
|
|
||||||
uint32_t _options;
|
//! Instruction id.
|
||||||
//! Extra register used by instruction (either REP register or AVX-512 selector).
|
InstId _id;
|
||||||
|
//! Instruction options.
|
||||||
|
InstOptions _options;
|
||||||
|
//! Extra register used by the instruction (either REP register or AVX-512 selector).
|
||||||
RegOnly _extraReg;
|
RegOnly _extraReg;
|
||||||
|
|
||||||
enum Id : uint32_t {
|
enum Id : uint32_t {
|
||||||
@@ -57,110 +198,39 @@ public:
|
|||||||
kIdAbstract = 0x80000000u
|
kIdAbstract = 0x80000000u
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Options : uint32_t {
|
//! \}
|
||||||
//! Used internally by emitters for handling errors and rare cases.
|
|
||||||
kOptionReserved = 0x00000001u,
|
|
||||||
|
|
||||||
//! Prevents following a jump during compilation (BaseCompiler).
|
|
||||||
kOptionUnfollow = 0x00000002u,
|
|
||||||
|
|
||||||
//! Overwrite the destination operand(s) (BaseCompiler).
|
|
||||||
//!
|
|
||||||
//! Hint that is important for register liveness analysis. It tells the
|
|
||||||
//! compiler that the destination operand will be overwritten now or by
|
|
||||||
//! adjacent instructions. BaseCompiler knows when a register is completely
|
|
||||||
//! overwritten by a single instruction, for example you don't have to
|
|
||||||
//! mark "movaps" or "pxor x, x", however, if a pair of instructions is
|
|
||||||
//! used and the first of them doesn't completely overwrite the content
|
|
||||||
//! of the destination, BaseCompiler fails to mark that register as dead.
|
|
||||||
//!
|
|
||||||
//! X86 Specific
|
|
||||||
//! ------------
|
|
||||||
//!
|
|
||||||
//! - All instructions that always overwrite at least the size of the
|
|
||||||
//! register the virtual-register uses , for example "mov", "movq",
|
|
||||||
//! "movaps" don't need the overwrite option to be used - conversion,
|
|
||||||
//! shuffle, and other miscellaneous instructions included.
|
|
||||||
//!
|
|
||||||
//! - All instructions that clear the destination register if all operands
|
|
||||||
//! are the same, for example "xor x, x", "pcmpeqb x x", etc...
|
|
||||||
//!
|
|
||||||
//! - Consecutive instructions that partially overwrite the variable until
|
|
||||||
//! there is no old content require `BaseCompiler::overwrite()` to be used.
|
|
||||||
//! Some examples (not always the best use cases thought):
|
|
||||||
//!
|
|
||||||
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
|
|
||||||
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
|
|
||||||
//! - `mov al, ?` followed by `and ax, 0xFF`
|
|
||||||
//! - `mov al, ?` followed by `mov ah, al`
|
|
||||||
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
|
|
||||||
//!
|
|
||||||
//! - If allocated variable is used temporarily for scalar operations. For
|
|
||||||
//! example if you allocate a full vector like `x86::Compiler::newXmm()`
|
|
||||||
//! and then use that vector for scalar operations you should use
|
|
||||||
//! `overwrite()` directive:
|
|
||||||
//!
|
|
||||||
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't
|
|
||||||
//! use HI elements, use `compiler.overwrite().sqrtss(x, y)`.
|
|
||||||
kOptionOverwrite = 0x00000004u,
|
|
||||||
|
|
||||||
//! Emit short-form of the instruction.
|
|
||||||
kOptionShortForm = 0x00000010u,
|
|
||||||
//! Emit long-form of the instruction.
|
|
||||||
kOptionLongForm = 0x00000020u,
|
|
||||||
|
|
||||||
//! Conditional jump is likely to be taken.
|
|
||||||
kOptionTaken = 0x00000040u,
|
|
||||||
//! Conditional jump is unlikely to be taken.
|
|
||||||
kOptionNotTaken = 0x00000080u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Control type.
|
|
||||||
enum ControlType : uint32_t {
|
|
||||||
//! No control type (doesn't jump).
|
|
||||||
kControlNone = 0u,
|
|
||||||
//! Unconditional jump.
|
|
||||||
kControlJump = 1u,
|
|
||||||
//! Conditional jump (branch).
|
|
||||||
kControlBranch = 2u,
|
|
||||||
//! Function call.
|
|
||||||
kControlCall = 3u,
|
|
||||||
//! Function return.
|
|
||||||
kControlReturn = 4u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a new BaseInst instance with `id` and `options` set.
|
//! Creates a new BaseInst instance with `id` and `options` set.
|
||||||
//!
|
//!
|
||||||
//! Default values of `id` and `options` are zero, which means none instruction.
|
//! Default values of `id` and `options` are zero, which means 'none' instruction. Such instruction is guaranteed
|
||||||
//! Such instruction is guaranteed to never exist for any architecture supported
|
//! to never exist for any architecture supported by AsmJit.
|
||||||
//! by AsmJit.
|
inline explicit BaseInst(InstId instId = 0, InstOptions options = InstOptions::kNone) noexcept
|
||||||
inline explicit BaseInst(uint32_t id = 0, uint32_t options = 0) noexcept
|
: _id(instId),
|
||||||
: _id(id),
|
|
||||||
_options(options),
|
_options(options),
|
||||||
_extraReg() {}
|
_extraReg() {}
|
||||||
|
|
||||||
inline BaseInst(uint32_t id, uint32_t options, const RegOnly& extraReg) noexcept
|
inline BaseInst(InstId instId, InstOptions options, const RegOnly& extraReg) noexcept
|
||||||
: _id(id),
|
: _id(instId),
|
||||||
_options(options),
|
_options(options),
|
||||||
_extraReg(extraReg) {}
|
_extraReg(extraReg) {}
|
||||||
|
|
||||||
inline BaseInst(uint32_t id, uint32_t options, const BaseReg& extraReg) noexcept
|
inline BaseInst(InstId instId, InstOptions options, const BaseReg& extraReg) noexcept
|
||||||
: _id(id),
|
: _id(instId),
|
||||||
_options(options),
|
_options(options),
|
||||||
_extraReg { extraReg.signature(), extraReg.id() } {}
|
_extraReg { extraReg.signature(), extraReg.id() } {}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Instruction ID
|
//! \name Instruction Id
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the instruction id.
|
//! Returns the instruction id.
|
||||||
inline uint32_t id() const noexcept { return _id; }
|
inline InstId id() const noexcept { return _id; }
|
||||||
//! Sets the instruction id to the given `id`.
|
//! Sets the instruction id to the given `id`.
|
||||||
inline void setId(uint32_t id) noexcept { _id = id; }
|
inline void setId(InstId id) noexcept { _id = id; }
|
||||||
//! Resets the instruction id to zero, see \ref kIdNone.
|
//! Resets the instruction id to zero, see \ref kIdNone.
|
||||||
inline void resetId() noexcept { _id = 0; }
|
inline void resetId() noexcept { _id = 0; }
|
||||||
|
|
||||||
@@ -169,12 +239,12 @@ public:
|
|||||||
//! \name Instruction Options
|
//! \name Instruction Options
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline uint32_t options() const noexcept { return _options; }
|
inline InstOptions options() const noexcept { return _options; }
|
||||||
inline bool hasOption(uint32_t option) const noexcept { return (_options & option) != 0; }
|
inline bool hasOption(InstOptions option) const noexcept { return Support::test(_options, option); }
|
||||||
inline void setOptions(uint32_t options) noexcept { _options = options; }
|
inline void setOptions(InstOptions options) noexcept { _options = options; }
|
||||||
inline void addOptions(uint32_t options) noexcept { _options |= options; }
|
inline void addOptions(InstOptions options) noexcept { _options |= options; }
|
||||||
inline void clearOptions(uint32_t options) noexcept { _options &= ~options; }
|
inline void clearOptions(InstOptions options) noexcept { _options &= ~options; }
|
||||||
inline void resetOptions() noexcept { _options = 0; }
|
inline void resetOptions() noexcept { _options = InstOptions::kNone; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -191,20 +261,144 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! CPU read/write flags used by \ref InstRWInfo.
|
||||||
// [asmjit::OpRWInfo]
|
//!
|
||||||
// ============================================================================
|
//! These flags can be used to get a basic overview about CPU specifics flags used by instructions.
|
||||||
|
enum class CpuRWFlags : uint32_t {
|
||||||
|
//! No flags.
|
||||||
|
kNone = 0x00000000u,
|
||||||
|
|
||||||
|
// Common RW Flags (0x000000FF)
|
||||||
|
// ----------------------------
|
||||||
|
|
||||||
|
//! Carry flag.
|
||||||
|
kCF = 0x00000001u,
|
||||||
|
//! Signed overflow flag.
|
||||||
|
kOF = 0x00000002u,
|
||||||
|
//! Sign flag (negative/sign, if set).
|
||||||
|
kSF = 0x00000004u,
|
||||||
|
//! Zero and/or equality flag (1 if zero/equal).
|
||||||
|
kZF = 0x00000008u,
|
||||||
|
|
||||||
|
// X86 Specific RW Flags (0xFFFFFF00)
|
||||||
|
// ----------------------------------
|
||||||
|
|
||||||
|
//! Carry flag (X86, X86_64).
|
||||||
|
kX86_CF = kCF,
|
||||||
|
//! Overflow flag (X86, X86_64).
|
||||||
|
kX86_OF = kOF,
|
||||||
|
//! Sign flag (X86, X86_64).
|
||||||
|
kX86_SF = kSF,
|
||||||
|
//! Zero flag (X86, X86_64).
|
||||||
|
kX86_ZF = kZF,
|
||||||
|
|
||||||
|
//! Adjust flag (X86, X86_64).
|
||||||
|
kX86_AF = 0x00000100u,
|
||||||
|
//! Parity flag (X86, X86_64).
|
||||||
|
kX86_PF = 0x00000200u,
|
||||||
|
//! Direction flag (X86, X86_64).
|
||||||
|
kX86_DF = 0x00000400u,
|
||||||
|
//! Interrupt enable flag (X86, X86_64).
|
||||||
|
kX86_IF = 0x00000800u,
|
||||||
|
|
||||||
|
//! Alignment check flag (X86, X86_64).
|
||||||
|
kX86_AC = 0x00001000u,
|
||||||
|
|
||||||
|
//! FPU C0 status flag (X86, X86_64).
|
||||||
|
kX86_C0 = 0x00010000u,
|
||||||
|
//! FPU C1 status flag (X86, X86_64).
|
||||||
|
kX86_C1 = 0x00020000u,
|
||||||
|
//! FPU C2 status flag (X86, X86_64).
|
||||||
|
kX86_C2 = 0x00040000u,
|
||||||
|
//! FPU C3 status flag (X86, X86_64).
|
||||||
|
kX86_C3 = 0x00080000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(CpuRWFlags)
|
||||||
|
|
||||||
|
//! Operand read/write flags describe how the operand is accessed and some additional features.
|
||||||
|
enum class OpRWFlags {
|
||||||
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Operand is read.
|
||||||
|
kRead = 0x00000001u,
|
||||||
|
|
||||||
|
//! Operand is written.
|
||||||
|
kWrite = 0x00000002u,
|
||||||
|
|
||||||
|
//! Operand is both read and written.
|
||||||
|
kRW = 0x00000003u,
|
||||||
|
|
||||||
|
//! Register operand can be replaced by a memory operand.
|
||||||
|
kRegMem = 0x00000004u,
|
||||||
|
|
||||||
|
//! The register must be allocated to the index of the previous register + 1.
|
||||||
|
//!
|
||||||
|
//! 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
|
||||||
|
//! X86/X86_64 architecture this is used by instructions such as V4FMADDPS, V4FMADDSS, V4FNMADDPS, V4FNMADDSS,
|
||||||
|
//! VP4DPWSSD, VP4DPWSSDS, VP2INTERSECTD, and VP2INTERSECTQ. On ARM/AArch64 this is used by vector load and store
|
||||||
|
//! instructions that can load or store multiple registers at once.
|
||||||
|
kConsecutive = 0x00000008u,
|
||||||
|
|
||||||
|
//! The `extendByteMask()` represents a zero extension.
|
||||||
|
kZExt = 0x00000010u,
|
||||||
|
|
||||||
|
//! Register operand must use \ref OpRWInfo::physId().
|
||||||
|
kRegPhysId = 0x00000100u,
|
||||||
|
//! Base register of a memory operand must use \ref OpRWInfo::physId().
|
||||||
|
kMemPhysId = 0x00000200u,
|
||||||
|
|
||||||
|
//! This memory operand is only used to encode registers and doesn't access memory.
|
||||||
|
//!
|
||||||
|
//! X86 Specific
|
||||||
|
//! ------------
|
||||||
|
//!
|
||||||
|
//! Instructions that use such feature include BNDLDX, BNDSTX, and LEA.
|
||||||
|
kMemFake = 0x000000400u,
|
||||||
|
|
||||||
|
//! Base register of the memory operand will be read.
|
||||||
|
kMemBaseRead = 0x00001000u,
|
||||||
|
//! Base register of the memory operand will be written.
|
||||||
|
kMemBaseWrite = 0x00002000u,
|
||||||
|
//! Base register of the memory operand will be read & written.
|
||||||
|
kMemBaseRW = 0x00003000u,
|
||||||
|
|
||||||
|
//! Index register of the memory operand will be read.
|
||||||
|
kMemIndexRead = 0x00004000u,
|
||||||
|
//! Index register of the memory operand will be written.
|
||||||
|
kMemIndexWrite = 0x00008000u,
|
||||||
|
//! Index register of the memory operand will be read & written.
|
||||||
|
kMemIndexRW = 0x0000C000u,
|
||||||
|
|
||||||
|
//! Base register of the memory operand will be modified before the operation.
|
||||||
|
kMemBasePreModify = 0x00010000u,
|
||||||
|
//! Base register of the memory operand will be modified after the operation.
|
||||||
|
kMemBasePostModify = 0x00020000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(OpRWFlags)
|
||||||
|
|
||||||
|
// Don't remove these asserts. Read/Write flags are used extensively
|
||||||
|
// by Compiler and they must always be compatible with constants below.
|
||||||
|
static_assert(uint32_t(OpRWFlags::kRead) == 0x1, "OpRWFlags::kRead flag must be 0x1");
|
||||||
|
static_assert(uint32_t(OpRWFlags::kWrite) == 0x2, "OpRWFlags::kWrite flag must be 0x2");
|
||||||
|
static_assert(uint32_t(OpRWFlags::kRegMem) == 0x4, "OpRWFlags::kRegMem flag must be 0x4");
|
||||||
|
|
||||||
//! Read/Write information related to a single operand, used by \ref InstRWInfo.
|
//! Read/Write information related to a single operand, used by \ref InstRWInfo.
|
||||||
struct OpRWInfo {
|
struct OpRWInfo {
|
||||||
//! Read/Write flags, see \ref OpRWInfo::Flags.
|
//! \name Members
|
||||||
uint32_t _opFlags;
|
//! \{
|
||||||
|
|
||||||
|
//! Read/Write flags.
|
||||||
|
OpRWFlags _opFlags;
|
||||||
//! Physical register index, if required.
|
//! Physical register index, if required.
|
||||||
uint8_t _physId;
|
uint8_t _physId;
|
||||||
//! Size of a possible memory operand that can replace a register operand.
|
//! Size of a possible memory operand that can replace a register operand.
|
||||||
uint8_t _rmSize;
|
uint8_t _rmSize;
|
||||||
|
//! If non-zero, then this is a consecutive lead register, and the value describes how many registers follow.
|
||||||
|
uint8_t _consecutiveLeadCount;
|
||||||
//! Reserved for future use.
|
//! Reserved for future use.
|
||||||
uint8_t _reserved[2];
|
uint8_t _reserved[1];
|
||||||
//! Read bit-mask where each bit represents one byte read from Reg/Mem.
|
//! Read bit-mask where each bit represents one byte read from Reg/Mem.
|
||||||
uint64_t _readByteMask;
|
uint64_t _readByteMask;
|
||||||
//! Write bit-mask where each bit represents one byte written to Reg/Mem.
|
//! Write bit-mask where each bit represents one byte written to Reg/Mem.
|
||||||
@@ -212,61 +406,7 @@ struct OpRWInfo {
|
|||||||
//! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem.
|
//! Zero/Sign extend bit-mask where each bit represents one byte written to Reg/Mem.
|
||||||
uint64_t _extendByteMask;
|
uint64_t _extendByteMask;
|
||||||
|
|
||||||
//! Flags describe how the operand is accessed and some additional information.
|
//! \}
|
||||||
enum Flags : uint32_t {
|
|
||||||
//! Operand is read.
|
|
||||||
kRead = 0x00000001u,
|
|
||||||
|
|
||||||
//! Operand is written.
|
|
||||||
kWrite = 0x00000002u,
|
|
||||||
|
|
||||||
//! Operand is both read and written.
|
|
||||||
kRW = 0x00000003u,
|
|
||||||
|
|
||||||
//! Register operand can be replaced by a memory operand.
|
|
||||||
kRegMem = 0x00000004u,
|
|
||||||
|
|
||||||
//! The `extendByteMask()` represents a zero extension.
|
|
||||||
kZExt = 0x00000010u,
|
|
||||||
|
|
||||||
//! Register operand must use \ref physId().
|
|
||||||
kRegPhysId = 0x00000100u,
|
|
||||||
//! Base register of a memory operand must use \ref physId().
|
|
||||||
kMemPhysId = 0x00000200u,
|
|
||||||
|
|
||||||
//! This memory operand is only used to encode registers and doesn't access memory.
|
|
||||||
//!
|
|
||||||
//! X86 Specific
|
|
||||||
//! ------------
|
|
||||||
//!
|
|
||||||
//! Instructions that use such feature include BNDLDX, BNDSTX, and LEA.
|
|
||||||
kMemFake = 0x000000400u,
|
|
||||||
|
|
||||||
//! Base register of the memory operand will be read.
|
|
||||||
kMemBaseRead = 0x00001000u,
|
|
||||||
//! Base register of the memory operand will be written.
|
|
||||||
kMemBaseWrite = 0x00002000u,
|
|
||||||
//! Base register of the memory operand will be read & written.
|
|
||||||
kMemBaseRW = 0x00003000u,
|
|
||||||
|
|
||||||
//! Index register of the memory operand will be read.
|
|
||||||
kMemIndexRead = 0x00004000u,
|
|
||||||
//! Index register of the memory operand will be written.
|
|
||||||
kMemIndexWrite = 0x00008000u,
|
|
||||||
//! Index register of the memory operand will be read & written.
|
|
||||||
kMemIndexRW = 0x0000C000u,
|
|
||||||
|
|
||||||
//! Base register of the memory operand will be modified before the operation.
|
|
||||||
kMemBasePreModify = 0x00010000u,
|
|
||||||
//! Base register of the memory operand will be modified after the operation.
|
|
||||||
kMemBasePostModify = 0x00020000u
|
|
||||||
};
|
|
||||||
|
|
||||||
// Don't remove these asserts. Read/Write flags are used extensively
|
|
||||||
// by Compiler and they must always be compatible with constants below.
|
|
||||||
static_assert(kRead == 0x1, "OpRWInfo::kRead flag must be 0x1");
|
|
||||||
static_assert(kWrite == 0x2, "OpRWInfo::kWrite flag must be 0x2");
|
|
||||||
static_assert(kRegMem == 0x4, "OpRWInfo::kRegMem flag must be 0x4");
|
|
||||||
|
|
||||||
//! \name Reset
|
//! \name Reset
|
||||||
//! \{
|
//! \{
|
||||||
@@ -276,20 +416,21 @@ 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(uint32_t opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept {
|
inline void reset(OpRWFlags opFlags, uint32_t regSize, uint32_t physId = BaseReg::kIdBad) noexcept {
|
||||||
_opFlags = opFlags;
|
_opFlags = opFlags;
|
||||||
_physId = uint8_t(physId);
|
_physId = uint8_t(physId);
|
||||||
_rmSize = uint8_t((opFlags & kRegMem) ? regSize : uint32_t(0));
|
_rmSize = Support::test(opFlags, OpRWFlags::kRegMem) ? uint8_t(regSize) : uint8_t(0);
|
||||||
|
_consecutiveLeadCount = 0;
|
||||||
_resetReserved();
|
_resetReserved();
|
||||||
|
|
||||||
uint64_t mask = Support::lsbMask<uint64_t>(regSize);
|
uint64_t mask = Support::lsbMask<uint64_t>(regSize);
|
||||||
_readByteMask = opFlags & kRead ? mask : uint64_t(0);
|
_readByteMask = Support::test(opFlags, OpRWFlags::kRead) ? mask : uint64_t(0);
|
||||||
_writeByteMask = opFlags & kWrite ? mask : uint64_t(0);
|
_writeByteMask = Support::test(opFlags, OpRWFlags::kWrite) ? mask : uint64_t(0);
|
||||||
_extendByteMask = 0;
|
_extendByteMask = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void _resetReserved() noexcept {
|
inline void _resetReserved() noexcept {
|
||||||
memset(_reserved, 0, sizeof(_reserved));
|
_reserved[0] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -297,77 +438,77 @@ struct OpRWInfo {
|
|||||||
//! \name Operand Flags
|
//! \name Operand Flags
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns operand flags, see \ref Flags.
|
//! Returns operand flags.
|
||||||
inline uint32_t opFlags() const noexcept { return _opFlags; }
|
inline OpRWFlags opFlags() const noexcept { return _opFlags; }
|
||||||
//! Tests whether operand flags contain the given `flag`.
|
//! Tests whether operand flags contain the given `flag`.
|
||||||
inline bool hasOpFlag(uint32_t flag) const noexcept { return (_opFlags & flag) != 0; }
|
inline bool hasOpFlag(OpRWFlags flag) const noexcept { return Support::test(_opFlags, flag); }
|
||||||
|
|
||||||
//! Adds the given `flags` to operand flags.
|
//! Adds the given `flags` to operand flags.
|
||||||
inline void addOpFlags(uint32_t flags) noexcept { _opFlags |= flags; }
|
inline void addOpFlags(OpRWFlags flags) noexcept { _opFlags |= flags; }
|
||||||
//! Removes the given `flags` from operand flags.
|
//! Removes the given `flags` from operand flags.
|
||||||
inline void clearOpFlags(uint32_t flags) noexcept { _opFlags &= ~flags; }
|
inline void clearOpFlags(OpRWFlags flags) noexcept { _opFlags &= ~flags; }
|
||||||
|
|
||||||
//! Tests whether this operand is read from.
|
//! Tests whether this operand is read from.
|
||||||
inline bool isRead() const noexcept { return hasOpFlag(kRead); }
|
inline bool isRead() const noexcept { return hasOpFlag(OpRWFlags::kRead); }
|
||||||
//! Tests whether this operand is written to.
|
//! Tests whether this operand is written to.
|
||||||
inline bool isWrite() const noexcept { return hasOpFlag(kWrite); }
|
inline bool isWrite() const noexcept { return hasOpFlag(OpRWFlags::kWrite); }
|
||||||
//! Tests whether this operand is both read and write.
|
//! Tests whether this operand is both read and write.
|
||||||
inline bool isReadWrite() const noexcept { return (_opFlags & kRW) == kRW; }
|
inline bool isReadWrite() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRW; }
|
||||||
//! Tests whether this operand is read only.
|
//! Tests whether this operand is read only.
|
||||||
inline bool isReadOnly() const noexcept { return (_opFlags & kRW) == kRead; }
|
inline bool isReadOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kRead; }
|
||||||
//! Tests whether this operand is write only.
|
//! Tests whether this operand is write only.
|
||||||
inline bool isWriteOnly() const noexcept { return (_opFlags & kRW) == kWrite; }
|
inline bool isWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kRW) == OpRWFlags::kWrite; }
|
||||||
|
|
||||||
|
//! Returns the type of a lead register, which is followed by consecutive registers.
|
||||||
|
inline uint32_t consecutiveLeadCount() const noexcept { return _consecutiveLeadCount; }
|
||||||
|
|
||||||
//! Tests whether this operand is Reg/Mem
|
//! Tests whether this operand is Reg/Mem
|
||||||
//!
|
//!
|
||||||
//! Reg/Mem operands can use either register or memory.
|
//! Reg/Mem operands can use either register or memory.
|
||||||
inline bool isRm() const noexcept { return hasOpFlag(kRegMem); }
|
inline bool isRm() const noexcept { return hasOpFlag(OpRWFlags::kRegMem); }
|
||||||
|
|
||||||
//! Tests whether the operand will be zero extended.
|
//! Tests whether the operand will be zero extended.
|
||||||
inline bool isZExt() const noexcept { return hasOpFlag(kZExt); }
|
inline bool isZExt() const noexcept { return hasOpFlag(OpRWFlags::kZExt); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Memory Flags
|
//! \name Memory Flags
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Tests whether this is a fake memory operand, which is only used, because
|
//! Tests whether this is a fake memory operand, which is only used, because of encoding. Fake memory operands do
|
||||||
//! of encoding. Fake memory operands do not access any memory, they are only
|
//! not access any memory, they are only used to encode registers.
|
||||||
//! used to encode registers.
|
inline bool isMemFake() const noexcept { return hasOpFlag(OpRWFlags::kMemFake); }
|
||||||
inline bool isMemFake() const noexcept { return hasOpFlag(kMemFake); }
|
|
||||||
|
|
||||||
//! Tests whether the instruction's memory BASE register is used.
|
//! Tests whether the instruction's memory BASE register is used.
|
||||||
inline bool isMemBaseUsed() const noexcept { return (_opFlags & kMemBaseRW) != 0; }
|
inline bool isMemBaseUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRW); }
|
||||||
//! Tests whether the instruction reads from its BASE registers.
|
//! Tests whether the instruction reads from its BASE registers.
|
||||||
inline bool isMemBaseRead() const noexcept { return hasOpFlag(kMemBaseRead); }
|
inline bool isMemBaseRead() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseRead); }
|
||||||
//! Tests whether the instruction writes to its BASE registers.
|
//! Tests whether the instruction writes to its BASE registers.
|
||||||
inline bool isMemBaseWrite() const noexcept { return hasOpFlag(kMemBaseWrite); }
|
inline bool isMemBaseWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemBaseWrite); }
|
||||||
//! Tests whether the instruction reads and writes from/to its BASE registers.
|
//! Tests whether the instruction reads and writes from/to its BASE registers.
|
||||||
inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRW; }
|
inline bool isMemBaseReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRW; }
|
||||||
//! Tests whether the instruction only reads from its BASE registers.
|
//! Tests whether the instruction only reads from its BASE registers.
|
||||||
inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseRead; }
|
inline bool isMemBaseReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseRead; }
|
||||||
//! Tests whether the instruction only writes to its BASE registers.
|
//! Tests whether the instruction only writes to its BASE registers.
|
||||||
inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & kMemBaseRW) == kMemBaseWrite; }
|
inline bool isMemBaseWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemBaseRW) == OpRWFlags::kMemBaseWrite; }
|
||||||
|
|
||||||
//! Tests whether the instruction modifies the BASE register before it uses
|
//! Tests whether the instruction modifies the BASE register before it uses it to calculate the target address.
|
||||||
//! it to calculate the target address.
|
inline bool isMemBasePreModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePreModify); }
|
||||||
inline bool isMemBasePreModify() const noexcept { return hasOpFlag(kMemBasePreModify); }
|
//! Tests whether the instruction modifies the BASE register after it uses it to calculate the target address.
|
||||||
//! Tests whether the instruction modifies the BASE register after it uses
|
inline bool isMemBasePostModify() const noexcept { return hasOpFlag(OpRWFlags::kMemBasePostModify); }
|
||||||
//! it to calculate the target address.
|
|
||||||
inline bool isMemBasePostModify() const noexcept { return hasOpFlag(kMemBasePostModify); }
|
|
||||||
|
|
||||||
//! Tests whether the instruction's memory INDEX register is used.
|
//! Tests whether the instruction's memory INDEX register is used.
|
||||||
inline bool isMemIndexUsed() const noexcept { return (_opFlags & kMemIndexRW) != 0; }
|
inline bool isMemIndexUsed() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRW); }
|
||||||
//! Tests whether the instruction reads the INDEX registers.
|
//! Tests whether the instruction reads the INDEX registers.
|
||||||
inline bool isMemIndexRead() const noexcept { return hasOpFlag(kMemIndexRead); }
|
inline bool isMemIndexRead() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexRead); }
|
||||||
//! Tests whether the instruction writes to its INDEX registers.
|
//! Tests whether the instruction writes to its INDEX registers.
|
||||||
inline bool isMemIndexWrite() const noexcept { return hasOpFlag(kMemIndexWrite); }
|
inline bool isMemIndexWrite() const noexcept { return hasOpFlag(OpRWFlags::kMemIndexWrite); }
|
||||||
//! Tests whether the instruction reads and writes from/to its INDEX registers.
|
//! Tests whether the instruction reads and writes from/to its INDEX registers.
|
||||||
inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRW; }
|
inline bool isMemIndexReadWrite() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRW; }
|
||||||
//! Tests whether the instruction only reads from its INDEX registers.
|
//! Tests whether the instruction only reads from its INDEX registers.
|
||||||
inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexRead; }
|
inline bool isMemIndexReadOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexRead; }
|
||||||
//! Tests whether the instruction only writes to its INDEX registers.
|
//! Tests whether the instruction only writes to its INDEX registers.
|
||||||
inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & kMemIndexRW) == kMemIndexWrite; }
|
inline bool isMemIndexWriteOnly() const noexcept { return (_opFlags & OpRWFlags::kMemIndexRW) == OpRWFlags::kMemIndexWrite; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -415,18 +556,17 @@ struct OpRWInfo {
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::InstRWInfo]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Read/Write information of an instruction.
|
//! Read/Write information of an instruction.
|
||||||
struct InstRWInfo {
|
struct InstRWInfo {
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Instruction flags (there are no flags at the moment, this field is reserved).
|
//! Instruction flags (there are no flags at the moment, this field is reserved).
|
||||||
uint32_t _instFlags;
|
uint32_t _instFlags;
|
||||||
//! Mask of CPU flags read.
|
//! CPU flags read.
|
||||||
uint32_t _readFlags;
|
CpuRWFlags _readFlags;
|
||||||
//! Mask of CPU flags written.
|
//! CPU flags written.
|
||||||
uint32_t _writeFlags;
|
CpuRWFlags _writeFlags;
|
||||||
//! Count of operands.
|
//! Count of operands.
|
||||||
uint8_t _opCount;
|
uint8_t _opCount;
|
||||||
//! CPU feature required for replacing register operand with memory operand.
|
//! CPU feature required for replacing register operand with memory operand.
|
||||||
@@ -438,6 +578,8 @@ struct InstRWInfo {
|
|||||||
//! Read/Write info of instruction operands.
|
//! Read/Write info of instruction operands.
|
||||||
OpRWInfo _operands[Globals::kMaxOpCount];
|
OpRWInfo _operands[Globals::kMaxOpCount];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Commons
|
//! \name Commons
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -446,40 +588,29 @@ struct InstRWInfo {
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Instruction Flags
|
//! \name CPU Flags Information
|
||||||
//!
|
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline uint32_t instFlags() const noexcept { return _instFlags; }
|
//! Returns a mask of CPU flags read.
|
||||||
inline bool hasInstFlag(uint32_t flag) const noexcept { return (_instFlags & flag) != 0; }
|
inline CpuRWFlags readFlags() const noexcept { return _readFlags; }
|
||||||
|
//! Returns a mask of CPU flags written.
|
||||||
//! }
|
inline CpuRWFlags writeFlags() const noexcept { return _writeFlags; }
|
||||||
|
|
||||||
//! \name CPU Flags Read/Write Information
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Returns read flags of the instruction.
|
|
||||||
inline uint32_t readFlags() const noexcept { return _readFlags; }
|
|
||||||
//! Returns write flags of the instruction.
|
|
||||||
inline uint32_t writeFlags() const noexcept { return _writeFlags; }
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Reg/Mem Information
|
//! \name Reg/Mem Information
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the CPU feature required to replace a register operand with memory
|
//! Returns the CPU feature required to replace a register operand with memory operand. If the returned feature is
|
||||||
//! operand. If the returned feature is zero (none) then this instruction
|
//! zero (none) then this instruction either doesn't provide memory operand combination or there is no extra CPU
|
||||||
//! either doesn't provide memory operand combination or there is no extra
|
//! feature required.
|
||||||
//! CPU feature required.
|
|
||||||
//!
|
//!
|
||||||
//! X86 Specific
|
//! X86 Specific
|
||||||
//! ------------
|
//! ------------
|
||||||
//!
|
//!
|
||||||
//! Some AVX+ instructions may require extra features for replacing registers
|
//! Some AVX+ instructions may require extra features for replacing registers with memory operands, for example
|
||||||
//! with memory operands, for example VPSLLDQ instruction only supports
|
//! VPSLLDQ instruction only supports `vpslldq reg, reg, imm` combination on AVX/AVX2 capable CPUs and requires
|
||||||
//! 'reg/reg/imm' combination on AVX/AVX2 capable CPUs and requires AVX-512 for
|
//! AVX-512 for `vpslldq reg, mem, imm` combination.
|
||||||
//! 'reg/mem/imm' combination.
|
|
||||||
inline uint32_t rmFeature() const noexcept { return _rmFeature; }
|
inline uint32_t rmFeature() const noexcept { return _rmFeature; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -505,49 +636,43 @@ struct InstRWInfo {
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! Validation flags that can be used with \ref InstAPI::validate().
|
||||||
// [asmjit::InstAPI]
|
enum class ValidationFlags : uint32_t {
|
||||||
// ============================================================================
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
//! Allow virtual registers in the instruction.
|
||||||
|
kEnableVirtRegs = 0x01u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(ValidationFlags)
|
||||||
|
|
||||||
//! Instruction API.
|
//! Instruction API.
|
||||||
namespace InstAPI {
|
namespace InstAPI {
|
||||||
|
|
||||||
//! Validation flags that can be used with \ref InstAPI::validate().
|
|
||||||
enum ValidationFlags : uint32_t {
|
|
||||||
//! Allow virtual registers in the instruction.
|
|
||||||
kValidationFlagVirtRegs = 0x01u
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_TEXT
|
#ifndef ASMJIT_NO_TEXT
|
||||||
//! Appends the name of the instruction specified by `instId` and `instOptions`
|
//! Appends the name of the instruction specified by `instId` and `instOptions` into the `output` string.
|
||||||
//! into the `output` string.
|
|
||||||
//!
|
//!
|
||||||
//! \note Instruction options would only affect instruction prefix & suffix,
|
//! \note Instruction options would only affect instruction prefix & suffix, other options would be ignored.
|
||||||
//! other options would be ignored. If `instOptions` is zero then only raw
|
//! If `instOptions` is zero then only raw instruction name (without any additional text) will be appended.
|
||||||
//! instruction name (without any additional text) will be appended.
|
ASMJIT_API Error instIdToString(Arch arch, InstId instId, String& output) noexcept;
|
||||||
ASMJIT_API Error instIdToString(uint32_t arch, uint32_t instId, String& output) noexcept;
|
|
||||||
|
|
||||||
//! Parses an instruction name in the given string `s`. Length is specified
|
//! Parses an instruction name in the given string `s`. Length is specified by `len` argument, which can be
|
||||||
//! by `len` argument, which can be `SIZE_MAX` if `s` is known to be null
|
//! `SIZE_MAX` if `s` is known to be null terminated.
|
||||||
//! terminated.
|
|
||||||
//!
|
//!
|
||||||
//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such
|
//! Returns the parsed instruction id or \ref BaseInst::kIdNone if no such instruction exists.
|
||||||
//! instruction exists.
|
ASMJIT_API InstId stringToInstId(Arch arch, const char* s, size_t len) noexcept;
|
||||||
ASMJIT_API uint32_t stringToInstId(uint32_t arch, const char* s, size_t len) noexcept;
|
|
||||||
#endif // !ASMJIT_NO_TEXT
|
#endif // !ASMJIT_NO_TEXT
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_VALIDATION
|
#ifndef ASMJIT_NO_VALIDATION
|
||||||
//! Validates the given instruction considering the validation `flags`, see
|
//! Validates the given instruction considering the given `validationFlags`.
|
||||||
//! \ref ValidationFlags.
|
ASMJIT_API Error validate(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, ValidationFlags validationFlags = ValidationFlags::kNone) noexcept;
|
||||||
ASMJIT_API Error validate(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, uint32_t validationFlags = 0) noexcept;
|
|
||||||
#endif // !ASMJIT_NO_VALIDATION
|
#endif // !ASMJIT_NO_VALIDATION
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_INTROSPECTION
|
#ifndef ASMJIT_NO_INTROSPECTION
|
||||||
//! Gets Read/Write information of the given instruction.
|
//! Gets Read/Write information of the given instruction.
|
||||||
ASMJIT_API Error queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
|
ASMJIT_API Error queryRWInfo(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept;
|
||||||
|
|
||||||
//! Gets CPU features required by the given instruction.
|
//! Gets CPU features required by the given instruction.
|
||||||
ASMJIT_API Error queryFeatures(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, BaseFeatures* out) noexcept;
|
ASMJIT_API Error queryFeatures(Arch arch, const BaseInst& inst, const Operand_* operands, size_t opCount, CpuFeatures* out) noexcept;
|
||||||
#endif // !ASMJIT_NO_INTROSPECTION
|
#endif // !ASMJIT_NO_INTROSPECTION
|
||||||
|
|
||||||
} // {InstAPI}
|
} // {InstAPI}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_JIT
|
#ifndef ASMJIT_NO_JIT
|
||||||
@@ -35,24 +17,24 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Constants
|
||||||
// [asmjit::JitAllocator - Constants]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
enum JitAllocatorConstants : uint32_t {
|
//! Number of pools to use when `JitAllocatorOptions::kUseMultiplePools` is set.
|
||||||
//! Number of pools to use when `JitAllocator::kOptionUseMultiplePools` is set.
|
//!
|
||||||
//!
|
//! Each pool increases granularity twice to make memory management more
|
||||||
//! Each pool increases granularity twice to make memory management more
|
//! efficient. Ideal number of pools appears to be 3 to 4 as it distributes
|
||||||
//! efficient. Ideal number of pools appears to be 3 to 4 as it distributes
|
//! small and large functions properly.
|
||||||
//! small and large functions properly.
|
static constexpr uint32_t kJitAllocatorMultiPoolCount = 3;
|
||||||
kJitAllocatorMultiPoolCount = 3,
|
|
||||||
|
|
||||||
//! Minimum granularity (and the default granularity for pool #0).
|
//! Minimum granularity (and the default granularity for pool #0).
|
||||||
kJitAllocatorBaseGranularity = 64,
|
static constexpr uint32_t kJitAllocatorBaseGranularity = 64;
|
||||||
|
|
||||||
//! Maximum block size (32MB).
|
//! Maximum block size (32MB).
|
||||||
kJitAllocatorMaxBlockSize = 1024 * 1024 * 32
|
static constexpr uint32_t kJitAllocatorMaxBlockSize = 1024 * 1024 * 32;
|
||||||
};
|
|
||||||
|
// JitAllocator - Fill Pattern
|
||||||
|
// ===========================
|
||||||
|
|
||||||
static inline uint32_t JitAllocator_defaultFillPattern() noexcept {
|
static inline uint32_t JitAllocator_defaultFillPattern() noexcept {
|
||||||
// X86 and X86_64 - 4x 'int3' instruction.
|
// X86 and X86_64 - 4x 'int3' instruction.
|
||||||
@@ -63,9 +45,8 @@ static inline uint32_t JitAllocator_defaultFillPattern() noexcept {
|
|||||||
return 0u;
|
return 0u;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - BitVectorRangeIterator
|
||||||
// [asmjit::BitVectorRangeIterator]
|
// =====================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
template<typename T, uint32_t B>
|
template<typename T, uint32_t B>
|
||||||
class BitVectorRangeIterator {
|
class BitVectorRangeIterator {
|
||||||
@@ -78,19 +59,19 @@ public:
|
|||||||
enum : uint32_t { kBitWordSize = Support::bitSizeOf<T>() };
|
enum : uint32_t { kBitWordSize = Support::bitSizeOf<T>() };
|
||||||
enum : T { kXorMask = B == 0 ? Support::allOnes<T>() : T(0) };
|
enum : T { kXorMask = B == 0 ? Support::allOnes<T>() : T(0) };
|
||||||
|
|
||||||
ASMJIT_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords) noexcept {
|
ASMJIT_FORCE_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords) noexcept {
|
||||||
init(data, numBitWords);
|
init(data, numBitWords);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords, size_t start, size_t end) noexcept {
|
ASMJIT_FORCE_INLINE BitVectorRangeIterator(const T* data, size_t numBitWords, size_t start, size_t end) noexcept {
|
||||||
init(data, numBitWords, start, end);
|
init(data, numBitWords, start, end);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void init(const T* data, size_t numBitWords) noexcept {
|
ASMJIT_FORCE_INLINE void init(const T* data, size_t numBitWords) noexcept {
|
||||||
init(data, numBitWords, 0, numBitWords * kBitWordSize);
|
init(data, numBitWords, 0, numBitWords * kBitWordSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void init(const T* data, size_t numBitWords, size_t start, size_t end) noexcept {
|
ASMJIT_FORCE_INLINE void init(const T* data, size_t numBitWords, size_t start, size_t end) noexcept {
|
||||||
ASMJIT_ASSERT(numBitWords >= (end + kBitWordSize - 1) / kBitWordSize);
|
ASMJIT_ASSERT(numBitWords >= (end + kBitWordSize - 1) / kBitWordSize);
|
||||||
DebugUtils::unused(numBitWords);
|
DebugUtils::unused(numBitWords);
|
||||||
|
|
||||||
@@ -107,7 +88,7 @@ public:
|
|||||||
_bitWord = bitWord;
|
_bitWord = bitWord;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE bool nextRange(size_t* rangeStart, size_t* rangeEnd, size_t rangeHint = std::numeric_limits<size_t>::max()) noexcept {
|
ASMJIT_FORCE_INLINE bool nextRange(size_t* rangeStart, size_t* rangeEnd, size_t rangeHint = std::numeric_limits<size_t>::max()) noexcept {
|
||||||
// Skip all empty BitWords.
|
// Skip all empty BitWords.
|
||||||
while (_bitWord == 0) {
|
while (_bitWord == 0) {
|
||||||
_idx += kBitWordSize;
|
_idx += kBitWordSize;
|
||||||
@@ -153,9 +134,8 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Pool
|
||||||
// [asmjit::JitAllocator - Pool]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class JitAllocatorBlock;
|
class JitAllocatorBlock;
|
||||||
|
|
||||||
@@ -163,6 +143,27 @@ class JitAllocatorPool {
|
|||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(JitAllocatorPool)
|
ASMJIT_NONCOPYABLE(JitAllocatorPool)
|
||||||
|
|
||||||
|
//! Double linked list of blocks.
|
||||||
|
ZoneList<JitAllocatorBlock> blocks;
|
||||||
|
//! Where to start looking first.
|
||||||
|
JitAllocatorBlock* cursor;
|
||||||
|
|
||||||
|
//! Count of blocks.
|
||||||
|
uint32_t blockCount;
|
||||||
|
//! Allocation granularity.
|
||||||
|
uint16_t granularity;
|
||||||
|
//! Log2(granularity).
|
||||||
|
uint8_t granularityLog2;
|
||||||
|
//! Count of empty blocks (either 0 or 1 as we won't keep more blocks empty).
|
||||||
|
uint8_t emptyBlockCount;
|
||||||
|
|
||||||
|
//! Number of bits reserved across all blocks.
|
||||||
|
size_t totalAreaSize;
|
||||||
|
//! Number of bits used across all blocks.
|
||||||
|
size_t totalAreaUsed;
|
||||||
|
//! Overhead of all blocks (in bytes).
|
||||||
|
size_t totalOverheadBytes;
|
||||||
|
|
||||||
inline JitAllocatorPool(uint32_t granularity) noexcept
|
inline JitAllocatorPool(uint32_t granularity) noexcept
|
||||||
: blocks(),
|
: blocks(),
|
||||||
cursor(nullptr),
|
cursor(nullptr),
|
||||||
@@ -190,32 +191,10 @@ public:
|
|||||||
using namespace Support;
|
using namespace Support;
|
||||||
return alignUp<size_t>(areaSize, kBitWordSizeInBits) / kBitWordSizeInBits;
|
return alignUp<size_t>(areaSize, kBitWordSizeInBits) / kBitWordSizeInBits;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Double linked list of blocks.
|
|
||||||
ZoneList<JitAllocatorBlock> blocks;
|
|
||||||
//! Where to start looking first.
|
|
||||||
JitAllocatorBlock* cursor;
|
|
||||||
|
|
||||||
//! Count of blocks.
|
|
||||||
uint32_t blockCount;
|
|
||||||
//! Allocation granularity.
|
|
||||||
uint16_t granularity;
|
|
||||||
//! Log2(granularity).
|
|
||||||
uint8_t granularityLog2;
|
|
||||||
//! Count of empty blocks (either 0 or 1 as we won't keep more blocks empty).
|
|
||||||
uint8_t emptyBlockCount;
|
|
||||||
|
|
||||||
//! Number of bits reserved across all blocks.
|
|
||||||
size_t totalAreaSize;
|
|
||||||
//! Number of bits used across all blocks.
|
|
||||||
size_t totalAreaUsed;
|
|
||||||
//! Overhead of all blocks (in bytes).
|
|
||||||
size_t totalOverheadBytes;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Block
|
||||||
// [asmjit::JitAllocator - Block]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class JitAllocatorBlock : public ZoneTreeNodeT<JitAllocatorBlock>,
|
class JitAllocatorBlock : public ZoneTreeNodeT<JitAllocatorBlock>,
|
||||||
public ZoneListNode<JitAllocatorBlock> {
|
public ZoneListNode<JitAllocatorBlock> {
|
||||||
@@ -280,7 +259,7 @@ public:
|
|||||||
|
|
||||||
inline JitAllocatorPool* pool() const noexcept { return _pool; }
|
inline JitAllocatorPool* pool() const noexcept { return _pool; }
|
||||||
|
|
||||||
inline uint8_t* roPtr() const noexcept { return static_cast<uint8_t*>(_mapping.ro); }
|
inline uint8_t* rxPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rx); }
|
||||||
inline uint8_t* rwPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rw); }
|
inline uint8_t* rwPtr() const noexcept { return static_cast<uint8_t*>(_mapping.rw); }
|
||||||
|
|
||||||
inline bool hasFlag(uint32_t f) const noexcept { return (_flags & f) != 0; }
|
inline bool hasFlag(uint32_t f) const noexcept { return (_flags & f) != 0; }
|
||||||
@@ -376,30 +355,25 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RBTree default CMP uses '<' and '>' operators.
|
// RBTree default CMP uses '<' and '>' operators.
|
||||||
inline bool operator<(const JitAllocatorBlock& other) const noexcept { return roPtr() < other.roPtr(); }
|
inline bool operator<(const JitAllocatorBlock& other) const noexcept { return rxPtr() < other.rxPtr(); }
|
||||||
inline bool operator>(const JitAllocatorBlock& other) const noexcept { return roPtr() > other.roPtr(); }
|
inline 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 roPtr() + _blockSize <= key; }
|
inline bool operator<(const uint8_t* key) const noexcept { return rxPtr() + _blockSize <= key; }
|
||||||
inline bool operator>(const uint8_t* key) const noexcept { return roPtr() > key; }
|
inline bool operator>(const uint8_t* key) const noexcept { return rxPtr() > key; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - PrivateImpl
|
||||||
// [asmjit::JitAllocator - PrivateImpl]
|
// ==========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
class JitAllocatorPrivateImpl : public JitAllocator::Impl {
|
class JitAllocatorPrivateImpl : public JitAllocator::Impl {
|
||||||
public:
|
public:
|
||||||
inline JitAllocatorPrivateImpl(JitAllocatorPool* pools, size_t poolCount) noexcept
|
|
||||||
: JitAllocator::Impl {},
|
|
||||||
pools(pools),
|
|
||||||
poolCount(poolCount) {}
|
|
||||||
inline ~JitAllocatorPrivateImpl() noexcept {}
|
|
||||||
|
|
||||||
//! 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).
|
||||||
uint32_t pageSize;
|
uint32_t pageSize;
|
||||||
|
//! Number of active allocations.
|
||||||
|
size_t allocationCount;
|
||||||
|
|
||||||
//! Blocks from all pools in RBTree.
|
//! Blocks from all pools in RBTree.
|
||||||
ZoneTree<JitAllocatorBlock> tree;
|
ZoneTree<JitAllocatorBlock> tree;
|
||||||
@@ -407,14 +381,21 @@ public:
|
|||||||
JitAllocatorPool* pools;
|
JitAllocatorPool* pools;
|
||||||
//! Number of allocator pools.
|
//! Number of allocator pools.
|
||||||
size_t poolCount;
|
size_t poolCount;
|
||||||
|
|
||||||
|
inline JitAllocatorPrivateImpl(JitAllocatorPool* pools, size_t poolCount) noexcept
|
||||||
|
: JitAllocator::Impl {},
|
||||||
|
pageSize(0),
|
||||||
|
allocationCount(0),
|
||||||
|
pools(pools),
|
||||||
|
poolCount(poolCount) {}
|
||||||
|
inline ~JitAllocatorPrivateImpl() noexcept {}
|
||||||
};
|
};
|
||||||
|
|
||||||
static const JitAllocator::Impl JitAllocatorImpl_none {};
|
static const JitAllocator::Impl JitAllocatorImpl_none {};
|
||||||
static const JitAllocator::CreateParams JitAllocatorParams_none {};
|
static const JitAllocator::CreateParams JitAllocatorParams_none {};
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Utilities
|
||||||
// [asmjit::JitAllocator - Utilities]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
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();
|
||||||
@@ -422,14 +403,14 @@ static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::
|
|||||||
if (!params)
|
if (!params)
|
||||||
params = &JitAllocatorParams_none;
|
params = &JitAllocatorParams_none;
|
||||||
|
|
||||||
uint32_t options = params->options;
|
JitAllocatorOptions options = params->options;
|
||||||
uint32_t blockSize = params->blockSize;
|
uint32_t blockSize = params->blockSize;
|
||||||
uint32_t granularity = params->granularity;
|
uint32_t granularity = params->granularity;
|
||||||
uint32_t fillPattern = params->fillPattern;
|
uint32_t fillPattern = params->fillPattern;
|
||||||
|
|
||||||
// Setup pool count to [1..3].
|
// Setup pool count to [1..3].
|
||||||
size_t poolCount = 1;
|
size_t poolCount = 1;
|
||||||
if (options & JitAllocator::kOptionUseMultiplePools)
|
if (Support::test(options, JitAllocatorOptions::kUseMultiplePools))
|
||||||
poolCount = kJitAllocatorMultiPoolCount;;
|
poolCount = kJitAllocatorMultiPoolCount;;
|
||||||
|
|
||||||
// Setup block size [64kB..256MB].
|
// Setup block size [64kB..256MB].
|
||||||
@@ -441,7 +422,7 @@ static inline JitAllocatorPrivateImpl* JitAllocatorImpl_new(const JitAllocator::
|
|||||||
granularity = kJitAllocatorBaseGranularity;
|
granularity = kJitAllocatorBaseGranularity;
|
||||||
|
|
||||||
// Setup fill-pattern.
|
// Setup fill-pattern.
|
||||||
if (!(options & JitAllocator::kOptionCustomFillPattern))
|
if (uint32_t(options & JitAllocatorOptions::kCustomFillPattern) == 0)
|
||||||
fillPattern = JitAllocator_defaultFillPattern();
|
fillPattern = JitAllocator_defaultFillPattern();
|
||||||
|
|
||||||
size_t size = sizeof(JitAllocatorPrivateImpl) + sizeof(JitAllocatorPool) * poolCount;
|
size_t size = sizeof(JitAllocatorPrivateImpl) + sizeof(JitAllocatorPool) * poolCount;
|
||||||
@@ -533,26 +514,32 @@ static JitAllocatorBlock* JitAllocatorImpl_newBlock(JitAllocatorPrivateImpl* imp
|
|||||||
|
|
||||||
uint32_t blockFlags = 0;
|
uint32_t blockFlags = 0;
|
||||||
if (bitWords != nullptr) {
|
if (bitWords != nullptr) {
|
||||||
if (impl->options & JitAllocator::kOptionUseDualMapping) {
|
if (Support::test(impl->options, JitAllocatorOptions::kUseDualMapping)) {
|
||||||
err = VirtMem::allocDualMapping(&virtMem, blockSize, VirtMem::kAccessRWX);
|
err = VirtMem::allocDualMapping(&virtMem, blockSize, VirtMem::MemoryFlags::kAccessRWX);
|
||||||
blockFlags |= JitAllocatorBlock::kFlagDualMapped;
|
blockFlags |= JitAllocatorBlock::kFlagDualMapped;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
err = VirtMem::alloc(&virtMem.ro, blockSize, VirtMem::kAccessRWX);
|
err = VirtMem::alloc(&virtMem.rx, blockSize, VirtMem::MemoryFlags::kAccessRWX);
|
||||||
virtMem.rw = virtMem.ro;
|
virtMem.rw = virtMem.rx;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Out of memory.
|
// Out of memory.
|
||||||
if (ASMJIT_UNLIKELY(!block || !bitWords || err != kErrorOk)) {
|
if (ASMJIT_UNLIKELY(!block || !bitWords || err != kErrorOk)) {
|
||||||
if (bitWords) ::free(bitWords);
|
if (bitWords)
|
||||||
if (block) ::free(block);
|
::free(bitWords);
|
||||||
|
|
||||||
|
if (block)
|
||||||
|
::free(block);
|
||||||
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fill the memory if the secure mode is enabled.
|
// Fill the memory if the secure mode is enabled.
|
||||||
if (impl->options & JitAllocator::kOptionFillUnusedMemory)
|
if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory)) {
|
||||||
|
VirtMem::ProtectJitReadWriteScope scope(virtMem.rw, blockSize);
|
||||||
JitAllocatorImpl_fillPattern(virtMem.rw, impl->fillPattern, blockSize);
|
JitAllocatorImpl_fillPattern(virtMem.rw, impl->fillPattern, blockSize);
|
||||||
|
}
|
||||||
|
|
||||||
memset(bitWords, 0, size_t(numBitWords) * 2 * sizeof(BitWord));
|
memset(bitWords, 0, size_t(numBitWords) * 2 * sizeof(BitWord));
|
||||||
return new(block) JitAllocatorBlock(pool, virtMem, blockSize, blockFlags, bitWords, bitWords + numBitWords, areaSize);
|
return new(block) JitAllocatorBlock(pool, virtMem, blockSize, blockFlags, bitWords, bitWords + numBitWords, areaSize);
|
||||||
@@ -564,7 +551,7 @@ static void JitAllocatorImpl_deleteBlock(JitAllocatorPrivateImpl* impl, JitAlloc
|
|||||||
if (block->hasFlag(JitAllocatorBlock::kFlagDualMapped))
|
if (block->hasFlag(JitAllocatorBlock::kFlagDualMapped))
|
||||||
VirtMem::releaseDualMapping(&block->_mapping, block->blockSize());
|
VirtMem::releaseDualMapping(&block->_mapping, block->blockSize());
|
||||||
else
|
else
|
||||||
VirtMem::release(block->roPtr(), block->blockSize());
|
VirtMem::release(block->rxPtr(), block->blockSize());
|
||||||
|
|
||||||
::free(block->_usedBitVector);
|
::free(block->_usedBitVector);
|
||||||
::free(block);
|
::free(block);
|
||||||
@@ -603,26 +590,31 @@ static void JitAllocatorImpl_removeBlock(JitAllocatorPrivateImpl* impl, JitAlloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void JitAllocatorImpl_wipeOutBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept {
|
static void JitAllocatorImpl_wipeOutBlock(JitAllocatorPrivateImpl* impl, JitAllocatorBlock* block) noexcept {
|
||||||
JitAllocatorPool* pool = block->pool();
|
|
||||||
|
|
||||||
if (block->hasFlag(JitAllocatorBlock::kFlagEmpty))
|
if (block->hasFlag(JitAllocatorBlock::kFlagEmpty))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
JitAllocatorPool* pool = block->pool();
|
||||||
uint32_t areaSize = block->areaSize();
|
uint32_t areaSize = block->areaSize();
|
||||||
uint32_t granularity = pool->granularity;
|
uint32_t granularity = pool->granularity;
|
||||||
size_t numBitWords = pool->bitWordCountFromAreaSize(areaSize);
|
size_t numBitWords = pool->bitWordCountFromAreaSize(areaSize);
|
||||||
|
|
||||||
if (impl->options & JitAllocator::kOptionFillUnusedMemory) {
|
VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite);
|
||||||
|
if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory)) {
|
||||||
uint8_t* rwPtr = block->rwPtr();
|
uint8_t* rwPtr = block->rwPtr();
|
||||||
for (size_t i = 0; i < numBitWords; i++) {
|
BitVectorRangeIterator<Support::BitWord, 0> it(block->_usedBitVector, pool->bitWordCountFromAreaSize(block->areaSize()));
|
||||||
Support::BitWordIterator<Support::BitWord> it(block->_usedBitVector[i]);
|
|
||||||
while (it.hasNext()) {
|
size_t rangeStart;
|
||||||
size_t index = it.next();
|
size_t rangeEnd;
|
||||||
JitAllocatorImpl_fillPattern(rwPtr + index * granularity , impl->fillPattern, granularity);
|
|
||||||
}
|
while (it.nextRange(&rangeStart, &rangeEnd)) {
|
||||||
rwPtr += Support::bitSizeOf<Support::BitWord>() * granularity;
|
uint8_t* spanPtr = rwPtr + rangeStart * granularity;
|
||||||
|
size_t spanSize = (rangeEnd - rangeStart) * granularity;
|
||||||
|
|
||||||
|
JitAllocatorImpl_fillPattern(spanPtr, impl->fillPattern, spanSize);
|
||||||
|
VirtMem::flushInstructionCache(spanPtr, spanSize);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute);
|
||||||
|
|
||||||
memset(block->_usedBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord));
|
memset(block->_usedBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord));
|
||||||
memset(block->_stopBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord));
|
memset(block->_stopBitVector, 0, size_t(numBitWords) * sizeof(Support::BitWord));
|
||||||
@@ -635,9 +627,8 @@ static void JitAllocatorImpl_wipeOutBlock(JitAllocatorPrivateImpl* impl, JitAllo
|
|||||||
block->clearFlags(JitAllocatorBlock::kFlagDirty);
|
block->clearFlags(JitAllocatorBlock::kFlagDirty);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Construction & Destruction
|
||||||
// [asmjit::JitAllocator - Construction / Destruction]
|
// =========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
JitAllocator::JitAllocator(const CreateParams* params) noexcept {
|
JitAllocator::JitAllocator(const CreateParams* params) noexcept {
|
||||||
_impl = JitAllocatorImpl_new(params);
|
_impl = JitAllocatorImpl_new(params);
|
||||||
@@ -649,15 +640,14 @@ JitAllocator::~JitAllocator() noexcept {
|
|||||||
if (_impl == &JitAllocatorImpl_none)
|
if (_impl == &JitAllocatorImpl_none)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
reset(Globals::kResetHard);
|
reset(ResetPolicy::kHard);
|
||||||
JitAllocatorImpl_destroy(static_cast<JitAllocatorPrivateImpl*>(_impl));
|
JitAllocatorImpl_destroy(static_cast<JitAllocatorPrivateImpl*>(_impl));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Reset
|
||||||
// [asmjit::JitAllocator - Reset]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void JitAllocator::reset(uint32_t resetPolicy) noexcept {
|
void JitAllocator::reset(ResetPolicy resetPolicy) noexcept {
|
||||||
if (_impl == &JitAllocatorImpl_none)
|
if (_impl == &JitAllocatorImpl_none)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -670,7 +660,7 @@ void JitAllocator::reset(uint32_t resetPolicy) noexcept {
|
|||||||
JitAllocatorBlock* block = pool.blocks.first();
|
JitAllocatorBlock* block = pool.blocks.first();
|
||||||
|
|
||||||
JitAllocatorBlock* blockToKeep = nullptr;
|
JitAllocatorBlock* blockToKeep = nullptr;
|
||||||
if (resetPolicy != Globals::kResetHard && !(impl->options & kOptionImmediateRelease)) {
|
if (resetPolicy != ResetPolicy::kHard && uint32_t(impl->options & JitAllocatorOptions::kImmediateRelease) == 0) {
|
||||||
blockToKeep = block;
|
blockToKeep = block;
|
||||||
block = block->next();
|
block = block->next();
|
||||||
}
|
}
|
||||||
@@ -693,9 +683,8 @@ void JitAllocator::reset(uint32_t resetPolicy) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Statistics
|
||||||
// [asmjit::JitAllocator - Statistics]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
JitAllocator::Statistics JitAllocator::statistics() const noexcept {
|
JitAllocator::Statistics JitAllocator::statistics() const noexcept {
|
||||||
Statistics statistics;
|
Statistics statistics;
|
||||||
@@ -713,23 +702,24 @@ JitAllocator::Statistics JitAllocator::statistics() const noexcept {
|
|||||||
statistics._usedSize += size_t(pool.totalAreaUsed) * pool.granularity;
|
statistics._usedSize += size_t(pool.totalAreaUsed) * pool.granularity;
|
||||||
statistics._overheadSize += size_t(pool.totalOverheadBytes);
|
statistics._overheadSize += size_t(pool.totalOverheadBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
statistics._allocationCount = impl->allocationCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
return statistics;
|
return statistics;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Alloc & Release
|
||||||
// [asmjit::JitAllocator - Alloc / Release]
|
// ==============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error JitAllocator::alloc(void** roPtrOut, void** rwPtrOut, size_t size) noexcept {
|
Error JitAllocator::alloc(void** rxPtrOut, void** rwPtrOut, size_t size) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
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();
|
constexpr uint32_t kNoIndex = std::numeric_limits<uint32_t>::max();
|
||||||
|
|
||||||
*roPtrOut = nullptr;
|
*rxPtrOut = nullptr;
|
||||||
*rwPtrOut = nullptr;
|
*rwPtrOut = nullptr;
|
||||||
|
|
||||||
// Align to the minimum granularity by default.
|
// Align to the minimum granularity by default.
|
||||||
@@ -815,49 +805,56 @@ Error JitAllocator::alloc(void** roPtrOut, void** rwPtrOut, size_t size) noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Update statistics.
|
// Update statistics.
|
||||||
|
impl->allocationCount++;
|
||||||
block->markAllocatedArea(areaIndex, areaIndex + areaSize);
|
block->markAllocatedArea(areaIndex, areaIndex + areaSize);
|
||||||
|
|
||||||
// Return a pointer to the allocated memory.
|
// Return a pointer to the allocated memory.
|
||||||
size_t offset = pool->byteSizeFromAreaSize(areaIndex);
|
size_t offset = pool->byteSizeFromAreaSize(areaIndex);
|
||||||
ASMJIT_ASSERT(offset <= block->blockSize() - size);
|
ASMJIT_ASSERT(offset <= block->blockSize() - size);
|
||||||
|
|
||||||
*roPtrOut = block->roPtr() + offset;
|
*rxPtrOut = block->rxPtr() + offset;
|
||||||
*rwPtrOut = block->rwPtr() + offset;
|
*rwPtrOut = block->rwPtr() + offset;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error JitAllocator::release(void* roPtr) noexcept {
|
Error JitAllocator::release(void* rxPtr) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!roPtr))
|
if (ASMJIT_UNLIKELY(!rxPtr))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
||||||
LockGuard guard(impl->lock);
|
LockGuard guard(impl->lock);
|
||||||
|
|
||||||
JitAllocatorBlock* block = impl->tree.get(static_cast<uint8_t*>(roPtr));
|
JitAllocatorBlock* block = impl->tree.get(static_cast<uint8_t*>(rxPtr));
|
||||||
if (ASMJIT_UNLIKELY(!block))
|
if (ASMJIT_UNLIKELY(!block))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
// Offset relative to the start of the block.
|
// Offset relative to the start of the block.
|
||||||
JitAllocatorPool* pool = block->pool();
|
JitAllocatorPool* pool = block->pool();
|
||||||
size_t offset = (size_t)((uint8_t*)roPtr - block->roPtr());
|
size_t offset = (size_t)((uint8_t*)rxPtr - block->rxPtr());
|
||||||
|
|
||||||
// The first bit representing the allocated area and its size.
|
// The first bit representing the allocated area and its size.
|
||||||
uint32_t areaIndex = uint32_t(offset >> pool->granularityLog2);
|
uint32_t areaIndex = uint32_t(offset >> pool->granularityLog2);
|
||||||
uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaIndex, true)) + 1;
|
uint32_t areaEnd = uint32_t(Support::bitVectorIndexOf(block->_stopBitVector, areaIndex, true)) + 1;
|
||||||
uint32_t areaSize = areaEnd - areaIndex;
|
uint32_t areaSize = areaEnd - areaIndex;
|
||||||
|
|
||||||
|
impl->allocationCount--;
|
||||||
block->markReleasedArea(areaIndex, areaEnd);
|
block->markReleasedArea(areaIndex, areaEnd);
|
||||||
|
|
||||||
// Fill the released memory if the secure mode is enabled.
|
// Fill the released memory if the secure mode is enabled.
|
||||||
if (impl->options & kOptionFillUnusedMemory)
|
if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory)) {
|
||||||
JitAllocatorImpl_fillPattern(block->rwPtr() + areaIndex * pool->granularity, impl->fillPattern, areaSize * pool->granularity);
|
uint8_t* spanPtr = block->rwPtr() + areaIndex * pool->granularity;
|
||||||
|
size_t spanSize = areaSize * pool->granularity;
|
||||||
|
|
||||||
|
VirtMem::ProtectJitReadWriteScope scope(spanPtr, spanSize);
|
||||||
|
JitAllocatorImpl_fillPattern(spanPtr, impl->fillPattern, spanSize);
|
||||||
|
}
|
||||||
|
|
||||||
// Release the whole block if it became empty.
|
// Release the whole block if it became empty.
|
||||||
if (block->areaUsed() == 0) {
|
if (block->areaUsed() == 0) {
|
||||||
if (pool->emptyBlockCount || (impl->options & kOptionImmediateRelease)) {
|
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);
|
||||||
}
|
}
|
||||||
@@ -869,26 +866,26 @@ Error JitAllocator::release(void* roPtr) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error JitAllocator::shrink(void* roPtr, size_t newSize) noexcept {
|
Error JitAllocator::shrink(void* rxPtr, size_t newSize) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
if (ASMJIT_UNLIKELY(_impl == &JitAllocatorImpl_none))
|
||||||
return DebugUtils::errored(kErrorNotInitialized);
|
return DebugUtils::errored(kErrorNotInitialized);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!roPtr))
|
if (ASMJIT_UNLIKELY(!rxPtr))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(newSize == 0))
|
if (ASMJIT_UNLIKELY(newSize == 0))
|
||||||
return release(roPtr);
|
return release(rxPtr);
|
||||||
|
|
||||||
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
JitAllocatorPrivateImpl* impl = static_cast<JitAllocatorPrivateImpl*>(_impl);
|
||||||
LockGuard guard(impl->lock);
|
LockGuard guard(impl->lock);
|
||||||
JitAllocatorBlock* block = impl->tree.get(static_cast<uint8_t*>(roPtr));
|
JitAllocatorBlock* block = impl->tree.get(static_cast<uint8_t*>(rxPtr));
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!block))
|
if (ASMJIT_UNLIKELY(!block))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
// Offset relative to the start of the block.
|
// Offset relative to the start of the block.
|
||||||
JitAllocatorPool* pool = block->pool();
|
JitAllocatorPool* pool = block->pool();
|
||||||
size_t offset = (size_t)((uint8_t*)roPtr - block->roPtr());
|
size_t offset = (size_t)((uint8_t*)rxPtr - block->rxPtr());
|
||||||
|
|
||||||
// The first bit representing the allocated area and its size.
|
// The first bit representing the allocated area and its size.
|
||||||
uint32_t areaStart = uint32_t(offset >> pool->granularityLog2);
|
uint32_t areaStart = uint32_t(offset >> pool->granularityLog2);
|
||||||
@@ -905,16 +902,15 @@ Error JitAllocator::shrink(void* roPtr, size_t newSize) noexcept {
|
|||||||
block->markShrunkArea(areaStart + areaShrunkSize, areaEnd);
|
block->markShrunkArea(areaStart + areaShrunkSize, areaEnd);
|
||||||
|
|
||||||
// Fill released memory if the secure mode is enabled.
|
// Fill released memory if the secure mode is enabled.
|
||||||
if (impl->options & kOptionFillUnusedMemory)
|
if (Support::test(impl->options, JitAllocatorOptions::kFillUnusedMemory))
|
||||||
JitAllocatorImpl_fillPattern(block->rwPtr() + (areaStart + areaShrunkSize) * pool->granularity, fillPattern(), areaDiff * pool->granularity);
|
JitAllocatorImpl_fillPattern(block->rwPtr() + (areaStart + areaShrunkSize) * pool->granularity, fillPattern(), areaDiff * pool->granularity);
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// JitAllocator - Tests
|
||||||
// [asmjit::JitAllocator - Unit]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
// A pseudo random number generator based on a paper by Sebastiano Vigna:
|
// A pseudo random number generator based on a paper by Sebastiano Vigna:
|
||||||
@@ -1034,14 +1030,14 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void* alloc(size_t size) noexcept {
|
void* alloc(size_t size) noexcept {
|
||||||
void* roPtr;
|
void* rxPtr;
|
||||||
void* rwPtr;
|
void* rwPtr;
|
||||||
|
|
||||||
Error err = _allocator.alloc(&roPtr, &rwPtr, size);
|
Error err = _allocator.alloc(&rxPtr, &rwPtr, size);
|
||||||
EXPECT(err == kErrorOk, "JitAllocator failed to allocate %zu bytes\n", size);
|
EXPECT(err == kErrorOk, "JitAllocator failed to allocate %zu bytes\n", size);
|
||||||
|
|
||||||
_insert(roPtr, size);
|
_insert(rxPtr, size);
|
||||||
return roPtr;
|
return rxPtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void release(void* p) noexcept {
|
void release(void* p) noexcept {
|
||||||
@@ -1099,7 +1095,7 @@ static void BitVectorRangeIterator_testRandom(Random& rnd, size_t count) noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (size_t j = 0; j < kPatternSize; j++) {
|
for (size_t j = 0; j < kPatternSize; j++) {
|
||||||
EXPECT(in[j] == out[j], "Invalid pattern detected at [%zu] (%llX != %llX", j, (unsigned long long)in[j], (unsigned long long)out[j]);
|
EXPECT(in[j] == out[j], "Invalid pattern detected at [%zu] (%llX != %llX)", j, (unsigned long long)in[j], (unsigned long long)out[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1109,20 +1105,20 @@ UNIT(jit_allocator) {
|
|||||||
|
|
||||||
struct TestParams {
|
struct TestParams {
|
||||||
const char* name;
|
const char* name;
|
||||||
uint32_t options;
|
JitAllocatorOptions options;
|
||||||
uint32_t blockSize;
|
uint32_t blockSize;
|
||||||
uint32_t granularity;
|
uint32_t granularity;
|
||||||
};
|
};
|
||||||
|
|
||||||
static TestParams testParams[] = {
|
static TestParams testParams[] = {
|
||||||
{ "Default", 0, 0, 0 },
|
{ "Default", JitAllocatorOptions::kNone, 0, 0 },
|
||||||
{ "16MB blocks", 0, 16 * 1024 * 1024, 0 },
|
{ "16MB blocks", JitAllocatorOptions::kNone, 16 * 1024 * 1024, 0 },
|
||||||
{ "256B granularity", 0, 0, 256 },
|
{ "256B granularity", JitAllocatorOptions::kNone, 0, 256 },
|
||||||
{ "kOptionUseDualMapping", JitAllocator::kOptionUseDualMapping, 0, 0 },
|
{ "kUseDualMapping", JitAllocatorOptions::kUseDualMapping, 0, 0 },
|
||||||
{ "kOptionUseMultiplePools", JitAllocator::kOptionUseMultiplePools, 0, 0 },
|
{ "kUseMultiplePools", JitAllocatorOptions::kUseMultiplePools, 0, 0 },
|
||||||
{ "kOptionFillUnusedMemory", JitAllocator::kOptionFillUnusedMemory, 0, 0 },
|
{ "kFillUnusedMemory", JitAllocatorOptions::kFillUnusedMemory, 0, 0 },
|
||||||
{ "kOptionImmediateRelease", JitAllocator::kOptionImmediateRelease, 0, 0 },
|
{ "kImmediateRelease", JitAllocatorOptions::kImmediateRelease, 0, 0 },
|
||||||
{ "kOptionUseDualMapping | kOptionFillUnusedMemory", JitAllocator::kOptionUseDualMapping | JitAllocator::kOptionFillUnusedMemory, 0, 0 }
|
{ "kUseDualMapping | kFillUnusedMemory", JitAllocatorOptions::kUseDualMapping | JitAllocatorOptions::kFillUnusedMemory, 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
INFO("BitVectorRangeIterator<uint32_t>");
|
INFO("BitVectorRangeIterator<uint32_t>");
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
#ifndef ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
||||||
#define ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
#define ASMJIT_CORE_JITALLOCATOR_H_INCLUDED
|
||||||
@@ -35,37 +17,67 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_virtual_memory
|
//! \addtogroup asmjit_virtual_memory
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Options used by \ref JitAllocator.
|
||||||
// [asmjit::JitAllocator]
|
enum class JitAllocatorOptions : uint32_t {
|
||||||
// ============================================================================
|
//! No options.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Enables the use of an anonymous memory-mapped memory that is mapped into two buffers having a different pointer.
|
||||||
|
//! The first buffer has read and execute permissions and the second buffer has read+write permissions.
|
||||||
|
//!
|
||||||
|
//! See \ref VirtMem::allocDualMapping() for more details about this feature.
|
||||||
|
kUseDualMapping = 0x00000001u,
|
||||||
|
|
||||||
|
//! Enables the use of multiple pools with increasing granularity instead of a single pool. This flag would enable
|
||||||
|
//! 3 internal pools in total having 64, 128, and 256 bytes granularity.
|
||||||
|
//!
|
||||||
|
//! This feature is only recommended for users that generate a lot of code and would like to minimize the overhead
|
||||||
|
//! of `JitAllocator` itself by having blocks of different allocation granularities. Using this feature only for
|
||||||
|
//! few allocations won't pay off as the allocator may need to create more blocks initially before it can take the
|
||||||
|
//! advantage of variable block granularity.
|
||||||
|
kUseMultiplePools = 0x00000002u,
|
||||||
|
|
||||||
|
//! Always fill reserved memory by a fill-pattern.
|
||||||
|
//!
|
||||||
|
//! Causes a new block to be cleared by the fill pattern and freshly released memory to be cleared before making
|
||||||
|
//! it ready for another use.
|
||||||
|
kFillUnusedMemory = 0x00000004u,
|
||||||
|
|
||||||
|
//! When this flag is set the allocator would immediately release unused blocks during `release()` or `reset()`.
|
||||||
|
//! When this flag is not set the allocator would keep one empty block in each pool to prevent excessive virtual
|
||||||
|
//! memory allocations and deallocations in border cases, which involve constantly allocating and deallocating a
|
||||||
|
//! single block caused by repetitive calling `alloc()` and `release()` when the allocator has either no blocks
|
||||||
|
//! or have all blocks fully occupied.
|
||||||
|
kImmediateRelease = 0x00000008u,
|
||||||
|
|
||||||
|
//! Use a custom fill pattern, must be combined with `kFlagFillUnusedMemory`.
|
||||||
|
kCustomFillPattern = 0x10000000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(JitAllocatorOptions)
|
||||||
|
|
||||||
//! A simple implementation of memory manager that uses `asmjit::VirtMem`
|
//! A simple implementation of memory manager that uses `asmjit::VirtMem`
|
||||||
//! functions to manage virtual memory for JIT compiled code.
|
//! functions to manage virtual memory for JIT compiled code.
|
||||||
//!
|
//!
|
||||||
//! Implementation notes:
|
//! Implementation notes:
|
||||||
//!
|
//!
|
||||||
//! - Granularity of allocated blocks is different than granularity for a typical
|
//! - Granularity of allocated blocks is different than granularity for a typical C malloc. In addition, the allocator
|
||||||
//! C malloc. In addition, the allocator can use several memory pools having a
|
//! can use several memory pools having a different granularity to minimize the maintenance overhead. Multiple pools
|
||||||
//! different granularity to minimize the maintenance overhead. Multiple pools
|
|
||||||
//! feature requires `kFlagUseMultiplePools` flag to be set.
|
//! feature requires `kFlagUseMultiplePools` flag to be set.
|
||||||
//!
|
//!
|
||||||
//! - The allocator doesn't store any information in executable memory, instead,
|
//! - The allocator doesn't store any information in executable memory, instead, the implementation uses two
|
||||||
//! the implementation uses two bit-vectors to manage allocated memory of each
|
//! bit-vectors to manage allocated memory of each allocator-block. The first bit-vector called 'used' is used to
|
||||||
//! allocator-block. The first bit-vector called 'used' is used to track used
|
//! track used memory (where each bit represents memory size defined by granularity) and the second bit vector called
|
||||||
//! memory (where each bit represents memory size defined by granularity) and
|
//! 'stop' is used as a sentinel to mark where the allocated area ends.
|
||||||
//! the second bit vector called 'stop' is used as a sentinel to mark where
|
|
||||||
//! the allocated area ends.
|
|
||||||
//!
|
//!
|
||||||
//! - Internally, the allocator also uses RB tree to keep track of all blocks
|
//! - Internally, the allocator also uses RB tree to keep track of all blocks across all pools. Each inserted block is
|
||||||
//! across all pools. Each inserted block is added to the tree so it can be
|
//! added to the tree so it can be matched fast during `release()` and `shrink()`.
|
||||||
//! matched fast during `release()` and `shrink()`.
|
|
||||||
class JitAllocator {
|
class JitAllocator {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(JitAllocator)
|
ASMJIT_NONCOPYABLE(JitAllocator)
|
||||||
|
|
||||||
struct Impl {
|
struct Impl {
|
||||||
//! Allocator options, see \ref JitAllocator::Options.
|
//! Allocator options.
|
||||||
uint32_t options;
|
JitAllocatorOptions options;
|
||||||
//! Base block size (0 if the allocator is not initialized).
|
//! Base block size (0 if the allocator is not initialized).
|
||||||
uint32_t blockSize;
|
uint32_t blockSize;
|
||||||
//! Base granularity (0 if the allocator is not initialized).
|
//! Base granularity (0 if the allocator is not initialized).
|
||||||
@@ -77,45 +89,6 @@ public:
|
|||||||
//! Allocator implementation (private).
|
//! Allocator implementation (private).
|
||||||
Impl* _impl;
|
Impl* _impl;
|
||||||
|
|
||||||
enum Options : uint32_t {
|
|
||||||
//! Enables the use of an anonymous memory-mapped memory that is mapped into
|
|
||||||
//! two buffers having a different pointer. The first buffer has read and
|
|
||||||
//! execute permissions and the second buffer has read+write permissions.
|
|
||||||
//!
|
|
||||||
//! See \ref VirtMem::allocDualMapping() for more details about this feature.
|
|
||||||
kOptionUseDualMapping = 0x00000001u,
|
|
||||||
|
|
||||||
//! Enables the use of multiple pools with increasing granularity instead of
|
|
||||||
//! a single pool. This flag would enable 3 internal pools in total having
|
|
||||||
//! 64, 128, and 256 bytes granularity.
|
|
||||||
//!
|
|
||||||
//! This feature is only recommended for users that generate a lot of code
|
|
||||||
//! and would like to minimize the overhead of `JitAllocator` itself by
|
|
||||||
//! having blocks of different allocation granularities. Using this feature
|
|
||||||
//! only for few allocations won't pay off as the allocator may need to
|
|
||||||
//! create more blocks initially before it can take the advantage of
|
|
||||||
//! variable block granularity.
|
|
||||||
kOptionUseMultiplePools = 0x00000002u,
|
|
||||||
|
|
||||||
//! Always fill reserved memory by a fill-pattern.
|
|
||||||
//!
|
|
||||||
//! Causes a new block to be cleared by the fill pattern and freshly
|
|
||||||
//! released memory to be cleared before making it ready for another use.
|
|
||||||
kOptionFillUnusedMemory = 0x00000004u,
|
|
||||||
|
|
||||||
//! When this flag is set the allocator would immediately release unused
|
|
||||||
//! blocks during `release()` or `reset()`. When this flag is not set the
|
|
||||||
//! allocator would keep one empty block in each pool to prevent excessive
|
|
||||||
//! virtual memory allocations and deallocations in border cases, which
|
|
||||||
//! involve constantly allocating and deallocating a single block caused
|
|
||||||
//! by repetitive calling `alloc()` and `release()` when the allocator has
|
|
||||||
//! either no blocks or have all blocks fully occupied.
|
|
||||||
kOptionImmediateRelease = 0x00000008u,
|
|
||||||
|
|
||||||
//! Use a custom fill pattern, must be combined with `kFlagFillUnusedMemory`.
|
|
||||||
kOptionCustomFillPattern = 0x10000000u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -132,39 +105,35 @@ public:
|
|||||||
//! JitAllocator allocator(¶ms);
|
//! JitAllocator allocator(¶ms);
|
||||||
//! ```
|
//! ```
|
||||||
struct CreateParams {
|
struct CreateParams {
|
||||||
//! Allocator options, see \ref JitAllocator::Options.
|
//! Allocator options.
|
||||||
//!
|
//!
|
||||||
//! No options are used by default.
|
//! No options are used by default.
|
||||||
uint32_t options;
|
JitAllocatorOptions options = JitAllocatorOptions::kNone;
|
||||||
|
|
||||||
//! Base size of a single block in bytes (default 64kB).
|
//! Base size of a single block in bytes (default 64kB).
|
||||||
//!
|
//!
|
||||||
//! \remarks Block size must be equal or greater to page size and must be
|
//! \remarks Block size must be equal to or greater than page size and must be power of 2. If the input is not
|
||||||
//! power of 2. If the input is not valid then the default block size will
|
//! valid then the default block size will be used instead.
|
||||||
//! be used instead.
|
uint32_t blockSize = 0;
|
||||||
uint32_t blockSize;
|
|
||||||
|
|
||||||
//! Base granularity (and also natural alignment) of allocations in bytes
|
//! Base granularity (and also natural alignment) of allocations in bytes (default 64).
|
||||||
//! (default 64).
|
|
||||||
//!
|
//!
|
||||||
//! Since the `JitAllocator` uses bit-arrays to mark used memory the
|
//! Since the `JitAllocator` uses bit-arrays to mark used memory the granularity also specifies how many bytes
|
||||||
//! granularity also specifies how many bytes correspond to a single bit in
|
//! correspond to a single bit in such bit-array. Higher granularity means more waste of virtual memory (as it
|
||||||
//! such bit-array. Higher granularity means more waste of virtual memory
|
//! increases the natural alignment), but smaller bit-arrays as less bits would be required per a single block.
|
||||||
//! (as it increases the natural alignment), but smaller bit-arrays as less
|
uint32_t granularity = 0;
|
||||||
//! bits would be required per a single block.
|
|
||||||
uint32_t granularity;
|
|
||||||
|
|
||||||
//! Patter to use to fill unused memory.
|
//! Patter to use to fill unused memory.
|
||||||
//!
|
//!
|
||||||
//! Only used if \ref kOptionCustomFillPattern is set.
|
//! Only used if \ref JitAllocatorOptions::kCustomFillPattern is set.
|
||||||
uint32_t fillPattern;
|
uint32_t fillPattern = 0;
|
||||||
|
|
||||||
// Reset the content of `CreateParams`.
|
// Reset the content of `CreateParams`.
|
||||||
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Creates a `JitAllocator` instance.
|
//! Creates a `JitAllocator` instance.
|
||||||
explicit ASMJIT_API JitAllocator(const CreateParams* params = nullptr) noexcept;
|
ASMJIT_API explicit JitAllocator(const CreateParams* params = nullptr) noexcept;
|
||||||
//! Destroys the `JitAllocator` instance and release all blocks held.
|
//! Destroys the `JitAllocator` instance and release all blocks held.
|
||||||
ASMJIT_API ~JitAllocator() noexcept;
|
ASMJIT_API ~JitAllocator() noexcept;
|
||||||
|
|
||||||
@@ -172,10 +141,9 @@ public:
|
|||||||
|
|
||||||
//! Free all allocated memory - makes all pointers returned by `alloc()` invalid.
|
//! Free all allocated memory - makes all pointers returned by `alloc()` invalid.
|
||||||
//!
|
//!
|
||||||
//! \remarks This function is not thread-safe as it's designed to be used when
|
//! \remarks This function is not thread-safe as it's designed to be used when nobody else is using allocator.
|
||||||
//! nobody else is using allocator. The reason is that there is no point of
|
//! The reason is that there is no point of calling `reset()` when the allocator is still in use.
|
||||||
//1 calling `reset()` when the allocator is still in use.
|
ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
|
||||||
ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept;
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -183,9 +151,9 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns allocator options, see `Flags`.
|
//! Returns allocator options, see `Flags`.
|
||||||
inline uint32_t options() const noexcept { return _impl->options; }
|
inline JitAllocatorOptions options() const noexcept { return _impl->options; }
|
||||||
//! Tests whether the allocator has the given `option` set.
|
//! Tests whether the allocator has the given `option` set.
|
||||||
inline bool hasOption(uint32_t option) const noexcept { return (_impl->options & option) != 0; }
|
inline bool hasOption(JitAllocatorOptions option) const noexcept { return uint32_t(_impl->options & option) != 0; }
|
||||||
|
|
||||||
//! Returns a base block size (a minimum size of block that the allocator would allocate).
|
//! Returns a base block size (a minimum size of block that the allocator would allocate).
|
||||||
inline uint32_t blockSize() const noexcept { return _impl->blockSize; }
|
inline uint32_t blockSize() const noexcept { return _impl->blockSize; }
|
||||||
@@ -199,20 +167,31 @@ public:
|
|||||||
//! \name Alloc & Release
|
//! \name Alloc & Release
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Allocate `size` bytes of virtual memory.
|
//! Allocates a new memory block of the requested `size`.
|
||||||
//!
|
//!
|
||||||
//! \remarks This function is thread-safe.
|
//! When the function is successful it stores two pointers in `rxPtrOut` and `rwPtrOut`. The pointers will be
|
||||||
ASMJIT_API Error alloc(void** roPtrOut, void** rwPtrOut, size_t size) noexcept;
|
//! different only if `kOptionUseDualMapping` was used to setup the allocator (in that case the `rxPtrOut` would
|
||||||
|
//! point to a Read+Execute region and `rwPtrOut` would point to a Read+Write region of the same memory-mapped block.
|
||||||
|
ASMJIT_API Error alloc(void** rxPtrOut, void** rwPtrOut, size_t size) noexcept;
|
||||||
|
|
||||||
//! Release a memory returned by `alloc()`.
|
//! Releases a memory block returned by `alloc()`.
|
||||||
//!
|
//!
|
||||||
//! \remarks This function is thread-safe.
|
//! \remarks This function is thread-safe.
|
||||||
ASMJIT_API Error release(void* roPtr) noexcept;
|
ASMJIT_API Error release(void* rxPtr) noexcept;
|
||||||
|
|
||||||
//! Free extra memory allocated with `p` by restricting it to `newSize` size.
|
//! Frees extra memory allocated with `rxPtr` by shrinking it to the given `newSize`.
|
||||||
//!
|
//!
|
||||||
//! \remarks This function is thread-safe.
|
//! \remarks This function is thread-safe.
|
||||||
ASMJIT_API Error shrink(void* roPtr, size_t newSize) noexcept;
|
ASMJIT_API Error shrink(void* rxPtr, size_t newSize) noexcept;
|
||||||
|
|
||||||
|
//! Queries information about an allocated memory block that contains the given `rxPtr`.
|
||||||
|
//!
|
||||||
|
//! The function returns `kErrorOk` when `rxPtr` is matched and fills `rxPtrOut`, `rwPtrOut`, and `sizeOut` output
|
||||||
|
//! arguments. The returned `rxPtrOut` and `rwPtrOut` pointers point to the beginning of the block, and `sizeOut`
|
||||||
|
//! describes the total amount of bytes this allocation uses - `sizeOut` will always be aligned to the allocation
|
||||||
|
//! granularity, so for example if an allocation was 1 byte and the size granularity is 64, the returned `sizeOut`
|
||||||
|
//! will be 64 bytes, because that's what the allocator sees.
|
||||||
|
ASMJIT_API Error query(void* rxPtr, void** rxPtrOut, void** rwPtrOut, size_t* sizeOut) const noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -223,6 +202,8 @@ public:
|
|||||||
struct Statistics {
|
struct Statistics {
|
||||||
//! Number of blocks `JitAllocator` maintains.
|
//! Number of blocks `JitAllocator` maintains.
|
||||||
size_t _blockCount;
|
size_t _blockCount;
|
||||||
|
//! Number of active allocations.
|
||||||
|
size_t _allocationCount;
|
||||||
//! How many bytes are currently used / allocated.
|
//! How many bytes are currently used / allocated.
|
||||||
size_t _usedSize;
|
size_t _usedSize;
|
||||||
//! How many bytes are currently reserved by the allocator.
|
//! How many bytes are currently reserved by the allocator.
|
||||||
@@ -239,6 +220,8 @@ public:
|
|||||||
|
|
||||||
//! Returns count of blocks managed by `JitAllocator` at the moment.
|
//! Returns count of blocks managed by `JitAllocator` at the moment.
|
||||||
inline size_t blockCount() const noexcept { return _blockCount; }
|
inline size_t blockCount() const noexcept { return _blockCount; }
|
||||||
|
//! Returns the number of active allocations.
|
||||||
|
inline size_t allocationCount() const noexcept { return _allocationCount; }
|
||||||
|
|
||||||
//! Returns how many bytes are currently used.
|
//! Returns how many bytes are currently used.
|
||||||
inline size_t usedSize() const noexcept { return _usedSize; }
|
inline size_t usedSize() const noexcept { return _usedSize; }
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_JIT
|
#ifndef ASMJIT_NO_JIT
|
||||||
@@ -29,44 +11,14 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::JitRuntime - Utilities]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Only useful on non-x86 architectures.
|
|
||||||
static inline void JitRuntime_flushInstructionCache(const void* p, size_t size) noexcept {
|
|
||||||
#if ASMJIT_ARCH_X86
|
|
||||||
DebugUtils::unused(p, size);
|
|
||||||
#else
|
|
||||||
# if defined(_WIN32)
|
|
||||||
// Windows has a built-in support in `kernel32.dll`.
|
|
||||||
::FlushInstructionCache(::GetCurrentProcess(), p, size);
|
|
||||||
# elif defined(__GNUC__)
|
|
||||||
char* start = static_cast<char*>(const_cast<void*>(p));
|
|
||||||
char* end = start + size;
|
|
||||||
__builtin___clear_cache(start, end);
|
|
||||||
# else
|
|
||||||
DebugUtils::unused(p, size);
|
|
||||||
# endif
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::JitRuntime - Construction / Destruction]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept
|
JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept
|
||||||
: _allocator(params) {
|
: _allocator(params) {
|
||||||
_environment = hostEnvironment();
|
_environment = Environment::host();
|
||||||
_environment.setFormat(Environment::kFormatJIT);
|
_environment.setObjectFormat(ObjectFormat::kJIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
JitRuntime::~JitRuntime() noexcept {}
|
JitRuntime::~JitRuntime() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::JitRuntime - Interface]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
||||||
*dst = nullptr;
|
*dst = nullptr;
|
||||||
|
|
||||||
@@ -77,14 +29,14 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
|||||||
if (ASMJIT_UNLIKELY(estimatedCodeSize == 0))
|
if (ASMJIT_UNLIKELY(estimatedCodeSize == 0))
|
||||||
return DebugUtils::errored(kErrorNoCodeGenerated);
|
return DebugUtils::errored(kErrorNoCodeGenerated);
|
||||||
|
|
||||||
uint8_t* ro;
|
uint8_t* rx;
|
||||||
uint8_t* rw;
|
uint8_t* rw;
|
||||||
ASMJIT_PROPAGATE(_allocator.alloc((void**)&ro, (void**)&rw, estimatedCodeSize));
|
ASMJIT_PROPAGATE(_allocator.alloc((void**)&rx, (void**)&rw, estimatedCodeSize));
|
||||||
|
|
||||||
// Relocate the code.
|
// Relocate the code.
|
||||||
Error err = code->relocateToBase(uintptr_t((void*)ro));
|
Error err = code->relocateToBase(uintptr_t((void*)rx));
|
||||||
if (ASMJIT_UNLIKELY(err)) {
|
if (ASMJIT_UNLIKELY(err)) {
|
||||||
_allocator.release(ro);
|
_allocator.release(rx);
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -92,26 +44,28 @@ Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
|
|||||||
// 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 = code->codeSize();
|
||||||
|
|
||||||
for (Section* section : code->_sections) {
|
if (codeSize < estimatedCodeSize)
|
||||||
size_t offset = size_t(section->offset());
|
_allocator.shrink(rx, codeSize);
|
||||||
size_t bufferSize = size_t(section->bufferSize());
|
|
||||||
size_t virtualSize = size_t(section->virtualSize());
|
|
||||||
|
|
||||||
ASMJIT_ASSERT(offset + bufferSize <= codeSize);
|
{
|
||||||
memcpy(rw + offset, section->data(), bufferSize);
|
VirtMem::ProtectJitReadWriteScope rwScope(rx, codeSize);
|
||||||
|
|
||||||
if (virtualSize > bufferSize) {
|
for (Section* section : code->_sections) {
|
||||||
ASMJIT_ASSERT(offset + virtualSize <= codeSize);
|
size_t offset = size_t(section->offset());
|
||||||
memset(rw + offset + bufferSize, 0, virtualSize - bufferSize);
|
size_t bufferSize = size_t(section->bufferSize());
|
||||||
|
size_t virtualSize = size_t(section->virtualSize());
|
||||||
|
|
||||||
|
ASMJIT_ASSERT(offset + bufferSize <= codeSize);
|
||||||
|
memcpy(rw + offset, section->data(), bufferSize);
|
||||||
|
|
||||||
|
if (virtualSize > bufferSize) {
|
||||||
|
ASMJIT_ASSERT(offset + virtualSize <= codeSize);
|
||||||
|
memset(rw + offset + bufferSize, 0, virtualSize - bufferSize);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (codeSize < estimatedCodeSize)
|
*dst = rx;
|
||||||
_allocator.shrink(ro, codeSize);
|
|
||||||
|
|
||||||
flush(ro, codeSize);
|
|
||||||
*dst = ro;
|
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -119,10 +73,6 @@ Error JitRuntime::_release(void* p) noexcept {
|
|||||||
return _allocator.release(p);
|
return _allocator.release(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void JitRuntime::flush(const void* p, size_t size) noexcept {
|
|
||||||
JitRuntime_flushInstructionCache(p, size);
|
|
||||||
}
|
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
#ifndef ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
||||||
#define ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
#define ASMJIT_CORE_JITRUNTIME_H_INCLUDED
|
||||||
@@ -38,10 +20,6 @@ class CodeHolder;
|
|||||||
//! \addtogroup asmjit_virtual_memory
|
//! \addtogroup asmjit_virtual_memory
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::JitRuntime]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! JIT execution runtime is a special `Target` that is designed to store and
|
//! JIT execution runtime is a special `Target` that is designed to store and
|
||||||
//! execute the generated code.
|
//! execute the generated code.
|
||||||
class ASMJIT_VIRTAPI JitRuntime : public Target {
|
class ASMJIT_VIRTAPI JitRuntime : public Target {
|
||||||
@@ -55,11 +33,11 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Creates a `JitRuntime` instance.
|
//! Creates a `JitRuntime` instance.
|
||||||
explicit ASMJIT_API JitRuntime(const JitAllocator::CreateParams* params = nullptr) noexcept;
|
ASMJIT_API explicit JitRuntime(const JitAllocator::CreateParams* params = nullptr) noexcept;
|
||||||
//! Destroys the `JitRuntime` instance.
|
//! Destroys the `JitRuntime` instance.
|
||||||
ASMJIT_API virtual ~JitRuntime() noexcept;
|
ASMJIT_API virtual ~JitRuntime() noexcept;
|
||||||
|
|
||||||
inline void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept {
|
inline void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept {
|
||||||
_allocator.reset(resetPolicy);
|
_allocator.reset(resetPolicy);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -79,12 +57,10 @@ public:
|
|||||||
// NOTE: To allow passing function pointers to `add()` and `release()` the
|
// NOTE: To allow passing function pointers to `add()` and `release()` the
|
||||||
// virtual methods are prefixed with `_` and called from templates instead.
|
// virtual methods are prefixed with `_` and called from templates instead.
|
||||||
|
|
||||||
//! Allocates memory needed for a code stored in the `CodeHolder` and relocates
|
//! Allocates memory needed for a code stored in the `CodeHolder` and relocates the code to the pointer allocated.
|
||||||
//! the code to the pointer allocated.
|
|
||||||
//!
|
//!
|
||||||
//! The beginning of the memory allocated for the function is returned in `dst`.
|
//! The beginning of the memory allocated for the function is returned in `dst`. If failed `Error` code is returned
|
||||||
//! If failed `Error` code is returned and `dst` is explicitly set to `nullptr`
|
//! and `dst` is explicitly set to `nullptr` (this means that you don't have to set it to null before calling `add()`).
|
||||||
//! (this means that you don't have to set it to null before calling `add()`).
|
|
||||||
template<typename Func>
|
template<typename Func>
|
||||||
inline Error add(Func* dst, CodeHolder* code) noexcept {
|
inline Error add(Func* dst, CodeHolder* code) noexcept {
|
||||||
return _add(Support::ptr_cast_impl<void**, Func*>(dst), code);
|
return _add(Support::ptr_cast_impl<void**, Func*>(dst), code);
|
||||||
@@ -102,19 +78,6 @@ public:
|
|||||||
//! Type-unsafe version of `release()`.
|
//! Type-unsafe version of `release()`.
|
||||||
ASMJIT_API virtual Error _release(void* p) noexcept;
|
ASMJIT_API virtual Error _release(void* p) noexcept;
|
||||||
|
|
||||||
//! Flushes an instruction cache.
|
|
||||||
//!
|
|
||||||
//! This member function is called after the code has been copied to the
|
|
||||||
//! destination buffer. It is only useful for JIT code generation as it
|
|
||||||
//! causes a flush of the processor's cache.
|
|
||||||
//!
|
|
||||||
//! Flushing is basically a NOP under X86, but is needed by architectures
|
|
||||||
//! that do not have a transparent instruction cache like ARM.
|
|
||||||
//!
|
|
||||||
//! This function can also be overridden to improve compatibility with tools
|
|
||||||
//! such as Valgrind, however, it's not an official part of AsmJit.
|
|
||||||
ASMJIT_API virtual void flush(const void* p, size_t size) noexcept;
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
@@ -30,18 +12,13 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// Logger - Implementation
|
||||||
// [asmjit::Logger - Construction / Destruction]
|
// =======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Logger::Logger() noexcept
|
Logger::Logger() noexcept
|
||||||
: _options() {}
|
: _options() {}
|
||||||
Logger::~Logger() noexcept {}
|
Logger::~Logger() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Logger - Logging]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error Logger::logf(const char* fmt, ...) noexcept {
|
Error Logger::logf(const char* fmt, ...) noexcept {
|
||||||
Error err;
|
Error err;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
@@ -59,18 +36,13 @@ Error Logger::logv(const char* fmt, va_list ap) noexcept {
|
|||||||
return log(sb);
|
return log(sb);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// FileLogger - Implementation
|
||||||
// [asmjit::FileLogger - Construction / Destruction]
|
// ===========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
FileLogger::FileLogger(FILE* file) noexcept
|
FileLogger::FileLogger(FILE* file) noexcept
|
||||||
: _file(file) {}
|
: _file(file) {}
|
||||||
FileLogger::~FileLogger() noexcept {}
|
FileLogger::~FileLogger() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FileLogger - Logging]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error FileLogger::_log(const char* data, size_t size) noexcept {
|
Error FileLogger::_log(const char* data, size_t size) noexcept {
|
||||||
if (!_file)
|
if (!_file)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -82,17 +54,12 @@ Error FileLogger::_log(const char* data, size_t size) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// StringLogger - Implementation
|
||||||
// [asmjit::StringLogger - Construction / Destruction]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
StringLogger::StringLogger() noexcept {}
|
StringLogger::StringLogger() noexcept {}
|
||||||
StringLogger::~StringLogger() noexcept {}
|
StringLogger::~StringLogger() noexcept {}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::StringLogger - Logging]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error StringLogger::_log(const char* data, size_t size) noexcept {
|
Error StringLogger::_log(const char* data, size_t size) noexcept {
|
||||||
return _content.append(data, size);
|
return _content.append(data, size);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_LOGGING_H_INCLUDED
|
#ifndef ASMJIT_CORE_LOGGING_H_INCLUDED
|
||||||
#define ASMJIT_CORE_LOGGING_H_INCLUDED
|
#define ASMJIT_CORE_LOGGING_H_INCLUDED
|
||||||
@@ -35,15 +17,10 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_logging
|
//! \addtogroup asmjit_logging
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Logger]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Logging interface.
|
//! Logging interface.
|
||||||
//!
|
//!
|
||||||
//! This class can be inherited and reimplemented to fit into your own logging
|
//! This class can be inherited and reimplemented to fit into your own logging needs. When reimplementing a logger
|
||||||
//! needs. When reimplementing a logger use \ref Logger::_log() method to log
|
//! use \ref Logger::_log() method to log customize the output.
|
||||||
//! customize the output.
|
|
||||||
//!
|
//!
|
||||||
//! There are two `Logger` implementations offered by AsmJit:
|
//! There are two `Logger` implementations offered by AsmJit:
|
||||||
//! - \ref FileLogger - logs into a `FILE*`.
|
//! - \ref FileLogger - logs into a `FILE*`.
|
||||||
@@ -73,25 +50,35 @@ public:
|
|||||||
inline FormatOptions& options() noexcept { return _options; }
|
inline FormatOptions& options() noexcept { return _options; }
|
||||||
//! \overload
|
//! \overload
|
||||||
inline const FormatOptions& options() const noexcept { return _options; }
|
inline const FormatOptions& options() const noexcept { return _options; }
|
||||||
|
//! Sets formatting options of this Logger to `options`.
|
||||||
|
inline void setOptions(const FormatOptions& options) noexcept { _options = options; }
|
||||||
|
//! Resets formatting options of this Logger to defaults.
|
||||||
|
inline void resetOptions() noexcept { _options.reset(); }
|
||||||
|
|
||||||
//! Returns formatting flags, see \ref FormatOptions::Flags.
|
//! Returns formatting flags.
|
||||||
inline uint32_t flags() const noexcept { return _options.flags(); }
|
inline FormatFlags flags() const noexcept { return _options.flags(); }
|
||||||
//! Tests whether the logger has the given `flag` enabled.
|
//! Tests whether the logger has the given `flag` enabled.
|
||||||
inline bool hasFlag(uint32_t flag) const noexcept { return _options.hasFlag(flag); }
|
inline bool hasFlag(FormatFlags flag) const noexcept { return _options.hasFlag(flag); }
|
||||||
//! Sets formatting flags to `flags`, see \ref FormatOptions::Flags.
|
//! Sets formatting flags to `flags`.
|
||||||
inline void setFlags(uint32_t flags) noexcept { _options.setFlags(flags); }
|
inline void setFlags(FormatFlags flags) noexcept { _options.setFlags(flags); }
|
||||||
//! Enables the given formatting `flags`, see \ref FormatOptions::Flags.
|
//! Enables the given formatting `flags`.
|
||||||
inline void addFlags(uint32_t flags) noexcept { _options.addFlags(flags); }
|
inline void addFlags(FormatFlags flags) noexcept { _options.addFlags(flags); }
|
||||||
//! Disables the given formatting `flags`, see \ref FormatOptions::Flags.
|
//! Disables the given formatting `flags`.
|
||||||
inline void clearFlags(uint32_t flags) noexcept { _options.clearFlags(flags); }
|
inline void clearFlags(FormatFlags flags) noexcept { _options.clearFlags(flags); }
|
||||||
|
|
||||||
//! Returns indentation of `type`, see \ref FormatOptions::IndentationType.
|
//! Returns indentation of a given indentation `group`.
|
||||||
inline uint32_t indentation(uint32_t type) const noexcept { return _options.indentation(type); }
|
inline uint32_t indentation(FormatIndentationGroup type) const noexcept { return _options.indentation(type); }
|
||||||
//! Sets indentation of the given indentation `type` to `n` spaces, see \ref
|
//! Sets indentation of the given indentation `group` to `n` spaces.
|
||||||
//! FormatOptions::IndentationType.
|
inline void setIndentation(FormatIndentationGroup type, uint32_t n) noexcept { _options.setIndentation(type, n); }
|
||||||
inline void setIndentation(uint32_t type, uint32_t n) noexcept { _options.setIndentation(type, n); }
|
//! Resets indentation of the given indentation `group` to 0 spaces.
|
||||||
//! Resets indentation of the given indentation `type` to 0 spaces.
|
inline void resetIndentation(FormatIndentationGroup type) noexcept { _options.resetIndentation(type); }
|
||||||
inline void resetIndentation(uint32_t type) noexcept { _options.resetIndentation(type); }
|
|
||||||
|
//! Returns padding of a given padding `group`.
|
||||||
|
inline size_t padding(FormatPaddingGroup type) const noexcept { return _options.padding(type); }
|
||||||
|
//! Sets padding of a given padding `group` to `n`.
|
||||||
|
inline void setPadding(FormatPaddingGroup type, uint32_t n) noexcept { _options.setPadding(type, n); }
|
||||||
|
//! Resets padding of a given padding `group` to 0, which means that a default will be used.
|
||||||
|
inline void resetPadding(FormatPaddingGroup type) noexcept { _options.resetPadding(type); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -100,9 +87,8 @@ public:
|
|||||||
|
|
||||||
//! Logs `str` - must be reimplemented.
|
//! Logs `str` - must be reimplemented.
|
||||||
//!
|
//!
|
||||||
//! The function can accept either a null terminated string if `size` is
|
//! The function can accept either a null terminated string if `size` is `SIZE_MAX` or a non-null terminated
|
||||||
//! `SIZE_MAX` or a non-null terminated string of the given `size`. The
|
//! string of the given `size`. The function cannot assume that the data is null terminated and must handle
|
||||||
//! function cannot assume that the data is null terminated and must handle
|
|
||||||
//! non-null terminated inputs.
|
//! non-null terminated inputs.
|
||||||
virtual Error _log(const char* data, size_t size) noexcept = 0;
|
virtual Error _log(const char* data, size_t size) noexcept = 0;
|
||||||
|
|
||||||
@@ -111,21 +97,15 @@ public:
|
|||||||
//! Logs content of a string `str`.
|
//! Logs content of a string `str`.
|
||||||
inline Error log(const String& str) noexcept { return _log(str.data(), str.size()); }
|
inline Error log(const String& str) noexcept { return _log(str.data(), str.size()); }
|
||||||
|
|
||||||
//! Formats the message by using `snprintf()` and then passes the formatted
|
//! Formats the message by using `snprintf()` and then passes the formatted string to \ref _log().
|
||||||
//! string to \ref _log().
|
|
||||||
ASMJIT_API Error logf(const char* fmt, ...) noexcept;
|
ASMJIT_API Error logf(const char* fmt, ...) noexcept;
|
||||||
|
|
||||||
//! Formats the message by using `vsnprintf()` and then passes the formatted
|
//! Formats the message by using `vsnprintf()` and then passes the formatted string to \ref _log().
|
||||||
//! string to \ref _log().
|
|
||||||
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
|
ASMJIT_API Error logv(const char* fmt, va_list ap) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::FileLogger]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Logger that can log to a `FILE*`.
|
//! Logger that can log to a `FILE*`.
|
||||||
class ASMJIT_VIRTAPI FileLogger : public Logger {
|
class ASMJIT_VIRTAPI FileLogger : public Logger {
|
||||||
public:
|
public:
|
||||||
@@ -146,17 +126,14 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the logging output stream or null if the logger has no output
|
//! Returns the logging output stream or null if the logger has no output stream.
|
||||||
//! stream.
|
|
||||||
inline FILE* file() const noexcept { return _file; }
|
inline FILE* file() const noexcept { return _file; }
|
||||||
|
|
||||||
//! Sets the logging output stream to `stream` or null.
|
//! Sets the logging output stream to `stream` or null.
|
||||||
//!
|
//!
|
||||||
//! \note If the `file` is null the logging will be disabled. When a logger
|
//! \note If the `file` is null the logging will be disabled. When a logger is attached to `CodeHolder` or any
|
||||||
//! is attached to `CodeHolder` or any emitter the logging API will always
|
//! emitter the logging API will always be called regardless of the output file. This means that if you really
|
||||||
//! be called regardless of the output file. This means that if you really
|
//! want to disable logging at emitter level you must not attach a logger to it.
|
||||||
//! want to disable logging at emitter level you must not attach a logger
|
|
||||||
//! to it.
|
|
||||||
inline void setFile(FILE* file) noexcept { _file = file; }
|
inline void setFile(FILE* file) noexcept { _file = file; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -164,10 +141,6 @@ public:
|
|||||||
ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override;
|
ASMJIT_API Error _log(const char* data, size_t size = SIZE_MAX) noexcept override;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::StringLogger]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Logger that stores everything in an internal string buffer.
|
//! Logger that stores everything in an internal string buffer.
|
||||||
class ASMJIT_VIRTAPI StringLogger : public Logger {
|
class ASMJIT_VIRTAPI StringLogger : public Logger {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_MISC_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_MISC_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_MISC_P_H_INCLUDED
|
#define ASMJIT_CORE_MISC_P_H_INCLUDED
|
||||||
|
|||||||
@@ -1,36 +1,22 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/operand.h"
|
#include "../core/operand.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// Operand - Tests
|
||||||
// [asmjit::Operand - Unit]
|
// ===============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
|
enum class StrongEnumForImmTests : uint32_t {
|
||||||
|
kValue0,
|
||||||
|
kValue0xFFFFFFFF = 0xFFFFFFFFu
|
||||||
|
};
|
||||||
|
|
||||||
UNIT(operand) {
|
UNIT(operand) {
|
||||||
INFO("Checking operand sizes");
|
INFO("Checking operand sizes");
|
||||||
EXPECT(sizeof(Operand) == 16);
|
EXPECT(sizeof(Operand) == 16);
|
||||||
@@ -65,22 +51,23 @@ UNIT(operand) {
|
|||||||
EXPECT(dummy.as<BaseReg>().isValid() == false);
|
EXPECT(dummy.as<BaseReg>().isValid() == false);
|
||||||
|
|
||||||
// Create some register (not specific to any architecture).
|
// Create some register (not specific to any architecture).
|
||||||
uint32_t rSig = Operand::kOpReg | (1 << Operand::kSignatureRegTypeShift ) |
|
OperandSignature rSig = OperandSignature::fromOpType(OperandType::kReg) |
|
||||||
(2 << Operand::kSignatureRegGroupShift) |
|
OperandSignature::fromRegType(RegType::kVec128) |
|
||||||
(8 << Operand::kSignatureSizeShift ) ;
|
OperandSignature::fromRegGroup(RegGroup::kVec) |
|
||||||
BaseReg r1 = BaseReg::fromSignatureAndId(rSig, 5);
|
OperandSignature::fromSize(8);
|
||||||
|
BaseReg r1(rSig, 5);
|
||||||
|
|
||||||
EXPECT(r1.isValid() == true);
|
EXPECT(r1.isValid() == true);
|
||||||
EXPECT(r1.isReg() == true);
|
EXPECT(r1.isReg() == true);
|
||||||
EXPECT(r1.isReg(1) == true);
|
EXPECT(r1.isReg(RegType::kVec128) == true);
|
||||||
EXPECT(r1.isPhysReg() == true);
|
EXPECT(r1.isPhysReg() == true);
|
||||||
EXPECT(r1.isVirtReg() == false);
|
EXPECT(r1.isVirtReg() == false);
|
||||||
EXPECT(r1.signature() == rSig);
|
EXPECT(r1.signature() == rSig);
|
||||||
EXPECT(r1.type() == 1);
|
EXPECT(r1.type() == RegType::kVec128);
|
||||||
EXPECT(r1.group() == 2);
|
EXPECT(r1.group() == RegGroup::kVec);
|
||||||
EXPECT(r1.size() == 8);
|
EXPECT(r1.size() == 8);
|
||||||
EXPECT(r1.id() == 5);
|
EXPECT(r1.id() == 5);
|
||||||
EXPECT(r1.isReg(1, 5) == true); // RegType and Id.
|
EXPECT(r1.isReg(RegType::kVec128, 5) == true); // RegType and Id.
|
||||||
EXPECT(r1._data[0] == 0);
|
EXPECT(r1._data[0] == 0);
|
||||||
EXPECT(r1._data[1] == 0);
|
EXPECT(r1._data[1] == 0);
|
||||||
|
|
||||||
@@ -88,7 +75,7 @@ UNIT(operand) {
|
|||||||
BaseReg r2(r1, 6);
|
BaseReg r2(r1, 6);
|
||||||
EXPECT(r2.isValid() == true);
|
EXPECT(r2.isValid() == true);
|
||||||
EXPECT(r2.isReg() == true);
|
EXPECT(r2.isReg() == true);
|
||||||
EXPECT(r2.isReg(1) == true);
|
EXPECT(r2.isReg(RegType::kVec128) == true);
|
||||||
EXPECT(r2.isPhysReg() == true);
|
EXPECT(r2.isPhysReg() == true);
|
||||||
EXPECT(r2.isVirtReg() == false);
|
EXPECT(r2.isVirtReg() == false);
|
||||||
EXPECT(r2.signature() == rSig);
|
EXPECT(r2.signature() == rSig);
|
||||||
@@ -96,7 +83,7 @@ UNIT(operand) {
|
|||||||
EXPECT(r2.group() == r1.group());
|
EXPECT(r2.group() == r1.group());
|
||||||
EXPECT(r2.size() == r1.size());
|
EXPECT(r2.size() == r1.size());
|
||||||
EXPECT(r2.id() == 6);
|
EXPECT(r2.id() == 6);
|
||||||
EXPECT(r2.isReg(1, 6) == true);
|
EXPECT(r2.isReg(RegType::kVec128, 6) == true);
|
||||||
|
|
||||||
r1.reset();
|
r1.reset();
|
||||||
EXPECT(!r1.isReg());
|
EXPECT(!r1.isReg());
|
||||||
@@ -126,17 +113,19 @@ UNIT(operand) {
|
|||||||
|
|
||||||
INFO("Checking basic functionality of Imm");
|
INFO("Checking basic functionality of Imm");
|
||||||
Imm immValue(-42);
|
Imm immValue(-42);
|
||||||
EXPECT(immValue.type() == Imm::kTypeInteger);
|
EXPECT(immValue.type() == ImmType::kInt);
|
||||||
EXPECT(Imm(-1).value() == -1);
|
EXPECT(Imm(-1).value() == -1);
|
||||||
EXPECT(imm(-1).value() == -1);
|
EXPECT(imm(-1).value() == -1);
|
||||||
EXPECT(immValue.value() == -42);
|
EXPECT(immValue.value() == -42);
|
||||||
EXPECT(imm(0xFFFFFFFF).value() == int64_t(0xFFFFFFFF));
|
EXPECT(imm(0xFFFFFFFF).value() == int64_t(0xFFFFFFFF));
|
||||||
|
|
||||||
Imm immDouble(0.4);
|
Imm immDouble(0.4);
|
||||||
EXPECT(immDouble.type() == Imm::kTypeDouble);
|
EXPECT(immDouble.type() == ImmType::kDouble);
|
||||||
EXPECT(immDouble.valueAs<double>() == 0.4);
|
EXPECT(immDouble.valueAs<double>() == 0.4);
|
||||||
EXPECT(immDouble == imm(0.4));
|
EXPECT(immDouble == imm(0.4));
|
||||||
|
|
||||||
|
EXPECT(Imm(StrongEnumForImmTests::kValue0).value() == 0);
|
||||||
|
EXPECT(Imm(StrongEnumForImmTests::kValue0xFFFFFFFF).value() == 0xFFFFFFFFu);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/osutils.h"
|
#include "../core/osutils.h"
|
||||||
@@ -36,10 +18,6 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::OSUtils - GetTickCount]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
uint32_t OSUtils::getTickCount() noexcept {
|
uint32_t OSUtils::getTickCount() noexcept {
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
enum HiResStatus : uint32_t {
|
enum HiResStatus : uint32_t {
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_OSUTILS_H_INCLUDED
|
#ifndef ASMJIT_CORE_OSUTILS_H_INCLUDED
|
||||||
#define ASMJIT_CORE_OSUTILS_H_INCLUDED
|
#define ASMJIT_CORE_OSUTILS_H_INCLUDED
|
||||||
@@ -31,22 +13,14 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_utilities
|
//! \addtogroup asmjit_utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::OSUtils]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Operating system utilities.
|
//! Operating system utilities.
|
||||||
namespace OSUtils {
|
namespace OSUtils {
|
||||||
//! Gets the current CPU tick count, used for benchmarking (1ms resolution).
|
//! Gets the current CPU tick count, used for benchmarking (1ms resolution).
|
||||||
ASMJIT_API uint32_t getTickCount() noexcept;
|
ASMJIT_API uint32_t getTickCount() noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Lock]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
|
|
||||||
//! Lock.
|
//! Lock.
|
||||||
//!
|
//!
|
||||||
//! Lock is internal, it cannot be used outside of AsmJit, however, its internal
|
//! Lock is internal, it cannot be used outside of AsmJit, however, its internal
|
||||||
@@ -72,11 +46,11 @@ public:
|
|||||||
Handle _handle;
|
Handle _handle;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
inline Lock() noexcept;
|
ASMJIT_FORCE_INLINE Lock() noexcept;
|
||||||
inline ~Lock() noexcept;
|
ASMJIT_FORCE_INLINE ~Lock() noexcept;
|
||||||
|
|
||||||
inline void lock() noexcept;
|
ASMJIT_FORCE_INLINE void lock() noexcept;
|
||||||
inline void unlock() noexcept;
|
ASMJIT_FORCE_INLINE void unlock() noexcept;
|
||||||
};
|
};
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_OSUTILS_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_OSUTILS_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_OSUTILS_P_H_INCLUDED
|
#define ASMJIT_CORE_OSUTILS_P_H_INCLUDED
|
||||||
@@ -32,47 +14,39 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_utilities
|
//! \addtogroup asmjit_utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Lock]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
// Windows implementation.
|
// Windows implementation.
|
||||||
static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION");
|
static_assert(sizeof(Lock::Handle) == sizeof(CRITICAL_SECTION), "asmjit::Lock::Handle layout must match CRITICAL_SECTION");
|
||||||
static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION");
|
static_assert(alignof(Lock::Handle) == alignof(CRITICAL_SECTION), "asmjit::Lock::Handle alignment must match CRITICAL_SECTION");
|
||||||
|
|
||||||
inline Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
ASMJIT_FORCE_INLINE Lock::Lock() noexcept { InitializeCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
||||||
inline Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
ASMJIT_FORCE_INLINE Lock::~Lock() noexcept { DeleteCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
||||||
inline void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
ASMJIT_FORCE_INLINE void Lock::lock() noexcept { EnterCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
||||||
inline void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
ASMJIT_FORCE_INLINE void Lock::unlock() noexcept { LeaveCriticalSection(reinterpret_cast<CRITICAL_SECTION*>(&_handle)); }
|
||||||
|
|
||||||
#elif !defined(__EMSCRIPTEN__)
|
#elif !defined(__EMSCRIPTEN__)
|
||||||
|
|
||||||
// PThread implementation.
|
// PThread implementation.
|
||||||
#ifdef PTHREAD_MUTEX_INITIALIZER
|
#ifdef PTHREAD_MUTEX_INITIALIZER
|
||||||
inline Lock::Lock() noexcept : _handle(PTHREAD_MUTEX_INITIALIZER) {}
|
ASMJIT_FORCE_INLINE Lock::Lock() noexcept : _handle(PTHREAD_MUTEX_INITIALIZER) {}
|
||||||
#else
|
#else
|
||||||
inline Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); }
|
ASMJIT_FORCE_INLINE Lock::Lock() noexcept { pthread_mutex_init(&_handle, nullptr); }
|
||||||
#endif
|
#endif
|
||||||
inline Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); }
|
ASMJIT_FORCE_INLINE Lock::~Lock() noexcept { pthread_mutex_destroy(&_handle); }
|
||||||
inline void Lock::lock() noexcept { pthread_mutex_lock(&_handle); }
|
ASMJIT_FORCE_INLINE void Lock::lock() noexcept { pthread_mutex_lock(&_handle); }
|
||||||
inline void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); }
|
ASMJIT_FORCE_INLINE void Lock::unlock() noexcept { pthread_mutex_unlock(&_handle); }
|
||||||
|
|
||||||
#else
|
#else
|
||||||
|
|
||||||
// Dummy implementation - Emscripten or other unsupported platform.
|
// Dummy implementation - Emscripten or other unsupported platform.
|
||||||
inline Lock::Lock() noexcept {}
|
ASMJIT_FORCE_INLINE Lock::Lock() noexcept {}
|
||||||
inline Lock::~Lock() noexcept {}
|
ASMJIT_FORCE_INLINE Lock::~Lock() noexcept {}
|
||||||
inline void Lock::lock() noexcept {}
|
ASMJIT_FORCE_INLINE void Lock::lock() noexcept {}
|
||||||
inline void Lock::unlock() noexcept {}
|
ASMJIT_FORCE_INLINE void Lock::unlock() noexcept {}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::LockGuard]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Scoped lock.
|
//! Scoped lock.
|
||||||
class LockGuard {
|
class LockGuard {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED
|
#define ASMJIT_CORE_RAASSIGNMENT_P_H_INCLUDED
|
||||||
@@ -35,10 +17,12 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_ra
|
//! \addtogroup asmjit_ra
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Holds the current register assignment.
|
||||||
// [asmjit::RAAssignment]
|
//!
|
||||||
// ============================================================================
|
//! Has two purposes:
|
||||||
|
//!
|
||||||
|
//! 1. Holds register assignment of a local register allocator (see \ref RALocalAllocator).
|
||||||
|
//! 2. Holds register assignment of the entry of basic blocks (see \ref RABlock).
|
||||||
class RAAssignment {
|
class RAAssignment {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(RAAssignment)
|
ASMJIT_NONCOPYABLE(RAAssignment)
|
||||||
@@ -120,6 +104,9 @@ public:
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Physical registers layout.
|
//! Physical registers layout.
|
||||||
Layout _layout;
|
Layout _layout;
|
||||||
//! WorkReg to PhysReg mapping.
|
//! WorkReg to PhysReg mapping.
|
||||||
@@ -127,7 +114,9 @@ public:
|
|||||||
//! PhysReg to WorkReg mapping and assigned/dirty bits.
|
//! PhysReg to WorkReg mapping and assigned/dirty bits.
|
||||||
PhysToWorkMap* _physToWorkMap;
|
PhysToWorkMap* _physToWorkMap;
|
||||||
//! Optimization to translate PhysRegs to WorkRegs faster.
|
//! Optimization to translate PhysRegs to WorkRegs faster.
|
||||||
uint32_t* _physToWorkIds[BaseReg::kGroupVirt];
|
Support::Array<uint32_t*, Globals::kNumVirtGroups> _physToWorkIds;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -137,31 +126,30 @@ public:
|
|||||||
resetMaps();
|
resetMaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void initLayout(const RARegCount& physCount, const RAWorkRegs& workRegs) noexcept {
|
ASMJIT_FORCE_INLINE void initLayout(const RARegCount& physCount, const RAWorkRegs& workRegs) noexcept {
|
||||||
// Layout must be initialized before data.
|
// Layout must be initialized before data.
|
||||||
ASMJIT_ASSERT(_physToWorkMap == nullptr);
|
ASMJIT_ASSERT(_physToWorkMap == nullptr);
|
||||||
ASMJIT_ASSERT(_workToPhysMap == nullptr);
|
ASMJIT_ASSERT(_workToPhysMap == nullptr);
|
||||||
|
|
||||||
_layout.physIndex.buildIndexes(physCount);
|
_layout.physIndex.buildIndexes(physCount);
|
||||||
_layout.physCount = physCount;
|
_layout.physCount = physCount;
|
||||||
_layout.physTotal = uint32_t(_layout.physIndex[BaseReg::kGroupVirt - 1]) +
|
_layout.physTotal = uint32_t(_layout.physIndex[RegGroup::kMaxVirt]) +
|
||||||
uint32_t(_layout.physCount[BaseReg::kGroupVirt - 1]) ;
|
uint32_t(_layout.physCount[RegGroup::kMaxVirt]) ;
|
||||||
_layout.workCount = workRegs.size();
|
_layout.workCount = workRegs.size();
|
||||||
_layout.workRegs = &workRegs;
|
_layout.workRegs = &workRegs;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void initMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept {
|
ASMJIT_FORCE_INLINE void initMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept {
|
||||||
_physToWorkMap = physToWorkMap;
|
_physToWorkMap = physToWorkMap;
|
||||||
_workToPhysMap = workToPhysMap;
|
_workToPhysMap = workToPhysMap;
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++)
|
for (RegGroup group : RegGroupVirtValues{})
|
||||||
_physToWorkIds[group] = physToWorkMap->workIds + _layout.physIndex.get(group);
|
_physToWorkIds[group] = physToWorkMap->workIds + _layout.physIndex.get(group);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void resetMaps() noexcept {
|
ASMJIT_FORCE_INLINE void resetMaps() noexcept {
|
||||||
_physToWorkMap = nullptr;
|
_physToWorkMap = nullptr;
|
||||||
_workToPhysMap = nullptr;
|
_workToPhysMap = nullptr;
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++)
|
_physToWorkIds.fill(nullptr);
|
||||||
_physToWorkIds[group] = nullptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -174,30 +162,30 @@ public:
|
|||||||
|
|
||||||
inline RARegMask& assigned() noexcept { return _physToWorkMap->assigned; }
|
inline RARegMask& assigned() noexcept { return _physToWorkMap->assigned; }
|
||||||
inline const RARegMask& assigned() const noexcept { return _physToWorkMap->assigned; }
|
inline const RARegMask& assigned() const noexcept { return _physToWorkMap->assigned; }
|
||||||
inline uint32_t assigned(uint32_t group) const noexcept { return _physToWorkMap->assigned[group]; }
|
inline uint32_t assigned(RegGroup group) const noexcept { return _physToWorkMap->assigned[group]; }
|
||||||
|
|
||||||
inline RARegMask& dirty() noexcept { return _physToWorkMap->dirty; }
|
inline RARegMask& dirty() noexcept { return _physToWorkMap->dirty; }
|
||||||
inline const RARegMask& dirty() const noexcept { return _physToWorkMap->dirty; }
|
inline const RARegMask& dirty() const noexcept { return _physToWorkMap->dirty; }
|
||||||
inline uint32_t dirty(uint32_t group) const noexcept { return _physToWorkMap->dirty[group]; }
|
inline RegMask dirty(RegGroup group) const noexcept { return _physToWorkMap->dirty[group]; }
|
||||||
|
|
||||||
inline uint32_t workToPhysId(uint32_t group, uint32_t workId) const noexcept {
|
inline uint32_t workToPhysId(RegGroup group, uint32_t workId) const noexcept {
|
||||||
DebugUtils::unused(group);
|
DebugUtils::unused(group);
|
||||||
ASMJIT_ASSERT(workId != kWorkNone);
|
ASMJIT_ASSERT(workId != kWorkNone);
|
||||||
ASMJIT_ASSERT(workId < _layout.workCount);
|
ASMJIT_ASSERT(workId < _layout.workCount);
|
||||||
return _workToPhysMap->physIds[workId];
|
return _workToPhysMap->physIds[workId];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t physToWorkId(uint32_t group, uint32_t physId) const noexcept {
|
inline uint32_t physToWorkId(RegGroup group, uint32_t physId) const noexcept {
|
||||||
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
||||||
return _physToWorkIds[group][physId];
|
return _physToWorkIds[group][physId];
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isPhysAssigned(uint32_t group, uint32_t physId) const noexcept {
|
inline bool isPhysAssigned(RegGroup group, uint32_t physId) const noexcept {
|
||||||
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
||||||
return Support::bitTest(_physToWorkMap->assigned[group], physId);
|
return Support::bitTest(_physToWorkMap->assigned[group], physId);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool isPhysDirty(uint32_t group, uint32_t physId) const noexcept {
|
inline bool isPhysDirty(RegGroup group, uint32_t physId) const noexcept {
|
||||||
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
||||||
return Support::bitTest(_physToWorkMap->dirty[group], physId);
|
return Support::bitTest(_physToWorkMap->dirty[group], physId);
|
||||||
}
|
}
|
||||||
@@ -205,15 +193,15 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Assignment
|
//! \name Assignment
|
||||||
|
//!
|
||||||
|
//! These are low-level allocation helpers that are used to update the current mappings between physical and
|
||||||
|
//! virt/work registers and also to update masks that represent allocated and dirty registers. These functions
|
||||||
|
//! don't emit any code; they are only used to update and keep all mappings in sync.
|
||||||
|
//!
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// These are low-level allocation helpers that are used to update the current
|
|
||||||
// mappings between physical and virt/work registers and also to update masks
|
|
||||||
// that represent allocated and dirty registers. These functions don't emit
|
|
||||||
// any code; they are only used to update and keep all mappings in sync.
|
|
||||||
|
|
||||||
//! Assign [VirtReg/WorkReg] to a physical register.
|
//! Assign [VirtReg/WorkReg] to a physical register.
|
||||||
ASMJIT_INLINE void assign(uint32_t group, uint32_t workId, uint32_t physId, uint32_t dirty) noexcept {
|
inline void assign(RegGroup group, uint32_t workId, uint32_t physId, bool dirty) noexcept {
|
||||||
ASMJIT_ASSERT(workToPhysId(group, workId) == kPhysNone);
|
ASMJIT_ASSERT(workToPhysId(group, workId) == kPhysNone);
|
||||||
ASMJIT_ASSERT(physToWorkId(group, physId) == kWorkNone);
|
ASMJIT_ASSERT(physToWorkId(group, physId) == kWorkNone);
|
||||||
ASMJIT_ASSERT(!isPhysAssigned(group, physId));
|
ASMJIT_ASSERT(!isPhysAssigned(group, physId));
|
||||||
@@ -222,15 +210,15 @@ public:
|
|||||||
_workToPhysMap->physIds[workId] = uint8_t(physId);
|
_workToPhysMap->physIds[workId] = uint8_t(physId);
|
||||||
_physToWorkIds[group][physId] = workId;
|
_physToWorkIds[group][physId] = workId;
|
||||||
|
|
||||||
uint32_t regMask = Support::bitMask(physId);
|
RegMask regMask = Support::bitMask(physId);
|
||||||
_physToWorkMap->assigned[group] |= regMask;
|
_physToWorkMap->assigned[group] |= regMask;
|
||||||
_physToWorkMap->dirty[group] |= regMask & Support::bitMaskFromBool<uint32_t>(dirty);
|
_physToWorkMap->dirty[group] |= regMask & Support::bitMaskFromBool<RegMask>(dirty);
|
||||||
|
|
||||||
verify();
|
verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Reassign [VirtReg/WorkReg] to `dstPhysId` from `srcPhysId`.
|
//! Reassign [VirtReg/WorkReg] to `dstPhysId` from `srcPhysId`.
|
||||||
ASMJIT_INLINE void reassign(uint32_t group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
inline void reassign(RegGroup group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
||||||
ASMJIT_ASSERT(dstPhysId != srcPhysId);
|
ASMJIT_ASSERT(dstPhysId != srcPhysId);
|
||||||
ASMJIT_ASSERT(workToPhysId(group, workId) == srcPhysId);
|
ASMJIT_ASSERT(workToPhysId(group, workId) == srcPhysId);
|
||||||
ASMJIT_ASSERT(physToWorkId(group, srcPhysId) == workId);
|
ASMJIT_ASSERT(physToWorkId(group, srcPhysId) == workId);
|
||||||
@@ -241,19 +229,19 @@ public:
|
|||||||
_physToWorkIds[group][srcPhysId] = kWorkNone;
|
_physToWorkIds[group][srcPhysId] = kWorkNone;
|
||||||
_physToWorkIds[group][dstPhysId] = workId;
|
_physToWorkIds[group][dstPhysId] = workId;
|
||||||
|
|
||||||
uint32_t srcMask = Support::bitMask(srcPhysId);
|
RegMask srcMask = Support::bitMask(srcPhysId);
|
||||||
uint32_t dstMask = Support::bitMask(dstPhysId);
|
RegMask dstMask = Support::bitMask(dstPhysId);
|
||||||
|
|
||||||
uint32_t dirty = (_physToWorkMap->dirty[group] & srcMask) != 0;
|
bool dirty = (_physToWorkMap->dirty[group] & srcMask) != 0;
|
||||||
uint32_t regMask = dstMask | srcMask;
|
RegMask regMask = dstMask | srcMask;
|
||||||
|
|
||||||
_physToWorkMap->assigned[group] ^= regMask;
|
_physToWorkMap->assigned[group] ^= regMask;
|
||||||
_physToWorkMap->dirty[group] ^= regMask & Support::bitMaskFromBool<uint32_t>(dirty);
|
_physToWorkMap->dirty[group] ^= regMask & Support::bitMaskFromBool<RegMask>(dirty);
|
||||||
|
|
||||||
verify();
|
verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void swap(uint32_t group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
|
inline void swap(RegGroup group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
|
||||||
ASMJIT_ASSERT(aPhysId != bPhysId);
|
ASMJIT_ASSERT(aPhysId != bPhysId);
|
||||||
ASMJIT_ASSERT(workToPhysId(group, aWorkId) == aPhysId);
|
ASMJIT_ASSERT(workToPhysId(group, aWorkId) == aPhysId);
|
||||||
ASMJIT_ASSERT(workToPhysId(group, bWorkId) == bPhysId);
|
ASMJIT_ASSERT(workToPhysId(group, bWorkId) == bPhysId);
|
||||||
@@ -267,21 +255,17 @@ public:
|
|||||||
_physToWorkIds[group][aPhysId] = bWorkId;
|
_physToWorkIds[group][aPhysId] = bWorkId;
|
||||||
_physToWorkIds[group][bPhysId] = aWorkId;
|
_physToWorkIds[group][bPhysId] = aWorkId;
|
||||||
|
|
||||||
uint32_t aMask = Support::bitMask(aPhysId);
|
RegMask aMask = Support::bitMask(aPhysId);
|
||||||
uint32_t bMask = Support::bitMask(bPhysId);
|
RegMask bMask = Support::bitMask(bPhysId);
|
||||||
|
RegMask flipMask = Support::bitMaskFromBool<RegMask>(((_physToWorkMap->dirty[group] & aMask) != 0) ^ ((_physToWorkMap->dirty[group] & bMask) != 0));
|
||||||
uint32_t flipMask = Support::bitMaskFromBool<uint32_t>(
|
RegMask regMask = aMask | bMask;
|
||||||
((_physToWorkMap->dirty[group] & aMask) != 0) ^
|
|
||||||
((_physToWorkMap->dirty[group] & bMask) != 0));
|
|
||||||
|
|
||||||
uint32_t regMask = aMask | bMask;
|
|
||||||
_physToWorkMap->dirty[group] ^= regMask & flipMask;
|
_physToWorkMap->dirty[group] ^= regMask & flipMask;
|
||||||
|
|
||||||
verify();
|
verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Unassign [VirtReg/WorkReg] from a physical register.
|
//! Unassign [VirtReg/WorkReg] from a physical register.
|
||||||
ASMJIT_INLINE void unassign(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline void unassign(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
ASMJIT_ASSERT(physId < Globals::kMaxPhysRegs);
|
||||||
ASMJIT_ASSERT(workToPhysId(group, workId) == physId);
|
ASMJIT_ASSERT(workToPhysId(group, workId) == physId);
|
||||||
ASMJIT_ASSERT(physToWorkId(group, physId) == workId);
|
ASMJIT_ASSERT(physToWorkId(group, physId) == workId);
|
||||||
@@ -290,22 +274,22 @@ public:
|
|||||||
_workToPhysMap->physIds[workId] = kPhysNone;
|
_workToPhysMap->physIds[workId] = kPhysNone;
|
||||||
_physToWorkIds[group][physId] = kWorkNone;
|
_physToWorkIds[group][physId] = kWorkNone;
|
||||||
|
|
||||||
uint32_t regMask = Support::bitMask(physId);
|
RegMask regMask = Support::bitMask(physId);
|
||||||
_physToWorkMap->assigned[group] &= ~regMask;
|
_physToWorkMap->assigned[group] &= ~regMask;
|
||||||
_physToWorkMap->dirty[group] &= ~regMask;
|
_physToWorkMap->dirty[group] &= ~regMask;
|
||||||
|
|
||||||
verify();
|
verify();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void makeClean(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline void makeClean(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
DebugUtils::unused(workId);
|
DebugUtils::unused(workId);
|
||||||
uint32_t regMask = Support::bitMask(physId);
|
RegMask regMask = Support::bitMask(physId);
|
||||||
_physToWorkMap->dirty[group] &= ~regMask;
|
_physToWorkMap->dirty[group] &= ~regMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void makeDirty(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline void makeDirty(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
DebugUtils::unused(workId);
|
DebugUtils::unused(workId);
|
||||||
uint32_t regMask = Support::bitMask(physId);
|
RegMask regMask = Support::bitMask(physId);
|
||||||
_physToWorkMap->dirty[group] |= regMask;
|
_physToWorkMap->dirty[group] |= regMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -314,12 +298,10 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline void swap(RAAssignment& other) noexcept {
|
ASMJIT_FORCE_INLINE void swap(RAAssignment& other) noexcept {
|
||||||
std::swap(_workToPhysMap, other._workToPhysMap);
|
std::swap(_workToPhysMap, other._workToPhysMap);
|
||||||
std::swap(_physToWorkMap, other._physToWorkMap);
|
std::swap(_physToWorkMap, other._physToWorkMap);
|
||||||
|
_physToWorkIds.swap(other._physToWorkIds);
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++)
|
|
||||||
std::swap(_physToWorkIds[group], other._physToWorkIds[group]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void copyFrom(const PhysToWorkMap* physToWorkMap, const WorkToPhysMap* workToPhysMap) noexcept {
|
inline void copyFrom(const PhysToWorkMap* physToWorkMap, const WorkToPhysMap* workToPhysMap) noexcept {
|
||||||
@@ -373,7 +355,7 @@ public:
|
|||||||
uint32_t physId = _workToPhysMap->physIds[workId];
|
uint32_t physId = _workToPhysMap->physIds[workId];
|
||||||
if (physId != kPhysNone) {
|
if (physId != kPhysNone) {
|
||||||
const RAWorkReg* workReg = _layout.workRegs->at(workId);
|
const RAWorkReg* workReg = _layout.workRegs->at(workId);
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
ASMJIT_ASSERT(_physToWorkIds[group][physId] == workId);
|
ASMJIT_ASSERT(_physToWorkIds[group][physId] == workId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -381,7 +363,7 @@ public:
|
|||||||
|
|
||||||
// Verify PhysToWorkMap.
|
// Verify PhysToWorkMap.
|
||||||
{
|
{
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
uint32_t physCount = _layout.physCount[group];
|
uint32_t physCount = _layout.physCount[group];
|
||||||
for (uint32_t physId = 0; physId < physCount; physId++) {
|
for (uint32_t physId = 0; physId < physCount; physId++) {
|
||||||
uint32_t workId = _physToWorkIds[group][physId];
|
uint32_t workId = _physToWorkIds[group][physId];
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_RABUILDERS_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_RABUILDERS_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_RABUILDERS_P_H_INCLUDED
|
#define ASMJIT_CORE_RABUILDERS_P_H_INCLUDED
|
||||||
@@ -36,13 +18,22 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_ra
|
//! \addtogroup asmjit_ra
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::RACFGBuilderT]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
template<typename This>
|
template<typename This>
|
||||||
class RACFGBuilderT {
|
class RACFGBuilderT {
|
||||||
public:
|
public:
|
||||||
|
enum : uint32_t {
|
||||||
|
kRootIndentation = 2,
|
||||||
|
kCodeIndentation = 4,
|
||||||
|
|
||||||
|
// NOTE: This is a bit hacky. There are some nodes which are processed twice (see `onBeforeInvoke()` and
|
||||||
|
// `onBeforeRet()`) as they can insert some nodes around them. Since we don't have any flags to mark these
|
||||||
|
// we just use their position that is [at that time] unassigned.
|
||||||
|
kNodePositionDidOnBefore = 0xFFFFFFFFu
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
BaseRAPass* _pass = nullptr;
|
BaseRAPass* _pass = nullptr;
|
||||||
BaseCompiler* _cc = nullptr;
|
BaseCompiler* _cc = nullptr;
|
||||||
RABlock* _curBlock = nullptr;
|
RABlock* _curBlock = nullptr;
|
||||||
@@ -58,38 +49,30 @@ public:
|
|||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
Logger* _logger = nullptr;
|
Logger* _logger = nullptr;
|
||||||
uint32_t _logFlags = FormatOptions::kFlagPositions;
|
FormatOptions _formatOptions {};
|
||||||
StringTmp<512> _sb;
|
StringTmp<512> _sb;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static constexpr uint32_t kRootIndentation = 2;
|
//! \}
|
||||||
static constexpr uint32_t kCodeIndentation = 4;
|
|
||||||
|
|
||||||
// NOTE: This is a bit hacky. There are some nodes which are processed twice
|
|
||||||
// (see `onBeforeInvoke()` and `onBeforeRet()`) as they can insert some nodes
|
|
||||||
// around them. Since we don't have any flags to mark these we just use their
|
|
||||||
// position that is [at that time] unassigned.
|
|
||||||
static constexpr uint32_t kNodePositionDidOnBefore = 0xFFFFFFFFu;
|
|
||||||
|
|
||||||
inline RACFGBuilderT(BaseRAPass* pass) noexcept
|
inline RACFGBuilderT(BaseRAPass* pass) noexcept
|
||||||
: _pass(pass),
|
: _pass(pass),
|
||||||
_cc(pass->cc()) {
|
_cc(pass->cc()) {
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
_logger = _pass->debugLogger();
|
_logger = _pass->hasDiagnosticOption(DiagnosticOptions::kRADebugCFG) ? _pass->logger() : nullptr;
|
||||||
if (_logger)
|
if (_logger)
|
||||||
_logFlags |= _logger->flags();
|
_formatOptions = _logger->options();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline BaseCompiler* cc() const noexcept { return _cc; }
|
inline BaseCompiler* cc() const noexcept { return _cc; }
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Run
|
||||||
// [Run]
|
//! \{
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
//! Called per function by an architecture-specific CFG builder.
|
//! Called per function by an architecture-specific CFG builder.
|
||||||
Error run() noexcept {
|
Error run() noexcept {
|
||||||
log("[RAPass::BuildCFG]\n");
|
log("[BuildCFG]\n");
|
||||||
ASMJIT_PROPAGATE(prepare());
|
ASMJIT_PROPAGATE(prepare());
|
||||||
|
|
||||||
logNode(_funcNode, kRootIndentation);
|
logNode(_funcNode, kRootIndentation);
|
||||||
@@ -114,12 +97,11 @@ public:
|
|||||||
// Instruction | Jump | Invoke | Return
|
// Instruction | Jump | Invoke | Return
|
||||||
// ------------------------------------
|
// ------------------------------------
|
||||||
|
|
||||||
// Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them
|
// Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them share the same interface that provides
|
||||||
// share the same interface that provides operands that have read/write
|
// operands that have read/write semantics.
|
||||||
// semantics.
|
|
||||||
if (ASMJIT_UNLIKELY(!_curBlock)) {
|
if (ASMJIT_UNLIKELY(!_curBlock)) {
|
||||||
// Unreachable code has to be removed, we cannot allocate registers
|
// Unreachable code has to be removed, we cannot allocate registers in such code as we cannot do proper
|
||||||
// in such code as we cannot do proper liveness analysis in such case.
|
// liveness analysis in such case.
|
||||||
removeNode(node);
|
removeNode(node);
|
||||||
node = next;
|
node = next;
|
||||||
continue;
|
continue;
|
||||||
@@ -129,15 +111,13 @@ public:
|
|||||||
|
|
||||||
if (node->isInvoke() || node->isFuncRet()) {
|
if (node->isInvoke() || node->isFuncRet()) {
|
||||||
if (node->position() != kNodePositionDidOnBefore) {
|
if (node->position() != kNodePositionDidOnBefore) {
|
||||||
// Call and Reg are complicated as they may insert some surrounding
|
// Call and Reg are complicated as they may insert some surrounding code around them. The simplest
|
||||||
// code around them. The simplest approach is to get the previous
|
// approach is to get the previous node, call the `onBefore()` handlers and then check whether
|
||||||
// node, call the `onBefore()` handlers and then check whether
|
// anything changed and restart if so. By restart we mean that the current `node` would go back to
|
||||||
// anything changed and restart if so. By restart we mean that the
|
// the first possible inserted node by `onBeforeInvoke()` or `onBeforeRet()`.
|
||||||
// current `node` would go back to the first possible inserted node
|
|
||||||
// by `onBeforeInvoke()` or `onBeforeRet()`.
|
|
||||||
BaseNode* prev = node->prev();
|
BaseNode* prev = node->prev();
|
||||||
|
|
||||||
if (node->type() == BaseNode::kNodeInvoke)
|
if (node->type() == NodeType::kInvoke)
|
||||||
ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeInvoke(node->as<InvokeNode>()));
|
ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeInvoke(node->as<InvokeNode>()));
|
||||||
else
|
else
|
||||||
ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeRet(node->as<FuncRetNode>()));
|
ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeRet(node->as<FuncRetNode>()));
|
||||||
@@ -167,9 +147,9 @@ public:
|
|||||||
InstNode* inst = node->as<InstNode>();
|
InstNode* inst = node->as<InstNode>();
|
||||||
logNode(inst, kCodeIndentation);
|
logNode(inst, kCodeIndentation);
|
||||||
|
|
||||||
uint32_t controlType = BaseInst::kControlNone;
|
InstControlFlow cf = InstControlFlow::kRegular;
|
||||||
ib.reset();
|
ib.reset();
|
||||||
ASMJIT_PROPAGATE(static_cast<This*>(this)->onInst(inst, controlType, ib));
|
ASMJIT_PROPAGATE(static_cast<This*>(this)->onInst(inst, cf, ib));
|
||||||
|
|
||||||
if (node->isInvoke()) {
|
if (node->isInvoke()) {
|
||||||
ASMJIT_PROPAGATE(static_cast<This*>(this)->onInvoke(inst->as<InvokeNode>(), ib));
|
ASMJIT_PROPAGATE(static_cast<This*>(this)->onInvoke(inst->as<InvokeNode>(), ib));
|
||||||
@@ -177,20 +157,20 @@ public:
|
|||||||
|
|
||||||
if (node->isFuncRet()) {
|
if (node->isFuncRet()) {
|
||||||
ASMJIT_PROPAGATE(static_cast<This*>(this)->onRet(inst->as<FuncRetNode>(), ib));
|
ASMJIT_PROPAGATE(static_cast<This*>(this)->onRet(inst->as<FuncRetNode>(), ib));
|
||||||
controlType = BaseInst::kControlReturn;
|
cf = InstControlFlow::kReturn;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlType == BaseInst::kControlJump) {
|
if (cf == InstControlFlow::kJump) {
|
||||||
uint32_t fixedRegCount = 0;
|
uint32_t fixedRegCount = 0;
|
||||||
for (RATiedReg& tiedReg : ib) {
|
for (RATiedReg& tiedReg : ib) {
|
||||||
RAWorkReg* workReg = _pass->workRegById(tiedReg.workId());
|
RAWorkReg* workReg = _pass->workRegById(tiedReg.workId());
|
||||||
if (workReg->group() == BaseReg::kGroupGp) {
|
if (workReg->group() == RegGroup::kGp) {
|
||||||
uint32_t useId = tiedReg.useId();
|
uint32_t useId = tiedReg.useId();
|
||||||
if (useId == BaseReg::kIdBad) {
|
if (useId == BaseReg::kIdBad) {
|
||||||
useId = _pass->_scratchRegIndexes[fixedRegCount++];
|
useId = _pass->_scratchRegIndexes[fixedRegCount++];
|
||||||
tiedReg.setUseId(useId);
|
tiedReg.setUseId(useId);
|
||||||
}
|
}
|
||||||
_curBlock->addExitScratchGpRegs(Support::bitMask<uint32_t>(useId));
|
_curBlock->addExitScratchGpRegs(Support::bitMask(useId));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,14 +178,14 @@ public:
|
|||||||
ASMJIT_PROPAGATE(_pass->assignRAInst(inst, _curBlock, ib));
|
ASMJIT_PROPAGATE(_pass->assignRAInst(inst, _curBlock, ib));
|
||||||
_blockRegStats.combineWith(ib._stats);
|
_blockRegStats.combineWith(ib._stats);
|
||||||
|
|
||||||
if (controlType != BaseInst::kControlNone) {
|
if (cf != InstControlFlow::kRegular) {
|
||||||
// Support for conditional and unconditional jumps.
|
// Support for conditional and unconditional jumps.
|
||||||
if (controlType == BaseInst::kControlJump || controlType == BaseInst::kControlBranch) {
|
if (cf == InstControlFlow::kJump || cf == InstControlFlow::kBranch) {
|
||||||
_curBlock->setLast(node);
|
_curBlock->setLast(node);
|
||||||
_curBlock->addFlags(RABlock::kFlagHasTerminator);
|
_curBlock->addFlags(RABlockFlags::kHasTerminator);
|
||||||
_curBlock->makeConstructed(_blockRegStats);
|
_curBlock->makeConstructed(_blockRegStats);
|
||||||
|
|
||||||
if (!(inst->instOptions() & BaseInst::kOptionUnfollow)) {
|
if (!inst->hasOption(InstOptions::kUnfollow)) {
|
||||||
// Jmp/Jcc/Call/Loop/etc...
|
// Jmp/Jcc/Call/Loop/etc...
|
||||||
uint32_t opCount = inst->opCount();
|
uint32_t opCount = inst->opCount();
|
||||||
const Operand* opArray = inst->operands();
|
const Operand* opArray = inst->operands();
|
||||||
@@ -227,14 +207,13 @@ public:
|
|||||||
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(targetBlock));
|
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(targetBlock));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Not a label - could be jump with reg/mem operand, which
|
// Not a label - could be jump with reg/mem operand, which means that it can go anywhere. Such jumps
|
||||||
// means that it can go anywhere. Such jumps must either be
|
// must either be annotated so the CFG can be properly constructed, otherwise we assume the worst case
|
||||||
// annotated so the CFG can be properly constructed, otherwise
|
// - can jump to any basic block.
|
||||||
// we assume the worst case - can jump to any basic block.
|
|
||||||
JumpAnnotation* jumpAnnotation = nullptr;
|
JumpAnnotation* jumpAnnotation = nullptr;
|
||||||
_curBlock->addFlags(RABlock::kFlagHasJumpTable);
|
_curBlock->addFlags(RABlockFlags::kHasJumpTable);
|
||||||
|
|
||||||
if (inst->type() == BaseNode::kNodeJump)
|
if (inst->type() == NodeType::kJump)
|
||||||
jumpAnnotation = inst->as<JumpNode>()->annotation();
|
jumpAnnotation = inst->as<JumpNode>()->annotation();
|
||||||
|
|
||||||
if (jumpAnnotation) {
|
if (jumpAnnotation) {
|
||||||
@@ -262,13 +241,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlType == BaseInst::kControlJump) {
|
if (cf == InstControlFlow::kJump) {
|
||||||
// Unconditional jump makes the code after the jump unreachable,
|
// Unconditional jump makes the code after the jump unreachable, which will be removed instantly during
|
||||||
// which will be removed instantly during the CFG construction;
|
// the CFG construction; as we cannot allocate registers for instructions that are not part of any block.
|
||||||
// as we cannot allocate registers for instructions that are not
|
// Of course we can leave these instructions as they are, however, that would only postpone the problem
|
||||||
// part of any block. Of course we can leave these instructions
|
// as assemblers can't encode instructions that use virtual registers.
|
||||||
// as they are, however, that would only postpone the problem as
|
|
||||||
// assemblers can't encode instructions that use virtual registers.
|
|
||||||
_curBlock = nullptr;
|
_curBlock = nullptr;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -277,7 +254,7 @@ public:
|
|||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
RABlock* consecutiveBlock;
|
RABlock* consecutiveBlock;
|
||||||
if (node->type() == BaseNode::kNodeLabel) {
|
if (node->type() == NodeType::kLabel) {
|
||||||
if (node->hasPassData()) {
|
if (node->hasPassData()) {
|
||||||
consecutiveBlock = node->passData<RABlock>();
|
consecutiveBlock = node->passData<RABlock>();
|
||||||
}
|
}
|
||||||
@@ -294,7 +271,7 @@ public:
|
|||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
_curBlock->addFlags(RABlock::kFlagHasConsecutive);
|
_curBlock->addFlags(RABlockFlags::kHasConsecutive);
|
||||||
ASMJIT_PROPAGATE(_curBlock->prependSuccessor(consecutiveBlock));
|
ASMJIT_PROPAGATE(_curBlock->prependSuccessor(consecutiveBlock));
|
||||||
|
|
||||||
_curBlock = consecutiveBlock;
|
_curBlock = consecutiveBlock;
|
||||||
@@ -310,7 +287,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (controlType == BaseInst::kControlReturn) {
|
if (cf == InstControlFlow::kReturn) {
|
||||||
_curBlock->setLast(node);
|
_curBlock->setLast(node);
|
||||||
_curBlock->makeConstructed(_blockRegStats);
|
_curBlock->makeConstructed(_blockRegStats);
|
||||||
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(_retBlock));
|
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(_retBlock));
|
||||||
@@ -319,19 +296,18 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node->type() == BaseNode::kNodeLabel) {
|
else if (node->type() == NodeType::kLabel) {
|
||||||
// Label - Basic-Block Management
|
// Label - Basic-Block Management
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
|
|
||||||
if (!_curBlock) {
|
if (!_curBlock) {
|
||||||
// If the current code is unreachable the label makes it reachable
|
// If the current code is unreachable the label makes it reachable again. We may remove the whole block in
|
||||||
// again. We may remove the whole block in the future if it's not
|
// the future if it's not referenced though.
|
||||||
// referenced though.
|
|
||||||
_curBlock = node->passData<RABlock>();
|
_curBlock = node->passData<RABlock>();
|
||||||
|
|
||||||
if (_curBlock) {
|
if (_curBlock) {
|
||||||
// If the label has a block assigned we can either continue with
|
// If the label has a block assigned we can either continue with it or skip it if the block has been
|
||||||
// it or skip it if the block has been constructed already.
|
// constructed already.
|
||||||
if (_curBlock->isConstructed())
|
if (_curBlock->isConstructed())
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -354,20 +330,18 @@ public:
|
|||||||
consecutive->makeTargetable();
|
consecutive->makeTargetable();
|
||||||
|
|
||||||
if (_curBlock == consecutive) {
|
if (_curBlock == consecutive) {
|
||||||
// The label currently processed is part of the current block. This
|
// The label currently processed is part of the current block. This is only possible for multiple labels
|
||||||
// is only possible for multiple labels that are right next to each
|
// that are right next to each other or labels that are separated by non-code nodes like directives and
|
||||||
// other or labels that are separated by non-code nodes like directives
|
// comments.
|
||||||
// and comments.
|
|
||||||
if (ASMJIT_UNLIKELY(_hasCode))
|
if (ASMJIT_UNLIKELY(_hasCode))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Label makes the current block constructed. There is a chance that the
|
// Label makes the current block constructed. There is a chance that the Label is not used, but we don't
|
||||||
// Label is not used, but we don't know that at this point. In the worst
|
// know that at this point. In the worst case there would be two blocks next to each other, it's just fine.
|
||||||
// case there would be two blocks next to each other, it's just fine.
|
|
||||||
ASMJIT_ASSERT(_curBlock->last() != node);
|
ASMJIT_ASSERT(_curBlock->last() != node);
|
||||||
_curBlock->setLast(node->prev());
|
_curBlock->setLast(node->prev());
|
||||||
_curBlock->addFlags(RABlock::kFlagHasConsecutive);
|
_curBlock->addFlags(RABlockFlags::kHasConsecutive);
|
||||||
_curBlock->makeConstructed(_blockRegStats);
|
_curBlock->makeConstructed(_blockRegStats);
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(consecutive));
|
ASMJIT_PROPAGATE(_curBlock->appendSuccessor(consecutive));
|
||||||
@@ -381,12 +355,11 @@ public:
|
|||||||
else {
|
else {
|
||||||
// First time we see this label.
|
// First time we see this label.
|
||||||
if (_hasCode || _curBlock == entryBlock) {
|
if (_hasCode || _curBlock == entryBlock) {
|
||||||
// Cannot continue the current block if it already contains some
|
// Cannot continue the current block if it already contains some code or it's a block entry. We need to
|
||||||
// code or it's a block entry. We need to create a new block and
|
// create a new block and make it a successor.
|
||||||
// make it a successor.
|
|
||||||
ASMJIT_ASSERT(_curBlock->last() != node);
|
ASMJIT_ASSERT(_curBlock->last() != node);
|
||||||
_curBlock->setLast(node->prev());
|
_curBlock->setLast(node->prev());
|
||||||
_curBlock->addFlags(RABlock::kFlagHasConsecutive);
|
_curBlock->addFlags(RABlockFlags::kHasConsecutive);
|
||||||
_curBlock->makeConstructed(_blockRegStats);
|
_curBlock->makeConstructed(_blockRegStats);
|
||||||
|
|
||||||
RABlock* consecutive = _pass->newBlock(node);
|
RABlock* consecutive = _pass->newBlock(node);
|
||||||
@@ -425,7 +398,7 @@ public:
|
|||||||
|
|
||||||
logNode(node, kCodeIndentation);
|
logNode(node, kCodeIndentation);
|
||||||
|
|
||||||
if (node->type() == BaseNode::kNodeSentinel) {
|
if (node->type() == NodeType::kSentinel) {
|
||||||
if (node == _funcNode->endNode()) {
|
if (node == _funcNode->endNode()) {
|
||||||
// Make sure we didn't flow here if this is the end of the function sentinel.
|
// Make sure we didn't flow here if this is the end of the function sentinel.
|
||||||
if (ASMJIT_UNLIKELY(_curBlock))
|
if (ASMJIT_UNLIKELY(_curBlock))
|
||||||
@@ -433,7 +406,7 @@ public:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if (node->type() == BaseNode::kNodeFunc) {
|
else if (node->type() == NodeType::kFunc) {
|
||||||
// RAPass can only compile a single function at a time. If we
|
// RAPass can only compile a single function at a time. If we
|
||||||
// encountered a function it must be the current one, bail if not.
|
// encountered a function it must be the current one, bail if not.
|
||||||
if (ASMJIT_UNLIKELY(node != _funcNode))
|
if (ASMJIT_UNLIKELY(node != _funcNode))
|
||||||
@@ -448,10 +421,9 @@ public:
|
|||||||
// Advance to the next node.
|
// Advance to the next node.
|
||||||
node = next;
|
node = next;
|
||||||
|
|
||||||
// NOTE: We cannot encounter a NULL node, because every function must be
|
// NOTE: We cannot encounter a NULL node, because every function must be terminated by a sentinel (`stop`)
|
||||||
// terminated by a sentinel (`stop`) node. If we encountered a NULL node it
|
// node. If we encountered a NULL node it means that something went wrong and this node list is corrupted;
|
||||||
// means that something went wrong and this node list is corrupted; bail in
|
// bail in such case.
|
||||||
// such case.
|
|
||||||
if (ASMJIT_UNLIKELY(!node))
|
if (ASMJIT_UNLIKELY(!node))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
}
|
}
|
||||||
@@ -465,9 +437,10 @@ public:
|
|||||||
return _pass->initSharedAssignments(_sharedAssignmentsMap);
|
return _pass->initSharedAssignments(_sharedAssignmentsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \}
|
||||||
// [Prepare]
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Prepare
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Prepares the CFG builder of the current function.
|
//! Prepares the CFG builder of the current function.
|
||||||
Error prepare() noexcept {
|
Error prepare() noexcept {
|
||||||
@@ -504,9 +477,10 @@ public:
|
|||||||
return _pass->addBlock(_curBlock);
|
return _pass->addBlock(_curBlock);
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \}
|
||||||
// [Utilities]
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Utilities
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Called when a `node` is removed, e.g. because of a dead code elimination.
|
//! Called when a `node` is removed, e.g. because of a dead code elimination.
|
||||||
void removeNode(BaseNode* node) noexcept {
|
void removeNode(BaseNode* node) noexcept {
|
||||||
@@ -516,9 +490,8 @@ public:
|
|||||||
|
|
||||||
//! Handles block with unknown jump, which could be a jump to a jump table.
|
//! Handles block with unknown jump, which could be a jump to a jump table.
|
||||||
//!
|
//!
|
||||||
//! If we encounter such block we basically insert all existing blocks as
|
//! If we encounter such block we basically insert all existing blocks as successors except the function entry
|
||||||
//! successors except the function entry block and a natural successor, if
|
//! block and a natural successor, if such block exists.
|
||||||
//! such block exists.
|
|
||||||
Error handleBlockWithUnknownJump(RABlock* block) noexcept {
|
Error handleBlockWithUnknownJump(RABlock* block) noexcept {
|
||||||
RABlocks& blocks = _pass->blocks();
|
RABlocks& blocks = _pass->blocks();
|
||||||
size_t blockCount = blocks.size();
|
size_t blockCount = blocks.size();
|
||||||
@@ -570,9 +543,10 @@ public:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
//! \}
|
||||||
// [Logging]
|
|
||||||
// --------------------------------------------------------------------------
|
//! \name Logging
|
||||||
|
//! \{
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_LOGGING
|
#ifndef ASMJIT_NO_LOGGING
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
@@ -606,7 +580,7 @@ public:
|
|||||||
_sb.append(action);
|
_sb.append(action);
|
||||||
_sb.append(' ');
|
_sb.append(' ');
|
||||||
}
|
}
|
||||||
Formatter::formatNode(_sb, _logFlags, cc(), node);
|
Formatter::formatNode(_sb, _formatOptions, cc(), node);
|
||||||
_sb.append('\n');
|
_sb.append('\n');
|
||||||
_logger->log(_sb);
|
_logger->log(_sb);
|
||||||
}
|
}
|
||||||
@@ -625,6 +599,8 @@ public:
|
|||||||
DebugUtils::unused(node, indentation, action);
|
DebugUtils::unused(node, indentation, action);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
#ifndef ASMJIT_NO_COMPILER
|
||||||
@@ -29,20 +11,18 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// RALocalAllocator - Utilities
|
||||||
// [asmjit::RALocalAllocator - Utilities]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static ASMJIT_INLINE RATiedReg* RALocal_findTiedRegByWorkId(RATiedReg* tiedRegs, size_t count, uint32_t workId) noexcept {
|
static ASMJIT_FORCE_INLINE RATiedReg* RALocal_findTiedRegByWorkId(RATiedReg* tiedRegs, size_t count, uint32_t workId) noexcept {
|
||||||
for (size_t i = 0; i < count; i++)
|
for (size_t i = 0; i < count; i++)
|
||||||
if (tiedRegs[i].workId() == workId)
|
if (tiedRegs[i].workId() == workId)
|
||||||
return &tiedRegs[i];
|
return &tiedRegs[i];
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// RALocalAllocator - Init & Reset
|
||||||
// [asmjit::RALocalAllocator - Init / Reset]
|
// ===============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error RALocalAllocator::init() noexcept {
|
Error RALocalAllocator::init() noexcept {
|
||||||
PhysToWorkMap* physToWorkMap;
|
PhysToWorkMap* physToWorkMap;
|
||||||
@@ -67,9 +47,8 @@ Error RALocalAllocator::init() noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// RALocalAllocator - Assignment
|
||||||
// [asmjit::RALocalAllocator - Assignment]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error RALocalAllocator::makeInitialAssignment() noexcept {
|
Error RALocalAllocator::makeInitialAssignment() noexcept {
|
||||||
FuncNode* func = _pass->func();
|
FuncNode* func = _pass->func();
|
||||||
@@ -83,10 +62,12 @@ Error RALocalAllocator::makeInitialAssignment() noexcept {
|
|||||||
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
|
for (uint32_t argIndex = 0; argIndex < argCount; argIndex++) {
|
||||||
for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
|
for (uint32_t valueIndex = 0; valueIndex < Globals::kMaxValuePack; valueIndex++) {
|
||||||
// Unassigned argument.
|
// Unassigned argument.
|
||||||
VirtReg* virtReg = func->argPack(argIndex)[valueIndex];
|
const RegOnly& regArg = func->argPack(argIndex)[valueIndex];
|
||||||
if (!virtReg)
|
if (!regArg.isReg() || !_cc->isVirtIdValid(regArg.id()))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
VirtReg* virtReg = _cc->virtRegById(regArg.id());
|
||||||
|
|
||||||
// Unreferenced argument.
|
// Unreferenced argument.
|
||||||
RAWorkReg* workReg = virtReg->workReg();
|
RAWorkReg* workReg = virtReg->workReg();
|
||||||
if (!workReg)
|
if (!workReg)
|
||||||
@@ -97,18 +78,18 @@ Error RALocalAllocator::makeInitialAssignment() noexcept {
|
|||||||
if (!liveIn.bitAt(workId))
|
if (!liveIn.bitAt(workId))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
if (_curAssignment.workToPhysId(group, workId) != RAAssignment::kPhysNone)
|
if (_curAssignment.workToPhysId(group, workId) != RAAssignment::kPhysNone)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
uint32_t allocableRegs = _availableRegs[group] & ~_curAssignment.assigned(group);
|
RegMask allocableRegs = _availableRegs[group] & ~_curAssignment.assigned(group);
|
||||||
if (iter == 0) {
|
if (iter == 0) {
|
||||||
// First iteration: Try to allocate to home RegId.
|
// First iteration: Try to allocate to home RegId.
|
||||||
if (workReg->hasHomeRegId()) {
|
if (workReg->hasHomeRegId()) {
|
||||||
uint32_t physId = workReg->homeRegId();
|
uint32_t physId = workReg->homeRegId();
|
||||||
if (Support::bitTest(allocableRegs, physId)) {
|
if (Support::bitTest(allocableRegs, physId)) {
|
||||||
_curAssignment.assign(group, workId, physId, true);
|
_curAssignment.assign(group, workId, physId, true);
|
||||||
_pass->_argsAssignment.assignRegInPack(argIndex, valueIndex, workReg->info().type(), physId, workReg->typeId());
|
_pass->_argsAssignment.assignRegInPack(argIndex, valueIndex, workReg->type(), physId, workReg->typeId());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -120,7 +101,7 @@ Error RALocalAllocator::makeInitialAssignment() noexcept {
|
|||||||
if (allocableRegs) {
|
if (allocableRegs) {
|
||||||
uint32_t physId = Support::ctz(allocableRegs);
|
uint32_t physId = Support::ctz(allocableRegs);
|
||||||
_curAssignment.assign(group, workId, physId, true);
|
_curAssignment.assign(group, workId, physId, true);
|
||||||
_pass->_argsAssignment.assignRegInPack(argIndex, valueIndex, workReg->info().type(), physId, workReg->typeId());
|
_pass->_argsAssignment.assignRegInPack(argIndex, valueIndex, workReg->type(), physId, workReg->typeId());
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// This register will definitely need stack, create the slot now and assign also `argIndex`
|
// This register will definitely need stack, create the slot now and assign also `argIndex`
|
||||||
@@ -130,7 +111,7 @@ Error RALocalAllocator::makeInitialAssignment() noexcept {
|
|||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
// This means STACK_ARG may be moved to STACK.
|
// This means STACK_ARG may be moved to STACK.
|
||||||
workReg->addFlags(RAWorkReg::kFlagStackArgToStack);
|
workReg->addFlags(RAWorkRegFlags::kStackArgToStack);
|
||||||
_pass->_numStackArgsToStackSlots++;
|
_pass->_numStackArgsToStackSlots++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -165,15 +146,15 @@ Error RALocalAllocator::switchToAssignment(
|
|||||||
if (tryMode)
|
if (tryMode)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
// ------------------------------------------------------------------------
|
// STEP 1
|
||||||
// STEP 1:
|
// ------
|
||||||
|
//
|
||||||
// - KILL all registers that are not live at `dst`,
|
// - KILL all registers that are not live at `dst`,
|
||||||
// - SPILL all registers that are not assigned at `dst`.
|
// - SPILL all registers that are not assigned at `dst`.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (!tryMode) {
|
if (!tryMode) {
|
||||||
Support::BitWordIterator<uint32_t> it(cur.assigned(group));
|
Support::BitWordIterator<RegMask> it(cur.assigned(group));
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
uint32_t physId = it.next();
|
uint32_t physId = it.next();
|
||||||
uint32_t workId = cur.physToWorkId(group, physId);
|
uint32_t workId = cur.physToWorkId(group, physId);
|
||||||
@@ -195,19 +176,18 @@ Error RALocalAllocator::switchToAssignment(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 2
|
||||||
// STEP 2:
|
// ------
|
||||||
// - MOVE and SWAP registers from their current assignments into their
|
//
|
||||||
// DST assignments.
|
// - MOVE and SWAP registers from their current assignments into their DST assignments.
|
||||||
// - Build `willLoadRegs` mask of registers scheduled for `onLoadReg()`.
|
// - Build `willLoadRegs` mask of registers scheduled for `onLoadReg()`.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Current run-id (1 means more aggressive decisions).
|
// Current run-id (1 means more aggressive decisions).
|
||||||
int32_t runId = -1;
|
int32_t runId = -1;
|
||||||
// Remaining registers scheduled for `onLoadReg()`.
|
// Remaining registers scheduled for `onLoadReg()`.
|
||||||
uint32_t willLoadRegs = 0;
|
RegMask willLoadRegs = 0;
|
||||||
// Remaining registers to be allocated in this loop.
|
// Remaining registers to be allocated in this loop.
|
||||||
uint32_t affectedRegs = dst.assigned(group);
|
RegMask affectedRegs = dst.assigned(group);
|
||||||
|
|
||||||
while (affectedRegs) {
|
while (affectedRegs) {
|
||||||
if (++runId == 2) {
|
if (++runId == 2) {
|
||||||
@@ -218,10 +198,10 @@ Error RALocalAllocator::switchToAssignment(
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
Support::BitWordIterator<uint32_t> it(affectedRegs);
|
Support::BitWordIterator<RegMask> it(affectedRegs);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
uint32_t physId = it.next();
|
uint32_t physId = it.next();
|
||||||
uint32_t physMask = Support::bitMask(physId);
|
RegMask physMask = Support::bitMask<RegMask>(physId);
|
||||||
|
|
||||||
uint32_t curWorkId = cur.physToWorkId(group, physId);
|
uint32_t curWorkId = cur.physToWorkId(group, physId);
|
||||||
uint32_t dstWorkId = dst.physToWorkId(group, physId);
|
uint32_t dstWorkId = dst.physToWorkId(group, physId);
|
||||||
@@ -243,7 +223,7 @@ Error RALocalAllocator::switchToAssignment(
|
|||||||
// Reset as we will do some changes to the current assignment.
|
// Reset as we will do some changes to the current assignment.
|
||||||
runId = -1;
|
runId = -1;
|
||||||
|
|
||||||
if (_archTraits->hasSwap(group)) {
|
if (_archTraits->hasInstRegSwap(group)) {
|
||||||
ASMJIT_PROPAGATE(onSwapReg(group, curWorkId, physId, dstWorkId, altPhysId));
|
ASMJIT_PROPAGATE(onSwapReg(group, curWorkId, physId, dstWorkId, altPhysId));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -252,7 +232,7 @@ Error RALocalAllocator::switchToAssignment(
|
|||||||
ASMJIT_PROPAGATE(onKillReg(group, curWorkId, physId));
|
ASMJIT_PROPAGATE(onKillReg(group, curWorkId, physId));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
uint32_t allocableRegs = _pass->_availableRegs[group] & ~cur.assigned(group);
|
RegMask allocableRegs = _pass->_availableRegs[group] & ~cur.assigned(group);
|
||||||
|
|
||||||
// If possible don't conflict with assigned regs at DST.
|
// If possible don't conflict with assigned regs at DST.
|
||||||
if (allocableRegs & ~dst.assigned(group))
|
if (allocableRegs & ~dst.assigned(group))
|
||||||
@@ -294,9 +274,8 @@ Cleared:
|
|||||||
// CUR dirty, DST not dirty (the assert is just to visualize the condition).
|
// CUR dirty, DST not dirty (the assert is just to visualize the condition).
|
||||||
ASMJIT_ASSERT(!dst.isPhysDirty(group, physId) && cur.isPhysDirty(group, physId));
|
ASMJIT_ASSERT(!dst.isPhysDirty(group, physId) && cur.isPhysDirty(group, physId));
|
||||||
|
|
||||||
// If `dstReadOnly` is true it means that that block was already
|
// If `dstReadOnly` is true it means that that block was already processed and we cannot change from
|
||||||
// processed and we cannot change from CLEAN to DIRTY. In that case
|
// CLEAN to DIRTY. In that case the register has to be saved as it cannot enter the block DIRTY.
|
||||||
// the register has to be saved as it cannot enter the block DIRTY.
|
|
||||||
if (dstReadOnly)
|
if (dstReadOnly)
|
||||||
ASMJIT_PROPAGATE(onSaveReg(group, dstWorkId, physId));
|
ASMJIT_PROPAGATE(onSaveReg(group, dstWorkId, physId));
|
||||||
else
|
else
|
||||||
@@ -319,13 +298,13 @@ Cleared:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 3
|
||||||
// STEP 3:
|
// ------
|
||||||
|
//
|
||||||
// - Load registers specified by `willLoadRegs`.
|
// - Load registers specified by `willLoadRegs`.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
{
|
{
|
||||||
Support::BitWordIterator<uint32_t> it(willLoadRegs);
|
Support::BitWordIterator<RegMask> it(willLoadRegs);
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
uint32_t physId = it.next();
|
uint32_t physId = it.next();
|
||||||
|
|
||||||
@@ -349,7 +328,7 @@ Cleared:
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tryMode) {
|
if (!tryMode) {
|
||||||
// Hre is a code that dumps the conflicting part if something fails here:
|
// Here is a code that dumps the conflicting part if something fails here:
|
||||||
// if (!dst.equals(cur)) {
|
// if (!dst.equals(cur)) {
|
||||||
// uint32_t physTotal = dst._layout.physTotal;
|
// uint32_t physTotal = dst._layout.physTotal;
|
||||||
// uint32_t workCount = dst._layout.workCount;
|
// uint32_t workCount = dst._layout.workCount;
|
||||||
@@ -374,9 +353,9 @@ Cleared:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error RALocalAllocator::spillScratchGpRegsBeforeEntry(uint32_t scratchRegs) noexcept {
|
Error RALocalAllocator::spillScratchGpRegsBeforeEntry(RegMask scratchRegs) noexcept {
|
||||||
uint32_t group = BaseReg::kGroupGp;
|
RegGroup group = RegGroup::kGp;
|
||||||
Support::BitWordIterator<uint32_t> it(scratchRegs);
|
Support::BitWordIterator<RegMask> it(scratchRegs);
|
||||||
|
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
uint32_t physId = it.next();
|
uint32_t physId = it.next();
|
||||||
@@ -389,15 +368,15 @@ Error RALocalAllocator::spillScratchGpRegsBeforeEntry(uint32_t scratchRegs) noex
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// RALocalAllocator - Allocation
|
||||||
// [asmjit::RALocalAllocator - Allocation]
|
// =============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
||||||
RAInst* raInst = node->passData<RAInst>();
|
RAInst* raInst = node->passData<RAInst>();
|
||||||
|
|
||||||
RATiedReg* outTiedRegs[Globals::kMaxPhysRegs];
|
RATiedReg* outTiedRegs[Globals::kMaxPhysRegs];
|
||||||
RATiedReg* dupTiedRegs[Globals::kMaxPhysRegs];
|
RATiedReg* dupTiedRegs[Globals::kMaxPhysRegs];
|
||||||
|
RATiedReg* consecutiveRegs[kMaxConsecutiveRegs];
|
||||||
|
|
||||||
// The cursor must point to the previous instruction for a possible instruction insertion.
|
// The cursor must point to the previous instruction for a possible instruction insertion.
|
||||||
_cc->_setCursor(node->prev());
|
_cc->_setCursor(node->prev());
|
||||||
@@ -410,34 +389,43 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
// Whether we already replaced register operand with memory operand.
|
// Whether we already replaced register operand with memory operand.
|
||||||
bool rmAllocated = false;
|
bool rmAllocated = false;
|
||||||
|
|
||||||
for (uint32_t group = 0; group < BaseReg::kGroupVirt; group++) {
|
for (RegGroup group : RegGroupVirtValues{}) {
|
||||||
uint32_t i, count = this->tiedCount(group);
|
uint32_t i, count = this->tiedCount(group);
|
||||||
RATiedReg* tiedRegs = this->tiedRegs(group);
|
RATiedReg* tiedRegs = this->tiedRegs(group);
|
||||||
|
|
||||||
uint32_t willUse = _raInst->_usedRegs[group];
|
RegMask willUse = _raInst->_usedRegs[group];
|
||||||
uint32_t willOut = _raInst->_clobberedRegs[group];
|
RegMask willOut = _raInst->_clobberedRegs[group];
|
||||||
uint32_t willFree = 0;
|
RegMask willFree = 0;
|
||||||
uint32_t usePending = count;
|
|
||||||
|
|
||||||
|
uint32_t usePending = count;
|
||||||
uint32_t outTiedCount = 0;
|
uint32_t outTiedCount = 0;
|
||||||
uint32_t dupTiedCount = 0;
|
uint32_t dupTiedCount = 0;
|
||||||
|
uint32_t consecutiveMask = 0;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 1
|
||||||
// STEP 1:
|
// ------
|
||||||
//
|
//
|
||||||
// Calculate `willUse` and `willFree` masks based on tied registers we have.
|
// Calculate `willUse` and `willFree` masks based on tied registers we have. In addition, aggregate information
|
||||||
|
// regarding consecutive registers used by this instruction. We need that to make USE/OUT assignments.
|
||||||
//
|
//
|
||||||
// We don't do any assignment decisions at this stage as we just need to
|
// We don't do any assignment decisions at this stage as we just need to collect some information first. Then,
|
||||||
// collect some information first. Then, after we populate all masks needed
|
// after we populate all masks needed we can finally make some decisions in the second loop. The main reason
|
||||||
// we can finally make some decisions in the second loop. The main reason
|
// for this is that we really need `willFree` to make assignment decisions for `willUse`, because if we mark
|
||||||
// for this is that we really need `willFree` to make assignment decisions
|
// some registers that will be freed, we can consider them in decision making afterwards.
|
||||||
// for `willUse`, because if we mark some registers that will be freed, we
|
|
||||||
// can consider them in decision making afterwards.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
RATiedReg* tiedReg = &tiedRegs[i];
|
RATiedReg* tiedReg = &tiedRegs[i];
|
||||||
|
|
||||||
|
if (tiedReg->hasAnyConsecutiveFlag()) {
|
||||||
|
uint32_t consecutiveOffset = tiedReg->isLeadConsecutive() ? uint32_t(0) : tiedReg->consecutiveData();
|
||||||
|
|
||||||
|
if (ASMJIT_UNLIKELY(Support::bitTest(consecutiveMask, consecutiveOffset)))
|
||||||
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
|
consecutiveMask |= Support::bitMask(consecutiveOffset);
|
||||||
|
consecutiveRegs[consecutiveOffset] = tiedReg;
|
||||||
|
}
|
||||||
|
|
||||||
// Add OUT and KILL to `outPending` for CLOBBERing and/or OUT assignment.
|
// Add OUT and KILL to `outPending` for CLOBBERing and/or OUT assignment.
|
||||||
if (tiedReg->isOutOrKill())
|
if (tiedReg->isOutOrKill())
|
||||||
outTiedRegs[outTiedCount++] = tiedReg;
|
outTiedRegs[outTiedCount++] = tiedReg;
|
||||||
@@ -451,12 +439,16 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Don't assign anything here if this is a consecutive USE - we will handle this in STEP 2 instead.
|
||||||
|
if (tiedReg->isUseConsecutive())
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
||||||
|
|
||||||
if (tiedReg->hasUseId()) {
|
if (tiedReg->hasUseId()) {
|
||||||
// If the register has `useId` it means it can only be allocated in that register.
|
// If the register has `useId` it means it can only be allocated in that register.
|
||||||
uint32_t useMask = Support::bitMask(tiedReg->useId());
|
RegMask useMask = Support::bitMask(tiedReg->useId());
|
||||||
|
|
||||||
// RAInstBuilder must have collected `usedRegs` on-the-fly.
|
// RAInstBuilder must have collected `usedRegs` on-the-fly.
|
||||||
ASMJIT_ASSERT((willUse & useMask) != 0);
|
ASMJIT_ASSERT((willUse & useMask) != 0);
|
||||||
@@ -475,9 +467,9 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
// Check if the register must be moved to `allocableRegs`.
|
// Check if the register must be moved to `allocableRegs`.
|
||||||
uint32_t allocableRegs = tiedReg->allocableRegs();
|
RegMask allocableRegs = tiedReg->useRegMask();
|
||||||
if (assignedId != RAAssignment::kPhysNone) {
|
if (assignedId != RAAssignment::kPhysNone) {
|
||||||
uint32_t assignedMask = Support::bitMask(assignedId);
|
RegMask assignedMask = Support::bitMask(assignedId);
|
||||||
if ((allocableRegs & ~willUse) & assignedMask) {
|
if ((allocableRegs & ~willUse) & assignedMask) {
|
||||||
tiedReg->setUseId(assignedId);
|
tiedReg->setUseId(assignedId);
|
||||||
tiedReg->markUseDone();
|
tiedReg->markUseDone();
|
||||||
@@ -493,24 +485,107 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 2
|
||||||
// STEP 2:
|
// ------
|
||||||
//
|
//
|
||||||
// Do some decision making to find the best candidates of registers that
|
// Verify that all the consecutive registers are really consecutive. Terminate if there is a gap. In addition,
|
||||||
// need to be assigned, moved, and/or spilled. Only USE registers are
|
// decide which USE ids will be used in case that this consecutive sequence is USE (OUT registers are allocated
|
||||||
// considered here, OUT will be decided later after all CLOBBERed and OUT
|
// in a different step).
|
||||||
|
uint32_t consecutiveCount = 0;
|
||||||
|
|
||||||
|
if (consecutiveMask) {
|
||||||
|
if ((consecutiveMask & (consecutiveMask + 1u)) != 0)
|
||||||
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
|
||||||
|
// Count of trailing ones is the count of consecutive registers. There cannot be gap.
|
||||||
|
consecutiveCount = Support::ctz(~consecutiveMask);
|
||||||
|
|
||||||
|
// Prioritize allocation that would result in least moves even when moving registers away from their homes.
|
||||||
|
RATiedReg* lead = consecutiveRegs[0];
|
||||||
|
|
||||||
|
// Assign the best possible USE Ids to all consecutives.
|
||||||
|
if (lead->isUseConsecutive()) {
|
||||||
|
uint32_t bestScore = 0;
|
||||||
|
uint32_t bestLeadReg = 0xFFFFFFFF;
|
||||||
|
RegMask allocableRegs = (_availableRegs[group] | willFree) & ~willUse;
|
||||||
|
|
||||||
|
uint32_t assignments[kMaxConsecutiveRegs];
|
||||||
|
|
||||||
|
for (i = 0; i < consecutiveCount; i++)
|
||||||
|
assignments[i] = _curAssignment.workToPhysId(group, consecutiveRegs[i]->workId());
|
||||||
|
|
||||||
|
Support::BitWordIterator<uint32_t> it(lead->useRegMask());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
uint32_t regIndex = it.next();
|
||||||
|
if (Support::bitTest(lead->useRegMask(), regIndex)) {
|
||||||
|
uint32_t score = 15;
|
||||||
|
|
||||||
|
for (i = 0; i < consecutiveCount; i++) {
|
||||||
|
uint32_t consecutiveIndex = regIndex + i;
|
||||||
|
if (!Support::bitTest(allocableRegs, consecutiveIndex)) {
|
||||||
|
score = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAWorkReg* workReg = workRegById(consecutiveRegs[i]->workId());
|
||||||
|
score += uint32_t(workReg->homeRegId() == consecutiveIndex);
|
||||||
|
score += uint32_t(assignments[i] == consecutiveIndex) * 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestLeadReg = regIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestLeadReg == 0xFFFFFFFF)
|
||||||
|
return DebugUtils::errored(kErrorConsecutiveRegsAllocation);
|
||||||
|
|
||||||
|
for (i = 0; i < consecutiveCount; i++) {
|
||||||
|
uint32_t consecutiveIndex = bestLeadReg + i;
|
||||||
|
|
||||||
|
RATiedReg* tiedReg = consecutiveRegs[i];
|
||||||
|
RegMask useMask = Support::bitMask(consecutiveIndex);
|
||||||
|
|
||||||
|
uint32_t workId = tiedReg->workId();
|
||||||
|
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
||||||
|
|
||||||
|
tiedReg->setUseId(consecutiveIndex);
|
||||||
|
|
||||||
|
if (assignedId == consecutiveIndex) {
|
||||||
|
// If the register is already allocated in this one, mark it done and continue.
|
||||||
|
tiedReg->markUseDone();
|
||||||
|
if (tiedReg->isWrite())
|
||||||
|
_curAssignment.makeDirty(group, workId, assignedId);
|
||||||
|
usePending--;
|
||||||
|
willUse |= useMask;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
willUse |= useMask;
|
||||||
|
willFree |= useMask & _curAssignment.assigned(group);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// STEP 3
|
||||||
|
// ------
|
||||||
|
//
|
||||||
|
// Do some decision making to find the best candidates of registers that need to be assigned, moved, and/or
|
||||||
|
// spilled. Only USE registers are considered here, OUT will be decided later after all CLOBBERed and OUT
|
||||||
// registers are unassigned.
|
// registers are unassigned.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (usePending) {
|
if (usePending) {
|
||||||
// TODO: Not sure `liveRegs` should be used, maybe willUse and willFree would be enough and much more clear.
|
// TODO: Not sure `liveRegs` should be used, maybe willUse and willFree would be enough and much more clear.
|
||||||
|
|
||||||
// All registers that are currently alive without registers that will be freed.
|
// All registers that are currently alive without registers that will be freed.
|
||||||
uint32_t liveRegs = _curAssignment.assigned(group) & ~willFree;
|
RegMask liveRegs = _curAssignment.assigned(group) & ~willFree;
|
||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
RATiedReg* tiedReg = &tiedRegs[i];
|
RATiedReg* tiedReg = &tiedRegs[i];
|
||||||
if (tiedReg->isUseDone()) continue;
|
if (tiedReg->isUseDone())
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
||||||
@@ -538,18 +613,17 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (!tiedReg->hasUseId()) {
|
if (!tiedReg->hasUseId()) {
|
||||||
uint32_t allocableRegs = tiedReg->allocableRegs() & ~(willFree | willUse);
|
|
||||||
|
|
||||||
// DECIDE where to assign the USE register.
|
// DECIDE where to assign the USE register.
|
||||||
|
RegMask allocableRegs = tiedReg->useRegMask() & ~(willFree | willUse);
|
||||||
uint32_t useId = decideOnAssignment(group, workId, assignedId, allocableRegs);
|
uint32_t useId = decideOnAssignment(group, workId, assignedId, allocableRegs);
|
||||||
uint32_t useMask = Support::bitMask(useId);
|
|
||||||
|
|
||||||
|
RegMask useMask = Support::bitMask(useId);
|
||||||
willUse |= useMask;
|
willUse |= useMask;
|
||||||
willFree |= useMask & liveRegs;
|
willFree |= useMask & liveRegs;
|
||||||
tiedReg->setUseId(useId);
|
tiedReg->setUseId(useId);
|
||||||
|
|
||||||
if (assignedId != RAAssignment::kPhysNone) {
|
if (assignedId != RAAssignment::kPhysNone) {
|
||||||
uint32_t assignedMask = Support::bitMask(assignedId);
|
RegMask assignedMask = Support::bitMask(assignedId);
|
||||||
|
|
||||||
willFree |= assignedMask;
|
willFree |= assignedMask;
|
||||||
liveRegs &= ~assignedMask;
|
liveRegs &= ~assignedMask;
|
||||||
@@ -579,19 +653,18 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initially all used regs will be marked clobbered.
|
// Initially all used regs will be marked as clobbered.
|
||||||
uint32_t clobberedByInst = willUse | willOut;
|
RegMask clobberedByInst = willUse | willOut;
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 4
|
||||||
// STEP 3:
|
// ------
|
||||||
//
|
//
|
||||||
// Free all registers that we marked as `willFree`. Only registers that are not
|
// Free all registers that we marked as `willFree`. Only registers that are not USEd by the instruction are
|
||||||
// USEd by the instruction are considered as we don't want to free regs we need.
|
// considered as we don't want to free regs we need.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (willFree) {
|
if (willFree) {
|
||||||
uint32_t allocableRegs = _availableRegs[group] & ~(_curAssignment.assigned(group) | willFree | willUse | willOut);
|
RegMask allocableRegs = _availableRegs[group] & ~(_curAssignment.assigned(group) | willFree | willUse | willOut);
|
||||||
Support::BitWordIterator<uint32_t> it(willFree);
|
Support::BitWordIterator<RegMask> it(willFree);
|
||||||
|
|
||||||
do {
|
do {
|
||||||
uint32_t assignedId = it.next();
|
uint32_t assignedId = it.next();
|
||||||
@@ -613,21 +686,17 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
} while (it.hasNext());
|
} while (it.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 5
|
||||||
// STEP 4:
|
// ------
|
||||||
//
|
//
|
||||||
// ALLOCATE / SHUFFLE all registers that we marked as `willUse` and weren't
|
// ALLOCATE / SHUFFLE all registers that we marked as `willUse` and weren't allocated yet. This is a bit
|
||||||
// allocated yet. This is a bit complicated as the allocation is iterative.
|
// complicated as the allocation is iterative. In some cases we have to wait before allocating a particual
|
||||||
// In some cases we have to wait before allocating a particual physical
|
// physical register as it's still occupied by some other one, which we need to move before we can use it.
|
||||||
// register as it's still occupied by some other one, which we need to move
|
// In this case we skip it and allocate another some other instead (making it free for another iteration).
|
||||||
// before we can use it. In this case we skip it and allocate another some
|
|
||||||
// other instead (making it free for another iteration).
|
|
||||||
//
|
//
|
||||||
// NOTE: Iterations are mostly important for complicated allocations like
|
// NOTE: Iterations are mostly important for complicated allocations like function calls, where there can
|
||||||
// function calls, where there can be up to N registers used at once. Asm
|
// be up to N registers used at once. Asm instructions won't run the loop more than once in 99.9% of cases
|
||||||
// instructions won't run the loop more than once in 99.9% of cases as they
|
// as they use 2..3 registers in average.
|
||||||
// use 2..3 registers in average.
|
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (usePending) {
|
if (usePending) {
|
||||||
bool mustSwap = false;
|
bool mustSwap = false;
|
||||||
@@ -636,7 +705,8 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
|
|
||||||
for (i = 0; i < count; i++) {
|
for (i = 0; i < count; i++) {
|
||||||
RATiedReg* thisTiedReg = &tiedRegs[i];
|
RATiedReg* thisTiedReg = &tiedRegs[i];
|
||||||
if (thisTiedReg->isUseDone()) continue;
|
if (thisTiedReg->isUseDone())
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t thisWorkId = thisTiedReg->workId();
|
uint32_t thisWorkId = thisTiedReg->workId();
|
||||||
uint32_t thisPhysId = _curAssignment.workToPhysId(group, thisWorkId);
|
uint32_t thisPhysId = _curAssignment.workToPhysId(group, thisWorkId);
|
||||||
@@ -649,11 +719,10 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
if (targetWorkId != RAAssignment::kWorkNone) {
|
if (targetWorkId != RAAssignment::kWorkNone) {
|
||||||
RAWorkReg* targetWorkReg = workRegById(targetWorkId);
|
RAWorkReg* targetWorkReg = workRegById(targetWorkId);
|
||||||
|
|
||||||
// Swapping two registers can solve two allocation tasks by emitting
|
// Swapping two registers can solve two allocation tasks by emitting just a single instruction. However,
|
||||||
// just a single instruction. However, swap is only available on few
|
// swap is only available on few architectures and it's definitely not available for each register group.
|
||||||
// architectures and it's definitely not available for each register
|
// Calling `onSwapReg()` before checking these would be fatal.
|
||||||
// group. Calling `onSwapReg()` before checking these would be fatal.
|
if (_archTraits->hasInstRegSwap(group) && thisPhysId != RAAssignment::kPhysNone) {
|
||||||
if (_archTraits->hasSwap(group) && thisPhysId != RAAssignment::kPhysNone) {
|
|
||||||
ASMJIT_PROPAGATE(onSwapReg(group, thisWorkId, thisPhysId, targetWorkId, targetPhysId));
|
ASMJIT_PROPAGATE(onSwapReg(group, thisWorkId, thisPhysId, targetWorkId, targetPhysId));
|
||||||
|
|
||||||
thisTiedReg->markUseDone();
|
thisTiedReg->markUseDone();
|
||||||
@@ -675,10 +744,9 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
if (!mustSwap)
|
if (!mustSwap)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
// Only branched here if the previous iteration did nothing. This is
|
// Only branched here if the previous iteration did nothing. This is essentially a SWAP operation without
|
||||||
// essentially a SWAP operation without having a dedicated instruction
|
// having a dedicated instruction for that purpose (vector registers, etc). The simplest way to handle
|
||||||
// for that purpose (vector registers, etc). The simplest way to
|
// such case is to SPILL the target register.
|
||||||
// handle such case is to SPILL the target register.
|
|
||||||
ASMJIT_PROPAGATE(onSpillReg(group, targetWorkId, targetPhysId));
|
ASMJIT_PROPAGATE(onSpillReg(group, targetWorkId, targetPhysId));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -704,11 +772,10 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
} while (usePending);
|
} while (usePending);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 6
|
||||||
// STEP 5:
|
// ------
|
||||||
//
|
//
|
||||||
// KILL registers marked as KILL/OUT.
|
// KILL registers marked as KILL/OUT.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
uint32_t outPending = outTiedCount;
|
uint32_t outPending = outTiedCount;
|
||||||
if (outTiedCount) {
|
if (outTiedCount) {
|
||||||
@@ -718,28 +785,27 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
uint32_t physId = _curAssignment.workToPhysId(group, workId);
|
uint32_t physId = _curAssignment.workToPhysId(group, workId);
|
||||||
|
|
||||||
// Must check if it's allocated as KILL can be related to OUT (like KILL
|
// Must check if it's allocated as KILL can be related to OUT (like KILL immediately after OUT, which could
|
||||||
// immediately after OUT, which could mean the register is not assigned).
|
// mean the register is not assigned).
|
||||||
if (physId != RAAssignment::kPhysNone) {
|
if (physId != RAAssignment::kPhysNone) {
|
||||||
ASMJIT_PROPAGATE(onKillReg(group, workId, physId));
|
ASMJIT_PROPAGATE(onKillReg(group, workId, physId));
|
||||||
willOut &= ~Support::bitMask(physId);
|
willOut &= ~Support::bitMask(physId);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We still maintain number of pending registers for OUT assignment.
|
// We still maintain number of pending registers for OUT assignment. So, if this is only KILL, not OUT, we
|
||||||
// So, if this is only KILL, not OUT, we can safely decrement it.
|
// can safely decrement it.
|
||||||
outPending -= !tiedReg->isOut();
|
outPending -= !tiedReg->isOut();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 7
|
||||||
// STEP 6:
|
// ------
|
||||||
//
|
//
|
||||||
// SPILL registers that will be CLOBBERed. Since OUT and KILL were
|
// SPILL registers that will be CLOBBERed. Since OUT and KILL were already processed this is used mostly to
|
||||||
// already processed this is used mostly to handle function CALLs.
|
// handle function CALLs.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (willOut) {
|
if (willOut) {
|
||||||
Support::BitWordIterator<uint32_t> it(willOut);
|
Support::BitWordIterator<RegMask> it(willOut);
|
||||||
do {
|
do {
|
||||||
uint32_t physId = it.next();
|
uint32_t physId = it.next();
|
||||||
uint32_t workId = _curAssignment.physToWorkId(group, physId);
|
uint32_t workId = _curAssignment.physToWorkId(group, physId);
|
||||||
@@ -751,18 +817,17 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
} while (it.hasNext());
|
} while (it.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 8
|
||||||
// STEP 7:
|
// ------
|
||||||
//
|
//
|
||||||
// Duplication.
|
// Duplication.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
for (i = 0; i < dupTiedCount; i++) {
|
for (i = 0; i < dupTiedCount; i++) {
|
||||||
RATiedReg* tiedReg = dupTiedRegs[i];
|
RATiedReg* tiedReg = dupTiedRegs[i];
|
||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
uint32_t srcId = tiedReg->useId();
|
uint32_t srcId = tiedReg->useId();
|
||||||
|
|
||||||
Support::BitWordIterator<uint32_t> it(tiedReg->_allocableRegs);
|
Support::BitWordIterator<RegMask> it(tiedReg->useRegMask());
|
||||||
while (it.hasNext()) {
|
while (it.hasNext()) {
|
||||||
uint32_t dstId = it.next();
|
uint32_t dstId = it.next();
|
||||||
if (dstId == srcId)
|
if (dstId == srcId)
|
||||||
@@ -771,27 +836,71 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// STEP 9
|
||||||
// STEP 8:
|
// ------
|
||||||
//
|
//
|
||||||
// Assign OUT registers.
|
// Assign OUT registers.
|
||||||
// ------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (outPending) {
|
if (outPending) {
|
||||||
// Live registers, we need a separate variable (outside of `_curAssignment)
|
// Live registers, we need a separate register (outside of `_curAssignment) to hold these because of KILLed
|
||||||
// to hold these because of KILLed registers. If we KILL a register here it
|
// registers. If we KILL a register here it will go out from `_curAssignment`, but we cannot assign to it in
|
||||||
// will go out from `_curAssignment`, but we cannot assign to it in here.
|
// here.
|
||||||
uint32_t liveRegs = _curAssignment.assigned(group);
|
RegMask liveRegs = _curAssignment.assigned(group);
|
||||||
|
|
||||||
// Must avoid as they have been already OUTed (added during the loop).
|
// Must avoid as they have been already OUTed (added during the loop).
|
||||||
uint32_t outRegs = 0;
|
RegMask outRegs = 0;
|
||||||
|
|
||||||
// Must avoid as they collide with already allocated ones.
|
// Must avoid as they collide with already allocated ones.
|
||||||
uint32_t avoidRegs = willUse & ~clobberedByInst;
|
RegMask avoidRegs = willUse & ~clobberedByInst;
|
||||||
|
|
||||||
|
// Assign the best possible OUT ids of all consecutives.
|
||||||
|
if (consecutiveCount) {
|
||||||
|
RATiedReg* lead = consecutiveRegs[0];
|
||||||
|
if (lead->isOutConsecutive()) {
|
||||||
|
uint32_t bestScore = 0;
|
||||||
|
uint32_t bestLeadReg = 0xFFFFFFFF;
|
||||||
|
RegMask allocableRegs = _availableRegs[group] & ~(outRegs | avoidRegs);
|
||||||
|
|
||||||
|
Support::BitWordIterator<uint32_t> it(lead->outRegMask());
|
||||||
|
while (it.hasNext()) {
|
||||||
|
uint32_t regIndex = it.next();
|
||||||
|
if (Support::bitTest(lead->outRegMask(), regIndex)) {
|
||||||
|
uint32_t score = 15;
|
||||||
|
|
||||||
|
for (i = 0; i < consecutiveCount; i++) {
|
||||||
|
uint32_t consecutiveIndex = regIndex + i;
|
||||||
|
if (!Support::bitTest(allocableRegs, consecutiveIndex)) {
|
||||||
|
score = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
RAWorkReg* workReg = workRegById(consecutiveRegs[i]->workId());
|
||||||
|
score += uint32_t(workReg->homeRegId() == consecutiveIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (score > bestScore) {
|
||||||
|
bestScore = score;
|
||||||
|
bestLeadReg = regIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bestLeadReg == 0xFFFFFFFF)
|
||||||
|
return DebugUtils::errored(kErrorConsecutiveRegsAllocation);
|
||||||
|
|
||||||
|
for (i = 0; i < consecutiveCount; i++) {
|
||||||
|
uint32_t consecutiveIndex = bestLeadReg + i;
|
||||||
|
RATiedReg* tiedReg = consecutiveRegs[i];
|
||||||
|
tiedReg->setOutId(consecutiveIndex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allocate OUT registers.
|
||||||
for (i = 0; i < outTiedCount; i++) {
|
for (i = 0; i < outTiedCount; i++) {
|
||||||
RATiedReg* tiedReg = outTiedRegs[i];
|
RATiedReg* tiedReg = outTiedRegs[i];
|
||||||
if (!tiedReg->isOut()) continue;
|
if (!tiedReg->isOut())
|
||||||
|
continue;
|
||||||
|
|
||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
||||||
@@ -801,7 +910,7 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
|
|
||||||
uint32_t physId = tiedReg->outId();
|
uint32_t physId = tiedReg->outId();
|
||||||
if (physId == RAAssignment::kPhysNone) {
|
if (physId == RAAssignment::kPhysNone) {
|
||||||
uint32_t allocableRegs = tiedReg->_allocableRegs & ~(outRegs | avoidRegs);
|
RegMask allocableRegs = tiedReg->outRegMask() & ~(outRegs | avoidRegs);
|
||||||
|
|
||||||
if (!(allocableRegs & ~liveRegs)) {
|
if (!(allocableRegs & ~liveRegs)) {
|
||||||
// There are no more registers, decide which one to spill.
|
// There are no more registers, decide which one to spill.
|
||||||
@@ -839,9 +948,8 @@ Error RALocalAllocator::allocInst(InstNode* node) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Error RALocalAllocator::spillAfterAllocation(InstNode* node) noexcept {
|
Error RALocalAllocator::spillAfterAllocation(InstNode* node) noexcept {
|
||||||
// This is experimental feature that would spill registers that don't have
|
// This is experimental feature that would spill registers that don't have home-id and are last in this basic block.
|
||||||
// home-id and are last in this basic block. This prevents saving these regs
|
// This prevents saving these regs in other basic blocks and then restoring them (mostly relevant for loops).
|
||||||
// in other basic blocks and then restoring them (mostly relevant for loops).
|
|
||||||
RAInst* raInst = node->passData<RAInst>();
|
RAInst* raInst = node->passData<RAInst>();
|
||||||
uint32_t count = raInst->tiedCount();
|
uint32_t count = raInst->tiedCount();
|
||||||
|
|
||||||
@@ -851,7 +959,7 @@ Error RALocalAllocator::spillAfterAllocation(InstNode* node) noexcept {
|
|||||||
uint32_t workId = tiedReg->workId();
|
uint32_t workId = tiedReg->workId();
|
||||||
RAWorkReg* workReg = workRegById(workId);
|
RAWorkReg* workReg = workRegById(workId);
|
||||||
if (!workReg->hasHomeRegId()) {
|
if (!workReg->hasHomeRegId()) {
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
uint32_t assignedId = _curAssignment.workToPhysId(group, workId);
|
||||||
if (assignedId != RAAssignment::kPhysNone) {
|
if (assignedId != RAAssignment::kPhysNone) {
|
||||||
_cc->_setCursor(node);
|
_cc->_setCursor(node);
|
||||||
@@ -898,9 +1006,8 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co
|
|||||||
|
|
||||||
BaseNode* curCursor = _cc->cursor();
|
BaseNode* curCursor = _cc->cursor();
|
||||||
if (curCursor != injectionPoint) {
|
if (curCursor != injectionPoint) {
|
||||||
// Additional instructions emitted to switch from the current state to
|
// Additional instructions emitted to switch from the current state to the `target` state. This means
|
||||||
// the `target` state. This means that we have to move these instructions
|
// that we have to move these instructions into an independent code block and patch the jump location.
|
||||||
// into an independent code block and patch the jump location.
|
|
||||||
Operand& targetOp = node->op(node->opCount() - 1);
|
Operand& targetOp = node->op(node->opCount() - 1);
|
||||||
if (ASMJIT_UNLIKELY(!targetOp.isLabel()))
|
if (ASMJIT_UNLIKELY(!targetOp.isLabel()))
|
||||||
return DebugUtils::errored(kErrorInvalidState);
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
@@ -911,9 +1018,9 @@ Error RALocalAllocator::allocBranch(InstNode* node, RABlock* target, RABlock* co
|
|||||||
// Patch `target` to point to the `trampoline` we just created.
|
// Patch `target` to point to the `trampoline` we just created.
|
||||||
targetOp = trampoline;
|
targetOp = trampoline;
|
||||||
|
|
||||||
// Clear a possible SHORT form as we have no clue now if the SHORT form would
|
// Clear a possible SHORT form as we have no clue now if the SHORT form would be encodable after patching
|
||||||
// be encodable after patching the target to `trampoline` (X86 specific).
|
// the target to `trampoline` (X86 specific).
|
||||||
node->clearInstOptions(BaseInst::kOptionShortForm);
|
node->clearOptions(InstOptions::kShortForm);
|
||||||
|
|
||||||
// Finalize the switch assignment sequence.
|
// Finalize the switch assignment sequence.
|
||||||
ASMJIT_PROPAGATE(_pass->emitJump(savedTarget));
|
ASMJIT_PROPAGATE(_pass->emitJump(savedTarget));
|
||||||
@@ -969,11 +1076,10 @@ Error RALocalAllocator::allocJumpTable(InstNode* node, const RABlocks& targets,
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// RALocalAllocator - Decision Making
|
||||||
// [asmjit::RALocalAllocator - Decision Making]
|
// ==================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
uint32_t RALocalAllocator::decideOnAssignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept {
|
uint32_t RALocalAllocator::decideOnAssignment(RegGroup group, uint32_t workId, uint32_t physId, RegMask allocableRegs) const noexcept {
|
||||||
ASMJIT_ASSERT(allocableRegs != 0);
|
ASMJIT_ASSERT(allocableRegs != 0);
|
||||||
DebugUtils::unused(group, physId);
|
DebugUtils::unused(group, physId);
|
||||||
|
|
||||||
@@ -987,14 +1093,14 @@ uint32_t RALocalAllocator::decideOnAssignment(uint32_t group, uint32_t workId, u
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Prefer registers used upon block entries.
|
// Prefer registers used upon block entries.
|
||||||
uint32_t previouslyAssignedRegs = workReg->allocatedMask();
|
RegMask previouslyAssignedRegs = workReg->allocatedMask();
|
||||||
if (allocableRegs & previouslyAssignedRegs)
|
if (allocableRegs & previouslyAssignedRegs)
|
||||||
allocableRegs &= previouslyAssignedRegs;
|
allocableRegs &= previouslyAssignedRegs;
|
||||||
|
|
||||||
return Support::ctz(allocableRegs);
|
return Support::ctz(allocableRegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RALocalAllocator::decideOnReassignment(uint32_t group, uint32_t workId, uint32_t physId, uint32_t allocableRegs) const noexcept {
|
uint32_t RALocalAllocator::decideOnReassignment(RegGroup group, uint32_t workId, uint32_t physId, RegMask allocableRegs) const noexcept {
|
||||||
ASMJIT_ASSERT(allocableRegs != 0);
|
ASMJIT_ASSERT(allocableRegs != 0);
|
||||||
DebugUtils::unused(group, physId);
|
DebugUtils::unused(group, physId);
|
||||||
|
|
||||||
@@ -1012,12 +1118,12 @@ uint32_t RALocalAllocator::decideOnReassignment(uint32_t group, uint32_t workId,
|
|||||||
return RAAssignment::kPhysNone;
|
return RAAssignment::kPhysNone;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t RALocalAllocator::decideOnSpillFor(uint32_t group, uint32_t workId, uint32_t spillableRegs, uint32_t* spillWorkId) const noexcept {
|
uint32_t RALocalAllocator::decideOnSpillFor(RegGroup group, uint32_t workId, RegMask spillableRegs, uint32_t* spillWorkId) const noexcept {
|
||||||
// May be used in the future to decide which register would be best to spill so `workId` can be assigned.
|
// May be used in the future to decide which register would be best to spill so `workId` can be assigned.
|
||||||
DebugUtils::unused(workId);
|
DebugUtils::unused(workId);
|
||||||
ASMJIT_ASSERT(spillableRegs != 0);
|
ASMJIT_ASSERT(spillableRegs != 0);
|
||||||
|
|
||||||
Support::BitWordIterator<uint32_t> it(spillableRegs);
|
Support::BitWordIterator<RegMask> it(spillableRegs);
|
||||||
uint32_t bestPhysId = it.next();
|
uint32_t bestPhysId = it.next();
|
||||||
uint32_t bestWorkId = _curAssignment.physToWorkId(group, bestPhysId);
|
uint32_t bestWorkId = _curAssignment.physToWorkId(group, bestPhysId);
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_RALOCAL_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_RALOCAL_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_RALOCAL_P_H_INCLUDED
|
#define ASMJIT_CORE_RALOCAL_P_H_INCLUDED
|
||||||
@@ -38,10 +20,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_ra
|
//! \addtogroup asmjit_ra
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::RALocalAllocator]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Local register allocator.
|
//! Local register allocator.
|
||||||
class RALocalAllocator {
|
class RALocalAllocator {
|
||||||
public:
|
public:
|
||||||
@@ -119,14 +97,14 @@ public:
|
|||||||
//! Returns all tied regs as `RATiedReg` array.
|
//! Returns all tied regs as `RATiedReg` array.
|
||||||
inline RATiedReg* tiedRegs() const noexcept { return _raInst->tiedRegs(); }
|
inline RATiedReg* tiedRegs() const noexcept { return _raInst->tiedRegs(); }
|
||||||
//! Returns tied registers grouped by the given `group`.
|
//! Returns tied registers grouped by the given `group`.
|
||||||
inline RATiedReg* tiedRegs(uint32_t group) const noexcept { return _raInst->tiedRegs(group); }
|
inline RATiedReg* tiedRegs(RegGroup group) const noexcept { return _raInst->tiedRegs(group); }
|
||||||
|
|
||||||
//! Returns count of all TiedRegs used by the instruction.
|
//! Returns count of all TiedRegs used by the instruction.
|
||||||
inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
|
inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
|
||||||
//! Returns count of TiedRegs used by the given register `group`.
|
//! Returns count of TiedRegs used by the given register `group`.
|
||||||
inline uint32_t tiedCount(uint32_t group) const noexcept { return _tiedCount.get(group); }
|
inline uint32_t tiedCount(RegGroup group) const noexcept { return _tiedCount.get(group); }
|
||||||
|
|
||||||
inline bool isGroupUsed(uint32_t group) const noexcept { return _tiedCount[group] != 0; }
|
inline bool isGroupUsed(RegGroup group) const noexcept { return _tiedCount[group] != 0; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -139,14 +117,12 @@ public:
|
|||||||
const PhysToWorkMap* physToWorkMap,
|
const PhysToWorkMap* physToWorkMap,
|
||||||
const WorkToPhysMap* workToPhysMap) noexcept;
|
const WorkToPhysMap* workToPhysMap) noexcept;
|
||||||
|
|
||||||
//! Switch to the given assignment by reassigning all register and emitting
|
//! Switch to the given assignment by reassigning all register and emitting code that reassigns them.
|
||||||
//! code that reassigns them. This is always used to switch to a previously
|
//! This is always used to switch to a previously stored assignment.
|
||||||
//! stored assignment.
|
|
||||||
//!
|
//!
|
||||||
//! If `tryMode` is true then the final assignment doesn't have to be exactly
|
//! If `tryMode` is true then the final assignment doesn't have to be exactly same as specified by `dstPhysToWorkMap`
|
||||||
//! same as specified by `dstPhysToWorkMap` and `dstWorkToPhysMap`. This mode
|
//! and `dstWorkToPhysMap`. This mode is only used before conditional jumps that already have assignment to generate
|
||||||
//! is only used before conditional jumps that already have assignment to
|
//! a code sequence that is always executed regardless of the flow.
|
||||||
//! generate a code sequence that is always executed regardless of the flow.
|
|
||||||
Error switchToAssignment(
|
Error switchToAssignment(
|
||||||
PhysToWorkMap* dstPhysToWorkMap,
|
PhysToWorkMap* dstPhysToWorkMap,
|
||||||
WorkToPhysMap* dstWorkToPhysMap,
|
WorkToPhysMap* dstWorkToPhysMap,
|
||||||
@@ -185,7 +161,7 @@ public:
|
|||||||
return uint32_t(int32_t(freq * float(kCostOfFrequency)));
|
return uint32_t(int32_t(freq * float(kCostOfFrequency)));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline uint32_t calculateSpillCost(uint32_t group, uint32_t workId, uint32_t assignedId) const noexcept {
|
inline uint32_t calculateSpillCost(RegGroup group, uint32_t workId, uint32_t assignedId) const noexcept {
|
||||||
RAWorkReg* workReg = workRegById(workId);
|
RAWorkReg* workReg = workRegById(workId);
|
||||||
uint32_t cost = costByFrequency(workReg->liveStats().freq());
|
uint32_t cost = costByFrequency(workReg->liveStats().freq());
|
||||||
|
|
||||||
@@ -196,18 +172,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Decides on register assignment.
|
//! Decides on register assignment.
|
||||||
uint32_t decideOnAssignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept;
|
uint32_t decideOnAssignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept;
|
||||||
|
|
||||||
//! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated
|
//! Decides on whether to MOVE or SPILL the given WorkReg, because it's allocated in a physical register that have
|
||||||
//! in a physical register that have to be used by another WorkReg.
|
//! to be used by another WorkReg.
|
||||||
//!
|
//!
|
||||||
//! The function must return either `RAAssignment::kPhysNone`, which means that
|
//! The function must return either `RAAssignment::kPhysNone`, which means that the WorkReg of `workId` should be
|
||||||
//! the WorkReg of `workId` should be spilled, or a valid physical register ID,
|
//! spilled, or a valid physical register ID, which means that the register should be moved to that physical register
|
||||||
//! which means that the register should be moved to that physical register instead.
|
//! instead.
|
||||||
uint32_t decideOnReassignment(uint32_t group, uint32_t workId, uint32_t assignedId, uint32_t allocableRegs) const noexcept;
|
uint32_t decideOnReassignment(RegGroup group, uint32_t workId, uint32_t assignedId, RegMask allocableRegs) const noexcept;
|
||||||
|
|
||||||
//! Decides on best spill given a register mask `spillableRegs`
|
//! Decides on best spill given a register mask `spillableRegs`
|
||||||
uint32_t decideOnSpillFor(uint32_t group, uint32_t workId, uint32_t spillableRegs, uint32_t* spillWorkId) const noexcept;
|
uint32_t decideOnSpillFor(RegGroup group, uint32_t workId, RegMask spillableRegs, uint32_t* spillWorkId) const noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -216,7 +192,7 @@ public:
|
|||||||
|
|
||||||
//! Emits a move between a destination and source register, and fixes the
|
//! Emits a move between a destination and source register, and fixes the
|
||||||
//! register assignment.
|
//! register assignment.
|
||||||
inline Error onMoveReg(uint32_t group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
inline Error onMoveReg(RegGroup group, uint32_t workId, uint32_t dstPhysId, uint32_t srcPhysId) noexcept {
|
||||||
if (dstPhysId == srcPhysId) return kErrorOk;
|
if (dstPhysId == srcPhysId) return kErrorOk;
|
||||||
_curAssignment.reassign(group, workId, dstPhysId, srcPhysId);
|
_curAssignment.reassign(group, workId, dstPhysId, srcPhysId);
|
||||||
return _pass->emitMove(workId, dstPhysId, srcPhysId);
|
return _pass->emitMove(workId, dstPhysId, srcPhysId);
|
||||||
@@ -225,21 +201,21 @@ public:
|
|||||||
//! Emits a swap between two physical registers and fixes their assignment.
|
//! Emits a swap between two physical registers and fixes their assignment.
|
||||||
//!
|
//!
|
||||||
//! \note Target must support this operation otherwise this would ASSERT.
|
//! \note Target must support this operation otherwise this would ASSERT.
|
||||||
inline Error onSwapReg(uint32_t group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
|
inline Error onSwapReg(RegGroup group, uint32_t aWorkId, uint32_t aPhysId, uint32_t bWorkId, uint32_t bPhysId) noexcept {
|
||||||
_curAssignment.swap(group, aWorkId, aPhysId, bWorkId, bPhysId);
|
_curAssignment.swap(group, aWorkId, aPhysId, bWorkId, bPhysId);
|
||||||
return _pass->emitSwap(aWorkId, aPhysId, bWorkId, bPhysId);
|
return _pass->emitSwap(aWorkId, aPhysId, bWorkId, bPhysId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Emits a load from [VirtReg/WorkReg]'s spill slot to a physical register
|
//! Emits a load from [VirtReg/WorkReg]'s spill slot to a physical register
|
||||||
//! and makes it assigned and clean.
|
//! and makes it assigned and clean.
|
||||||
inline Error onLoadReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline Error onLoadReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
_curAssignment.assign(group, workId, physId, RAAssignment::kClean);
|
_curAssignment.assign(group, workId, physId, RAAssignment::kClean);
|
||||||
return _pass->emitLoad(workId, physId);
|
return _pass->emitLoad(workId, physId);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Emits a save a physical register to a [VirtReg/WorkReg]'s spill slot,
|
//! Emits a save a physical register to a [VirtReg/WorkReg]'s spill slot,
|
||||||
//! keeps it assigned, and makes it clean.
|
//! keeps it assigned, and makes it clean.
|
||||||
inline Error onSaveReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline Error onSaveReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
ASMJIT_ASSERT(_curAssignment.workToPhysId(group, workId) == physId);
|
ASMJIT_ASSERT(_curAssignment.workToPhysId(group, workId) == physId);
|
||||||
ASMJIT_ASSERT(_curAssignment.physToWorkId(group, physId) == workId);
|
ASMJIT_ASSERT(_curAssignment.physToWorkId(group, physId) == workId);
|
||||||
|
|
||||||
@@ -248,24 +224,24 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Assigns a register, the content of it is undefined at this point.
|
//! Assigns a register, the content of it is undefined at this point.
|
||||||
inline Error onAssignReg(uint32_t group, uint32_t workId, uint32_t physId, uint32_t dirty) noexcept {
|
inline Error onAssignReg(RegGroup group, uint32_t workId, uint32_t physId, bool dirty) noexcept {
|
||||||
_curAssignment.assign(group, workId, physId, dirty);
|
_curAssignment.assign(group, workId, physId, dirty);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Spills a variable/register, saves the content to the memory-home if modified.
|
//! Spills a variable/register, saves the content to the memory-home if modified.
|
||||||
inline Error onSpillReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline Error onSpillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
if (_curAssignment.isPhysDirty(group, physId))
|
if (_curAssignment.isPhysDirty(group, physId))
|
||||||
ASMJIT_PROPAGATE(onSaveReg(group, workId, physId));
|
ASMJIT_PROPAGATE(onSaveReg(group, workId, physId));
|
||||||
return onKillReg(group, workId, physId);
|
return onKillReg(group, workId, physId);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error onDirtyReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline Error onDirtyReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
_curAssignment.makeDirty(group, workId, physId);
|
_curAssignment.makeDirty(group, workId, physId);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error onKillReg(uint32_t group, uint32_t workId, uint32_t physId) noexcept {
|
inline Error onKillReg(RegGroup group, uint32_t workId, uint32_t physId) noexcept {
|
||||||
_curAssignment.unassign(group, workId, physId);
|
_curAssignment.unassign(group, workId, physId);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_RAPASS_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_RAPASS_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_RAPASS_P_H_INCLUDED
|
#define ASMJIT_CORE_RAPASS_P_H_INCLUDED
|
||||||
@@ -40,9 +22,34 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_ra
|
//! \addtogroup asmjit_ra
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Flags used by \ref RABlock.
|
||||||
// [asmjit::RABlock]
|
enum class RABlockFlags : uint32_t {
|
||||||
// ============================================================================
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Block has been constructed from nodes.
|
||||||
|
kIsConstructed = 0x00000001u,
|
||||||
|
//! Block is reachable (set by `buildCFGViews()`).
|
||||||
|
kIsReachable = 0x00000002u,
|
||||||
|
//! Block is a target (has an associated label or multiple labels).
|
||||||
|
kIsTargetable = 0x00000004u,
|
||||||
|
//! Block has been allocated.
|
||||||
|
kIsAllocated = 0x00000008u,
|
||||||
|
//! Block is a function-exit.
|
||||||
|
kIsFuncExit = 0x00000010u,
|
||||||
|
|
||||||
|
//! Block has a terminator (jump, conditional jump, ret).
|
||||||
|
kHasTerminator = 0x00000100u,
|
||||||
|
//! Block naturally flows to the next block.
|
||||||
|
kHasConsecutive = 0x00000200u,
|
||||||
|
//! Block has a jump to a jump-table at the end.
|
||||||
|
kHasJumpTable = 0x00000400u,
|
||||||
|
//! Block contains fixed registers (precolored).
|
||||||
|
kHasFixedRegs = 0x00000800u,
|
||||||
|
//! Block contains function calls.
|
||||||
|
kHasFuncCalls = 0x00001000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(RABlockFlags)
|
||||||
|
|
||||||
//! Basic block used by register allocator pass.
|
//! Basic block used by register allocator pass.
|
||||||
class RABlock {
|
class RABlock {
|
||||||
@@ -52,42 +59,34 @@ public:
|
|||||||
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
||||||
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
||||||
|
|
||||||
enum Id : uint32_t {
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
enum : uint32_t {
|
||||||
|
//! Unassigned block id.
|
||||||
kUnassignedId = 0xFFFFFFFFu
|
kUnassignedId = 0xFFFFFFFFu
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Basic block flags.
|
enum LiveType : uint32_t {
|
||||||
enum Flags : uint32_t {
|
kLiveIn = 0,
|
||||||
//! Block has been constructed from nodes.
|
kLiveOut = 1,
|
||||||
kFlagIsConstructed = 0x00000001u,
|
kLiveGen = 2,
|
||||||
//! Block is reachable (set by `buildViews()`).
|
kLiveKill = 3,
|
||||||
kFlagIsReachable = 0x00000002u,
|
kLiveCount = 4
|
||||||
//! Block is a target (has an associated label or multiple labels).
|
|
||||||
kFlagIsTargetable = 0x00000004u,
|
|
||||||
//! Block has been allocated.
|
|
||||||
kFlagIsAllocated = 0x00000008u,
|
|
||||||
//! Block is a function-exit.
|
|
||||||
kFlagIsFuncExit = 0x00000010u,
|
|
||||||
|
|
||||||
//! Block has a terminator (jump, conditional jump, ret).
|
|
||||||
kFlagHasTerminator = 0x00000100u,
|
|
||||||
//! Block naturally flows to the next block.
|
|
||||||
kFlagHasConsecutive = 0x00000200u,
|
|
||||||
//! Block has a jump to a jump-table at the end.
|
|
||||||
kFlagHasJumpTable = 0x00000400u,
|
|
||||||
//! Block contains fixed registers (precolored).
|
|
||||||
kFlagHasFixedRegs = 0x00000800u,
|
|
||||||
//! Block contains function calls.
|
|
||||||
kFlagHasFuncCalls = 0x00001000u
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Register allocator pass.
|
//! Register allocator pass.
|
||||||
BaseRAPass* _ra;
|
BaseRAPass* _ra;
|
||||||
|
|
||||||
//! Block id (indexed from zero).
|
//! Block id (indexed from zero).
|
||||||
uint32_t _blockId = kUnassignedId;
|
uint32_t _blockId = kUnassignedId;
|
||||||
//! Block flags, see `Flags`.
|
//! Block flags, see `Flags`.
|
||||||
uint32_t _flags = 0;
|
RABlockFlags _flags = RABlockFlags::kNone;
|
||||||
|
|
||||||
//! First `BaseNode` of this block (inclusive).
|
//! First `BaseNode` of this block (inclusive).
|
||||||
BaseNode* _first = nullptr;
|
BaseNode* _first = nullptr;
|
||||||
@@ -119,30 +118,24 @@ public:
|
|||||||
//! Block successors.
|
//! Block successors.
|
||||||
RABlocks _successors {};
|
RABlocks _successors {};
|
||||||
|
|
||||||
enum LiveType : uint32_t {
|
|
||||||
kLiveIn = 0,
|
|
||||||
kLiveOut = 1,
|
|
||||||
kLiveGen = 2,
|
|
||||||
kLiveKill = 3,
|
|
||||||
kLiveCount = 4
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Liveness in/out/use/kill.
|
//! Liveness in/out/use/kill.
|
||||||
ZoneBitVector _liveBits[kLiveCount] {};
|
ZoneBitVector _liveBits[kLiveCount] {};
|
||||||
|
|
||||||
//! Shared assignment it or `Globals::kInvalidId` if this block doesn't
|
//! Shared assignment it or `Globals::kInvalidId` if this block doesn't have shared assignment.
|
||||||
//! have shared assignment. See `RASharedAssignment` for more details.
|
//! See \ref RASharedAssignment for more details.
|
||||||
uint32_t _sharedAssignmentId = Globals::kInvalidId;
|
uint32_t _sharedAssignmentId = Globals::kInvalidId;
|
||||||
//! Scratch registers that cannot be allocated upon block entry.
|
//! Scratch registers that cannot be allocated upon block entry.
|
||||||
uint32_t _entryScratchGpRegs = 0;
|
RegMask _entryScratchGpRegs = 0;
|
||||||
//! Scratch registers used at exit, by a terminator instruction.
|
//! Scratch registers used at exit, by a terminator instruction.
|
||||||
uint32_t _exitScratchGpRegs = 0;
|
RegMask _exitScratchGpRegs = 0;
|
||||||
|
|
||||||
//! Register assignment (PhysToWork) on entry.
|
//! Register assignment (PhysToWork) on entry.
|
||||||
PhysToWorkMap* _entryPhysToWorkMap = nullptr;
|
PhysToWorkMap* _entryPhysToWorkMap = nullptr;
|
||||||
//! Register assignment (WorkToPhys) on entry.
|
//! Register assignment (WorkToPhys) on entry.
|
||||||
WorkToPhysMap* _entryWorkToPhysMap = nullptr;
|
WorkToPhysMap* _entryWorkToPhysMap = nullptr;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -158,37 +151,43 @@ public:
|
|||||||
inline ZoneAllocator* allocator() const noexcept;
|
inline ZoneAllocator* allocator() const noexcept;
|
||||||
|
|
||||||
inline uint32_t blockId() const noexcept { return _blockId; }
|
inline uint32_t blockId() const noexcept { return _blockId; }
|
||||||
inline uint32_t flags() const noexcept { return _flags; }
|
inline RABlockFlags flags() const noexcept { return _flags; }
|
||||||
|
|
||||||
inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
|
inline bool hasFlag(RABlockFlags flag) const noexcept { return Support::test(_flags, flag); }
|
||||||
inline void addFlags(uint32_t flags) noexcept { _flags |= flags; }
|
inline void addFlags(RABlockFlags flags) noexcept { _flags |= flags; }
|
||||||
|
|
||||||
inline bool isAssigned() const noexcept { return _blockId != kUnassignedId; }
|
inline bool isAssigned() const noexcept { return _blockId != kUnassignedId; }
|
||||||
|
|
||||||
inline bool isConstructed() const noexcept { return hasFlag(kFlagIsConstructed); }
|
inline bool isConstructed() const noexcept { return hasFlag(RABlockFlags::kIsConstructed); }
|
||||||
inline bool isReachable() const noexcept { return hasFlag(kFlagIsReachable); }
|
inline bool isReachable() const noexcept { return hasFlag(RABlockFlags::kIsReachable); }
|
||||||
inline bool isTargetable() const noexcept { return hasFlag(kFlagIsTargetable); }
|
inline bool isTargetable() const noexcept { return hasFlag(RABlockFlags::kIsTargetable); }
|
||||||
inline bool isAllocated() const noexcept { return hasFlag(kFlagIsAllocated); }
|
inline bool isAllocated() const noexcept { return hasFlag(RABlockFlags::kIsAllocated); }
|
||||||
inline bool isFuncExit() const noexcept { return hasFlag(kFlagIsFuncExit); }
|
inline bool isFuncExit() const noexcept { return hasFlag(RABlockFlags::kIsFuncExit); }
|
||||||
|
inline bool hasTerminator() const noexcept { return hasFlag(RABlockFlags::kHasTerminator); }
|
||||||
|
inline bool hasConsecutive() const noexcept { return hasFlag(RABlockFlags::kHasConsecutive); }
|
||||||
|
inline bool hasJumpTable() const noexcept { return hasFlag(RABlockFlags::kHasJumpTable); }
|
||||||
|
|
||||||
inline void makeConstructed(const RARegsStats& regStats) noexcept {
|
inline void makeConstructed(const RARegsStats& regStats) noexcept {
|
||||||
_flags |= kFlagIsConstructed;
|
_flags |= RABlockFlags::kIsConstructed;
|
||||||
_regsStats.combineWith(regStats);
|
_regsStats.combineWith(regStats);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void makeReachable() noexcept { _flags |= kFlagIsReachable; }
|
inline void makeReachable() noexcept { _flags |= RABlockFlags::kIsReachable; }
|
||||||
inline void makeTargetable() noexcept { _flags |= kFlagIsTargetable; }
|
inline void makeTargetable() noexcept { _flags |= RABlockFlags::kIsTargetable; }
|
||||||
inline void makeAllocated() noexcept { _flags |= kFlagIsAllocated; }
|
inline void makeAllocated() noexcept { _flags |= RABlockFlags::kIsAllocated; }
|
||||||
|
|
||||||
inline const RARegsStats& regsStats() const noexcept { return _regsStats; }
|
inline const RARegsStats& regsStats() const noexcept { return _regsStats; }
|
||||||
|
|
||||||
inline bool hasTerminator() const noexcept { return hasFlag(kFlagHasTerminator); }
|
|
||||||
inline bool hasConsecutive() const noexcept { return hasFlag(kFlagHasConsecutive); }
|
|
||||||
inline bool hasJumpTable() const noexcept { return hasFlag(kFlagHasJumpTable); }
|
|
||||||
|
|
||||||
inline bool hasPredecessors() const noexcept { return !_predecessors.empty(); }
|
inline bool hasPredecessors() const noexcept { return !_predecessors.empty(); }
|
||||||
inline bool hasSuccessors() const noexcept { return !_successors.empty(); }
|
inline bool hasSuccessors() const noexcept { return !_successors.empty(); }
|
||||||
|
|
||||||
|
inline bool hasSuccessor(RABlock* block) noexcept {
|
||||||
|
if (block->_predecessors.size() < _successors.size())
|
||||||
|
return block->_predecessors.contains(this);
|
||||||
|
else
|
||||||
|
return _successors.contains(block);
|
||||||
|
}
|
||||||
|
|
||||||
inline const RABlocks& predecessors() const noexcept { return _predecessors; }
|
inline const RABlocks& predecessors() const noexcept { return _predecessors; }
|
||||||
inline const RABlocks& successors() const noexcept { return _successors; }
|
inline const RABlocks& successors() const noexcept { return _successors; }
|
||||||
|
|
||||||
@@ -206,11 +205,11 @@ public:
|
|||||||
|
|
||||||
inline uint32_t povOrder() const noexcept { return _povOrder; }
|
inline uint32_t povOrder() const noexcept { return _povOrder; }
|
||||||
|
|
||||||
inline uint32_t entryScratchGpRegs() const noexcept;
|
inline RegMask entryScratchGpRegs() const noexcept;
|
||||||
inline uint32_t exitScratchGpRegs() const noexcept { return _exitScratchGpRegs; }
|
inline RegMask exitScratchGpRegs() const noexcept { return _exitScratchGpRegs; }
|
||||||
|
|
||||||
inline void addEntryScratchGpRegs(uint32_t regMask) noexcept { _entryScratchGpRegs |= regMask; }
|
inline void addEntryScratchGpRegs(RegMask regMask) noexcept { _entryScratchGpRegs |= regMask; }
|
||||||
inline void addExitScratchGpRegs(uint32_t regMask) noexcept { _exitScratchGpRegs |= regMask; }
|
inline void addExitScratchGpRegs(RegMask regMask) noexcept { _exitScratchGpRegs |= regMask; }
|
||||||
|
|
||||||
inline bool hasSharedAssignmentId() const noexcept { return _sharedAssignmentId != Globals::kInvalidId; }
|
inline bool hasSharedAssignmentId() const noexcept { return _sharedAssignmentId != Globals::kInvalidId; }
|
||||||
inline uint32_t sharedAssignmentId() const noexcept { return _sharedAssignmentId; }
|
inline uint32_t sharedAssignmentId() const noexcept { return _sharedAssignmentId; }
|
||||||
@@ -261,11 +260,9 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Adds a successor to this block, and predecessor to `successor`, making
|
//! Adds a successor to this block, and predecessor to `successor`, making connection on both sides.
|
||||||
//! connection on both sides.
|
|
||||||
//!
|
//!
|
||||||
//! This API must be used to manage successors and predecessors, never manage
|
//! This API must be used to manage successors and predecessors, never manage it manually.
|
||||||
//! it manually.
|
|
||||||
Error appendSuccessor(RABlock* successor) noexcept;
|
Error appendSuccessor(RABlock* successor) noexcept;
|
||||||
|
|
||||||
//! Similar to `appendSuccessor()`, but does prepend instead append.
|
//! Similar to `appendSuccessor()`, but does prepend instead append.
|
||||||
@@ -276,19 +273,18 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::RAInst]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Register allocator's data associated with each `InstNode`.
|
//! Register allocator's data associated with each `InstNode`.
|
||||||
class RAInst {
|
class RAInst {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(RAInst)
|
ASMJIT_NONCOPYABLE(RAInst)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Parent block.
|
//! Parent block.
|
||||||
RABlock* _block;
|
RABlock* _block;
|
||||||
//! Instruction flags.
|
//! Aggregated RATiedFlags from all operands & instruction specific flags.
|
||||||
uint32_t _flags;
|
RATiedFlags _flags;
|
||||||
//! Total count of RATiedReg's.
|
//! Total count of RATiedReg's.
|
||||||
uint32_t _tiedTotal;
|
uint32_t _tiedTotal;
|
||||||
//! Index of RATiedReg's per register group.
|
//! Index of RATiedReg's per register group.
|
||||||
@@ -304,14 +300,12 @@ public:
|
|||||||
//! Tied registers.
|
//! Tied registers.
|
||||||
RATiedReg _tiedRegs[1];
|
RATiedReg _tiedRegs[1];
|
||||||
|
|
||||||
enum Flags : uint32_t {
|
//! \}
|
||||||
kFlagIsTransformable = 0x80000000u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE RAInst(RABlock* block, uint32_t flags, uint32_t tiedTotal, const RARegMask& clobberedRegs) noexcept {
|
inline RAInst(RABlock* block, RATiedFlags flags, uint32_t tiedTotal, const RARegMask& clobberedRegs) noexcept {
|
||||||
_block = block;
|
_block = block;
|
||||||
_flags = flags;
|
_flags = flags;
|
||||||
_tiedTotal = tiedTotal;
|
_tiedTotal = tiedTotal;
|
||||||
@@ -328,18 +322,18 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the instruction flags.
|
//! Returns the instruction flags.
|
||||||
inline uint32_t flags() const noexcept { return _flags; }
|
inline RATiedFlags flags() const noexcept { return _flags; }
|
||||||
//! Tests whether the instruction has flag `flag`.
|
//! Tests whether the instruction has flag `flag`.
|
||||||
inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
|
inline bool hasFlag(RATiedFlags flag) const noexcept { return Support::test(_flags, flag); }
|
||||||
//! Replaces the existing instruction flags with `flags`.
|
//! Replaces the existing instruction flags with `flags`.
|
||||||
inline void setFlags(uint32_t flags) noexcept { _flags = flags; }
|
inline void setFlags(RATiedFlags flags) noexcept { _flags = flags; }
|
||||||
//! Adds instruction `flags` to this RAInst.
|
//! Adds instruction `flags` to this RAInst.
|
||||||
inline void addFlags(uint32_t flags) noexcept { _flags |= flags; }
|
inline void addFlags(RATiedFlags flags) noexcept { _flags |= flags; }
|
||||||
//! Clears instruction `flags` from this RAInst.
|
//! Clears instruction `flags` from this RAInst.
|
||||||
inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
|
inline void clearFlags(RATiedFlags flags) noexcept { _flags &= ~flags; }
|
||||||
|
|
||||||
//! Tests whether this instruction can be transformed to another instruction if necessary.
|
//! Tests whether this instruction can be transformed to another instruction if necessary.
|
||||||
inline bool isTransformable() const noexcept { return hasFlag(kFlagIsTransformable); }
|
inline bool isTransformable() const noexcept { return hasFlag(RATiedFlags::kInst_IsTransformable); }
|
||||||
|
|
||||||
//! Returns the associated block with this RAInst.
|
//! Returns the associated block with this RAInst.
|
||||||
inline RABlock* block() const noexcept { return _block; }
|
inline RABlock* block() const noexcept { return _block; }
|
||||||
@@ -347,12 +341,12 @@ public:
|
|||||||
//! Returns tied registers (all).
|
//! Returns tied registers (all).
|
||||||
inline RATiedReg* tiedRegs() const noexcept { return const_cast<RATiedReg*>(_tiedRegs); }
|
inline RATiedReg* tiedRegs() const noexcept { return const_cast<RATiedReg*>(_tiedRegs); }
|
||||||
//! Returns tied registers for a given `group`.
|
//! Returns tied registers for a given `group`.
|
||||||
inline RATiedReg* tiedRegs(uint32_t group) const noexcept { return const_cast<RATiedReg*>(_tiedRegs) + _tiedIndex.get(group); }
|
inline RATiedReg* tiedRegs(RegGroup group) const noexcept { return const_cast<RATiedReg*>(_tiedRegs) + _tiedIndex.get(group); }
|
||||||
|
|
||||||
//! Returns count of all tied registers.
|
//! Returns count of all tied registers.
|
||||||
inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
|
inline uint32_t tiedCount() const noexcept { return _tiedTotal; }
|
||||||
//! Returns count of tied registers of a given `group`.
|
//! Returns count of tied registers of a given `group`.
|
||||||
inline uint32_t tiedCount(uint32_t group) const noexcept { return _tiedCount[group]; }
|
inline uint32_t tiedCount(RegGroup group) const noexcept { return _tiedCount[group]; }
|
||||||
|
|
||||||
//! Returns `RATiedReg` at the given `index`.
|
//! Returns `RATiedReg` at the given `index`.
|
||||||
inline RATiedReg* tiedAt(uint32_t index) const noexcept {
|
inline RATiedReg* tiedAt(uint32_t index) const noexcept {
|
||||||
@@ -361,8 +355,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Returns `RATiedReg` at the given `index` of the given register `group`.
|
//! Returns `RATiedReg` at the given `index` of the given register `group`.
|
||||||
inline RATiedReg* tiedOf(uint32_t group, uint32_t index) const noexcept {
|
inline RATiedReg* tiedOf(RegGroup group, uint32_t index) const noexcept {
|
||||||
ASMJIT_ASSERT(index < _tiedCount._regs[group]);
|
ASMJIT_ASSERT(index < _tiedCount.get(group));
|
||||||
return tiedRegs(group) + index;
|
return tiedRegs(group) + index;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -381,20 +375,18 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! A helper class that is used to build an array of RATiedReg items that are then copied to `RAInst`.
|
||||||
// [asmjit::RAInstBuilder]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! A helper class that is used to build an array of RATiedReg items that are
|
|
||||||
//! then copied to `RAInst`.
|
|
||||||
class RAInstBuilder {
|
class RAInstBuilder {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(RAInstBuilder)
|
ASMJIT_NONCOPYABLE(RAInstBuilder)
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Flags combined from all RATiedReg's.
|
//! Flags combined from all RATiedReg's.
|
||||||
uint32_t _aggregatedFlags;
|
RATiedFlags _aggregatedFlags;
|
||||||
//! Flags that will be cleared before storing the aggregated flags to `RAInst`.
|
//! Flags that will be cleared before storing the aggregated flags to `RAInst`.
|
||||||
uint32_t _forbiddenFlags;
|
RATiedFlags _forbiddenFlags;
|
||||||
RARegCount _count;
|
RARegCount _count;
|
||||||
RARegsStats _stats;
|
RARegsStats _stats;
|
||||||
|
|
||||||
@@ -406,6 +398,8 @@ public:
|
|||||||
//! Array of temporary tied registers.
|
//! Array of temporary tied registers.
|
||||||
RATiedReg _tiedRegs[128];
|
RATiedReg _tiedRegs[128];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -413,8 +407,8 @@ public:
|
|||||||
|
|
||||||
inline void init() noexcept { reset(); }
|
inline void init() noexcept { reset(); }
|
||||||
inline void reset() noexcept {
|
inline void reset() noexcept {
|
||||||
_aggregatedFlags = 0;
|
_aggregatedFlags = RATiedFlags::kNone;
|
||||||
_forbiddenFlags = 0;
|
_forbiddenFlags = RATiedFlags::kNone;
|
||||||
_count.reset();
|
_count.reset();
|
||||||
_stats.reset();
|
_stats.reset();
|
||||||
_used.reset();
|
_used.reset();
|
||||||
@@ -427,11 +421,11 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline uint32_t aggregatedFlags() const noexcept { return _aggregatedFlags; }
|
inline RATiedFlags aggregatedFlags() const noexcept { return _aggregatedFlags; }
|
||||||
inline uint32_t forbiddenFlags() const noexcept { return _forbiddenFlags; }
|
inline RATiedFlags forbiddenFlags() const noexcept { return _forbiddenFlags; }
|
||||||
|
|
||||||
inline void addAggregatedFlags(uint32_t flags) noexcept { _aggregatedFlags |= flags; }
|
inline void addAggregatedFlags(RATiedFlags flags) noexcept { _aggregatedFlags |= flags; }
|
||||||
inline void addForbiddenFlags(uint32_t flags) noexcept { _forbiddenFlags |= flags; }
|
inline void addForbiddenFlags(RATiedFlags flags) noexcept { _forbiddenFlags |= flags; }
|
||||||
|
|
||||||
//! Returns the number of tied registers added to the builder.
|
//! Returns the number of tied registers added to the builder.
|
||||||
inline uint32_t tiedRegCount() const noexcept { return uint32_t((size_t)(_cur - _tiedRegs)); }
|
inline uint32_t tiedRegCount() const noexcept { return uint32_t((size_t)(_cur - _tiedRegs)); }
|
||||||
@@ -459,19 +453,26 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
Error add(RAWorkReg* workReg, uint32_t flags, uint32_t allocable, uint32_t useId, uint32_t useRewriteMask, uint32_t outId, uint32_t outRewriteMask, uint32_t rmSize = 0) noexcept {
|
Error add(
|
||||||
uint32_t group = workReg->group();
|
RAWorkReg* workReg,
|
||||||
|
RATiedFlags flags,
|
||||||
|
RegMask useRegMask, uint32_t useId, uint32_t useRewriteMask,
|
||||||
|
RegMask outRegMask, uint32_t outId, uint32_t outRewriteMask,
|
||||||
|
uint32_t rmSize = 0,
|
||||||
|
uint32_t consecutiveParent = Globals::kInvalidId) noexcept {
|
||||||
|
|
||||||
|
RegGroup group = workReg->group();
|
||||||
RATiedReg* tiedReg = workReg->tiedReg();
|
RATiedReg* tiedReg = workReg->tiedReg();
|
||||||
|
|
||||||
if (useId != BaseReg::kIdBad) {
|
if (useId != BaseReg::kIdBad) {
|
||||||
_stats.makeFixed(group);
|
_stats.makeFixed(group);
|
||||||
_used[group] |= Support::bitMask(useId);
|
_used[group] |= Support::bitMask(useId);
|
||||||
flags |= RATiedReg::kUseFixed;
|
flags |= RATiedFlags::kUseFixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outId != BaseReg::kIdBad) {
|
if (outId != BaseReg::kIdBad) {
|
||||||
_clobbered[group] |= Support::bitMask(outId);
|
_clobbered[group] |= Support::bitMask(outId);
|
||||||
flags |= RATiedReg::kOutFixed;
|
flags |= RATiedFlags::kOutFixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
_aggregatedFlags |= flags;
|
_aggregatedFlags |= flags;
|
||||||
@@ -482,13 +483,19 @@ public:
|
|||||||
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
||||||
|
|
||||||
tiedReg = _cur++;
|
tiedReg = _cur++;
|
||||||
tiedReg->init(workReg->workId(), flags, allocable, useId, useRewriteMask, outId, outRewriteMask, rmSize);
|
tiedReg->init(workReg->workId(), flags, useRegMask, useId, useRewriteMask, outRegMask, outId, outRewriteMask, rmSize, consecutiveParent);
|
||||||
workReg->setTiedReg(tiedReg);
|
workReg->setTiedReg(tiedReg);
|
||||||
|
|
||||||
_count.add(group);
|
_count.add(group);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
if (consecutiveParent != tiedReg->consecutiveParent()) {
|
||||||
|
if (tiedReg->consecutiveParent() != Globals::kInvalidId)
|
||||||
|
return DebugUtils::errored(kErrorInvalidState);
|
||||||
|
tiedReg->_consecutiveParent = consecutiveParent;
|
||||||
|
}
|
||||||
|
|
||||||
if (useId != BaseReg::kIdBad) {
|
if (useId != BaseReg::kIdBad) {
|
||||||
if (ASMJIT_UNLIKELY(tiedReg->hasUseId()))
|
if (ASMJIT_UNLIKELY(tiedReg->hasUseId()))
|
||||||
return DebugUtils::errored(kErrorOverlappedRegs);
|
return DebugUtils::errored(kErrorOverlappedRegs);
|
||||||
@@ -503,8 +510,9 @@ public:
|
|||||||
|
|
||||||
tiedReg->addRefCount();
|
tiedReg->addRefCount();
|
||||||
tiedReg->addFlags(flags);
|
tiedReg->addFlags(flags);
|
||||||
tiedReg->_allocableRegs &= allocable;
|
tiedReg->_useRegMask &= useRegMask;
|
||||||
tiedReg->_useRewriteMask |= useRewriteMask;
|
tiedReg->_useRewriteMask |= useRewriteMask;
|
||||||
|
tiedReg->_outRegMask &= outRegMask;
|
||||||
tiedReg->_outRewriteMask |= outRewriteMask;
|
tiedReg->_outRewriteMask |= outRewriteMask;
|
||||||
tiedReg->_rmSize = uint8_t(Support::max<uint32_t>(tiedReg->rmSize(), rmSize));
|
tiedReg->_rmSize = uint8_t(Support::max<uint32_t>(tiedReg->rmSize(), rmSize));
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
@@ -514,9 +522,9 @@ public:
|
|||||||
Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept {
|
Error addCallArg(RAWorkReg* workReg, uint32_t useId) noexcept {
|
||||||
ASMJIT_ASSERT(useId != BaseReg::kIdBad);
|
ASMJIT_ASSERT(useId != BaseReg::kIdBad);
|
||||||
|
|
||||||
uint32_t flags = RATiedReg::kUse | RATiedReg::kRead | RATiedReg::kUseFixed;
|
RATiedFlags flags = RATiedFlags::kUse | RATiedFlags::kRead | RATiedFlags::kUseFixed;
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
uint32_t allocable = Support::bitMask(useId);
|
RegMask allocable = Support::bitMask(useId);
|
||||||
|
|
||||||
_aggregatedFlags |= flags;
|
_aggregatedFlags |= flags;
|
||||||
_used[group] |= allocable;
|
_used[group] |= allocable;
|
||||||
@@ -529,7 +537,7 @@ public:
|
|||||||
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
||||||
|
|
||||||
tiedReg = _cur++;
|
tiedReg = _cur++;
|
||||||
tiedReg->init(workReg->workId(), flags, allocable, useId, 0, BaseReg::kIdBad, 0);
|
tiedReg->init(workReg->workId(), flags, allocable, useId, 0, allocable, BaseReg::kIdBad, 0);
|
||||||
workReg->setTiedReg(tiedReg);
|
workReg->setTiedReg(tiedReg);
|
||||||
|
|
||||||
_count.add(group);
|
_count.add(group);
|
||||||
@@ -537,12 +545,12 @@ public:
|
|||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (tiedReg->hasUseId()) {
|
if (tiedReg->hasUseId()) {
|
||||||
flags |= RATiedReg::kDuplicate;
|
flags |= RATiedFlags::kDuplicate;
|
||||||
tiedReg->_allocableRegs |= allocable;
|
tiedReg->_useRegMask |= allocable;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
tiedReg->setUseId(useId);
|
tiedReg->setUseId(useId);
|
||||||
tiedReg->_allocableRegs &= allocable;
|
tiedReg->_useRegMask &= allocable;
|
||||||
}
|
}
|
||||||
|
|
||||||
tiedReg->addRefCount();
|
tiedReg->addRefCount();
|
||||||
@@ -554,12 +562,12 @@ public:
|
|||||||
Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept {
|
Error addCallRet(RAWorkReg* workReg, uint32_t outId) noexcept {
|
||||||
ASMJIT_ASSERT(outId != BaseReg::kIdBad);
|
ASMJIT_ASSERT(outId != BaseReg::kIdBad);
|
||||||
|
|
||||||
uint32_t flags = RATiedReg::kOut | RATiedReg::kWrite | RATiedReg::kOutFixed;
|
RATiedFlags flags = RATiedFlags::kOut | RATiedFlags::kWrite | RATiedFlags::kOutFixed;
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
uint32_t allocable = Support::bitMask(outId);
|
RegMask outRegs = Support::bitMask(outId);
|
||||||
|
|
||||||
_aggregatedFlags |= flags;
|
_aggregatedFlags |= flags;
|
||||||
_used[group] |= allocable;
|
_used[group] |= outRegs;
|
||||||
_stats.makeFixed(group);
|
_stats.makeFixed(group);
|
||||||
_stats.makeUsed(group);
|
_stats.makeUsed(group);
|
||||||
|
|
||||||
@@ -569,7 +577,7 @@ public:
|
|||||||
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
ASMJIT_ASSERT(tiedRegCount() < ASMJIT_ARRAY_SIZE(_tiedRegs));
|
||||||
|
|
||||||
tiedReg = _cur++;
|
tiedReg = _cur++;
|
||||||
tiedReg->init(workReg->workId(), flags, allocable, BaseReg::kIdBad, 0, outId, 0);
|
tiedReg->init(workReg->workId(), flags, Support::allOnes<RegMask>(), BaseReg::kIdBad, 0, outRegs, outId, 0);
|
||||||
workReg->setTiedReg(tiedReg);
|
workReg->setTiedReg(tiedReg);
|
||||||
|
|
||||||
_count.add(group);
|
_count.add(group);
|
||||||
@@ -589,21 +597,21 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! Intersection of multiple register assignments.
|
||||||
// [asmjit::RASharedAssignment]
|
//!
|
||||||
// ============================================================================
|
//! See \ref RAAssignment for more information about register assignments.
|
||||||
|
|
||||||
class RASharedAssignment {
|
class RASharedAssignment {
|
||||||
public:
|
public:
|
||||||
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
||||||
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
||||||
|
|
||||||
//! Bit-mask of registers that cannot be used upon a block entry, for each
|
//! \name Members
|
||||||
//! block that has this shared assignment. Scratch registers can come from
|
//! \{
|
||||||
//! ISA limits (like jecx/loop instructions on x86) or because the registers
|
|
||||||
//! are used by jump/branch instruction that uses registers to perform an
|
//! Bit-mask of registers that cannot be used upon a block entry, for each block that has this shared assignment.
|
||||||
//! indirect jump.
|
//! Scratch registers can come from ISA limits (like jecx/loop instructions on x86) or because the registers are
|
||||||
uint32_t _entryScratchGpRegs = 0;
|
//! used by jump/branch instruction that uses registers to perform an indirect jump.
|
||||||
|
RegMask _entryScratchGpRegs = 0;
|
||||||
//! Union of all live-in registers.
|
//! Union of all live-in registers.
|
||||||
ZoneBitVector _liveIn {};
|
ZoneBitVector _liveIn {};
|
||||||
//! Register assignment (PhysToWork).
|
//! Register assignment (PhysToWork).
|
||||||
@@ -611,30 +619,28 @@ public:
|
|||||||
//! Register assignment (WorkToPhys).
|
//! Register assignment (WorkToPhys).
|
||||||
WorkToPhysMap* _workToPhysMap = nullptr;
|
WorkToPhysMap* _workToPhysMap = nullptr;
|
||||||
|
|
||||||
//! Most likely never called as we initialize a vector of shared assignments to zero.
|
//! \}
|
||||||
inline RASharedAssignment() noexcept {}
|
|
||||||
|
|
||||||
inline uint32_t entryScratchGpRegs() const noexcept { return _entryScratchGpRegs; }
|
//! \name Accessors
|
||||||
inline void addEntryScratchGpRegs(uint32_t mask) noexcept { _entryScratchGpRegs |= mask; }
|
//! \{
|
||||||
|
|
||||||
|
inline bool empty() const noexcept { return _physToWorkMap == nullptr; }
|
||||||
|
|
||||||
|
inline RegMask entryScratchGpRegs() const noexcept { return _entryScratchGpRegs; }
|
||||||
|
inline void addEntryScratchGpRegs(RegMask mask) noexcept { _entryScratchGpRegs |= mask; }
|
||||||
|
|
||||||
inline const ZoneBitVector& liveIn() const noexcept { return _liveIn; }
|
inline const ZoneBitVector& liveIn() const noexcept { return _liveIn; }
|
||||||
|
|
||||||
inline PhysToWorkMap* physToWorkMap() const noexcept { return _physToWorkMap; }
|
inline PhysToWorkMap* physToWorkMap() const noexcept { return _physToWorkMap; }
|
||||||
inline WorkToPhysMap* workToPhysMap() const noexcept { return _workToPhysMap; }
|
inline WorkToPhysMap* workToPhysMap() const noexcept { return _workToPhysMap; }
|
||||||
|
|
||||||
inline bool empty() const noexcept {
|
|
||||||
return _physToWorkMap == nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void assignMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept {
|
inline void assignMaps(PhysToWorkMap* physToWorkMap, WorkToPhysMap* workToPhysMap) noexcept {
|
||||||
_physToWorkMap = physToWorkMap;
|
_physToWorkMap = physToWorkMap;
|
||||||
_workToPhysMap = workToPhysMap;
|
_workToPhysMap = workToPhysMap;
|
||||||
}
|
}
|
||||||
};
|
|
||||||
|
|
||||||
// ============================================================================
|
//! \}
|
||||||
// [asmjit::BaseRAPass]
|
};
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Register allocation pass used by `BaseCompiler`.
|
//! Register allocation pass used by `BaseCompiler`.
|
||||||
class BaseRAPass : public FuncPass {
|
class BaseRAPass : public FuncPass {
|
||||||
@@ -642,13 +648,16 @@ public:
|
|||||||
ASMJIT_NONCOPYABLE(BaseRAPass)
|
ASMJIT_NONCOPYABLE(BaseRAPass)
|
||||||
typedef FuncPass Base;
|
typedef FuncPass Base;
|
||||||
|
|
||||||
enum Weights : uint32_t {
|
enum : uint32_t {
|
||||||
kCallArgWeight = 80
|
kCallArgWeight = 80
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
typedef RAAssignment::PhysToWorkMap PhysToWorkMap;
|
||||||
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
typedef RAAssignment::WorkToPhysMap WorkToPhysMap;
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Allocator that uses zone passed to `runOnFunction()`.
|
//! Allocator that uses zone passed to `runOnFunction()`.
|
||||||
ZoneAllocator _allocator {};
|
ZoneAllocator _allocator {};
|
||||||
//! Emit helper.
|
//! Emit helper.
|
||||||
@@ -656,10 +665,10 @@ public:
|
|||||||
|
|
||||||
//! Logger, disabled if null.
|
//! Logger, disabled if null.
|
||||||
Logger* _logger = nullptr;
|
Logger* _logger = nullptr;
|
||||||
//! Debug logger, non-null only if `kOptionDebugPasses` option is set.
|
//! Format options, copied from Logger, or zeroed if there is no logger.
|
||||||
Logger* _debugLogger = nullptr;
|
FormatOptions _formatOptions {};
|
||||||
//! Logger flags.
|
//! Diagnostic options, copied from Emitter, or zeroed if there is no logger.
|
||||||
uint32_t _loggerFlags = 0;
|
DiagnosticOptions _diagnosticOptions {};
|
||||||
|
|
||||||
//! Function being processed.
|
//! Function being processed.
|
||||||
FuncNode* _func = nullptr;
|
FuncNode* _func = nullptr;
|
||||||
@@ -680,7 +689,7 @@ public:
|
|||||||
//! Number of created blocks (internal).
|
//! Number of created blocks (internal).
|
||||||
uint32_t _createdBlockCount = 0;
|
uint32_t _createdBlockCount = 0;
|
||||||
|
|
||||||
//! SharedState blocks.
|
//! Shared assignment blocks.
|
||||||
ZoneVector<RASharedAssignment> _sharedAssignments {};
|
ZoneVector<RASharedAssignment> _sharedAssignments {};
|
||||||
|
|
||||||
//! Timestamp generator (incremental).
|
//! Timestamp generator (incremental).
|
||||||
@@ -695,7 +704,7 @@ public:
|
|||||||
//! Total number of physical registers.
|
//! Total number of physical registers.
|
||||||
uint32_t _physRegTotal = 0;
|
uint32_t _physRegTotal = 0;
|
||||||
//! Indexes of a possible scratch registers that can be selected if necessary.
|
//! Indexes of a possible scratch registers that can be selected if necessary.
|
||||||
uint8_t _scratchRegIndexes[2] {};
|
Support::Array<uint8_t, 2> _scratchRegIndexes {};
|
||||||
|
|
||||||
//! Registers available for allocation.
|
//! Registers available for allocation.
|
||||||
RARegMask _availableRegs = RARegMask();
|
RARegMask _availableRegs = RARegMask();
|
||||||
@@ -707,14 +716,14 @@ public:
|
|||||||
//! Work registers (registers used by the function).
|
//! Work registers (registers used by the function).
|
||||||
RAWorkRegs _workRegs;
|
RAWorkRegs _workRegs;
|
||||||
//! Work registers per register group.
|
//! Work registers per register group.
|
||||||
RAWorkRegs _workRegsOfGroup[BaseReg::kGroupVirt];
|
Support::Array<RAWorkRegs, Globals::kNumVirtGroups> _workRegsOfGroup;
|
||||||
|
|
||||||
//! Register allocation strategy per register group.
|
//! Register allocation strategy per register group.
|
||||||
RAStrategy _strategy[BaseReg::kGroupVirt];
|
Support::Array<RAStrategy, Globals::kNumVirtGroups> _strategy;
|
||||||
//! Global max live-count (from all blocks) per register group.
|
//! Global max live-count (from all blocks) per register group.
|
||||||
RALiveCount _globalMaxLiveCount = RALiveCount();
|
RALiveCount _globalMaxLiveCount = RALiveCount();
|
||||||
//! Global live spans per register group.
|
//! Global live spans per register group.
|
||||||
LiveRegSpans* _globalLiveSpans[BaseReg::kGroupVirt] {};
|
Support::Array<LiveRegSpans*, Globals::kNumVirtGroups> _globalLiveSpans {};
|
||||||
//! Temporary stack slot.
|
//! Temporary stack slot.
|
||||||
Operand _temporaryMem = Operand();
|
Operand _temporaryMem = Operand();
|
||||||
|
|
||||||
@@ -734,7 +743,9 @@ public:
|
|||||||
//! Temporary string builder used to format comments.
|
//! Temporary string builder used to format comments.
|
||||||
StringTmp<80> _tmpString;
|
StringTmp<80> _tmpString;
|
||||||
|
|
||||||
//! \name Construction & Reset
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
BaseRAPass() noexcept;
|
BaseRAPass() noexcept;
|
||||||
@@ -747,8 +758,14 @@ public:
|
|||||||
|
|
||||||
//! Returns \ref Logger passed to \ref runOnFunction().
|
//! Returns \ref Logger passed to \ref runOnFunction().
|
||||||
inline Logger* logger() const noexcept { return _logger; }
|
inline Logger* logger() const noexcept { return _logger; }
|
||||||
//! Returns \ref Logger passed to \ref runOnFunction() or null if `kOptionDebugPasses` is not set.
|
|
||||||
inline Logger* debugLogger() const noexcept { return _debugLogger; }
|
//! Returns either a valid logger if the given `option` is set and logging is enabled, or nullptr.
|
||||||
|
inline Logger* getLoggerIf(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option) ? _logger : nullptr; }
|
||||||
|
|
||||||
|
//! Returns whether the diagnostic `option` is enabled.
|
||||||
|
//!
|
||||||
|
//! \note Returns false if there is no logger (as diagnostics without logging make no sense).
|
||||||
|
inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
|
||||||
|
|
||||||
//! Returns \ref Zone passed to \ref runOnFunction().
|
//! Returns \ref Zone passed to \ref runOnFunction().
|
||||||
inline Zone* zone() const noexcept { return _allocator.zone(); }
|
inline Zone* zone() const noexcept { return _allocator.zone(); }
|
||||||
@@ -778,7 +795,7 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline void makeUnavailable(uint32_t group, uint32_t regId) noexcept {
|
inline void makeUnavailable(RegGroup group, uint32_t regId) noexcept {
|
||||||
_availableRegs[group] &= ~Support::bitMask(regId);
|
_availableRegs[group] &= ~Support::bitMask(regId);
|
||||||
_availableRegCount[group]--;
|
_availableRegCount[group]--;
|
||||||
}
|
}
|
||||||
@@ -829,12 +846,11 @@ public:
|
|||||||
//! Returns the count of reachable basic blocks (returns size of `_pov` array).
|
//! Returns the count of reachable basic blocks (returns size of `_pov` array).
|
||||||
inline uint32_t reachableBlockCount() const noexcept { return _pov.size(); }
|
inline uint32_t reachableBlockCount() const noexcept { return _pov.size(); }
|
||||||
|
|
||||||
//! Tests whether the CFG has dangling blocks - these were created by `newBlock()`,
|
//! Tests whether the CFG has dangling blocks - these were created by `newBlock()`, but not added to CFG through
|
||||||
//! but not added to CFG through `addBlocks()`. If `true` is returned and the
|
//! `addBlocks()`. If `true` is returned and the CFG is constructed it means that something is missing and it's
|
||||||
//! CFG is constructed it means that something is missing and it's incomplete.
|
//! incomplete.
|
||||||
//!
|
//!
|
||||||
//! \note This is only used to check if the number of created blocks matches
|
//! \note This is only used to check if the number of created blocks matches the number of added blocks.
|
||||||
//! the number of added blocks.
|
|
||||||
inline bool hasDanglingBlocks() const noexcept { return _createdBlockCount != blockCount(); }
|
inline bool hasDanglingBlocks() const noexcept { return _createdBlockCount != blockCount(); }
|
||||||
|
|
||||||
//! Gest a next timestamp to be used to mark CFG blocks.
|
//! Gest a next timestamp to be used to mark CFG blocks.
|
||||||
@@ -842,31 +858,29 @@ public:
|
|||||||
|
|
||||||
//! Createss a new `RABlock` instance.
|
//! Createss a new `RABlock` instance.
|
||||||
//!
|
//!
|
||||||
//! \note New blocks don't have ID assigned until they are added to the block
|
//! \note New blocks don't have ID assigned until they are added to the block array by calling `addBlock()`.
|
||||||
//! array by calling `addBlock()`.
|
|
||||||
RABlock* newBlock(BaseNode* initialNode = nullptr) noexcept;
|
RABlock* newBlock(BaseNode* initialNode = nullptr) noexcept;
|
||||||
|
|
||||||
//! Tries to find a neighboring LabelNode (without going through code) that is
|
//! Tries to find a neighboring LabelNode (without going through code) that is already connected with `RABlock`.
|
||||||
//! already connected with `RABlock`. If no label is found then a new RABlock
|
//! If no label is found then a new RABlock is created and assigned to all possible labels in a backward direction.
|
||||||
//! is created and assigned to all possible labels in a backward direction.
|
|
||||||
RABlock* newBlockOrExistingAt(LabelNode* cbLabel, BaseNode** stoppedAt = nullptr) noexcept;
|
RABlock* newBlockOrExistingAt(LabelNode* cbLabel, BaseNode** stoppedAt = nullptr) noexcept;
|
||||||
|
|
||||||
//! Adds the given `block` to the block list and assign it a unique block id.
|
//! Adds the given `block` to the block list and assign it a unique block id.
|
||||||
Error addBlock(RABlock* block) noexcept;
|
Error addBlock(RABlock* block) noexcept;
|
||||||
|
|
||||||
inline Error addExitBlock(RABlock* block) noexcept {
|
inline Error addExitBlock(RABlock* block) noexcept {
|
||||||
block->addFlags(RABlock::kFlagIsFuncExit);
|
block->addFlags(RABlockFlags::kIsFuncExit);
|
||||||
return _exits.append(allocator(), block);
|
return _exits.append(allocator(), block);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE RAInst* newRAInst(RABlock* block, uint32_t flags, uint32_t tiedRegCount, const RARegMask& clobberedRegs) noexcept {
|
ASMJIT_FORCE_INLINE RAInst* newRAInst(RABlock* block, RATiedFlags flags, uint32_t tiedRegCount, const RARegMask& clobberedRegs) noexcept {
|
||||||
void* p = zone()->alloc(RAInst::sizeOf(tiedRegCount));
|
void* p = zone()->alloc(RAInst::sizeOf(tiedRegCount));
|
||||||
if (ASMJIT_UNLIKELY(!p))
|
if (ASMJIT_UNLIKELY(!p))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
return new(p) RAInst(block, flags, tiedRegCount, clobberedRegs);
|
return new(p) RAInst(block, flags, tiedRegCount, clobberedRegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE Error assignRAInst(BaseNode* node, RABlock* block, RAInstBuilder& ib) noexcept {
|
ASMJIT_FORCE_INLINE Error assignRAInst(BaseNode* node, RABlock* block, RAInstBuilder& ib) noexcept {
|
||||||
uint32_t tiedRegCount = ib.tiedRegCount();
|
uint32_t tiedRegCount = ib.tiedRegCount();
|
||||||
RAInst* raInst = newRAInst(block, ib.aggregatedFlags(), tiedRegCount, ib._clobbered);
|
RAInst* raInst = newRAInst(block, ib.aggregatedFlags(), tiedRegCount, ib._clobbered);
|
||||||
|
|
||||||
@@ -874,7 +888,7 @@ public:
|
|||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
RARegIndex index;
|
RARegIndex index;
|
||||||
uint32_t flagsFilter = ~ib.forbiddenFlags();
|
RATiedFlags flagsFilter = ~ib.forbiddenFlags();
|
||||||
|
|
||||||
index.buildIndexes(ib._count);
|
index.buildIndexes(ib._count);
|
||||||
raInst->_tiedIndex = index;
|
raInst->_tiedIndex = index;
|
||||||
@@ -885,15 +899,15 @@ public:
|
|||||||
RAWorkReg* workReg = workRegById(tiedReg->workId());
|
RAWorkReg* workReg = workRegById(tiedReg->workId());
|
||||||
|
|
||||||
workReg->resetTiedReg();
|
workReg->resetTiedReg();
|
||||||
uint32_t group = workReg->group();
|
RegGroup group = workReg->group();
|
||||||
|
|
||||||
if (tiedReg->hasUseId()) {
|
if (tiedReg->hasUseId()) {
|
||||||
block->addFlags(RABlock::kFlagHasFixedRegs);
|
block->addFlags(RABlockFlags::kHasFixedRegs);
|
||||||
raInst->_usedRegs[group] |= Support::bitMask(tiedReg->useId());
|
raInst->_usedRegs[group] |= Support::bitMask(tiedReg->useId());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (tiedReg->hasOutId()) {
|
if (tiedReg->hasOutId()) {
|
||||||
block->addFlags(RABlock::kFlagHasFixedRegs);
|
block->addFlags(RABlockFlags::kHasFixedRegs);
|
||||||
}
|
}
|
||||||
|
|
||||||
RATiedReg& dst = raInst->_tiedRegs[index[group]++];
|
RATiedReg& dst = raInst->_tiedRegs[index[group]++];
|
||||||
@@ -901,7 +915,7 @@ public:
|
|||||||
dst._flags &= flagsFilter;
|
dst._flags &= flagsFilter;
|
||||||
|
|
||||||
if (!tiedReg->isDuplicate())
|
if (!tiedReg->isDuplicate())
|
||||||
dst._allocableRegs &= ~ib._used[group];
|
dst._useRegMask &= ~ib._used[group];
|
||||||
}
|
}
|
||||||
|
|
||||||
node->setPassData<RAInst>(raInst);
|
node->setPassData<RAInst>(raInst);
|
||||||
@@ -915,18 +929,15 @@ public:
|
|||||||
|
|
||||||
//! Traverse the whole function and do the following:
|
//! Traverse the whole function and do the following:
|
||||||
//!
|
//!
|
||||||
//! 1. Construct CFG (represented by `RABlock`) by populating `_blocks` and
|
//! 1. Construct CFG (represented by `RABlock`) by populating `_blocks` and `_exits`. Blocks describe the control
|
||||||
//! `_exits`. Blocks describe the control flow of the function and contain
|
//! flow of the function and contain some additional information that is used by the register allocator.
|
||||||
//! some additional information that is used by the register allocator.
|
|
||||||
//!
|
//!
|
||||||
//! 2. Remove unreachable code immediately. This is not strictly necessary
|
//! 2. Remove unreachable code immediately. This is not strictly necessary for BaseCompiler itself as the register
|
||||||
//! for BaseCompiler itself as the register allocator cannot reach such
|
//! allocator cannot reach such nodes, but keeping instructions that use virtual registers would fail during
|
||||||
//! nodes, but keeping instructions that use virtual registers would fail
|
//! instruction encoding phase (Assembler).
|
||||||
//! during instruction encoding phase (Assembler).
|
|
||||||
//!
|
//!
|
||||||
//! 3. `RAInst` is created for each `InstNode` or compatible. It contains
|
//! 3. `RAInst` is created for each `InstNode` or compatible. It contains information that is essential for further
|
||||||
//! information that is essential for further analysis and register
|
//! analysis and register allocation.
|
||||||
//! allocation.
|
|
||||||
//!
|
//!
|
||||||
//! Use `RACFGBuilderT` template that provides the necessary boilerplate.
|
//! Use `RACFGBuilderT` template that provides the necessary boilerplate.
|
||||||
virtual Error buildCFG() noexcept = 0;
|
virtual Error buildCFG() noexcept = 0;
|
||||||
@@ -940,7 +951,7 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Constructs CFG views (only POV at the moment).
|
//! Constructs CFG views (only POV at the moment).
|
||||||
Error buildViews() noexcept;
|
Error buildCFGViews() noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -948,13 +959,11 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// Terminology:
|
// Terminology:
|
||||||
// - A node `X` dominates a node `Z` if any path from the entry point to
|
// - A node `X` dominates a node `Z` if any path from the entry point to `Z` has to go through `X`.
|
||||||
// `Z` has to go through `X`.
|
// - A node `Z` post-dominates a node `X` if any path from `X` to the end of the graph has to go through `Z`.
|
||||||
// - A node `Z` post-dominates a node `X` if any path from `X` to the end
|
|
||||||
// of the graph has to go through `Z`.
|
|
||||||
|
|
||||||
//! Constructs a dominator-tree from CFG.
|
//! Constructs a dominator-tree from CFG.
|
||||||
Error buildDominators() noexcept;
|
Error buildCFGDominators() noexcept;
|
||||||
|
|
||||||
bool _strictlyDominates(const RABlock* a, const RABlock* b) const noexcept;
|
bool _strictlyDominates(const RABlock* a, const RABlock* b) const noexcept;
|
||||||
const RABlock* _nearestCommonDominator(const RABlock* a, const RABlock* b) const noexcept;
|
const RABlock* _nearestCommonDominator(const RABlock* a, const RABlock* b) const noexcept;
|
||||||
@@ -974,17 +983,15 @@ public:
|
|||||||
//! \name CFG - Utilities
|
//! \name CFG - Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
Error removeUnreachableBlocks() noexcept;
|
Error removeUnreachableCode() noexcept;
|
||||||
|
|
||||||
//! Returns `node` or some node after that is ideal for beginning a new block.
|
//! Returns `node` or some node after that is ideal for beginning a new block. This function is mostly used after
|
||||||
//! This function is mostly used after a conditional or unconditional jump to
|
//! a conditional or unconditional jump to select the successor node. In some cases the next node could be a label,
|
||||||
//! select the successor node. In some cases the next node could be a label,
|
|
||||||
//! which means it could have assigned some block already.
|
//! which means it could have assigned some block already.
|
||||||
BaseNode* findSuccessorStartingAt(BaseNode* node) noexcept;
|
BaseNode* findSuccessorStartingAt(BaseNode* node) noexcept;
|
||||||
|
|
||||||
//! Returns `true` of the `node` can flow to `target` without reaching code
|
//! Returns `true` of the `node` can flow to `target` without reaching code nor data. It's used to eliminate jumps
|
||||||
//! nor data. It's used to eliminate jumps to labels that are next right to
|
//! to labels that are next right to them.
|
||||||
//! them.
|
|
||||||
bool isNextTo(BaseNode* node, BaseNode* target) noexcept;
|
bool isNextTo(BaseNode* node, BaseNode* target) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -994,25 +1001,25 @@ public:
|
|||||||
|
|
||||||
//! Returns a native size of the general-purpose register of the target architecture.
|
//! Returns a native size of the general-purpose register of the target architecture.
|
||||||
inline uint32_t registerSize() const noexcept { return _sp.size(); }
|
inline uint32_t registerSize() const noexcept { return _sp.size(); }
|
||||||
inline uint32_t availableRegCount(uint32_t group) const noexcept { return _availableRegCount[group]; }
|
inline uint32_t availableRegCount(RegGroup group) const noexcept { return _availableRegCount[group]; }
|
||||||
|
|
||||||
inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _workRegs[workId]; }
|
inline RAWorkReg* workRegById(uint32_t workId) const noexcept { return _workRegs[workId]; }
|
||||||
|
|
||||||
inline RAWorkRegs& workRegs() noexcept { return _workRegs; }
|
inline RAWorkRegs& workRegs() noexcept { return _workRegs; }
|
||||||
inline RAWorkRegs& workRegs(uint32_t group) noexcept { return _workRegsOfGroup[group]; }
|
inline RAWorkRegs& workRegs(RegGroup group) noexcept { return _workRegsOfGroup[group]; }
|
||||||
|
|
||||||
inline const RAWorkRegs& workRegs() const noexcept { return _workRegs; }
|
inline const RAWorkRegs& workRegs() const noexcept { return _workRegs; }
|
||||||
inline const RAWorkRegs& workRegs(uint32_t group) const noexcept { return _workRegsOfGroup[group]; }
|
inline const RAWorkRegs& workRegs(RegGroup group) const noexcept { return _workRegsOfGroup[group]; }
|
||||||
|
|
||||||
inline uint32_t workRegCount() const noexcept { return _workRegs.size(); }
|
inline uint32_t workRegCount() const noexcept { return _workRegs.size(); }
|
||||||
inline uint32_t workRegCount(uint32_t group) const noexcept { return _workRegsOfGroup[group].size(); }
|
inline uint32_t workRegCount(RegGroup group) const noexcept { return _workRegsOfGroup[group].size(); }
|
||||||
|
|
||||||
inline void _buildPhysIndex() noexcept {
|
inline void _buildPhysIndex() noexcept {
|
||||||
_physRegIndex.buildIndexes(_physRegCount);
|
_physRegIndex.buildIndexes(_physRegCount);
|
||||||
_physRegTotal = uint32_t(_physRegIndex[BaseReg::kGroupVirt - 1]) +
|
_physRegTotal = uint32_t(_physRegIndex[RegGroup::kMaxVirt]) +
|
||||||
uint32_t(_physRegCount[BaseReg::kGroupVirt - 1]) ;
|
uint32_t(_physRegCount[RegGroup::kMaxVirt]) ;
|
||||||
}
|
}
|
||||||
inline uint32_t physRegIndex(uint32_t group) const noexcept { return _physRegIndex[group]; }
|
inline uint32_t physRegIndex(RegGroup group) const noexcept { return _physRegIndex[group]; }
|
||||||
inline uint32_t physRegTotal() const noexcept { return _physRegTotal; }
|
inline uint32_t physRegTotal() const noexcept { return _physRegTotal; }
|
||||||
|
|
||||||
Error _asWorkReg(VirtReg* vReg, RAWorkReg** out) noexcept;
|
Error _asWorkReg(VirtReg* vReg, RAWorkReg** out) noexcept;
|
||||||
@@ -1024,7 +1031,7 @@ public:
|
|||||||
return *out ? kErrorOk : _asWorkReg(vReg, out);
|
return *out ? kErrorOk : _asWorkReg(vReg, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline Error virtIndexAsWorkReg(uint32_t vIndex, RAWorkReg** out) noexcept {
|
ASMJIT_FORCE_INLINE Error virtIndexAsWorkReg(uint32_t vIndex, RAWorkReg** out) noexcept {
|
||||||
const ZoneVector<VirtReg*>& virtRegs = cc()->virtRegs();
|
const ZoneVector<VirtReg*>& virtRegs = cc()->virtRegs();
|
||||||
if (ASMJIT_UNLIKELY(vIndex >= virtRegs.size()))
|
if (ASMJIT_UNLIKELY(vIndex >= virtRegs.size()))
|
||||||
return DebugUtils::errored(kErrorInvalidVirtId);
|
return DebugUtils::errored(kErrorInvalidVirtId);
|
||||||
@@ -1045,7 +1052,10 @@ public:
|
|||||||
|
|
||||||
inline BaseMem workRegAsMem(RAWorkReg* workReg) noexcept {
|
inline BaseMem workRegAsMem(RAWorkReg* workReg) noexcept {
|
||||||
getOrCreateStackSlot(workReg);
|
getOrCreateStackSlot(workReg);
|
||||||
return BaseMem(BaseMem::Decomposed { _sp.type(), workReg->virtId(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag });
|
return BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
|
||||||
|
OperandSignature::fromMemBaseType(_sp.type()) |
|
||||||
|
OperandSignature::fromBits(OperandSignature::kMemRegHomeFlag),
|
||||||
|
workReg->virtId(), 0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
WorkToPhysMap* newWorkToPhysMap() noexcept;
|
WorkToPhysMap* newWorkToPhysMap() noexcept;
|
||||||
@@ -1085,7 +1095,7 @@ public:
|
|||||||
//! Initializes data structures used for global live spans.
|
//! Initializes data structures used for global live spans.
|
||||||
Error initGlobalLiveSpans() noexcept;
|
Error initGlobalLiveSpans() noexcept;
|
||||||
|
|
||||||
Error binPack(uint32_t group) noexcept;
|
Error binPack(RegGroup group) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -1159,8 +1169,8 @@ public:
|
|||||||
|
|
||||||
inline ZoneAllocator* RABlock::allocator() const noexcept { return _ra->allocator(); }
|
inline ZoneAllocator* RABlock::allocator() const noexcept { return _ra->allocator(); }
|
||||||
|
|
||||||
inline uint32_t RABlock::entryScratchGpRegs() const noexcept {
|
inline RegMask RABlock::entryScratchGpRegs() const noexcept {
|
||||||
uint32_t regs = _entryScratchGpRegs;
|
RegMask regs = _entryScratchGpRegs;
|
||||||
if (hasSharedAssignmentId())
|
if (hasSharedAssignmentId())
|
||||||
regs = _ra->_sharedAssignments[_sharedAssignmentId].entryScratchGpRegs();
|
regs = _ra->_sharedAssignments[_sharedAssignmentId].entryScratchGpRegs();
|
||||||
return regs;
|
return regs;
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_COMPILER
|
#ifndef ASMJIT_NO_COMPILER
|
||||||
@@ -29,9 +11,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// RAStackAllocator - Slots
|
||||||
// [asmjit::RAStackAllocator - Slots]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32_t alignment, uint32_t flags) noexcept {
|
RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32_t alignment, uint32_t flags) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_slots.willGrow(allocator(), 1) != kErrorOk))
|
if (ASMJIT_UNLIKELY(_slots.willGrow(allocator(), 1) != kErrorOk))
|
||||||
@@ -55,9 +36,8 @@ RAStackSlot* RAStackAllocator::newSlot(uint32_t baseRegId, uint32_t size, uint32
|
|||||||
return slot;
|
return slot;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// RAStackAllocator - Utilities
|
||||||
// [asmjit::RAStackAllocator - Utilities]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
struct RAStackGap {
|
struct RAStackGap {
|
||||||
inline RAStackGap() noexcept
|
inline RAStackGap() noexcept
|
||||||
@@ -82,10 +62,9 @@ Error RAStackAllocator::calculateStackFrame() noexcept {
|
|||||||
|
|
||||||
// STEP 1:
|
// STEP 1:
|
||||||
//
|
//
|
||||||
// Update usage based on the size of the slot. We boost smaller slots in a way
|
// Update usage based on the size of the slot. We boost smaller slots in a way that 32-bit register has higher
|
||||||
// that 32-bit register has higher priority than a 128-bit register, however,
|
// priority than a 128-bit register, however, if one 128-bit register is used 4 times more than some other 32-bit
|
||||||
// if one 128-bit register is used 4 times more than some other 32-bit register
|
// register it will overweight it.
|
||||||
// it will overweight it.
|
|
||||||
for (RAStackSlot* slot : _slots) {
|
for (RAStackSlot* slot : _slots) {
|
||||||
uint32_t alignment = slot->alignment();
|
uint32_t alignment = slot->alignment();
|
||||||
ASMJIT_ASSERT(alignment > 0);
|
ASMJIT_ASSERT(alignment > 0);
|
||||||
@@ -98,8 +77,8 @@ Error RAStackAllocator::calculateStackFrame() noexcept {
|
|||||||
else
|
else
|
||||||
weight = power;
|
weight = power;
|
||||||
|
|
||||||
// If overflown, which has less chance of winning a lottery, just use max
|
// If overflown, which has less chance of winning a lottery, just use max possible weight. In such case it
|
||||||
// possible weight. In such case it probably doesn't matter at all.
|
// probably doesn't matter at all.
|
||||||
if (weight > 0xFFFFFFFFu)
|
if (weight > 0xFFFFFFFFu)
|
||||||
weight = 0xFFFFFFFFu;
|
weight = 0xFFFFFFFFu;
|
||||||
|
|
||||||
@@ -116,12 +95,11 @@ Error RAStackAllocator::calculateStackFrame() noexcept {
|
|||||||
|
|
||||||
// STEP 3:
|
// STEP 3:
|
||||||
//
|
//
|
||||||
// Calculate offset of each slot. We start from the slot that has the highest
|
// Calculate offset of each slot. We start from the slot that has the highest weight and advance to slots with
|
||||||
// weight and advance to slots with lower weight. It could look that offsets
|
// lower weight. It could look that offsets start from the first slot in our list and then simply increase, but
|
||||||
// start from the first slot in our list and then simply increase, but it's
|
// it's not always the case as we also try to fill all gaps introduced by the fact that slots are sorted by
|
||||||
// not always the case as we also try to fill all gaps introduced by the fact
|
// weight and not by size & alignment, so when we need to align some slot we distribute the gap caused by the
|
||||||
// that slots are sorted by weight and not by size & alignment, so when we need
|
// alignment to `gaps`.
|
||||||
// to align some slot we distribute the gap caused by the alignment to `gaps`.
|
|
||||||
uint32_t offset = 0;
|
uint32_t offset = 0;
|
||||||
ZoneVector<RAStackGap> gaps[kSizeCount - 1];
|
ZoneVector<RAStackGap> gaps[kSizeCount - 1];
|
||||||
|
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_RASTACK_P_H_INCLUDED
|
#ifndef ASMJIT_CORE_RASTACK_P_H_INCLUDED
|
||||||
#define ASMJIT_CORE_RASTACK_P_H_INCLUDED
|
#define ASMJIT_CORE_RASTACK_P_H_INCLUDED
|
||||||
@@ -35,26 +17,25 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_ra
|
//! \addtogroup asmjit_ra
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::RAStackSlot]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Stack slot.
|
//! Stack slot.
|
||||||
struct RAStackSlot {
|
struct RAStackSlot {
|
||||||
//! Stack slot flags.
|
//! Stack slot flags.
|
||||||
//!
|
//!
|
||||||
//! TODO: kFlagStackArg is not used by the current implementation, do we need to keep it?
|
//! TODO: kFlagStackArg is not used by the current implementation, do we need to keep it?
|
||||||
enum Flags : uint32_t {
|
enum Flags : uint16_t {
|
||||||
//! Stack slot is register home slot.
|
//! Stack slot is register home slot.
|
||||||
kFlagRegHome = 0x0001u,
|
kFlagRegHome = 0x0001u,
|
||||||
//! Stack slot position matches argument passed via stack.
|
//! Stack slot position matches argument passed via stack.
|
||||||
kFlagStackArg = 0x0002u
|
kFlagStackArg = 0x0002u
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ArgIndex : uint32_t {
|
enum ArgIndex : uint32_t {
|
||||||
kNoArgIndex = 0xFF
|
kNoArgIndex = 0xFF
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Base register used to address the stack.
|
//! Base register used to address the stack.
|
||||||
uint8_t _baseRegId;
|
uint8_t _baseRegId;
|
||||||
//! Minimum alignment required by the slot.
|
//! Minimum alignment required by the slot.
|
||||||
@@ -71,6 +52,8 @@ struct RAStackSlot {
|
|||||||
//! Stack offset, calculated by \ref RAStackAllocator::calculateStackFrame().
|
//! Stack offset, calculated by \ref RAStackAllocator::calculateStackFrame().
|
||||||
int32_t _offset;
|
int32_t _offset;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -101,10 +84,6 @@ struct RAStackSlot {
|
|||||||
|
|
||||||
typedef ZoneVector<RAStackSlot*> RAStackSlots;
|
typedef ZoneVector<RAStackSlot*> RAStackSlots;
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::RAStackAllocator]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Stack allocator.
|
//! Stack allocator.
|
||||||
class RAStackAllocator {
|
class RAStackAllocator {
|
||||||
public:
|
public:
|
||||||
@@ -121,6 +100,9 @@ public:
|
|||||||
kSizeCount = 7
|
kSizeCount = 7
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Allocator used to allocate internal data.
|
//! Allocator used to allocate internal data.
|
||||||
ZoneAllocator* _allocator;
|
ZoneAllocator* _allocator;
|
||||||
//! Count of bytes used by all slots.
|
//! Count of bytes used by all slots.
|
||||||
@@ -132,7 +114,9 @@ public:
|
|||||||
//! Stack slots vector.
|
//! Stack slots vector.
|
||||||
RAStackSlots _slots;
|
RAStackSlots _slots;
|
||||||
|
|
||||||
//! \name Construction / Destruction
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline RAStackAllocator() noexcept
|
inline RAStackAllocator() noexcept
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/string.h"
|
#include "../core/string.h"
|
||||||
@@ -27,18 +9,16 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// String - Globals
|
||||||
// [asmjit::String - Globals]
|
// ================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const char String_baseN[] = "0123456789ABCDEF";
|
static const char String_baseN[] = "0123456789ABCDEF";
|
||||||
|
|
||||||
constexpr size_t kMinAllocSize = 64;
|
constexpr size_t kMinAllocSize = 64;
|
||||||
constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold;
|
constexpr size_t kMaxAllocSize = SIZE_MAX - Globals::kGrowThreshold;
|
||||||
|
|
||||||
// ============================================================================
|
// String - Clear & Reset
|
||||||
// [asmjit::String]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error String::reset() noexcept {
|
Error String::reset() noexcept {
|
||||||
if (_type == kTypeLarge)
|
if (_type == kTypeLarge)
|
||||||
@@ -60,7 +40,10 @@ Error String::clear() noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
char* String::prepare(uint32_t op, size_t size) noexcept {
|
// String - Prepare
|
||||||
|
// ================
|
||||||
|
|
||||||
|
char* String::prepare(ModifyOp op, size_t size) noexcept {
|
||||||
char* curData;
|
char* curData;
|
||||||
size_t curSize;
|
size_t curSize;
|
||||||
size_t curCapacity;
|
size_t curCapacity;
|
||||||
@@ -76,7 +59,7 @@ char* String::prepare(uint32_t op, size_t size) noexcept {
|
|||||||
curCapacity = kSSOCapacity;
|
curCapacity = kSSOCapacity;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (op == kOpAssign) {
|
if (op == ModifyOp::kAssign) {
|
||||||
if (size > curCapacity) {
|
if (size > curCapacity) {
|
||||||
// Prevent arithmetic overflow.
|
// Prevent arithmetic overflow.
|
||||||
if (ASMJIT_UNLIKELY(size >= kMaxAllocSize))
|
if (ASMJIT_UNLIKELY(size >= kMaxAllocSize))
|
||||||
@@ -150,6 +133,9 @@ char* String::prepare(uint32_t op, size_t size) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// String - Assign
|
||||||
|
// ===============
|
||||||
|
|
||||||
Error String::assign(const char* data, size_t size) noexcept {
|
Error String::assign(const char* data, size_t size) noexcept {
|
||||||
char* dst = nullptr;
|
char* dst = nullptr;
|
||||||
|
|
||||||
@@ -210,11 +196,10 @@ Error String::assign(const char* data, size_t size) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// String - Operations
|
||||||
// [asmjit::String - Operations]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error String::_opString(uint32_t op, const char* str, size_t size) noexcept {
|
Error String::_opString(ModifyOp op, const char* str, size_t size) noexcept {
|
||||||
if (size == SIZE_MAX)
|
if (size == SIZE_MAX)
|
||||||
size = str ? strlen(str) : size_t(0);
|
size = str ? strlen(str) : size_t(0);
|
||||||
|
|
||||||
@@ -229,7 +214,7 @@ Error String::_opString(uint32_t op, const char* str, size_t size) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opChar(uint32_t op, char c) noexcept {
|
Error String::_opChar(ModifyOp op, char c) noexcept {
|
||||||
char* p = prepare(op, 1);
|
char* p = prepare(op, 1);
|
||||||
if (!p)
|
if (!p)
|
||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
@@ -238,7 +223,7 @@ Error String::_opChar(uint32_t op, char c) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opChars(uint32_t op, char c, size_t n) noexcept {
|
Error String::_opChars(ModifyOp op, char c, size_t n) noexcept {
|
||||||
if (!n)
|
if (!n)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
@@ -255,7 +240,7 @@ Error String::padEnd(size_t n, char c) noexcept {
|
|||||||
return n > size ? appendChars(c, n - size) : kErrorOk;
|
return n > size ? appendChars(c, n - size) : kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) noexcept {
|
Error String::_opNumber(ModifyOp op, uint64_t i, uint32_t base, size_t width, StringFormatFlags flags) noexcept {
|
||||||
if (base == 0)
|
if (base == 0)
|
||||||
base = 10;
|
base = 10;
|
||||||
|
|
||||||
@@ -265,24 +250,22 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
uint64_t orig = i;
|
uint64_t orig = i;
|
||||||
char sign = '\0';
|
char sign = '\0';
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Format Sign
|
||||||
// [Sign]
|
// -----------
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if ((flags & kFormatSigned) != 0 && int64_t(i) < 0) {
|
if (Support::test(flags, StringFormatFlags::kSigned) && int64_t(i) < 0) {
|
||||||
i = uint64_t(-int64_t(i));
|
i = uint64_t(-int64_t(i));
|
||||||
sign = '-';
|
sign = '-';
|
||||||
}
|
}
|
||||||
else if ((flags & kFormatShowSign) != 0) {
|
else if (Support::test(flags, StringFormatFlags::kShowSign)) {
|
||||||
sign = '+';
|
sign = '+';
|
||||||
}
|
}
|
||||||
else if ((flags & kFormatShowSpace) != 0) {
|
else if (Support::test(flags, StringFormatFlags::kShowSpace)) {
|
||||||
sign = ' ';
|
sign = ' ';
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Format Number
|
||||||
// [Number]
|
// -------------
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
switch (base) {
|
switch (base) {
|
||||||
case 2:
|
case 2:
|
||||||
@@ -320,11 +303,10 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
|
|
||||||
size_t numberSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
|
size_t numberSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Alternate Form
|
||||||
// [Alternate Form]
|
// --------------
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if ((flags & kFormatAlternate) != 0) {
|
if (Support::test(flags, StringFormatFlags::kAlternate)) {
|
||||||
if (base == 8) {
|
if (base == 8) {
|
||||||
if (orig != 0)
|
if (orig != 0)
|
||||||
*--p = '0';
|
*--p = '0';
|
||||||
@@ -335,9 +317,8 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// String Width
|
||||||
// [Width]
|
// ------------
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
if (sign != 0)
|
if (sign != 0)
|
||||||
*--p = sign;
|
*--p = sign;
|
||||||
@@ -350,9 +331,8 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
else
|
else
|
||||||
width -= numberSize;
|
width -= numberSize;
|
||||||
|
|
||||||
// --------------------------------------------------------------------------
|
// Finalize
|
||||||
// Write]
|
// --------
|
||||||
// --------------------------------------------------------------------------
|
|
||||||
|
|
||||||
size_t prefixSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberSize;
|
size_t prefixSize = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberSize;
|
||||||
char* data = prepare(op, prefixSize + width + numberSize);
|
char* data = prepare(op, prefixSize + width + numberSize);
|
||||||
@@ -370,7 +350,7 @@ Error String::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, ui
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opHex(uint32_t op, const void* data, size_t size, char separator) noexcept {
|
Error String::_opHex(ModifyOp op, const void* data, size_t size, char separator) noexcept {
|
||||||
char* dst;
|
char* dst;
|
||||||
const uint8_t* src = static_cast<const uint8_t*>(data);
|
const uint8_t* src = static_cast<const uint8_t*>(data);
|
||||||
|
|
||||||
@@ -414,7 +394,7 @@ Error String::_opHex(uint32_t op, const void* data, size_t size, char separator)
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opFormat(uint32_t op, const char* fmt, ...) noexcept {
|
Error String::_opFormat(ModifyOp op, const char* fmt, ...) noexcept {
|
||||||
Error err;
|
Error err;
|
||||||
va_list ap;
|
va_list ap;
|
||||||
|
|
||||||
@@ -425,8 +405,8 @@ Error String::_opFormat(uint32_t op, const char* fmt, ...) noexcept {
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error String::_opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept {
|
Error String::_opVFormat(ModifyOp op, const char* fmt, va_list ap) noexcept {
|
||||||
size_t startAt = (op == kOpAssign) ? size_t(0) : size();
|
size_t startAt = (op == ModifyOp::kAssign) ? size_t(0) : size();
|
||||||
size_t remainingCapacity = capacity() - startAt;
|
size_t remainingCapacity = capacity() - startAt;
|
||||||
|
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
@@ -504,9 +484,8 @@ bool String::eq(const char* other, size_t size) const noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// String - Tests
|
||||||
// [asmjit::Support - Unit]
|
// ==============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
UNIT(core_string) {
|
UNIT(core_string) {
|
||||||
@@ -566,7 +545,7 @@ UNIT(core_string) {
|
|||||||
EXPECT(s.appendUInt(1234) == kErrorOk);
|
EXPECT(s.appendUInt(1234) == kErrorOk);
|
||||||
EXPECT(s.eq("1234") == true);
|
EXPECT(s.eq("1234") == true);
|
||||||
|
|
||||||
EXPECT(s.assignUInt(0xFFFF, 16, 0, String::kFormatAlternate) == kErrorOk);
|
EXPECT(s.assignUInt(0xFFFF, 16, 0, StringFormatFlags::kAlternate) == kErrorOk);
|
||||||
EXPECT(s.eq("0xFFFF"));
|
EXPECT(s.eq("0xFFFF"));
|
||||||
|
|
||||||
StringTmp<64> sTmp;
|
StringTmp<64> sTmp;
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_STRING_H_INCLUDED
|
#ifndef ASMJIT_CORE_STRING_H_INCLUDED
|
||||||
#define ASMJIT_CORE_STRING_H_INCLUDED
|
#define ASMJIT_CORE_STRING_H_INCLUDED
|
||||||
@@ -32,20 +14,41 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_utilities
|
//! \addtogroup asmjit_utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Format flags used by \ref String API.
|
||||||
// [asmjit::FixedString]
|
enum class StringFormatFlags : uint32_t {
|
||||||
// ============================================================================
|
//! No flags.
|
||||||
|
kNone = 0x00000000u,
|
||||||
|
//! Show sign.
|
||||||
|
kShowSign = 0x00000001u,
|
||||||
|
//! Show space.
|
||||||
|
kShowSpace = 0x00000002u,
|
||||||
|
//! Alternate form (use 0x when formatting HEX number).
|
||||||
|
kAlternate = 0x00000004u,
|
||||||
|
//! The input is signed.
|
||||||
|
kSigned = 0x80000000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(StringFormatFlags)
|
||||||
|
|
||||||
//! A fixed string - only useful for strings that would never exceed `N - 1`
|
//! Fixed string - only useful for strings that would never exceed `N - 1` characters; always null-terminated.
|
||||||
//! characters; always null-terminated.
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
union FixedString {
|
union FixedString {
|
||||||
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
// This cannot be constexpr as GCC 4.8 refuses constexpr members of unions.
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
kNumU32 = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t))
|
kNumUInt32Words = uint32_t((N + sizeof(uint32_t) - 1) / sizeof(uint32_t))
|
||||||
};
|
};
|
||||||
|
|
||||||
char str[kNumU32 * sizeof(uint32_t)];
|
//! \}
|
||||||
uint32_t u32[kNumU32];
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
char str[kNumUInt32Words * sizeof(uint32_t)];
|
||||||
|
uint32_t u32[kNumUInt32Words];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
@@ -56,46 +59,31 @@ union FixedString {
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::String]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! A simple non-reference counted string that uses small string optimization (SSO).
|
//! A simple non-reference counted string that uses small string optimization (SSO).
|
||||||
//!
|
//!
|
||||||
//! This string has 3 allocation possibilities:
|
//! This string has 3 allocation possibilities:
|
||||||
//!
|
//!
|
||||||
//! 1. Small - embedded buffer is used for up to `kSSOCapacity` characters.
|
//! 1. Small - embedded buffer is used for up to `kSSOCapacity` characters. This should handle most small
|
||||||
//! This should handle most small strings and thus avoid dynamic
|
//! strings and thus avoid dynamic memory allocation for most use-cases.
|
||||||
//! memory allocation for most use-cases.
|
|
||||||
//!
|
//!
|
||||||
//! 2. Large - string that doesn't fit into an embedded buffer (or string
|
//! 2. Large - string that doesn't fit into an embedded buffer (or string that was truncated from a larger
|
||||||
//! that was truncated from a larger buffer) and is owned by
|
//! buffer) and is owned by AsmJit. When you destroy the string AsmJit would automatically
|
||||||
//! AsmJit. When you destroy the string AsmJit would automatically
|
|
||||||
//! release the large buffer.
|
//! release the large buffer.
|
||||||
//!
|
//!
|
||||||
//! 3. External - like Large (2), however, the large buffer is not owned by
|
//! 3. External - like Large (2), however, the large buffer is not owned by AsmJit and won't be released when
|
||||||
//! AsmJit and won't be released when the string is destroyed
|
//! the string is destroyed or reallocated. This is mostly useful for working with larger temporary
|
||||||
//! or reallocated. This is mostly useful for working with
|
//! strings allocated on stack or with immutable strings.
|
||||||
//! larger temporary strings allocated on stack or with immutable
|
|
||||||
//! strings.
|
|
||||||
class String {
|
class String {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(String)
|
ASMJIT_NONCOPYABLE(String)
|
||||||
|
|
||||||
//! String operation.
|
//! String operation.
|
||||||
enum Op : uint32_t {
|
enum class ModifyOp : uint32_t {
|
||||||
//! Assignment - a new content replaces the current one.
|
//! Assignment - a new content replaces the current one.
|
||||||
kOpAssign = 0,
|
kAssign = 0,
|
||||||
//! Append - a new content is appended to the string.
|
//! Append - a new content is appended to the string.
|
||||||
kOpAppend = 1
|
kAppend = 1
|
||||||
};
|
|
||||||
|
|
||||||
//! String format flags.
|
|
||||||
enum FormatFlags : uint32_t {
|
|
||||||
kFormatShowSign = 0x00000001u,
|
|
||||||
kFormatShowSpace = 0x00000002u,
|
|
||||||
kFormatAlternate = 0x00000004u,
|
|
||||||
kFormatSigned = 0x80000000u
|
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
@@ -106,8 +94,10 @@ public:
|
|||||||
|
|
||||||
//! String type.
|
//! String type.
|
||||||
enum Type : uint8_t {
|
enum Type : uint8_t {
|
||||||
kTypeLarge = 0x1Fu, //!< Large string (owned by String).
|
//! Large string (owned by String).
|
||||||
kTypeExternal = 0x20u //!< External string (zone allocated or not owned by String).
|
kTypeLarge = 0x1Fu,
|
||||||
|
//! External string (zone allocated or not owned by String).
|
||||||
|
kTypeExternal = 0x20u
|
||||||
};
|
};
|
||||||
|
|
||||||
union Raw {
|
union Raw {
|
||||||
@@ -213,15 +203,15 @@ public:
|
|||||||
//! Clears the content of the string.
|
//! Clears the content of the string.
|
||||||
ASMJIT_API Error clear() noexcept;
|
ASMJIT_API Error clear() noexcept;
|
||||||
|
|
||||||
ASMJIT_API char* prepare(uint32_t op, size_t size) noexcept;
|
ASMJIT_API char* prepare(ModifyOp op, size_t size) noexcept;
|
||||||
|
|
||||||
ASMJIT_API Error _opString(uint32_t op, const char* str, size_t size = SIZE_MAX) noexcept;
|
ASMJIT_API Error _opString(ModifyOp op, const char* str, size_t size = SIZE_MAX) noexcept;
|
||||||
ASMJIT_API Error _opChar(uint32_t op, char c) noexcept;
|
ASMJIT_API Error _opChar(ModifyOp op, char c) noexcept;
|
||||||
ASMJIT_API Error _opChars(uint32_t op, char c, size_t n) noexcept;
|
ASMJIT_API Error _opChars(ModifyOp op, char c, size_t n) noexcept;
|
||||||
ASMJIT_API Error _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept;
|
ASMJIT_API Error _opNumber(ModifyOp op, uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept;
|
||||||
ASMJIT_API Error _opHex(uint32_t op, const void* data, size_t size, char separator = '\0') noexcept;
|
ASMJIT_API Error _opHex(ModifyOp op, const void* data, size_t size, char separator = '\0') noexcept;
|
||||||
ASMJIT_API Error _opFormat(uint32_t op, const char* fmt, ...) noexcept;
|
ASMJIT_API Error _opFormat(ModifyOp op, const char* fmt, ...) noexcept;
|
||||||
ASMJIT_API Error _opVFormat(uint32_t op, const char* fmt, va_list ap) noexcept;
|
ASMJIT_API Error _opVFormat(ModifyOp op, const char* fmt, va_list ap) noexcept;
|
||||||
|
|
||||||
//! Replaces the current of the string with `data` of the given `size`.
|
//! Replaces the current of the string with `data` of the given `size`.
|
||||||
//!
|
//!
|
||||||
@@ -235,45 +225,45 @@ public:
|
|||||||
|
|
||||||
//! Replaces the current of the string by a single `c` character.
|
//! Replaces the current of the string by a single `c` character.
|
||||||
inline Error assign(char c) noexcept {
|
inline Error assign(char c) noexcept {
|
||||||
return _opChar(kOpAssign, c);
|
return _opChar(ModifyOp::kAssign, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by a `c` character, repeated `n` times.
|
//! Replaces the current of the string by a `c` character, repeated `n` times.
|
||||||
inline Error assignChars(char c, size_t n) noexcept {
|
inline Error assignChars(char c, size_t n) noexcept {
|
||||||
return _opChars(kOpAssign, c, n);
|
return _opChars(ModifyOp::kAssign, c, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by a formatted integer `i` (signed).
|
//! Replaces the current of the string by a formatted integer `i` (signed).
|
||||||
inline Error assignInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept {
|
inline Error assignInt(int64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
|
||||||
return _opNumber(kOpAssign, uint64_t(i), base, width, flags | kFormatSigned);
|
return _opNumber(ModifyOp::kAssign, uint64_t(i), base, width, flags | StringFormatFlags::kSigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by a formatted integer `i` (unsigned).
|
//! Replaces the current of the string by a formatted integer `i` (unsigned).
|
||||||
inline Error assignUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept {
|
inline Error assignUInt(uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
|
||||||
return _opNumber(kOpAssign, i, base, width, flags);
|
return _opNumber(ModifyOp::kAssign, i, base, width, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by the given `data` converted to a HEX string.
|
//! Replaces the current of the string by the given `data` converted to a HEX string.
|
||||||
inline Error assignHex(const void* data, size_t size, char separator = '\0') noexcept {
|
inline Error assignHex(const void* data, size_t size, char separator = '\0') noexcept {
|
||||||
return _opHex(kOpAssign, data, size, separator);
|
return _opHex(ModifyOp::kAssign, data, size, separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by a formatted string `fmt`.
|
//! Replaces the current of the string by a formatted string `fmt`.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline Error assignFormat(const char* fmt, Args&&... args) noexcept {
|
inline Error assignFormat(const char* fmt, Args&&... args) noexcept {
|
||||||
return _opFormat(kOpAssign, fmt, std::forward<Args>(args)...);
|
return _opFormat(ModifyOp::kAssign, fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Replaces the current of the string by a formatted string `fmt` (va_list version).
|
//! Replaces the current of the string by a formatted string `fmt` (va_list version).
|
||||||
inline Error assignVFormat(const char* fmt, va_list ap) noexcept {
|
inline Error assignVFormat(const char* fmt, va_list ap) noexcept {
|
||||||
return _opVFormat(kOpAssign, fmt, ap);
|
return _opVFormat(ModifyOp::kAssign, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends `str` having the given size `size` to the string.
|
//! Appends `str` having the given size `size` to the string.
|
||||||
//!
|
//!
|
||||||
//! Null terminated strings can set `size` to `SIZE_MAX`.
|
//! Null terminated strings can set `size` to `SIZE_MAX`.
|
||||||
inline Error append(const char* str, size_t size = SIZE_MAX) noexcept {
|
inline Error append(const char* str, size_t size = SIZE_MAX) noexcept {
|
||||||
return _opString(kOpAppend, str, size);
|
return _opString(ModifyOp::kAppend, str, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends `other` string to this string.
|
//! Appends `other` string to this string.
|
||||||
@@ -283,38 +273,38 @@ public:
|
|||||||
|
|
||||||
//! Appends a single `c` character.
|
//! Appends a single `c` character.
|
||||||
inline Error append(char c) noexcept {
|
inline Error append(char c) noexcept {
|
||||||
return _opChar(kOpAppend, c);
|
return _opChar(ModifyOp::kAppend, c);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends `c` character repeated `n` times.
|
//! Appends `c` character repeated `n` times.
|
||||||
inline Error appendChars(char c, size_t n) noexcept {
|
inline Error appendChars(char c, size_t n) noexcept {
|
||||||
return _opChars(kOpAppend, c, n);
|
return _opChars(ModifyOp::kAppend, c, n);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends a formatted integer `i` (signed).
|
//! Appends a formatted integer `i` (signed).
|
||||||
inline Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept {
|
inline Error appendInt(int64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
|
||||||
return _opNumber(kOpAppend, uint64_t(i), base, width, flags | kFormatSigned);
|
return _opNumber(ModifyOp::kAppend, uint64_t(i), base, width, flags | StringFormatFlags::kSigned);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends a formatted integer `i` (unsigned).
|
//! Appends a formatted integer `i` (unsigned).
|
||||||
inline Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) noexcept {
|
inline Error appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, StringFormatFlags flags = StringFormatFlags::kNone) noexcept {
|
||||||
return _opNumber(kOpAppend, i, base, width, flags);
|
return _opNumber(ModifyOp::kAppend, i, base, width, flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends the given `data` converted to a HEX string.
|
//! Appends the given `data` converted to a HEX string.
|
||||||
inline Error appendHex(const void* data, size_t size, char separator = '\0') noexcept {
|
inline Error appendHex(const void* data, size_t size, char separator = '\0') noexcept {
|
||||||
return _opHex(kOpAppend, data, size, separator);
|
return _opHex(ModifyOp::kAppend, data, size, separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends a formatted string `fmt` with `args`.
|
//! Appends a formatted string `fmt` with `args`.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
inline Error appendFormat(const char* fmt, Args&&... args) noexcept {
|
inline Error appendFormat(const char* fmt, Args&&... args) noexcept {
|
||||||
return _opFormat(kOpAppend, fmt, std::forward<Args>(args)...);
|
return _opFormat(ModifyOp::kAppend, fmt, std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Appends a formatted string `fmt` (va_list version).
|
//! Appends a formatted string `fmt` (va_list version).
|
||||||
inline Error appendVFormat(const char* fmt, va_list ap) noexcept {
|
inline Error appendVFormat(const char* fmt, va_list ap) noexcept {
|
||||||
return _opVFormat(kOpAppend, fmt, ap);
|
return _opVFormat(ModifyOp::kAppend, fmt, ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept;
|
ASMJIT_API Error padEnd(size_t n, char c = ' ') noexcept;
|
||||||
@@ -332,8 +322,8 @@ public:
|
|||||||
|
|
||||||
//! Resets string to embedded and makes it empty (zero length, zero first char)
|
//! Resets string to embedded and makes it empty (zero length, zero first char)
|
||||||
//!
|
//!
|
||||||
//! \note This is always called internally after an external buffer was released
|
//! \note This is always called internally after an external buffer was released as it zeroes all bytes
|
||||||
//! as it zeroes all bytes used by String's embedded storage.
|
//! used by String's embedded storage.
|
||||||
inline void _resetInternal() noexcept {
|
inline void _resetInternal() noexcept {
|
||||||
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_raw.uptr); i++)
|
for (size_t i = 0; i < ASMJIT_ARRAY_SIZE(_raw.uptr); i++)
|
||||||
_raw.uptr[i] = 0;
|
_raw.uptr[i] = 0;
|
||||||
@@ -347,26 +337,8 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
ASMJIT_DEPRECATED("Use assign() instead of assignString()")
|
|
||||||
inline Error assignString(const char* data, size_t size = SIZE_MAX) noexcept { return assign(data, size); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use assign() instead of assignChar()")
|
|
||||||
inline Error assignChar(char c) noexcept { return assign(c); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use append() instead of appendString()")
|
|
||||||
inline Error appendString(const char* data, size_t size = SIZE_MAX) noexcept { return append(data, size); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use append() instead of appendChar()")
|
|
||||||
inline Error appendChar(char c) noexcept { return append(c); }
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::StringTmp]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Temporary string builder, has statically allocated `N` bytes.
|
//! Temporary string builder, has statically allocated `N` bytes.
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
class StringTmp : public String {
|
class StringTmp : public String {
|
||||||
|
|||||||
@@ -1,34 +1,15 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// Support - Tests
|
||||||
// [asmjit::Support - Unit]
|
// ===============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
template<typename T>
|
template<typename T>
|
||||||
@@ -85,10 +66,14 @@ static void testBitUtils() noexcept {
|
|||||||
for (i = 0; i < 63; i++) EXPECT(Support::blsi(uint64_t(3) << i) == uint64_t(1) << i);
|
for (i = 0; i < 63; i++) EXPECT(Support::blsi(uint64_t(3) << i) == uint64_t(1) << i);
|
||||||
|
|
||||||
INFO("Support::ctz()");
|
INFO("Support::ctz()");
|
||||||
|
for (i = 0; i < 32; i++) EXPECT(Support::Internal::clzFallback(uint32_t(1) << i) == 31 - i);
|
||||||
|
for (i = 0; i < 64; i++) EXPECT(Support::Internal::clzFallback(uint64_t(1) << i) == 63 - i);
|
||||||
|
for (i = 0; i < 32; i++) EXPECT(Support::Internal::ctzFallback(uint32_t(1) << i) == i);
|
||||||
|
for (i = 0; i < 64; i++) EXPECT(Support::Internal::ctzFallback(uint64_t(1) << i) == i);
|
||||||
|
for (i = 0; i < 32; i++) EXPECT(Support::clz(uint32_t(1) << i) == 31 - i);
|
||||||
|
for (i = 0; i < 64; i++) EXPECT(Support::clz(uint64_t(1) << i) == 63 - i);
|
||||||
for (i = 0; i < 32; i++) EXPECT(Support::ctz(uint32_t(1) << i) == i);
|
for (i = 0; i < 32; i++) EXPECT(Support::ctz(uint32_t(1) << i) == i);
|
||||||
for (i = 0; i < 64; i++) EXPECT(Support::ctz(uint64_t(1) << i) == i);
|
for (i = 0; i < 64; i++) EXPECT(Support::ctz(uint64_t(1) << i) == i);
|
||||||
for (i = 0; i < 32; i++) EXPECT(Support::constCtz(uint32_t(1) << i) == i);
|
|
||||||
for (i = 0; i < 64; i++) EXPECT(Support::constCtz(uint64_t(1) << i) == i);
|
|
||||||
|
|
||||||
INFO("Support::bitMask()");
|
INFO("Support::bitMask()");
|
||||||
EXPECT(Support::bitMask(0, 1, 7) == 0x83u);
|
EXPECT(Support::bitMask(0, 1, 7) == 0x83u);
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,37 +1,14 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/target.h"
|
#include "../core/target.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
Target::Target() noexcept : _environment() {}
|
||||||
// [asmjit::Target - Construction / Destruction]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Target::Target() noexcept
|
|
||||||
: _environment() {}
|
|
||||||
Target::~Target() noexcept {}
|
Target::~Target() noexcept {}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_TARGET_H_INCLUDED
|
#ifndef ASMJIT_CORE_TARGET_H_INCLUDED
|
||||||
#define ASMJIT_CORE_TARGET_H_INCLUDED
|
#define ASMJIT_CORE_TARGET_H_INCLUDED
|
||||||
@@ -32,98 +14,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::CodeInfo]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
//! Basic information about a code (or target). It describes its architecture,
|
|
||||||
//! code generation mode (or optimization level), and base address.
|
|
||||||
class ASMJIT_DEPRECATED_STRUCT("Use Environment instead of CodeInfo") CodeInfo {
|
|
||||||
public:
|
|
||||||
//!< Environment information.
|
|
||||||
Environment _environment;
|
|
||||||
//! Base address.
|
|
||||||
uint64_t _baseAddress;
|
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
inline CodeInfo() noexcept
|
|
||||||
: _environment(),
|
|
||||||
_baseAddress(Globals::kNoBaseAddress) {}
|
|
||||||
|
|
||||||
inline explicit CodeInfo(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept
|
|
||||||
: _environment(arch, subArch),
|
|
||||||
_baseAddress(baseAddress) {}
|
|
||||||
|
|
||||||
inline explicit CodeInfo(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept
|
|
||||||
: _environment(environment),
|
|
||||||
_baseAddress(baseAddress) {}
|
|
||||||
|
|
||||||
|
|
||||||
inline CodeInfo(const CodeInfo& other) noexcept { init(other); }
|
|
||||||
|
|
||||||
inline bool isInitialized() const noexcept {
|
|
||||||
return _environment.arch() != Environment::kArchUnknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void init(const CodeInfo& other) noexcept {
|
|
||||||
*this = other;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void init(uint32_t arch, uint32_t subArch = 0, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept {
|
|
||||||
_environment.init(arch, subArch);
|
|
||||||
_baseAddress = baseAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void reset() noexcept {
|
|
||||||
_environment.reset();
|
|
||||||
_baseAddress = Globals::kNoBaseAddress;
|
|
||||||
}
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Overloaded Operators
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
inline CodeInfo& operator=(const CodeInfo& other) noexcept = default;
|
|
||||||
|
|
||||||
inline bool operator==(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) == 0; }
|
|
||||||
inline bool operator!=(const CodeInfo& other) const noexcept { return ::memcmp(this, &other, sizeof(*this)) != 0; }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
|
|
||||||
//! \name Accessors
|
|
||||||
//! \{
|
|
||||||
|
|
||||||
//! Returns the target environment information, see \ref Environment.
|
|
||||||
inline const Environment& environment() const noexcept { return _environment; }
|
|
||||||
|
|
||||||
//! Returns the target architecture, see \ref Environment::Arch.
|
|
||||||
inline uint32_t arch() const noexcept { return _environment.arch(); }
|
|
||||||
//! Returns the target sub-architecture, see \ref Environment::SubArch.
|
|
||||||
inline uint32_t subArch() const noexcept { return _environment.subArch(); }
|
|
||||||
//! Returns the native size of the target's architecture GP register.
|
|
||||||
inline uint32_t gpSize() const noexcept { return _environment.registerSize(); }
|
|
||||||
|
|
||||||
//! Tests whether this CodeInfo has a base address set.
|
|
||||||
inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
|
|
||||||
//! Returns the base address or \ref Globals::kNoBaseAddress if it's not set.
|
|
||||||
inline uint64_t baseAddress() const noexcept { return _baseAddress; }
|
|
||||||
//! Sets base address to `p`.
|
|
||||||
inline void setBaseAddress(uint64_t p) noexcept { _baseAddress = p; }
|
|
||||||
//! Resets base address (implicitly sets it to \ref Globals::kNoBaseAddress).
|
|
||||||
inline void resetBaseAddress() noexcept { _baseAddress = Globals::kNoBaseAddress; }
|
|
||||||
|
|
||||||
//! \}
|
|
||||||
};
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Target]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Target is an abstract class that describes a machine code target.
|
//! Target is an abstract class that describes a machine code target.
|
||||||
class ASMJIT_VIRTAPI Target {
|
class ASMJIT_VIRTAPI Target {
|
||||||
public:
|
public:
|
||||||
@@ -146,24 +36,12 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns CodeInfo of this target.
|
//! Returns target's environment.
|
||||||
//!
|
|
||||||
//! CodeInfo can be used to setup a CodeHolder in case you plan to generate a
|
|
||||||
//! code compatible and executable by this Runtime.
|
|
||||||
inline const Environment& environment() const noexcept { return _environment; }
|
inline const Environment& environment() const noexcept { return _environment; }
|
||||||
|
//! Returns the target architecture.
|
||||||
//! Returns the target architecture, see \ref Environment::Arch.
|
inline Arch arch() const noexcept { return _environment.arch(); }
|
||||||
inline uint32_t arch() const noexcept { return _environment.arch(); }
|
//! Returns the target sub-architecture.
|
||||||
//! Returns the target sub-architecture, see \ref Environment::SubArch.
|
inline SubArch subArch() const noexcept { return _environment.subArch(); }
|
||||||
inline uint32_t subArch() const noexcept { return _environment.subArch(); }
|
|
||||||
|
|
||||||
#ifndef ASMJIT_NO_DEPRECATED
|
|
||||||
ASMJIT_DEPRECATED("Use environment() instead")
|
|
||||||
inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment); }
|
|
||||||
|
|
||||||
ASMJIT_DEPRECATED("Use environment().format() instead")
|
|
||||||
inline uint32_t targetType() const noexcept { return _environment.format(); }
|
|
||||||
#endif // !ASMJIT_NO_DEPRECATED
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/misc_p.h"
|
#include "../core/misc_p.h"
|
||||||
@@ -27,58 +9,58 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
namespace TypeUtils {
|
||||||
// [asmjit::Type]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
namespace Type {
|
template<uint32_t Index>
|
||||||
|
struct ScalarOfTypeId {
|
||||||
template<uint32_t TYPE_ID>
|
enum : uint32_t {
|
||||||
struct BaseOfTypeId {
|
kTypeId = uint32_t(
|
||||||
static constexpr uint32_t kTypeId =
|
isScalar(TypeId(Index)) ? TypeId(Index) :
|
||||||
isBase (TYPE_ID) ? TYPE_ID :
|
isMask8 (TypeId(Index)) ? TypeId::kUInt8 :
|
||||||
isMask8 (TYPE_ID) ? kIdU8 :
|
isMask16(TypeId(Index)) ? TypeId::kUInt16 :
|
||||||
isMask16(TYPE_ID) ? kIdU16 :
|
isMask32(TypeId(Index)) ? TypeId::kUInt32 :
|
||||||
isMask32(TYPE_ID) ? kIdU32 :
|
isMask64(TypeId(Index)) ? TypeId::kUInt64 :
|
||||||
isMask64(TYPE_ID) ? kIdU64 :
|
isMmx32 (TypeId(Index)) ? TypeId::kUInt32 :
|
||||||
isMmx32 (TYPE_ID) ? kIdI32 :
|
isMmx64 (TypeId(Index)) ? TypeId::kUInt64 :
|
||||||
isMmx64 (TYPE_ID) ? kIdI64 :
|
isVec32 (TypeId(Index)) ? TypeId((Index - uint32_t(TypeId::_kVec32Start ) + uint32_t(TypeId::kInt8)) & 0xFF) :
|
||||||
isVec32 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec32Start :
|
isVec64 (TypeId(Index)) ? TypeId((Index - uint32_t(TypeId::_kVec64Start ) + uint32_t(TypeId::kInt8)) & 0xFF) :
|
||||||
isVec64 (TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec64Start :
|
isVec128(TypeId(Index)) ? TypeId((Index - uint32_t(TypeId::_kVec128Start) + uint32_t(TypeId::kInt8)) & 0xFF) :
|
||||||
isVec128(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec128Start :
|
isVec256(TypeId(Index)) ? TypeId((Index - uint32_t(TypeId::_kVec256Start) + uint32_t(TypeId::kInt8)) & 0xFF) :
|
||||||
isVec256(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec256Start :
|
isVec512(TypeId(Index)) ? TypeId((Index - uint32_t(TypeId::_kVec512Start) + uint32_t(TypeId::kInt8)) & 0xFF) : TypeId::kVoid)
|
||||||
isVec512(TYPE_ID) ? TYPE_ID + kIdI8 - _kIdVec512Start : 0;
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<uint32_t TYPE_ID>
|
template<uint32_t Index>
|
||||||
struct SizeOfTypeId {
|
struct SizeOfTypeId {
|
||||||
static constexpr uint32_t kTypeSize =
|
enum : uint32_t {
|
||||||
isInt8 (TYPE_ID) ? 1 :
|
kTypeSize =
|
||||||
isUInt8 (TYPE_ID) ? 1 :
|
isInt8 (TypeId(Index)) ? 1 :
|
||||||
isInt16 (TYPE_ID) ? 2 :
|
isUInt8 (TypeId(Index)) ? 1 :
|
||||||
isUInt16 (TYPE_ID) ? 2 :
|
isInt16 (TypeId(Index)) ? 2 :
|
||||||
isInt32 (TYPE_ID) ? 4 :
|
isUInt16 (TypeId(Index)) ? 2 :
|
||||||
isUInt32 (TYPE_ID) ? 4 :
|
isInt32 (TypeId(Index)) ? 4 :
|
||||||
isInt64 (TYPE_ID) ? 8 :
|
isUInt32 (TypeId(Index)) ? 4 :
|
||||||
isUInt64 (TYPE_ID) ? 8 :
|
isInt64 (TypeId(Index)) ? 8 :
|
||||||
isFloat32(TYPE_ID) ? 4 :
|
isUInt64 (TypeId(Index)) ? 8 :
|
||||||
isFloat64(TYPE_ID) ? 8 :
|
isFloat32(TypeId(Index)) ? 4 :
|
||||||
isFloat80(TYPE_ID) ? 10 :
|
isFloat64(TypeId(Index)) ? 8 :
|
||||||
isMask8 (TYPE_ID) ? 1 :
|
isFloat80(TypeId(Index)) ? 10 :
|
||||||
isMask16 (TYPE_ID) ? 2 :
|
isMask8 (TypeId(Index)) ? 1 :
|
||||||
isMask32 (TYPE_ID) ? 4 :
|
isMask16 (TypeId(Index)) ? 2 :
|
||||||
isMask64 (TYPE_ID) ? 8 :
|
isMask32 (TypeId(Index)) ? 4 :
|
||||||
isMmx32 (TYPE_ID) ? 4 :
|
isMask64 (TypeId(Index)) ? 8 :
|
||||||
isMmx64 (TYPE_ID) ? 8 :
|
isMmx32 (TypeId(Index)) ? 4 :
|
||||||
isVec32 (TYPE_ID) ? 4 :
|
isMmx64 (TypeId(Index)) ? 8 :
|
||||||
isVec64 (TYPE_ID) ? 8 :
|
isVec32 (TypeId(Index)) ? 4 :
|
||||||
isVec128 (TYPE_ID) ? 16 :
|
isVec64 (TypeId(Index)) ? 8 :
|
||||||
isVec256 (TYPE_ID) ? 32 :
|
isVec128 (TypeId(Index)) ? 16 :
|
||||||
isVec512 (TYPE_ID) ? 64 : 0;
|
isVec256 (TypeId(Index)) ? 32 :
|
||||||
|
isVec512 (TypeId(Index)) ? 64 : 0
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const TypeData _typeData = {
|
const TypeData _typeData = {
|
||||||
#define VALUE(x) BaseOfTypeId<x>::kTypeId
|
#define VALUE(x) TypeId(ScalarOfTypeId<x>::kTypeId)
|
||||||
{ ASMJIT_LOOKUP_TABLE_256(VALUE, 0) },
|
{ ASMJIT_LOOKUP_TABLE_256(VALUE, 0) },
|
||||||
#undef VALUE
|
#undef VALUE
|
||||||
|
|
||||||
@@ -87,6 +69,6 @@ const TypeData _typeData = {
|
|||||||
#undef VALUE
|
#undef VALUE
|
||||||
};
|
};
|
||||||
|
|
||||||
} // {Type}
|
} // {TypeUtils}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|||||||
@@ -1,210 +1,237 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_TYPE_H_INCLUDED
|
#ifndef ASMJIT_CORE_TYPE_H_INCLUDED
|
||||||
#define ASMJIT_CORE_TYPE_H_INCLUDED
|
#define ASMJIT_CORE_TYPE_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
|
#include "../core/support.h"
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
//! \addtogroup asmjit_core
|
//! \addtogroup asmjit_core
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! Type identifier provides a minimalist type system used across AsmJit library.
|
||||||
// [asmjit::Type]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Provides a minimalist type-system that is used by Asmjit library.
|
|
||||||
namespace Type {
|
|
||||||
|
|
||||||
//! TypeId.
|
|
||||||
//!
|
//!
|
||||||
//! This is an additional information that can be used to describe a value-type
|
//! This is an additional information that can be used to describe a value-type of physical or virtual register. It's
|
||||||
//! of physical or virtual register. it's used mostly by BaseCompiler to describe
|
//! used mostly by BaseCompiler to describe register representation (the group of data stored in the register and the
|
||||||
//! register representation (the group of data stored in the register and the
|
//! width used) and it's also used by APIs that allow to describe and work with function signatures.
|
||||||
//! width used) and it's also used by APIs that allow to describe and work with
|
enum class TypeId : uint8_t {
|
||||||
//! function signatures.
|
//! Void type.
|
||||||
enum Id : uint32_t {
|
kVoid = 0,
|
||||||
kIdVoid = 0, //!< Void type.
|
|
||||||
|
|
||||||
_kIdBaseStart = 32,
|
_kBaseStart = 32,
|
||||||
_kIdBaseEnd = 44,
|
_kBaseEnd = 44,
|
||||||
|
|
||||||
_kIdIntStart = 32,
|
_kIntStart = 32,
|
||||||
_kIdIntEnd = 41,
|
_kIntEnd = 41,
|
||||||
|
|
||||||
kIdIntPtr = 32, //!< Abstract signed integer type that has a native size.
|
//! Abstract signed integer type that has a native size.
|
||||||
kIdUIntPtr = 33, //!< Abstract unsigned integer type that has a native size.
|
kIntPtr = 32,
|
||||||
|
//! Abstract unsigned integer type that has a native size.
|
||||||
|
kUIntPtr = 33,
|
||||||
|
|
||||||
kIdI8 = 34, //!< 8-bit signed integer type.
|
//! 8-bit signed integer type.
|
||||||
kIdU8 = 35, //!< 8-bit unsigned integer type.
|
kInt8 = 34,
|
||||||
kIdI16 = 36, //!< 16-bit signed integer type.
|
//! 8-bit unsigned integer type.
|
||||||
kIdU16 = 37, //!< 16-bit unsigned integer type.
|
kUInt8 = 35,
|
||||||
kIdI32 = 38, //!< 32-bit signed integer type.
|
//! 16-bit signed integer type.
|
||||||
kIdU32 = 39, //!< 32-bit unsigned integer type.
|
kInt16 = 36,
|
||||||
kIdI64 = 40, //!< 64-bit signed integer type.
|
//! 16-bit unsigned integer type.
|
||||||
kIdU64 = 41, //!< 64-bit unsigned integer type.
|
kUInt16 = 37,
|
||||||
|
//! 32-bit signed integer type.
|
||||||
|
kInt32 = 38,
|
||||||
|
//! 32-bit unsigned integer type.
|
||||||
|
kUInt32 = 39,
|
||||||
|
//! 64-bit signed integer type.
|
||||||
|
kInt64 = 40,
|
||||||
|
//! 64-bit unsigned integer type.
|
||||||
|
kUInt64 = 41,
|
||||||
|
|
||||||
_kIdFloatStart = 42,
|
_kFloatStart = 42,
|
||||||
_kIdFloatEnd = 44,
|
_kFloatEnd = 44,
|
||||||
|
|
||||||
kIdF32 = 42, //!< 32-bit floating point type.
|
//! 32-bit floating point type.
|
||||||
kIdF64 = 43, //!< 64-bit floating point type.
|
kFloat32 = 42,
|
||||||
kIdF80 = 44, //!< 80-bit floating point type.
|
//! 64-bit floating point type.
|
||||||
|
kFloat64 = 43,
|
||||||
|
//! 80-bit floating point type.
|
||||||
|
kFloat80 = 44,
|
||||||
|
|
||||||
_kIdMaskStart = 45,
|
_kMaskStart = 45,
|
||||||
_kIdMaskEnd = 48,
|
_kMaskEnd = 48,
|
||||||
|
|
||||||
kIdMask8 = 45, //!< 8-bit opmask register (K).
|
//! 8-bit opmask register (K).
|
||||||
kIdMask16 = 46, //!< 16-bit opmask register (K).
|
kMask8 = 45,
|
||||||
kIdMask32 = 47, //!< 32-bit opmask register (K).
|
//! 16-bit opmask register (K).
|
||||||
kIdMask64 = 48, //!< 64-bit opmask register (K).
|
kMask16 = 46,
|
||||||
|
//! 32-bit opmask register (K).
|
||||||
|
kMask32 = 47,
|
||||||
|
//! 64-bit opmask register (K).
|
||||||
|
kMask64 = 48,
|
||||||
|
|
||||||
_kIdMmxStart = 49,
|
_kMmxStart = 49,
|
||||||
_kIdMmxEnd = 50,
|
_kMmxEnd = 50,
|
||||||
|
|
||||||
kIdMmx32 = 49, //!< 64-bit MMX register only used for 32 bits.
|
//! 64-bit MMX register only used for 32 bits.
|
||||||
kIdMmx64 = 50, //!< 64-bit MMX register.
|
kMmx32 = 49,
|
||||||
|
//! 64-bit MMX register.
|
||||||
|
kMmx64 = 50,
|
||||||
|
|
||||||
_kIdVec32Start = 51,
|
_kVec32Start = 51,
|
||||||
_kIdVec32End = 60,
|
_kVec32End = 60,
|
||||||
|
|
||||||
kIdI8x4 = 51,
|
kInt8x4 = 51,
|
||||||
kIdU8x4 = 52,
|
kUInt8x4 = 52,
|
||||||
kIdI16x2 = 53,
|
kInt16x2 = 53,
|
||||||
kIdU16x2 = 54,
|
kUInt16x2 = 54,
|
||||||
kIdI32x1 = 55,
|
kInt32x1 = 55,
|
||||||
kIdU32x1 = 56,
|
kUInt32x1 = 56,
|
||||||
kIdF32x1 = 59,
|
kFloat32x1 = 59,
|
||||||
|
|
||||||
_kIdVec64Start = 61,
|
_kVec64Start = 61,
|
||||||
_kIdVec64End = 70,
|
_kVec64End = 70,
|
||||||
|
|
||||||
kIdI8x8 = 61,
|
kInt8x8 = 61,
|
||||||
kIdU8x8 = 62,
|
kUInt8x8 = 62,
|
||||||
kIdI16x4 = 63,
|
kInt16x4 = 63,
|
||||||
kIdU16x4 = 64,
|
kUInt16x4 = 64,
|
||||||
kIdI32x2 = 65,
|
kInt32x2 = 65,
|
||||||
kIdU32x2 = 66,
|
kUInt32x2 = 66,
|
||||||
kIdI64x1 = 67,
|
kInt64x1 = 67,
|
||||||
kIdU64x1 = 68,
|
kUInt64x1 = 68,
|
||||||
kIdF32x2 = 69,
|
kFloat32x2 = 69,
|
||||||
kIdF64x1 = 70,
|
kFloat64x1 = 70,
|
||||||
|
|
||||||
_kIdVec128Start = 71,
|
_kVec128Start = 71,
|
||||||
_kIdVec128End = 80,
|
_kVec128End = 80,
|
||||||
|
|
||||||
kIdI8x16 = 71,
|
kInt8x16 = 71,
|
||||||
kIdU8x16 = 72,
|
kUInt8x16 = 72,
|
||||||
kIdI16x8 = 73,
|
kInt16x8 = 73,
|
||||||
kIdU16x8 = 74,
|
kUInt16x8 = 74,
|
||||||
kIdI32x4 = 75,
|
kInt32x4 = 75,
|
||||||
kIdU32x4 = 76,
|
kUInt32x4 = 76,
|
||||||
kIdI64x2 = 77,
|
kInt64x2 = 77,
|
||||||
kIdU64x2 = 78,
|
kUInt64x2 = 78,
|
||||||
kIdF32x4 = 79,
|
kFloat32x4 = 79,
|
||||||
kIdF64x2 = 80,
|
kFloat64x2 = 80,
|
||||||
|
|
||||||
_kIdVec256Start = 81,
|
_kVec256Start = 81,
|
||||||
_kIdVec256End = 90,
|
_kVec256End = 90,
|
||||||
|
|
||||||
kIdI8x32 = 81,
|
kInt8x32 = 81,
|
||||||
kIdU8x32 = 82,
|
kUInt8x32 = 82,
|
||||||
kIdI16x16 = 83,
|
kInt16x16 = 83,
|
||||||
kIdU16x16 = 84,
|
kUInt16x16 = 84,
|
||||||
kIdI32x8 = 85,
|
kInt32x8 = 85,
|
||||||
kIdU32x8 = 86,
|
kUInt32x8 = 86,
|
||||||
kIdI64x4 = 87,
|
kInt64x4 = 87,
|
||||||
kIdU64x4 = 88,
|
kUInt64x4 = 88,
|
||||||
kIdF32x8 = 89,
|
kFloat32x8 = 89,
|
||||||
kIdF64x4 = 90,
|
kFloat64x4 = 90,
|
||||||
|
|
||||||
_kIdVec512Start = 91,
|
_kVec512Start = 91,
|
||||||
_kIdVec512End = 100,
|
_kVec512End = 100,
|
||||||
|
|
||||||
kIdI8x64 = 91,
|
kInt8x64 = 91,
|
||||||
kIdU8x64 = 92,
|
kUInt8x64 = 92,
|
||||||
kIdI16x32 = 93,
|
kInt16x32 = 93,
|
||||||
kIdU16x32 = 94,
|
kUInt16x32 = 94,
|
||||||
kIdI32x16 = 95,
|
kInt32x16 = 95,
|
||||||
kIdU32x16 = 96,
|
kUInt32x16 = 96,
|
||||||
kIdI64x8 = 97,
|
kInt64x8 = 97,
|
||||||
kIdU64x8 = 98,
|
kUInt64x8 = 98,
|
||||||
kIdF32x16 = 99,
|
kFloat32x16 = 99,
|
||||||
kIdF64x8 = 100,
|
kFloat64x8 = 100,
|
||||||
|
|
||||||
kIdCount = 101,
|
kLastAssigned = kFloat64x8,
|
||||||
kIdMax = 255
|
|
||||||
|
kMaxValue = 255
|
||||||
};
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_COMPARE(TypeId)
|
||||||
|
|
||||||
|
//! Type identifier utilities.
|
||||||
|
namespace TypeUtils {
|
||||||
|
|
||||||
struct TypeData {
|
struct TypeData {
|
||||||
uint8_t baseOf[kIdMax + 1];
|
TypeId scalarOf[uint32_t(TypeId::kMaxValue) + 1];
|
||||||
uint8_t sizeOf[kIdMax + 1];
|
uint8_t sizeOf[uint32_t(TypeId::kMaxValue) + 1];
|
||||||
};
|
};
|
||||||
ASMJIT_VARAPI const TypeData _typeData;
|
ASMJIT_VARAPI const TypeData _typeData;
|
||||||
|
|
||||||
static constexpr bool isVoid(uint32_t typeId) noexcept { return typeId == 0; }
|
//! Returns the scalar type of `typeId`.
|
||||||
static constexpr bool isValid(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdVec512End; }
|
static inline TypeId scalarOf(TypeId typeId) noexcept { return _typeData.scalarOf[uint32_t(typeId)]; }
|
||||||
static constexpr bool isBase(uint32_t typeId) noexcept { return typeId >= _kIdBaseStart && typeId <= _kIdBaseEnd; }
|
|
||||||
static constexpr bool isAbstract(uint32_t typeId) noexcept { return typeId >= kIdIntPtr && typeId <= kIdUIntPtr; }
|
|
||||||
|
|
||||||
static constexpr bool isInt(uint32_t typeId) noexcept { return typeId >= _kIdIntStart && typeId <= _kIdIntEnd; }
|
//! Returns the size [in bytes] of `typeId`.
|
||||||
static constexpr bool isInt8(uint32_t typeId) noexcept { return typeId == kIdI8; }
|
static inline uint32_t sizeOf(TypeId typeId) noexcept { return _typeData.sizeOf[uint32_t(typeId)]; }
|
||||||
static constexpr bool isUInt8(uint32_t typeId) noexcept { return typeId == kIdU8; }
|
|
||||||
static constexpr bool isInt16(uint32_t typeId) noexcept { return typeId == kIdI16; }
|
|
||||||
static constexpr bool isUInt16(uint32_t typeId) noexcept { return typeId == kIdU16; }
|
|
||||||
static constexpr bool isInt32(uint32_t typeId) noexcept { return typeId == kIdI32; }
|
|
||||||
static constexpr bool isUInt32(uint32_t typeId) noexcept { return typeId == kIdU32; }
|
|
||||||
static constexpr bool isInt64(uint32_t typeId) noexcept { return typeId == kIdI64; }
|
|
||||||
static constexpr bool isUInt64(uint32_t typeId) noexcept { return typeId == kIdU64; }
|
|
||||||
|
|
||||||
static constexpr bool isGp8(uint32_t typeId) noexcept { return typeId >= kIdI8 && typeId <= kIdU8; }
|
//! Tests whether a given type `typeId` is between `a` and `b`.
|
||||||
static constexpr bool isGp16(uint32_t typeId) noexcept { return typeId >= kIdI16 && typeId <= kIdU16; }
|
static inline constexpr bool isBetween(TypeId typeId, TypeId a, TypeId b) noexcept {
|
||||||
static constexpr bool isGp32(uint32_t typeId) noexcept { return typeId >= kIdI32 && typeId <= kIdU32; }
|
return Support::isBetween(uint32_t(typeId), uint32_t(a), uint32_t(b));
|
||||||
static constexpr bool isGp64(uint32_t typeId) noexcept { return typeId >= kIdI64 && typeId <= kIdU64; }
|
}
|
||||||
|
|
||||||
static constexpr bool isFloat(uint32_t typeId) noexcept { return typeId >= _kIdFloatStart && typeId <= _kIdFloatEnd; }
|
//! Tests whether a given type `typeId` is \ref TypeId::kVoid.
|
||||||
static constexpr bool isFloat32(uint32_t typeId) noexcept { return typeId == kIdF32; }
|
static inline constexpr bool isVoid(TypeId typeId) noexcept { return typeId == TypeId::kVoid; }
|
||||||
static constexpr bool isFloat64(uint32_t typeId) noexcept { return typeId == kIdF64; }
|
//! Tests whether a given type `typeId` is a valid non-void type.
|
||||||
static constexpr bool isFloat80(uint32_t typeId) noexcept { return typeId == kIdF80; }
|
static inline constexpr bool isValid(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kIntStart, TypeId::_kVec512End); }
|
||||||
|
//! Tests whether a given type `typeId` is scalar (has no vector part).
|
||||||
|
static inline constexpr bool isScalar(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kBaseStart, TypeId::_kBaseEnd); }
|
||||||
|
//! Tests whether a given type `typeId` is abstract, which means that its size depends on register size.
|
||||||
|
static inline constexpr bool isAbstract(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kIntPtr, TypeId::kUIntPtr); }
|
||||||
|
|
||||||
static constexpr bool isMask(uint32_t typeId) noexcept { return typeId >= _kIdMaskStart && typeId <= _kIdMaskEnd; }
|
//! Tests whether a given type is a scalar integer (signed or unsigned) of any size.
|
||||||
static constexpr bool isMask8(uint32_t typeId) noexcept { return typeId == kIdMask8; }
|
static inline constexpr bool isInt(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kIntStart, TypeId::_kIntEnd); }
|
||||||
static constexpr bool isMask16(uint32_t typeId) noexcept { return typeId == kIdMask16; }
|
//! Tests whether a given type is a scalar 8-bit integer (signed).
|
||||||
static constexpr bool isMask32(uint32_t typeId) noexcept { return typeId == kIdMask32; }
|
static inline constexpr bool isInt8(TypeId typeId) noexcept { return typeId == TypeId::kInt8; }
|
||||||
static constexpr bool isMask64(uint32_t typeId) noexcept { return typeId == kIdMask64; }
|
//! Tests whether a given type is a scalar 8-bit integer (unsigned).
|
||||||
|
static inline constexpr bool isUInt8(TypeId typeId) noexcept { return typeId == TypeId::kUInt8; }
|
||||||
|
//! Tests whether a given type is a scalar 16-bit integer (signed).
|
||||||
|
static inline constexpr bool isInt16(TypeId typeId) noexcept { return typeId == TypeId::kInt16; }
|
||||||
|
//! Tests whether a given type is a scalar 16-bit integer (unsigned).
|
||||||
|
static inline constexpr bool isUInt16(TypeId typeId) noexcept { return typeId == TypeId::kUInt16; }
|
||||||
|
//! Tests whether a given type is a scalar 32-bit integer (signed).
|
||||||
|
static inline constexpr bool isInt32(TypeId typeId) noexcept { return typeId == TypeId::kInt32; }
|
||||||
|
//! Tests whether a given type is a scalar 32-bit integer (unsigned).
|
||||||
|
static inline constexpr bool isUInt32(TypeId typeId) noexcept { return typeId == TypeId::kUInt32; }
|
||||||
|
//! Tests whether a given type is a scalar 64-bit integer (signed).
|
||||||
|
static inline constexpr bool isInt64(TypeId typeId) noexcept { return typeId == TypeId::kInt64; }
|
||||||
|
//! Tests whether a given type is a scalar 64-bit integer (unsigned).
|
||||||
|
static inline constexpr bool isUInt64(TypeId typeId) noexcept { return typeId == TypeId::kUInt64; }
|
||||||
|
|
||||||
static constexpr bool isMmx(uint32_t typeId) noexcept { return typeId >= _kIdMmxStart && typeId <= _kIdMmxEnd; }
|
static inline constexpr bool isGp8(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt8, TypeId::kUInt8); }
|
||||||
static constexpr bool isMmx32(uint32_t typeId) noexcept { return typeId == kIdMmx32; }
|
static inline constexpr bool isGp16(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt16, TypeId::kUInt16); }
|
||||||
static constexpr bool isMmx64(uint32_t typeId) noexcept { return typeId == kIdMmx64; }
|
static inline constexpr bool isGp32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt32, TypeId::kUInt32); }
|
||||||
|
static inline constexpr bool isGp64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::kInt64, TypeId::kUInt64); }
|
||||||
|
|
||||||
static constexpr bool isVec(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec512End; }
|
//! Tests whether a given type is a scalar floating point of any size.
|
||||||
static constexpr bool isVec32(uint32_t typeId) noexcept { return typeId >= _kIdVec32Start && typeId <= _kIdVec32End; }
|
static inline constexpr bool isFloat(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kFloatStart, TypeId::_kFloatEnd); }
|
||||||
static constexpr bool isVec64(uint32_t typeId) noexcept { return typeId >= _kIdVec64Start && typeId <= _kIdVec64End; }
|
//! Tests whether a given type is a scalar 32-bit float.
|
||||||
static constexpr bool isVec128(uint32_t typeId) noexcept { return typeId >= _kIdVec128Start && typeId <= _kIdVec128End; }
|
static inline constexpr bool isFloat32(TypeId typeId) noexcept { return typeId == TypeId::kFloat32; }
|
||||||
static constexpr bool isVec256(uint32_t typeId) noexcept { return typeId >= _kIdVec256Start && typeId <= _kIdVec256End; }
|
//! Tests whether a given type is a scalar 64-bit float.
|
||||||
static constexpr bool isVec512(uint32_t typeId) noexcept { return typeId >= _kIdVec512Start && typeId <= _kIdVec512End; }
|
static inline constexpr bool isFloat64(TypeId typeId) noexcept { return typeId == TypeId::kFloat64; }
|
||||||
|
//! Tests whether a given type is a scalar 80-bit float.
|
||||||
|
static inline constexpr bool isFloat80(TypeId typeId) noexcept { return typeId == TypeId::kFloat80; }
|
||||||
|
|
||||||
|
static inline constexpr bool isMask(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMaskStart, TypeId::_kMaskEnd); }
|
||||||
|
static inline constexpr bool isMask8(TypeId typeId) noexcept { return typeId == TypeId::kMask8; }
|
||||||
|
static inline constexpr bool isMask16(TypeId typeId) noexcept { return typeId == TypeId::kMask16; }
|
||||||
|
static inline constexpr bool isMask32(TypeId typeId) noexcept { return typeId == TypeId::kMask32; }
|
||||||
|
static inline constexpr bool isMask64(TypeId typeId) noexcept { return typeId == TypeId::kMask64; }
|
||||||
|
|
||||||
|
static inline constexpr bool isMmx(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kMmxStart, TypeId::_kMmxEnd); }
|
||||||
|
static inline constexpr bool isMmx32(TypeId typeId) noexcept { return typeId == TypeId::kMmx32; }
|
||||||
|
static inline constexpr bool isMmx64(TypeId typeId) noexcept { return typeId == TypeId::kMmx64; }
|
||||||
|
|
||||||
|
static inline constexpr bool isVec(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec512End); }
|
||||||
|
static inline constexpr bool isVec32(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec32Start, TypeId::_kVec32End); }
|
||||||
|
static inline constexpr bool isVec64(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec64Start, TypeId::_kVec64End); }
|
||||||
|
static inline constexpr bool isVec128(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec128Start, TypeId::_kVec128End); }
|
||||||
|
static inline constexpr bool isVec256(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec256Start, TypeId::_kVec256End); }
|
||||||
|
static inline constexpr bool isVec512(TypeId typeId) noexcept { return isBetween(typeId, TypeId::_kVec512Start, TypeId::_kVec512End); }
|
||||||
|
|
||||||
//! \cond
|
//! \cond
|
||||||
enum TypeCategory : uint32_t {
|
enum TypeCategory : uint32_t {
|
||||||
@@ -215,157 +242,174 @@ enum TypeCategory : uint32_t {
|
|||||||
kTypeCategoryFunction = 4
|
kTypeCategoryFunction = 4
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T, uint32_t Category>
|
template<typename T, TypeCategory kCategory>
|
||||||
struct IdOfT_ByCategory {}; // Fails if not specialized.
|
struct TypeIdOfT_ByCategory {}; // Fails if not specialized.
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT_ByCategory<T, kTypeCategoryIntegral> {
|
struct TypeIdOfT_ByCategory<T, kTypeCategoryIntegral> {
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
kTypeId = (sizeof(T) == 1 && std::is_signed<T>::value) ? kIdI8 :
|
kTypeId = uint32_t(
|
||||||
(sizeof(T) == 1 && !std::is_signed<T>::value) ? kIdU8 :
|
(sizeof(T) == 1 && std::is_signed<T>::value) ? TypeId::kInt8 :
|
||||||
(sizeof(T) == 2 && std::is_signed<T>::value) ? kIdI16 :
|
(sizeof(T) == 1 && !std::is_signed<T>::value) ? TypeId::kUInt8 :
|
||||||
(sizeof(T) == 2 && !std::is_signed<T>::value) ? kIdU16 :
|
(sizeof(T) == 2 && std::is_signed<T>::value) ? TypeId::kInt16 :
|
||||||
(sizeof(T) == 4 && std::is_signed<T>::value) ? kIdI32 :
|
(sizeof(T) == 2 && !std::is_signed<T>::value) ? TypeId::kUInt16 :
|
||||||
(sizeof(T) == 4 && !std::is_signed<T>::value) ? kIdU32 :
|
(sizeof(T) == 4 && std::is_signed<T>::value) ? TypeId::kInt32 :
|
||||||
(sizeof(T) == 8 && std::is_signed<T>::value) ? kIdI64 :
|
(sizeof(T) == 4 && !std::is_signed<T>::value) ? TypeId::kUInt32 :
|
||||||
(sizeof(T) == 8 && !std::is_signed<T>::value) ? kIdU64 : kIdVoid
|
(sizeof(T) == 8 && std::is_signed<T>::value) ? TypeId::kInt64 :
|
||||||
|
(sizeof(T) == 8 && !std::is_signed<T>::value) ? TypeId::kUInt64 : TypeId::kVoid)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT_ByCategory<T, kTypeCategoryFloatingPoint> {
|
struct TypeIdOfT_ByCategory<T, kTypeCategoryFloatingPoint> {
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
kTypeId = (sizeof(T) == 4 ) ? kIdF32 :
|
kTypeId = uint32_t(
|
||||||
(sizeof(T) == 8 ) ? kIdF64 :
|
(sizeof(T) == 4 ) ? TypeId::kFloat32 :
|
||||||
(sizeof(T) >= 10) ? kIdF80 : kIdVoid
|
(sizeof(T) == 8 ) ? TypeId::kFloat64 :
|
||||||
|
(sizeof(T) >= 10) ? TypeId::kFloat80 : TypeId::kVoid)
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT_ByCategory<T, kTypeCategoryEnum>
|
struct TypeIdOfT_ByCategory<T, kTypeCategoryEnum>
|
||||||
: public IdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {};
|
: public TypeIdOfT_ByCategory<typename std::underlying_type<T>::type, kTypeCategoryIntegral> {};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT_ByCategory<T, kTypeCategoryFunction> {
|
struct TypeIdOfT_ByCategory<T, kTypeCategoryFunction> {
|
||||||
enum: uint32_t { kTypeId = kIdUIntPtr };
|
enum : uint32_t {
|
||||||
|
kTypeId = uint32_t(TypeId::kUIntPtr)
|
||||||
|
};
|
||||||
};
|
};
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
//! IdOfT<> template allows to get a TypeId from a C++ type `T`.
|
//! TypeIdOfT<> template allows to get a TypeId from a C++ type `T`.
|
||||||
template<typename T>
|
|
||||||
struct IdOfT
|
|
||||||
#ifdef _DOXYGEN
|
#ifdef _DOXYGEN
|
||||||
|
template<typename T>
|
||||||
|
struct TypeIdOfT {
|
||||||
//! TypeId of C++ type `T`.
|
//! TypeId of C++ type `T`.
|
||||||
static constexpr uint32_t kTypeId = _TypeIdDeducedAtCompileTime_;
|
static constexpr TypeId kTypeId = _TypeIdDeducedAtCompileTime_;
|
||||||
|
};
|
||||||
#else
|
#else
|
||||||
: public IdOfT_ByCategory<T,
|
template<typename T>
|
||||||
|
struct TypeIdOfT
|
||||||
|
: public TypeIdOfT_ByCategory<T,
|
||||||
std::is_enum<T>::value ? kTypeCategoryEnum :
|
std::is_enum<T>::value ? kTypeCategoryEnum :
|
||||||
std::is_integral<T>::value ? kTypeCategoryIntegral :
|
std::is_integral<T>::value ? kTypeCategoryIntegral :
|
||||||
std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint :
|
std::is_floating_point<T>::value ? kTypeCategoryFloatingPoint :
|
||||||
std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown>
|
std::is_function<T>::value ? kTypeCategoryFunction : kTypeCategoryUnknown> {};
|
||||||
#endif
|
#endif
|
||||||
{};
|
|
||||||
|
|
||||||
//! \cond
|
//! \cond
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT<T*> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
|
struct TypeIdOfT<T*> {
|
||||||
|
enum : uint32_t {
|
||||||
|
kTypeId = uint32_t(TypeId::kUIntPtr)
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct IdOfT<T&> { enum : uint32_t { kTypeId = kIdUIntPtr }; };
|
struct TypeIdOfT<T&> {
|
||||||
|
enum : uint32_t {
|
||||||
|
kTypeId = uint32_t(TypeId::kUIntPtr)
|
||||||
|
};
|
||||||
|
};
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
static inline uint32_t baseOf(uint32_t typeId) noexcept {
|
//! Returns a corresponding \ref TypeId of `T` type.
|
||||||
ASMJIT_ASSERT(typeId <= kIdMax);
|
template<typename T>
|
||||||
return _typeData.baseOf[typeId];
|
static inline constexpr TypeId typeIdOfT() noexcept { return TypeId(TypeIdOfT<T>::kTypeId); }
|
||||||
}
|
|
||||||
|
|
||||||
static inline uint32_t sizeOf(uint32_t typeId) noexcept {
|
//! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId into a type that matches `registerSize`
|
||||||
ASMJIT_ASSERT(typeId <= kIdMax);
|
//! (general-purpose register size). If you find such TypeId it's then only about adding the offset to it.
|
||||||
return _typeData.sizeOf[typeId];
|
|
||||||
}
|
|
||||||
|
|
||||||
//! Returns offset needed to convert a `kIntPtr` and `kUIntPtr` TypeId
|
|
||||||
//! into a type that matches `registerSize` (general-purpose register size).
|
|
||||||
//! If you find such TypeId it's then only about adding the offset to it.
|
|
||||||
//!
|
//!
|
||||||
//! For example:
|
//! For example:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! uint32_t registerSize = '4' or '8';
|
//! uint32_t registerSize = /* 4 or 8 */;
|
||||||
//! uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize);
|
//! uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize);
|
||||||
//!
|
//!
|
||||||
//! uint32_t typeId = 'some type-id';
|
//! TypeId typeId = 'some type-id';
|
||||||
//!
|
//!
|
||||||
//! // Normalize some typeId into a non-abstract typeId.
|
//! // Normalize some typeId into a non-abstract typeId.
|
||||||
//! if (Type::isAbstract(typeId)) typeId += deabstractDelta;
|
//! if (TypeUtils::isAbstract(typeId)) typeId += deabstractDelta;
|
||||||
//!
|
//!
|
||||||
//! // The same, but by using Type::deabstract() function.
|
//! // The same, but by using TypeUtils::deabstract() function.
|
||||||
//! typeId = Type::deabstract(typeId, deabstractDelta);
|
//! typeId = TypeUtils::deabstract(typeId, deabstractDelta);
|
||||||
//! ```
|
//! ```
|
||||||
static constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept {
|
static inline constexpr uint32_t deabstractDeltaOfSize(uint32_t registerSize) noexcept {
|
||||||
return registerSize >= 8 ? kIdI64 - kIdIntPtr : kIdI32 - kIdIntPtr;
|
return registerSize >= 8 ? uint32_t(TypeId::kInt64) - uint32_t(TypeId::kIntPtr)
|
||||||
|
: uint32_t(TypeId::kInt32) - uint32_t(TypeId::kIntPtr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static constexpr uint32_t deabstract(uint32_t typeId, uint32_t deabstractDelta) noexcept {
|
//! Deabstracts a given `typeId` into a native type by using `deabstractDelta`, which was previously
|
||||||
return isAbstract(typeId) ? typeId + deabstractDelta : typeId;
|
//! calculated by calling \ref deabstractDeltaOfSize() with a target native register size.
|
||||||
|
static inline constexpr TypeId deabstract(TypeId typeId, uint32_t deabstractDelta) noexcept {
|
||||||
|
return isAbstract(typeId) ? TypeId(uint32_t(typeId) + deabstractDelta) : typeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline constexpr TypeId scalarToVector(TypeId scalarTypeId, TypeId vecStartId) noexcept {
|
||||||
|
return TypeId(uint32_t(vecStartId) + uint32_t(scalarTypeId) - uint32_t(TypeId::kInt8));
|
||||||
|
}
|
||||||
|
|
||||||
|
} // {TypeUtils}
|
||||||
|
|
||||||
|
//! Provides type identifiers that can be used in templates instead of native types.
|
||||||
|
namespace Type {
|
||||||
|
|
||||||
//! bool as C++ type-name.
|
//! bool as C++ type-name.
|
||||||
struct Bool {};
|
struct Bool {};
|
||||||
//! int8_t as C++ type-name.
|
//! int8_t as C++ type-name.
|
||||||
struct I8 {};
|
struct Int8 {};
|
||||||
//! uint8_t as C++ type-name.
|
//! uint8_t as C++ type-name.
|
||||||
struct U8 {};
|
struct UInt8 {};
|
||||||
//! int16_t as C++ type-name.
|
//! int16_t as C++ type-name.
|
||||||
struct I16 {};
|
struct Int16 {};
|
||||||
//! uint16_t as C++ type-name.
|
//! uint16_t as C++ type-name.
|
||||||
struct U16 {};
|
struct UInt16 {};
|
||||||
//! int32_t as C++ type-name.
|
//! int32_t as C++ type-name.
|
||||||
struct I32 {};
|
struct Int32 {};
|
||||||
//! uint32_t as C++ type-name.
|
//! uint32_t as C++ type-name.
|
||||||
struct U32 {};
|
struct UInt32 {};
|
||||||
//! int64_t as C++ type-name.
|
//! int64_t as C++ type-name.
|
||||||
struct I64 {};
|
struct Int64 {};
|
||||||
//! uint64_t as C++ type-name.
|
//! uint64_t as C++ type-name.
|
||||||
struct U64 {};
|
struct UInt64 {};
|
||||||
//! intptr_t as C++ type-name.
|
//! intptr_t as C++ type-name.
|
||||||
struct IPtr {};
|
struct IntPtr {};
|
||||||
//! uintptr_t as C++ type-name.
|
//! uintptr_t as C++ type-name.
|
||||||
struct UPtr {};
|
struct UIntPtr {};
|
||||||
//! float as C++ type-name.
|
//! float as C++ type-name.
|
||||||
struct F32 {};
|
struct Float32 {};
|
||||||
//! double as C++ type-name.
|
//! double as C++ type-name.
|
||||||
struct F64 {};
|
struct Float64 {};
|
||||||
|
|
||||||
} // {Type}
|
} // {Type}
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [ASMJIT_DEFINE_TYPE_ID]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \cond
|
//! \cond
|
||||||
#define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
|
#define ASMJIT_DEFINE_TYPE_ID(T, TYPE_ID) \
|
||||||
namespace Type { \
|
namespace TypeUtils { \
|
||||||
template<> \
|
template<> \
|
||||||
struct IdOfT<T> { \
|
struct TypeIdOfT<T> { \
|
||||||
enum : uint32_t { kTypeId = TYPE_ID }; \
|
enum : uint32_t { \
|
||||||
}; \
|
kTypeId = uint32_t(TYPE_ID) \
|
||||||
|
}; \
|
||||||
|
}; \
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_DEFINE_TYPE_ID(void, kIdVoid);
|
ASMJIT_DEFINE_TYPE_ID(void , TypeId::kVoid);
|
||||||
ASMJIT_DEFINE_TYPE_ID(Bool, kIdU8);
|
ASMJIT_DEFINE_TYPE_ID(Type::Bool , TypeId::kUInt8);
|
||||||
ASMJIT_DEFINE_TYPE_ID(I8 , kIdI8);
|
ASMJIT_DEFINE_TYPE_ID(Type::Int8 , TypeId::kInt8);
|
||||||
ASMJIT_DEFINE_TYPE_ID(U8 , kIdU8);
|
ASMJIT_DEFINE_TYPE_ID(Type::UInt8 , TypeId::kUInt8);
|
||||||
ASMJIT_DEFINE_TYPE_ID(I16 , kIdI16);
|
ASMJIT_DEFINE_TYPE_ID(Type::Int16 , TypeId::kInt16);
|
||||||
ASMJIT_DEFINE_TYPE_ID(U16 , kIdU16);
|
ASMJIT_DEFINE_TYPE_ID(Type::UInt16 , TypeId::kUInt16);
|
||||||
ASMJIT_DEFINE_TYPE_ID(I32 , kIdI32);
|
ASMJIT_DEFINE_TYPE_ID(Type::Int32 , TypeId::kInt32);
|
||||||
ASMJIT_DEFINE_TYPE_ID(U32 , kIdU32);
|
ASMJIT_DEFINE_TYPE_ID(Type::UInt32 , TypeId::kUInt32);
|
||||||
ASMJIT_DEFINE_TYPE_ID(I64 , kIdI64);
|
ASMJIT_DEFINE_TYPE_ID(Type::Int64 , TypeId::kInt64);
|
||||||
ASMJIT_DEFINE_TYPE_ID(U64 , kIdU64);
|
ASMJIT_DEFINE_TYPE_ID(Type::UInt64 , TypeId::kUInt64);
|
||||||
ASMJIT_DEFINE_TYPE_ID(IPtr, kIdIntPtr);
|
ASMJIT_DEFINE_TYPE_ID(Type::IntPtr , TypeId::kIntPtr);
|
||||||
ASMJIT_DEFINE_TYPE_ID(UPtr, kIdUIntPtr);
|
ASMJIT_DEFINE_TYPE_ID(Type::UIntPtr, TypeId::kUIntPtr);
|
||||||
ASMJIT_DEFINE_TYPE_ID(F32 , kIdF32);
|
ASMJIT_DEFINE_TYPE_ID(Type::Float32, TypeId::kFloat32);
|
||||||
ASMJIT_DEFINE_TYPE_ID(F64 , kIdF64);
|
ASMJIT_DEFINE_TYPE_ID(Type::Float64, TypeId::kFloat64);
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#ifndef ASMJIT_NO_JIT
|
#ifndef ASMJIT_NO_JIT
|
||||||
@@ -44,9 +26,11 @@
|
|||||||
|
|
||||||
// Apple recently introduced MAP_JIT flag, which we want to use.
|
// Apple recently introduced MAP_JIT flag, which we want to use.
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
|
#include <pthread.h>
|
||||||
#include <TargetConditionals.h>
|
#include <TargetConditionals.h>
|
||||||
#if TARGET_OS_OSX
|
#if TARGET_OS_OSX
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
|
#include <libkern/OSCacheControl.h> // sys_icache_invalidate().
|
||||||
#endif
|
#endif
|
||||||
// Older SDK doesn't define `MAP_JIT`.
|
// Older SDK doesn't define `MAP_JIT`.
|
||||||
#ifndef MAP_JIT
|
#ifndef MAP_JIT
|
||||||
@@ -54,7 +38,7 @@
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// BSD/OSX: `MAP_ANONYMOUS` is not defined, `MAP_ANON` is.
|
// BSD/MAC: `MAP_ANONYMOUS` is not defined, `MAP_ANON` is.
|
||||||
#if !defined(MAP_ANONYMOUS)
|
#if !defined(MAP_ANONYMOUS)
|
||||||
#define MAP_ANONYMOUS MAP_ANON
|
#define MAP_ANONYMOUS MAP_ANON
|
||||||
#endif
|
#endif
|
||||||
@@ -75,22 +59,25 @@
|
|||||||
#define ASMJIT_VM_SHM_AVAILABLE 1
|
#define ASMJIT_VM_SHM_AVAILABLE 1
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
#if defined(__APPLE__) && ASMJIT_ARCH_ARM >= 64
|
||||||
|
#define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
|
||||||
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
ASMJIT_BEGIN_SUB_NAMESPACE(VirtMem)
|
||||||
// [asmjit::VirtMem - Utilities]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const uint32_t VirtMem_dualMappingFilter[2] = {
|
// Virtual Memory Utilities
|
||||||
VirtMem::kAccessWrite | VirtMem::kMMapMaxAccessWrite,
|
// ========================
|
||||||
VirtMem::kAccessExecute | VirtMem::kMMapMaxAccessExecute
|
|
||||||
|
static const MemoryFlags dualMappingFilter[2] = {
|
||||||
|
MemoryFlags::kAccessWrite | MemoryFlags::kMMapMaxAccessWrite,
|
||||||
|
MemoryFlags::kAccessExecute | MemoryFlags::kMMapMaxAccessExecute
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// Virtual Memory [Windows]
|
||||||
// [asmjit::VirtMem - Virtual Memory [Windows]]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
|
|
||||||
struct ScopedHandle {
|
struct ScopedHandle {
|
||||||
inline ScopedHandle() noexcept
|
inline ScopedHandle() noexcept
|
||||||
: value(nullptr) {}
|
: value(nullptr) {}
|
||||||
@@ -103,7 +90,7 @@ struct ScopedHandle {
|
|||||||
HANDLE value;
|
HANDLE value;
|
||||||
};
|
};
|
||||||
|
|
||||||
static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept {
|
static void getVMInfo(Info& vmInfo) noexcept {
|
||||||
SYSTEM_INFO systemInfo;
|
SYSTEM_INFO systemInfo;
|
||||||
|
|
||||||
::GetSystemInfo(&systemInfo);
|
::GetSystemInfo(&systemInfo);
|
||||||
@@ -111,15 +98,15 @@ static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept {
|
|||||||
vmInfo.pageGranularity = systemInfo.dwAllocationGranularity;
|
vmInfo.pageGranularity = systemInfo.dwAllocationGranularity;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns windows-specific protectFlags from \ref VirtMem::Flags.
|
// Returns windows-specific protectFlags from \ref MemoryFlags.
|
||||||
static DWORD VirtMem_winProtectFlagsFromFlags(uint32_t flags) noexcept {
|
static DWORD protectFlagsFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
||||||
DWORD protectFlags;
|
DWORD protectFlags;
|
||||||
|
|
||||||
// READ|WRITE|EXECUTE.
|
// READ|WRITE|EXECUTE.
|
||||||
if (flags & VirtMem::kAccessExecute)
|
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
|
||||||
protectFlags = (flags & VirtMem::kAccessWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
|
||||||
else if (flags & VirtMem::kAccessRW)
|
else if (Support::test(memoryFlags, MemoryFlags::kAccessRW))
|
||||||
protectFlags = (flags & VirtMem::kAccessWrite) ? PAGE_READWRITE : PAGE_READONLY;
|
protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_READWRITE : PAGE_READONLY;
|
||||||
else
|
else
|
||||||
protectFlags = PAGE_NOACCESS;
|
protectFlags = PAGE_NOACCESS;
|
||||||
|
|
||||||
@@ -127,19 +114,23 @@ static DWORD VirtMem_winProtectFlagsFromFlags(uint32_t flags) noexcept {
|
|||||||
return protectFlags;
|
return protectFlags;
|
||||||
}
|
}
|
||||||
|
|
||||||
static DWORD VirtMem_winDesiredAccessFromFlags(uint32_t flags) noexcept {
|
static DWORD desiredAccessFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
||||||
DWORD access = (flags & VirtMem::kAccessWrite) ? FILE_MAP_WRITE : FILE_MAP_READ;
|
DWORD access = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? FILE_MAP_WRITE : FILE_MAP_READ;
|
||||||
if (flags & VirtMem::kAccessExecute)
|
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
|
||||||
access |= FILE_MAP_EXECUTE;
|
access |= FILE_MAP_EXECUTE;
|
||||||
return access;
|
return access;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::alloc(void** p, size_t size, uint32_t flags) noexcept {
|
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
||||||
|
return HardenedRuntimeFlags::kNone;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
DWORD protectFlags = VirtMem_winProtectFlagsFromFlags(flags);
|
DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
|
||||||
void* result = ::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, protectFlags);
|
void* result = ::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, protectFlags);
|
||||||
|
|
||||||
if (!result)
|
if (!result)
|
||||||
@@ -149,15 +140,15 @@ Error VirtMem::alloc(void** p, size_t size, uint32_t flags) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::release(void* p, size_t size) noexcept {
|
Error release(void* p, size_t size) noexcept {
|
||||||
DebugUtils::unused(size);
|
DebugUtils::unused(size);
|
||||||
if (ASMJIT_UNLIKELY(!::VirtualFree(p, 0, MEM_RELEASE)))
|
if (ASMJIT_UNLIKELY(!::VirtualFree(p, 0, MEM_RELEASE)))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::protect(void* p, size_t size, uint32_t flags) noexcept {
|
Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
DWORD protectFlags = VirtMem_winProtectFlagsFromFlags(flags);
|
DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
|
||||||
DWORD oldFlags;
|
DWORD oldFlags;
|
||||||
|
|
||||||
if (::VirtualProtect(p, size, protectFlags, &oldFlags))
|
if (::VirtualProtect(p, size, protectFlags, &oldFlags))
|
||||||
@@ -166,8 +157,8 @@ Error VirtMem::protect(void* p, size_t size, uint32_t flags) noexcept {
|
|||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) noexcept {
|
Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
dm->ro = nullptr;
|
dm->rx = nullptr;
|
||||||
dm->rw = nullptr;
|
dm->rw = nullptr;
|
||||||
|
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
@@ -187,8 +178,8 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no
|
|||||||
|
|
||||||
void* ptr[2];
|
void* ptr[2];
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
for (uint32_t i = 0; i < 2; i++) {
|
||||||
uint32_t accessFlags = flags & ~VirtMem_dualMappingFilter[i];
|
MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
|
||||||
DWORD desiredAccess = VirtMem_winDesiredAccessFromFlags(accessFlags);
|
DWORD desiredAccess = desiredAccessFromMemoryFlags(accessFlags);
|
||||||
ptr[i] = ::MapViewOfFile(handle.value, desiredAccess, 0, 0, size);
|
ptr[i] = ::MapViewOfFile(handle.value, desiredAccess, 0, 0, size);
|
||||||
|
|
||||||
if (ptr[i] == nullptr) {
|
if (ptr[i] == nullptr) {
|
||||||
@@ -198,37 +189,36 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dm->ro = ptr[0];
|
dm->rx = ptr[0];
|
||||||
dm->rw = ptr[1];
|
dm->rw = ptr[1];
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
||||||
DebugUtils::unused(size);
|
DebugUtils::unused(size);
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
if (!::UnmapViewOfFile(dm->ro))
|
if (!::UnmapViewOfFile(dm->rx))
|
||||||
failed = true;
|
failed = true;
|
||||||
|
|
||||||
if (dm->ro != dm->rw && !UnmapViewOfFile(dm->rw))
|
if (dm->rx != dm->rw && !UnmapViewOfFile(dm->rw))
|
||||||
failed = true;
|
failed = true;
|
||||||
|
|
||||||
if (failed)
|
if (failed)
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
dm->ro = nullptr;
|
dm->rx = nullptr;
|
||||||
dm->rw = nullptr;
|
dm->rw = nullptr;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// Virtual Memory [Posix]
|
||||||
// [asmjit::VirtMem - Virtual Memory [Posix]]
|
// ======================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if !defined(_WIN32)
|
#if !defined(_WIN32)
|
||||||
|
|
||||||
static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept {
|
static void getVMInfo(Info& vmInfo) noexcept {
|
||||||
uint32_t pageSize = uint32_t(::getpagesize());
|
uint32_t pageSize = uint32_t(::getpagesize());
|
||||||
|
|
||||||
vmInfo.pageSize = pageSize;
|
vmInfo.pageSize = pageSize;
|
||||||
@@ -236,14 +226,14 @@ static void VirtMem_getInfo(VirtMem::Info& vmInfo) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if !defined(SHM_ANON)
|
#if !defined(SHM_ANON)
|
||||||
static const char* VirtMem_getTmpDir() noexcept {
|
static const char* getTmpDir() noexcept {
|
||||||
const char* tmpDir = getenv("TMPDIR");
|
const char* tmpDir = getenv("TMPDIR");
|
||||||
return tmpDir ? tmpDir : "/tmp";
|
return tmpDir ? tmpDir : "/tmp";
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`.
|
// Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`.
|
||||||
static Error VirtMem_asmjitErrorFromErrno(int e) noexcept {
|
static Error asmjitErrorFromErrno(int e) noexcept {
|
||||||
switch (e) {
|
switch (e) {
|
||||||
case EACCES:
|
case EACCES:
|
||||||
case EAGAIN:
|
case EAGAIN:
|
||||||
@@ -265,16 +255,14 @@ static Error VirtMem_asmjitErrorFromErrno(int e) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some operating systems don't allow /dev/shm to be executable. On Linux this
|
// Some operating systems don't allow /dev/shm to be executable. On Linux this happens when /dev/shm is mounted with
|
||||||
// happens when /dev/shm is mounted with 'noexec', which is enforced by systemd.
|
// 'noexec', which is enforced by systemd. Other operating systems like MacOS also restrict executable permissions
|
||||||
// Other operating systems like MacOS also restrict executable permissions regarding
|
// regarding /dev/shm, so we use a runtime detection before attempting to allocate executable memory. Sometimes we
|
||||||
// /dev/shm, so we use a runtime detection before attempting to allocate executable
|
// don't need the detection as we know it would always result in `ShmStrategy::kTmpDir`.
|
||||||
// memory. Sometimes we don't need the detection as we know it would always result
|
enum class ShmStrategy : uint32_t {
|
||||||
// in `kShmStrategyTmpDir`.
|
kUnknown = 0,
|
||||||
enum ShmStrategy : uint32_t {
|
kDevShm = 1,
|
||||||
kShmStrategyUnknown = 0,
|
kTmpDir = 2
|
||||||
kShmStrategyDevShm = 1,
|
|
||||||
kShmStrategyTmpDir = 2
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AnonymousMemory {
|
class AnonymousMemory {
|
||||||
@@ -289,17 +277,17 @@ public:
|
|||||||
FileType _fileType;
|
FileType _fileType;
|
||||||
StringTmp<128> _tmpName;
|
StringTmp<128> _tmpName;
|
||||||
|
|
||||||
ASMJIT_INLINE AnonymousMemory() noexcept
|
inline AnonymousMemory() noexcept
|
||||||
: _fd(-1),
|
: _fd(-1),
|
||||||
_fileType(kFileTypeNone),
|
_fileType(kFileTypeNone),
|
||||||
_tmpName() {}
|
_tmpName() {}
|
||||||
|
|
||||||
ASMJIT_INLINE ~AnonymousMemory() noexcept {
|
inline ~AnonymousMemory() noexcept {
|
||||||
unlink();
|
unlink();
|
||||||
close();
|
close();
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE int fd() const noexcept { return _fd; }
|
inline int fd() const noexcept { return _fd; }
|
||||||
|
|
||||||
Error open(bool preferTmpOverDevShm) noexcept {
|
Error open(bool preferTmpOverDevShm) noexcept {
|
||||||
#if defined(__linux__) && defined(__NR_memfd_create)
|
#if defined(__linux__) && defined(__NR_memfd_create)
|
||||||
@@ -319,7 +307,7 @@ public:
|
|||||||
if (e == ENOSYS)
|
if (e == ENOSYS)
|
||||||
memfd_create_not_supported = 1;
|
memfd_create_not_supported = 1;
|
||||||
else
|
else
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(e));
|
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@@ -331,13 +319,12 @@ public:
|
|||||||
if (ASMJIT_LIKELY(_fd >= 0))
|
if (ASMJIT_LIKELY(_fd >= 0))
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
else
|
else
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(errno));
|
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
||||||
#else
|
#else
|
||||||
// POSIX API. We have to generate somehow a unique name. This is nothing
|
// POSIX API. We have to generate somehow a unique name. This is nothing cryptographic, just using a bit from
|
||||||
// cryptographic, just using a bit from the stack address to always have
|
// the stack address to always have a different base for different threads (as threads have their own stack)
|
||||||
// a different base for different threads (as threads have their own stack)
|
// and retries for avoiding collisions. We use `shm_open()` with flags that require creation of the file so we
|
||||||
// and retries for avoiding collisions. We use `shm_open()` with flags that
|
// never open an existing shared memory.
|
||||||
// require creation of the file so we never open an existing shared memory.
|
|
||||||
static std::atomic<uint32_t> internalCounter;
|
static std::atomic<uint32_t> internalCounter;
|
||||||
const char* kShmFormat = "/shm-id-%016llX";
|
const char* kShmFormat = "/shm-id-%016llX";
|
||||||
|
|
||||||
@@ -351,7 +338,7 @@ public:
|
|||||||
bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm;
|
bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm;
|
||||||
|
|
||||||
if (useTmp) {
|
if (useTmp) {
|
||||||
_tmpName.assign(VirtMem_getTmpDir());
|
_tmpName.assign(getTmpDir());
|
||||||
_tmpName.appendFormat(kShmFormat, (unsigned long long)bits);
|
_tmpName.appendFormat(kShmFormat, (unsigned long long)bits);
|
||||||
_fd = ::open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0);
|
_fd = ::open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0);
|
||||||
if (ASMJIT_LIKELY(_fd >= 0)) {
|
if (ASMJIT_LIKELY(_fd >= 0)) {
|
||||||
@@ -372,7 +359,7 @@ public:
|
|||||||
|
|
||||||
int e = errno;
|
int e = errno;
|
||||||
if (e != EEXIST)
|
if (e != EEXIST)
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(e));
|
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
||||||
}
|
}
|
||||||
|
|
||||||
return DebugUtils::errored(kErrorFailedToOpenAnonymousMemory);
|
return DebugUtils::errored(kErrorFailedToOpenAnonymousMemory);
|
||||||
@@ -406,17 +393,30 @@ public:
|
|||||||
Error allocate(size_t size) noexcept {
|
Error allocate(size_t size) noexcept {
|
||||||
// TODO: Improve this by using `posix_fallocate()` when available.
|
// TODO: Improve this by using `posix_fallocate()` when available.
|
||||||
if (ftruncate(_fd, off_t(size)) != 0)
|
if (ftruncate(_fd, off_t(size)) != 0)
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(errno));
|
return DebugUtils::errored(asmjitErrorFromErrno(errno));
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Returns `mmap()` protection flags from \ref MemoryFlags.
|
||||||
|
static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
||||||
|
int protection = 0;
|
||||||
|
if (Support::test(memoryFlags, MemoryFlags::kAccessRead)) protection |= PROT_READ;
|
||||||
|
if (Support::test(memoryFlags, MemoryFlags::kAccessWrite)) protection |= PROT_READ | PROT_WRITE;
|
||||||
|
if (Support::test(memoryFlags, MemoryFlags::kAccessExecute)) protection |= PROT_READ | PROT_EXEC;
|
||||||
|
return protection;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// Detects whether the current process is hardened, which means that pages that
|
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags cannot
|
||||||
// have WRITE and EXECUTABLE flags cannot be allocated without MAP_JIT flag.
|
// be allocated without MAP_JIT flag.
|
||||||
static ASMJIT_INLINE bool VirtMem_isHardened() noexcept {
|
static inline bool hasHardenedRuntimeMacOS() noexcept {
|
||||||
static volatile uint32_t globalHardenedFlag;
|
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
|
// MacOS on AArch64 has always hardened runtime enabled.
|
||||||
|
return true;
|
||||||
|
#else
|
||||||
|
static std::atomic<uint32_t> globalHardenedFlag;
|
||||||
|
|
||||||
enum HardenedFlag : uint32_t {
|
enum HardenedFlag : uint32_t {
|
||||||
kHardenedFlagUnknown = 0,
|
kHardenedFlagUnknown = 0,
|
||||||
@@ -424,37 +424,40 @@ static ASMJIT_INLINE bool VirtMem_isHardened() noexcept {
|
|||||||
kHardenedFlagEnabled = 2
|
kHardenedFlagEnabled = 2
|
||||||
};
|
};
|
||||||
|
|
||||||
uint32_t flag = globalHardenedFlag;
|
uint32_t flag = globalHardenedFlag.load();
|
||||||
if (flag == kHardenedFlagUnknown) {
|
if (flag == kHardenedFlagUnknown) {
|
||||||
VirtMem::Info memInfo;
|
size_t pageSize = ::getpagesize();
|
||||||
VirtMem_getInfo(memInfo);
|
|
||||||
|
|
||||||
void* ptr = mmap(nullptr, memInfo.pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||||
if (ptr == MAP_FAILED) {
|
if (ptr == MAP_FAILED) {
|
||||||
flag = kHardenedFlagEnabled;
|
flag = kHardenedFlagEnabled;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
flag = kHardenedFlagDisabled;
|
flag = kHardenedFlagDisabled;
|
||||||
munmap(ptr, memInfo.pageSize);
|
munmap(ptr, pageSize);
|
||||||
}
|
}
|
||||||
globalHardenedFlag = flag;
|
globalHardenedFlag.store(flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
return flag == kHardenedFlagEnabled;
|
return flag == kHardenedFlagEnabled;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// MAP_JIT flag required to run unsigned JIT code is only supported by kernel
|
static inline bool hasMapJitSupportMacOS() noexcept {
|
||||||
// version 10.14+ (Mojave) and IOS.
|
#if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
|
||||||
static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept {
|
// MacOS for 64-bit AArch architecture always uses hardened runtime. Some documentation can be found here:
|
||||||
#if TARGET_OS_OSX
|
// - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
|
||||||
static volatile int globalVersion;
|
return true;
|
||||||
|
#elif TARGET_OS_OSX
|
||||||
|
// MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave) and IOS.
|
||||||
|
static std::atomic<uint32_t> globalVersion;
|
||||||
|
|
||||||
int ver = globalVersion;
|
int ver = globalVersion.load();
|
||||||
if (!ver) {
|
if (!ver) {
|
||||||
struct utsname osname;
|
struct utsname osname {};
|
||||||
uname(&osname);
|
uname(&osname);
|
||||||
ver = atoi(osname.release);
|
ver = atoi(osname.release);
|
||||||
globalVersion = ver;
|
globalVersion.store(ver);
|
||||||
}
|
}
|
||||||
return ver >= 18;
|
return ver >= 18;
|
||||||
#else
|
#else
|
||||||
@@ -462,53 +465,63 @@ static ASMJIT_INLINE bool VirtMem_hasMapJitSupport() noexcept {
|
|||||||
return true;
|
return true;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif // __APPLE__
|
||||||
|
|
||||||
// Returns `mmap()` protection flags from \ref VirtMem::Flags.
|
// Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags
|
||||||
static int VirtMem_mmProtFromFlags(uint32_t flags) noexcept {
|
// cannot be normally allocated. On MacOS such allocation requires MAP_JIT flag.
|
||||||
int protection = 0;
|
static inline bool hasHardenedRuntime() noexcept {
|
||||||
if (flags & VirtMem::kAccessRead) protection |= PROT_READ;
|
#if defined(__APPLE__)
|
||||||
if (flags & VirtMem::kAccessWrite) protection |= PROT_READ | PROT_WRITE;
|
return hasHardenedRuntimeMacOS();
|
||||||
if (flags & VirtMem::kAccessExecute) protection |= PROT_READ | PROT_EXEC;
|
#else
|
||||||
return protection;
|
return false;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detects whether MAP_JIT is available.
|
||||||
|
static inline bool hasMapJitSupport() noexcept {
|
||||||
|
#if defined(__APPLE__)
|
||||||
|
return hasMapJitSupportMacOS();
|
||||||
|
#else
|
||||||
|
return false;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns either MAP_JIT or 0 based on `flags` and the host operating system.
|
// Returns either MAP_JIT or 0 based on `flags` and the host operating system.
|
||||||
static ASMJIT_INLINE int VirtMem_mmMapJitFromFlags(uint32_t flags) noexcept {
|
static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
||||||
#if defined(__APPLE__)
|
#if defined(__APPLE__)
|
||||||
// Always use MAP_JIT flag if user asked for it (could be used for testing
|
// Always use MAP_JIT flag if user asked for it (could be used for testing on non-hardened processes) and detect
|
||||||
// on non-hardened processes) and detect whether it must be used when the
|
// whether it must be used when the process is actually hardened (in that case it doesn't make sense to rely on
|
||||||
// process is actually hardened (in that case it doesn't make sense to rely
|
// user `memoryFlags`).
|
||||||
// on user `flags`).
|
bool useMapJit = Support::test(memoryFlags, MemoryFlags::kMMapEnableMapJit) || hasHardenedRuntime();
|
||||||
bool useMapJit = (flags & VirtMem::kMMapEnableMapJit) != 0 || VirtMem_isHardened();
|
|
||||||
if (useMapJit)
|
if (useMapJit)
|
||||||
return VirtMem_hasMapJitSupport() ? int(MAP_JIT) : 0;
|
return hasMapJitSupport() ? int(MAP_JIT) : 0;
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
DebugUtils::unused(flags);
|
DebugUtils::unused(memoryFlags);
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns BSD-specific `PROT_MAX()` flags.
|
// Returns BSD-specific `PROT_MAX()` flags.
|
||||||
static ASMJIT_INLINE int VirtMem_mmMaxProtFromFlags(uint32_t flags) noexcept {
|
static inline int mmMaxProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
|
||||||
#if defined(PROT_MAX)
|
#if defined(PROT_MAX)
|
||||||
static constexpr uint32_t kMaxProtShift = Support::constCtz(VirtMem::kMMapMaxAccessRead);
|
static constexpr uint32_t kMaxProtShift = Support::ConstCTZ<uint32_t(MemoryFlags::kMMapMaxAccessRead)>::value;
|
||||||
if (flags & (VirtMem::kMMapMaxAccessReadWrite | VirtMem::kMMapMaxAccessExecute))
|
|
||||||
return PROT_MAX(VirtMem_mmProtFromFlags(flags >> kMaxProtShift));
|
if (Support::test(memoryFlags, MemoryFlags::kMMapMaxAccessReadWrite | MemoryFlags::kMMapMaxAccessExecute))
|
||||||
|
return PROT_MAX(mmProtFromMemoryFlags((MemoryFlags)(uint32_t(memoryFlags) >> kMaxProtShift)));
|
||||||
else
|
else
|
||||||
return 0;
|
return 0;
|
||||||
#else
|
#else
|
||||||
DebugUtils::unused(flags);
|
DebugUtils::unused(memoryFlags);
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if ASMJIT_VM_SHM_DETECT
|
#if ASMJIT_VM_SHM_DETECT
|
||||||
static Error VirtMem_detectShmStrategy(uint32_t* strategyOut) noexcept {
|
static Error detectShmStrategy(ShmStrategy* strategyOut) noexcept {
|
||||||
AnonymousMemory anonMem;
|
AnonymousMemory anonMem;
|
||||||
VirtMem::Info vmInfo = VirtMem::info();
|
Info vmInfo = info();
|
||||||
|
|
||||||
ASMJIT_PROPAGATE(anonMem.open(false));
|
ASMJIT_PROPAGATE(anonMem.open(false));
|
||||||
ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize));
|
ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize));
|
||||||
@@ -517,46 +530,57 @@ static Error VirtMem_detectShmStrategy(uint32_t* strategyOut) noexcept {
|
|||||||
if (ptr == MAP_FAILED) {
|
if (ptr == MAP_FAILED) {
|
||||||
int e = errno;
|
int e = errno;
|
||||||
if (e == EINVAL) {
|
if (e == EINVAL) {
|
||||||
*strategyOut = kShmStrategyTmpDir;
|
*strategyOut = ShmStrategy::kTmpDir;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(e));
|
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
munmap(ptr, vmInfo.pageSize);
|
munmap(ptr, vmInfo.pageSize);
|
||||||
*strategyOut = kShmStrategyDevShm;
|
*strategyOut = ShmStrategy::kDevShm;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static Error VirtMem_getShmStrategy(uint32_t* strategyOut) noexcept {
|
static Error getShmStrategy(ShmStrategy* strategyOut) noexcept {
|
||||||
#if ASMJIT_VM_SHM_DETECT
|
#if ASMJIT_VM_SHM_DETECT
|
||||||
// Initially don't assume anything. It has to be tested whether
|
// Initially don't assume anything. It has to be tested whether '/dev/shm' was mounted with 'noexec' flag or not.
|
||||||
// '/dev/shm' was mounted with 'noexec' flag or not.
|
static std::atomic<uint32_t> globalShmStrategy;
|
||||||
static volatile uint32_t globalShmStrategy = kShmStrategyUnknown;
|
|
||||||
|
|
||||||
uint32_t strategy = globalShmStrategy;
|
ShmStrategy strategy = static_cast<ShmStrategy>(globalShmStrategy.load());
|
||||||
if (strategy == kShmStrategyUnknown) {
|
if (strategy == ShmStrategy::kUnknown) {
|
||||||
ASMJIT_PROPAGATE(VirtMem_detectShmStrategy(&strategy));
|
ASMJIT_PROPAGATE(detectShmStrategy(&strategy));
|
||||||
globalShmStrategy = strategy;
|
globalShmStrategy.store(static_cast<uint32_t>(strategy));
|
||||||
}
|
}
|
||||||
|
|
||||||
*strategyOut = strategy;
|
*strategyOut = strategy;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
#else
|
#else
|
||||||
*strategyOut = kShmStrategyTmpDir;
|
*strategyOut = ShmStrategy::kTmpDir;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::alloc(void** p, size_t size, uint32_t flags) noexcept {
|
static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
|
||||||
|
HardenedRuntimeFlags hrFlags = HardenedRuntimeFlags::kNone;
|
||||||
|
|
||||||
|
if (hasHardenedRuntime())
|
||||||
|
hrFlags |= HardenedRuntimeFlags::kEnabled;
|
||||||
|
|
||||||
|
if (hasMapJitSupport())
|
||||||
|
hrFlags |= HardenedRuntimeFlags::kMapJit;
|
||||||
|
|
||||||
|
return hrFlags;
|
||||||
|
}
|
||||||
|
|
||||||
|
Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
*p = nullptr;
|
*p = nullptr;
|
||||||
if (size == 0)
|
if (size == 0)
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
int protection = VirtMem_mmProtFromFlags(flags) | VirtMem_mmMaxProtFromFlags(flags);
|
int protection = mmProtFromMemoryFlags(memoryFlags) | mmMaxProtFromMemoryFlags(memoryFlags);
|
||||||
int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | VirtMem_mmMapJitFromFlags(flags);
|
int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | mmMapJitFromMemoryFlags(memoryFlags);
|
||||||
|
|
||||||
void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0);
|
void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0);
|
||||||
if (ptr == MAP_FAILED)
|
if (ptr == MAP_FAILED)
|
||||||
@@ -566,7 +590,7 @@ Error VirtMem::alloc(void** p, size_t size, uint32_t flags) noexcept {
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::release(void* p, size_t size) noexcept {
|
Error release(void* p, size_t size) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(munmap(p, size) != 0))
|
if (ASMJIT_UNLIKELY(munmap(p, size) != 0))
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
@@ -574,26 +598,26 @@ Error VirtMem::release(void* p, size_t size) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Error VirtMem::protect(void* p, size_t size, uint32_t flags) noexcept {
|
Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
int protection = VirtMem_mmProtFromFlags(flags);
|
int protection = mmProtFromMemoryFlags(memoryFlags);
|
||||||
if (mprotect(p, size, protection) == 0)
|
if (mprotect(p, size, protection) == 0)
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
|
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) noexcept {
|
Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
|
||||||
dm->ro = nullptr;
|
dm->rx = nullptr;
|
||||||
dm->rw = nullptr;
|
dm->rw = nullptr;
|
||||||
|
|
||||||
if (off_t(size) <= 0)
|
if (off_t(size) <= 0)
|
||||||
return DebugUtils::errored(size == 0 ? kErrorInvalidArgument : kErrorTooLarge);
|
return DebugUtils::errored(size == 0 ? kErrorInvalidArgument : kErrorTooLarge);
|
||||||
|
|
||||||
bool preferTmpOverDevShm = (flags & kMappingPreferTmp) != 0;
|
bool preferTmpOverDevShm = Support::test(memoryFlags, MemoryFlags::kMappingPreferTmp);
|
||||||
if (!preferTmpOverDevShm) {
|
if (!preferTmpOverDevShm) {
|
||||||
uint32_t strategy;
|
ShmStrategy strategy;
|
||||||
ASMJIT_PROPAGATE(VirtMem_getShmStrategy(&strategy));
|
ASMJIT_PROPAGATE(getShmStrategy(&strategy));
|
||||||
preferTmpOverDevShm = (strategy == kShmStrategyTmpDir);
|
preferTmpOverDevShm = (strategy == ShmStrategy::kTmpDir);
|
||||||
}
|
}
|
||||||
|
|
||||||
AnonymousMemory anonMem;
|
AnonymousMemory anonMem;
|
||||||
@@ -602,8 +626,8 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no
|
|||||||
|
|
||||||
void* ptr[2];
|
void* ptr[2];
|
||||||
for (uint32_t i = 0; i < 2; i++) {
|
for (uint32_t i = 0; i < 2; i++) {
|
||||||
uint32_t accessFlags = flags & ~VirtMem_dualMappingFilter[i];
|
MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
|
||||||
int protection = VirtMem_mmProtFromFlags(accessFlags) | VirtMem_mmMaxProtFromFlags(accessFlags);
|
int protection = mmProtFromMemoryFlags(accessFlags) | mmMaxProtFromMemoryFlags(accessFlags);
|
||||||
|
|
||||||
ptr[i] = mmap(nullptr, size, protection, MAP_SHARED, anonMem.fd(), 0);
|
ptr[i] = mmap(nullptr, size, protection, MAP_SHARED, anonMem.fd(), 0);
|
||||||
if (ptr[i] == MAP_FAILED) {
|
if (ptr[i] == MAP_FAILED) {
|
||||||
@@ -611,40 +635,61 @@ Error VirtMem::allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) no
|
|||||||
int e = errno;
|
int e = errno;
|
||||||
if (i == 1)
|
if (i == 1)
|
||||||
munmap(ptr[0], size);
|
munmap(ptr[0], size);
|
||||||
return DebugUtils::errored(VirtMem_asmjitErrorFromErrno(e));
|
return DebugUtils::errored(asmjitErrorFromErrno(e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dm->ro = ptr[0];
|
dm->rx = ptr[0];
|
||||||
dm->rw = ptr[1];
|
dm->rw = ptr[1];
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Error VirtMem::releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
|
||||||
Error err = release(dm->ro, size);
|
Error err = release(dm->rx, size);
|
||||||
if (dm->ro != dm->rw)
|
if (dm->rx != dm->rw)
|
||||||
err |= release(dm->rw, size);
|
err |= release(dm->rw, size);
|
||||||
|
|
||||||
if (err)
|
if (err)
|
||||||
return DebugUtils::errored(kErrorInvalidArgument);
|
return DebugUtils::errored(kErrorInvalidArgument);
|
||||||
|
|
||||||
dm->ro = nullptr;
|
dm->rx = nullptr;
|
||||||
dm->rw = nullptr;
|
dm->rw = nullptr;
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// Virtual Memory - Flush Instruction Cache
|
||||||
// [asmjit::VirtMem - Virtual Memory [Memory Info]]
|
// ========================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
VirtMem::Info VirtMem::info() noexcept {
|
void flushInstructionCache(void* p, size_t size) noexcept {
|
||||||
static VirtMem::Info vmInfo;
|
#if ASMJIT_ARCH_X86
|
||||||
|
// X86/X86_64 architecture doesn't require to do anything to flush instruction cache.
|
||||||
|
DebugUtils::unused(p, size);
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
sys_icache_invalidate(p, size);
|
||||||
|
#elif defined(_WIN32)
|
||||||
|
// Windows has a built-in support in `kernel32.dll`.
|
||||||
|
FlushInstructionCache(GetCurrentProcess(), p, size);
|
||||||
|
#elif defined(__GNUC__)
|
||||||
|
char* start = static_cast<char*>(p);
|
||||||
|
char* end = start + size;
|
||||||
|
__builtin___clear_cache(start, end);
|
||||||
|
#else
|
||||||
|
#pragma message("asmjit::VirtMem::flushInstructionCache() doesn't have implementation for the target OS and compiler")
|
||||||
|
DebugUtils::unused(p, size);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
// Virtual Memory - Memory Info
|
||||||
|
// ============================
|
||||||
|
|
||||||
|
Info info() noexcept {
|
||||||
static std::atomic<uint32_t> vmInfoInitialized;
|
static std::atomic<uint32_t> vmInfoInitialized;
|
||||||
|
static Info vmInfo;
|
||||||
|
|
||||||
if (!vmInfoInitialized.load()) {
|
if (!vmInfoInitialized.load()) {
|
||||||
VirtMem::Info localMemInfo;
|
Info localMemInfo;
|
||||||
VirtMem_getInfo(localMemInfo);
|
getVMInfo(localMemInfo);
|
||||||
|
|
||||||
vmInfo = localMemInfo;
|
vmInfo = localMemInfo;
|
||||||
vmInfoInitialized.store(1u);
|
vmInfoInitialized.store(1u);
|
||||||
@@ -653,6 +698,24 @@ VirtMem::Info VirtMem::info() noexcept {
|
|||||||
return vmInfo;
|
return vmInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
// Virtual Memory - Hardened Runtime Info
|
||||||
|
// ======================================
|
||||||
|
|
||||||
|
HardenedRuntimeInfo hardenedRuntimeInfo() noexcept {
|
||||||
|
return HardenedRuntimeInfo { getHardenedRuntimeFlags() };
|
||||||
|
}
|
||||||
|
|
||||||
|
// Virtual Memory - Project JIT Memory
|
||||||
|
// ===================================
|
||||||
|
|
||||||
|
void protectJitMemory(ProtectJitAccess access) noexcept {
|
||||||
|
#if defined(ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP)
|
||||||
|
pthread_jit_write_protect_np(static_cast<uint32_t>(access));
|
||||||
|
#else
|
||||||
|
DebugUtils::unused(access);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
ASMJIT_END_SUB_NAMESPACE
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_VIRTMEM_H_INCLUDED
|
#ifndef ASMJIT_CORE_VIRTMEM_H_INCLUDED
|
||||||
#define ASMJIT_CORE_VIRTMEM_H_INCLUDED
|
#define ASMJIT_CORE_VIRTMEM_H_INCLUDED
|
||||||
@@ -34,65 +16,14 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_virtual_memory
|
//! \addtogroup asmjit_virtual_memory
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::VirtMem]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Virtual memory management.
|
//! Virtual memory management.
|
||||||
namespace VirtMem {
|
namespace VirtMem {
|
||||||
|
|
||||||
//! Virtual memory access and mmap-specific flags.
|
//! Flushes instruction cache in the given region.
|
||||||
enum Flags : uint32_t {
|
//!
|
||||||
//! No access flags.
|
//! Only useful on non-x86 architectures, however, it's a good practice to call it on any platform to make your
|
||||||
kAccessNone = 0x00000000u,
|
//! code more portable.
|
||||||
//! Memory is readable.
|
ASMJIT_API void flushInstructionCache(void* p, size_t size) noexcept;
|
||||||
kAccessRead = 0x00000001u,
|
|
||||||
//! Memory is writable.
|
|
||||||
kAccessWrite = 0x00000002u,
|
|
||||||
//! Memory is executable.
|
|
||||||
kAccessExecute = 0x00000004u,
|
|
||||||
|
|
||||||
//! A combination of \ref kAccessRead and \ref kAccessWrite.
|
|
||||||
kAccessReadWrite = kAccessRead | kAccessWrite,
|
|
||||||
//! A combination of \ref kAccessRead, \ref kAccessWrite.
|
|
||||||
kAccessRW = kAccessRead | kAccessWrite,
|
|
||||||
//! A combination of \ref kAccessRead and \ref kAccessExecute.
|
|
||||||
kAccessRX = kAccessRead | kAccessExecute,
|
|
||||||
//! A combination of \ref kAccessRead, \ref kAccessWrite, and \ref kAccessExecute.
|
|
||||||
kAccessRWX = kAccessRead | kAccessWrite | kAccessExecute,
|
|
||||||
|
|
||||||
//! Use a `MAP_JIT` flag available on Apple platforms (introduced by Mojave),
|
|
||||||
//! which allows JIT code to be executed in MAC bundles. This flag is not turned
|
|
||||||
//! on by default, because when a process uses `fork()` the child process
|
|
||||||
//! has no access to the pages mapped with `MAP_JIT`, which could break code
|
|
||||||
//! that doesn't expect this behavior.
|
|
||||||
kMMapEnableMapJit = 0x00000010u,
|
|
||||||
|
|
||||||
//! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`.
|
|
||||||
kMMapMaxAccessRead = 0x00000020u,
|
|
||||||
//! Pass `PROT_MAX(PROT_WRITE)` to mmap() on platforms that support `PROT_MAX`.
|
|
||||||
kMMapMaxAccessWrite = 0x00000040u,
|
|
||||||
//! Pass `PROT_MAX(PROT_EXEC)` to mmap() on platforms that support `PROT_MAX`.
|
|
||||||
kMMapMaxAccessExecute = 0x00000080u,
|
|
||||||
|
|
||||||
//! A combination of \ref kMMapMaxAccessRead and \ref kMMapMaxAccessWrite.
|
|
||||||
kMMapMaxAccessReadWrite = kMMapMaxAccessRead | kMMapMaxAccessWrite,
|
|
||||||
//! A combination of \ref kMMapMaxAccessRead and \ref kMMapMaxAccessWrite.
|
|
||||||
kMMapMaxAccessRW = kMMapMaxAccessRead | kMMapMaxAccessWrite,
|
|
||||||
//! A combination of \ref kMMapMaxAccessRead and \ref kMMapMaxAccessExecute.
|
|
||||||
kMMapMaxAccessRX = kMMapMaxAccessRead | kMMapMaxAccessExecute,
|
|
||||||
//! A combination of \ref kMMapMaxAccessRead, \ref kMMapMaxAccessWrite, \ref kMMapMaxAccessExecute.
|
|
||||||
kMMapMaxAccessRWX = kMMapMaxAccessRead | kMMapMaxAccessWrite | kMMapMaxAccessExecute,
|
|
||||||
|
|
||||||
//! Not an access flag, only used by `allocDualMapping()` to override the
|
|
||||||
//! default allocation strategy to always use a 'tmp' directory instead of
|
|
||||||
//! "/dev/shm" (on POSIX platforms). Please note that this flag will be
|
|
||||||
//! ignored if the operating system allows to allocate an executable memory
|
|
||||||
//! by a different API than `open()` or `shm_open()`. For example on Linux
|
|
||||||
//! `memfd_create()` is preferred and on BSDs `shm_open(SHM_ANON, ...)` is
|
|
||||||
//! used if SHM_ANON is defined.
|
|
||||||
kMappingPreferTmp = 0x80000000u
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Virtual memory information.
|
//! Virtual memory information.
|
||||||
struct Info {
|
struct Info {
|
||||||
@@ -102,59 +33,205 @@ struct Info {
|
|||||||
uint32_t pageGranularity;
|
uint32_t pageGranularity;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Dual memory mapping used to map an anonymous memory into two memory regions
|
|
||||||
//! where one region is read-only, but executable, and the second region is
|
|
||||||
//! read+write, but not executable. Please see \ref VirtMem::allocDualMapping()
|
|
||||||
//! for more details.
|
|
||||||
struct DualMapping {
|
|
||||||
//! Pointer to data with 'Read' or 'Read+Execute' access.
|
|
||||||
void* ro;
|
|
||||||
//! Pointer to data with 'Read-Write' access, but never 'Write+Execute'.
|
|
||||||
void* rw;
|
|
||||||
};
|
|
||||||
|
|
||||||
//! Returns virtual memory information, see `VirtMem::Info` for more details.
|
//! Returns virtual memory information, see `VirtMem::Info` for more details.
|
||||||
ASMJIT_API Info info() noexcept;
|
ASMJIT_API Info info() noexcept;
|
||||||
|
|
||||||
//! Allocates virtual memory by either using `mmap()` (POSIX) or `VirtualAlloc()`
|
//! Virtual memory access and mmap-specific flags.
|
||||||
//! (Windows).
|
enum class MemoryFlags : uint32_t {
|
||||||
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Memory is readable.
|
||||||
|
kAccessRead = 0x00000001u,
|
||||||
|
|
||||||
|
//! Memory is writable.
|
||||||
|
kAccessWrite = 0x00000002u,
|
||||||
|
|
||||||
|
//! Memory is executable.
|
||||||
|
kAccessExecute = 0x00000004u,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kAccessRead and \ref MemoryFlags::kAccessWrite.
|
||||||
|
kAccessReadWrite = kAccessRead | kAccessWrite,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kAccessRead, \ref MemoryFlags::kAccessWrite.
|
||||||
|
kAccessRW = kAccessRead | kAccessWrite,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kAccessRead and \ref MemoryFlags::kAccessExecute.
|
||||||
|
kAccessRX = kAccessRead | kAccessExecute,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kAccessRead, \ref MemoryFlags::kAccessWrite, and
|
||||||
|
//! \ref MemoryFlags::kAccessExecute.
|
||||||
|
kAccessRWX = kAccessRead | kAccessWrite | kAccessExecute,
|
||||||
|
|
||||||
|
//! Use a `MAP_JIT` flag available on Apple platforms (introduced by Mojave), which allows JIT code to be executed
|
||||||
|
//! in MAC bundles. This flag is not turned on by default, because when a process uses `fork()` the child process
|
||||||
|
//! has no access to the pages mapped with `MAP_JIT`, which could break code that doesn't expect this behavior.
|
||||||
|
//!
|
||||||
|
//! \note This flag can only be used with \ref VirtMem::alloc().
|
||||||
|
kMMapEnableMapJit = 0x00000010u,
|
||||||
|
|
||||||
|
//! Pass `PROT_MAX(PROT_READ)` to mmap() on platforms that support `PROT_MAX`.
|
||||||
|
//!
|
||||||
|
//! \note This flag can only be used with \ref VirtMem::alloc().
|
||||||
|
kMMapMaxAccessRead = 0x00000020u,
|
||||||
|
//! Pass `PROT_MAX(PROT_WRITE)` to mmap() on platforms that support `PROT_MAX`.
|
||||||
|
//!
|
||||||
|
//! \note This flag can only be used with \ref VirtMem::alloc().
|
||||||
|
kMMapMaxAccessWrite = 0x00000040u,
|
||||||
|
//! Pass `PROT_MAX(PROT_EXEC)` to mmap() on platforms that support `PROT_MAX`.
|
||||||
|
//!
|
||||||
|
//! \note This flag can only be used with \ref VirtMem::alloc().
|
||||||
|
kMMapMaxAccessExecute = 0x00000080u,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessWrite.
|
||||||
|
kMMapMaxAccessReadWrite = kMMapMaxAccessRead | kMMapMaxAccessWrite,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessWrite.
|
||||||
|
kMMapMaxAccessRW = kMMapMaxAccessRead | kMMapMaxAccessWrite,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kMMapMaxAccessRead and \ref MemoryFlags::kMMapMaxAccessExecute.
|
||||||
|
kMMapMaxAccessRX = kMMapMaxAccessRead | kMMapMaxAccessExecute,
|
||||||
|
|
||||||
|
//! A combination of \ref MemoryFlags::kMMapMaxAccessRead, \ref MemoryFlags::kMMapMaxAccessWrite, \ref
|
||||||
|
//! MemoryFlags::kMMapMaxAccessExecute.
|
||||||
|
kMMapMaxAccessRWX = kMMapMaxAccessRead | kMMapMaxAccessWrite | kMMapMaxAccessExecute,
|
||||||
|
|
||||||
|
//! Not an access flag, only used by `allocDualMapping()` to override the default allocation strategy to always use
|
||||||
|
//! a 'tmp' directory instead of "/dev/shm" (on POSIX platforms). Please note that this flag will be ignored if the
|
||||||
|
//! operating system allows to allocate an executable memory by a different API than `open()` or `shm_open()`. For
|
||||||
|
//! example on Linux `memfd_create()` is preferred and on BSDs `shm_open(SHM_ANON, ...)` is used if SHM_ANON is
|
||||||
|
//! defined.
|
||||||
|
//!
|
||||||
|
//! \note This flag can only be used with \ref VirtMem::alloc().
|
||||||
|
kMappingPreferTmp = 0x80000000u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(MemoryFlags)
|
||||||
|
|
||||||
|
//! Allocates virtual memory by either using `mmap()` (POSIX) or `VirtualAlloc()` (Windows).
|
||||||
//!
|
//!
|
||||||
//! \note `size` should be aligned to page size, use \ref VirtMem::info()
|
//! \note `size` should be aligned to page size, use \ref VirtMem::info() to obtain it. Invalid size will not be
|
||||||
//! to obtain it. Invalid size will not be corrected by the implementation
|
//! corrected by the implementation and the allocation would not succeed in such case.
|
||||||
//! and the allocation would not succeed in such case.
|
ASMJIT_API Error alloc(void** p, size_t size, MemoryFlags flags) noexcept;
|
||||||
ASMJIT_API Error alloc(void** p, size_t size, uint32_t flags) noexcept;
|
|
||||||
|
|
||||||
//! Releases virtual memory previously allocated by \ref VirtMem::alloc().
|
//! Releases virtual memory previously allocated by \ref VirtMem::alloc().
|
||||||
//!
|
//!
|
||||||
//! \note The size must be the same as used by \ref VirtMem::alloc(). If the
|
//! \note The size must be the same as used by \ref VirtMem::alloc(). If the size is not the same value the call
|
||||||
//! size is not the same value the call will fail on any POSIX system, but
|
//! will fail on any POSIX system, but pass on Windows, because it's implemented differently.
|
||||||
//! pass on Windows, because it's implemented differently.
|
|
||||||
ASMJIT_API Error release(void* p, size_t size) noexcept;
|
ASMJIT_API Error release(void* p, size_t size) noexcept;
|
||||||
|
|
||||||
//! A cross-platform wrapper around `mprotect()` (POSIX) and `VirtualProtect()`
|
//! A cross-platform wrapper around `mprotect()` (POSIX) and `VirtualProtect()` (Windows).
|
||||||
//! (Windows).
|
ASMJIT_API Error protect(void* p, size_t size, MemoryFlags flags) noexcept;
|
||||||
ASMJIT_API Error protect(void* p, size_t size, uint32_t flags) noexcept;
|
|
||||||
|
|
||||||
//! Allocates virtual memory and creates two views of it where the first view
|
//! Dual memory mapping used to map an anonymous memory into two memory regions where one region is read-only, but
|
||||||
//! has no write access. This is an addition to the API that should be used
|
//! executable, and the second region is read+write, but not executable. See \ref VirtMem::allocDualMapping() for
|
||||||
//! in cases in which the operating system either enforces W^X security policy
|
//! more details.
|
||||||
//! or the application wants to use this policy by default to improve security
|
struct DualMapping {
|
||||||
//! and prevent an accidental (or purposed) self-modifying code.
|
//! Pointer to data with 'Read+Execute' access (this memory is not writable).
|
||||||
|
void* rx;
|
||||||
|
//! Pointer to data with 'Read+Write' access (this memory is not executable).
|
||||||
|
void* rw;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Allocates virtual memory and creates two views of it where the first view has no write access. This is an addition
|
||||||
|
//! to the API that should be used in cases in which the operating system either enforces W^X security policy or the
|
||||||
|
//! application wants to use this policy by default to improve security and prevent an accidental (or purposed)
|
||||||
|
//! self-modifying code.
|
||||||
//!
|
//!
|
||||||
//! The memory returned in the `dm` are two independent mappings of the same
|
//! The memory returned in the `dm` are two independent mappings of the same shared memory region. You must use
|
||||||
//! shared memory region. You must use \ref VirtMem::releaseDualMapping() to
|
//! \ref VirtMem::releaseDualMapping() to release it when it's no longer needed. Never use `VirtMem::release()` to
|
||||||
//! release it when it's no longer needed. Never use `VirtMem::release()` to
|
//! release the memory returned by `allocDualMapping()` as that would fail on Windows.
|
||||||
//! release the memory returned by `allocDualMapping()` as that would fail on
|
|
||||||
//! Windows.
|
|
||||||
//!
|
//!
|
||||||
//! \remarks Both pointers in `dm` would be set to `nullptr` if the function fails.
|
//! \remarks Both pointers in `dm` would be set to `nullptr` if the function fails.
|
||||||
ASMJIT_API Error allocDualMapping(DualMapping* dm, size_t size, uint32_t flags) noexcept;
|
ASMJIT_API Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags flags) noexcept;
|
||||||
|
|
||||||
//! Releases virtual memory mapping previously allocated by \ref VirtMem::allocDualMapping().
|
//! Releases virtual memory mapping previously allocated by \ref VirtMem::allocDualMapping().
|
||||||
//!
|
//!
|
||||||
//! \remarks Both pointers in `dm` would be set to `nullptr` if the function succeeds.
|
//! \remarks Both pointers in `dm` would be set to `nullptr` if the function succeeds.
|
||||||
ASMJIT_API Error releaseDualMapping(DualMapping* dm, size_t size) noexcept;
|
ASMJIT_API Error releaseDualMapping(DualMapping* dm, size_t size) noexcept;
|
||||||
|
|
||||||
|
//! Hardened runtime flags.
|
||||||
|
enum class HardenedRuntimeFlags : uint32_t {
|
||||||
|
//! No flags.
|
||||||
|
kNone = 0,
|
||||||
|
|
||||||
|
//! Hardened runtime is enabled - it's not possible to have "Write & Execute" memory protection. The runtime
|
||||||
|
//! enforces W^X (either write or execute).
|
||||||
|
//!
|
||||||
|
//! \note If the runtime is hardened it means that an operating system specific protection is used. For example on
|
||||||
|
//! MacOS platform it's possible to allocate memory with MAP_JIT flag and then use `pthread_jit_write_protect_np()`
|
||||||
|
//! to temporarily swap access permissions for the current thread. Dual mapping is also a possibility on X86/X64
|
||||||
|
//! architecture.
|
||||||
|
kEnabled = 0x00000001u,
|
||||||
|
|
||||||
|
//! Read+Write+Execute can only be allocated with MAP_JIT flag (Apple specific).
|
||||||
|
kMapJit = 0x00000002u
|
||||||
|
};
|
||||||
|
ASMJIT_DEFINE_ENUM_FLAGS(HardenedRuntimeFlags)
|
||||||
|
|
||||||
|
//! Hardened runtime information.
|
||||||
|
struct HardenedRuntimeInfo {
|
||||||
|
//! Hardened runtime flags.
|
||||||
|
HardenedRuntimeFlags flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Returns runtime features provided by the OS.
|
||||||
|
ASMJIT_API HardenedRuntimeInfo hardenedRuntimeInfo() noexcept;
|
||||||
|
|
||||||
|
//! Values that can be used with `protectJitMemory()` function.
|
||||||
|
enum class ProtectJitAccess : uint32_t {
|
||||||
|
//! Protect JIT memory with Read+Write permissions.
|
||||||
|
kReadWrite = 0,
|
||||||
|
//! Protect JIT memory with Read+Execute permissions.
|
||||||
|
kReadExecute = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//! Protects access of memory mapped with MAP_JIT flag for the current thread.
|
||||||
|
//!
|
||||||
|
//! \note This feature is only available on Apple hardware (AArch64) at the moment and and uses a non-portable
|
||||||
|
//! `pthread_jit_write_protect_np()` call when available.
|
||||||
|
//!
|
||||||
|
//! This function must be called before and after a memory mapped with MAP_JIT flag is modified. Example:
|
||||||
|
//!
|
||||||
|
//! ```
|
||||||
|
//! void* codePtr = ...;
|
||||||
|
//! size_t codeSize = ...;
|
||||||
|
//!
|
||||||
|
//! VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite);
|
||||||
|
//! memcpy(codePtr, source, codeSize);
|
||||||
|
//! VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute);
|
||||||
|
//! VirtMem::flushInstructionCache(codePtr, codeSize);
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
|
//! See \ref ProtectJitReadWriteScope, which makes it simpler than the code above.
|
||||||
|
ASMJIT_API void protectJitMemory(ProtectJitAccess access) noexcept;
|
||||||
|
|
||||||
|
//! JIT protection scope that prepares the given memory block to be written to in the current thread.
|
||||||
|
//!
|
||||||
|
//! It calls `VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadWrite)` at construction time and
|
||||||
|
//! `VirtMem::protectJitMemory(VirtMem::ProtectJitAccess::kReadExecute)` combined with `flushInstructionCache()`
|
||||||
|
//! in destructor. The purpose of this class is to make writing to JIT memory easier.
|
||||||
|
class ProtectJitReadWriteScope {
|
||||||
|
public:
|
||||||
|
void* _rxPtr;
|
||||||
|
size_t _size;
|
||||||
|
|
||||||
|
//! Makes the given memory block RW protected.
|
||||||
|
ASMJIT_FORCE_INLINE ProtectJitReadWriteScope(void* rxPtr, size_t size) noexcept
|
||||||
|
: _rxPtr(rxPtr),
|
||||||
|
_size(size) {
|
||||||
|
protectJitMemory(ProtectJitAccess::kReadWrite);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not copyable.
|
||||||
|
ProtectJitReadWriteScope(const ProtectJitReadWriteScope& other) = delete;
|
||||||
|
|
||||||
|
//! Makes the memory block RX protected again and flushes instruction cache.
|
||||||
|
ASMJIT_FORCE_INLINE ~ProtectJitReadWriteScope() noexcept {
|
||||||
|
protectJitMemory(ProtectJitAccess::kReadExecute);
|
||||||
|
flushInstructionCache(_rxPtr, _size);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // VirtMem
|
} // VirtMem
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
@@ -27,17 +9,15 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// Zone - Globals
|
||||||
// [asmjit::Zone - Statics]
|
// ==============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
// Zero size block used by `Zone` that doesn't have any memory allocated.
|
// Zero size block used by `Zone` that doesn't have any memory allocated. Should be allocated in read-only memory
|
||||||
// Should be allocated in read-only memory and should never be modified.
|
// and should never be modified.
|
||||||
const Zone::Block Zone::_zeroBlock = { nullptr, nullptr, 0 };
|
const Zone::Block Zone::_zeroBlock = { nullptr, nullptr, 0 };
|
||||||
|
|
||||||
// ============================================================================
|
// Zone - Init & Reset
|
||||||
// [asmjit::Zone - Init / Reset]
|
// ===================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void Zone::_init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
|
void Zone::_init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
|
||||||
ASMJIT_ASSERT(blockSize >= kMinBlockSize);
|
ASMJIT_ASSERT(blockSize >= kMinBlockSize);
|
||||||
@@ -66,28 +46,27 @@ void Zone::_init(size_t blockSize, size_t blockAlignment, const Support::Tempora
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Zone::reset(uint32_t resetPolicy) noexcept {
|
void Zone::reset(ResetPolicy resetPolicy) noexcept {
|
||||||
Block* cur = _block;
|
Block* cur = _block;
|
||||||
|
|
||||||
// Can't be altered.
|
// Can't be altered.
|
||||||
if (cur == &_zeroBlock)
|
if (cur == &_zeroBlock)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (resetPolicy == Globals::kResetHard) {
|
if (resetPolicy == ResetPolicy::kHard) {
|
||||||
Block* initial = const_cast<Zone::Block*>(&_zeroBlock);
|
Block* initial = const_cast<Zone::Block*>(&_zeroBlock);
|
||||||
_ptr = initial->data();
|
_ptr = initial->data();
|
||||||
_end = initial->data();
|
_end = initial->data();
|
||||||
_block = initial;
|
_block = initial;
|
||||||
|
|
||||||
// Since cur can be in the middle of the double-linked list, we have to
|
// Since cur can be in the middle of the double-linked list, we have to traverse both directions (`prev` and
|
||||||
// traverse both directions (`prev` and `next`) separately to visit all.
|
// `next`) separately to visit all.
|
||||||
Block* next = cur->next;
|
Block* next = cur->next;
|
||||||
do {
|
do {
|
||||||
Block* prev = cur->prev;
|
Block* prev = cur->prev;
|
||||||
|
|
||||||
// If this is the first block and this ZoneTmp is temporary then the
|
// If this is the first block and this ZoneTmp is temporary then the first block is statically allocated.
|
||||||
// first block is statically allocated. We cannot free it and it makes
|
// We cannot free it and it makes sense to keep it even when this is hard reset.
|
||||||
// sense to keep it even when this is hard reset.
|
|
||||||
if (prev == nullptr && _isTemporary) {
|
if (prev == nullptr && _isTemporary) {
|
||||||
cur->prev = nullptr;
|
cur->prev = nullptr;
|
||||||
cur->next = nullptr;
|
cur->next = nullptr;
|
||||||
@@ -113,9 +92,8 @@ void Zone::reset(uint32_t resetPolicy) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// Zone - Alloc
|
||||||
// [asmjit::Zone - Alloc]
|
// ============
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void* Zone::_alloc(size_t size, size_t alignment) noexcept {
|
void* Zone::_alloc(size_t size, size_t alignment) noexcept {
|
||||||
Block* curBlock = _block;
|
Block* curBlock = _block;
|
||||||
@@ -124,10 +102,9 @@ void* Zone::_alloc(size_t size, size_t alignment) noexcept {
|
|||||||
size_t rawBlockAlignment = blockAlignment();
|
size_t rawBlockAlignment = blockAlignment();
|
||||||
size_t minimumAlignment = Support::max<size_t>(alignment, rawBlockAlignment);
|
size_t minimumAlignment = Support::max<size_t>(alignment, rawBlockAlignment);
|
||||||
|
|
||||||
// If the `Zone` has been cleared the current block doesn't have to be the
|
// If the `Zone` has been cleared the current block doesn't have to be the last one. Check if there is a block
|
||||||
// last one. Check if there is a block that can be used instead of allocating
|
// that can be used instead of allocating a new one. If there is a `next` block it's completely unused, we don't
|
||||||
// a new one. If there is a `next` block it's completely unused, we don't have
|
// have to check for remaining bytes in that case.
|
||||||
// to check for remaining bytes in that case.
|
|
||||||
if (next) {
|
if (next) {
|
||||||
uint8_t* ptr = Support::alignUp(next->data(), minimumAlignment);
|
uint8_t* ptr = Support::alignUp(next->data(), minimumAlignment);
|
||||||
uint8_t* end = Support::alignDown(next->data() + next->size, rawBlockAlignment);
|
uint8_t* end = Support::alignDown(next->data() + next->size, rawBlockAlignment);
|
||||||
@@ -147,18 +124,16 @@ void* Zone::_alloc(size_t size, size_t alignment) noexcept {
|
|||||||
if (ASMJIT_UNLIKELY(newSize > SIZE_MAX - kBlockSize - blockAlignmentOverhead))
|
if (ASMJIT_UNLIKELY(newSize > SIZE_MAX - kBlockSize - blockAlignmentOverhead))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Allocate new block - we add alignment overhead to `newSize`, which becomes the
|
// Allocate new block - we add alignment overhead to `newSize`, which becomes the new block size, and we also add
|
||||||
// new block size, and we also add `kBlockOverhead` to the allocator as it includes
|
// `kBlockOverhead` to the allocator as it includes members of `Zone::Block` structure.
|
||||||
// members of `Zone::Block` structure.
|
|
||||||
newSize += blockAlignmentOverhead;
|
newSize += blockAlignmentOverhead;
|
||||||
Block* newBlock = static_cast<Block*>(::malloc(newSize + kBlockSize));
|
Block* newBlock = static_cast<Block*>(::malloc(newSize + kBlockSize));
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(!newBlock))
|
if (ASMJIT_UNLIKELY(!newBlock))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
// Align the pointer to `minimumAlignment` and adjust the size of this block
|
// Align the pointer to `minimumAlignment` and adjust the size of this block accordingly. It's the same as using
|
||||||
// accordingly. It's the same as using `minimumAlignment - Support::alignUpDiff()`,
|
// `minimumAlignment - Support::alignUpDiff()`, just written differently.
|
||||||
// just written differently.
|
|
||||||
{
|
{
|
||||||
newBlock->prev = nullptr;
|
newBlock->prev = nullptr;
|
||||||
newBlock->next = nullptr;
|
newBlock->next = nullptr;
|
||||||
@@ -168,9 +143,8 @@ void* Zone::_alloc(size_t size, size_t alignment) noexcept {
|
|||||||
newBlock->prev = curBlock;
|
newBlock->prev = curBlock;
|
||||||
curBlock->next = newBlock;
|
curBlock->next = newBlock;
|
||||||
|
|
||||||
// Does only happen if there is a next block, but the requested memory
|
// Does only happen if there is a next block, but the requested memory can't fit into it. In this case a new
|
||||||
// can't fit into it. In this case a new buffer is allocated and inserted
|
// buffer is allocated and inserted between the current block and the next one.
|
||||||
// between the current block and the next one.
|
|
||||||
if (next) {
|
if (next) {
|
||||||
newBlock->next = next;
|
newBlock->next = next;
|
||||||
next->prev = newBlock;
|
next->prev = newBlock;
|
||||||
@@ -226,9 +200,8 @@ char* Zone::sformat(const char* fmt, ...) noexcept {
|
|||||||
return static_cast<char*>(dup(buf, size));
|
return static_cast<char*>(dup(buf, size));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneAllocator - Utilities
|
||||||
// [asmjit::ZoneAllocator - Helpers]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_BUILD_DEBUG)
|
#if defined(ASMJIT_BUILD_DEBUG)
|
||||||
static bool ZoneAllocator_hasDynamicBlock(ZoneAllocator* self, ZoneAllocator::DynamicBlock* block) noexcept {
|
static bool ZoneAllocator_hasDynamicBlock(ZoneAllocator* self, ZoneAllocator::DynamicBlock* block) noexcept {
|
||||||
@@ -242,9 +215,8 @@ static bool ZoneAllocator_hasDynamicBlock(ZoneAllocator* self, ZoneAllocator::Dy
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneAllocator - Init & Reset
|
||||||
// [asmjit::ZoneAllocator - Init / Reset]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void ZoneAllocator::reset(Zone* zone) noexcept {
|
void ZoneAllocator::reset(Zone* zone) noexcept {
|
||||||
// Free dynamic blocks.
|
// Free dynamic blocks.
|
||||||
@@ -260,9 +232,8 @@ void ZoneAllocator::reset(Zone* zone) noexcept {
|
|||||||
_zone = zone;
|
_zone = zone;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// asmjit::ZoneAllocator - Alloc & Release
|
||||||
// [asmjit::ZoneAllocator - Alloc / Release]
|
// =======================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void* ZoneAllocator::_alloc(size_t size, size_t& allocatedSize) noexcept {
|
void* ZoneAllocator::_alloc(size_t size, size_t& allocatedSize) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONE_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONE_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONE_H_INCLUDED
|
#define ASMJIT_CORE_ZONE_H_INCLUDED
|
||||||
@@ -31,20 +13,14 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::Zone]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Zone memory.
|
//! Zone memory.
|
||||||
//!
|
//!
|
||||||
//! Zone is an incremental memory allocator that allocates memory by simply
|
//! Zone is an incremental memory allocator that allocates memory by simply incrementing a pointer. It allocates
|
||||||
//! incrementing a pointer. It allocates blocks of memory by using C's `malloc()`,
|
//! blocks of memory by using C's `malloc()`, but divides these blocks into smaller segments requested by calling
|
||||||
//! but divides these blocks into smaller segments requested by calling
|
|
||||||
//! `Zone::alloc()` and friends.
|
//! `Zone::alloc()` and friends.
|
||||||
//!
|
//!
|
||||||
//! Zone has no function to release the allocated memory. It has to be released
|
//! Zone has no function to release the allocated memory. It has to be released all at once by calling `reset()`.
|
||||||
//! all at once by calling `reset()`. If you need a more friendly allocator that
|
//! If you need a more friendly allocator that also supports `release()`, consider using `Zone` with `ZoneAllocator`.
|
||||||
//! also supports `release()`, consider using `Zone` with `ZoneAllocator`.
|
|
||||||
class Zone {
|
class Zone {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(Zone)
|
ASMJIT_NONCOPYABLE(Zone)
|
||||||
@@ -103,28 +79,31 @@ public:
|
|||||||
|
|
||||||
//! Creates a new Zone.
|
//! Creates a new Zone.
|
||||||
//!
|
//!
|
||||||
//! The `blockSize` parameter describes the default size of the block. If the
|
//! The `blockSize` parameter describes the default size of the block. If the `size` parameter passed to `alloc()`
|
||||||
//! `size` parameter passed to `alloc()` is greater than the default size
|
//! is greater than the default size `Zone` will allocate and use a larger block, but it will not change the
|
||||||
//! `Zone` will allocate and use a larger block, but it will not change the
|
|
||||||
//! default `blockSize`.
|
//! default `blockSize`.
|
||||||
//!
|
//!
|
||||||
//! It's not required, but it's good practice to set `blockSize` to a
|
//! It's not required, but it's good practice to set `blockSize` to a reasonable value that depends on the usage
|
||||||
//! reasonable value that depends on the usage of `Zone`. Greater block sizes
|
//! of `Zone`. Greater block sizes are generally safer and perform better than unreasonably low block sizes.
|
||||||
//! are generally safer and perform better than unreasonably low block sizes.
|
inline explicit Zone(size_t blockSize, size_t blockAlignment = 1) noexcept {
|
||||||
ASMJIT_INLINE explicit Zone(size_t blockSize, size_t blockAlignment = 1) noexcept {
|
|
||||||
_init(blockSize, blockAlignment, nullptr);
|
_init(blockSize, blockAlignment, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary& temporary) noexcept {
|
//! Creates a new Zone with a first block pointing to a `temporary` memory.
|
||||||
|
inline Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary& temporary) noexcept {
|
||||||
_init(blockSize, blockAlignment, &temporary);
|
_init(blockSize, blockAlignment, &temporary);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \overload
|
||||||
|
inline Zone(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
|
||||||
|
_init(blockSize, blockAlignment, temporary);
|
||||||
|
}
|
||||||
|
|
||||||
//! Moves an existing `Zone`.
|
//! Moves an existing `Zone`.
|
||||||
//!
|
//!
|
||||||
//! \note You cannot move an existing `ZoneTmp` as it uses embedded storage.
|
//! \note You cannot move an existing `ZoneTmp` as it uses embedded storage. Attempting to move `ZoneTmp` would
|
||||||
//! Attempting to move `ZoneTmp` would result in assertion failure in debug
|
//! result in assertion failure in debug mode and undefined behavior in release mode.
|
||||||
//! mode and undefined behavior in release mode.
|
inline Zone(Zone&& other) noexcept
|
||||||
ASMJIT_INLINE Zone(Zone&& other) noexcept
|
|
||||||
: _ptr(other._ptr),
|
: _ptr(other._ptr),
|
||||||
_end(other._end),
|
_end(other._end),
|
||||||
_block(other._block),
|
_block(other._block),
|
||||||
@@ -137,16 +116,16 @@ public:
|
|||||||
|
|
||||||
//! Destroys the `Zone` instance.
|
//! Destroys the `Zone` instance.
|
||||||
//!
|
//!
|
||||||
//! This will destroy the `Zone` instance and release all blocks of memory
|
//! This will destroy the `Zone` instance and release all blocks of memory allocated by it. It performs implicit
|
||||||
//! allocated by it. It performs implicit `reset(Globals::kResetHard)`.
|
//! `reset(ResetPolicy::kHard)`.
|
||||||
ASMJIT_INLINE ~Zone() noexcept { reset(Globals::kResetHard); }
|
inline ~Zone() noexcept { reset(ResetPolicy::kHard); }
|
||||||
|
|
||||||
ASMJIT_API void _init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept;
|
ASMJIT_API void _init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept;
|
||||||
|
|
||||||
//! Resets the `Zone` invalidating all blocks allocated.
|
//! Resets the `Zone` invalidating all blocks allocated.
|
||||||
//!
|
//!
|
||||||
//! See `Globals::ResetPolicy` for more details.
|
//! See `Globals::ResetPolicy` for more details.
|
||||||
ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept;
|
ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -154,29 +133,28 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Tests whether this `Zone` is actually a `ZoneTmp` that uses temporary memory.
|
//! Tests whether this `Zone` is actually a `ZoneTmp` that uses temporary memory.
|
||||||
ASMJIT_INLINE bool isTemporary() const noexcept { return _isTemporary != 0; }
|
inline bool isTemporary() const noexcept { return _isTemporary != 0; }
|
||||||
|
|
||||||
//! Returns the default block size.
|
//! Returns the default block size.
|
||||||
ASMJIT_INLINE size_t blockSize() const noexcept { return _blockSize; }
|
inline size_t blockSize() const noexcept { return _blockSize; }
|
||||||
//! Returns the default block alignment.
|
//! Returns the default block alignment.
|
||||||
ASMJIT_INLINE size_t blockAlignment() const noexcept { return size_t(1) << _blockAlignmentShift; }
|
inline size_t blockAlignment() const noexcept { return size_t(1) << _blockAlignmentShift; }
|
||||||
//! Returns remaining size of the current block.
|
//! Returns remaining size of the current block.
|
||||||
ASMJIT_INLINE size_t remainingSize() const noexcept { return (size_t)(_end - _ptr); }
|
inline size_t remainingSize() const noexcept { return (size_t)(_end - _ptr); }
|
||||||
|
|
||||||
//! Returns the current zone cursor (dangerous).
|
//! Returns the current zone cursor (dangerous).
|
||||||
//!
|
//!
|
||||||
//! This is a function that can be used to get exclusive access to the current
|
//! This is a function that can be used to get exclusive access to the current block's memory buffer.
|
||||||
//! block's memory buffer.
|
|
||||||
template<typename T = uint8_t>
|
template<typename T = uint8_t>
|
||||||
ASMJIT_INLINE T* ptr() noexcept { return reinterpret_cast<T*>(_ptr); }
|
inline T* ptr() noexcept { return reinterpret_cast<T*>(_ptr); }
|
||||||
|
|
||||||
//! Returns the end of the current zone block, only useful if you use `ptr()`.
|
//! Returns the end of the current zone block, only useful if you use `ptr()`.
|
||||||
template<typename T = uint8_t>
|
template<typename T = uint8_t>
|
||||||
ASMJIT_INLINE T* end() noexcept { return reinterpret_cast<T*>(_end); }
|
inline T* end() noexcept { return reinterpret_cast<T*>(_end); }
|
||||||
|
|
||||||
//! Sets the current zone pointer to `ptr` (must be within the current block).
|
//! Sets the current zone pointer to `ptr` (must be within the current block).
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void setPtr(T* ptr) noexcept {
|
inline void setPtr(T* ptr) noexcept {
|
||||||
uint8_t* p = reinterpret_cast<uint8_t*>(ptr);
|
uint8_t* p = reinterpret_cast<uint8_t*>(ptr);
|
||||||
ASMJIT_ASSERT(p >= _ptr && p <= _end);
|
ASMJIT_ASSERT(p >= _ptr && p <= _end);
|
||||||
_ptr = p;
|
_ptr = p;
|
||||||
@@ -184,7 +162,7 @@ public:
|
|||||||
|
|
||||||
//! Sets the end zone pointer to `end` (must be within the current block).
|
//! Sets the end zone pointer to `end` (must be within the current block).
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE void setEnd(T* end) noexcept {
|
inline void setEnd(T* end) noexcept {
|
||||||
uint8_t* p = reinterpret_cast<uint8_t*>(end);
|
uint8_t* p = reinterpret_cast<uint8_t*>(end);
|
||||||
ASMJIT_ASSERT(p >= _ptr && p <= _end);
|
ASMJIT_ASSERT(p >= _ptr && p <= _end);
|
||||||
_end = p;
|
_end = p;
|
||||||
@@ -195,7 +173,7 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE void swap(Zone& other) noexcept {
|
inline void swap(Zone& other) noexcept {
|
||||||
// This could lead to a disaster.
|
// This could lead to a disaster.
|
||||||
ASMJIT_ASSERT(!this->isTemporary());
|
ASMJIT_ASSERT(!this->isTemporary());
|
||||||
ASMJIT_ASSERT(!other.isTemporary());
|
ASMJIT_ASSERT(!other.isTemporary());
|
||||||
@@ -207,30 +185,29 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Aligns the current pointer to `alignment`.
|
//! Aligns the current pointer to `alignment`.
|
||||||
ASMJIT_INLINE void align(size_t alignment) noexcept {
|
inline void align(size_t alignment) noexcept {
|
||||||
_ptr = Support::min(Support::alignUp(_ptr, alignment), _end);
|
_ptr = Support::min(Support::alignUp(_ptr, alignment), _end);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Ensures the remaining size is at least equal or greater than `size`.
|
//! Ensures the remaining size is at least equal or greater than `size`.
|
||||||
//!
|
//!
|
||||||
//! \note This function doesn't respect any alignment. If you need to ensure
|
//! \note This function doesn't respect any alignment. If you need to ensure there is enough room for an aligned
|
||||||
//! there is enough room for an aligned allocation you need to call `align()`
|
//! allocation you need to call `align()` before calling `ensure()`.
|
||||||
//! before calling `ensure()`.
|
inline Error ensure(size_t size) noexcept {
|
||||||
ASMJIT_INLINE Error ensure(size_t size) noexcept {
|
|
||||||
if (size <= remainingSize())
|
if (size <= remainingSize())
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
else
|
else
|
||||||
return _alloc(0, 1) ? kErrorOk : DebugUtils::errored(kErrorOutOfMemory);
|
return _alloc(0, 1) ? kErrorOk : DebugUtils::errored(kErrorOutOfMemory);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void _assignBlock(Block* block) noexcept {
|
inline void _assignBlock(Block* block) noexcept {
|
||||||
size_t alignment = blockAlignment();
|
size_t alignment = blockAlignment();
|
||||||
_ptr = Support::alignUp(block->data(), alignment);
|
_ptr = Support::alignUp(block->data(), alignment);
|
||||||
_end = Support::alignDown(block->data() + block->size, alignment);
|
_end = Support::alignDown(block->data() + block->size, alignment);
|
||||||
_block = block;
|
_block = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE void _assignZeroBlock() noexcept {
|
inline void _assignZeroBlock() noexcept {
|
||||||
Block* block = const_cast<Block*>(&_zeroBlock);
|
Block* block = const_cast<Block*>(&_zeroBlock);
|
||||||
_ptr = block->data();
|
_ptr = block->data();
|
||||||
_end = block->data();
|
_end = block->data();
|
||||||
@@ -244,9 +221,8 @@ public:
|
|||||||
|
|
||||||
//! Allocates the requested memory specified by `size`.
|
//! Allocates the requested memory specified by `size`.
|
||||||
//!
|
//!
|
||||||
//! Pointer returned is valid until the `Zone` instance is destroyed or reset
|
//! Pointer returned is valid until the `Zone` instance is destroyed or reset by calling `reset()`. If you plan to
|
||||||
//! by calling `reset()`. If you plan to make an instance of C++ from the
|
//! make an instance of C++ from the given pointer use placement `new` and `delete` operators:
|
||||||
//! given pointer use placement `new` and `delete` operators:
|
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! using namespace asmjit;
|
//! using namespace asmjit;
|
||||||
@@ -274,7 +250,7 @@ public:
|
|||||||
//! // Reset or destroy `Zone`.
|
//! // Reset or destroy `Zone`.
|
||||||
//! zone.reset();
|
//! zone.reset();
|
||||||
//! ```
|
//! ```
|
||||||
ASMJIT_INLINE void* alloc(size_t size) noexcept {
|
inline void* alloc(size_t size) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(size > remainingSize()))
|
if (ASMJIT_UNLIKELY(size > remainingSize()))
|
||||||
return _alloc(size, 1);
|
return _alloc(size, 1);
|
||||||
|
|
||||||
@@ -284,7 +260,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Allocates the requested memory specified by `size` and `alignment`.
|
//! Allocates the requested memory specified by `size` and `alignment`.
|
||||||
ASMJIT_INLINE void* alloc(size_t size, size_t alignment) noexcept {
|
inline void* alloc(size_t size, size_t alignment) noexcept {
|
||||||
ASMJIT_ASSERT(Support::isPowerOf2(alignment));
|
ASMJIT_ASSERT(Support::isPowerOf2(alignment));
|
||||||
uint8_t* ptr = Support::alignUp(_ptr, alignment);
|
uint8_t* ptr = Support::alignUp(_ptr, alignment);
|
||||||
|
|
||||||
@@ -298,7 +274,7 @@ public:
|
|||||||
//! Allocates the requested memory specified by `size` without doing any checks.
|
//! Allocates the requested memory specified by `size` without doing any checks.
|
||||||
//!
|
//!
|
||||||
//! Can only be called if `remainingSize()` returns size at least equal to `size`.
|
//! Can only be called if `remainingSize()` returns size at least equal to `size`.
|
||||||
ASMJIT_INLINE void* allocNoCheck(size_t size) noexcept {
|
inline void* allocNoCheck(size_t size) noexcept {
|
||||||
ASMJIT_ASSERT(remainingSize() >= size);
|
ASMJIT_ASSERT(remainingSize() >= size);
|
||||||
|
|
||||||
uint8_t* ptr = _ptr;
|
uint8_t* ptr = _ptr;
|
||||||
@@ -309,7 +285,7 @@ public:
|
|||||||
//! Allocates the requested memory specified by `size` and `alignment` without doing any checks.
|
//! Allocates the requested memory specified by `size` and `alignment` without doing any checks.
|
||||||
//!
|
//!
|
||||||
//! Performs the same operation as `Zone::allocNoCheck(size)` with `alignment` applied.
|
//! Performs the same operation as `Zone::allocNoCheck(size)` with `alignment` applied.
|
||||||
ASMJIT_INLINE void* allocNoCheck(size_t size, size_t alignment) noexcept {
|
inline void* allocNoCheck(size_t size, size_t alignment) noexcept {
|
||||||
ASMJIT_ASSERT(Support::isPowerOf2(alignment));
|
ASMJIT_ASSERT(Support::isPowerOf2(alignment));
|
||||||
|
|
||||||
uint8_t* ptr = Support::alignUp(_ptr, alignment);
|
uint8_t* ptr = Support::alignUp(_ptr, alignment);
|
||||||
@@ -324,25 +300,25 @@ public:
|
|||||||
|
|
||||||
//! Like `alloc()`, but the return pointer is casted to `T*`.
|
//! Like `alloc()`, but the return pointer is casted to `T*`.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE T* allocT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
inline T* allocT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
||||||
return static_cast<T*>(alloc(size, alignment));
|
return static_cast<T*>(alloc(size, alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Like `allocNoCheck()`, but the return pointer is casted to `T*`.
|
//! Like `allocNoCheck()`, but the return pointer is casted to `T*`.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE T* allocNoCheckT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
inline T* allocNoCheckT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
||||||
return static_cast<T*>(allocNoCheck(size, alignment));
|
return static_cast<T*>(allocNoCheck(size, alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Like `allocZeroed()`, but the return pointer is casted to `T*`.
|
//! Like `allocZeroed()`, but the return pointer is casted to `T*`.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE T* allocZeroedT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
inline T* allocZeroedT(size_t size = sizeof(T), size_t alignment = alignof(T)) noexcept {
|
||||||
return static_cast<T*>(allocZeroed(size, alignment));
|
return static_cast<T*>(allocZeroed(size, alignment));
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
|
//! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
ASMJIT_INLINE T* newT() noexcept {
|
inline T* newT() noexcept {
|
||||||
void* p = alloc(sizeof(T), alignof(T));
|
void* p = alloc(sizeof(T), alignof(T));
|
||||||
if (ASMJIT_UNLIKELY(!p))
|
if (ASMJIT_UNLIKELY(!p))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -351,7 +327,7 @@ public:
|
|||||||
|
|
||||||
//! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
|
//! Like `new(std::nothrow) T(...)`, but allocated by `Zone`.
|
||||||
template<typename T, typename... Args>
|
template<typename T, typename... Args>
|
||||||
ASMJIT_INLINE T* newT(Args&&... args) noexcept {
|
inline T* newT(Args&&... args) noexcept {
|
||||||
void* p = alloc(sizeof(T), alignof(T));
|
void* p = alloc(sizeof(T), alignof(T));
|
||||||
if (ASMJIT_UNLIKELY(!p))
|
if (ASMJIT_UNLIKELY(!p))
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -368,7 +344,7 @@ public:
|
|||||||
ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept;
|
ASMJIT_API void* dup(const void* data, size_t size, bool nullTerminate = false) noexcept;
|
||||||
|
|
||||||
//! Helper to duplicate data.
|
//! Helper to duplicate data.
|
||||||
ASMJIT_INLINE void* dupAligned(const void* data, size_t size, size_t alignment, bool nullTerminate = false) noexcept {
|
inline void* dupAligned(const void* data, size_t size, size_t alignment, bool nullTerminate = false) noexcept {
|
||||||
align(alignment);
|
align(alignment);
|
||||||
return dup(data, size, nullTerminate);
|
return dup(data, size, nullTerminate);
|
||||||
}
|
}
|
||||||
@@ -379,15 +355,10 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [b2d::ZoneTmp]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! \ref Zone with `N` bytes of a static storage, used for the initial block.
|
//! \ref Zone with `N` bytes of a static storage, used for the initial block.
|
||||||
//!
|
//!
|
||||||
//! Temporary zones are used in cases where it's known that some memory will be
|
//! Temporary zones are used in cases where it's known that some memory will be required, but in many cases it won't
|
||||||
//! required, but in many cases it won't exceed N bytes, so the whole operation
|
//! exceed N bytes, so the whole operation can be performed without a dynamic memory allocation.
|
||||||
//! can be performed without a dynamic memory allocation.
|
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
class ZoneTmp : public Zone {
|
class ZoneTmp : public Zone {
|
||||||
public:
|
public:
|
||||||
@@ -399,35 +370,29 @@ public:
|
|||||||
} _storage;
|
} _storage;
|
||||||
|
|
||||||
//! Creates a temporary zone. Dynamic block size is specified by `blockSize`.
|
//! Creates a temporary zone. Dynamic block size is specified by `blockSize`.
|
||||||
ASMJIT_INLINE explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept
|
inline explicit ZoneTmp(size_t blockSize, size_t blockAlignment = 1) noexcept
|
||||||
: Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {}
|
: Zone(blockSize, blockAlignment, Support::Temporary(_storage.data, N)) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! Zone-based memory allocator that uses an existing `Zone` and provides a `release()` functionality on top of it.
|
||||||
// [asmjit::ZoneAllocator]
|
//! It uses `Zone` only for chunks that can be pooled, and uses libc `malloc()` for chunks that are large.
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Zone-based memory allocator that uses an existing `Zone` and provides a
|
|
||||||
//! `release()` functionality on top of it. It uses `Zone` only for chunks
|
|
||||||
//! that can be pooled, and uses libc `malloc()` for chunks that are large.
|
|
||||||
//!
|
//!
|
||||||
//! The advantage of ZoneAllocator is that it can allocate small chunks of memory
|
//! The advantage of ZoneAllocator is that it can allocate small chunks of memory really fast, and these chunks,
|
||||||
//! really fast, and these chunks, when released, will be reused by consecutive
|
//! when released, will be reused by consecutive calls to `alloc()`. Also, since ZoneAllocator uses `Zone`, you can
|
||||||
//! calls to `alloc()`. Also, since ZoneAllocator uses `Zone`, you can turn any
|
//! turn any `Zone` into a `ZoneAllocator`, and use it in your `Pass` when necessary.
|
||||||
//! `Zone` into a `ZoneAllocator`, and use it in your `Pass` when necessary.
|
|
||||||
//!
|
//!
|
||||||
//! ZoneAllocator is used by AsmJit containers to make containers having only
|
//! ZoneAllocator is used by AsmJit containers to make containers having only few elements fast (and lightweight)
|
||||||
//! few elements fast (and lightweight) and to allow them to grow and use
|
//! and to allow them to grow and use dynamic blocks when require more storage.
|
||||||
//! dynamic blocks when require more storage.
|
|
||||||
class ZoneAllocator {
|
class ZoneAllocator {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneAllocator)
|
ASMJIT_NONCOPYABLE(ZoneAllocator)
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
enum {
|
|
||||||
// In short, we pool chunks of these sizes:
|
|
||||||
// [32, 64, 96, 128, 192, 256, 320, 384, 448, 512]
|
|
||||||
|
|
||||||
|
// In short, we pool chunks of these sizes:
|
||||||
|
// [32, 64, 96, 128, 192, 256, 320, 384, 448, 512]
|
||||||
|
|
||||||
|
enum : uint32_t {
|
||||||
//! How many bytes per a low granularity pool (has to be at least 16).
|
//! How many bytes per a low granularity pool (has to be at least 16).
|
||||||
kLoGranularity = 32,
|
kLoGranularity = 32,
|
||||||
//! Number of slots of a low granularity pool.
|
//! Number of slots of a low granularity pool.
|
||||||
@@ -452,9 +417,8 @@ public:
|
|||||||
Slot* next;
|
Slot* next;
|
||||||
};
|
};
|
||||||
|
|
||||||
//! A block of memory that has been allocated dynamically and is not part of
|
//! A block of memory that has been allocated dynamically and is not part of block-list used by the allocator.
|
||||||
//! block-list used by the allocator. This is used to keep track of all these
|
//! This is used to keep track of all these blocks so they can be freed by `reset()` if not freed explicitly.
|
||||||
//! blocks so they can be freed by `reset()` if not freed explicitly.
|
|
||||||
struct DynamicBlock {
|
struct DynamicBlock {
|
||||||
DynamicBlock* prev;
|
DynamicBlock* prev;
|
||||||
DynamicBlock* next;
|
DynamicBlock* next;
|
||||||
@@ -462,6 +426,9 @@ public:
|
|||||||
|
|
||||||
//! \endcond
|
//! \endcond
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Zone used to allocate memory that fits into slots.
|
//! Zone used to allocate memory that fits into slots.
|
||||||
Zone* _zone;
|
Zone* _zone;
|
||||||
//! Indexed slots containing released memory.
|
//! Indexed slots containing released memory.
|
||||||
@@ -469,6 +436,8 @@ public:
|
|||||||
//! Dynamic blocks for larger allocations (no slots).
|
//! Dynamic blocks for larger allocations (no slots).
|
||||||
DynamicBlock* _dynamicBlocks;
|
DynamicBlock* _dynamicBlocks;
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -496,9 +465,9 @@ public:
|
|||||||
//! It's the same as calling `reset(zone)`.
|
//! It's the same as calling `reset(zone)`.
|
||||||
inline void init(Zone* zone) noexcept { reset(zone); }
|
inline void init(Zone* zone) noexcept { reset(zone); }
|
||||||
|
|
||||||
//! Resets this `ZoneAllocator` and also forget about the current `Zone` which
|
//! Resets this `ZoneAllocator` and also forget about the current `Zone` which is attached (if any). Reset
|
||||||
//! is attached (if any). Reset optionally attaches a new `zone` passed, or
|
//! optionally attaches a new `zone` passed, or keeps the `ZoneAllocator` in an uninitialized state, if
|
||||||
//! keeps the `ZoneAllocator` in an uninitialized state, if `zone` is null.
|
//! `zone` is null.
|
||||||
ASMJIT_API void reset(Zone* zone = nullptr) noexcept;
|
ASMJIT_API void reset(Zone* zone = nullptr) noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -506,8 +475,7 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the assigned `Zone` of this allocator or null if this `ZoneAllocator`
|
//! Returns the assigned `Zone` of this allocator or null if this `ZoneAllocator` is not initialized.
|
||||||
//! is not initialized.
|
|
||||||
inline Zone* zone() const noexcept { return _zone; }
|
inline Zone* zone() const noexcept { return _zone; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -516,10 +484,10 @@ public:
|
|||||||
//! \name Internals
|
//! \name Internals
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Returns the slot index to be used for `size`. Returns `true` if a valid slot
|
//! Returns the slot index to be used for `size`. Returns `true` if a valid slot has been written to `slot` and
|
||||||
//! has been written to `slot` and `allocatedSize` has been filled with slot
|
//! `allocatedSize` has been filled with slot exact size (`allocatedSize` can be equal or slightly greater than
|
||||||
//! exact size (`allocatedSize` can be equal or slightly greater than `size`).
|
//! `size`).
|
||||||
static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot) noexcept {
|
static inline bool _getSlotIndex(size_t size, uint32_t& slot) noexcept {
|
||||||
ASMJIT_ASSERT(size > 0);
|
ASMJIT_ASSERT(size > 0);
|
||||||
if (size > kHiMaxSize)
|
if (size > kHiMaxSize)
|
||||||
return false;
|
return false;
|
||||||
@@ -533,7 +501,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! \overload
|
//! \overload
|
||||||
static ASMJIT_INLINE bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept {
|
static inline bool _getSlotIndex(size_t size, uint32_t& slot, size_t& allocatedSize) noexcept {
|
||||||
ASMJIT_ASSERT(size > 0);
|
ASMJIT_ASSERT(size > 0);
|
||||||
if (size > kHiMaxSize)
|
if (size > kHiMaxSize)
|
||||||
return false;
|
return false;
|
||||||
@@ -571,9 +539,8 @@ public:
|
|||||||
return _alloc(size, allocatedSize);
|
return _alloc(size, allocatedSize);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Like `alloc(size)`, but provides a second argument `allocatedSize` that
|
//! Like `alloc(size)`, but provides a second argument `allocatedSize` that provides a way to know how big
|
||||||
//! provides a way to know how big the block returned actually is. This is
|
//! the block returned actually is. This is useful for containers to prevent growing too early.
|
||||||
//! useful for containers to prevent growing too early.
|
|
||||||
inline void* alloc(size_t size, size_t& allocatedSize) noexcept {
|
inline void* alloc(size_t size, size_t& allocatedSize) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
return _alloc(size, allocatedSize);
|
return _alloc(size, allocatedSize);
|
||||||
@@ -621,9 +588,8 @@ public:
|
|||||||
return new(p) T(std::forward<Args>(args)...);
|
return new(p) T(std::forward<Args>(args)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Releases the memory previously allocated by `alloc()`. The `size` argument
|
//! Releases the memory previously allocated by `alloc()`. The `size` argument has to be the same as used to call
|
||||||
//! has to be the same as used to call `alloc()` or `allocatedSize` returned
|
//! `alloc()` or `allocatedSize` returned by `alloc()`.
|
||||||
//! by `alloc()`.
|
|
||||||
inline void release(void* p, size_t size) noexcept {
|
inline void release(void* p, size_t size) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
ASMJIT_ASSERT(p != nullptr);
|
ASMJIT_ASSERT(p != nullptr);
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
@@ -28,9 +10,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneHashBase - Prime Numbers
|
||||||
// [asmjit::ZoneHashBase - Helpers]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#define ASMJIT_POPULATE_PRIMES(ENTRY) \
|
#define ASMJIT_POPULATE_PRIMES(ENTRY) \
|
||||||
ENTRY(2 , 0x80000000, 32), /* [N * 0x80000000 >> 32] (rcp=2147483648) */ \
|
ENTRY(2 , 0x80000000, 32), /* [N * 0x80000000 >> 32] (rcp=2147483648) */ \
|
||||||
@@ -183,9 +164,8 @@ static const uint8_t ZoneHash_primeShift[] = {
|
|||||||
#undef E
|
#undef E
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneHashBase - Rehash
|
||||||
// [asmjit::ZoneHashBase - Rehash]
|
// =====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
void ZoneHashBase::_rehash(ZoneAllocator* allocator, uint32_t primeIndex) noexcept {
|
void ZoneHashBase::_rehash(ZoneAllocator* allocator, uint32_t primeIndex) noexcept {
|
||||||
ASMJIT_ASSERT(primeIndex < ASMJIT_ARRAY_SIZE(ZoneHash_primeArray));
|
ASMJIT_ASSERT(primeIndex < ASMJIT_ARRAY_SIZE(ZoneHash_primeArray));
|
||||||
@@ -225,9 +205,8 @@ void ZoneHashBase::_rehash(ZoneAllocator* allocator, uint32_t primeIndex) noexce
|
|||||||
allocator->release(oldData, oldCount * sizeof(ZoneHashNode*));
|
allocator->release(oldData, oldCount * sizeof(ZoneHashNode*));
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneHashBase - Operations
|
||||||
// [asmjit::ZoneHashBase - Ops]
|
// =========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
ZoneHashNode* ZoneHashBase::_insert(ZoneAllocator* allocator, ZoneHashNode* node) noexcept {
|
ZoneHashNode* ZoneHashBase::_insert(ZoneAllocator* allocator, ZoneHashNode* node) noexcept {
|
||||||
uint32_t hashMod = _calcMod(node->_hashCode);
|
uint32_t hashMod = _calcMod(node->_hashCode);
|
||||||
@@ -266,9 +245,8 @@ ZoneHashNode* ZoneHashBase::_remove(ZoneAllocator* allocator, ZoneHashNode* node
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneHashBase - Tests
|
||||||
// [asmjit::ZoneHash - Unit]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
struct MyHashNode : public ZoneHashNode {
|
struct MyHashNode : public ZoneHashNode {
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONEHASH_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONEHASH_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONEHASH_H_INCLUDED
|
#define ASMJIT_CORE_ZONEHASH_H_INCLUDED
|
||||||
@@ -31,14 +13,9 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneHashNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Node used by \ref ZoneHash template.
|
//! Node used by \ref ZoneHash template.
|
||||||
//!
|
//!
|
||||||
//! You must provide function `bool eq(const Key& key)` in order to make
|
//! You must provide function `bool eq(const Key& key)` in order to make `ZoneHash::get()` working.
|
||||||
//! `ZoneHash::get()` working.
|
|
||||||
class ZoneHashNode {
|
class ZoneHashNode {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneHashNode)
|
ASMJIT_NONCOPYABLE(ZoneHashNode)
|
||||||
@@ -56,10 +33,6 @@ public:
|
|||||||
uint32_t _customData;
|
uint32_t _customData;
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneHashBase]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Base class used by \ref ZoneHash template
|
//! Base class used by \ref ZoneHash template
|
||||||
class ZoneHashBase {
|
class ZoneHashBase {
|
||||||
public:
|
public:
|
||||||
@@ -162,16 +135,11 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneHash]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Low-level hash table specialized for storing string keys and POD values.
|
//! Low-level hash table specialized for storing string keys and POD values.
|
||||||
//!
|
//!
|
||||||
//! This hash table allows duplicates to be inserted (the API is so low
|
//! This hash table allows duplicates to be inserted (the API is so low level that it's up to you if you allow it or
|
||||||
//! level that it's up to you if you allow it or not, as you should first
|
//! not, as you should first `get()` the node and then modify it or insert a new node by using `insert()`, depending
|
||||||
//! `get()` the node and then modify it or insert a new node by using `insert()`,
|
//! on the intention).
|
||||||
//! depending on the intention).
|
|
||||||
template<typename NodeT>
|
template<typename NodeT>
|
||||||
class ZoneHash : public ZoneHashBase {
|
class ZoneHash : public ZoneHashBase {
|
||||||
public:
|
public:
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/zone.h"
|
#include "../core/zone.h"
|
||||||
@@ -27,9 +9,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneList - Tests
|
||||||
// [asmjit::ZoneList - Unit]
|
// ================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
class MyListNode : public ZoneListNode<MyListNode> {};
|
class MyListNode : public ZoneListNode<MyListNode> {};
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONELIST_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONELIST_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONELIST_H_INCLUDED
|
#define ASMJIT_CORE_ZONELIST_H_INCLUDED
|
||||||
@@ -31,17 +13,28 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneListNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Node used by \ref ZoneList template.
|
//! Node used by \ref ZoneList template.
|
||||||
template<typename NodeT>
|
template<typename NodeT>
|
||||||
class ZoneListNode {
|
class ZoneListNode {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneListNode)
|
ASMJIT_NONCOPYABLE(ZoneListNode)
|
||||||
|
|
||||||
NodeT* _listNodes[Globals::kLinkCount];
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
enum : size_t {
|
||||||
|
kNodeIndexPrev = 0,
|
||||||
|
kNodeIndexNext = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
NodeT* _listNodes[2];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -57,26 +50,37 @@ public:
|
|||||||
//! \name Accessors
|
//! \name Accessors
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline bool hasPrev() const noexcept { return _listNodes[Globals::kLinkPrev] != nullptr; }
|
inline bool hasPrev() const noexcept { return _listNodes[kNodeIndexPrev] != nullptr; }
|
||||||
inline bool hasNext() const noexcept { return _listNodes[Globals::kLinkNext] != nullptr; }
|
inline bool hasNext() const noexcept { return _listNodes[kNodeIndexNext] != nullptr; }
|
||||||
|
|
||||||
inline NodeT* prev() const noexcept { return _listNodes[Globals::kLinkPrev]; }
|
inline NodeT* prev() const noexcept { return _listNodes[kNodeIndexPrev]; }
|
||||||
inline NodeT* next() const noexcept { return _listNodes[Globals::kLinkNext]; }
|
inline NodeT* next() const noexcept { return _listNodes[kNodeIndexNext]; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneList<T>]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Zone allocated list container that uses nodes of `NodeT` type.
|
//! Zone allocated list container that uses nodes of `NodeT` type.
|
||||||
template <typename NodeT>
|
template <typename NodeT>
|
||||||
class ZoneList {
|
class ZoneList {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneList)
|
ASMJIT_NONCOPYABLE(ZoneList)
|
||||||
|
|
||||||
NodeT* _nodes[Globals::kLinkCount];
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
enum : size_t {
|
||||||
|
kNodeIndexFirst = 0,
|
||||||
|
kNodeIndexLast = 1
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
NodeT* _nodes[2];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -98,8 +102,8 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline bool empty() const noexcept { return _nodes[0] == nullptr; }
|
inline bool empty() const noexcept { return _nodes[0] == nullptr; }
|
||||||
inline NodeT* first() const noexcept { return _nodes[Globals::kLinkFirst]; }
|
inline NodeT* first() const noexcept { return _nodes[kNodeIndexFirst]; }
|
||||||
inline NodeT* last() const noexcept { return _nodes[Globals::kLinkLast]; }
|
inline NodeT* last() const noexcept { return _nodes[kNodeIndexLast]; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -140,11 +144,11 @@ public:
|
|||||||
node->_listNodes[ dir] = next;
|
node->_listNodes[ dir] = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void append(NodeT* node) noexcept { _addNode(node, Globals::kLinkLast); }
|
inline void append(NodeT* node) noexcept { _addNode(node, kNodeIndexLast); }
|
||||||
inline void prepend(NodeT* node) noexcept { _addNode(node, Globals::kLinkFirst); }
|
inline void prepend(NodeT* node) noexcept { _addNode(node, kNodeIndexFirst); }
|
||||||
|
|
||||||
inline void insertAfter(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, Globals::kLinkNext); }
|
inline void insertAfter(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, NodeT::kNodeIndexNext); }
|
||||||
inline void insertBefore(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, Globals::kLinkPrev); }
|
inline void insertBefore(NodeT* ref, NodeT* node) noexcept { _insertNode(ref, node, NodeT::kNodeIndexPrev); }
|
||||||
|
|
||||||
inline NodeT* unlink(NodeT* node) noexcept {
|
inline NodeT* unlink(NodeT* node) noexcept {
|
||||||
NodeT* prev = node->prev();
|
NodeT* prev = node->prev();
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/zone.h"
|
#include "../core/zone.h"
|
||||||
@@ -27,15 +9,14 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneStackBase - Init & Reset
|
||||||
// [asmjit::ZoneStackBase - Init / Reset]
|
// ============================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcept {
|
Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcept {
|
||||||
ZoneAllocator* oldAllocator = _allocator;
|
ZoneAllocator* oldAllocator = _allocator;
|
||||||
|
|
||||||
if (oldAllocator) {
|
if (oldAllocator) {
|
||||||
Block* block = _block[Globals::kLinkFirst];
|
Block* block = _block[kBlockIndexFirst];
|
||||||
while (block) {
|
while (block) {
|
||||||
Block* next = block->next();
|
Block* next = block->next();
|
||||||
oldAllocator->release(block, kBlockSize);
|
oldAllocator->release(block, kBlockSize);
|
||||||
@@ -43,8 +24,8 @@ Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcep
|
|||||||
}
|
}
|
||||||
|
|
||||||
_allocator = nullptr;
|
_allocator = nullptr;
|
||||||
_block[Globals::kLinkLeft] = nullptr;
|
_block[kBlockIndexFirst] = nullptr;
|
||||||
_block[Globals::kLinkRight] = nullptr;
|
_block[kBlockIndexLast] = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (allocator) {
|
if (allocator) {
|
||||||
@@ -52,22 +33,21 @@ Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcep
|
|||||||
if (ASMJIT_UNLIKELY(!block))
|
if (ASMJIT_UNLIKELY(!block))
|
||||||
return DebugUtils::errored(kErrorOutOfMemory);
|
return DebugUtils::errored(kErrorOutOfMemory);
|
||||||
|
|
||||||
block->_link[Globals::kLinkLeft] = nullptr;
|
block->_link[kBlockIndexPrev] = nullptr;
|
||||||
block->_link[Globals::kLinkRight] = nullptr;
|
block->_link[kBlockIndexNext] = nullptr;
|
||||||
block->_start = (uint8_t*)block + middleIndex;
|
block->_start = (uint8_t*)block + middleIndex;
|
||||||
block->_end = (uint8_t*)block + middleIndex;
|
block->_end = (uint8_t*)block + middleIndex;
|
||||||
|
|
||||||
_allocator = allocator;
|
_allocator = allocator;
|
||||||
_block[Globals::kLinkLeft] = block;
|
_block[kBlockIndexFirst] = block;
|
||||||
_block[Globals::kLinkRight] = block;
|
_block[kBlockIndexLast] = block;
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneStackBase - Operations
|
||||||
// [asmjit::ZoneStackBase - Ops]
|
// ==========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error ZoneStackBase::_prepareBlock(uint32_t side, size_t initialIndex) noexcept {
|
Error ZoneStackBase::_prepareBlock(uint32_t side, size_t initialIndex) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
@@ -109,9 +89,8 @@ void ZoneStackBase::_cleanupBlock(uint32_t side, size_t middleIndex) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneStack - Tests
|
||||||
// [asmjit::ZoneStack - Unit]
|
// =================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONESTACK_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONESTACK_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONESTACK_H_INCLUDED
|
#define ASMJIT_CORE_ZONESTACK_H_INCLUDED
|
||||||
@@ -31,24 +13,43 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneStackBase]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Base class used by \ref ZoneStack.
|
//! Base class used by \ref ZoneStack.
|
||||||
class ZoneStackBase {
|
class ZoneStackBase {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneStackBase)
|
ASMJIT_NONCOPYABLE(ZoneStackBase)
|
||||||
|
|
||||||
static constexpr uint32_t kBlockSize = ZoneAllocator::kHiMaxSize;
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
enum : size_t {
|
||||||
|
kBlockIndexPrev = 0,
|
||||||
|
kBlockIndexNext = 1,
|
||||||
|
|
||||||
|
kBlockIndexFirst = 0,
|
||||||
|
kBlockIndexLast = 1,
|
||||||
|
|
||||||
|
kBlockSize = ZoneAllocator::kHiMaxSize
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Types
|
||||||
|
//! \{
|
||||||
|
|
||||||
struct Block {
|
struct Block {
|
||||||
inline bool empty() const noexcept { return _start == _end; }
|
//! Next and previous blocks.
|
||||||
inline Block* prev() const noexcept { return _link[Globals::kLinkLeft]; }
|
Block* _link[2];
|
||||||
inline Block* next() const noexcept { return _link[Globals::kLinkRight]; }
|
//! Pointer to the start of the array.
|
||||||
|
void* _start;
|
||||||
|
//! Pointer to the end of the array.
|
||||||
|
void* _end;
|
||||||
|
|
||||||
inline void setPrev(Block* block) noexcept { _link[Globals::kLinkLeft] = block; }
|
inline bool empty() const noexcept { return _start == _end; }
|
||||||
inline void setNext(Block* block) noexcept { _link[Globals::kLinkRight] = block; }
|
inline Block* prev() const noexcept { return _link[kBlockIndexPrev]; }
|
||||||
|
inline Block* next() const noexcept { return _link[kBlockIndexNext]; }
|
||||||
|
|
||||||
|
inline void setPrev(Block* block) noexcept { _link[kBlockIndexPrev] = block; }
|
||||||
|
inline void setNext(Block* block) noexcept { _link[kBlockIndexNext] = block; }
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline T* start() const noexcept { return static_cast<T*>(_start); }
|
inline T* start() const noexcept { return static_cast<T*>(_start); }
|
||||||
@@ -74,18 +75,21 @@ public:
|
|||||||
|
|
||||||
return (uintptr_t)_end <= ((uintptr_t)this + kEndBlockIndex - sizeof(T));
|
return (uintptr_t)_end <= ((uintptr_t)this + kEndBlockIndex - sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
Block* _link[Globals::kLinkCount]; //!< Next and previous blocks.
|
|
||||||
void* _start; //!< Pointer to the start of the array.
|
|
||||||
void* _end; //!< Pointer to the end of the array.
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Allocator used to allocate data.
|
//! Allocator used to allocate data.
|
||||||
ZoneAllocator* _allocator;
|
ZoneAllocator* _allocator;
|
||||||
//! First and last blocks.
|
//! First and last blocks.
|
||||||
Block* _block[Globals::kLinkCount];
|
Block* _block[2];
|
||||||
|
|
||||||
//! \name Construction / Destruction
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline ZoneStackBase() noexcept {
|
inline ZoneStackBase() noexcept {
|
||||||
@@ -125,16 +129,15 @@ public:
|
|||||||
//! \endcond
|
//! \endcond
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneStack<T>]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Zone allocated stack container.
|
//! Zone allocated stack container.
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class ZoneStack : public ZoneStackBase {
|
class ZoneStack : public ZoneStackBase {
|
||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneStack)
|
ASMJIT_NONCOPYABLE(ZoneStack)
|
||||||
|
|
||||||
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
enum : uint32_t {
|
enum : uint32_t {
|
||||||
kNumBlockItems = uint32_t((kBlockSize - sizeof(Block)) / sizeof(T)),
|
kNumBlockItems = uint32_t((kBlockSize - sizeof(Block)) / sizeof(T)),
|
||||||
kStartBlockIndex = uint32_t(sizeof(Block)),
|
kStartBlockIndex = uint32_t(sizeof(Block)),
|
||||||
@@ -142,7 +145,9 @@ public:
|
|||||||
kEndBlockIndex = uint32_t(kStartBlockIndex + (kNumBlockItems ) * sizeof(T))
|
kEndBlockIndex = uint32_t(kStartBlockIndex + (kNumBlockItems ) * sizeof(T))
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \name Construction / Destruction
|
//! \}
|
||||||
|
|
||||||
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
inline ZoneStack() noexcept {}
|
inline ZoneStack() noexcept {}
|
||||||
@@ -155,13 +160,13 @@ public:
|
|||||||
//! \name Utilities
|
//! \name Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE Error prepend(T item) noexcept {
|
inline Error prepend(T item) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
Block* block = _block[Globals::kLinkFirst];
|
Block* block = _block[kBlockIndexFirst];
|
||||||
|
|
||||||
if (!block->canPrepend<T>()) {
|
if (!block->canPrepend<T>()) {
|
||||||
ASMJIT_PROPAGATE(_prepareBlock(Globals::kLinkFirst, kEndBlockIndex));
|
ASMJIT_PROPAGATE(_prepareBlock(kBlockIndexFirst, kEndBlockIndex));
|
||||||
block = _block[Globals::kLinkFirst];
|
block = _block[kBlockIndexFirst];
|
||||||
}
|
}
|
||||||
|
|
||||||
T* ptr = block->start<T>() - 1;
|
T* ptr = block->start<T>() - 1;
|
||||||
@@ -171,13 +176,13 @@ public:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE Error append(T item) noexcept {
|
inline Error append(T item) noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
Block* block = _block[Globals::kLinkLast];
|
Block* block = _block[kBlockIndexLast];
|
||||||
|
|
||||||
if (!block->canAppend<T>()) {
|
if (!block->canAppend<T>()) {
|
||||||
ASMJIT_PROPAGATE(_prepareBlock(Globals::kLinkLast, kStartBlockIndex));
|
ASMJIT_PROPAGATE(_prepareBlock(kBlockIndexLast, kStartBlockIndex));
|
||||||
block = _block[Globals::kLinkLast];
|
block = _block[kBlockIndexLast];
|
||||||
}
|
}
|
||||||
|
|
||||||
T* ptr = block->end<T>();
|
T* ptr = block->end<T>();
|
||||||
@@ -188,11 +193,11 @@ public:
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE T popFirst() noexcept {
|
inline T popFirst() noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
ASMJIT_ASSERT(!empty());
|
ASMJIT_ASSERT(!empty());
|
||||||
|
|
||||||
Block* block = _block[Globals::kLinkFirst];
|
Block* block = _block[kBlockIndexFirst];
|
||||||
ASMJIT_ASSERT(!block->empty());
|
ASMJIT_ASSERT(!block->empty());
|
||||||
|
|
||||||
T* ptr = block->start<T>();
|
T* ptr = block->start<T>();
|
||||||
@@ -200,16 +205,16 @@ public:
|
|||||||
|
|
||||||
block->setStart(ptr);
|
block->setStart(ptr);
|
||||||
if (block->empty())
|
if (block->empty())
|
||||||
_cleanupBlock(Globals::kLinkFirst, kMidBlockIndex);
|
_cleanupBlock(kBlockIndexFirst, kMidBlockIndex);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE T pop() noexcept {
|
inline T pop() noexcept {
|
||||||
ASMJIT_ASSERT(isInitialized());
|
ASMJIT_ASSERT(isInitialized());
|
||||||
ASMJIT_ASSERT(!empty());
|
ASMJIT_ASSERT(!empty());
|
||||||
|
|
||||||
Block* block = _block[Globals::kLinkLast];
|
Block* block = _block[kBlockIndexLast];
|
||||||
ASMJIT_ASSERT(!block->empty());
|
ASMJIT_ASSERT(!block->empty());
|
||||||
|
|
||||||
T* ptr = block->end<T>();
|
T* ptr = block->end<T>();
|
||||||
@@ -219,7 +224,7 @@ public:
|
|||||||
|
|
||||||
block->setEnd(ptr);
|
block->setEnd(ptr);
|
||||||
if (block->empty())
|
if (block->empty())
|
||||||
_cleanupBlock(Globals::kLinkLast, kMidBlockIndex);
|
_cleanupBlock(kBlockIndexLast, kMidBlockIndex);
|
||||||
|
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,28 +1,10 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_SMALLSTRING_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
||||||
#define ASMJIT_CORE_SMALLSTRING_H_INCLUDED
|
#define ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
||||||
|
|
||||||
#include "../core/globals.h"
|
#include "../core/globals.h"
|
||||||
#include "../core/zone.h"
|
#include "../core/zone.h"
|
||||||
@@ -32,10 +14,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneStringBase]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! A helper class used by \ref ZoneString implementation.
|
//! A helper class used by \ref ZoneString implementation.
|
||||||
struct ZoneStringBase {
|
struct ZoneStringBase {
|
||||||
union {
|
union {
|
||||||
@@ -74,28 +52,34 @@ struct ZoneStringBase {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneString<N>]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! A string template that can be zone allocated.
|
//! A string template that can be zone allocated.
|
||||||
//!
|
//!
|
||||||
//! Helps with creating strings that can be either statically allocated if they
|
//! Helps with creating strings that can be either statically allocated if they are small, or externally allocated
|
||||||
//! are small, or externally allocated in case their size exceeds the limit.
|
//! in case their size exceeds the limit. The `N` represents the size of the whole `ZoneString` structure, based on
|
||||||
//! The `N` represents the size of the whole `ZoneString` structure, based on
|
|
||||||
//! that size the maximum size of the internal buffer is determined.
|
//! that size the maximum size of the internal buffer is determined.
|
||||||
template<size_t N>
|
template<size_t N>
|
||||||
class ZoneString {
|
class ZoneString {
|
||||||
public:
|
public:
|
||||||
static constexpr uint32_t kWholeSize =
|
//! \name Constants
|
||||||
(N > sizeof(ZoneStringBase)) ? uint32_t(N) : uint32_t(sizeof(ZoneStringBase));
|
//! \{
|
||||||
static constexpr uint32_t kMaxEmbeddedSize = kWholeSize - 5;
|
|
||||||
|
enum : uint32_t {
|
||||||
|
kWholeSize = (N > sizeof(ZoneStringBase)) ? uint32_t(N) : uint32_t(sizeof(ZoneStringBase)),
|
||||||
|
kMaxEmbeddedSize = kWholeSize - 5
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
union {
|
union {
|
||||||
ZoneStringBase _base;
|
ZoneStringBase _base;
|
||||||
char _wholeData[kWholeSize];
|
char _wholeData[kWholeSize];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -120,9 +104,8 @@ public:
|
|||||||
|
|
||||||
//! Copies a new `data` of the given `size` to the string.
|
//! Copies a new `data` of the given `size` to the string.
|
||||||
//!
|
//!
|
||||||
//! If the `size` exceeds the internal buffer the given `zone` will be
|
//! If the `size` exceeds the internal buffer the given `zone` will be used to duplicate the data, otherwise
|
||||||
//! used to duplicate the data, otherwise the internal buffer will be
|
//! the internal buffer will be used as a storage.
|
||||||
//! used as a storage.
|
|
||||||
inline Error setData(Zone* zone, const char* data, size_t size) noexcept {
|
inline Error setData(Zone* zone, const char* data, size_t size) noexcept {
|
||||||
return _base.setData(zone, kMaxEmbeddedSize, data, size);
|
return _base.setData(zone, kMaxEmbeddedSize, data, size);
|
||||||
}
|
}
|
||||||
@@ -134,4 +117,4 @@ public:
|
|||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
#endif // ASMJIT_CORE_SMALLSTRING_H_INCLUDED
|
#endif // ASMJIT_CORE_ZONESTRING_H_INCLUDED
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
@@ -28,9 +10,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneTreeBase - Tests
|
||||||
// [asmjit::ZoneTree - Unit]
|
// ====================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
template<typename NodeT>
|
template<typename NodeT>
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONETREE_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONETREE_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONETREE_H_INCLUDED
|
#define ASMJIT_CORE_ZONETREE_H_INCLUDED
|
||||||
@@ -31,10 +13,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneTreeNode]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! RB-Tree node.
|
//! RB-Tree node.
|
||||||
//!
|
//!
|
||||||
//! The color is stored in a least significant bit of the `left` node.
|
//! The color is stored in a least significant bit of the `left` node.
|
||||||
@@ -44,12 +22,22 @@ class ZoneTreeNode {
|
|||||||
public:
|
public:
|
||||||
ASMJIT_NONCOPYABLE(ZoneTreeNode)
|
ASMJIT_NONCOPYABLE(ZoneTreeNode)
|
||||||
|
|
||||||
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
enum : uintptr_t {
|
enum : uintptr_t {
|
||||||
kRedMask = 0x1,
|
kRedMask = 0x1,
|
||||||
kPtrMask = ~kRedMask
|
kPtrMask = ~kRedMask
|
||||||
};
|
};
|
||||||
|
|
||||||
uintptr_t _rbNodeData[Globals::kLinkCount];
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
uintptr_t _rbNodeData[2];
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
@@ -123,10 +111,6 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneTree]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! RB-Tree.
|
//! RB-Tree.
|
||||||
template<typename NodeT>
|
template<typename NodeT>
|
||||||
class ZoneTree {
|
class ZoneTree {
|
||||||
@@ -164,7 +148,7 @@ public:
|
|||||||
std::swap(_root, other._root);
|
std::swap(_root, other._root);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename CompareT = Support::Compare<Support::kSortAscending>>
|
template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
||||||
void insert(NodeT* node, const CompareT& cmp = CompareT()) noexcept {
|
void insert(NodeT* node, const CompareT& cmp = CompareT()) noexcept {
|
||||||
// Node to insert must not contain garbage.
|
// Node to insert must not contain garbage.
|
||||||
ASMJIT_ASSERT(!node->hasLeft());
|
ASMJIT_ASSERT(!node->hasLeft());
|
||||||
@@ -176,18 +160,18 @@ public:
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZoneTreeNode head; // False root node,
|
ZoneTreeNode head; // False root node,
|
||||||
head._setRight(_root); // having root on the right.
|
head._setRight(_root); // having root on the right.
|
||||||
|
|
||||||
ZoneTreeNode* g = nullptr; // Grandparent.
|
ZoneTreeNode* g = nullptr; // Grandparent.
|
||||||
ZoneTreeNode* p = nullptr; // Parent.
|
ZoneTreeNode* p = nullptr; // Parent.
|
||||||
ZoneTreeNode* t = &head; // Iterator.
|
ZoneTreeNode* t = &head; // Iterator.
|
||||||
ZoneTreeNode* q = _root; // Query.
|
ZoneTreeNode* q = _root; // Query.
|
||||||
|
|
||||||
size_t dir = 0; // Direction for accessing child nodes.
|
size_t dir = 0; // Direction for accessing child nodes.
|
||||||
size_t last = 0; // Not needed to initialize, but makes some tools happy.
|
size_t last = 0; // Not needed to initialize, but makes some tools happy.
|
||||||
|
|
||||||
node->_makeRed(); // New nodes are always red and violations fixed appropriately.
|
node->_makeRed(); // New nodes are always red and violations fixed appropriately.
|
||||||
|
|
||||||
// Search down the tree.
|
// Search down the tree.
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@@ -229,7 +213,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Remove node from RBTree.
|
//! Remove node from RBTree.
|
||||||
template<typename CompareT = Support::Compare<Support::kSortAscending>>
|
template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
||||||
void remove(ZoneTreeNode* node, const CompareT& cmp = CompareT()) noexcept {
|
void remove(ZoneTreeNode* node, const CompareT& cmp = CompareT()) noexcept {
|
||||||
ZoneTreeNode head; // False root node,
|
ZoneTreeNode head; // False root node,
|
||||||
head._setRight(_root); // having root on the right.
|
head._setRight(_root); // having root on the right.
|
||||||
@@ -304,10 +288,9 @@ public:
|
|||||||
p->_setChild(p->_getRight() == q,
|
p->_setChild(p->_getRight() == q,
|
||||||
q->_getChild(q->_getLeft() == nullptr));
|
q->_getChild(q->_getLeft() == nullptr));
|
||||||
|
|
||||||
// NOTE: The original algorithm used a trick to just copy 'key/value' to
|
// NOTE: The original algorithm used a trick to just copy 'key/value' to `f` and mark `q` for deletion. But this
|
||||||
// `f` and mark `q` for deletion. But this is unacceptable here as we
|
// is unacceptable here as we really want to destroy the passed `node`. So, we have to make sure that we have
|
||||||
// really want to destroy the passed `node`. So, we have to make sure that
|
// really removed `f` and not `q`.
|
||||||
// we have really removed `f` and not `q`.
|
|
||||||
if (f != q) {
|
if (f != q) {
|
||||||
ASMJIT_ASSERT(f != &head);
|
ASMJIT_ASSERT(f != &head);
|
||||||
ASMJIT_ASSERT(f != gf);
|
ASMJIT_ASSERT(f != gf);
|
||||||
@@ -337,8 +320,8 @@ public:
|
|||||||
if (_root) _root->_makeBlack();
|
if (_root) _root->_makeBlack();
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename KeyT, typename CompareT = Support::Compare<Support::kSortAscending>>
|
template<typename KeyT, typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
||||||
ASMJIT_INLINE NodeT* get(const KeyT& key, const CompareT& cmp = CompareT()) const noexcept {
|
inline NodeT* get(const KeyT& key, const CompareT& cmp = CompareT()) const noexcept {
|
||||||
ZoneTreeNode* node = _root;
|
ZoneTreeNode* node = _root;
|
||||||
while (node) {
|
while (node) {
|
||||||
auto result = cmp(*static_cast<const NodeT*>(node), key);
|
auto result = cmp(*static_cast<const NodeT*>(node), key);
|
||||||
@@ -359,7 +342,7 @@ public:
|
|||||||
static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return ZoneTreeNode::_isValidRed(node); }
|
static inline bool _isValidRed(ZoneTreeNode* node) noexcept { return ZoneTreeNode::_isValidRed(node); }
|
||||||
|
|
||||||
//! Single rotation.
|
//! Single rotation.
|
||||||
static ASMJIT_INLINE ZoneTreeNode* _singleRotate(ZoneTreeNode* root, size_t dir) noexcept {
|
static inline ZoneTreeNode* _singleRotate(ZoneTreeNode* root, size_t dir) noexcept {
|
||||||
ZoneTreeNode* save = root->_getChild(!dir);
|
ZoneTreeNode* save = root->_getChild(!dir);
|
||||||
root->_setChild(!dir, save->_getChild(dir));
|
root->_setChild(!dir, save->_getChild(dir));
|
||||||
save->_setChild( dir, root);
|
save->_setChild( dir, root);
|
||||||
@@ -369,7 +352,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Double rotation.
|
//! Double rotation.
|
||||||
static ASMJIT_INLINE ZoneTreeNode* _doubleRotate(ZoneTreeNode* root, size_t dir) noexcept {
|
static inline ZoneTreeNode* _doubleRotate(ZoneTreeNode* root, size_t dir) noexcept {
|
||||||
root->_setChild(!dir, _singleRotate(root->_getChild(!dir), !dir));
|
root->_setChild(!dir, _singleRotate(root->_getChild(!dir), !dir));
|
||||||
return _singleRotate(root, dir);
|
return _singleRotate(root, dir);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#include "../core/api-build_p.h"
|
#include "../core/api-build_p.h"
|
||||||
#include "../core/support.h"
|
#include "../core/support.h"
|
||||||
@@ -28,9 +10,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneVectorBase - Helpers
|
||||||
// [asmjit::ZoneVectorBase - Helpers]
|
// ========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error ZoneVectorBase::_grow(ZoneAllocator* allocator, uint32_t sizeOfT, uint32_t n) noexcept {
|
Error ZoneVectorBase::_grow(ZoneAllocator* allocator, uint32_t sizeOfT, uint32_t n) noexcept {
|
||||||
uint32_t threshold = Globals::kGrowThreshold / sizeOfT;
|
uint32_t threshold = Globals::kGrowThreshold / sizeOfT;
|
||||||
@@ -112,9 +93,8 @@ Error ZoneVectorBase::_resize(ZoneAllocator* allocator, uint32_t sizeOfT, uint32
|
|||||||
return kErrorOk;
|
return kErrorOk;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneBitVector - Operations
|
||||||
// [asmjit::ZoneBitVector - Ops]
|
// ==========================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
Error ZoneBitVector::copyFrom(ZoneAllocator* allocator, const ZoneBitVector& other) noexcept {
|
Error ZoneBitVector::copyFrom(ZoneAllocator* allocator, const ZoneBitVector& other) noexcept {
|
||||||
BitWord* data = _data;
|
BitWord* data = _data;
|
||||||
@@ -280,9 +260,8 @@ Error ZoneBitVector::_append(ZoneAllocator* allocator, bool value) noexcept {
|
|||||||
return _resize(allocator, newSize, idealCapacity, value);
|
return _resize(allocator, newSize, idealCapacity, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ============================================================================
|
// ZoneVector / ZoneBitVector - Tests
|
||||||
// [asmjit::ZoneVector / ZoneBitVector - Unit]
|
// ==================================
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
#if defined(ASMJIT_TEST)
|
#if defined(ASMJIT_TEST)
|
||||||
template<typename T>
|
template<typename T>
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_CORE_ZONEVECTOR_H_INCLUDED
|
#ifndef ASMJIT_CORE_ZONEVECTOR_H_INCLUDED
|
||||||
#define ASMJIT_CORE_ZONEVECTOR_H_INCLUDED
|
#define ASMJIT_CORE_ZONEVECTOR_H_INCLUDED
|
||||||
@@ -32,10 +14,6 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
//! \addtogroup asmjit_zone
|
//! \addtogroup asmjit_zone
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneVectorBase]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Base class used by \ref ZoneVector template.
|
//! Base class used by \ref ZoneVector template.
|
||||||
class ZoneVectorBase {
|
class ZoneVectorBase {
|
||||||
public:
|
public:
|
||||||
@@ -129,10 +107,6 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneVector<T>]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Template used to store and manage array of Zone allocated data.
|
//! Template used to store and manage array of Zone allocated data.
|
||||||
//!
|
//!
|
||||||
//! This template has these advantages over other std::vector<>:
|
//! This template has these advantages over other std::vector<>:
|
||||||
@@ -213,10 +187,10 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Swaps this vector with `other`.
|
//! Swaps this vector with `other`.
|
||||||
inline void swap(ZoneVector<T>& other) noexcept { _swap(other); }
|
ASMJIT_FORCE_INLINE void swap(ZoneVector<T>& other) noexcept { _swap(other); }
|
||||||
|
|
||||||
//! Prepends `item` to the vector.
|
//! Prepends `item` to the vector.
|
||||||
inline Error prepend(ZoneAllocator* allocator, const T& item) noexcept {
|
ASMJIT_FORCE_INLINE Error prepend(ZoneAllocator* allocator, const T& item) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_size == _capacity))
|
if (ASMJIT_UNLIKELY(_size == _capacity))
|
||||||
ASMJIT_PROPAGATE(grow(allocator, 1));
|
ASMJIT_PROPAGATE(grow(allocator, 1));
|
||||||
|
|
||||||
@@ -228,7 +202,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Inserts an `item` at the specified `index`.
|
//! Inserts an `item` at the specified `index`.
|
||||||
inline Error insert(ZoneAllocator* allocator, size_t index, const T& item) noexcept {
|
ASMJIT_FORCE_INLINE Error insert(ZoneAllocator* allocator, size_t index, const T& item) noexcept {
|
||||||
ASMJIT_ASSERT(index <= _size);
|
ASMJIT_ASSERT(index <= _size);
|
||||||
|
|
||||||
if (ASMJIT_UNLIKELY(_size == _capacity))
|
if (ASMJIT_UNLIKELY(_size == _capacity))
|
||||||
@@ -243,7 +217,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Appends `item` to the vector.
|
//! Appends `item` to the vector.
|
||||||
inline Error append(ZoneAllocator* allocator, const T& item) noexcept {
|
ASMJIT_FORCE_INLINE Error append(ZoneAllocator* allocator, const T& item) noexcept {
|
||||||
if (ASMJIT_UNLIKELY(_size == _capacity))
|
if (ASMJIT_UNLIKELY(_size == _capacity))
|
||||||
ASMJIT_PROPAGATE(grow(allocator, 1));
|
ASMJIT_PROPAGATE(grow(allocator, 1));
|
||||||
|
|
||||||
@@ -254,7 +228,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Appends `other` vector at the end of this vector.
|
//! Appends `other` vector at the end of this vector.
|
||||||
inline Error concat(ZoneAllocator* allocator, const ZoneVector<T>& other) noexcept {
|
ASMJIT_FORCE_INLINE Error concat(ZoneAllocator* allocator, const ZoneVector<T>& other) noexcept {
|
||||||
uint32_t size = other._size;
|
uint32_t size = other._size;
|
||||||
if (_capacity - _size < size)
|
if (_capacity - _size < size)
|
||||||
ASMJIT_PROPAGATE(grow(allocator, size));
|
ASMJIT_PROPAGATE(grow(allocator, size));
|
||||||
@@ -269,10 +243,9 @@ public:
|
|||||||
|
|
||||||
//! Prepends `item` to the vector (unsafe case).
|
//! Prepends `item` to the vector (unsafe case).
|
||||||
//!
|
//!
|
||||||
//! Can only be used together with `willGrow()`. If `willGrow(N)` returns
|
//! Can only be used together with `willGrow()`. If `willGrow(N)` returns `kErrorOk` then N elements
|
||||||
//! `kErrorOk` then N elements can be added to the vector without checking
|
//! can be added to the vector without checking if there is a place for them. Used mostly internally.
|
||||||
//! if there is a place for them. Used mostly internally.
|
ASMJIT_FORCE_INLINE void prependUnsafe(const T& item) noexcept {
|
||||||
inline void prependUnsafe(const T& item) noexcept {
|
|
||||||
ASMJIT_ASSERT(_size < _capacity);
|
ASMJIT_ASSERT(_size < _capacity);
|
||||||
T* data = static_cast<T*>(_data);
|
T* data = static_cast<T*>(_data);
|
||||||
|
|
||||||
@@ -285,10 +258,9 @@ public:
|
|||||||
|
|
||||||
//! Append s`item` to the vector (unsafe case).
|
//! Append s`item` to the vector (unsafe case).
|
||||||
//!
|
//!
|
||||||
//! Can only be used together with `willGrow()`. If `willGrow(N)` returns
|
//! Can only be used together with `willGrow()`. If `willGrow(N)` returns `kErrorOk` then N elements
|
||||||
//! `kErrorOk` then N elements can be added to the vector without checking
|
//! can be added to the vector without checking if there is a place for them. Used mostly internally.
|
||||||
//! if there is a place for them. Used mostly internally.
|
ASMJIT_FORCE_INLINE void appendUnsafe(const T& item) noexcept {
|
||||||
inline void appendUnsafe(const T& item) noexcept {
|
|
||||||
ASMJIT_ASSERT(_size < _capacity);
|
ASMJIT_ASSERT(_size < _capacity);
|
||||||
|
|
||||||
memcpy(static_cast<T*>(_data) + _size, &item, sizeof(T));
|
memcpy(static_cast<T*>(_data) + _size, &item, sizeof(T));
|
||||||
@@ -296,7 +268,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Inserts an `item` at the specified `index` (unsafe case).
|
//! Inserts an `item` at the specified `index` (unsafe case).
|
||||||
inline void insertUnsafe(size_t index, const T& item) noexcept {
|
ASMJIT_FORCE_INLINE void insertUnsafe(size_t index, const T& item) noexcept {
|
||||||
ASMJIT_ASSERT(_size < _capacity);
|
ASMJIT_ASSERT(_size < _capacity);
|
||||||
ASMJIT_ASSERT(index <= _size);
|
ASMJIT_ASSERT(index <= _size);
|
||||||
|
|
||||||
@@ -306,7 +278,7 @@ public:
|
|||||||
_size++;
|
_size++;
|
||||||
}
|
}
|
||||||
//! Concatenates all items of `other` at the end of the vector.
|
//! Concatenates all items of `other` at the end of the vector.
|
||||||
inline void concatUnsafe(const ZoneVector<T>& other) noexcept {
|
ASMJIT_FORCE_INLINE void concatUnsafe(const ZoneVector<T>& other) noexcept {
|
||||||
uint32_t size = other._size;
|
uint32_t size = other._size;
|
||||||
ASMJIT_ASSERT(_capacity - _size >= size);
|
ASMJIT_ASSERT(_capacity - _size >= size);
|
||||||
|
|
||||||
@@ -317,7 +289,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! Returns index of the given `val` or `Globals::kNotFound` if it doesn't exist.
|
//! Returns index of the given `val` or `Globals::kNotFound` if it doesn't exist.
|
||||||
inline uint32_t indexOf(const T& val) const noexcept {
|
ASMJIT_FORCE_INLINE uint32_t indexOf(const T& val) const noexcept {
|
||||||
const T* data = static_cast<const T*>(_data);
|
const T* data = static_cast<const T*>(_data);
|
||||||
uint32_t size = _size;
|
uint32_t size = _size;
|
||||||
|
|
||||||
@@ -351,7 +323,7 @@ public:
|
|||||||
return data()[index];
|
return data()[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename CompareT = Support::Compare<Support::kSortAscending>>
|
template<typename CompareT = Support::Compare<Support::SortOrder::kAscending>>
|
||||||
inline void sort(const CompareT& cmp = CompareT()) noexcept {
|
inline void sort(const CompareT& cmp = CompareT()) noexcept {
|
||||||
Support::qSort<T, CompareT>(data(), size(), cmp);
|
Support::qSort<T, CompareT>(data(), size(), cmp);
|
||||||
}
|
}
|
||||||
@@ -370,18 +342,16 @@ public:
|
|||||||
|
|
||||||
//! Returns a reference to the first element of the vector.
|
//! Returns a reference to the first element of the vector.
|
||||||
//!
|
//!
|
||||||
//! \note The vector must have at least one element. Attempting to use
|
//! \note The vector must have at least one element. Attempting to use `first()` on empty vector will trigger
|
||||||
//! `first()` on empty vector will trigger an assertion failure in debug
|
//! an assertion failure in debug builds.
|
||||||
//! builds.
|
|
||||||
inline T& first() noexcept { return operator[](0); }
|
inline T& first() noexcept { return operator[](0); }
|
||||||
//! \overload
|
//! \overload
|
||||||
inline const T& first() const noexcept { return operator[](0); }
|
inline const T& first() const noexcept { return operator[](0); }
|
||||||
|
|
||||||
//! Returns a reference to the last element of the vector.
|
//! Returns a reference to the last element of the vector.
|
||||||
//!
|
//!
|
||||||
//! \note The vector must have at least one element. Attempting to use
|
//! \note The vector must have at least one element. Attempting to use `last()` on empty vector will trigger
|
||||||
//! `last()` on empty vector will trigger an assertion failure in debug
|
//! an assertion failure in debug builds.
|
||||||
//! builds.
|
|
||||||
inline T& last() noexcept { return operator[](_size - 1); }
|
inline T& last() noexcept { return operator[](_size - 1); }
|
||||||
//! \overload
|
//! \overload
|
||||||
inline const T& last() const noexcept { return operator[](_size - 1); }
|
inline const T& last() const noexcept { return operator[](_size - 1); }
|
||||||
@@ -403,9 +373,8 @@ public:
|
|||||||
|
|
||||||
//! Resizes the vector to hold `n` elements.
|
//! Resizes the vector to hold `n` elements.
|
||||||
//!
|
//!
|
||||||
//! If `n` is greater than the current size then the additional elements'
|
//! If `n` is greater than the current size then the additional elements' content will be initialized to zero.
|
||||||
//! content will be initialized to zero. If `n` is less than the current
|
//! If `n` is less than the current size then the vector will be truncated to exactly `n` elements.
|
||||||
//! size then the vector will be truncated to exactly `n` elements.
|
|
||||||
inline Error resize(ZoneAllocator* allocator, uint32_t n) noexcept {
|
inline Error resize(ZoneAllocator* allocator, uint32_t n) noexcept {
|
||||||
return ZoneVectorBase::_resize(allocator, sizeof(T), n);
|
return ZoneVectorBase::_resize(allocator, sizeof(T), n);
|
||||||
}
|
}
|
||||||
@@ -422,15 +391,24 @@ public:
|
|||||||
//! \}
|
//! \}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
|
||||||
// [asmjit::ZoneBitVector]
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
//! Zone-allocated bit vector.
|
//! Zone-allocated bit vector.
|
||||||
class ZoneBitVector {
|
class ZoneBitVector {
|
||||||
public:
|
public:
|
||||||
typedef Support::BitWord BitWord;
|
typedef Support::BitWord BitWord;
|
||||||
static constexpr uint32_t kBitWordSizeInBits = Support::kBitWordSizeInBits;
|
|
||||||
|
ASMJIT_NONCOPYABLE(ZoneBitVector)
|
||||||
|
|
||||||
|
//! \name Constants
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
enum : uint32_t {
|
||||||
|
kBitWordSizeInBits = Support::kBitWordSizeInBits
|
||||||
|
};
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Members
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Bits.
|
//! Bits.
|
||||||
BitWord* _data = nullptr;
|
BitWord* _data = nullptr;
|
||||||
@@ -439,7 +417,7 @@ public:
|
|||||||
//! Capacity of the bit-vector (in bits).
|
//! Capacity of the bit-vector (in bits).
|
||||||
uint32_t _capacity = 0;
|
uint32_t _capacity = 0;
|
||||||
|
|
||||||
ASMJIT_NONCOPYABLE(ZoneBitVector)
|
//! \}
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
//! \name Internal
|
//! \name Internal
|
||||||
@@ -548,7 +526,7 @@ public:
|
|||||||
Support::bitVectorFlipBit(_data, index);
|
Support::bitVectorFlipBit(_data, index);
|
||||||
}
|
}
|
||||||
|
|
||||||
ASMJIT_INLINE Error append(ZoneAllocator* allocator, bool value) noexcept {
|
ASMJIT_FORCE_INLINE Error append(ZoneAllocator* allocator, bool value) noexcept {
|
||||||
uint32_t index = _size;
|
uint32_t index = _size;
|
||||||
if (ASMJIT_UNLIKELY(index >= _capacity))
|
if (ASMJIT_UNLIKELY(index >= _capacity))
|
||||||
return _append(allocator, value);
|
return _append(allocator, value);
|
||||||
@@ -567,35 +545,34 @@ public:
|
|||||||
|
|
||||||
ASMJIT_API Error copyFrom(ZoneAllocator* allocator, const ZoneBitVector& other) noexcept;
|
ASMJIT_API Error copyFrom(ZoneAllocator* allocator, const ZoneBitVector& other) noexcept;
|
||||||
|
|
||||||
inline void clearAll() noexcept {
|
ASMJIT_FORCE_INLINE void clearAll() noexcept {
|
||||||
_zeroBits(_data, _wordsPerBits(_size));
|
_zeroBits(_data, _wordsPerBits(_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void fillAll() noexcept {
|
ASMJIT_FORCE_INLINE void fillAll() noexcept {
|
||||||
_fillBits(_data, _wordsPerBits(_size));
|
_fillBits(_data, _wordsPerBits(_size));
|
||||||
_clearUnusedBits();
|
_clearUnusedBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void clearBits(uint32_t start, uint32_t count) noexcept {
|
ASMJIT_FORCE_INLINE void clearBits(uint32_t start, uint32_t count) noexcept {
|
||||||
ASMJIT_ASSERT(start <= _size);
|
ASMJIT_ASSERT(start <= _size);
|
||||||
ASMJIT_ASSERT(_size - start >= count);
|
ASMJIT_ASSERT(_size - start >= count);
|
||||||
|
|
||||||
Support::bitVectorClear(_data, start, count);
|
Support::bitVectorClear(_data, start, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void fillBits(uint32_t start, uint32_t count) noexcept {
|
ASMJIT_FORCE_INLINE void fillBits(uint32_t start, uint32_t count) noexcept {
|
||||||
ASMJIT_ASSERT(start <= _size);
|
ASMJIT_ASSERT(start <= _size);
|
||||||
ASMJIT_ASSERT(_size - start >= count);
|
ASMJIT_ASSERT(_size - start >= count);
|
||||||
|
|
||||||
Support::bitVectorFill(_data, start, count);
|
Support::bitVectorFill(_data, start, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Performs a logical bitwise AND between bits specified in this array and bits
|
//! Performs a logical bitwise AND between bits specified in this array and bits in `other`. If `other` has less
|
||||||
//! in `other`. If `other` has less bits than `this` then all remaining bits are
|
//! bits than `this` then all remaining bits are set to zero.
|
||||||
//! set to zero.
|
|
||||||
//!
|
//!
|
||||||
//! \note The size of the BitVector is unaffected by this operation.
|
//! \note The size of the BitVector is unaffected by this operation.
|
||||||
inline void and_(const ZoneBitVector& other) noexcept {
|
ASMJIT_FORCE_INLINE void and_(const ZoneBitVector& other) noexcept {
|
||||||
BitWord* dst = _data;
|
BitWord* dst = _data;
|
||||||
const BitWord* src = other._data;
|
const BitWord* src = other._data;
|
||||||
|
|
||||||
@@ -615,12 +592,11 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Performs a logical bitwise AND between bits specified in this array and
|
//! Performs a logical bitwise AND between bits specified in this array and negated bits in `other`. If `other`
|
||||||
//! negated bits in `other`. If `other` has less bits than `this` then all
|
//! has less bits than `this` then all remaining bits are kept intact.
|
||||||
//! remaining bits are kept intact.
|
|
||||||
//!
|
//!
|
||||||
//! \note The size of the BitVector is unaffected by this operation.
|
//! \note The size of the BitVector is unaffected by this operation.
|
||||||
inline void andNot(const ZoneBitVector& other) noexcept {
|
ASMJIT_FORCE_INLINE void andNot(const ZoneBitVector& other) noexcept {
|
||||||
BitWord* dst = _data;
|
BitWord* dst = _data;
|
||||||
const BitWord* src = other._data;
|
const BitWord* src = other._data;
|
||||||
|
|
||||||
@@ -629,12 +605,11 @@ public:
|
|||||||
dst[i] = dst[i] & ~src[i];
|
dst[i] = dst[i] & ~src[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
//! Performs a logical bitwise OP between bits specified in this array and bits
|
//! Performs a logical bitwise OP between bits specified in this array and bits in `other`. If `other` has less
|
||||||
//! in `other`. If `other` has less bits than `this` then all remaining bits
|
//! bits than `this` then all remaining bits are kept intact.
|
||||||
//! are kept intact.
|
|
||||||
//!
|
//!
|
||||||
//! \note The size of the BitVector is unaffected by this operation.
|
//! \note The size of the BitVector is unaffected by this operation.
|
||||||
inline void or_(const ZoneBitVector& other) noexcept {
|
ASMJIT_FORCE_INLINE void or_(const ZoneBitVector& other) noexcept {
|
||||||
BitWord* dst = _data;
|
BitWord* dst = _data;
|
||||||
const BitWord* src = other._data;
|
const BitWord* src = other._data;
|
||||||
|
|
||||||
@@ -644,15 +619,16 @@ public:
|
|||||||
_clearUnusedBits();
|
_clearUnusedBits();
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void _clearUnusedBits() noexcept {
|
ASMJIT_FORCE_INLINE void _clearUnusedBits() noexcept {
|
||||||
uint32_t idx = _size / kBitWordSizeInBits;
|
uint32_t idx = _size / kBitWordSizeInBits;
|
||||||
uint32_t bit = _size % kBitWordSizeInBits;
|
uint32_t bit = _size % kBitWordSizeInBits;
|
||||||
|
|
||||||
if (!bit) return;
|
if (!bit)
|
||||||
|
return;
|
||||||
_data[idx] &= (BitWord(1) << bit) - 1u;
|
_data[idx] &= (BitWord(1) << bit) - 1u;
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool eq(const ZoneBitVector& other) const noexcept {
|
ASMJIT_FORCE_INLINE bool eq(const ZoneBitVector& other) const noexcept {
|
||||||
if (_size != other._size)
|
if (_size != other._size)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@@ -691,14 +667,14 @@ public:
|
|||||||
|
|
||||||
class ForEachBitSet : public Support::BitVectorIterator<BitWord> {
|
class ForEachBitSet : public Support::BitVectorIterator<BitWord> {
|
||||||
public:
|
public:
|
||||||
ASMJIT_INLINE explicit ForEachBitSet(const ZoneBitVector& bitVector) noexcept
|
inline explicit ForEachBitSet(const ZoneBitVector& bitVector) noexcept
|
||||||
: Support::BitVectorIterator<BitWord>(bitVector.data(), bitVector.sizeInBitWords()) {}
|
: Support::BitVectorIterator<BitWord>(bitVector.data(), bitVector.sizeInBitWords()) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
template<class Operator>
|
template<class Operator>
|
||||||
class ForEachBitOp : public Support::BitVectorOpIterator<BitWord, Operator> {
|
class ForEachBitOp : public Support::BitVectorOpIterator<BitWord, Operator> {
|
||||||
public:
|
public:
|
||||||
ASMJIT_INLINE ForEachBitOp(const ZoneBitVector& a, const ZoneBitVector& b) noexcept
|
inline ForEachBitOp(const ZoneBitVector& a, const ZoneBitVector& b) noexcept
|
||||||
: Support::BitVectorOpIterator<BitWord, Operator>(a.data(), b.data(), a.sizeInBitWords()) {
|
: Support::BitVectorOpIterator<BitWord, Operator>(a.data(), b.data(), a.sizeInBitWords()) {
|
||||||
ASMJIT_ASSERT(a.size() == b.size());
|
ASMJIT_ASSERT(a.size() == b.size());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_X86_H_INCLUDED
|
#ifndef ASMJIT_X86_H_INCLUDED
|
||||||
#define ASMJIT_X86_H_INCLUDED
|
#define ASMJIT_X86_H_INCLUDED
|
||||||
@@ -40,15 +22,14 @@
|
|||||||
//! ### Supported Instructions
|
//! ### Supported Instructions
|
||||||
//!
|
//!
|
||||||
//! - Emitters:
|
//! - Emitters:
|
||||||
//! - \ref x86::EmitterExplicitT - Provides all instructions that use
|
//! - \ref x86::EmitterExplicitT - Provides all instructions that use explicit operands, provides also utility
|
||||||
//! explicit operands, provides also utility functions. The member
|
//! functions. The member functions provided are part of all X86 emitters.
|
||||||
//! functions provided are part of all X86 emitters.
|
//! - \ref x86::EmitterImplicitT - Provides all instructions that use implicit operands, these cannot be used
|
||||||
//! - \ref x86::EmitterImplicitT - Provides all instructions that use
|
//! with \ref x86::Compiler.
|
||||||
//! implicit operands, these cannot be used with \ref x86::Compiler.
|
|
||||||
//!
|
//!
|
||||||
//! - Instruction representation:
|
//! - Instruction representation:
|
||||||
//! - \ref x86::Inst::Id - instruction identifiers.
|
//! - \ref x86::Inst::Id - Provides instruction identifiers for both X86/X86_64 architectures.
|
||||||
//! - \ref x86::Inst::Options - instruction options.
|
//! - \ref InstOptions - Provides generic and X86/X86_64 specific options.
|
||||||
//!
|
//!
|
||||||
//! ### Register Operands
|
//! ### Register Operands
|
||||||
//!
|
//!
|
||||||
@@ -74,34 +55,28 @@
|
|||||||
//!
|
//!
|
||||||
//! ### Memory Operands
|
//! ### Memory Operands
|
||||||
//!
|
//!
|
||||||
//! - \ref x86::Mem - X86/X64 memory operand that provides support for all
|
//! - \ref x86::Mem - X86/X64 memory operand that provides support for all X86 and X64 addressing features
|
||||||
//! X86 and X64 addressing features including absolute addresses, index
|
//! including absolute addresses, index scales, and segment override prefixes.
|
||||||
//! scales, and segment override prefixes.
|
|
||||||
//!
|
|
||||||
//! ### Other
|
|
||||||
//!
|
|
||||||
//! - \ref x86::Features - X86/X64 CPU features on top of \ref BaseFeatures.
|
|
||||||
//!
|
//!
|
||||||
//! ### Status and Control Words
|
//! ### Status and Control Words
|
||||||
//!
|
//!
|
||||||
//! - \ref asmjit::x86::FpuWord::Status - FPU status word.
|
//! - \ref x86::FpuStatusWord - FPU status word bits / decomposition.
|
||||||
//! - \ref asmjit::x86::FpuWord::Control - FPU control word.
|
//! - \ref x86::FpuControlWord - FPU control word bits / decomposition.
|
||||||
//!
|
//!
|
||||||
//! ### Predicates
|
//! ### Predicates (immediate values)
|
||||||
//!
|
//!
|
||||||
//! - \ref x86::Predicate - namespace that provides X86/X64 predicates.
|
//! - \ref x86::CmpImm - `CMP[PD|PS|SD|SS]` predicate (SSE+).
|
||||||
//! - \ref x86::Predicate::Cmp - `CMP[PD|PS|SD|SS]` predicate (SSE+).
|
//! - \ref x86::PCmpStrImm - `[V]PCMP[I|E]STR[I|M]` predicate (SSE4.1+, AVX+).
|
||||||
//! - \ref x86::Predicate::PCmpStr - `[V]PCMP[I|E]STR[I|M]` predicate (SSE4.1+).
|
//! - \ref x86::RoundImm - `[V]ROUND[PD|PS|SD|SS]` predicate (SSE+, AVX+).
|
||||||
//! - \ref x86::Predicate::Round - `ROUND[PD|PS|SD|SS]` predicate (SSE+).
|
//! - \ref x86::VCmpImm - `VCMP[PD|PS|SD|SS]` predicate (AVX+).
|
||||||
//! - \ref x86::Predicate::VCmp - `VCMP[PD|PS|SD|SS]` predicate (AVX+).
|
//! - \ref x86::VFixupImm - `VFIXUPIMM[PD|PS|SD|SS]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VFixupImm - `VFIXUPIMM[PD|PS|SD|SS]` predicate (AVX512+).
|
//! - \ref x86::VFPClassImm - `VFPCLASS[PD|PS|SD|SS]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VFPClass - `VFPCLASS[PD|PS|SD|SS]` predicate (AVX512+).
|
//! - \ref x86::VGetMantImm - `VGETMANT[PD|PS|SD|SS]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VGetMant - `VGETMANT[PD|PS|SD|SS]` predicate (AVX512+).
|
//! - \ref x86::VPCmpImm - `VPCMP[U][B|W|D|Q]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VPCmp - `VPCMP[U][B|W|D|Q]` predicate (AVX512+).
|
//! - \ref x86::VPComImm - `VPCOM[U][B|W|D|Q]` predicate (XOP).
|
||||||
//! - \ref x86::Predicate::VPCom - `VPCOM[U][B|W|D|Q]` predicate (XOP).
|
//! - \ref x86::VRangeImm - `VRANGE[PD|PS|SD|SS]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VRange - `VRANGE[PD|PS|SD|SS]` predicate (AVX512+).
|
//! - \ref x86::VReduceImm - `REDUCE[PD|PS|SD|SS]` predicate (AVX512+).
|
||||||
//! - \ref x86::Predicate::VReduce - `REDUCE[PD|PS|SD|SS]` predicate (AVX512+).
|
//! - \ref x86::TLogImm - `VPTERNLOG[D|Q]` predicate and operations (AVX512+).
|
||||||
//! - \ref x86::TLog - namespace that provides `VPTERNLOG[D|Q]` predicate / operations.
|
|
||||||
|
|
||||||
#include "core.h"
|
#include "core.h"
|
||||||
|
|
||||||
@@ -110,7 +85,6 @@
|
|||||||
#include "x86/x86builder.h"
|
#include "x86/x86builder.h"
|
||||||
#include "x86/x86compiler.h"
|
#include "x86/x86compiler.h"
|
||||||
#include "x86/x86emitter.h"
|
#include "x86/x86emitter.h"
|
||||||
#include "x86/x86features.h"
|
|
||||||
#include "x86/x86globals.h"
|
#include "x86/x86globals.h"
|
||||||
#include "x86/x86instdb.h"
|
#include "x86/x86instdb.h"
|
||||||
#include "x86/x86operand.h"
|
#include "x86/x86operand.h"
|
||||||
|
|||||||
@@ -1,25 +1,7 @@
|
|||||||
// AsmJit - Machine code generation for C++
|
// This file is part of AsmJit project <https://asmjit.com>
|
||||||
//
|
//
|
||||||
// * Official AsmJit Home Page: https://asmjit.com
|
// See asmjit.h or LICENSE.md for license and copyright information
|
||||||
// * Official Github Repository: https://github.com/asmjit/asmjit
|
// SPDX-License-Identifier: Zlib
|
||||||
//
|
|
||||||
// Copyright (c) 2008-2020 The AsmJit Authors
|
|
||||||
//
|
|
||||||
// This software is provided 'as-is', without any express or implied
|
|
||||||
// warranty. In no event will the authors be held liable for any damages
|
|
||||||
// arising from the use of this software.
|
|
||||||
//
|
|
||||||
// Permission is granted to anyone to use this software for any purpose,
|
|
||||||
// including commercial applications, and to alter it and redistribute it
|
|
||||||
// freely, subject to the following restrictions:
|
|
||||||
//
|
|
||||||
// 1. The origin of this software must not be misrepresented; you must not
|
|
||||||
// claim that you wrote the original software. If you use this software
|
|
||||||
// in a product, an acknowledgment in the product documentation would be
|
|
||||||
// appreciated but is not required.
|
|
||||||
// 2. Altered source versions must be plainly marked as such, and must not be
|
|
||||||
// misrepresented as being the original software.
|
|
||||||
// 3. This notice may not be removed or altered from any source distribution.
|
|
||||||
|
|
||||||
#ifndef ASMJIT_X86_X86ARCHTRAITS_P_H_INCLUDED
|
#ifndef ASMJIT_X86_X86ARCHTRAITS_P_H_INCLUDED
|
||||||
#define ASMJIT_X86_X86ARCHTRAITS_P_H_INCLUDED
|
#define ASMJIT_X86_X86ARCHTRAITS_P_H_INCLUDED
|
||||||
@@ -34,10 +16,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//! \addtogroup asmjit_x86
|
//! \addtogroup asmjit_x86
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
// ============================================================================
|
//! X86 architecture traits (internal).
|
||||||
// [asmjit::x86::x86ArchTraits
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const constexpr ArchTraits x86ArchTraits = {
|
static const constexpr ArchTraits x86ArchTraits = {
|
||||||
// SP/FP/LR/PC.
|
// SP/FP/LR/PC.
|
||||||
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
||||||
@@ -52,51 +31,53 @@ static const constexpr ArchTraits x86ArchTraits = {
|
|||||||
0x7FFFFFFFu, 0x7FFFFFFFu,
|
0x7FFFFFFFu, 0x7FFFFFFFu,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
{ ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop, 0, 0, 0 },
|
{{
|
||||||
|
InstHints::kRegSwap | InstHints::kPushPop,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints
|
||||||
|
}},
|
||||||
|
|
||||||
// RegInfo.
|
// Register signatures.
|
||||||
#define V(index) { x86::RegTraits<index>::kSignature }
|
#define V(index) OperandSignature(x86::RegTraits<RegType(index)>::kSignature)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// RegTypeToTypeId.
|
// RegTypeToTypeId.
|
||||||
#define V(index) x86::RegTraits<index>::kTypeId
|
#define V(index) TypeId(x86::RegTraits<RegType(index)>::kTypeId)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// TypeIdToRegType.
|
// TypeIdToRegType.
|
||||||
#define V(index) (index + Type::_kIdBaseStart == Type::kIdI8 ? Reg::kTypeGpbLo : \
|
#define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kX86_GpbLo : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU8 ? Reg::kTypeGpbLo : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kX86_GpbLo : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdI16 ? Reg::kTypeGpw : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kX86_Gpw : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU16 ? Reg::kTypeGpw : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kX86_Gpw : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdI32 ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU32 ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdIntPtr ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdUIntPtr ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdF32 ? Reg::kTypeXmm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kX86_Xmm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdF64 ? Reg::kTypeXmm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kX86_Xmm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask8 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask8) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask16 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask16) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask32 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask32) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask64) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMmx32) ? RegType::kX86_Mm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMmx64) ? RegType::kX86_Mm : RegType::kNone)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
{
|
{
|
||||||
ISAWordNameId::kDB,
|
ArchTypeNameId::kDB,
|
||||||
ISAWordNameId::kDW,
|
ArchTypeNameId::kDW,
|
||||||
ISAWordNameId::kDD,
|
ArchTypeNameId::kDD,
|
||||||
ISAWordNameId::kDQ
|
ArchTypeNameId::kDQ
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
//! X64 architecture traits (internal).
|
||||||
// [asmjit::x86::x64ArchTraits
|
|
||||||
// ============================================================================
|
|
||||||
|
|
||||||
static const constexpr ArchTraits x64ArchTraits = {
|
static const constexpr ArchTraits x64ArchTraits = {
|
||||||
// SP/FP/LR/PC.
|
// SP/FP/LR/PC.
|
||||||
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
Gp::kIdSp, Gp::kIdBp, 0xFF, 0xFF,
|
||||||
@@ -111,46 +92,51 @@ static const constexpr ArchTraits x64ArchTraits = {
|
|||||||
0x7FFFFFFFu, 0x7FFFFFFFu,
|
0x7FFFFFFFu, 0x7FFFFFFFu,
|
||||||
|
|
||||||
// ISA features [Gp, Vec, Other0, Other1].
|
// ISA features [Gp, Vec, Other0, Other1].
|
||||||
{ ArchTraits::kIsaFeatureSwap | ArchTraits::kIsaFeaturePushPop, 0, 0, 0 },
|
{{
|
||||||
|
InstHints::kRegSwap | InstHints::kPushPop,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints,
|
||||||
|
InstHints::kNoHints
|
||||||
|
}},
|
||||||
|
|
||||||
// RegInfo.
|
// Register signatures.
|
||||||
#define V(index) { x86::RegTraits<index>::kSignature }
|
#define V(index) OperandSignature(x86::RegTraits<RegType(index)>::kSignature)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// RegTypeToTypeId.
|
// RegTypeToTypeId.
|
||||||
#define V(index) x86::RegTraits<index>::kTypeId
|
#define V(index) TypeId(x86::RegTraits<RegType(index)>::kTypeId)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// TypeIdToRegType.
|
// TypeIdToRegType.
|
||||||
#define V(index) (index + Type::_kIdBaseStart == Type::kIdI8 ? Reg::kTypeGpbLo : \
|
#define V(index) (index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt8) ? RegType::kX86_GpbLo : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU8 ? Reg::kTypeGpbLo : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt8) ? RegType::kX86_GpbLo : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdI16 ? Reg::kTypeGpw : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt16) ? RegType::kX86_Gpw : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU16 ? Reg::kTypeGpw : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt16) ? RegType::kX86_Gpw : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdI32 ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt32) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU32 ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt32) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdI64 ? Reg::kTypeGpq : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kInt64) ? RegType::kX86_Gpq : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdU64 ? Reg::kTypeGpq : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUInt64) ? RegType::kX86_Gpq : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdIntPtr ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kIntPtr) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdUIntPtr ? Reg::kTypeGpd : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kUIntPtr) ? RegType::kX86_Gpd : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdF32 ? Reg::kTypeXmm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat32) ? RegType::kX86_Xmm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdF64 ? Reg::kTypeXmm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kFloat64) ? RegType::kX86_Xmm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask8 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask8) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask16 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask16) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask32 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask32) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMask64 ? Reg::kTypeKReg : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMask64) ? RegType::kX86_KReg : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx32 ? Reg::kTypeMm : \
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMmx32) ? RegType::kX86_Mm : \
|
||||||
index + Type::_kIdBaseStart == Type::kIdMmx64 ? Reg::kTypeMm : Reg::kTypeNone)
|
index + uint32_t(TypeId::_kBaseStart) == uint32_t(TypeId::kMmx64) ? RegType::kX86_Mm : RegType::kNone)
|
||||||
{ ASMJIT_LOOKUP_TABLE_32(V, 0) },
|
{{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
|
||||||
#undef V
|
#undef V
|
||||||
|
|
||||||
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
// Word names of 8-bit, 16-bit, 32-bit, and 64-bit quantities.
|
||||||
{
|
{
|
||||||
ISAWordNameId::kDB,
|
ArchTypeNameId::kDB,
|
||||||
ISAWordNameId::kDW,
|
ArchTypeNameId::kDW,
|
||||||
ISAWordNameId::kDD,
|
ArchTypeNameId::kDD,
|
||||||
ISAWordNameId::kDQ
|
ArchTypeNameId::kDQ
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
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