diff --git a/.github/workflows/build-config.json b/.github/workflows/build-config.json
index 3c76bd0..2be4612 100644
--- a/.github/workflows/build-config.json
+++ b/.github/workflows/build-config.json
@@ -19,6 +19,10 @@
"cmd": ["asmjit_test_assembler", "--quiet"],
"optional": true
},
+ {
+ "cmd": ["asmjit_test_assembler", "--quiet", "--validate"],
+ "optional": true
+ },
{
"cmd": ["asmjit_test_emitters"],
"optional": true
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index b322364..d7877f1 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -31,58 +31,59 @@ jobs:
fail-fast: false
matrix:
include:
- - { 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: "linux-lib" , os: "ubuntu-latest" , cc: "clang" , arch: "x64", build_type: "Release", 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-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-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-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-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-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-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-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-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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "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: "Release", 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: "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-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: "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-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-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-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-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-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-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: "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-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: "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-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: "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-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: "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: "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: "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: "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: "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" }
# 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" }
@@ -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: "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-latest", 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-latest", cc: "vs2019" , arch: "x64", build_type: "Release", defs: "ASMJIT_TEST=ON" }
+ - { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x86", build_type: "Debug" , defs: "ASMJIT_TEST=ON" }
+ - { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x86", build_type: "Release", defs: "ASMJIT_TEST=ON" }
+ - { title: "windows" , os: "windows-2019" , cc: "vs2019" , arch: "x64", build_type: "Debug" , 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}})"
runs-on: "${{matrix.os}}"
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 6a8c081..554722c 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -19,9 +19,8 @@ endif()
include(CheckCXXCompilerFlag)
include(GNUInstallDirs)
-# =============================================================================
-# [AsmJit - Deprecated]
-# =============================================================================
+# AsmJit - Deprecated
+# ===================
if (DEFINED ASMJIT_BUILD_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}")
endif()
-# =============================================================================
-# [AsmJit - Configuration]
-# =============================================================================
+# AsmJit - Configuration
+# ======================
if (NOT DEFINED ASMJIT_TEST)
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_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_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_LFLAGS "") # Linker flags required by currently enabled sanitizers.
-# =============================================================================
-# [AsmJit - Utilities]
-# =============================================================================
+# AsmJit - Utilities
+# ==================
function(asmjit_detect_cflags out)
set(out_array ${${out}})
@@ -172,9 +168,8 @@ function(asmjit_add_target target target_type)
endif()
endfunction()
-# =============================================================================
-# [AsmJit - Compiler Support]
-# =============================================================================
+# AsmJit - Compiler Support
+# =========================
set(ASMJIT_INCLUDE_DIRS "${ASMJIT_DIR}/src") # Include directory is the same as source dir.
set(ASMJIT_DEPS "") # AsmJit dependencies (libraries) for the linker.
@@ -283,9 +278,8 @@ foreach(build_option ASMJIT_STATIC
endif()
endforeach()
-# =============================================================================
-# [AsmJit - Linker Support]
-# =============================================================================
+# AsmJit - Linker Support
+# =======================
if (WIN32)
if(CMAKE_LINKER MATCHES "link\\.exe" OR CMAKE_LINKER MATCHES "lld-link\\.exe")
@@ -293,9 +287,8 @@ if (WIN32)
endif()
endif()
-# =============================================================================
-# [AsmJit - Source]
-# =============================================================================
+# AsmJit - Source
+# ===============
set(ASMJIT_SRC_LIST
asmjit/asmjit.h
@@ -324,7 +317,6 @@ set(ASMJIT_SRC_LIST
asmjit/core/constpool.h
asmjit/core/cpuinfo.cpp
asmjit/core/cpuinfo.h
- asmjit/core/datatypes.h
asmjit/core/emithelper.cpp
asmjit/core/emithelper_p.h
asmjit/core/emitter.cpp
@@ -335,7 +327,6 @@ set(ASMJIT_SRC_LIST
asmjit/core/environment.h
asmjit/core/errorhandler.cpp
asmjit/core/errorhandler.h
- asmjit/core/features.h
asmjit/core/formatter.cpp
asmjit/core/formatter.h
asmjit/core/func.cpp
@@ -401,8 +392,6 @@ set(ASMJIT_SRC_LIST
asmjit/x86/x86emithelper.cpp
asmjit/x86/x86emithelper_p.h
asmjit/x86/x86emitter.h
- asmjit/x86/x86features.cpp
- asmjit/x86/x86features.h
asmjit/x86/x86formatter.cpp
asmjit/x86/x86formatter_p.h
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})
endif()
-# =============================================================================
-# [AsmJit - Summary]
-# =============================================================================
+# AsmJit - Summary
+# ================
message("** AsmJit Summary **")
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_REL=${ASMJIT_PRIVATE_CFLAGS_REL}")
-# =============================================================================
-# [AsmJit - Targets]
-# =============================================================================
+# AsmJit - Targets
+# ================
if (NOT ASMJIT_EMBED)
# Add AsmJit target.
diff --git a/README.md b/README.md
index 08ac033..c683989 100644
--- a/README.md
+++ b/README.md
@@ -47,12 +47,10 @@ TODO
* [ ] Core:
* [ ] 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:
- * [ ] ARM/Thumb/AArch64 support.
+ * [ ] 32-bit ARM/Thumb port.
+ * [ ] 64-bit ARM (AArch64) port.
+ * [ ] RISC-V port.
Support
-------
diff --git a/src/asmjit.natvis b/src/asmjit.natvis
index b73d848..68012e0 100644
--- a/src/asmjit.natvis
+++ b/src/asmjit.natvis
@@ -34,50 +34,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ [None]
+ [Reg] {{ type={regType()} group={regGroup()} size={opSize(), d} }}
+ [Mem] {{ base={memBaseType()} index={memIndexType()} }}
+ [Imm] {{ type={immType()} }}
+ [Label]
+ [Unknown]
+
+
+ - _bits, X
+ - opType()
+ - regType()
+ - regGroup()
+ - opSize(), d
+ - memBaseType()
+ - memIndexType()
+ - memRegHome()
+ - opSize(), d
+ - memX86Segment()
+ - memX86AddrType()
+ - memX86ShiftValue()
+ - memX86Broadcast()
+ - immType()
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
-
-
-
+
+
- [None]
- [Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}
- [Mem] {{ baseId={memBaseId(), d} indexId={memIndexId(), d} offset={(__int64)memOffset(), d} }}
- [Imm] {{ val={immValue(), d} hex={immValue(), X} }}
- [Label] {{ id={_baseId} }}
+ [None]
+ [Reg] {{ id={_baseId, d} group={regGroup(), d} type={regType(), d} size={opSize(), d} }}
+ [Mem] {{ baseId={memBaseId(), d} indexId={memIndexId(), d} offset={(__int64)memOffset(), d} }}
+ [Imm] {{ val={immValue(), d} hex={immValue(), X} }}
+ [Label] {{ id={_baseId} }}
[Unknown]
- - _signature, X
- - (asmjit::Operand_::OpType)opType()
- - opSize(), d
- - (asmjit::BaseReg::RegType)regType()
- - (asmjit::BaseReg::RegGroup)regGroup()
- - (asmjit::BaseReg::RegType)memBaseType()
- - (asmjit::BaseReg::RegType)memIndexType()
- - (asmjit::BaseMem::AddrType)memAddrType()
- - (bool)memRegHome()
- - _baseId
- - _data[0]
- - _data[1]
- - _data[0]
- - _data[1]
- - _data[0]
- - _data[1]
+ - _signature._bits, X
+ - opType()
+ - opSize(), d
+ - regType()
+ - regGroup()
+ - _baseId, d
+ - memBaseType()
+ - memBaseId()
+ - memIndexType()
+ - memIndexId()
+ - memRegHome()
+ - memOffset(), d
+ - memX86Segment()
+ - memX86AddrType()
+ - memX86ShiftValue()
+ - memX86Broadcast()
+ - immType()
+ - immValue(), X
+ - _baseId, d
+ - _baseId
+ - _data[0]
+ - _data[1]
@@ -98,7 +142,7 @@
- _data
- - (asmjit::Type::Id)(typeId())
+ - (asmjit::TypeId)(typeId())
- (asmjit::BaseReg::RegType)regType()
- regId()
- stackOffset()
@@ -108,26 +152,26 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
[InstNode]
- [SectionNode]
+ [SectionNode]
[LabelNode]
[AlignNode]
[EmbedDataNode]
@@ -140,14 +184,14 @@
[FuncNode]
[FuncRetNode]
[InvokeNode]
- [UnknownNode {nodeType(), d}]
+ [UnknownNode {nodeType(), d}]
- _prev
- _next
- - (asmjit::BaseNode::NodeType)_any._nodeType
- - (asmjit::BaseNode::Flags)_any._nodeFlags
+ - _any._nodeType
+ - _any._nodeFlags
- _position
- _userDataU64
@@ -163,9 +207,9 @@
- ((asmjit::SectionNode*)this)->_id
- ((asmjit::SectionNode*)this)->_nextSection
- - ((asmjit::LabelNode*)this)->_id
+ - ((asmjit::LabelNode*)this)->_labelId
- - ((asmjit::AlignNode*)this)->_alignMode
+ - ((asmjit::AlignNode*)this)->_alignData._alignMode
- ((asmjit::AlignNode*)this)->_alignment
- _embed._typeId, d
@@ -175,15 +219,15 @@
- ((asmjit::EmbedDataNode*)this)->_inlineData
- ((asmjit::EmbedDataNode*)this)->_externalData
- - ((asmjit::EmbedLabelNode*)this)->_id
+ - ((asmjit::EmbedLabelNode*)this)->_labelId
- - ((asmjit::EmbedLabelDeltaNode*)this)->_id
- - ((asmjit::EmbedLabelDeltaNode*)this)->_baseId
+ - ((asmjit::EmbedLabelDeltaNode*)this)->_labelId
+ - ((asmjit::EmbedLabelDeltaNode*)this)->_baseLabelId
- ((asmjit::EmbedLabelDeltaNode*)this)->_dataSize
- ((asmjit::ConstPoolNode*)this)->_constPool
- - (asmjit::SentinelNode::SentinelType)_sentinel._sentinelType
+ - _sentinel._sentinelType
- ((asmjit::JumpNode*)this)->_annotation
@@ -194,7 +238,7 @@
- ((asmjit::FuncNode*)this)->_args, [((asmjit::FuncNode*)this)->_funcDetail._argCount]
- ((asmjit::InvokeNode*)this)->_funcDetail
- - ((asmjit::InvokeNode*)this)->_rets, [((asmjit::InvokeNode*)this)->_funcDetail._retCount]
+ - ((asmjit::InvokeNode*)this)->_rets
- ((asmjit::InvokeNode*)this)->_args, [((asmjit::InvokeNode*)this)->_funcDetail._argCount]
diff --git a/src/asmjit/asmjit-scope-begin.h b/src/asmjit/asmjit-scope-begin.h
index 6ee5050..93397b5 100644
--- a/src/asmjit/asmjit-scope-begin.h
+++ b/src/asmjit/asmjit-scope-begin.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifdef _WIN32
#pragma push_macro("min")
diff --git a/src/asmjit/asmjit-scope-end.h b/src/asmjit/asmjit-scope-end.h
index 447105a..702cef4 100644
--- a/src/asmjit/asmjit-scope-end.h
+++ b/src/asmjit/asmjit-scope-end.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifdef _WIN32
#pragma pop_macro("min")
diff --git a/src/asmjit/asmjit.h b/src/asmjit/asmjit.h
index 5f93fe4..1cd0651 100644
--- a/src/asmjit/asmjit.h
+++ b/src/asmjit/asmjit.h
@@ -1,9 +1,9 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * Official AsmJit Home Page: https://asmjit.com
-// * Official Github Repository: https://github.com/asmjit/asmjit
+// SPDX-License-Identifier: Zlib
+// 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
// warranty. In no event will the authors be held liable for any damages
diff --git a/src/asmjit/core.h b/src/asmjit/core.h
index 7620343..58a380d 100644
--- a/src/asmjit/core.h
+++ b/src/asmjit/core.h
@@ -1,88 +1,56 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_H_INCLUDED
#define ASMJIT_CORE_H_INCLUDED
//! Root namespace used by AsmJit.
-namespace asmjit {
-
-// ============================================================================
-// [Documentation - mainpage]
-// ============================================================================
+namespace asmjit {}
//! \mainpage API Reference
//!
//! AsmJit C++ API reference documentation generated by Doxygen.
//!
-//! AsmJit library uses one global namespace called \ref asmjit, which provides
-//! the whole functionality. Core functionality is within \ref asmjit namespace
-//! and architecture specific functionality is always in its own namespace. For
-//! example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
+//! AsmJit library uses one global namespace called \ref asmjit, which provides the whole functionality. Core
+//! functionality is within \ref asmjit namespace and architecture specific functionality is always in its own
+//! namespace. For example \ref asmjit::x86 provides both 32-bit and 64-bit X86 code generation.
//!
//! \section main_groups Documentation Groups
//!
-//! AsmJit documentation is structured into groups. Groups can be followed in
-//! order to learn AsmJit, but knowledge from multiple groups is required to
-//! use AsmJit properly:
+//! AsmJit documentation is structured into groups. Groups can be followed in order to learn AsmJit, but knowledge
+//! from multiple groups is required to use AsmJit properly:
//!
//! $$DOCS_GROUP_OVERVIEW$$
//!
-//! \note It's important to understand that in order to learn AsmJit all groups
-//! are important. Some groups can be omitted if a particular tool is out of
-//! interest - for example \ref asmjit_assembler users don't need to know about
-//! \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users
-//! must know about \ref asmjit_assembler as it also uses operands, labels, and
-//! other concepts. Similarly \ref asmjit_compiler users must know how both \ref
-//! asmjit_assembler and \ref asmjit_builder tools work.
+//! \note It's important to understand that in order to learn AsmJit all groups are important. Some groups can be
+//! omitted if a particular tool is out of interest - for example \ref asmjit_assembler users don't need to know
+//! about \ref asmjit_builder, but it's not the opposite. \ref asmjit_builder users must know about \ref
+//! asmjit_assembler as it also uses operands, labels, and other concepts. Similarly \ref asmjit_compiler users
+//! must know how both \ref asmjit_assembler and \ref asmjit_builder tools work.
//!
//! \section where_to_start Where To Start
//!
-//! AsmJit \ref asmjit_core provides the following two classes that are essential
-//! from the code generation perspective:
+//! AsmJit \ref asmjit_core provides the following two classes that are essential from the code generation perspective:
//!
-//! - \ref CodeHolder provides functionality
-//! to temporarily hold the generated code. It stores all the necessary
-//! information about the code - code buffers, sections, labels, symbols,
-//! and information about relocations.
+//! - \ref CodeHolder provides functionality to temporarily hold the generated code. It stores all the necessary
+//! information about the code - code buffers, sections, labels, symbols, and information about relocations.
//!
-//! - \ref BaseEmitter provides interface used
-//! by emitter implementations. The interface provides basic building blocks
-//! that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and
-//! \ref BaseCompiler.
+//! - \ref BaseEmitter provides interface used by emitter implementations. The interface provides basic building
+//! blocks that are then implemented by \ref BaseAssembler, \ref BaseBuilder, and \ref BaseCompiler.
//!
//! Code emitters:
//!
//! - \ref asmjit_assembler - provides direct machine code generation.
//!
-//! - \ref asmjit_builder - provides intermediate code generation that can
-//! be processed before it's serialized to \ref BaseAssembler.
+//! - \ref asmjit_builder - provides intermediate code generation that can be processed before it's serialized to
+//! \ref BaseAssembler.
//!
-//! - \ref asmjit_compiler - provides high-level code generation with built-in
-//! register allocation.
+//! - \ref asmjit_compiler - provides high-level code generation with built-in register allocation.
//!
-//! - \ref FuncNode - provides insight into how function looks from the Compiler
-//! perspective and how it's stored in a node-list.
+//! - \ref FuncNode - provides insight into how function looks from the Compiler perspective and how it's stored in
+//! a node-list.
//!
//! \section main_recommendations Recommendations
//!
@@ -92,76 +60,63 @@ namespace asmjit {
//!
//! - Make sure that you use \ref ErrorHandler, see \ref asmjit_error_handling.
//!
-//! - Instruction validation in your debug builds can reveal problems too.
-//! AsmJit provides validation at instruction level, that can be enabled
-//! by \ref BaseEmitter::addValidationOptions().
+//! - Instruction validation in your debug builds can reveal problems too. AsmJit provides validation at instruction
+//! level that can be enabled via \ref BaseEmitter::addDiagnosticOptions(). See \ref DiagnosticOptions for more
+//! details.
//!
-//! See \ref BaseEmitter::ValidationOptions for more details.
+//! - If you are a Compiler user, use diagnostic options and read carefully if anything suspicious pops out.
+//! Diagnostic options can be enabled via \ref BaseEmitter::addDiagnosticOptions(). If unsure which ones to use,
+//! enable annotations and all debug options: `DiagnosticOptions::kRAAnnotate | DiagnosticOptions::kRADebugAll`.
//!
-//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function
-//! if you have a problem with AsmJit returning errors during instruction
-//! encoding or register allocation. Having an active breakpoint there can
-//! help to reveal the origin of the error, to inspect variables and other
-//! conditions that caused to it.
+//! - Make sure you put a breakpoint into \ref DebugUtils::errored() function if you have a problem with AsmJit
+//! returning errors during instruction encoding or register allocation. Having an active breakpoint there can
+//! help to reveal the origin of the error, to inspect variables and other conditions that caused to it.
//!
-//! The reason for using \ref Logger and \ref ErrorHandler is that they provide
-//! a very useful information about what's happening inside emitters. In many
-//! cases the information provided by these two is crucial to quickly fix issues
-//! that happen during development (for example wrong instruction, address, or
-//! register used). In addition, output from \ref Logger is always necessary
-//! when filling bug reports. In other words, using logging and proper error
-//! handling can save a lot of time during the development.
+//! The reason for using \ref Logger and \ref ErrorHandler is that they provide a very useful information about what's
+//! happening inside emitters. In many cases the information provided by these two is crucial to quickly fix issues
+//! that happen during development (for example wrong instruction, address, or register used). In addition, output from
+//! \ref Logger is always necessary when filling bug reports. In other words, using logging and proper error handling
+//! can save a lot of time during the development.
//!
//! \section main_other Other Pages
//!
//! - Class List - List of classes sorted alphabetically
//! - AsmJit Namespace - List of symbols provided by `asmjit` namespace
-// ============================================================================
-// [Documentation - asmjit_build]
-// ============================================================================
//! \defgroup asmjit_build Build Instructions
//! \brief Build instructions, supported environments, and feature selection.
//!
//! ### Overview
//!
-//! AsmJit is designed to be easy embeddable in any project. However, it depends
-//! on some compile-time definitions that can be used to enable or disable
-//! features to decrease the resulting binary size. A typical way of building
-//! AsmJit is to use [cmake](https://www.cmake.org), but it's also possible to
-//! just include AsmJit source code in your project and to just build it. The
-//! easiest way to include AsmJit in your project is to just include **src**
-//! directory in your project and to define \ref ASMJIT_STATIC. AsmJit can be
-//! just updated from time to time without any changes to this integration
-//! process. Do not embed AsmJit's `test` files in such case as these are used
-//! exclusively for testing.
+//! AsmJit is designed to be easy embeddable in any project. However, it depends on some compile-time definitions that
+//! can be used to enable or disable features to decrease the resulting binary size. A typical way of building AsmJit
+//! is to use [cmake](https://www.cmake.org), but it's also possible to just include AsmJit source code in your project
+//! and to just build it. The easiest way to include AsmJit in your project is to just include **src** directory in
+//! your project and to define \ref ASMJIT_STATIC. AsmJit can be just updated from time to time without any changes to
+//! this integration process. Do not embed AsmJit's `test` files in such case as these are used exclusively for testing.
//!
//! ### Supported C++ Compilers
//!
//! - Requirements:
//!
-//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang
-//! you would have to enable at least C++11 standard through compiler flags.
+//! - AsmJit won't build without C++11 enabled. If you use older GCC or Clang you would have to enable at least
+//! C++11 standard through compiler flags.
//!
//! - Tested:
//!
-//! - **Clang** - Tested by Travis-CI - Clang 3.9+ (with C++11 enabled) is
-//! officially supported (older Clang versions having C++11 support are
-//! probably fine, but are not regularly tested).
+//! - **Clang** - Tested by GitHub Actions - Clang 3.9+ (with C++11 enabled) is officially supported (older Clang
+//! versions having C++11 support are probably fine, but are not regularly tested).
//!
-//! - **GNU** - Tested by Travis-CI - GCC 4.8+ (with C++11 enabled) is
-//! officially supported.
+//! - **GNU** - Tested by GitHub Actions - GCC 4.8+ (with C++11 enabled) is officially supported.
//!
-//! - **MINGW** - Tested by Travis-CI - Use the latest version, if possible.
+//! - **MINGW** - Should work, but it's not tested in our CI environment.
//!
-//! - **MSVC** - Tested by Travis-CI - VS2017+ is officially supported, VS2015
-//! is reported to work.
+//! - **MSVC** - Tested by GitHub Actions - VS2017+ is officially supported, VS2015 is reported to work.
//!
//! - Untested:
//!
-//! - **Intel** - No maintainers and no CI environment to regularly test
-//! this compiler.
+//! - **Intel** - No maintainers and no CI environment to regularly test this compiler.
//!
//! - **Other** C++ compilers would require basic support in
//! [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h).
@@ -170,258 +125,259 @@ namespace asmjit {
//!
//! - Tested:
//!
-//! - **Linux** - Tested by Travis-CI (any distribution is generally supported).
+//! - **Linux** - Tested by GitHub Actions (any distribution is generally supported).
//!
-//! - **OSX** - Tested by Travis-CI (any version is supported).
+//! - **Mac OS** - Tested by GitHub Actions (any version is supported).
//!
-//! - **Windows** - Tested by Travis-CI - (Windows 7+ is officially supported).
+//! - **Windows** - Tested by GitHub Actions - (Windows 7+ is officially supported).
//!
-//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit
-//! cannot generate WASM code, but can be used to generate X86/X64 code
-//! within a browser, for example.
+//! - **Emscripten** - Works if compiled with \ref ASMJIT_NO_JIT. AsmJit cannot generate WASM code, but can be
+//! used to generate X86/X64 code within a browser, for example.
//!
//! - Untested:
//!
-//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs,
-//! but they should work out of box.
+//! - **BSDs** - No maintainers, no CI environment to regularly test BSDs, but they should work out of box.
//!
//! - **Haiku** - Not regularly tested, but reported to work.
//!
-//! - **Other** operating systems would require some testing and support in
-//! the following files:
+//! - **Other** operating systems would require some testing and support in the following files:
//! - [core/api-config.h](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/api-config.h)
//! - [core/osutils.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/osutils.cpp)
//! - [core/virtmem.cpp](https://github.com/asmjit/asmjit/tree/master/src/asmjit/core/virtmem.cpp)
//!
//! ### Supported Backends / Architectures
//!
-//! - **X86** - Both 32-bit and 64-bit backends tested by Travis-CI.
-//! - **ARM** - Work-in-progress (not public at the moment).
+//! - **X86** - Both 32-bit and 64-bit backends tested on our CI.
//!
//! ### Static Builds and Embedding
//!
-//! These definitions can be used to enable static library build. Embed is used
-//! when AsmJit's source code is embedded directly in another project, implies
-//! static build as well.
+//! These definitions can be used to enable static library build. Embed is used when AsmJit's source code is embedded
+//! directly in another project, implies static build as well.
//!
//! - \ref ASMJIT_EMBED - Asmjit is embedded, implies \ref ASMJIT_STATIC.
//! - \ref ASMJIT_STATIC - Enable static-library build.
//!
-//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in
-//! all compilation units that use AsmJit, otherwise AsmJit would use dynamic
-//! library imports in \ref ASMJIT_API decorator. The recommendation is to
-//! define this macro across the whole project that uses AsmJit this way.
+//! \note Projects that use AsmJit statically must define \ref ASMJIT_STATIC in all compilation units that use AsmJit,
+//! otherwise AsmJit would use dynamic library imports in \ref ASMJIT_API decorator. The recommendation is to define
+//! this macro across the whole project that uses AsmJit this way.
//!
//! ### Build Configuration
//!
-//! These definitions control whether asserts are active or not. By default
-//! AsmJit would autodetect build configuration from existing pre-processor
-//! definitions, but this behavior can be overridden, for example to enable
-//! debug asserts in release configuration.
+//! These definitions control whether asserts are active or not. By default AsmJit would autodetect build configuration
+//! from existing pre-processor definitions, but this behavior can be overridden, for example to enable debug asserts
+//! in release configuration.
//!
-//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug,
-//! asserts will be enabled in this case.
-//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release,
-//! asserts will be disabled in this case.
+//! - \ref ASMJIT_BUILD_DEBUG - Overrides build configuration to debug, asserts will be enabled in this case.
+//! - \ref ASMJIT_BUILD_RELEASE - Overrides build configuration to release, asserts will be disabled in this case.
//!
-//! \note There is usually no need to override the build configuration. AsmJit
-//! detects the build configuration by checking whether `NDEBUG` is defined and
-//! automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides
-//! were not used. We only recommend using build configuration overrides in
-//! special situations, like using AsmJit in release configuration with asserts
-//! enabled for whatever reason.
+//! \note There is usually no need to override the build configuration. AsmJit detects the build configuration by
+//! checking whether `NDEBUG` is defined and automatically defines \ref ASMJIT_BUILD_RELEASE if configuration overrides
+//! were not used. We only recommend using build configuration overrides in special situations, like using AsmJit in
+//! release configuration with asserts enabled for whatever reason.
//!
//! ### AsmJit Backends
//!
-//! AsmJit currently supports only X86/X64 backend, but the plan is to add more
-//! backends in the future. By default AsmJit builds only the host backend, which
-//! is autodetected at compile-time, but this can be overridden.
+//! AsmJit currently supports only X86/X64 backend, but the plan is to add more backends in the future. By default
+//! AsmJit builds only the host backend, which is autodetected at compile-time, but this can be overridden.
//!
//! - \ref ASMJIT_NO_X86 - Disable X86/X64 backends.
//! - \ref ASMJIT_NO_FOREIGN - Disables the support for foreign architectures.
-//! If defined, it would internally set \ref ASMJIT_BUILD_HOST to true.
//!
//! ### Features Selection
//!
-//! AsmJit builds by defaults all supported features, which includes all emitters,
-//! logging, instruction validation and introspection, and JIT memory allocation.
-//! Features can be disabled at compile time by using `ASMJIT_NO_...` definitions.
+//! AsmJit builds by defaults all supported features, which includes all emitters, logging, instruction validation and
+//! introspection, and JIT memory allocation. Features can be disabled at compile time by using `ASMJIT_NO_...`
+//! definitions.
//!
-//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time
-//! so it won't be available and the compilation will fail if there is
-//! attempt to use such API. This includes deprecated classes, namespaces,
+//! - \ref ASMJIT_NO_DEPRECATED - Disables deprecated API at compile time so it won't be available and the
+//! compilation will fail if there is attempt to use such API. This includes deprecated classes, namespaces,
//! enumerations, and functions.
//!
-//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality
-//! completely. This implies \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler
-//! cannot be used without \ref asmjit_builder.
+//! - \ref ASMJIT_NO_BUILDER - Disables \ref asmjit_builder functionality completely. This implies \ref
+//! ASMJIT_NO_COMPILER as \ref asmjit_compiler cannot be used without \ref asmjit_builder.
//!
-//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality
-//! completely.
+//! - \ref ASMJIT_NO_COMPILER - Disables \ref asmjit_compiler functionality completely.
//!
//! - \ref ASMJIT_NO_JIT - Disables JIT memory management and \ref JitRuntime.
//!
//! - \ref ASMJIT_NO_LOGGING - Disables \ref Logger and \ref Formatter.
//!
-//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string
-//! representation of AsmJit constants, should be used together with
-//! \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the
-//! ability to quiry instruction names, register names, etc...
+//! - \ref ASMJIT_NO_TEXT - Disables everything that contains string representation of AsmJit constants, should
+//! be used together with \ref ASMJIT_NO_LOGGING as logging doesn't make sense without the ability to query
+//! instruction names, register names, etc...
//!
//! - \ref ASMJIT_NO_VALIDATION - Disables validation API.
//!
-//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API,
-//! must be used together with \ref ASMJIT_NO_COMPILER as \ref asmjit_compiler
-//! requires introspection for its liveness analysis and register allocation.
+//! - \ref ASMJIT_NO_INTROSPECTION - Disables instruction introspection API, must be used together with \ref
+//! ASMJIT_NO_COMPILER as \ref asmjit_compiler requires introspection for its liveness analysis and register
+//! allocation.
//!
-//! \note It's not recommended to disable features if you plan to build AsmJit
-//! as a shared library that will be used by multiple projects that you don't
-//! control how AsmJit was built (for example AsmJit in a Linux distribution).
-//! The possibility to disable certain features exists mainly for customized
-//! AsmJit builds.
+//! \note It's not recommended to disable features if you plan to build AsmJit as a shared library that will be
+//! used by multiple projects that you don't control how AsmJit was built (for example AsmJit in a Linux distribution).
+//! The possibility to disable certain features exists mainly for customized AsmJit builds.
-// ============================================================================
-// [Documentation - asmjit_breaking_changes]
-// ============================================================================
//! \defgroup asmjit_breaking_changes Breaking Changes
//! \brief Documentation of breaking changes
//!
//! ### Overview
//!
-//! AsmJit is a live project that is being actively developed. Deprecating the
-//! existing API in favor of a new one is preferred, but it's not always
-//! possible if the changes are significant. AsmJit authors prefer to do
-//! accumulated breaking changes at once instead of breaking the API often.
-//! This page documents deprecated and removed APIs and should serve as a how-to
-//! guide for people that want to port existing code to work with the newest AsmJit.
+//! AsmJit is a live project that is being actively developed. Deprecating the existing API in favor of a new
+//! one is preferred, but it's not always possible if the changes are significant. AsmJit authors prefer to do
+//! accumulated breaking changes at once instead of breaking the API often. This page documents deprecated and
+//! removed APIs and should serve as a how-to guide for people that want to port existing code to work with the
+//! newest AsmJit.
//!
//! ### Tips
//!
//! Useful tips before you start:
//!
-//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if
-//! you need a quick help.
+//! - Visit our [Public Gitter Channel](https://gitter.im/asmjit/asmjit) if you need a quick help.
//!
-//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that
-//! you are not using deprecated functionality at all. Deprecated functions
-//! are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes it's not
-//! possible to decorate everything like classes, which are used by deprecated
-//! functions as well, because some compilers would warn about that. If your
-//! project compiles fine with `ASMJIT_NO_DEPRECATED` it's not using anything,
-//! which was deprecated.
+//! - Build AsmJit with `ASMJIT_NO_DEPRECATED` macro defined to make sure that you are not using deprecated
+//! functionality at all. Deprecated functions are decorated with `ASMJIT_DEPRECATED()` macro, but sometimes
+//! it's not possible to decorate everything like classes, which are used by deprecated functions as well,
+//! because some compilers would warn about that. If your project compiles fine with `ASMJIT_NO_DEPRECATED`
+//! it's not using anything, which was deprecated.
//!
-//! ### Changes committed at 2020-05-30
-//!
-//! AsmJit has been cleaned up significantly, many todo items have been fixed
-//! and many functions and classes have been redesigned, some in an incompatible
-//! way.
+//! ### Changes committed at XXXX-XX-XX
//!
//! Core changes:
//!
-//! - \ref Imm operand has now only \ref Imm::value() and \ref Imm::valueAs()
-//! functions that return its value content, and \ref Imm::setValue() function
-//! that sets the content. Functions like `setI8()`, `setU8()` were deprecated.
+//! - Removed old deprecated API.
+//!
+//! - Many enumerations were changed to enum class, and many public APIs were changed to use such enums instead
+//! of uint32_t. This change makes some APIs backward incompatible - there are no deprecations this time.
+//!
+//! - Extracted operand signature manipulation to `OperandSignature`.
+//! - Setting function arguments through `Compiler::setArg()` was deprecated, use FuncNode::setArg() instead.
+//! - Moved `{arch}::Features::k` to `CpuFeatures::{arch}::k`.
+//! - Moved `BaseEmitter::kEncodingOption` to `EncodingOptions::k`.
+//! - Moved `BaseEmitter::kFlag` to `EmitterFlags::k`.
+//! - Moved `BaseEmitter::kType` to `EmitterType::k`.
+//! - Moved `BaseEmitter::kValidationOption` to `DiagnosticOptions::kValidate`.
+//! - Moved `BaseFeatures` to `CpuFeatures`.
+//! - Moved `BaseInst::kControl` to `InstControlFlow::k`.
+//! - Moved `BaseInst::kOption` and `x86::Inst::kOption` to `InstOptions::k`.
+//! - Moved `BaseNode::kNode` to `NodeType::k`.
+//! - Moved `BaseReg::kGroup` and `x86::Reg::kGroup` to `RegGroup::k`.
+//! - Moved `BaseReg::kType` and `x86::Reg::kType` to `RegType::k`.
+//! - Moved `CallConv::kFlag` to `CallConvFlags::k`.
+//! - Moved `CallConv::kId` to `CallConvId::k`.
+//! - Moved `CallConv::kStrategy` to `CallConvStrategy::k`.
+//! - Moved `CodeBuffer::kFlag` to `CodeBufferFlags`.
+//! - Moved `ConstPool::kScope` to `ConstPoolScope::k`.
+//! - Moved `Environment::kArch` to `Arch::k`.
+//! - Moved `Environment::kSubArch` to `SubArch::k`.
+//! - Moved `Environment::kFormat` to `OjectFormat::k`.
+//! - Moved `Environment::kPlatform` to `Platform::k`.
+//! - Moved `Environment::kAbi` to `PlatformABI::k`.
+//! - Moved `Environment::kVendor` to `Vendor::k`.
+//! - Moved `FormatOptions::kFlag` to `FormatFlags::k` and `DiagnosticOptions::k` (Compiler diagnostics flags).
+//! - Moved `FormatOptions::kIndentation` to `FormatIndentationGroup::k`.
+//! - Moved `FuncFrame::kAttr` to `FuncAttributes::k`.
+//! - Moved `Globals::kReset` to `ResetPolicy::k`.
+//! - Moved `InstDB::kAvx512Flag` to `InstDB::Avx512Flags::k`.
+//! - Moved `InstDB::kFlag` to `InstDB::InstFlags::k`.
+//! - Moved `InstDB::kMemFlag` to `InstDB::OpFlags::kMem`.
+//! - Moved `InstDB::kMode` to `InstDB::Mode::k`.
+//! - Moved `InstDB::kOpFlag` to `InstDB::OpFlags::k{OpType}...`.
+//! - Moved `JitAllocator::kOption` to `JitAllocatorOptions::k`.
+//! - Moved `Label::kType` to `LabelType::k`.
+//! - Moved `Operand::kOpType` to `OperandType::k`.
+//! - Moved `OpRWInfo::kFlag` to `OpRWFlags::k`.
+//! - Moved `Type::kId` to `TypeId::k`.
+//! - Moved `VirtMem::k` to `VirtMem::MemoryFlags::k`.
+//!
+//! ### Changes committed at 2020-05-30
+//!
+//! AsmJit has been cleaned up significantly, many todo items have been fixed and many functions and classes have
+//! been redesigned, some in an incompatible way.
+//!
+//! Core changes:
+//!
+//! - `Imm` operand has now only `Imm::value()` and `Imm::valueAs()` functions that return its value content,
+//! and `Imm::setValue()` function that sets the content. Functions like `setI8()`, `setU8()` were deprecated.
//!
//! Old functions were deprecated, but code using them should still compile.
//!
-//! - `ArchInfo` has been replaced with \ref Environment. Environment provides
-//! more details about the architecture, but drops some properties that
-//! were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can
-//! be replaced with `registerSize()` getter, which returns a native register
-//! size of the architecture the environment uses. However, `gpCount()` was
-//! removed - at the moment \ref ArchRegs can be used to access such properties.
+//! - `ArchInfo` has been replaced with `Environment`. Environment provides more details about the architecture,
+//! but drops some properties that were used by arch info - `gpSize(`) and `gpCount()`. `gpSize()` can be replaced
+//! with `registerSize()` getter, which returns a native register size of the architecture the environment uses.
+//! However, `gpCount()` was removed - at the moment `ArchTraits` can be used to access such properties.
//!
-//! Some other functions were renamed, like `ArchInfo::isX86Family()` is
-//! now \ref Environment::isFamilyX86(), etc. The reason for changing the
-//! order was support for more propertries and all the accessors now
-//! start with the type of the property, like \ref Environment::isPlatformWindows().
+//! Some other functions were renamed, like `ArchInfo::isX86Family()` is now `Environment::isFamilyX86()`, etc.
+//! The reason for changing the order was support for more propertries and all the accessors now start with the
+//! type of the property, like `Environment::isPlatformWindows()`.
//!
-//! This function causes many other classes to provide `environment()` getter
-//! instead of `archInfo()` getter. In addition, AsmJit now uses `arch()` to
-//! get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was renamed
-//! to `Environment::kArchXXX`.
+//! This function causes many other classes to provide `environment()` getter instead of `archInfo()` getter.
+//! In addition, AsmJit now uses `arch()` to get an architecture instead of `archId()`. `ArchInfo::kIdXXX` was
+//! renamed to `Environment::kArchXXX`.
//!
//! Some functions were deprecated, some removed...
//!
-//! - `CodeInfo` has been removed in favor of \ref Environment. If you used
-//! `CodeInfo` to set architecture and base address, this is now possible
-//! with \ref Environment and setting base address explicitly by \ref
-//! CodeHolder::init() - the first argument is \ref Environment, and the
-//! second argument is base address, which defaults to \ref
-//! Globals::kNoBaseAddress.
+//! - `CodeInfo` has been removed in favor of `Environment`. If you used `CodeInfo` to set architecture and base
+//! address, this is now possible with `Environment` and setting base address explicitly by `CodeHolder::init()`
+//! - the first argument is `Environment`, and the second argument is base address, which defaults to
+//! `Globals::kNoBaseAddress`.
//!
-//! CodeInfo class was deprecated, but the code using it should still
-//! compile with warnings.
+//! CodeInfo class was deprecated, but the code using it should still compile with warnings.
//!
-//! - \ref CallConv has been updated to offer a more unified way of representing
-//! calling conventions - many calling conventions were abstracted to follow
-//! standard naming like \ref CallConv::kIdCDecl or \ref CallConv::kIdStdCall.
+//! - `CallConv` has been updated to offer a more unified way of representing calling conventions - many calling
+//! conventions were abstracted to follow standard naming like `CallConvId::kCDecl` or `CallConvId::kStdCall`.
//!
-//! This change means that other APIs like \ref FuncDetail::init() now
-//! require both, calling convention and target \ref Environment.
+//! This change means that other APIs like `FuncDetail::init()` now require both, calling convention and target
+//! `Environment`.
//!
-//! - `Logging` namespace has been renamed to \ref Formatter, which now
-//! provides general functionality for formatting in AsmJit.
+//! - `Logging` namespace has been renamed to `Formatter`, which now provides general functionality for formatting
+//! in AsmJit.
//!
-//! Logging namespace should still work, but its use is deprecated.
-//! Unfortunately this will be without deprecation warnings, so please
-//! make sure you don't use it.
+//! Logging namespace should still work, but its use is deprecated. Unfortunately this will be without deprecation
+//! warnings, so make sure you don't use it.
//!
-//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should
-//! no longer be used. There is no replacement, AsmJit users should simply
-//! create their own structures if they need them or use the new repeated
-//! embed API in emitters, see \ref BaseEmitter::embedDataArray().
+//! - `Data64`, `Data128`, and `Data256` structs were deprecated and should no longer be used. There is no replacement,
+//! AsmJit users should simply create their own structures if they need them or use the new repeated embed API in
+//! emitters, see `BaseEmitter::embedDataArray()`.
//!
//! Emitter changes:
//!
-//! - \ref BaseEmitter::emit() function signature has been changed to accept
-//! 3 operands by reference and the rest 3 operands as a continuous array.
-//! This change is purely cosmetic and shouldn't affect users as emit()
-//! has many overloads that dispatch to the right function.
+//! - `BaseEmitter::emit()` function signature has been changed to accept 3 operands by reference and the rest 3
+//! operands as a continuous array. This change is purely cosmetic and shouldn't affect users as emit() has many
+//! overloads that dispatch to the right function.
//!
-//! - \ref x86::Emitter (Assembler, Builder, Compiler) deprecates embed
-//! utilities like `dint8()`, `duint8()`, `duint16()`, `dxmm()`, etc...
-//! in favor of a new and more powerful \ref BaseEmitter::embedDataArray().
-//! This function also allows emitting repeated values and/or patterns,
-//! which is used by helpers \ref BaseEmitter::embedUInt8(), and others...
+//! - `x86::Emitter` (Assembler, Builder, Compiler) deprecates embed utilities like `dint8()`, `duint8()`, `duint16()`,
+//! `dxmm()`, etc... in favor of a new and more powerful `BaseEmitter::embedDataArray()`. This function also allows
+//! emitting repeated values and/or patterns, which is used by helpers `BaseEmitter::embedUInt8()`, and others...
//!
-//! - Validation is now available through \ref BaseEmitter::ValidationOptions,
-//! which can be enabled/disabled through \ref BaseEmitter::addValidationOptions()
-//! and \ref BaseEmitter::clearValidationOptions(), respectively. Validation
-//! options now separate between encoding and Builder/Compiler so it's possible
-//! to choose the granularity required.
+//! - Validation is now available through `BaseEmitter::DiagnosticOptions`, which can be enabled/disabled through
+//! `BaseEmitter::addDiagnosticOptions()` and `BaseEmitter::clearDiagnosticOptions()`, respectively. Validation
+//! options now separate between encoding and Builder/Compiler so it's possible to choose the granularity required.
//!
//! Builder changes:
//!
-//! - Internal functions for creating nodes were redesigned. They now accept
-//! a pointer to the node created as a first parameter. These changes should
-//! not affect AsmJit users as these functions were used internally.
+//! - Internal functions for creating nodes were redesigned. They now accept a pointer to the node created as
+//! a first parameter. These changes should not affect AsmJit users as these functions were used internally.
//!
//! Compiler changes:
//!
-//! - `FuncCallNode` has been renamed to \ref InvokeNode. Additionally, function
-//! calls should now use \ref x86::Compiler::invoke() instead of `call()`.
-//! The reason behind this is to remove the confusion between a `call`
-//! instruction and AsmJit's `call()` intrinsic, which is now `invoke()`.
+//! - `FuncCallNode` has been renamed to `InvokeNode`. Additionally, function calls should now use
+//! `x86::Compiler::invoke()` instead of `call()`. The reason behind this is to remove the confusion between a
+//! `call` instruction and AsmJit's `call()` intrinsic, which is now `invoke()`.
//!
-//! - Creating new nodes also changed. Now the preferred way of invoking a
-//! function is to call \ref x86::Compiler::invoke() where the first
-//! argument is `InvokeNode**`. The function now returns an error and would
-//! call \ref ErrorHandler in case of a failure. Error handling was
-//! unspecified in the past - the function was marked noexcept, but called
-//! error handler, which could throw.
+//! - Creating new nodes also changed. Now the preferred way of invoking a function is to call
+//! `x86::Compiler::invoke()` where the first argument is `InvokeNode**`. The function now returns an error and
+//! would call `ErrorHandler` in case of a failure. Error handling was unspecified in the past - the function was
+//! marked noexcept, but called error handler, which could throw.
//!
-//! The reason behind this change is to make the API consistent with other
-//! changes and to also make it possible to inspect the possible error. In
-//! the previous API it returned a new node or `nullptr` in case of error,
-//! which the user couldn't inspect unless there was an attached \ref
-//! ErrorHandler.
+//! The reason behind this change is to make the API consistent with other changes and to also make it possible
+//! to inspect the possible error. In the previous API it returned a new node or `nullptr` in case of error,
+//! which the user couldn't inspect unless there was an attached `ErrorHandler`.
//!
//! Samples:
//!
//! ```
//! #include
+//!
//! using namespace asmjit;
//!
//! // The basic setup of JitRuntime and CodeHolder changed, use environment()
@@ -438,55 +394,46 @@ namespace asmjit {
//! }
//! ```
-// ============================================================================
-// [Documentation - asmjit_core]
-// ============================================================================
//! \defgroup asmjit_core Core
//! \brief Globals, code storage, and emitter interface.
//!
//! ### Overview
//!
-//! AsmJit library uses \ref CodeHolder to hold code during code generation and
-//! emitters inheriting from \ref BaseEmitter to emit code. CodeHolder uses
-//! containers to manage its data:
+//! AsmJit library uses \ref CodeHolder to hold code during code generation and emitters inheriting from \ref
+//! BaseEmitter to emit code. CodeHolder uses containers to manage its data:
//!
//! - \ref Section - stores information about a code or data section.
//! - \ref CodeBuffer - stores actual code or data, part of \ref Section.
-//! - \ref LabelEntry - stores information about a label - its name, offset,
-//! section where it belongs to, and other bits.
-//! - \ref LabelLink - stores information about yet unbound label, which was
-//! already used by the assembler.
+//! - \ref LabelEntry - stores information about a label - its name, offset, section where it belongs to, and
+//! other bits.
+//! - \ref LabelLink - stores information about yet unbound label, which was already used by the assembler.
//! - \ref RelocEntry - stores information about a relocation.
-//! - \ref AddressTableEntry - stores information about an address, which was
-//! used in a jump or call. Such address may need relocation.
+//! - \ref AddressTableEntry - stores information about an address, which was used in a jump or call. Such
+//! address may need relocation.
//!
//! To generate code you would need to instantiate at least the following classes:
//!
//! - \ref CodeHolder - to hold code during code generation.
//! - \ref BaseEmitter - to emit code into \ref CodeHolder.
-//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated
-//! code in executable memory. \ref Target can be customized by inheriting from
-//! it.
+//! - \ref Target (optional) - most likely \ref JitRuntime to keep the generated code in executable memory. \ref
+//! Target can be customized by inheriting from it.
//!
//! There are also other core classes that are important:
//!
-//! - \ref Environment - describes where the code will run. Environment brings
-//! the concept of target triples or tuples into AsmJit, which means that users
-//! can specify target architecture, platform, and ABI.
-//! - \ref Type - encapsulates lightweight type functionality that can be used
-//! to describe primitive and vector types. Types are used by higher level
-//! utilities, for example by \ref asmjit_function and \ref asmjit_compiler.
-//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information
-//! and features described by \ref BaseFeatures.
+//! - \ref Environment - describes where the code will run. Environment brings the concept of target triples or
+//! tuples into AsmJit, which means that users can specify target architecture, platform, and ABI.
+//! - \ref TypeId - encapsulates lightweight type functionality that can be used to describe primitive and vector
+//! types. Types are used by higher level utilities, for example by \ref asmjit_function and \ref asmjit_compiler.
+//! - \ref CpuInfo - encapsulates CPU information - stores both CPU information and CPU features described by \ref
+//! CpuFeatures.
//!
//! AsmJit also provides global constants:
//!
//! - \ref Globals - namespace that provides global constants.
//! - \ref ByteOrder - byte-order constants and functionality.
//!
-//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot
-//! be used to generate code.
+//! \note CodeHolder examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
//!
//! ### CodeHolder & Emitters
//!
@@ -529,8 +476,8 @@ namespace asmjit {
//! }
//! ```
//!
-//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the
-//! following emitters that offer various levels of abstraction:
+//! The example above used \ref x86::Assembler as an emitter. AsmJit provides the following emitters that offer various
+//! levels of abstraction:
//!
//! - \ref asmjit_assembler - Low-level emitter that emits directly to \ref CodeBuffer.
//! - \ref asmjit_builder - Low-level emitter that emits to a \ref BaseNode list.
@@ -538,30 +485,25 @@ namespace asmjit {
//!
//! ### Targets and JitRuntime
//!
-//! AsmJit's \ref Target is an interface that provides basic target abstraction.
-//! At the moment AsmJit provides only one implementation called \ref JitRuntime,
-//! which as the name suggests provides JIT code target and execution runtime.
-//! \ref JitRuntime provides all the necessary stuff to implement a simple JIT
-//! compiler with basic memory management. It only provides \ref JitRuntime::add()
-//! and \ref JitRuntime::release() functions that are used to either add code
-//! to the runtime or release it. \ref JitRuntime doesn't do any decisions on
-//! when the code should be released, the decision is up to the developer.
+//! AsmJit's \ref Target is an interface that provides basic target abstraction. At the moment AsmJit provides only
+//! one implementation called \ref JitRuntime, which as the name suggests provides JIT code target and execution
+//! runtime. \ref JitRuntime provides all the necessary stuff to implement a simple JIT compiler with basic memory
+//! management. It only provides \ref JitRuntime::add() and \ref JitRuntime::release() functions that are used to
+//! either add code to the runtime or release it. \ref JitRuntime doesn't do any decisions on when the code should be
+//! released, the decision is up to the developer.
//!
//! See more at \ref asmjit_virtual_memory group.
//!
//! ### More About Environment
//!
-//! In the previous example the \ref Environment is retrieved from \ref JitRuntime.
-//! It's logical as \ref JitRuntime always returns an \ref Environment that is
-//! compatible with the host. For example if your application runs in 64-bit mode
-//! the \ref Environment returned will use \ref Environment::kArchX64 architecture
-//! in contrast to \ref Environment::kArchX86, which will be used in 32-bit mode on
-//! any X86 platform.
+//! In the previous example the \ref Environment is retrieved from \ref JitRuntime. It's logical as \ref JitRuntime
+//! always returns an \ref Environment that is compatible with the host. For example if your application runs on X86_64
+//! CPU the \ref Environment returned will use \ref Arch::kX64 architecture in contrast to \ref Arch::kX86, which will
+//! be used in 32-bit mode on an X86 target.
//!
-//! AsmJit allows to setup the \ref Environment manually and to select a different
-//! architecture and ABI when necessary. So let's do something else this time, let's
-//! always generate a 32-bit code and print its binary representation. To do that, we
-//! can create our own \ref Environment and initialize it to \ref Environment::kArchX86.
+//! AsmJit allows to setup the \ref Environment manually and to select a different architecture and ABI when necessary.
+//! So let's do something else this time, let's always generate a 32-bit code and print its binary representation. To
+//! do that, we can create our own \ref Environment and initialize it to \ref Arch::kX86.
//!
//! ```
//! #include
@@ -574,7 +516,7 @@ namespace asmjit {
//!
//! // Create a custom environment initialized to 32-bit X86 architecture.
//! Environment env;
-//! env.setArch(Environment::kArchX86);
+//! env.setArch(Arch::kX86);
//!
//! CodeHolder code; // Create a CodeHolder.
//! code.init(env); // Initialize CodeHolder with custom environment.
@@ -612,46 +554,37 @@ namespace asmjit {
//!
//! ### Explicit Code Relocation
//!
-//! In addition to \ref Environment, \ref CodeHolder can be configured to
-//! specify a base-address (or a virtual base-address in a linker terminology),
-//! which could be static (useful when you know the location where the target's
-//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by
-//! default and relocates the code held by \ref CodeHolder to a user provided
-//! address on-demand. To be able to relocate to a user provided address it needs
-//! to store some information about relocations, which is represented by \ref
-//! RelocEntry. Relocation entries are only required if you call external functions
-//! from the generated code that cannot be encoded by using a 32-bit displacement
-//! (64-bit displacements are not provided by aby supported architecture).
+//! In addition to \ref Environment, \ref CodeHolder can be configured to specify a base-address (or a virtual base
+//! address in a linker terminology), which could be static (useful when you know the location where the target's
+//! machine code will be) or dynamic. AsmJit assumes dynamic base-address by default and relocates the code held by
+//! \ref CodeHolder to a user provided address on-demand. To be able to relocate to a user provided address it needs
+//! to store some information about relocations, which is represented by \ref RelocEntry. Relocation entries are only
+//! required if you call external functions from the generated code that cannot be encoded by using a 32-bit
+//! displacement (64-bit displacements are not provided by aby supported architecture).
//!
-//! There is also a concept called \ref LabelLink - label link is a lightweight
-//! data structure that doesn't have any identifier and is stored in \ref LabelEntry
-//! as a single-linked list. Label link represents either unbound yet used label
-//! and cross-sections links (only relevant to code that uses multiple sections).
-//! Since crossing sections is something that cannot be resolved immediately these
-//! links persist until offsets of these sections are assigned and until
-//! \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end
-//! up with code that has unresolved label links after flattening. You can verify
-//! it by calling \ref CodeHolder::hasUnresolvedLinks(), which inspects the value
-//! returned by \ref CodeHolder::unresolvedLinkCount().
+//! There is also a concept called \ref LabelLink - label link is a lightweight data structure that doesn't have any
+//! identifier and is stored in \ref LabelEntry as a single-linked list. Label link represents either unbound yet used
+//! label and cross-sections links (only relevant to code that uses multiple sections). Since crossing sections is
+//! something that cannot be resolved immediately these links persist until offsets of these sections are assigned and
+//! until \ref CodeHolder::resolveUnresolvedLinks() is called. It's an error if you end up with code that has
+//! unresolved label links after flattening. You can verify it by calling \ref CodeHolder::hasUnresolvedLinks(), which
+//! inspects the value returned by \ref CodeHolder::unresolvedLinkCount().
//!
-//! AsmJit can flatten code that uses multiple sections by assigning each section
-//! an incrementing offset that respects its alignment. Use \ref CodeHolder::flatten()
-//! to do that. After the sections are flattened their offsets and virtual-sizes
-//! are adjusted to respect each section's buffer size and alignment. The \ref
-//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating
-//! the code held by \ref CodeHolder. You can also flatten your code manually by
-//! iterating over all sections and calculating their offsets (relative to base)
-//! by your own algorithm. In that case \ref CodeHolder::flatten() should not be
-//! called, however, \ref CodeHolder::resolveUnresolvedLinks() should be.
+//! AsmJit can flatten code that uses multiple sections by assigning each section an incrementing offset that respects
+//! its alignment. Use \ref CodeHolder::flatten() to do that. After the sections are flattened their offsets and
+//! virtual sizes are adjusted to respect each section's buffer size and alignment. The \ref
+//! CodeHolder::resolveUnresolvedLinks() function must be called before relocating the code held by \ref CodeHolder.
+//! You can also flatten your code manually by iterating over all sections and calculating their offsets (relative to
+//! base) by your own algorithm. In that case \ref CodeHolder::flatten() should not be called, however,
+//! \ref CodeHolder::resolveUnresolvedLinks() should be.
//!
-//! The example below shows how to use a built-in virtual memory allocator
-//! \ref JitAllocator instead of using \ref JitRuntime (just in case you want
-//! to use your own memory management) and how to relocate the generated code
-//! into your own memory block - you can use your own virtual memory allocator
-//! if you prefer that, but that's OS specific and not covered by the documentation.
+//! The example below shows how to use a built-in virtual memory allocator \ref JitAllocator instead of using \ref
+//! JitRuntime (just in case you want to use your own memory management) and how to relocate the generated code
+//! into your own memory block - you can use your own virtual memory allocator if you prefer that, but that's OS
+//! specific and not covered by the documentation.
//!
-//! The following code is similar to the previous one, but implements a function
-//! working in both 32-bit and 64-bit environments:
+//! The following code is similar to the previous one, but implements a function working in both 32-bit and 64-bit
+//! environments:
//!
//! ```
//! #include
@@ -663,7 +596,7 @@ namespace asmjit {
//!
//! int main() {
//! // Create a custom environment that matches the current host environment.
-//! Environment env = hostEnvironment();
+//! Environment env = Environment::host();
//!
//! CodeHolder code; // Create a CodeHolder.
//! code.init(env); // Initialize CodeHolder with environment.
@@ -752,7 +685,7 @@ namespace asmjit {
//! // memcpy((uint8_t*)p + section->offset(),
//! // section->data(),
//! // section->bufferSize());
-//! code.copyFlattenedData(p, codeSize, CodeHolder::kCopyPadSectionBuffer);
+//! code.copyFlattenedData(p, codeSize, CopySectionFlags::kPadSectionBuffer);
//!
//! // Execute the generated function.
//! int inA[4] = { 4, 3, 2, 1 };
@@ -774,18 +707,19 @@ namespace asmjit {
//! }
//! ```
//!
-//! If you know the base-address in advance (before the code generation) it can
-//! be passed as a second argument to \ref CodeHolder::init(). In that case the
-//! Assembler will know the absolute position of each instruction and would be
-//! able to use it during instruction encoding to prevent relocations where
-//! possible. The following example shows how to configure the base address:
+//! If you know the base-address in advance (before the code generation) it can be passed as a second argument to
+//! \ref CodeHolder::init(). In that case the Assembler will know the absolute position of each instruction and
+//! would be able to use it during instruction encoding to prevent relocations where possible. The following example
+//! shows how to configure the base address:
//!
//! ```
//! #include
//! #include
//!
+//! using namespace asmjit;
+//!
//! void initializeCodeHolder(CodeHolder& code) {
-//! Environment env = hostEnvironment();
+//! Environment env = Environment::host();
//! uint64_t baseAddress = uint64_t(0x1234);
//!
//! // initialize CodeHolder with environment and custom base address.
@@ -795,16 +729,16 @@ namespace asmjit {
//!
//! ### Label Offsets and Links
//!
-//! When a label that is not yet bound is used by the Assembler, it creates a
-//! \ref LabelLink, which is then added to a \ref LabelEntry. These links are
-//! also created if a label is used in a different section than in which it
-//! was bound. Let's examine some functions that can be used to check whether
-//! there are any unresolved links.
+//! When a label that is not yet bound is used by the Assembler, it creates a \ref LabelLink, which is then added to
+//! a \ref LabelEntry. These links are also created if a label is used in a different section than in which it was
+//! bound. Let's examine some functions that can be used to check whether there are any unresolved links.
//!
//! ```
//! #include
//! #include
//!
+//! using namespace asmjit;
+//!
//! void labelLinksExample(CodeHolder& code, const Label& label) {
//! // Tests whether the `label` is bound.
//! bool isBound = code.isLabelBound(label);
@@ -819,16 +753,17 @@ namespace asmjit {
//! }
//! ```
//!
-//! There is no function that would return the number of unbound labels as this
-//! is completely unimportant from CodeHolder's perspective. If a label is not
-//! used then it doesn't matter whether it's bound or not, only actually used
-//! labels matter. After a Label is bound it's possible to query its offset
-//! offset relative to the start of the section where it was bound:
+//! There is no function that would return the number of unbound labels as this is completely unimportant from
+//! CodeHolder's perspective. If a label is not used then it doesn't matter whether it's bound or not, only actually
+//! used labels matter. After a Label is bound it's possible to query its offset offset relative to the start of the
+//! section where it was bound:
//!
//! ```
//! #include
//! #include
//!
+//! using namespace asmjit;
+//!
//! void labelOffsetExample(CodeHolder& code, const Label& label) {
//! // Label offset is known after it's bound. The offset provided is relative
//! // to the start of the section, see below for alternative. If the given
@@ -848,15 +783,16 @@ namespace asmjit {
//!
//! ### Sections
//!
-//! AsmJit allows to create multiple sections within the same \ref CodeHolder.
-//! A test-case [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp)
-//! can be used as a reference point although the following example should
-//! also provide a useful insight:
+//! AsmJit allows to create multiple sections within the same \ref CodeHolder. A test-case
+//! [asmjit_test_x86_sections.cpp](https://github.com/asmjit/asmjit/blob/master/test/asmjit_test_x86_sections.cpp)
+//! can be used as a reference point although the following example should also provide a useful insight:
//!
//! ```
//! #include
//! #include
//!
+//! using namespace asmjit;
+//!
//! void sectionsExample(CodeHolder& code) {
//! // Text section is always provided as the first section.
//! Section* text = code.textSection(); // or code.sectionById(0);
@@ -864,11 +800,11 @@ namespace asmjit {
//! // To create another section use CodeHolder::newSection().
//! Section* data;
//! Error err = code.newSection(&data,
-//! ".data", // Section name
-//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
-//! 0, // Section flags, see Section::Flags.
-//! 8, // Section alignment, must be power of 2.
-//! 0); // Section order value (optional, default 0).
+//! ".data", // Section name
+//! SIZE_MAX, // Name length if the name is not null terminated (or SIZE_MAX).
+//! SectionFlags::kNone, // Section flags, see SectionFlags.
+//! 8, // Section alignment, must be power of 2.
+//! 0); // Section order value (optional, default 0).
//!
//! // When you switch sections in Assembler, Builder, or Compiler the cursor
//! // will always move to the end of that section. When you create an Assembler
@@ -893,17 +829,17 @@ namespace asmjit {
//! }
//! ```
//!
-//! The last line in the example above shows that a LabelLink would be created
-//! even for bound labels that cross sections. In this case a referenced label
-//! was bound in another section, which means that the link couldn't be resolved
-//! at that moment. If your code uses sections, but you wish AsmJit to flatten
-//! these sections (you don't plan to flatten them manually) then there is an
-//! API for that.
+//! The last line in the example above shows that a LabelLink would be created even for bound labels that cross
+//! sections. In this case a referenced label was bound in another section, which means that the link couldn't be
+//! resolved at that moment. If your code uses sections, but you wish AsmJit to flatten these sections (you don't
+//! plan to flatten them manually) then there is an API for that.
//!
//! ```
//! #include
//! #include
//!
+//! using namespace asmjit;
+//!
//! // ... (continuing the previous example) ...
//! void sectionsExampleContinued(CodeHolder& code) {
//! // Suppose we have some code that contains multiple sections and
@@ -938,18 +874,14 @@ namespace asmjit {
//! }
//! ```
-// ============================================================================
-// [Documentation - asmjit_assembler]
-// ============================================================================
//! \defgroup asmjit_assembler Assembler
//! \brief Assembler interface and operands.
//!
//! ### Overview
//!
-//! AsmJit's Assembler is used to emit machine code directly into a \ref
-//! CodeBuffer. In general, code generation with assembler requires the knowledge
-//! of the following:
+//! AsmJit's Assembler is used to emit machine code directly into a \ref CodeBuffer. In general, code generation
+//! with assembler requires the knowledge of the following:
//!
//! - \ref BaseAssembler and architecture-specific assemblers:
//! - \ref x86::Assembler - Assembler specific to X86 architecture
@@ -961,76 +893,58 @@ namespace asmjit {
//! - \ref Imm - Immediate (value) operand.
//! - \ref Label - Label operand.
//!
-//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot
-//! be used to generate code.
+//! \note Assembler examples use \ref x86::Assembler as abstract interfaces cannot be used to generate code.
//!
//! ### Operand Basics
//!
-//! Let's start with operands. \ref Operand is a data structure that defines a
-//! data layout of any operand. It can be inherited, but any class inheriting
-//! it cannot add any members to it, only the existing layout can be reused.
-//! AsmJit allows to construct operands dynamically, to store them, and to query
-//! a complete information about them at run-time. Operands are small (always 16
-//! bytes per \ref Operand) and can be copied and passed by value. Please never
-//! allocate individual operands dynamically by using a `new` keyword - it would
-//! work, but then you would have to be responsible for deleting such operands.
-//! In AsmJit operands are always part of some other data structures like \ref
-//! InstNode, which is part of \ref asmjit_builder tool.
+//! Let's start with operands. \ref Operand is a data structure that defines a data layout of any operand. It can be
+//! inherited, but any class inheriting it cannot add any members to it, only the existing layout can be reused.
+//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them
+//! at run-time. Operands are small (always 16 bytes per \ref Operand) and can be copied and passed by value. Please
+//! never allocate individual operands dynamically by using a `new` keyword - it would work, but then you would have
+//! to be responsible for deleting such operands. In AsmJit operands are always part of some other data structures
+//! like \ref InstNode, which is part of \ref asmjit_builder tool.
//!
-//! Operands contain only identifiers, but not pointers to any code-generation data.
-//! For example \ref Label operand only provides label identifier, but not a pointer
-//! to \ref LabelEntry structure. In AsmJit such IDs are used to link stuff together
-//! without having to deal with pointers.
+//! Operands contain only identifiers, but not pointers to any code-generation data. For example \ref Label operand
+//! only provides label identifier, but not a pointer to \ref LabelEntry structure. In AsmJit such IDs are used to
+//! link stuff together without having to deal with pointers.
//!
-//! AsmJit's operands all inherit from a base class called \ref Operand. Operands
-//! have the following properties that are commonly accessible by getters and setters:
+//! AsmJit's operands all inherit from a base class called \ref Operand. Operands have the following properties that
+//! are commonly accessible by getters and setters:
//!
-//! - \ref Operand - Base operand, which only provides accessors that are common
-//! to all operand types.
-//! - \ref BaseReg - Describes either physical or virtual register. Physical
-//! registers have id that matches the target's machine id directly whereas
-//! virtual registers must be allocated into physical registers by a register
+//! - \ref Operand - Base operand, which only provides accessors that are common to all operand types.
+//! - \ref BaseReg - Describes either physical or virtual register. Physical registers have id that matches the
+//! target's machine id directly whereas virtual registers must be allocated into physical registers by a register
//! allocator pass. Register operand provides:
-//! - Register Type - Unique id that describes each possible register provided
-//! by the target architecture - for example X86 backend provides \ref
-//! x86::Reg::RegType, which defines all variations of general purpose registers
-//! (GPB-LO, GPB-HI, GPW, GPD, and GPQ) and all types of other registers like K,
-//! MM, BND, XMM, YMM, and ZMM.
-//! - Register Group - Groups multiple register types under a single group - for
-//! example all general-purpose registers (of all sizes) on X86 are part of
-//! \ref x86::Reg::kGroupGp and all SIMD registers (XMM, YMM, ZMM) are part
-//! of \ref x86::Reg::kGroupVec.
-//! - Register Size - Contains the size of the register in bytes. If the size
-//! depends on the mode (32-bit vs 64-bit) then generally the higher size is
-//! used (for example RIP register has size 8 by default).
+//! - Register Type (\ref RegType) - Unique id that describes each possible register provided by the target
+//! architecture - for example X86 backend provides general purpose registers (GPB-LO, GPB-HI, GPW, GPD, and GPQ)
+//! and all types of other registers like K, MM, BND, XMM, YMM, ZMM, and TMM.
+//! - Register Group (\ref RegGroup) - Groups multiple register types under a single group - for example all
+//! general-purpose registers (of all sizes) on X86 are part of \ref RegGroup::kGp and all SIMD registers
+//! (XMM, YMM, ZMM) are part of \ref RegGroup::kVec.
+//! - Register Size - Contains the size of the register in bytes. If the size depends on the mode (32-bit vs
+//! 64-bit) then generally the higher size is used (for example RIP register has size 8 by default).
//! - Register Id - Contains physical or virtual id of the register.
//! - \ref BaseMem - Used to reference a memory location. Memory operand provides:
//! - Base Register - A base register type and id (physical or virtual).
//! - Index Register - An index register type and id (physical or virtual).
-//! - Offset - Displacement or absolute address to be referenced (32-bit if base
-//! register is used and 64-bit if base register is not used).
-//! - Flags that can describe various architecture dependent information (like
-//! scale and segment-override on X86).
-//! - \ref Imm - Immediate values are usually part of instructions (encoded within
-//! the instruction itself) or data.
-//! - \ref Label - used to reference a location in code or data. Labels must be
-//! created by the \ref BaseEmitter or by \ref CodeHolder. Each label has its
-//! unique id per \ref CodeHolder instance.
+//! - Offset - Displacement or absolute address to be referenced (32-bit if base register is used and 64-bit if
+//! base register is not used).
+//! - Flags that can describe various architecture dependent information (like scale and segment-override on X86).
+//! - \ref Imm - Immediate values are usually part of instructions (encoded within the instruction itself) or data.
+//! - \ref Label - used to reference a location in code or data. Labels must be created by the \ref BaseEmitter or
+//! by \ref CodeHolder. Each label has its unique id per \ref CodeHolder instance.
//!
//! ### Operand Manipulation
//!
-//! AsmJit allows to construct operands dynamically, to store them, and to query
-//! a complete information about them at run-time. Operands are small (always 16
-//! bytes per `Operand`) and should be always copied (by value) if you intend to
-//! store them (don't create operands by using `new` keyword, it's not recommended).
-//! Operands are safe to be passed to `memcpy()` and `memset()`, which becomes
-//! handy when working with arrays of operands. If you set all members of an \ref
-//! Operand to zero the operand would become NONE operand, which is the same as a
-//! default constructed Operand.
+//! AsmJit allows to construct operands dynamically, to store them, and to query a complete information about them at
+//! run-time. Operands are small (always 16 bytes per `Operand`) and should be always copied (by value) if you intend
+//! to store them (don't create operands by using `new` keyword, it's not recommended). Operands are safe to be passed
+//! to `memcpy()` and `memset()`, which becomes handy when working with arrays of operands. If you set all members of
+//! an \ref Operand to zero the operand would become NONE operand, which is the same as a default constructed Operand.
//!
-//! The example below illustrates how operands can be used and modified even
-//! without using any other code generation classes. The example uses X86
-//! architecture-specific operands.
+//! The example below illustrates how operands can be used and modified even without using any other code generation
+//! classes. The example uses X86 architecture-specific operands.
//!
//! ```
//! #include
@@ -1050,7 +964,7 @@ namespace asmjit {
//! // Constructs [src + idx] memory address - referencing [rax + r10].
//! x86::Mem m = x86::ptr(src, idx);
//!
-//! // Examine `m`: Returns `x86::Reg::kTypeGpq`.
+//! // Examine `m`: Returns `RegType::kX86_Gpq`.
//! m.indexType();
//! // Examine `m`: Returns 10 (`r10`).
//! m.indexId();
@@ -1088,23 +1002,20 @@ namespace asmjit {
//! }
//! ```
//!
-//! Some operands have to be created explicitly by emitters. For example labels
-//! must be created by \ref BaseEmitter::newLabel(), which creates a label entry
-//! and returns a \ref Label operand with the id that refers to it. Such label
-//! then can be used by emitters.
+//! Some operands have to be created explicitly by emitters. For example labels must be created by \ref
+//! BaseEmitter::newLabel(), which creates a label entry and returns a \ref Label operand with the id that refers
+//! to it. Such label then can be used by emitters.
//!
//! ### Memory Operands
//!
-//! Some architectures like X86 provide a complex memory addressing model that
-//! allows to encode addresses having a BASE register, INDEX register with a
-//! possible scale (left shift), and displacement (called offset in AsmJit).
-//! Memory address on X86 can also specify memory segment (segment-override in
-//! X86 terminology) and some instructions (gather / scatter) require INDEX to
-//! be a \ref x86::Vec register instead of a general-purpose register.
+//! Some architectures like X86 provide a complex memory addressing model that allows to encode addresses having a
+//! BASE register, INDEX register with a possible scale (left shift), and displacement (called offset in AsmJit).
+//! Memory address on X86 can also specify memory segment (segment-override in X86 terminology) and some instructions
+//! (gather / scatter) require INDEX to be a \ref x86::Vec register instead of a general-purpose register.
//!
-//! AsmJit allows to encode and work with all forms of addresses mentioned and
-//! implemented by X86. In addition, it also allows to construct absolute 64-bit
-//! memory address operands, which is only allowed in one form of 'mov' instruction.
+//! AsmJit allows to encode and work with all forms of addresses mentioned and implemented by X86. In addition, it
+//! also allows to construct absolute 64-bit memory address operands, which is only allowed in one form of 'mov'
+//! instruction.
//!
//! ```
//! #include
@@ -1147,9 +1058,8 @@ namespace asmjit {
//! }
//! ```
//!
-//! Memory operands can optionally contain memory size. This is required by
-//! instructions where the memory size cannot be deduced from other operands,
-//! like `inc` and `dec` on X86:
+//! Memory operands can optionally contain memory size. This is required by instructions where the memory size cannot
+//! be deduced from other operands, like `inc` and `dec` on X86:
//!
//! ```
//! #include
@@ -1233,34 +1143,26 @@ namespace asmjit {
//!
//! - \ref x86::Assembler provides many X86/X64 examples.
-// ============================================================================
-// [Documentation - asmjit_builder]
-// ============================================================================
//! \defgroup asmjit_builder Builder
//! \brief Builder interface, nodes, and passes.
//!
//! ### Overview
//!
-//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters
-//! that emit into a representation that allows further processing. The code
-//! stored in such representation is completely safe to be patched, simplified,
-//! reordered, obfuscated, removed, injected, analyzed, or processed some other
-//! way. Each instruction, label, directive, or other building block is stored
-//! as \ref BaseNode (or derived class like \ref InstNode or \ref LabelNode)
-//! and contains all the information necessary to pass that node later to the
-//! assembler.
+//! Both \ref BaseBuilder and \ref BaseCompiler interfaces describe emitters that emit into a representation that
+//! allows further processing. The code stored in such representation is completely safe to be patched, simplified,
+//! reordered, obfuscated, removed, injected, analyzed, or processed some other way. Each instruction, label,
+//! directive, or other building block is stored as \ref BaseNode (or derived class like \ref InstNode or \ref
+//! LabelNode) and contains all the information necessary to pass that node later to the assembler.
//!
-//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface.
-//! It was designed to provide a maximum compatibility with the existing \ref
-//! BaseAssembler emitter so users can move from assembler to builder when needed,
+//! \ref BaseBuilder is an emitter that inherits from \ref BaseEmitter interface. It was designed to provide a maximum
+//! compatibility with the existing \ref BaseAssembler emitter so users can move from assembler to builder when needed,
//! for example to implement post-processing, which is not possible with Assembler.
//!
//! ### Builder Nodes
//!
-//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate
-//! representation based on nodes, however, it allows to serialize to \ref BaseAssembler
-//! when the code is ready to be encoded.
+//! \ref BaseBuilder doesn't generate machine code directly, it uses an intermediate representation based on nodes,
+//! however, it allows to serialize to \ref BaseAssembler when the code is ready to be encoded.
//!
//! There are multiple node types used by both \ref BaseBuilder and \ref BaseCompiler :
//!
@@ -1273,16 +1175,13 @@ namespace asmjit {
//! - Data nodes:
//! - \ref EmbedDataNode - Represents data.
//! - \ref EmbedLabelNode - Represents \ref Label address embedded as data.
-//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels
-//! embedded in data.
+//! - \ref EmbedLabelDeltaNode - Represents a difference of two labels embedded in data.
//! - \ref ConstPoolNode - Represents a constant pool data embedded as data.
//!
//! - Informative nodes:
-//! - \ref CommentNode - Represents a comment string, doesn't affect code
-//! generation.
-//! - \ref SentinelNode - A marker that can be used to remember certain
-//! position in code or data, doesn't affect code generation. Used by
-//! \ref FuncNode to mark the end of a function.
+//! - \ref CommentNode - Represents a comment string, doesn't affect code generation.
+//! - \ref SentinelNode - A marker that can be used to remember certain position in code or data, doesn't affect
+//! code generation. Used by \ref FuncNode to mark the end of a function.
//!
//! - Other nodes are provided by \ref asmjit_compiler infrastructure.
//!
@@ -1290,47 +1189,38 @@ namespace asmjit {
//!
//! - \ref x86::Builder provides many X86/X64 examples.
-// ============================================================================
-// [Documentation - asmjit_compiler]
-// ============================================================================
//! \defgroup asmjit_compiler Compiler
//! \brief Compiler interface.
//!
//! ### Overview
//!
-//! \ref BaseCompiler is a high-level interface built on top of \ref BaseBuilder
-//! interface, which provides register allocation and support for defining and
-//! invoking functions. At the moment it's the easiest way of generating code
-//! in AsmJit as most architecture and OS specifics is properly abstracted and
-//! handled by AsmJit automatically. However, abstractions also mean restrictions,
-//! which means that \ref BaseCompiler has more limitations than \ref BaseAssembler
-//! or \ref BaseBuilder.
+//! \ref BaseCompiler is a high-level interface, which provides register allocation and support for defining and
+//! invoking functions, built on top of \ref BaseBuilder interface At the moment it's the easiest way of generating
+//! code in AsmJit as most architecture and OS specifics is properly abstracted and handled by AsmJit automatically.
+//! However, abstractions also mean restrictions, which means that \ref BaseCompiler has more limitations than \ref
+//! BaseAssembler or \ref BaseBuilder.
//!
-//! Since \ref BaseCompiler provides register allocation it also establishes the
-//! concept of functions - a function in Compiler sense is a unit in which virtual
-//! registers are allocated into physical registers by the register allocator.
-//! In addition, it enables to use such virtual registers in function invocations.
+//! Since \ref BaseCompiler provides register allocation it also establishes the concept of functions - a function
+//! in Compiler sense is a unit in which virtual registers are allocated into physical registers by the register
+//! allocator. In addition, it enables to use such virtual registers in function invocations.
//!
-//! \ref BaseCompiler automatically handles function calling conventions. It's
-//! still architecture dependent, but makes the code generation much easies.
-//! Functions are essential; the first-step to generate some code is to define a
-//! signature of the function to be generated (before generating the function body
-//! itself). Function arguments and return value(s) are handled by assigning
-//! virtual registers to them. Similarly, function calls are handled the same way.
+//! \ref BaseCompiler automatically handles function calling conventions. It's still architecture dependent, but
+//! makes the code generation much easies. Functions are essential; the first-step to generate some code is to define
+//! a signature of the function to be generated (before generating the function body itself). Function arguments and
+//! return value(s) are handled by assigning virtual registers to them. Similarly, function calls are handled the same
+//! way.
//!
//! ### Compiler Nodes
//!
-//! \ref BaseCompiler adds some nodes that are required for function generation
-//! and invocation:
+//! \ref BaseCompiler adds some nodes that are required for function generation and invocation:
//!
//! - \ref FuncNode - Represents a function definition.
//! - \ref FuncRetNode - Represents a function return.
//! - \ref InvokeNode - Represents a function invocation.
//!
-//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically
-//! adds an architecture-dependent register allocator pass to the list of passes
-//! when attached to \ref CodeHolder.
+//! \ref BaseCompiler also makes the use of passes (\ref Pass) and automatically adds an architecture-dependent
+//! register allocator pass to the list of passes when attached to \ref CodeHolder.
//!
//! ### Compiler Examples
//!
@@ -1338,134 +1228,110 @@ namespace asmjit {
//!
//! ### Compiler Tips
//!
-//! Users of AsmJit have done mistakes in the past, this section should provide
-//! some useful tips for beginners:
+//! Users of AsmJit have done mistakes in the past, this section should provide some useful tips for beginners:
//!
-//! - Virtual registers in compiler are bound to a single function. At the
-//! moment the implementation doesn't care whether a single virtual register
-//! is used in multiple functions, but it sees it as two independent virtual
-//! registers in that case. This means that virtual registers cannot be used
-//! to implement global variables. Global variables are basically memory
-//! addresses which functions can read from and write to, and they have to
-//! be implemented in the same way.
+//! - Virtual registers in compiler are bound to a single function. At the moment the implementation doesn't
+//! care whether a single virtual register is used in multiple functions, but it sees it as two independent
+//! virtual registers in that case. This means that virtual registers cannot be used to implement global
+//! variables. Global variables are basically memory addresses which functions can read from and write to,
+//! and they have to be implemented in the same way.
//!
-//! - Compiler provides a useful debugging functionality, which can be turned
-//! on through \ref FormatOptions::Flags. Use \ref Logger::addFlags() to
-//! turn on additional logging features when using Compiler.
+//! - Compiler provides a useful debugging functionality, which can be turned on through \ref FormatFlags. Use
+//! \ref Logger::addFlags() to turn on additional logging features when using Compiler.
-// ============================================================================
-// [Documentation - asmjit_function]
-// ============================================================================
//! \defgroup asmjit_function Function
//! \brief Function definitions.
//!
//! ### Overview
//!
-//! AsmJit provides functionality that can be used to define function signatures
-//! and to calculate automatically optimal function frame that can be used directly
-//! by a prolog and epilog insertion. This feature was exclusive to AsmJit's Compiler
-//! for a very long time, but was abstracted out and is now available for all users
-//! regardless of the emitter they use. The following use cases are possible:
+//! AsmJit provides functionality that can be used to define function signatures and to calculate automatically
+//! optimal function frame that can be used directly by a prolog and epilog insertion. This feature was exclusive
+//! to AsmJit's Compiler for a very long time, but was abstracted out and is now available for all users regardless
+//! of the emitter they use. The following use cases are possible:
//!
-//! - Calculate function frame before the function is generated - this is the
-//! only way available to \ref BaseAssembler users and it will be described
-//! in this section.
+//! - Calculate function frame before the function is generated - this is the only way available to \ref
+//! BaseAssembler users and it will be described in this section.
//!
-//! - Calculate function frame after the function is generated - this way is
-//! generally used by \ref BaseBuilder and \ref BaseCompiler emitters and
-//! this way is generally described in \ref asmjit_compiler section.
+//! - Calculate function frame after the function is generated - this way is generally used by \ref BaseBuilder
+//! and \ref BaseCompiler emitters and this way is generally described in \ref asmjit_compiler section.
//!
//! The following concepts are used to describe and create functions in AsmJit:
//!
-//! - \ref Type::Id - Type-id is an 8-bit value that describes a platform
-//! independent type as we know from C/C++. It provides abstractions for
-//! most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`,
-//! `double`, and all possible vector types to match ISAs up to AVX512.
-//! \ref Type::Id was introduced originally for \ref asmjit_compiler, but
-//! it's now used by \ref FuncSignature as well.
+//! - \ref TypeId - Type-id is an 8-bit value that describes a platform independent type as we know from C/C++.
+//! It provides abstractions for most common types like `int8_t`, `uint32_t`, `uintptr_t`, `float`, `double`,
+//! and all possible vector types to match ISAs up to AVX512. \ref TypeId was introduced originally for \ref
+//! asmjit_compiler, but it's now used by \ref FuncSignature as well.
//!
-//! - \ref CallConv - Describes a calling convention - this class contains
-//! instructions to assign registers and stack addresses to function
-//! arguments and return value(s), but doesn't specify any function
-//! signature itself. Calling conventions are architecture and OS dependent.
+//! - \ref CallConv - Describes a calling convention - this class contains instructions to assign registers and
+//! stack addresses to function arguments and return value(s), but doesn't specify any function signature itself.
+//! Calling conventions are architecture and OS dependent.
//!
-//! - \ref FuncSignature - Describes a function signature, for example
-//! `int func(int, int)`. FuncSignature contains a function calling convention
-//! id, return value type, and function arguments. The signature itself is
-//! platform independent and uses \ref Type::Id to describe types of function
-//! arguments and function return value(s).
+//! - \ref FuncSignature - Describes a function signature, for example `int func(int, int)`. FuncSignature contains
+//! a function calling convention id, return value type, and function arguments. The signature itself is platform
+//! independent and uses \ref TypeId to describe types of function arguments and function return value(s).
//!
-//! - \ref FuncDetail - Architecture and ABI dependent information that describes
-//! \ref CallConv and expanded \ref FuncSignature. Each function argument and
-//! return value is represented as \ref FuncValue that contains the original
-//! \ref Type::Id enriched with additional information that specifies whether
-//! the value is passed or returned by register (and which register) or by
-//! stack. Each value also contains some other metadata that provide additional
-//! information required to handle it properly (for example whether a vector is
-//! passed indirectly by a pointer as required by WIN64 calling convention).
+//! - \ref FuncDetail - Architecture and ABI dependent information that describes \ref CallConv and expanded \ref
+//! FuncSignature. Each function argument and return value is represented as \ref FuncValue that contains the
+//! original \ref TypeId enriched with additional information that specifies whether the value is passed or
+//! returned by register (and which register) or by stack. Each value also contains some other metadata that
+//! provide additional information required to handle it properly (for example whether a vector is passed
+//! indirectly by a pointer as required by WIN64 calling convention).
//!
-//! - \ref FuncFrame - Contains information about the function frame that can
-//! be used by prolog/epilog inserter (PEI). Holds call stack size size and
-//! alignment, local stack size and alignment, and various attributes that
-//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't
-//! know anything about function's arguments or return values, it hold only
-//! information necessary to create a valid and ABI conforming function prologs
-//! and epilogs.
+//! - \ref FuncFrame - Contains information about the function frame that can be used by prolog/epilog inserter
+//! (PEI). Holds call stack size size and alignment, local stack size and alignment, and various attributes that
+//! describe how prolog and epilog should be constructed. `FuncFrame` doesn't know anything about function's
+//! arguments or return values, it hold only information necessary to create a valid and ABI conforming function
+//! prologs and epilogs.
//!
-//! - \ref FuncArgsAssignment - A helper class that can be used to reassign
-//! function arguments into user specified registers. It's architecture and
-//! ABI dependent mapping from function arguments described by \ref CallConv
+//! - \ref FuncArgsAssignment - A helper class that can be used to reassign function arguments into user specified
+//! registers. It's architecture and ABI dependent mapping from function arguments described by \ref CallConv
//! and \ref FuncDetail into registers specified by the user.
//!
-//! It's a lot of concepts where each represents one step in a function frame
-//! calculation. It can be used to create function prologs, epilogs, and also
-//! to calculate information necessary to perform function calls.
+//! It's a lot of concepts where each represents one step in a function frame calculation. It can be used to create
+//! function prologs, epilogs, and also to calculate information necessary to perform function calls.
-// ============================================================================
-// [Documentation - asmjit_logging]
-// ============================================================================
//! \defgroup asmjit_logging Logging
//! \brief Logging and formatting.
//!
//! ### Overview
//!
-//! The initial phase of a project that generates machine code is not always smooth.
-//! Failure cases are common not just at the beginning phase, but also during the
-//! development or refactoring. AsmJit provides logging functionality to address
-//! this issue. AsmJit does already a good job with function overloading to prevent
-//! from emitting unencodable instructions, but it can't prevent from emitting machine
-//! code that is correct at instruction level, but doesn't work when it's executed as
-//! a whole. Logging has always been an important part of AsmJit's infrastructure and
-//! looking at logs can sometimes reveal code generation issues quickly.
+//! The initial phase of a project that generates machine code is not always smooth. Failure cases are common not just
+//! at the beginning phase, but also during the development or refactoring. AsmJit provides logging functionality to
+//! address this issue. AsmJit does already a good job with function overloading to prevent from emitting unencodable
+//! instructions, but it can't prevent from emitting machine code that is correct at instruction level, but doesn't
+//! work when it's executed asa whole. Logging has always been an important part of AsmJit's infrastructure and looking
+//! at logs can sometimes reveal code generation issues quickly.
//!
//! AsmJit provides API for logging and formatting:
-//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters
-//! that inherit from \ref BaseEmitter.
-//! - \ref FormatOptions - Formatting options that can change how instructions and
-//! operands are formatted.
-//! - \ref Formatter - A namespace that provides functions that can format input
-//! data like \ref Operand, \ref BaseReg, \ref Label, and \ref BaseNode into
-//! \ref String.
+//!
+//! - \ref Logger - A logger that you can pass to \ref CodeHolder and all emitters that inherit from \ref BaseEmitter.
+//!
+//! - \ref FormatOptions - Formatting options that can change how instructions and operands are formatted.
+//!
+//! - \ref Formatter - A namespace that provides functions that can format input data like \ref Operand, \ref BaseReg,
+//! \ref Label, and \ref BaseNode into \ref String.
//!
//! AsmJit's \ref Logger serves the following purposes:
+//!
//! - Provides a basic foundation for logging.
-//! - Abstract class leaving the implementation on users. The following built-in
-//! implementations are provided for simplicity:
+//!
+//! - Abstract class leaving the implementation on users. The following built-in implementations are provided for
+//! simplicity:
+//!
//! - \ref FileLogger implements logging into a standard `FILE` stream.
//! - \ref StringLogger serializes all logs into a \ref String instance.
//!
-//! AsmJit's \ref FormatOptions provides the following to customize the formatting of
-//! instructions and operands through:
-//! - \ref FormatOptions::Flags
-//! - \ref FormatOptions::IndentationType
+//! AsmJit's \ref FormatOptions provides the following to customize the formatting of instructions and operands through:
+//!
+//! - \ref FormatFlags
+//! - \ref FormatIndentationGroup
//!
//! ### Logging
//!
-//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it
-//! to all attached emitters automatically. The example below illustrates how to
-//! use \ref FileLogger that outputs to standard output:
+//! A \ref Logger is typically attached to a \ref CodeHolder, which propagates it to all attached emitters
+//! automatically. The example below illustrates how to use \ref FileLogger that outputs to standard output:
//!
//! ```
//! #include
@@ -1486,8 +1352,8 @@ namespace asmjit {
//! }
//! ```
//!
-//! If output to FILE stream is not desired it's possible to use \ref StringLogger,
-//! which concatenates everything into a multi-line string:
+//! If output to FILE stream is not desired it's possible to use \ref StringLogger, which concatenates everything
+//! into a multi-line string:
//!
//! ```
//! #include
@@ -1520,11 +1386,10 @@ namespace asmjit {
//!
//! ### Formatting
//!
-//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref
-//! Logger. Formatting is public and can be used by AsmJit users as well. The
-//! most important thing to know regarding formatting is that \ref Formatter
-//! always appends to the output string, so it can be used to build complex
-//! strings without having to concatenate intermediate strings.
+//! AsmJit uses \ref Formatter to format inputs that are then passed to \ref Logger. Formatting is public and can be
+//! used by AsmJit users as well. The most important thing to know regarding formatting is that \ref Formatter always
+//! appends to the output string, so it can be used to build complex strings without having to concatenate
+//! intermediate strings.
//!
//! The first example illustrates how to format operands:
//!
@@ -1534,12 +1399,12 @@ namespace asmjit {
//!
//! using namespace asmjit;
//!
-//! void logOperand(uint32_t arch, const Operand_& op) {
+//! void logOperand(Arch arch, const Operand_& op) {
//! // The emitter is optional (named labels and virtual registers need it).
//! BaseEmitter* emitter = nullptr;
//!
//! // No flags by default.
-//! uint32_t formatFlags = FormatOptions::kNoFlags;
+//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! StringTmp<128> sb;
//! Formatter::formatOperand(sb, formatFlags, emitter, arch, op);
@@ -1552,7 +1417,7 @@ namespace asmjit {
//! // Architecture is not part of operand, it must be passed explicitly.
//! // Format flags. We pass it explicitly also to 'logOperand' to make
//! // compatible with what AsmJit normally does.
-//! uint32_t arch = Environment::kArchX64;
+//! Arch arch = Arch::kX64;
//!
//! log(arch, rax); // Prints 'rax'.
//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
@@ -1571,12 +1436,12 @@ namespace asmjit {
//! using namespace asmjit;
//!
//! template
-//! void logInstruction(uint32_t arch, const BaseInst& inst, Args&&... args) {
+//! void logInstruction(Arch arch, const BaseInst& inst, Args&&... args) {
//! // The emitter is optional (named labels and virtual registers need it).
//! BaseEmitter* emitter = nullptr;
//!
//! // No flags by default.
-//! uint32_t formatFlags = FormatOptions::kNoFlags;
+//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! // The formatter expects operands in an array.
//! Operand_ operands { std::forward(args)... };
@@ -1593,7 +1458,7 @@ namespace asmjit {
//! // Architecture is not part of operand, it must be passed explicitly.
//! // Format flags. We pass it explicitly also to 'logOperand' to make
//! // compatible with what AsmJit normally does.
-//! uint32_t arch = Environment::kArchX64;
+//! Arch arch = Arch::kX64;
//!
//! // Prints 'mov rax, rcx'.
//! logInstruction(arch, BaseInst(Inst::kIdMov), rax, rcx);
@@ -1606,19 +1471,19 @@ namespace asmjit {
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
//! // Prints 'lock add [rax], rcx'.
//! logInstruction(arch,
-//! BaseInst(Inst::kIdAdd, Inst::kOptionLock),
+//! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock),
//! x86::ptr(rax), rcx);
//!
//! // Similarly an extra register (like AVX-512 selector) can be used.
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
//! logInstruction(arch,
-//! BaseInst(Inst::kIdAdd, Inst::kOptionZMask, k2),
+//! BaseInst(Inst::kIdAdd, InstOptions::kX86_ZMask, k2),
//! zmm0, zmm1, ptr(rax));
//! }
//! ```
//!
-//! And finally, the example below illustrates how to use a built-in function
-//! to format the content of \ref BaseBuilder, which consists of nodes:
+//! And finally, the example below illustrates how to use a built-in function to format the content of
+//! \ref BaseBuilder, which consists of nodes:
//!
//! ```
//! #include
@@ -1627,7 +1492,7 @@ namespace asmjit {
//! using namespace asmjit;
//!
//! void formattingExample(BaseBuilder* builder) {
-//! uint32_t formatFlags = FormatOptions::kNoFlags;
+//! FormatFlags formatFlags = FormatFlags::kNone;
//!
//! // This also shows how temporary strings can be used.
//! StringTmp<512> sb;
@@ -1644,40 +1509,30 @@ namespace asmjit {
//! }
//! ```
-// ============================================================================
-// [Documentation - asmjit_error_handling]
-// ============================================================================
//! \defgroup asmjit_error_handling Error Handling
//! \brief Error handling.
//!
//! ### Overview
//!
-//! AsmJit uses error codes to represent and return errors. Every function that
-//! can fail returns an \ref Error code. Exceptions are never thrown by AsmJit
-//! itself even in extreme conditions like out-of-memory, but it's possible to
-//! override \ref ErrorHandler::handleError() to throw, in that case no error
-//! will be returned and exception will be thrown instead. All functions where
-//! this can happen are not marked `noexcept`.
+//! AsmJit uses error codes to represent and return errors. Every function that can fail returns an \ref Error code.
+//! Exceptions are never thrown by AsmJit itself even in extreme conditions like out-of-memory, but it's possible to
+//! override \ref ErrorHandler::handleError() to throw, in that case no error will be returned and exception will be
+//! thrown instead. All functions where this can happen are not marked `noexcept`.
//!
-//! Errors should never be ignored, however, checking errors after each AsmJit
-//! API call would simply overcomplicate the whole code generation experience.
-//! \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows
+//! Errors should never be ignored, however, checking errors after each AsmJit API call would simply overcomplicate
+//! the whole code generation experience. \ref ErrorHandler exists to make the use of AsmJit API simpler as it allows
//! to customize how errors can be handled:
//!
//! - Record the error and continue (the way how the error is user-implemented).
-//! - Throw an exception. AsmJit doesn't use exceptions and is completely
-//! exception-safe, but it's perfectly legal to throw an exception from
-//! the error handler.
-//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler,
-//! Builder and Compiler to a consistent state before calling \ref
-//! ErrorHandler::handleError(), so `longjmp()` can be used without issues to
-//! cancel the code-generation if an error occurred. This method can be used if
-//! exception handling in your project is turned off and you still want some
-//! comfort. In most cases it should be safe as AsmJit uses \ref Zone memory
-//! and the ownership of memory it allocates always ends with the instance that
-//! allocated it. If using this approach please never jump outside the life-time
-//! of \ref CodeHolder and \ref BaseEmitter.
+//! - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
+//! to throw an exception from the error handler.
+//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to a
+//! consistent state before calling \ref ErrorHandler::handleError(), so `longjmp()` can be used without issues
+//! to cancel the code-generation if an error occurred. This method can be used if exception handling in your
+//! project is turned off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref
+//! Zone memory and the ownership of memory it allocates always ends with the instance that allocated it. If
+//! using this approach please never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
//!
//! ### Using ErrorHandler
//!
@@ -1719,69 +1574,56 @@ namespace asmjit {
//! - See \ref Error that lists error codes that AsmJit uses.
//! - See \ref ErrorHandler for more details about error handling.
-// ============================================================================
-// [Documentation - asmjit_instruction_db]
-// ============================================================================
//! \defgroup asmjit_instruction_db Instruction DB
//! \brief Instruction database (introspection, read/write, validation, ...).
//!
//! ### Overview
//!
-//! AsmJit provides a public instruction database that can be used to query
-//! information about a complete instruction. The instruction database requires
-//! the knowledge of the following:
+//! AsmJit provides a public instruction database that can be used to query information about a complete instruction.
+//! The instruction database requires the knowledge of the following:
+//!
+//! - \ref BaseInst - Base instruction that contains instruction id, options, and a possible extra-register that
+//! represents either REP prefix counter or AVX-512 selector (mask).
//!
-//! - \ref BaseInst - Base instruction that contains instruction id, options,
-//! and a possible extra-register that represents either REP prefix counter
-//! or AVX-512 selector (mask).
//! - \ref Operand - Represents operands of an instruction.
//!
//! Each instruction can be then queried for the following information:
//!
-//! - \ref InstRWInfo - Read/write information of instruction and its oprands.
-//! - \ref OpRWInfo - Read/write information of a single operand, part of
-//! \ref InstRWInfo data structure.
-//! - \ref BaseFeatures - CPU features required to execute the instruction.
+//! - \ref InstRWInfo - Read/write information of instruction and its oprands (includes \ref OpRWInfo).
//!
-//! In addition to query functionality AsmJit is also able to validate whether
-//! an instruction and its operands are valid. This is useful for making sure
-//! that what user tries to emit is correct and it can be also used by other
+//! - \ref CpuFeatures - CPU features required to execute the instruction.
+//!
+//! In addition to query functionality AsmJit is also able to validate whether an instruction and its operands are
+//! valid. This is useful for making sure that what user tries to emit is correct and it can be also used by other
//! projects that parse user input, like AsmTK project.
//!
//! ### Query API
//!
-//! The instruction query API is provided by \ref InstAPI namespace. The
-//! following queries are possible:
+//! The instruction query API is provided by \ref InstAPI namespace. The following queries are possible:
//!
-//! - \ref InstAPI::queryRWInfo() - queries read/write information of the
-//! given instruction and its operands. Includes also CPU flags read/written.
+//! - \ref InstAPI::queryRWInfo() - queries read/write information of the given instruction and its operands.
+//! Includes also CPU flags read/written.
//!
-//! - \ref InstAPI::queryFeatures() - queries CPU features that are required
-//! to execute the given instruction. A full instruction with operands must
-//! be given as some architectures like X86 may require different features
-//! for the same instruction based on its operands.
+//! - \ref InstAPI::queryFeatures() - queries CPU features that are required to execute the given instruction. A full
+//! instruction with operands must be given as some architectures like X86 may require different features for the
+//! same instruction based on its operands.
//!
-//! - asmjit_test_x86_instinfo.cpp
+//! - asmjit_test_instinfo.cpp
//! can be also used as a reference about accessing instruction information.
//!
//! ### Validation API
//!
-//! The instruction validation API is provided by \ref InstAPI namespace in the
-//! similar fashion like the Query API, however, validation can also be turned
-//! on at \ref BaseEmitter level. The following is possible:
+//! The instruction validation API is provided by \ref InstAPI namespace in the similar fashion like the Query API,
+//! however, validation can also be turned on at \ref BaseEmitter level. The following is possible:
//!
-//! - \ref InstAPI::validate() - low-level instruction validation function
-//! that is used internally by emitters if strict validation is enabled.
+//! - \ref InstAPI::validate() - low-level instruction validation function that is used internally by emitters
+//! if strict validation is enabled.
//!
-//! - \ref BaseEmitter::addValidationOptions() - can be used to enable
-//! validation at emitter level, see \ref BaseEmitter::ValidationOptions.
+//! - \ref BaseEmitter::addDiagnosticOptions() - can be used to enable validation at emitter level, see \ref
+//! DiagnosticOptions.
-// ============================================================================
-// [Documentation - asmjit_virtual_memory]
-// ============================================================================
-
//! \defgroup asmjit_virtual_memory Virtual Memory
//! \brief Virtual memory management.
//!
@@ -1789,53 +1631,42 @@ namespace asmjit {
//!
//! AsmJit's virtual memory management is divided into two main categories:
//!
-//! - Low level API that provides cross-platform abstractions for virtual
-//! memory allocation. Implemented in \ref VirtMem namespace.
-//! - High level API that makes it very easy to store generated code for
-//! execution. See \ref JitRuntime, which is used by many examples for its
-//! simplicity and easy integration with \ref CodeHolder. There is also
-//! \ref JitAllocator, which lays somewhere between RAW memory allocation
-//! and \ref JitRuntime.
+//! - Low level API that provides cross-platform abstractions for virtual memory allocation. Implemented in
+//! \ref VirtMem namespace.
+//!
+//! - High level API that makes it very easy to store generated code for execution. See \ref JitRuntime, which is
+//! used by many examples for its simplicity and easy integration with \ref CodeHolder. There is also \ref
+//! JitAllocator, which lays somewhere between RAW memory allocation and \ref JitRuntime.
-// ============================================================================
-// [Documentation - asmjit_zone_memory]
-// ============================================================================
//! \defgroup asmjit_zone Zone Memory
//! \brief Zone memory allocator and containers.
//!
//! ### Overview
//!
-//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate
-//! most of the data it uses. It's a fast allocator that allows AsmJit to allocate
-//! a lot of small data structures fast and without `malloc()` overhead. Since
-//! code generators and all related classes are usually short-lived this approach
-//! decreases memory usage and fragmentation as arena-based allocators always
-//! allocate larger blocks of memory, which are then split into smaller chunks.
+//! AsmJit uses zone memory allocation (also known as Arena allocation) to allocate most of the data it uses. It's a
+//! fast allocator that allows AsmJit to allocate a lot of small data structures fast and without `malloc()` overhead.
+//! Since code generators and all related classes are usually short-lived this approach decreases memory usage and
+//! fragmentation as arena-based allocators always allocate larger blocks of memory, which are then split into smaller
+//! chunks.
//!
-//! Another advantage of zone memory allocation is that since the whole library
-//! uses this strategy it's very easy to deallocate everything that a particular
-//! instance is holding by simply releasing the memory the allocator holds. This
-//! improves destruction time of such objects as there is no destruction at all.
-//! Long-lived objects just reset its data in destructor or in their reset()
-//! member function for a future reuse. For this purpose all containers in AsmJit
-//! are also zone allocated.
+//! Another advantage of zone memory allocation is that since the whole library uses this strategy it's very easy to
+//! deallocate everything that a particular instance is holding by simply releasing the memory the allocator holds.
+//! This improves destruction time of such objects as there is no destruction at all. Long-lived objects just reset
+//! its data in destructor or in their reset() member function for a future reuse. For this purpose all containers in
+//! AsmJit are also zone allocated.
//!
//! ### Zone Allocation
//!
-//! - \ref Zone - Incremental zone memory allocator with minimum features. It
-//! can only allocate memory without the possibility to return it back to
-//! the allocator.
+//! - \ref Zone - Incremental zone memory allocator with minimum features. It can only allocate memory without the
+//! possibility to return it back to the allocator.
//!
-//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage.
-//! If the allocation requests fit the static storage allocated then there
-//! will be no dynamic memory allocation during the lifetime of \ref ZoneTmp,
-//! otherwise it would act as \ref Zone with one preallocated block on the
-//! stack.
+//! - \ref ZoneTmp - A temporary \ref Zone with some initial static storage. If the allocation requests fit the
+//! static storage allocated then there will be no dynamic memory allocation during the lifetime of \ref ZoneTmp,
+//! otherwise it would act as \ref Zone with one preallocated block on the stack.
//!
-//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability
-//! of returning memory to the allocator. Such memory is stored in a pool for
-//! later reuse.
+//! - \ref ZoneAllocator - A wrapper of \ref Zone that provides the capability of returning memory to the allocator.
+//! Such memory is stored in a pool for later reuse.
//!
//! ### Zone Allocated Containers
//!
@@ -1849,11 +1680,10 @@ namespace asmjit {
//!
//! ### Using Zone Allocated Containers
//!
-//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very
-//! similar to `std::vector`, but the implementation doesn't use exceptions and
-//! uses the mentioned \ref ZoneAllocator for performance reasons. You don't have
-//! to worry about allocations as you should not need to add items to AsmJit's
-//! data structures directly as there should be API for all required operations.
+//! The most common data structure exposed by AsmJit is \ref ZoneVector. It's very similar to `std::vector`, but the
+//! implementation doesn't use exceptions and uses the mentioned \ref ZoneAllocator for performance reasons. You don't
+//! have to worry about allocations as you should not need to add items to AsmJit's data structures directly as there
+//! should be API for all required operations.
//!
//! The following APIs in \ref CodeHolder returns \ref ZoneVector reference:
//!
@@ -1875,10 +1705,9 @@ namespace asmjit {
//! }
//! ```
//!
-//! \ref ZoneVector has overloaded array access operator to make it possible
-//! to access its elements through operator[]. Some standard functions like
-//! \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data()
-//! are provided as well. Vectors are also iterable through a range-based for loop:
+//! \ref ZoneVector has overloaded array access operator to make it possible to access its elements through operator[].
+//! Some standard functions like \ref ZoneVector::empty(), \ref ZoneVector::size(), and \ref ZoneVector::data() are
+//! provided as well. Vectors are also iterable through a range-based for loop:
//!
//! ```
//! using namespace asmjit;
@@ -1895,15 +1724,13 @@ namespace asmjit {
//!
//! ### Design Considerations
//!
-//! Zone-allocated containers do not store the allocator within the container.
-//! This decision was made to reduce the footprint of such containers as AsmJit
-//! tooling, especially Compiler's register allocation, may use many instances
+//! Zone-allocated containers do not store the allocator within the container. This decision was made to reduce the
+//! footprint of such containers as AsmJit tooling, especially Compiler's register allocation, may use many instances
//! of such containers to perform code analysis and register allocation.
//!
-//! For example to append an item into a \ref ZoneVector it's required to pass
-//! the allocator as the first argument, so it can be used in case that the
-//! vector needs a reallocation. Such function also returns an error, which
-//! must be propagated to the caller.
+//! For example to append an item into a \ref ZoneVector it's required to pass the allocator as the first argument,
+//! so it can be used in case that the vector needs a reallocation. Such function also returns an error, which must
+//! be propagated to the caller.
//!
//! ```
//! using namespace asmjit
@@ -1927,10 +1754,9 @@ namespace asmjit {
//! }
//! ```
//!
-//! Containers like \ref ZoneVector also provide a functionality to reserve a
-//! certain number of items before any items are added to it. This approach is
-//! used internally in most places as it allows to prepare space for data that
-//! will be added to some container before the data itself was created.
+//! Containers like \ref ZoneVector also provide a functionality to reserve a certain number of items before any items
+//! are added to it. This approach is used internally in most places as it allows to prepare space for data that will
+//! be added to some container before the data itself was created.
//!
//! ```
//! using namespace asmjit
@@ -1948,60 +1774,44 @@ namespace asmjit {
//! }
//! ```
-// ============================================================================
-// [Documentation - asmjit_utilities]
-// ============================================================================
//! \defgroup asmjit_utilities Utilities
//! \brief Utility classes and functions.
//!
//! ### Overview
//!
-//! AsmJit uses and provides utility classes and functions, that can be used
-//! with AsmJit. The functionality can be divided into the following topics:
+//! AsmJit uses and provides utility classes and functions, that can be used with AsmJit. The functionality can be
+//! divided into the following topics:
//!
//! ### String Functionality
//!
-//! - \ref String - AsmJit's string container, which is used internally
-//! and which doesn't use exceptions and has a stable layout, which is
-//! not dependent on C++ standard library.
-//! - \ref StringTmp - String that can have base storage allocated on
-//! stack. The amount of storage on stack can be specified as a template
-//! parameter.
+//! - \ref String - AsmJit's string container, which is used internally and which doesn't use exceptions and has
+//! a stable layout, which is not dependent on C++ standard library.
+//!
+//! - \ref StringTmp - String that can have base storage allocated on stack. The amount of storage on stack can
+//! be specified as a template parameter.
+//!
//! - \ref FixedString - Fixed string container limited up to N characters.
//!
//! ### Code Generation Utilities
//!
-//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also
-//! available to users that may find use of it.
+//! - \ref ConstPool - Constant pool used by \ref BaseCompiler, but also available to users that may find use of it.
//!
//! ### Support Functionality Used by AsmJit
//!
-//! - \ref Support namespace provides many other utility functions and
-//! classes that are used by AsmJit, and made public.
+//! - \ref Support namespace provides many other utility functions and classes that are used by AsmJit, and made
+//! public.
-// ============================================================================
-// [Documentation - asmjit_ backends]
-// ============================================================================
//! \defgroup asmjit_x86 X86 Backend
//! \brief X86/X64 backend.
-// ============================================================================
-// [Documentation - asmjit_ra]
-// ============================================================================
//! \cond INTERNAL
//! \defgroup asmjit_ra RA
//! \brief Register allocator internals.
//! \endcond
-} // {asmjit}
-
-// ============================================================================
-// [Core Headers]
-// ============================================================================
-
#include "asmjit-scope-begin.h"
#include "core/archtraits.h"
#include "core/assembler.h"
@@ -2010,11 +1820,9 @@ namespace asmjit {
#include "core/compiler.h"
#include "core/constpool.h"
#include "core/cpuinfo.h"
-#include "core/datatypes.h"
#include "core/emitter.h"
#include "core/environment.h"
#include "core/errorhandler.h"
-#include "core/features.h"
#include "core/formatter.h"
#include "core/func.h"
#include "core/globals.h"
@@ -2038,23 +1846,4 @@ namespace asmjit {
#include "core/zonevector.h"
#include "asmjit-scope-end.h"
-// ============================================================================
-// [Deprecated]
-// ============================================================================
-
-#ifndef ASMJIT_NO_DEPRECATED
-namespace asmjit {
-
-#ifndef ASMJIT_NO_COMPILER
-ASMJIT_DEPRECATED("Use InvokeNode instead of FuncCallNode")
-typedef InvokeNode FuncCallNode;
-#endif // !ASMJIT_NO_COMPILER
-
-#ifndef ASMJIT_NO_LOGGING
-namespace Logging { using namespace Formatter; }
-#endif //! ASMJIT_NO_LOGGING
-
-} // {asmjit}
-#endif // !ASMJIT_NO_DEPRECATED
-
#endif // ASMJIT_CORE_H_INCLUDED
diff --git a/src/asmjit/core/api-build_p.h b/src/asmjit/core/api-build_p.h
index db37ca7..6eca971 100644
--- a/src/asmjit/core/api-build_p.h
+++ b/src/asmjit/core/api-build_p.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_API_BUILD_P_H_INCLUDED
#define ASMJIT_CORE_API_BUILD_P_H_INCLUDED
@@ -47,10 +29,6 @@
#include
#endif
-// ============================================================================
-// [asmjit::Build - Globals - Build-Only]
-// ============================================================================
-
#include "./api-config.h"
#if !defined(ASMJIT_BUILD_DEBUG) && defined(__GNUC__) && !defined(__clang__)
diff --git a/src/asmjit/core/api-config.h b/src/asmjit/core/api-config.h
index c3f1080..7407c57 100644
--- a/src/asmjit/core/api-config.h
+++ b/src/asmjit/core/api-config.h
@@ -1,48 +1,59 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_API_CONFIG_H_INCLUDED
#define ASMJIT_CORE_API_CONFIG_H_INCLUDED
-// ============================================================================
-// [asmjit::Version]
-// ============================================================================
+// AsmJit Library & ABI Version
+// ============================
//! \addtogroup asmjit_core
//! \{
//! 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
//! \}
-// ============================================================================
-// [asmjit::Build - Documentation]
-// ============================================================================
+// Global Dependencies
+// ===================
-// NOTE: Doxygen cannot document macros that are not defined, that's why we have
-// to define them and then undefine them, so it won't use the macros with its
-// own preprocessor.
+#include
+#include
+#include // We really want std types as globals, not under 'std' namespace.
+#include
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+
+#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
+ #include
+#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
namespace asmjit {
@@ -80,10 +91,10 @@ namespace asmjit {
//! Disables \ref asmjit_compiler functionality completely.
#define ASMJIT_NO_COMPILER
-//! Disables JIT memory management and \ref JitRuntime.
+//! Disables JIT memory management and \ref asmjit::JitRuntime.
#define ASMJIT_NO_JIT
-//! Disables \ref Logger and \ref Formatter.
+//! Disables \ref asmjit::Logger and \ref asmjit::Formatter.
#define ASMJIT_NO_LOGGING
//! Disables everything that contains text.
@@ -116,33 +127,6 @@ namespace asmjit {
} // {asmjit}
#endif // _DOXYGEN
-// ============================================================================
-// [asmjit::Dependencies]
-// ============================================================================
-
-// We really want std-types as globals.
-#include
-#include
-#include
-#include
-#include
-#include
-
-#include
-#include
-#include
-#include
-#include
-
-#if !defined(_WIN32) && !defined(__EMSCRIPTEN__)
- #include
-#endif
-
-
-// ============================================================================
-// [asmjit::Options]
-// ============================================================================
-
// ASMJIT_NO_BUILDER implies ASMJIT_NO_COMPILER.
#if defined(ASMJIT_NO_BUILDER) && !defined(ASMJIT_NO_COMPILER)
#define ASMJIT_NO_COMPILER
@@ -150,37 +134,17 @@ namespace asmjit {
// Prevent compile-time errors caused by misconfiguration.
#if defined(ASMJIT_NO_TEXT) && !defined(ASMJIT_NO_LOGGING)
- #pragma "ASMJIT_NO_TEXT can only be defined when ASMJIT_NO_LOGGING is defined."
+ #pragma message("'ASMJIT_NO_TEXT' can only be defined when 'ASMJIT_NO_LOGGING' is defined.")
#undef ASMJIT_NO_TEXT
#endif
#if defined(ASMJIT_NO_INTROSPECTION) && !defined(ASMJIT_NO_COMPILER)
- #pragma message("ASMJIT_NO_INTROSPECTION can only be defined when ASMJIT_NO_COMPILER is defined")
+ #pragma message("'ASMJIT_NO_INTROSPECTION' can only be defined when 'ASMJIT_NO_COMPILER' is defined")
#undef ASMJIT_NO_INTROSPECTION
#endif
-// ============================================================================
-// [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]
-// ============================================================================
+// Build Mode
+// ==========
// Detect ASMJIT_BUILD_DEBUG and ASMJIT_BUILD_RELEASE if not defined.
#if !defined(ASMJIT_BUILD_DEBUG) && !defined(ASMJIT_BUILD_RELEASE)
@@ -191,9 +155,8 @@ namespace asmjit {
#endif
#endif
-// ============================================================================
-// [asmjit::Build - Globals - Target Architecture Information]
-// ============================================================================
+// Target Architecture Detection
+// =============================
#if defined(_M_X64) || defined(__x86_64__)
#define ASMJIT_ARCH_X86 64
@@ -239,19 +202,15 @@ namespace asmjit {
#define ASMJIT_ARCH_BE 0
#endif
-// ============================================================================
-// [asmjit::Build - Globals - Backends]
-// ============================================================================
-
#if defined(ASMJIT_NO_FOREIGN)
#if !ASMJIT_ARCH_X86 && !defined(ASMJIT_NO_X86)
#define ASMJIT_NO_X86
#endif
#endif
-// ============================================================================
-// [asmjit::Build - Globals - C++ Compiler and Features Detection]
-// ============================================================================
+
+// C++ Compiler and Features Detection
+// ===================================
#define ASMJIT_CXX_GNU 0
#define ASMJIT_CXX_MAKE_VER(MAJOR, MINOR) ((MAJOR) * 1000 + (MINOR))
@@ -293,9 +252,12 @@ namespace asmjit {
#define ASMJIT_CXX_HAS_ATTRIBUTE(NAME, CHECK) (!(!(CHECK)))
#endif
-// ============================================================================
-// [asmjit::Build - Globals - API Decorators & Language Extensions]
-// ============================================================================
+// API Decorators & C++ Extensions
+// ===============================
+
+//! \def ASMJIT_API
+//!
+//! A decorator that is used to decorate API that AsmJit exports when built as a shared library.
// API (Export / Import).
#if !defined(ASMJIT_STATIC)
@@ -324,12 +286,12 @@ namespace asmjit {
#define ASMJIT_VARAPI extern ASMJIT_API
#endif
-// This is basically a workaround. When using MSVC and marking class as DLL
-// export everything gets exported, which is unwanted in most projects. MSVC
-// automatically exports typeinfo and vtable if at least one symbol of the
-// class is exported. However, GCC has some strange behavior that even if
-// one or more symbol is exported it doesn't export typeinfo unless the
-// class itself is decorated with "visibility(default)" (i.e. ASMJIT_API).
+//! \def ASMJIT_VIRTAPI
+//!
+//! This is basically a workaround. When using MSVC and marking class as DLL export everything gets exported, which
+//! is unwanted in most projects. MSVC automatically exports typeinfo and vtable if at least one symbol of the class
+//! is exported. However, GCC has some strange behavior that even if one or more symbol is exported it doesn't export
+//! typeinfo unless the class itself is decorated with "visibility(default)" (i.e. ASMJIT_API).
#if !defined(_WIN32) && defined(__GNUC__)
#define ASMJIT_VIRTAPI ASMJIT_API
#else
@@ -338,11 +300,11 @@ namespace asmjit {
// Function attributes.
#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)
- #define ASMJIT_INLINE __forceinline
+ #define ASMJIT_FORCE_INLINE __forceinline
#else
- #define ASMJIT_INLINE inline
+ #define ASMJIT_FORCE_INLINE inline
#endif
#if defined(__GNUC__)
@@ -401,6 +363,17 @@ namespace asmjit {
#define ASMJIT_MAY_ALIAS
#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(...)
//!
//! Condition is likely to be taken (mostly error handling and edge cases).
@@ -457,49 +430,51 @@ namespace asmjit {
#define ASMJIT_ATTRIBUTE_NO_SANITIZE_UNDEF
#endif
-// ============================================================================
-// [asmjit::Build - Globals - Begin-Namespace / End-Namespace]
-// ============================================================================
+// Begin-Namespace & End-Namespace Macros
+// ======================================
-#if defined(__clang__)
+#if defined _DOXYGEN
+ #define ASMJIT_BEGIN_NAMESPACE namespace asmjit {
+ #define ASMJIT_END_NAMESPACE }
+#elif defined(__clang__)
#define ASMJIT_BEGIN_NAMESPACE \
- namespace asmjit { \
+ namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
_Pragma("clang diagnostic push") \
_Pragma("clang diagnostic ignored \"-Wconstant-logical-operand\"") \
_Pragma("clang diagnostic ignored \"-Wunnamed-type-template-args\"")
#define ASMJIT_END_NAMESPACE \
_Pragma("clang diagnostic pop") \
- }
+ }}
#elif defined(__GNUC__) && __GNUC__ == 4
#define ASMJIT_BEGIN_NAMESPACE \
- namespace asmjit { \
+ namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wmissing-field-initializers\"")
#define ASMJIT_END_NAMESPACE \
_Pragma("GCC diagnostic pop") \
- }
+ }}
#elif defined(__GNUC__) && __GNUC__ >= 8
#define ASMJIT_BEGIN_NAMESPACE \
- namespace asmjit { \
+ namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
_Pragma("GCC diagnostic push") \
_Pragma("GCC diagnostic ignored \"-Wclass-memaccess\"")
#define ASMJIT_END_NAMESPACE \
_Pragma("GCC diagnostic pop") \
- }
+ }}
#elif defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define ASMJIT_BEGIN_NAMESPACE \
- namespace asmjit { \
+ namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE { \
__pragma(warning(push)) \
__pragma(warning(disable: 4127)) /* conditional expression is const */ \
__pragma(warning(disable: 4201)) /* nameless struct/union */
#define ASMJIT_END_NAMESPACE \
__pragma(warning(pop)) \
- }
+ }}
#endif
#if !defined(ASMJIT_BEGIN_NAMESPACE) && !defined(ASMJIT_END_NAMESPACE)
- #define ASMJIT_BEGIN_NAMESPACE namespace asmjit {
- #define ASMJIT_END_NAMESPACE }
+ #define ASMJIT_BEGIN_NAMESPACE namespace asmjit { inline namespace ASMJIT_ABI_NAMESPACE {
+ #define ASMJIT_END_NAMESPACE }}
#endif
#define ASMJIT_BEGIN_SUB_NAMESPACE(NAMESPACE) \
@@ -510,9 +485,8 @@ namespace asmjit {
} \
ASMJIT_END_NAMESPACE
-// ============================================================================
-// [asmjit::Build - Globals - Utilities]
-// ============================================================================
+// C++ Utilities
+// =============
#define ASMJIT_NONCOPYABLE(Type) \
Type(const Type& other) = delete; \
@@ -523,11 +497,71 @@ namespace asmjit {
Type(const Type& other) = delete; \
Type& operator=(const Type& other) = delete;
-// ============================================================================
-// [asmjit::Build - Globals - Cleanup]
-// ============================================================================
+//! \def ASMJIT_DEFINE_ENUM_FLAGS(T)
+//!
+//! 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::type)(a)); \
+ } \
+ \
+ static ASMJIT_FORCE_INLINE constexpr T operator|(T a, T b) noexcept { \
+ return T((std::underlying_type::type)(a) | \
+ (std::underlying_type::type)(b)); \
+ } \
+ static ASMJIT_FORCE_INLINE constexpr T operator&(T a, T b) noexcept { \
+ return T((std::underlying_type::type)(a) & \
+ (std::underlying_type::type)(b)); \
+ } \
+ static ASMJIT_FORCE_INLINE constexpr T operator^(T a, T b) noexcept { \
+ return T((std::underlying_type::type)(a) ^ \
+ (std::underlying_type::type)(b)); \
+ } \
+ \
+ static ASMJIT_FORCE_INLINE T& operator|=(T& a, T b) noexcept { \
+ a = T((std::underlying_type::type)(a) | \
+ (std::underlying_type::type)(b)); \
+ return a; \
+ } \
+ static ASMJIT_FORCE_INLINE T& operator&=(T& a, T b) noexcept { \
+ a = T((std::underlying_type::type)(a) & \
+ (std::underlying_type::type)(b)); \
+ return a; \
+ } \
+ static ASMJIT_FORCE_INLINE T& operator^=(T& a, T b) noexcept { \
+ a = T((std::underlying_type::type)(a) ^ \
+ (std::underlying_type::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::type)(a) < (std::underlying_type::type)(b); \
+ } \
+ static ASMJIT_FORCE_INLINE bool operator<=(T a, T b) noexcept { \
+ return (std::underlying_type::type)(a) <= (std::underlying_type::type)(b); \
+ } \
+ static ASMJIT_FORCE_INLINE bool operator>(T a, T b) noexcept { \
+ return (std::underlying_type::type)(a) > (std::underlying_type::type)(b); \
+ } \
+ static ASMJIT_FORCE_INLINE bool operator>=(T a, T b) noexcept { \
+ return (std::underlying_type::type)(a) >= (std::underlying_type::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_MAKE_VER
diff --git a/src/asmjit/core/archcommons.h b/src/asmjit/core/archcommons.h
index fda2451..88b6069 100644
--- a/src/asmjit/core/archcommons.h
+++ b/src/asmjit/core/archcommons.h
@@ -1,106 +1,82 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
#define ASMJIT_CORE_ARCHCOMMONS_H_INCLUDED
-// This file provides architecture-specific classes that are required in the
-// core library. For example Imm operand allows to be created from arm::Shift
-// in a const-expr way, so the arm::Shift must be provided. So this header
-// file provides everything architecture-specific that is used by the Core API.
+// This file provides architecture-specific classes that are required in the core library. For example Imm operand
+// allows to be created from arm::Shift in a const-expr way, so the arm::Shift must be provided. So this header file
+// provides everything architecture-specific that is used by the Core API.
#include "../core/globals.h"
-// ============================================================================
-// [asmjit::arm]
-// ============================================================================
-
ASMJIT_BEGIN_SUB_NAMESPACE(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.
class Shift {
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.
- uint32_t _op;
+ ShiftOp _op;
//! Shift Value.
uint32_t _value;
@@ -111,51 +87,51 @@ public:
constexpr Shift(const Shift& other) noexcept = default;
//! 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),
_value(value) {}
//! 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.
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`.
inline void setValue(uint32_t value) noexcept { _value = value; }
};
//! 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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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).
-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); }
//! \}
diff --git a/src/asmjit/core/archtraits.cpp b/src/asmjit/core/archtraits.cpp
index 6c50bb1..8b79ee2 100644
--- a/src/asmjit/core/archtraits.cpp
+++ b/src/asmjit/core/archtraits.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/archtraits.h"
@@ -35,10 +17,6 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::ArchTraits]
-// ============================================================================
-
static const constexpr ArchTraits noArchTraits = {
// SP/FP/LR/PC.
0xFF, 0xFF, 0xFF, 0xFF,
@@ -53,27 +31,38 @@ static const constexpr ArchTraits noArchTraits = {
0, 0,
// ISA features [Gp, Vec, Other0, Other1].
- { 0, 0, 0, 0},
+ {{
+ InstHints::kNoHints,
+ InstHints::kNoHints,
+ InstHints::kNoHints,
+ InstHints::kNoHints
+ }},
// RegTypeToSignature.
- { { 0 } },
+ #define V(index) { OperandSignature(0) }
+ {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
+ #undef V
// RegTypeToTypeId.
- { 0 },
+ #define V(index) TypeId::kVoid
+ {{ ASMJIT_LOOKUP_TABLE_32(V, 0) }},
+ #undef V
// 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.
{
- ISAWordNameId::kByte,
- ISAWordNameId::kHalf,
- ISAWordNameId::kWord,
- ISAWordNameId::kQuad
+ ArchTypeNameId::kByte,
+ ArchTypeNameId::kHalf,
+ ArchTypeNameId::kWord,
+ ArchTypeNameId::kQuad
}
};
-ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
+ASMJIT_VARAPI const ArchTraits _archTraits[uint32_t(Arch::kMaxValue) + 1] = {
// No architecture.
noArchTraits,
@@ -111,63 +100,60 @@ ASMJIT_VARAPI const ArchTraits _archTraits[Environment::kArchCount] = {
noArchTraits
};
-// ============================================================================
-// [asmjit::ArchUtils]
-// ============================================================================
-
-ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t arch, uint32_t typeId, uint32_t* typeIdOut, RegInfo* regInfoOut) noexcept {
+ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegSignature(Arch arch, TypeId typeId, TypeId* typeIdOut, OperandSignature* regSignatureOut) noexcept {
const ArchTraits& archTraits = ArchTraits::byArch(arch);
+ // TODO: Remove this, should never be used like this.
// Passed RegType instead of TypeId?
- if (typeId <= BaseReg::kTypeMax)
- typeId = archTraits.regTypeToTypeId(typeId);
+ if (uint32_t(typeId) <= uint32_t(RegType::kMaxValue))
+ typeId = archTraits.regTypeToTypeId(RegType(uint32_t(typeId)));
- if (ASMJIT_UNLIKELY(!Type::isValid(typeId)))
+ if (ASMJIT_UNLIKELY(!TypeUtils::isValid(typeId)))
return DebugUtils::errored(kErrorInvalidTypeId);
// First normalize architecture dependent types.
- if (Type::isAbstract(typeId)) {
+ if (TypeUtils::isAbstract(typeId)) {
bool is32Bit = Environment::is32Bit(arch);
- if (typeId == Type::kIdIntPtr)
- typeId = is32Bit ? Type::kIdI32 : Type::kIdI64;
+ if (typeId == TypeId::kIntPtr)
+ typeId = is32Bit ? TypeId::kInt32 : TypeId::kInt64;
else
- typeId = is32Bit ? Type::kIdU32 : Type::kIdU64;
+ typeId = is32Bit ? TypeId::kUInt32 : TypeId::kUInt64;
}
// Type size helps to construct all groups of registers.
// TypeId is invalid if the size is zero.
- uint32_t size = Type::sizeOf(typeId);
+ uint32_t size = TypeUtils::sizeOf(typeId);
if (ASMJIT_UNLIKELY(!size))
return DebugUtils::errored(kErrorInvalidTypeId);
- if (ASMJIT_UNLIKELY(typeId == Type::kIdF80))
+ if (ASMJIT_UNLIKELY(typeId == TypeId::kFloat80))
return DebugUtils::errored(kErrorInvalidUseOfF80);
- uint32_t regType = 0;
- if (typeId >= Type::_kIdBaseStart && typeId < Type::_kIdVec32Start) {
- regType = archTraits._typeIdToRegType[typeId - Type::_kIdBaseStart];
- if (!regType) {
- if (typeId == Type::kIdI64 || typeId == Type::kIdU64)
+ RegType regType = RegType::kNone;
+ if (TypeUtils::isBetween(typeId, TypeId::_kBaseStart, TypeId::_kVec32Start)) {
+ regType = archTraits._typeIdToRegType[uint32_t(typeId) - uint32_t(TypeId::_kBaseStart)];
+ if (regType == RegType::kNone) {
+ if (typeId == TypeId::kInt64 || typeId == TypeId::kUInt64)
return DebugUtils::errored(kErrorInvalidUseOfGpq);
else
return DebugUtils::errored(kErrorInvalidTypeId);
}
}
else {
- if (size <= 8 && archTraits._regInfo[BaseReg::kTypeVec64].isValid())
- regType = BaseReg::kTypeVec64;
- else if (size <= 16 && archTraits._regInfo[BaseReg::kTypeVec128].isValid())
- regType = BaseReg::kTypeVec128;
- else if (size == 32 && archTraits._regInfo[BaseReg::kTypeVec256].isValid())
- regType = BaseReg::kTypeVec256;
- else if (archTraits._regInfo[BaseReg::kTypeVec512].isValid())
- regType = BaseReg::kTypeVec512;
+ if (size <= 8 && archTraits._regSignature[RegType::kVec64].isValid())
+ regType = RegType::kVec64;
+ else if (size <= 16 && archTraits._regSignature[RegType::kVec128].isValid())
+ regType = RegType::kVec128;
+ else if (size == 32 && archTraits._regSignature[RegType::kVec256].isValid())
+ regType = RegType::kVec256;
+ else if (archTraits._regSignature[RegType::kVec512].isValid())
+ regType = RegType::kVec512;
else
return DebugUtils::errored(kErrorInvalidTypeId);
}
*typeIdOut = typeId;
- regInfoOut->reset(archTraits.regTypeToSignature(regType));
+ *regSignatureOut = archTraits.regTypeToSignature(regType);
return kErrorOk;
}
diff --git a/src/asmjit/core/archtraits.h b/src/asmjit/core/archtraits.h
index 43ef10f..4d05c11 100644
--- a/src/asmjit/core/archtraits.h
+++ b/src/asmjit/core/archtraits.h
@@ -1,31 +1,13 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
#define ASMJIT_CORE_ARCHTRAITS_H_INCLUDED
-#include "../core/environment.h"
#include "../core/operand.h"
+#include "../core/support.h"
#include "../core/type.h"
ASMJIT_BEGIN_NAMESPACE
@@ -33,8 +15,98 @@ ASMJIT_BEGIN_NAMESPACE
//! \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.
-enum class ISAWordNameId : uint8_t {
+enum class ArchTypeNameId : uint8_t {
//! Describes 'db' (X86/X86_64 convention, always 8-bit quantity).
kDB = 0,
//! Describes 'dw' (X86/X86_64 convention, always 16-bit word).
@@ -64,23 +136,33 @@ enum class ISAWordNameId : uint8_t {
//! Describes 'quad' (64-bit word).
kQuad,
- //! Maximum value.
+ //! Maximum value of `ArchTypeNameId`.
kMaxValue = kQuad
};
-// ============================================================================
-// [asmjit::ArchTraits]
-// ============================================================================
+//! Instruction feature hints for each register group provided by \ref 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.
struct ArchTraits {
- //! ISA features for each register group.
- 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,
- };
+ //! \name Members
+ //! \{
//! Stack pointer register id.
uint8_t _spRegId;
@@ -101,84 +183,69 @@ struct ArchTraits {
//! Maximum addressable offset on stack depending on specific instruction.
uint32_t _maxStackOffset;
- //! Flags for each virtual register group (always covers GP and Vec groups).
- uint8_t _isaFlags[BaseReg::kGroupVirt];
+ //! Flags for each virtual register group.
+ Support::Array _instHints;
- //! Maps register type into a signature, that provides group, size and can
- //! be used to construct register operands.
- RegInfo _regInfo[BaseReg::kTypeMax + 1];
- //! Maps a register to type-id, see \ref Type::Id.
- uint8_t _regTypeToTypeId[BaseReg::kTypeMax + 1];
- //! Maps base TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref Type::Id.
- uint8_t _typeIdToRegType[32];
+ //! Maps register type into a signature, that provides group, size and can be used to construct register operands.
+ Support::Array _regSignature;
+ //! Maps a register to type-id, see \ref TypeId.
+ Support::Array _regTypeToTypeId;
+ //! Maps scalar TypeId values (from TypeId::_kIdBaseStart) to register types, see \ref TypeId.
+ Support::Array _typeIdToRegType;
//! 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
//! \{
//! 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.
- 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.
- 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.
- inline constexpr uint32_t ipRegId() const noexcept { return _ipRegId; }
+ inline uint32_t ipRegId() const noexcept { return _ipRegId; }
//! Returns a hardware stack alignment requirement.
//!
- //! \note This is a hardware constraint. Architectures that don't constrain
- //! it would return the lowest alignment (1), however, some architectures may
- //! constrain the alignment, for example AArch64 requires 16-byte alignment.
- inline constexpr uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; }
+ //! \note This is a hardware constraint. Architectures that don't constrain it would return the lowest alignment
+ //! (1), however, some architectures may constrain the alignment, for example AArch64 requires 16-byte alignment.
+ inline uint32_t hwStackAlignment() const noexcept { return _hwStackAlignment; }
- //! Tests whether the architecture provides link register, which is used across
- //! function calls. If the link register is not provided then a function call
- //! pushes the return address on stack (X86/X64).
- inline constexpr bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
+ //! Tests whether the architecture provides link register, which is used across function calls. If the link
+ //! register is not provided then a function call pushes the return address on stack (X86/X64).
+ inline bool hasLinkReg() const noexcept { return _linkRegId != BaseReg::kIdBad; }
//! 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.
- 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`.
- 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.
- 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`.
- 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`.
- 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 {
- return rType <= BaseReg::kTypeMax && _regInfo[rType].signature() != 0;
+ inline bool hasRegType(RegType type) const noexcept {
+ return type <= RegType::kMaxValue && _regSignature[type].isValid();
}
- inline uint32_t regTypeToSignature(uint32_t rType) const noexcept {
- ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
- return _regInfo[rType].signature();
- }
-
- inline uint32_t regTypeToGroup(uint32_t rType) const noexcept {
- ASMJIT_ASSERT(rType <= BaseReg::kTypeMax);
- return _regInfo[rType].group();
- }
-
- 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 an operand signature from the given register `type` of this architecture.
+ inline OperandSignature regTypeToSignature(RegType type) const noexcept { return _regSignature[type]; }
+ //! 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 regTypeToSize(RegType type) const noexcept { return _regSignature[type].size(); }
+ //! Returns a corresponding `TypeId` from the given register `type` of this architecture.
+ inline TypeId regTypeToTypeId(RegType type) const noexcept { return _regTypeToTypeId[type]; }
//! Returns a table of ISA word names that appear in formatted text. Word names are ISA dependent.
//!
@@ -187,10 +254,10 @@ struct ArchTraits {
//! - [1] 16-bits
//! - [2] 32-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.
- inline ISAWordNameId isaWordNameId(uint32_t index) const noexcept { return _isaWordNameIdTable[index]; }
+ //! Returns an ISA word name identifier of the given `index`, see \ref typeNameIdTable() for more details.
+ 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`.
- 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]; }
-
-// ============================================================================
-// [asmjit::ArchUtils]
-// ============================================================================
+//! \cond
+inline const ArchTraits& ArchTraits::byArch(Arch arch) noexcept { return _archTraits[uint32_t(arch)]; }
+//! \endcond
//! Architecture utilities.
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}
diff --git a/src/asmjit/core/assembler.cpp b/src/asmjit/core/assembler.cpp
index 6f9fe00..ea223a3 100644
--- a/src/asmjit/core/assembler.cpp
+++ b/src/asmjit/core/assembler.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/assembler.h"
@@ -32,18 +14,16 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::BaseAssembler - Construction / Destruction]
-// ============================================================================
+// BaseAssembler - Construction & Destruction
+// ==========================================
BaseAssembler::BaseAssembler() noexcept
- : BaseEmitter(kTypeAssembler) {}
+ : BaseEmitter(EmitterType::kAssembler) {}
BaseAssembler::~BaseAssembler() noexcept {}
-// ============================================================================
-// [asmjit::BaseAssembler - Buffer Management]
-// ============================================================================
+// BaseAssembler - Buffer Management
+// =================================
Error BaseAssembler::setOffset(size_t offset) {
if (ASMJIT_UNLIKELY(!_code))
@@ -57,9 +37,8 @@ Error BaseAssembler::setOffset(size_t offset) {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseAssembler - Section Management]
-// ============================================================================
+// BaseAssembler - Section Management
+// ==================================
static void BaseAssembler_initSection(BaseAssembler* self, Section* section) noexcept {
uint8_t* p = section->_buffer._data;
@@ -86,9 +65,8 @@ Error BaseAssembler::section(Section* section) {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseAssembler - Label Management]
-// ============================================================================
+// BaseAssembler - Label Management
+// ================================
Label BaseAssembler::newLabel() {
uint32_t labelId = Globals::kInvalidId;
@@ -103,7 +81,7 @@ Label BaseAssembler::newLabel() {
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;
if (ASMJIT_LIKELY(_code)) {
LabelEntry* le;
@@ -134,9 +112,8 @@ Error BaseAssembler::bind(const Label& label) {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseAssembler - Embed]
-// ============================================================================
+// BaseAssembler - Embed
+// =====================
Error BaseAssembler::embed(const void* data, size_t dataSize) {
if (ASMJIT_UNLIKELY(!_code))
@@ -154,7 +131,7 @@ Error BaseAssembler::embed(const void* data, size_t dataSize) {
#ifndef ASMJIT_NO_LOGGING
if (_logger) {
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');
_logger->log(sb);
}
@@ -163,17 +140,17 @@ Error BaseAssembler::embed(const void* data, size_t dataSize) {
return kErrorOk;
}
-Error BaseAssembler::embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) {
- uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
- uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
+Error BaseAssembler::embedDataArray(TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) {
+ uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize());
+ TypeId finalTypeId = TypeUtils::deabstract(typeId, deabstractDelta);
- if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
+ if (ASMJIT_UNLIKELY(!TypeUtils::isValid(finalTypeId)))
return reportError(DebugUtils::errored(kErrorInvalidArgument));
if (itemCount == 0 || repeatCount == 0)
return kErrorOk;
- uint32_t typeSize = Type::sizeOf(finalTypeId);
+ uint32_t typeSize = TypeUtils::sizeOf(finalTypeId);
Support::FastUInt8 of = 0;
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
-static const uint8_t dataTypeIdBySize[9] = {
- Type::kIdVoid, // [0] (invalid)
- Type::kIdU8, // [1] (uint8_t)
- Type::kIdU16, // [2] (uint16_t)
- Type::kIdVoid, // [3] (invalid)
- Type::kIdU32, // [4] (uint32_t)
- Type::kIdVoid, // [5] (invalid)
- Type::kIdVoid, // [6] (invalid)
- Type::kIdVoid, // [7] (invalid)
- Type::kIdU64 // [8] (uint64_t)
+static const TypeId dataTypeIdBySize[9] = {
+ TypeId::kVoid, // [0] (invalid)
+ TypeId::kUInt8, // [1] (uint8_t)
+ TypeId::kUInt16, // [2] (uint16_t)
+ TypeId::kVoid, // [3] (invalid)
+ TypeId::kUInt32, // [4] (uint32_t)
+ TypeId::kVoid, // [5] (invalid)
+ TypeId::kVoid, // [6] (invalid)
+ TypeId::kVoid, // [7] (invalid)
+ TypeId::kUInt64 // [8] (uint64_t)
};
#endif
@@ -223,7 +200,7 @@ Error BaseAssembler::embedConstPool(const Label& label, const ConstPool& pool) {
if (ASMJIT_UNLIKELY(!isLabelValid(label)))
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));
size_t size = pool.size();
@@ -282,13 +259,13 @@ Error BaseAssembler::embedLabel(const Label& label, size_t dataSize) {
sb.append('.');
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
sb.append(' ');
- Formatter::formatLabel(sb, 0, this, label.id());
+ Formatter::formatLabel(sb, FormatFlags::kNone, this, label.id());
sb.append('\n');
_logger->log(sb);
}
#endif
- Error err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs);
+ Error err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
if (ASMJIT_UNLIKELY(err))
return reportError(err);
@@ -343,9 +320,9 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
sb.append('.');
Formatter::formatDataType(sb, _logger->flags(), arch(), dataTypeIdBySize[dataSize]);
sb.append(" (");
- Formatter::formatLabel(sb, 0, this, label.id());
+ Formatter::formatLabel(sb, FormatFlags::kNone, this, label.id());
sb.append(" - ");
- Formatter::formatLabel(sb, 0, this, base.id());
+ Formatter::formatLabel(sb, FormatFlags::kNone, this, base.id());
sb.append(")\n");
_logger->log(sb);
}
@@ -358,7 +335,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
}
else {
RelocEntry* re;
- Error err = _code->newRelocEntry(&re, RelocEntry::kTypeExpression);
+ Error err = _code->newRelocEntry(&re, RelocType::kExpression);
if (ASMJIT_UNLIKELY(err))
return reportError(err);
@@ -367,7 +344,7 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
return reportError(DebugUtils::errored(kErrorOutOfMemory));
exp->reset();
- exp->opType = Expression::kOpSub;
+ exp->opType = ExpressionOpType::kSub;
exp->setValueAsLabel(0, labelEntry);
exp->setValueAsLabel(1, baseEntry);
@@ -383,19 +360,18 @@ Error BaseAssembler::embedLabelDelta(const Label& label, const Label& base, size
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseAssembler - Comment]
-// ============================================================================
+// BaseAssembler - Comment
+// =======================
Error BaseAssembler::comment(const char* data, size_t size) {
- if (!hasEmitterFlag(kFlagLogComments)) {
- if (!hasEmitterFlag(kFlagAttached))
+ if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
+ if (!hasEmitterFlag(EmitterFlags::kAttached))
return reportError(DebugUtils::errored(kErrorNotInitialized));
return kErrorOk;
}
#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);
_logger->log(data, size);
@@ -407,9 +383,8 @@ Error BaseAssembler::comment(const char* data, size_t size) {
#endif
}
-// ============================================================================
-// [asmjit::BaseAssembler - Events]
-// ============================================================================
+// BaseAssembler - Events
+// ======================
Error BaseAssembler::onAttach(CodeHolder* code) noexcept {
ASMJIT_PROPAGATE(Base::onAttach(code));
diff --git a/src/asmjit/core/assembler.h b/src/asmjit/core/assembler.h
index c0da819..7ea2505 100644
--- a/src/asmjit/core/assembler.h
+++ b/src/asmjit/core/assembler.h
@@ -1,31 +1,12 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_ASSEMBLER_H_INCLUDED
#define ASMJIT_CORE_ASSEMBLER_H_INCLUDED
#include "../core/codeholder.h"
-#include "../core/datatypes.h"
#include "../core/emitter.h"
#include "../core/operand.h"
@@ -34,10 +15,6 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_assembler
//! \{
-// ============================================================================
-// [asmjit::BaseAssembler]
-// ============================================================================
-
//! Base assembler.
//!
//! 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 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;
//! \}
@@ -121,7 +98,7 @@ public:
//! \{
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 embedLabel(const Label& label, size_t dataSize = 0) override;
diff --git a/src/asmjit/core/builder.cpp b/src/asmjit/core/builder.cpp
index ad89f1d..108a8b0 100644
--- a/src/asmjit/core/builder.cpp
+++ b/src/asmjit/core/builder.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#ifndef ASMJIT_NO_BUILDER
@@ -33,9 +15,8 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::PostponedErrorHandler (Internal)]
-// ============================================================================
+// PostponedErrorHandler (Internal)
+// ================================
//! 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
@@ -50,9 +31,8 @@ public:
StringTmp<128> _message;
};
-// ============================================================================
-// [asmjit::BaseBuilder - Utilities]
-// ============================================================================
+// BaseBuilder - Utilities
+// =======================
static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
for (Pass* pass : self->_passes)
@@ -60,12 +40,11 @@ static void BaseBuilder_deletePasses(BaseBuilder* self) noexcept {
self->_passes.reset();
}
-// ============================================================================
-// [asmjit::BaseBuilder - Construction / Destruction]
-// ============================================================================
+// BaseBuilder - Construction & Destruction
+// ========================================
BaseBuilder::BaseBuilder() noexcept
- : BaseEmitter(kTypeBuilder),
+ : BaseEmitter(EmitterType::kBuilder),
_codeZone(32768 - Zone::kBlockOverhead),
_dataZone(16384 - Zone::kBlockOverhead),
_passZone(65536 - Zone::kBlockOverhead),
@@ -75,11 +54,10 @@ BaseBuilder::~BaseBuilder() noexcept {
BaseBuilder_deletePasses(this);
}
-// ============================================================================
-// [asmjit::BaseBuilder - Node Management]
-// ============================================================================
+// 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);
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;
ASMJIT_PROPAGATE(_newNodeT(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;
return _newNodeT(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;
- uint32_t deabstractDelta = Type::deabstractDeltaOfSize(registerSize());
- uint32_t finalTypeId = Type::deabstract(typeId, deabstractDelta);
+ uint32_t deabstractDelta = TypeUtils::deabstractDeltaOfSize(registerSize());
+ TypeId finalTypeId = TypeUtils::deabstract(typeId, deabstractDelta);
- if (ASMJIT_UNLIKELY(!Type::isValid(finalTypeId)))
+ if (ASMJIT_UNLIKELY(!TypeUtils::isValid(finalTypeId)))
return reportError(DebugUtils::errored(kErrorInvalidArgument));
- uint32_t typeSize = Type::sizeOf(finalTypeId);
+ uint32_t typeSize = TypeUtils::sizeOf(finalTypeId);
Support::FastUInt8 of = 0;
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;
ASMJIT_PROPAGATE(_newNodeT(&node));
- node->_embed._typeId = uint8_t(typeId);
+ node->_embed._typeId = typeId;
node->_embed._typeSize = uint8_t(typeSize);
node->_itemCount = itemCount;
node->_repeatCount = repeatCount;
@@ -143,14 +121,14 @@ Error BaseBuilder::_newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const
return kErrorOk;
}
-Error BaseBuilder::_newConstPoolNode(ConstPoolNode** out) {
+Error BaseBuilder::newConstPoolNode(ConstPoolNode** out) {
*out = nullptr;
ASMJIT_PROPAGATE(_newNodeT(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;
if (data) {
@@ -198,7 +176,7 @@ BaseNode* BaseBuilder::addNode(BaseNode* node) noexcept {
_lastNode = node;
}
- node->addFlags(BaseNode::kFlagIsActive);
+ node->addFlags(NodeFlags::kIsActive);
if (node->isSection())
_dirtySectionLinks = true;
@@ -219,7 +197,7 @@ BaseNode* BaseBuilder::addAfter(BaseNode* node, BaseNode* ref) noexcept {
node->_prev = prev;
node->_next = next;
- node->addFlags(BaseNode::kFlagIsActive);
+ node->addFlags(NodeFlags::kIsActive);
if (node->isSection())
_dirtySectionLinks = true;
@@ -246,7 +224,7 @@ BaseNode* BaseBuilder::addBefore(BaseNode* node, BaseNode* ref) noexcept {
node->_prev = prev;
node->_next = next;
- node->addFlags(BaseNode::kFlagIsActive);
+ node->addFlags(NodeFlags::kIsActive);
if (node->isSection())
_dirtySectionLinks = true;
@@ -278,7 +256,7 @@ BaseNode* BaseBuilder::removeNode(BaseNode* node) noexcept {
node->_prev = nullptr;
node->_next = nullptr;
- node->clearFlags(BaseNode::kFlagIsActive);
+ node->clearFlags(NodeFlags::kIsActive);
if (node->isSection())
_dirtySectionLinks = true;
@@ -319,7 +297,7 @@ void BaseBuilder::removeNodes(BaseNode* first, BaseNode* last) noexcept {
node->_prev = nullptr;
node->_next = nullptr;
- node->clearFlags(BaseNode::kFlagIsActive);
+ node->clearFlags(NodeFlags::kIsActive);
didRemoveSection |= uint32_t(node->isSection());
if (_cursor == node)
@@ -340,9 +318,8 @@ BaseNode* BaseBuilder::setCursor(BaseNode* node) noexcept {
return old;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Section]
-// ============================================================================
+// BaseBuilder - Sections
+// ======================
Error BaseBuilder::sectionNodeOf(SectionNode** out, uint32_t sectionId) {
*out = nullptr;
@@ -424,9 +401,8 @@ void BaseBuilder::updateSectionLinks() noexcept {
_dirtySectionLinks = false;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Labels]
-// ============================================================================
+// BaseBuilder - Labels
+// ====================
Error BaseBuilder::labelNodeOf(LabelNode** out, uint32_t labelId) {
*out = nullptr;
@@ -500,7 +476,7 @@ Label BaseBuilder::newLabel() {
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;
LabelEntry* le;
@@ -521,9 +497,8 @@ Error BaseBuilder::bind(const Label& label) {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Passes]
-// ============================================================================
+// BaseBuilder - Passes
+// ====================
ASMJIT_FAVOR_SIZE Pass* BaseBuilder::passByName(const char* name) const noexcept {
for (Pass* pass : _passes)
@@ -603,21 +578,20 @@ Error BaseBuilder::runPasses() {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Emit]
-// ============================================================================
+// 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 options = instOptions() | forcedInstOptions();
+ InstOptions options = instOptions() | forcedInstOptions();
- if (options & BaseInst::kOptionReserved) {
+ if (Support::test(options, InstOptions::kReserved)) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
#ifndef ASMJIT_NO_VALIDATION
// Strict validation.
- if (hasValidationOption(kValidationOptionIntermediate)) {
+ if (hasDiagnosticOption(DiagnosticOptions::kValidateIntermediate)) {
Operand_ opArray[Globals::kMaxOpCount];
EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
@@ -631,8 +605,8 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
}
#endif
- // Clear options that should never be part of `InstNode`.
- options &= ~BaseInst::kOptionReserved;
+ // Clear instruction options that should never be part of a regular instruction.
+ options &= ~InstOptions::kReserved;
}
uint32_t opCapacity = InstNode::capacityOfOpCount(opCount);
@@ -666,42 +640,40 @@ Error BaseBuilder::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Align]
-// ============================================================================
+// BaseBuilder - Align
+// ===================
-Error BaseBuilder::align(uint32_t alignMode, uint32_t alignment) {
+Error BaseBuilder::align(AlignMode alignMode, uint32_t alignment) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
AlignNode* node;
- ASMJIT_PROPAGATE(_newAlignNode(&node, alignMode, alignment));
+ ASMJIT_PROPAGATE(newAlignNode(&node, alignMode, alignment));
addNode(node);
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Embed]
-// ============================================================================
+// BaseBuilder - Embed
+// ===================
Error BaseBuilder::embed(const void* data, size_t dataSize) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
EmbedDataNode* node;
- ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, data, dataSize));
+ ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, data, dataSize));
addNode(node);
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))
return DebugUtils::errored(kErrorNotInitialized);
EmbedDataNode* node;
- ASMJIT_PROPAGATE(_newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat));
+ ASMJIT_PROPAGATE(newEmbedDataNode(&node, typeId, data, itemCount, itemRepeat));
addNode(node);
return kErrorOk;
@@ -714,23 +686,22 @@ Error BaseBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
if (!isLabelValid(label))
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));
EmbedDataNode* node;
- ASMJIT_PROPAGATE(_newEmbedDataNode(&node, Type::kIdU8, nullptr, pool.size()));
+ ASMJIT_PROPAGATE(newEmbedDataNode(&node, TypeId::kUInt8, nullptr, pool.size()));
pool.fill(node->data());
addNode(node);
return kErrorOk;
}
-// EmbedLabel / EmbedLabelDelta
-// ----------------------------
+// BaseBuilder - EmbedLabel & EmbedLabelDelta
+// ==========================================
//
-// If dataSize is zero it means that the size is the same as target register
-// width, however, if it's provided we really want to validate whether it's
-// within the possible range.
+// If dataSize is zero it means that the size is the same as target register width, however,
+// if it's provided we really want to validate whether it's within the possible range.
static inline bool BaseBuilder_checkDataSize(size_t dataSize) noexcept {
return !dataSize || (Support::isPowerOf2(dataSize) && dataSize <= 8);
@@ -764,24 +735,22 @@ Error BaseBuilder::embedLabelDelta(const Label& label, const Label& base, size_t
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Comment]
-// ============================================================================
+// BaseBuilder - Comment
+// =====================
Error BaseBuilder::comment(const char* data, size_t size) {
if (ASMJIT_UNLIKELY(!_code))
return DebugUtils::errored(kErrorNotInitialized);
CommentNode* node;
- ASMJIT_PROPAGATE(_newCommentNode(&node, data, size));
+ ASMJIT_PROPAGATE(newCommentNode(&node, data, size));
addNode(node);
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Serialize]
-// ============================================================================
+// BaseBuilder - SerializeTo
+// =========================
Error BaseBuilder::serializeTo(BaseEmitter* dst) {
Error err = kErrorOk;
@@ -796,7 +765,7 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
InstNode* node = node_->as();
// NOTE: Inlined to remove one additional call per instruction.
- dst->setInstOptions(node->instOptions());
+ dst->setInstOptions(node->options());
dst->setExtraReg(node->extraReg());
const Operand_* op = node->operands();
@@ -862,9 +831,8 @@ Error BaseBuilder::serializeTo(BaseEmitter* dst) {
return err;
}
-// ============================================================================
-// [asmjit::BaseBuilder - Events]
-// ============================================================================
+// BaseBuilder - Events
+// ====================
Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
ASMJIT_PROPAGATE(Base::onAttach(code));
@@ -883,7 +851,7 @@ Error BaseBuilder::onAttach(CodeHolder* code) noexcept {
_cursor = initialSection;
_firstNode = initialSection;
_lastNode = initialSection;
- initialSection->setFlags(BaseNode::kFlagIsActive);
+ initialSection->setFlags(NodeFlags::kIsActive);
return kErrorOk;
}
@@ -898,8 +866,7 @@ Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
_dataZone.reset();
_passZone.reset();
- _nodeFlags = 0;
-
+ _nodeFlags = NodeFlags::kNone;
_cursor = nullptr;
_firstNode = nullptr;
_lastNode = nullptr;
@@ -907,9 +874,8 @@ Error BaseBuilder::onDetach(CodeHolder* code) noexcept {
return Base::onDetach(code);
}
-// ============================================================================
-// [asmjit::Pass - Construction / Destruction]
-// ============================================================================
+// Pass - Construction & Destruction
+// =================================
Pass::Pass(const char* name) noexcept
: _name(name) {}
diff --git a/src/asmjit/core/builder.h b/src/asmjit/core/builder.h
index 317bda1..545471d 100644
--- a/src/asmjit/core/builder.h
+++ b/src/asmjit/core/builder.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_BUILDER_H_INCLUDED
#define ASMJIT_CORE_BUILDER_H_INCLUDED
@@ -44,10 +26,6 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_builder
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class BaseBuilder;
class Pass;
@@ -63,21 +41,88 @@ class CommentNode;
class SentinelNode;
class LabelDeltaNode;
-// Only used by Compiler infrastructure.
-class JumpAnnotation;
+//! Type of node used by \ref BaseBuilder and \ref BaseCompiler.
+enum class NodeType : uint8_t {
+ //! Invalid node (internal, don't use).
+ kNone = 0,
-// ============================================================================
-// [asmjit::BaseBuilder]
-// ============================================================================
+ // [BaseBuilder]
+
+ //! Node is \ref InstNode or \ref InstExNode.
+ kInst = 1,
+ //! Node is \ref SectionNode.
+ kSection = 2,
+ //! Node is \ref LabelNode.
+ kLabel = 3,
+ //! Node is \ref AlignNode.
+ kAlign = 4,
+ //! Node is \ref EmbedDataNode.
+ kEmbedData = 5,
+ //! Node is \ref EmbedLabelNode.
+ kEmbedLabel = 6,
+ //! Node is \ref EmbedLabelDeltaNode.
+ kEmbedLabelDelta = 7,
+ //! Node is \ref ConstPoolNode.
+ kConstPool = 8,
+ //! Node is \ref CommentNode.
+ kComment = 9,
+ //! Node is \ref SentinelNode.
+ kSentinel = 10,
+
+ // [BaseCompiler]
+
+ //! Node is \ref JumpNode (acts as InstNode).
+ kJump = 15,
+ //! Node is \ref FuncNode (acts as LabelNode).
+ kFunc = 16,
+ //! Node is \ref FuncRetNode (acts as InstNode).
+ kFuncRet = 17,
+ //! Node is \ref InvokeNode (acts as InstNode).
+ kInvoke = 18,
+
+ // [UserDefined]
+
+ //! First id of a user-defined node.
+ kUser = 32
+};
+
+//! Node flags, specify what the node is and/or does.
+enum class NodeFlags : uint8_t {
+ //! No flags.
+ kNone = 0,
+ //! Node is code that can be executed (instruction, label, align, etc...).
+ kIsCode = 0x01u,
+ //! Node is data that cannot be executed (data, const-pool, etc...).
+ kIsData = 0x02u,
+ //! Node is informative, can be removed and ignored.
+ kIsInformative = 0x04u,
+ //! Node can be safely removed if unreachable.
+ kIsRemovable = 0x08u,
+ //! Node does nothing when executed (label, align, explicit nop).
+ kHasNoEffect = 0x10u,
+ //! Node is an instruction or acts as it.
+ kActsAsInst = 0x20u,
+ //! Node is a label or acts as it.
+ kActsAsLabel = 0x40u,
+ //! Node is active (part of the code).
+ kIsActive = 0x80u
+};
+ASMJIT_DEFINE_ENUM_FLAGS(NodeFlags)
+
+//! Type of the sentinel (purery informative purpose).
+enum class SentinelType : uint8_t {
+ //! Type of the sentinel is not known.
+ kUnknown = 0u,
+ //! This is a sentinel used at the end of \ref FuncNode.
+ kFuncEnd = 1u
+};
//! Builder interface.
//!
-//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler
-//! replacement in case pre-processing or post-processing of the generated code
-//! is required. The code can be modified during or after code generation. Pre
-//! or post processing can be done manually or through a \ref Pass object. \ref
-//! BaseBuilder stores the emitted code as a double-linked list of nodes, which
-//! allows O(1) insertion and removal during processing.
+//! `BaseBuilder` interface was designed to be used as a \ref BaseAssembler replacement in case pre-processing or
+//! post-processing of the generated code is required. The code can be modified during or after code generation.
+//! Pre processing or post processing can be done manually or through a \ref Pass object. \ref BaseBuilder stores
+//! the emitted code as a double-linked list of nodes, which allows O(1) insertion and removal during processing.
//!
//! Check out architecture specific builders for more details and examples:
//!
@@ -87,6 +132,9 @@ public:
ASMJIT_NONCOPYABLE(BaseBuilder)
typedef BaseEmitter Base;
+ //! \name Members
+ //! \{
+
//! Base zone used to allocate nodes and passes.
Zone _codeZone;
//! Data zone used to allocate data and names.
@@ -111,10 +159,12 @@ public:
BaseNode* _lastNode = nullptr;
//! Flags assigned to each new node.
- uint32_t _nodeFlags = 0;
+ NodeFlags _nodeFlags = NodeFlags::kNone;
//! The sections links are dirty (used internally).
bool _dirtySectionLinks = false;
+ //! \}
+
//! \name Construction & Destruction
//! \{
@@ -133,14 +183,13 @@ public:
//! Returns the last node.
inline BaseNode* lastNode() const noexcept { return _lastNode; }
- //! Allocates and instantiates a new node of type `T` and returns its instance.
- //! If the allocation fails `nullptr` is returned.
+ //! Allocates and instantiates a new node of type `T` and returns its instance. If the allocation fails `nullptr`
+ //! is returned.
//!
//! The template argument `T` must be a type that is extends \ref BaseNode.
//!
- //! \remarks The pointer returned (if non-null) is owned by the Builder or
- //! Compiler. When the Builder/Compiler is destroyed it destroys all nodes
- //! it created so no manual memory management is required.
+ //! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler
+ //! is destroyed it destroys all nodes it created so no manual memory management is required.
template
inline Error _newNodeT(T** out, Args&&... args) {
*out = _allocator.newT(this, std::forward(args)...);
@@ -150,17 +199,17 @@ public:
}
//! Creates a new \ref InstNode.
- ASMJIT_API Error _newInstNode(InstNode** out, uint32_t instId, uint32_t instOptions, uint32_t opCount);
+ ASMJIT_API Error newInstNode(InstNode** out, InstId instId, InstOptions instOptions, uint32_t opCount);
//! Creates a new \ref LabelNode.
- ASMJIT_API Error _newLabelNode(LabelNode** out);
+ ASMJIT_API Error newLabelNode(LabelNode** out);
//! Creates a new \ref AlignNode.
- ASMJIT_API Error _newAlignNode(AlignNode** out, uint32_t alignMode, uint32_t alignment);
+ ASMJIT_API Error newAlignNode(AlignNode** out, AlignMode alignMode, uint32_t alignment);
//! Creates a new \ref EmbedDataNode.
- ASMJIT_API Error _newEmbedDataNode(EmbedDataNode** out, uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1);
+ ASMJIT_API Error newEmbedDataNode(EmbedDataNode** out, TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1);
//! Creates a new \ref ConstPoolNode.
- ASMJIT_API Error _newConstPoolNode(ConstPoolNode** out);
+ ASMJIT_API Error newConstPoolNode(ConstPoolNode** out);
//! Creates a new \ref CommentNode.
- ASMJIT_API Error _newCommentNode(CommentNode** out, const char* data, size_t size);
+ ASMJIT_API Error newCommentNode(CommentNode** out, const char* data, size_t size);
//! Adds `node` after the current and sets the current node to the given `node`.
ASMJIT_API BaseNode* addNode(BaseNode* node) noexcept;
@@ -175,11 +224,9 @@ public:
//! Returns the cursor.
//!
- //! When the Builder/Compiler is created it automatically creates a '.text'
- //! \ref SectionNode, which will be the initial one. When instructions are
- //! added they are always added after the cursor and the cursor is changed
- //! to be that newly added node. Use `setCursor()` to change where new nodes
- //! are inserted.
+ //! When the Builder/Compiler is created it automatically creates a '.text' \ref SectionNode, which will be the
+ //! initial one. When instructions are added they are always added after the cursor and the cursor is changed
+ //! to be that newly added node. Use `setCursor()` to change where new nodes are inserted.
inline BaseNode* cursor() const noexcept {
return _cursor;
}
@@ -189,8 +236,8 @@ public:
//! Sets the current node without returning the previous node.
//!
- //! Only use this function if you are concerned about performance and want
- //! this inlined (for example if you set the cursor in a loop, etc...).
+ //! Only use this function if you are concerned about performance and want this inlined (for example if you set
+ //! the cursor in a loop, etc...).
inline void _setCursor(BaseNode* node) noexcept {
_cursor = node;
}
@@ -202,8 +249,8 @@ public:
//! Returns a vector of SectionNode objects.
//!
- //! \note If a section of some id is not associated with the Builder/Compiler
- //! it would be null, so always check for nulls if you iterate over the vector.
+ //! \note If a section of some id is not associated with the Builder/Compiler it would be null, so always check
+ //! for nulls if you iterate over the vector.
inline const ZoneVector& sectionNodes() const noexcept {
return _sectionNodes;
}
@@ -215,15 +262,14 @@ public:
//! Returns or creates a `SectionNode` that matches the given `sectionId`.
//!
- //! \remarks This function will either get the existing `SectionNode` or create
- //! it in case it wasn't created before. You can check whether a section has a
- //! registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`.
+ //! \remarks This function will either get the existing `SectionNode` or create it in case it wasn't created before.
+ //! You can check whether a section has a registered `SectionNode` by using `BaseBuilder::hasRegisteredSectionNode()`.
ASMJIT_API Error sectionNodeOf(SectionNode** out, uint32_t sectionId);
ASMJIT_API Error section(Section* section) override;
- //! Returns whether the section links of active section nodes are dirty. You can
- //! update these links by calling `updateSectionLinks()` in such case.
+ //! Returns whether the section links of active section nodes are dirty. You can update these links by calling
+ //! `updateSectionLinks()` in such case.
inline bool hasDirtySectionLinks() const noexcept { return _dirtySectionLinks; }
//! Updates links of all active section nodes.
@@ -236,8 +282,8 @@ public:
//! Returns a vector of \ref LabelNode nodes.
//!
- //! \note If a label of some id is not associated with the Builder/Compiler
- //! it would be null, so always check for nulls if you iterate over the vector.
+ //! \note If a label of some id is not associated with the Builder/Compiler it would be null, so always check for
+ //! nulls if you iterate over the vector.
inline const ZoneVector& labelNodes() const noexcept { return _labelNodes; }
//! Tests whether the `LabelNode` of the given `labelId` was registered.
@@ -252,9 +298,8 @@ public:
//! Gets or creates a \ref LabelNode that matches the given `labelId`.
//!
- //! \remarks This function will either get the existing `LabelNode` or create
- //! it in case it wasn't created before. You can check whether a label has a
- //! registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode().
+ //! \remarks This function will either get the existing `LabelNode` or create it in case it wasn't created before.
+ //! You can check whether a label has a registered `LabelNode` by calling \ref BaseBuilder::hasRegisteredLabelNode().
ASMJIT_API Error labelNodeOf(LabelNode** out, uint32_t labelId);
//! \overload
@@ -264,13 +309,12 @@ public:
//! Registers this \ref LabelNode (internal).
//!
- //! This function is used internally to register a newly created `LabelNode`
- //! with this instance of Builder/Compiler. Use \ref labelNodeOf() functions
- //! to get back \ref LabelNode from a label or its identifier.
+ //! This function is used internally to register a newly created `LabelNode` with this instance of Builder/Compiler.
+ //! Use \ref labelNodeOf() functions to get back \ref LabelNode from a label or its identifier.
ASMJIT_API Error registerLabelNode(LabelNode* node);
ASMJIT_API Label newLabel() override;
- ASMJIT_API Label newNamedLabel(const char* name, size_t nameSize = SIZE_MAX, uint32_t type = Label::kTypeGlobal, uint32_t parentId = Globals::kInvalidId) override;
+ 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;
//! \}
@@ -281,14 +325,13 @@ public:
//! Returns a vector of `Pass` instances that will be executed by `runPasses()`.
inline const ZoneVector& passes() const noexcept { return _passes; }
- //! Allocates and instantiates a new pass of type `T` and returns its instance.
- //! If the allocation fails `nullptr` is returned.
+ //! Allocates and instantiates a new pass of type `T` and returns its instance. If the allocation fails `nullptr` is
+ //! returned.
//!
//! The template argument `T` must be a type that is extends \ref Pass.
//!
- //! \remarks The pointer returned (if non-null) is owned by the Builder or
- //! Compiler. When the Builder/Compiler is destroyed it destroys all passes
- //! it created so no manual memory management is required.
+ //! \remarks The pointer returned (if non-null) is owned by the Builder or Compiler. When the Builder/Compiler is
+ //! destroyed it destroys all passes it created so no manual memory management is required.
template
inline T* newPassT() noexcept { return _codeZone.newT(); }
@@ -319,14 +362,14 @@ public:
//! \name Emit
//! \{
- ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override;
+ ASMJIT_API Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) override;
//! \}
//! \name Align
//! \{
- ASMJIT_API Error align(uint32_t alignMode, uint32_t alignment) override;
+ ASMJIT_API Error align(AlignMode alignMode, uint32_t alignment) override;
//! \}
@@ -334,7 +377,7 @@ public:
//! \{
ASMJIT_API Error embed(const void* data, size_t dataSize) override;
- ASMJIT_API Error embedDataArray(uint32_t typeId, const void* data, size_t count, size_t repeat = 1) override;
+ ASMJIT_API Error embedDataArray(TypeId typeId, const void* data, size_t count, size_t repeat = 1) override;
ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
ASMJIT_API Error embedLabel(const Label& label, size_t dataSize = 0) override;
@@ -354,9 +397,8 @@ public:
//! Serializes everything the given emitter `dst`.
//!
- //! Although not explicitly required the emitter will most probably be of
- //! Assembler type. The reason is that there is no known use of serializing
- //! nodes held by Builder/Compiler into another Builder-like emitter.
+ //! Although not explicitly required the emitter will most probably be of Assembler type. The reason is that
+ //! there is no known use of serializing nodes held by Builder/Compiler into another Builder-like emitter.
ASMJIT_API Error serializeTo(BaseEmitter* dst);
//! \}
@@ -368,37 +410,21 @@ public:
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use serializeTo() instead, serialize() is now also an instruction.")
- inline Error serialize(BaseEmitter* dst) {
- return serializeTo(dst);
- }
-
-#ifndef ASMJIT_NO_LOGGING
- ASMJIT_DEPRECATED("Use Formatter::formatNodeList(sb, formatFlags, builder)")
- inline Error dump(String& sb, uint32_t formatFlags = 0) const noexcept {
- return Formatter::formatNodeList(sb, formatFlags, this);
- }
-#endif // !ASMJIT_NO_LOGGING
-#endif // !ASMJIT_NO_DEPRECATED
};
-// ============================================================================
-// [asmjit::BaseNode]
-// ============================================================================
-
//! Base node.
//!
-//! Every node represents a building-block used by \ref BaseBuilder. It can
-//! be instruction, data, label, comment, directive, or any other high-level
-//! representation that can be transformed to the building blocks mentioned.
-//! Every class that inherits \ref BaseBuilder can define its own high-level
-//! nodes that can be later lowered to basic nodes like instructions.
+//! Every node represents a building-block used by \ref BaseBuilder. It can be instruction, data, label, comment,
+//! directive, or any other high-level representation that can be transformed to the building blocks mentioned.
+//! Every class that inherits \ref BaseBuilder can define its own high-level nodes that can be later lowered to
+//! basic nodes like instructions.
class BaseNode {
public:
ASMJIT_NONCOPYABLE(BaseNode)
+ //! \name Members
+ //! \{
+
union {
struct {
//! Previous node.
@@ -412,22 +438,34 @@ public:
//! Data shared between all types of nodes.
struct AnyData {
- //! Node type, see \ref NodeType.
- uint8_t _nodeType;
- //! Node flags, see \ref Flags.
- uint8_t _nodeFlags;
+ //! Node type.
+ NodeType _nodeType;
+ //! Node flags.
+ NodeFlags _nodeFlags;
//! Not used by BaseNode.
uint8_t _reserved0;
//! Not used by BaseNode.
uint8_t _reserved1;
};
+ //! Data used by \ref AlignNode.
+ struct AlignData {
+ //! Node type.
+ NodeType _nodeType;
+ //! Node flags.
+ NodeFlags _nodeFlags;
+ //! Align mode.
+ AlignMode _alignMode;
+ //! Not used by AlignNode.
+ uint8_t _reserved;
+ };
+
//! Data used by \ref InstNode.
struct InstData {
- //! Node type, see \ref NodeType.
- uint8_t _nodeType;
- //! Node flags, see \ref Flags.
- uint8_t _nodeFlags;
+ //! Node type.
+ NodeType _nodeType;
+ //! Node flags.
+ NodeFlags _nodeFlags;
//! Instruction operands count (used).
uint8_t _opCount;
//! Instruction operands capacity (allocated).
@@ -436,24 +474,24 @@ public:
//! Data used by \ref EmbedDataNode.
struct EmbedData {
- //! Node type, see \ref NodeType.
- uint8_t _nodeType;
- //! Node flags, see \ref Flags.
- uint8_t _nodeFlags;
- //! Type id, see \ref Type::Id.
- uint8_t _typeId;
+ //! Node type.
+ NodeType _nodeType;
+ //! Node flags.
+ NodeFlags _nodeFlags;
+ //! Type id.
+ TypeId _typeId;
//! Size of `_typeId`.
uint8_t _typeSize;
};
//! Data used by \ref SentinelNode.
struct SentinelData {
- //! Node type, see \ref NodeType.
- uint8_t _nodeType;
- //! Node flags, see \ref Flags.
- uint8_t _nodeFlags;
+ //! Node type.
+ NodeType _nodeType;
+ //! Node flags.
+ NodeFlags _nodeFlags;
//! Sentinel type.
- uint8_t _sentinelType;
+ SentinelType _sentinelType;
//! Not used by BaseNode.
uint8_t _reserved1;
};
@@ -462,6 +500,8 @@ public:
union {
//! Data useful by any node type.
AnyData _any;
+ //! Data specific to \ref AlignNode.
+ AlignData _alignData;
//! Data specific to \ref InstNode.
InstData _inst;
//! Data specific to \ref EmbedDataNode.
@@ -487,84 +527,17 @@ public:
//! Inline comment/annotation or nullptr if not used.
const char* _inlineComment;
- //! Type of `BaseNode`.
- enum NodeType : uint32_t {
- //! Invalid node (internal, don't use).
- kNodeNone = 0,
-
- // [BaseBuilder]
-
- //! Node is \ref InstNode or \ref InstExNode.
- kNodeInst = 1,
- //! Node is \ref SectionNode.
- kNodeSection = 2,
- //! Node is \ref LabelNode.
- kNodeLabel = 3,
- //! Node is \ref AlignNode.
- kNodeAlign = 4,
- //! Node is \ref EmbedDataNode.
- kNodeEmbedData = 5,
- //! Node is \ref EmbedLabelNode.
- kNodeEmbedLabel = 6,
- //! Node is \ref EmbedLabelDeltaNode.
- kNodeEmbedLabelDelta = 7,
- //! Node is \ref ConstPoolNode.
- kNodeConstPool = 8,
- //! Node is \ref CommentNode.
- kNodeComment = 9,
- //! Node is \ref SentinelNode.
- kNodeSentinel = 10,
-
- // [BaseCompiler]
-
- //! Node is \ref JumpNode (acts as InstNode).
- kNodeJump = 15,
- //! Node is \ref FuncNode (acts as LabelNode).
- kNodeFunc = 16,
- //! Node is \ref FuncRetNode (acts as InstNode).
- kNodeFuncRet = 17,
- //! Node is \ref InvokeNode (acts as InstNode).
- kNodeInvoke = 18,
-
- // [UserDefined]
-
- //! First id of a user-defined node.
- kNodeUser = 32,
-
-#ifndef ASMJIT_NO_DEPRECATED
- kNodeFuncCall = kNodeInvoke
-#endif // !ASMJIT_NO_DEPRECATED
- };
-
- //! Node flags, specify what the node is and/or does.
- enum Flags : uint32_t {
- //! Node is code that can be executed (instruction, label, align, etc...).
- kFlagIsCode = 0x01u,
- //! Node is data that cannot be executed (data, const-pool, etc...).
- kFlagIsData = 0x02u,
- //! Node is informative, can be removed and ignored.
- kFlagIsInformative = 0x04u,
- //! Node can be safely removed if unreachable.
- kFlagIsRemovable = 0x08u,
- //! Node does nothing when executed (label, align, explicit nop).
- kFlagHasNoEffect = 0x10u,
- //! Node is an instruction or acts as it.
- kFlagActsAsInst = 0x20u,
- //! Node is a label or acts as it.
- kFlagActsAsLabel = 0x40u,
- //! Node is active (part of the code).
- kFlagIsActive = 0x80u
- };
+ //! \}
//! \name Construction & Destruction
//! \{
//! Creates a new `BaseNode` - always use `BaseBuilder` to allocate nodes.
- ASMJIT_INLINE BaseNode(BaseBuilder* cb, uint32_t type, uint32_t flags = 0) noexcept {
+ inline BaseNode(BaseBuilder* cb, NodeType nodeType, NodeFlags nodeFlags = NodeFlags::kNone) noexcept {
_prev = nullptr;
_next = nullptr;
- _any._nodeType = uint8_t(type);
- _any._nodeFlags = uint8_t(flags | cb->_nodeFlags);
+ _any._nodeType = nodeType;
+ _any._nodeFlags = nodeFlags | cb->_nodeFlags;
_any._reserved0 = 0;
_any._reserved1 = 0;
_position = 0;
@@ -593,71 +566,65 @@ public:
inline BaseNode* next() const noexcept { return _next; }
//! Returns the type of the node, see `NodeType`.
- inline uint32_t type() const noexcept { return _any._nodeType; }
+ inline NodeType type() const noexcept { return _any._nodeType; }
//! Sets the type of the node, see `NodeType` (internal).
//!
- //! \remarks You should never set a type of a node to anything else than the
- //! initial value. This function is only provided for users that use custom
- //! nodes and need to change the type either during construction or later.
- inline void setType(uint32_t type) noexcept { _any._nodeType = uint8_t(type); }
+ //! \remarks You should never set a type of a node to anything else than the initial value. This function is only
+ //! provided for users that use custom nodes and need to change the type either during construction or later.
+ inline void setType(NodeType type) noexcept { _any._nodeType = type; }
//! Tests whether this node is either `InstNode` or extends it.
- inline bool isInst() const noexcept { return hasFlag(kFlagActsAsInst); }
+ inline bool isInst() const noexcept { return hasFlag(NodeFlags::kActsAsInst); }
//! Tests whether this node is `SectionNode`.
- inline bool isSection() const noexcept { return type() == kNodeSection; }
+ inline bool isSection() const noexcept { return type() == NodeType::kSection; }
//! Tests whether this node is either `LabelNode` or extends it.
- inline bool isLabel() const noexcept { return hasFlag(kFlagActsAsLabel); }
+ inline bool isLabel() const noexcept { return hasFlag(NodeFlags::kActsAsLabel); }
//! Tests whether this node is `AlignNode`.
- inline bool isAlign() const noexcept { return type() == kNodeAlign; }
+ inline bool isAlign() const noexcept { return type() == NodeType::kAlign; }
//! Tests whether this node is `EmbedDataNode`.
- inline bool isEmbedData() const noexcept { return type() == kNodeEmbedData; }
+ inline bool isEmbedData() const noexcept { return type() == NodeType::kEmbedData; }
//! Tests whether this node is `EmbedLabelNode`.
- inline bool isEmbedLabel() const noexcept { return type() == kNodeEmbedLabel; }
+ inline bool isEmbedLabel() const noexcept { return type() == NodeType::kEmbedLabel; }
//! Tests whether this node is `EmbedLabelDeltaNode`.
- inline bool isEmbedLabelDelta() const noexcept { return type() == kNodeEmbedLabelDelta; }
+ inline bool isEmbedLabelDelta() const noexcept { return type() == NodeType::kEmbedLabelDelta; }
//! Tests whether this node is `ConstPoolNode`.
- inline bool isConstPool() const noexcept { return type() == kNodeConstPool; }
+ inline bool isConstPool() const noexcept { return type() == NodeType::kConstPool; }
//! Tests whether this node is `CommentNode`.
- inline bool isComment() const noexcept { return type() == kNodeComment; }
+ inline bool isComment() const noexcept { return type() == NodeType::kComment; }
//! Tests whether this node is `SentinelNode`.
- inline bool isSentinel() const noexcept { return type() == kNodeSentinel; }
+ inline bool isSentinel() const noexcept { return type() == NodeType::kSentinel; }
//! Tests whether this node is `FuncNode`.
- inline bool isFunc() const noexcept { return type() == kNodeFunc; }
+ inline bool isFunc() const noexcept { return type() == NodeType::kFunc; }
//! Tests whether this node is `FuncRetNode`.
- inline bool isFuncRet() const noexcept { return type() == kNodeFuncRet; }
+ inline bool isFuncRet() const noexcept { return type() == NodeType::kFuncRet; }
//! Tests whether this node is `InvokeNode`.
- inline bool isInvoke() const noexcept { return type() == kNodeInvoke; }
+ inline bool isInvoke() const noexcept { return type() == NodeType::kInvoke; }
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use isInvoke")
- inline bool isFuncCall() const noexcept { return isInvoke(); }
-#endif // !ASMJIT_NO_DEPRECATED
-
- //! Returns the node flags, see \ref Flags.
- inline uint32_t flags() const noexcept { return _any._nodeFlags; }
+ //! Returns the node flags.
+ inline NodeFlags flags() const noexcept { return _any._nodeFlags; }
//! Tests whether the node has the given `flag` set.
- inline bool hasFlag(uint32_t flag) const noexcept { return (uint32_t(_any._nodeFlags) & flag) != 0; }
+ inline bool hasFlag(NodeFlags flag) const noexcept { return Support::test(_any._nodeFlags, flag); }
//! Replaces node flags with `flags`.
- inline void setFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(flags); }
+ inline void setFlags(NodeFlags flags) noexcept { _any._nodeFlags = flags; }
//! Adds the given `flags` to node flags.
- inline void addFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(_any._nodeFlags | flags); }
+ inline void addFlags(NodeFlags flags) noexcept { _any._nodeFlags |= flags; }
//! Clears the given `flags` from node flags.
- inline void clearFlags(uint32_t flags) noexcept { _any._nodeFlags = uint8_t(_any._nodeFlags & (flags ^ 0xFF)); }
+ inline void clearFlags(NodeFlags flags) noexcept { _any._nodeFlags &= ~flags; }
//! Tests whether the node is code that can be executed.
- inline bool isCode() const noexcept { return hasFlag(kFlagIsCode); }
+ inline bool isCode() const noexcept { return hasFlag(NodeFlags::kIsCode); }
//! Tests whether the node is data that cannot be executed.
- inline bool isData() const noexcept { return hasFlag(kFlagIsData); }
+ inline bool isData() const noexcept { return hasFlag(NodeFlags::kIsData); }
//! Tests whether the node is informative only (is never encoded like comment, etc...).
- inline bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); }
+ inline bool isInformative() const noexcept { return hasFlag(NodeFlags::kIsInformative); }
//! Tests whether the node is removable if it's in an unreachable code block.
- inline bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); }
+ inline bool isRemovable() const noexcept { return hasFlag(NodeFlags::kIsRemovable); }
//! Tests whether the node has no effect when executed (label, .align, nop, ...).
- inline bool hasNoEffect() const noexcept { return hasFlag(kFlagHasNoEffect); }
+ inline bool hasNoEffect() const noexcept { return hasFlag(NodeFlags::kHasNoEffect); }
//! Tests whether the node is part of the code.
- inline bool isActive() const noexcept { return hasFlag(kFlagIsActive); }
+ inline bool isActive() const noexcept { return hasFlag(NodeFlags::kIsActive); }
//! Tests whether the node has a position assigned.
//!
@@ -667,20 +634,18 @@ public:
inline uint32_t position() const noexcept { return _position; }
//! Sets node position.
//!
- //! Node position is a 32-bit unsigned integer that is used by Compiler to
- //! track where the node is relatively to the start of the function. It doesn't
- //! describe a byte position in a binary, instead it's just a pseudo position
+ //! Node position is a 32-bit unsigned integer that is used by Compiler to track where the node is relatively to
+ //! the start of the function. It doesn't describe a byte position in a binary, instead it's just a pseudo position
//! used by liveness analysis and other tools around Compiler.
//!
- //! If you don't use Compiler then you may use `position()` and `setPosition()`
- //! freely for your own purposes if the 32-bit value limit is okay for you.
+ //! If you don't use Compiler then you may use `position()` and `setPosition()` freely for your own purposes if
+ //! the 32-bit value limit is okay for you.
inline void setPosition(uint32_t position) noexcept { _position = position; }
//! Returns user data casted to `T*`.
//!
- //! User data is decicated to be used only by AsmJit users and not touched
- //! by the library. The data has a pointer size so you can either store a
- //! pointer or `intptr_t` value through `setUserDataAsIntPtr()`.
+ //! User data is decicated to be used only by AsmJit users and not touched by the library. The data has a pointer
+ //! size so you can either store a pointer or `intptr_t` value through `setUserDataAsIntPtr()`.
template
inline T* userDataAsPtr() const noexcept { return static_cast(_userDataPtr); }
//! Returns user data casted to `int64_t`.
@@ -722,10 +687,6 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::InstNode]
-// ============================================================================
-
//! Instruction node.
//!
//! Wraps an instruction with its options and operands.
@@ -733,25 +694,34 @@ class InstNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(InstNode)
+ //! \name Constants
+ //! \{
+
enum : uint32_t {
- //! Count of embedded operands per `InstNode` that are always allocated as
- //! a part of the instruction. Minimum embedded operands is 4, but in 32-bit
- //! more pointers are smaller and we can embed 5. The rest (up to 6 operands)
+ //! Count of embedded operands per `InstNode` that are always allocated as a part of the instruction. Minimum
+ //! embedded operands is 4, but in 32-bit more pointers are smaller and we can embed 5. The rest (up to 6 operands)
//! is always stored in `InstExNode`.
kBaseOpCapacity = uint32_t((128 - sizeof(BaseNode) - sizeof(BaseInst)) / sizeof(Operand_))
};
+ //! \}
+
+ //! \name Members
+ //! \{
+
//! Base instruction data.
BaseInst _baseInst;
//! First 4 or 5 operands (indexed from 0).
Operand_ _opArray[kBaseOpCapacity];
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `InstNode` instance.
- ASMJIT_INLINE InstNode(BaseBuilder* cb, uint32_t instId, uint32_t options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept
- : BaseNode(cb, kNodeInst, kFlagIsCode | kFlagIsRemovable | kFlagActsAsInst),
+ inline InstNode(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCount, uint32_t opCapacity = kBaseOpCapacity) noexcept
+ : BaseNode(cb, NodeType::kInst, NodeFlags::kIsCode | NodeFlags::kIsRemovable | NodeFlags::kActsAsInst),
_baseInst(instId, options) {
_inst._opCapacity = uint8_t(opCapacity);
_inst._opCount = uint8_t(opCount);
@@ -767,25 +737,38 @@ public:
//! \}
- //! \name Accessors
+ //! \name Instruction Object
//! \{
inline BaseInst& baseInst() noexcept { return _baseInst; }
inline const BaseInst& baseInst() const noexcept { return _baseInst; }
- //! Returns the instruction id, see `BaseInst::Id`.
- inline uint32_t id() const noexcept { return _baseInst.id(); }
- //! Sets the instruction id to `id`, see `BaseInst::Id`.
- inline void setId(uint32_t id) noexcept { _baseInst.setId(id); }
+ //! \}
- //! Returns instruction options.
- inline uint32_t instOptions() const noexcept { return _baseInst.options(); }
- //! Sets instruction options.
- inline void setInstOptions(uint32_t options) noexcept { _baseInst.setOptions(options); }
- //! Adds instruction options.
- inline void addInstOptions(uint32_t options) noexcept { _baseInst.addOptions(options); }
- //! Clears instruction options.
- inline void clearInstOptions(uint32_t options) noexcept { _baseInst.clearOptions(options); }
+ //! \name Instruction Id
+ //! \{
+
+ //! Returns the instruction id, see `BaseInst::Id`.
+ inline InstId id() const noexcept { return _baseInst.id(); }
+ //! Sets the instruction id to `id`, see `BaseInst::Id`.
+ inline void setId(InstId id) noexcept { _baseInst.setId(id); }
+
+ //! \}
+
+ //! \name Instruction Options
+ //! \{
+
+ inline InstOptions options() const noexcept { return _baseInst.options(); }
+ inline bool hasOption(InstOptions option) const noexcept { return _baseInst.hasOption(option); }
+ inline void setOptions(InstOptions options) noexcept { _baseInst.setOptions(options); }
+ inline void addOptions(InstOptions options) noexcept { _baseInst.addOptions(options); }
+ inline void clearOptions(InstOptions options) noexcept { _baseInst.clearOptions(options); }
+ inline void resetOptions() noexcept { _baseInst.resetOptions(); }
+
+ //! \}
+
+ //! \name Extra Register
+ //! \{
//! Tests whether the node has an extra register operand.
inline bool hasExtraReg() const noexcept { return _baseInst.hasExtraReg(); }
@@ -800,6 +783,11 @@ public:
//! Resets extra register operand.
inline void resetExtraReg() noexcept { _baseInst.resetExtraReg(); }
+ //! \}
+
+ //! \name Instruction Operands
+ //! \{
+
//! Returns operand count.
inline uint32_t opCount() const noexcept { return _inst._opCount; }
//! Returns operand capacity.
@@ -848,19 +836,19 @@ public:
//! \name Utilities
//! \{
- inline bool hasOpType(uint32_t opType) const noexcept {
+ inline bool hasOpType(OperandType opType) const noexcept {
for (uint32_t i = 0, count = opCount(); i < count; i++)
if (_opArray[i].opType() == opType)
return true;
return false;
}
- inline bool hasRegOp() const noexcept { return hasOpType(Operand::kOpReg); }
- inline bool hasMemOp() const noexcept { return hasOpType(Operand::kOpMem); }
- inline bool hasImmOp() const noexcept { return hasOpType(Operand::kOpImm); }
- inline bool hasLabelOp() const noexcept { return hasOpType(Operand::kOpLabel); }
+ inline bool hasRegOp() const noexcept { return hasOpType(OperandType::kReg); }
+ inline bool hasMemOp() const noexcept { return hasOpType(OperandType::kMem); }
+ inline bool hasImmOp() const noexcept { return hasOpType(OperandType::kImm); }
+ inline bool hasLabelOp() const noexcept { return hasOpType(OperandType::kLabel); }
- inline uint32_t indexOfOpType(uint32_t opType) const noexcept {
+ inline uint32_t indexOfOpType(OperandType opType) const noexcept {
uint32_t i = 0;
uint32_t count = opCount();
@@ -873,9 +861,9 @@ public:
return i;
}
- inline uint32_t indexOfMemOp() const noexcept { return indexOfOpType(Operand::kOpMem); }
- inline uint32_t indexOfImmOp() const noexcept { return indexOfOpType(Operand::kOpImm); }
- inline uint32_t indexOfLabelOp() const noexcept { return indexOfOpType(Operand::kOpLabel); }
+ inline uint32_t indexOfMemOp() const noexcept { return indexOfOpType(OperandType::kMem); }
+ inline uint32_t indexOfImmOp() const noexcept { return indexOfOpType(OperandType::kImm); }
+ inline uint32_t indexOfLabelOp() const noexcept { return indexOfOpType(OperandType::kLabel); }
//! \}
@@ -886,7 +874,7 @@ public:
inline uint32_t* _getRewriteArray() noexcept { return &_baseInst._extraReg._id; }
inline const uint32_t* _getRewriteArray() const noexcept { return &_baseInst._extraReg._id; }
- ASMJIT_INLINE uint32_t getRewriteIndex(const uint32_t* id) const noexcept {
+ inline uint32_t getRewriteIndex(const uint32_t* id) const noexcept {
const uint32_t* array = _getRewriteArray();
ASMJIT_ASSERT(array <= id);
@@ -896,7 +884,7 @@ public:
return uint32_t(index);
}
- ASMJIT_INLINE void rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept {
+ inline void rewriteIdAtIndex(uint32_t index, uint32_t id) noexcept {
uint32_t* array = _getRewriteArray();
array[index] = id;
}
@@ -921,58 +909,59 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::InstExNode]
-// ============================================================================
-
//! Instruction node with maximum number of operands.
//!
-//! This node is created automatically by Builder/Compiler in case that the
-//! required number of operands exceeds the default capacity of `InstNode`.
+//! This node is created automatically by Builder/Compiler in case that the required number of operands exceeds
+//! the default capacity of `InstNode`.
class InstExNode : public InstNode {
public:
ASMJIT_NONCOPYABLE(InstExNode)
+ //! \name Members
+ //! \{
+
//! Continued `_opArray[]` to hold up to `kMaxOpCount` operands.
Operand_ _opArrayEx[Globals::kMaxOpCount - kBaseOpCapacity];
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `InstExNode` instance.
- inline InstExNode(BaseBuilder* cb, uint32_t instId, uint32_t options, uint32_t opCapacity = Globals::kMaxOpCount) noexcept
+ inline InstExNode(BaseBuilder* cb, InstId instId, InstOptions options, uint32_t opCapacity = Globals::kMaxOpCount) noexcept
: InstNode(cb, instId, options, opCapacity) {}
//! \}
};
-// ============================================================================
-// [asmjit::SectionNode]
-// ============================================================================
-
//! Section node.
class SectionNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(SectionNode)
+ //! \name Members
+ //! \{
+
//! Section id.
uint32_t _id;
//! Next section node that follows this section.
//!
- //! This link is only valid when the section is active (is part of the code)
- //! and when `Builder::hasDirtySectionLinks()` returns `false`. If you intend
- //! to use this field you should always call `Builder::updateSectionLinks()`
- //! before you do so.
+ //! This link is only valid when the section is active (is part of the code) and when `Builder::hasDirtySectionLinks()`
+ //! returns `false`. If you intend to use this field you should always call `Builder::updateSectionLinks()` before you
+ //! do so.
SectionNode* _nextSection;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `SectionNode` instance.
- inline SectionNode(BaseBuilder* cb, uint32_t id = 0) noexcept
- : BaseNode(cb, kNodeSection, kFlagHasNoEffect),
- _id(id),
+ inline SectionNode(BaseBuilder* cb, uint32_t secionId = 0) noexcept
+ : BaseNode(cb, NodeType::kSection, NodeFlags::kHasNoEffect),
+ _id(secionId),
_nextSection(nullptr) {}
//! \}
@@ -986,24 +975,25 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::LabelNode]
-// ============================================================================
-
//! Label node.
class LabelNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(LabelNode)
+ //! \name Members
+ //! \{
+
//! Label identifier.
uint32_t _labelId;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `LabelNode` instance.
inline LabelNode(BaseBuilder* cb, uint32_t labelId = 0) noexcept
- : BaseNode(cb, kNodeLabel, kFlagHasNoEffect | kFlagActsAsLabel),
+ : BaseNode(cb, NodeType::kLabel, NodeFlags::kHasNoEffect | NodeFlags::kActsAsLabel),
_labelId(labelId) {}
//! \}
@@ -1017,17 +1007,8 @@ public:
inline uint32_t labelId() const noexcept { return _labelId; }
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use labelId() instead")
- inline uint32_t id() const noexcept { return labelId(); }
-#endif // !ASMJIT_NO_DEPRECATED
};
-// ============================================================================
-// [asmjit::AlignNode]
-// ============================================================================
-
//! Align directive (BaseBuilder).
//!
//! Wraps `.align` directive.
@@ -1035,19 +1016,24 @@ class AlignNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(AlignNode)
- //! Align mode, see `AlignMode`.
- uint32_t _alignMode;
+ //! \name Members
+ //! \{
+
//! Alignment (in bytes).
uint32_t _alignment;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `AlignNode` instance.
- inline AlignNode(BaseBuilder* cb, uint32_t alignMode, uint32_t alignment) noexcept
- : BaseNode(cb, kNodeAlign, kFlagIsCode | kFlagHasNoEffect),
- _alignMode(alignMode),
- _alignment(alignment) {}
+ inline AlignNode(BaseBuilder* cb, AlignMode alignMode, uint32_t alignment) noexcept
+ : BaseNode(cb, NodeType::kAlign, NodeFlags::kIsCode | NodeFlags::kHasNoEffect) {
+
+ _alignData._alignMode = alignMode;
+ _alignment = alignment;
+ }
//! \}
@@ -1055,9 +1041,9 @@ public:
//! \{
//! Returns align mode.
- inline uint32_t alignMode() const noexcept { return _alignMode; }
+ inline AlignMode alignMode() const noexcept { return _alignData._alignMode; }
//! Sets align mode to `alignMode`.
- inline void setAlignMode(uint32_t alignMode) noexcept { _alignMode = alignMode; }
+ inline void setAlignMode(AlignMode alignMode) noexcept { _alignData._alignMode = alignMode; }
//! Returns align offset in bytes.
inline uint32_t alignment() const noexcept { return _alignment; }
@@ -1067,22 +1053,22 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::EmbedDataNode]
-// ============================================================================
-
//! Embed data node.
//!
-//! Wraps `.data` directive. The node contains data that will be placed at the
-//! node's position in the assembler stream. The data is considered to be RAW;
-//! no analysis nor byte-order conversion is performed on RAW data.
+//! Wraps `.data` directive. The node contains data that will be placed at the node's position in the assembler
+//! stream. The data is considered to be RAW; no analysis nor byte-order conversion is performed on RAW data.
class EmbedDataNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(EmbedDataNode)
+ //! \cond INTERNAL
enum : uint32_t {
kInlineBufferSize = 128 - (sizeof(BaseNode) + sizeof(size_t) * 2)
};
+ //! \endcond
+
+ //! \name Members
+ //! \{
size_t _itemCount;
size_t _repeatCount;
@@ -1092,15 +1078,17 @@ public:
uint8_t _inlineData[kInlineBufferSize];
};
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `EmbedDataNode` instance.
inline EmbedDataNode(BaseBuilder* cb) noexcept
- : BaseNode(cb, kNodeEmbedData, kFlagIsData),
+ : BaseNode(cb, NodeType::kEmbedData, NodeFlags::kIsData),
_itemCount(0),
_repeatCount(0) {
- _embed._typeId = uint8_t(Type::kIdU8),
+ _embed._typeId = TypeId::kUInt8;
_embed._typeSize = uint8_t(1);
memset(_inlineData, 0, kInlineBufferSize);
}
@@ -1110,8 +1098,8 @@ public:
//! \name Accessors
//! \{
- //! Returns \ref Type::Id of the data.
- inline uint32_t typeId() const noexcept { return _embed._typeId; }
+ //! Returns data type as \ref TypeId.
+ inline TypeId typeId() const noexcept { return _embed._typeId; }
//! Returns the size of a single data element.
inline uint32_t typeSize() const noexcept { return _embed._typeSize; }
@@ -1140,24 +1128,25 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::EmbedLabelNode]
-// ============================================================================
-
//! Label data node.
class EmbedLabelNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(EmbedLabelNode)
+ //! \name Members
+ //! \{
+
uint32_t _labelId;
uint32_t _dataSize;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `EmbedLabelNode` instance.
inline EmbedLabelNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t dataSize = 0) noexcept
- : BaseNode(cb, kNodeEmbedLabel, kFlagIsData),
+ : BaseNode(cb, NodeType::kEmbedLabel, NodeFlags::kIsData),
_labelId(labelId),
_dataSize(dataSize) {}
@@ -1182,32 +1171,28 @@ public:
inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; }
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use labelId() instead")
- inline uint32_t id() const noexcept { return labelId(); }
-#endif // !ASMJIT_NO_DEPRECATED
};
-// ============================================================================
-// [asmjit::EmbedLabelDeltaNode]
-// ============================================================================
-
//! Label data node.
class EmbedLabelDeltaNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(EmbedLabelDeltaNode)
+ //! \name Members
+ //! \{
+
uint32_t _labelId;
uint32_t _baseLabelId;
uint32_t _dataSize;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `EmbedLabelDeltaNode` instance.
inline EmbedLabelDeltaNode(BaseBuilder* cb, uint32_t labelId = 0, uint32_t baseLabelId = 0, uint32_t dataSize = 0) noexcept
- : BaseNode(cb, kNodeEmbedLabelDelta, kFlagIsData),
+ : BaseNode(cb, NodeType::kEmbedLabelDelta, NodeFlags::kIsData),
_labelId(labelId),
_baseLabelId(baseLabelId),
_dataSize(dataSize) {}
@@ -1243,33 +1228,20 @@ public:
inline void setDataSize(uint32_t dataSize) noexcept { _dataSize = dataSize; }
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use labelId() instead")
- inline uint32_t id() const noexcept { return labelId(); }
-
- ASMJIT_DEPRECATED("Use setLabelId() instead")
- inline void setId(uint32_t id) noexcept { setLabelId(id); }
-
- ASMJIT_DEPRECATED("Use baseLabelId() instead")
- inline uint32_t baseId() const noexcept { return baseLabelId(); }
-
- ASMJIT_DEPRECATED("Use setBaseLabelId() instead")
- inline void setBaseId(uint32_t id) noexcept { setBaseLabelId(id); }
-#endif // !ASMJIT_NO_DEPRECATED
};
-// ============================================================================
-// [asmjit::ConstPoolNode]
-// ============================================================================
-
//! A node that wraps `ConstPool`.
class ConstPoolNode : public LabelNode {
public:
ASMJIT_NONCOPYABLE(ConstPoolNode)
+ //! \name Members
+ //! \{
+
ConstPool _constPool;
+ //! \}
+
//! \name Construction & Destruction
//! \{
@@ -1278,9 +1250,9 @@ public:
: LabelNode(cb, id),
_constPool(&cb->_codeZone) {
- setType(kNodeConstPool);
- addFlags(kFlagIsData);
- clearFlags(kFlagIsCode | kFlagHasNoEffect);
+ setType(NodeType::kConstPool);
+ addFlags(NodeFlags::kIsData);
+ clearFlags(NodeFlags::kIsCode | NodeFlags::kHasNoEffect);
}
//! \}
@@ -1313,10 +1285,6 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::CommentNode]
-// ============================================================================
-
//! Comment node.
class CommentNode : public BaseNode {
public:
@@ -1327,41 +1295,29 @@ public:
//! Creates a new `CommentNode` instance.
inline CommentNode(BaseBuilder* cb, const char* comment) noexcept
- : BaseNode(cb, kNodeComment, kFlagIsInformative | kFlagHasNoEffect | kFlagIsRemovable) {
+ : BaseNode(cb, NodeType::kComment, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect | NodeFlags::kIsRemovable) {
_inlineComment = comment;
}
//! \}
};
-// ============================================================================
-// [asmjit::SentinelNode]
-// ============================================================================
-
//! Sentinel node.
//!
-//! Sentinel is a marker that is completely ignored by the code builder. It's
-//! used to remember a position in a code as it never gets removed by any pass.
+//! Sentinel is a marker that is completely ignored by the code builder. It's used to remember a position in a code
+//! as it never gets removed by any pass.
class SentinelNode : public BaseNode {
public:
ASMJIT_NONCOPYABLE(SentinelNode)
- //! Type of the sentinel (purery informative purpose).
- enum SentinelType : uint32_t {
- //! Type of the sentinel is not known.
- kSentinelUnknown = 0u,
- //! This is a sentinel used at the end of \ref FuncNode.
- kSentinelFuncEnd = 1u
- };
-
//! \name Construction & Destruction
//! \{
//! Creates a new `SentinelNode` instance.
- inline SentinelNode(BaseBuilder* cb, uint32_t sentinelType = kSentinelUnknown) noexcept
- : BaseNode(cb, kNodeSentinel, kFlagIsInformative | kFlagHasNoEffect) {
+ inline SentinelNode(BaseBuilder* cb, SentinelType sentinelType = SentinelType::kUnknown) noexcept
+ : BaseNode(cb, NodeType::kSentinel, NodeFlags::kIsInformative | NodeFlags::kHasNoEffect) {
- _sentinel._sentinelType = uint8_t(sentinelType);
+ _sentinel._sentinelType = sentinelType;
}
//! \}
@@ -1370,33 +1326,34 @@ public:
//! \{
//! Returns the type of the sentinel.
- inline uint32_t sentinelType() const noexcept {
+ inline SentinelType sentinelType() const noexcept {
return _sentinel._sentinelType;
}
//! Sets the type of the sentinel.
- inline void setSentinelType(uint32_t type) noexcept {
- _sentinel._sentinelType = uint8_t(type);
+ inline void setSentinelType(SentinelType type) noexcept {
+ _sentinel._sentinelType = type;
}
//! \}
};
-// ============================================================================
-// [asmjit::Pass]
-// ============================================================================
-
//! Pass can be used to implement code transformations, analysis, and lowering.
class ASMJIT_VIRTAPI Pass {
public:
ASMJIT_BASE_CLASS(Pass)
ASMJIT_NONCOPYABLE(Pass)
+ //! \name Members
+ //! \{
+
//! BaseBuilder this pass is assigned to.
BaseBuilder* _cb = nullptr;
//! Name of the pass.
const char* _name = nullptr;
+ //! \}
+
//! \name Construction & Destruction
//! \{
@@ -1420,8 +1377,8 @@ public:
//! Processes the code stored in Builder or Compiler.
//!
- //! This is the only function that is called by the `BaseBuilder` to process
- //! the code. It passes `zone`, which will be reset after the `run()` finishes.
+ //! This is the only function that is called by the `BaseBuilder` to process the code. It passes `zone`,
+ //! which will be reset after the `run()` finishes.
virtual Error run(Zone* zone, Logger* logger) = 0;
//! \}
diff --git a/src/asmjit/core/codebuffer.h b/src/asmjit/core/codebuffer.h
index 76c86b1..4946e7a 100644
--- a/src/asmjit/core/codebuffer.h
+++ b/src/asmjit/core/codebuffer.h
@@ -1,42 +1,35 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_CODEBUFFER_H_INCLUDED
#define ASMJIT_CORE_CODEBUFFER_H_INCLUDED
#include "../core/globals.h"
+#include "../core/support.h"
ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [asmjit::CodeBuffer]
-// ============================================================================
+//! Flags used by \ref 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.
struct CodeBuffer {
+ //! \name Members
+ //! \{
+
//! The content of the buffer (data).
uint8_t* _data;
//! Number of bytes of `data` used.
@@ -44,15 +37,9 @@ struct CodeBuffer {
//! Buffer capacity (in bytes).
size_t _capacity;
//! 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
//! \{
@@ -73,20 +60,20 @@ struct CodeBuffer {
//! \name Accessors
//! \{
- //! Returns code buffer flags, see \ref Flags.
- inline uint32_t flags() const noexcept { return _flags; }
+ //! Returns code buffer flags.
+ inline CodeBufferFlags flags() const noexcept { return _flags; }
//! Tests whether the code buffer has the given `flag` set.
- inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
+ inline bool hasFlag(CodeBufferFlags flag) const noexcept { return Support::test(_flags, flag); }
//! Tests whether this code buffer has a fixed size.
//!
//! Fixed size means that the code buffer is fixed and cannot grow.
- inline bool isFixed() const noexcept { return hasFlag(kFlagIsFixed); }
+ inline bool isFixed() const noexcept { return hasFlag(CodeBufferFlags::kIsFixed); }
//! Tests whether the data in this code buffer is external.
//!
//! External data can only be provided by users, it's never used by AsmJit.
- inline bool isExternal() const noexcept { return hasFlag(kFlagIsExternal); }
+ inline bool isExternal() const noexcept { return hasFlag(CodeBufferFlags::kIsExternal); }
//! Tests whether the data in this code buffer is allocated (non-null).
inline bool isAllocated() const noexcept { return _data != nullptr; }
diff --git a/src/asmjit/core/codeholder.cpp b/src/asmjit/core/codeholder.cpp
index 3c4154e..f446801 100644
--- a/src/asmjit/core/codeholder.cpp
+++ b/src/asmjit/core/codeholder.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/assembler.h"
@@ -32,9 +14,8 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [Globals]
-// ============================================================================
+// Globals
+// =======
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;
}
-// ============================================================================
-// [asmjit::LabelLinkIterator]
-// ============================================================================
+// LabelLinkIterator
+// =================
class LabelLinkIterator {
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(); }
- ASMJIT_INLINE bool isValid() const noexcept { return _link != nullptr; }
+ inline explicit operator bool() const noexcept { return isValid(); }
+ inline bool isValid() const noexcept { return _link != nullptr; }
- ASMJIT_INLINE LabelLink* link() const noexcept { return _link; }
- ASMJIT_INLINE LabelLink* operator->() const noexcept { return _link; }
+ inline LabelLink* link() 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;
_link = *_pPrev;
}
- ASMJIT_INLINE void next() noexcept {
+ inline void next() noexcept {
_pPrev = &_link->next;
_link = *_pPrev;
}
- ASMJIT_INLINE void resolveAndNext(CodeHolder* code) noexcept {
+ inline void resolveAndNext(CodeHolder* code) noexcept {
LabelLink* linkToDelete = _link;
_link = _link->next;
@@ -81,11 +61,10 @@ public:
LabelLink* _link;
};
-// ============================================================================
-// [asmjit::CodeHolder - Utilities]
-// ============================================================================
+// CodeHolder - Utilities
+// ======================
-static void CodeHolder_resetInternal(CodeHolder* self, uint32_t resetPolicy) noexcept {
+static void CodeHolder_resetInternal(CodeHolder* self, ResetPolicy resetPolicy) noexcept {
uint32_t i;
const ZoneVector& emitters = self->emitters();
@@ -134,27 +113,25 @@ static void CodeHolder_onSettingsUpdated(CodeHolder* self) noexcept {
}
}
-// ============================================================================
-// [asmjit::CodeHolder - Construction / Destruction]
-// ============================================================================
+// CodeHolder - Construction & Destruction
+// =======================================
-CodeHolder::CodeHolder() noexcept
+CodeHolder::CodeHolder(const Support::Temporary* temporary) noexcept
: _environment(),
_baseAddress(Globals::kNoBaseAddress),
_logger(nullptr),
_errorHandler(nullptr),
- _zone(16384 - Zone::kBlockOverhead),
+ _zone(16384 - Zone::kBlockOverhead, 1, temporary),
_allocator(&_zone),
_unresolvedLinkCount(0),
_addressTableSection(nullptr) {}
CodeHolder::~CodeHolder() noexcept {
- CodeHolder_resetInternal(this, Globals::kResetHard);
+ CodeHolder_resetInternal(this, ResetPolicy::kHard);
}
-// ============================================================================
-// [asmjit::CodeHolder - Init / Reset]
-// ============================================================================
+// CodeHolder - Init & Reset
+// =========================
inline void CodeHolder_setSectionDefaultName(
Section* section,
@@ -179,7 +156,7 @@ Error CodeHolder::init(const Environment& environment, uint64_t baseAddress) noe
if (err == kErrorOk) {
Section* section = _allocator.allocZeroedT();
if (ASMJIT_LIKELY(section)) {
- section->_flags = Section::kFlagExec | Section::kFlagConst;
+ section->_flags = SectionFlags::kExecutable | SectionFlags::kReadOnly;
CodeHolder_setSectionDefaultName(section, '.', 't', 'e', 'x', 't');
_sections.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);
}
-// ============================================================================
-// [asmjit::CodeHolder - Attach / Detach]
-// ============================================================================
+// CodeHolder - Attach / Detach
+// ============================
Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
// Catch a possible misuse of the API.
@@ -214,8 +190,8 @@ Error CodeHolder::attach(BaseEmitter* emitter) noexcept {
return DebugUtils::errored(kErrorInvalidArgument);
// Invalid emitter, this should not be possible.
- uint32_t type = emitter->emitterType();
- if (ASMJIT_UNLIKELY(type == BaseEmitter::kTypeNone || type >= BaseEmitter::kTypeCount))
+ EmitterType type = emitter->emitterType();
+ if (ASMJIT_UNLIKELY(type == EmitterType::kNone || uint32_t(type) > uint32_t(EmitterType::kMaxValue)))
return DebugUtils::errored(kErrorInvalidState);
// This is suspicious, but don't fail if `emitter` is already attached
@@ -261,9 +237,8 @@ Error CodeHolder::detach(BaseEmitter* emitter) noexcept {
return err;
}
-// ============================================================================
-// [asmjit::CodeHolder - Logging]
-// ============================================================================
+// CodeHolder - Logging
+// ====================
void CodeHolder::setLogger(Logger* logger) noexcept {
#ifndef ASMJIT_NO_LOGGING
@@ -274,18 +249,16 @@ void CodeHolder::setLogger(Logger* logger) noexcept {
#endif
}
-// ============================================================================
-// [asmjit::CodeHolder - Error Handling]
-// ============================================================================
+// CodeHolder - Error Handling
+// ===========================
void CodeHolder::setErrorHandler(ErrorHandler* errorHandler) noexcept {
_errorHandler = errorHandler;
CodeHolder_onSettingsUpdated(this);
}
-// ============================================================================
-// [asmjit::CodeHolder - Code Buffer]
-// ============================================================================
+// CodeHolder - Code Buffer
+// ========================
static Error CodeHolder_reserveInternal(CodeHolder* self, CodeBuffer* cb, size_t n) noexcept {
uint8_t* oldData = cb->_data;
@@ -368,11 +341,10 @@ Error CodeHolder::reserveBuffer(CodeBuffer* cb, size_t n) noexcept {
return CodeHolder_reserveInternal(this, cb, n);
}
-// ============================================================================
-// [asmjit::CodeHolder - Sections]
-// ============================================================================
+// 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;
if (nameSize == SIZE_MAX)
@@ -435,7 +407,12 @@ Section* CodeHolder::ensureAddressTableSection() noexcept {
if (_addressTableSection)
return _addressTableSection;
- newSection(&_addressTableSection, CodeHolder_addrTabName, sizeof(CodeHolder_addrTabName) - 1, 0, _environment.registerSize(), std::numeric_limits::max());
+ newSection(&_addressTableSection,
+ CodeHolder_addrTabName,
+ sizeof(CodeHolder_addrTabName) - 1,
+ SectionFlags::kNone,
+ _environment.registerSize(),
+ std::numeric_limits::max());
return _addressTableSection;
}
@@ -458,9 +435,8 @@ Error CodeHolder::addAddressToAddressTable(uint64_t address) noexcept {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::CodeHolder - Labels / Symbols]
-// ============================================================================
+// CodeHolder - Labels & Symbols
+// =============================
//! Only used to lookup a label from `_namedLabels`.
class LabelByName {
@@ -547,32 +523,66 @@ Error CodeHolder::newLabelEntry(LabelEntry** entryOut) noexcept {
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;
uint32_t hashCode = CodeHolder_hashNameAndGetSize(name, nameSize);
- if (ASMJIT_UNLIKELY(nameSize == 0))
- return DebugUtils::errored(kErrorInvalidLabelName);
+ if (ASMJIT_UNLIKELY(nameSize == 0)) {
+ if (type == LabelType::kAnonymous)
+ return newLabelEntry(entryOut);
+ else
+ return DebugUtils::errored(kErrorInvalidLabelName);
+ }
if (ASMJIT_UNLIKELY(nameSize > Globals::kMaxLabelNameSize))
return DebugUtils::errored(kErrorLabelNameTooLong);
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();
+
+ 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()))
return DebugUtils::errored(kErrorInvalidParentLabel);
hashCode ^= parentId;
break;
+ }
- case Label::kTypeGlobal:
- case Label::kTypeExternal:
+ case LabelType::kGlobal:
+ case LabelType::kExternal: {
if (ASMJIT_UNLIKELY(parentId != Globals::kInvalidId))
- return DebugUtils::errored(kErrorNonLocalLabelCannotHaveParent);
+ return DebugUtils::errored(kErrorInvalidParentLabel);
break;
+ }
- default:
+ default: {
return DebugUtils::errored(kErrorInvalidArgument);
+ }
}
// 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->_setId(labelId);
- le->_type = uint8_t(type);
+ le->_type = type;
le->_parentId = parentId;
le->_offset = 0;
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;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Relocations]
-// ============================================================================
+// CodeHolder - Relocations
+// ========================
-Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
+Error CodeHolder::newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept {
ASMJIT_PROPAGATE(_relocations.willGrow(&_allocator));
uint32_t relocId = _relocations.size();
@@ -749,7 +758,7 @@ Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
return DebugUtils::errored(kErrorOutOfMemory);
re->_id = relocId;
- re->_relocType = uint8_t(relocType);
+ re->_relocType = relocType;
re->_sourceSectionId = Globals::kInvalidId;
re->_targetSectionId = Globals::kInvalidId;
_relocations.appendUnsafe(re);
@@ -758,26 +767,25 @@ Error CodeHolder::newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept {
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Expression Evaluation]
-// ============================================================================
+// CodeHolder - Expression Evaluation
+// ==================================
static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, uint64_t* out) noexcept {
uint64_t value[2];
for (size_t i = 0; i < 2; i++) {
uint64_t v;
switch (exp->valueType[i]) {
- case Expression::kValueNone: {
+ case ExpressionValueType::kNone: {
v = 0;
break;
}
- case Expression::kValueConstant: {
+ case ExpressionValueType::kConstant: {
v = exp->value[i].constant;
break;
}
- case Expression::kValueLabel: {
+ case ExpressionValueType::kLabel: {
LabelEntry* le = exp->value[i].label;
if (!le->isBound())
return DebugUtils::errored(kErrorExpressionLabelNotBound);
@@ -785,7 +793,7 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
break;
}
- case Expression::kValueExpression: {
+ case ExpressionValueType::kExpression: {
Expression* nested = exp->value[i].expression;
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(self, nested, &v));
break;
@@ -803,27 +811,27 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
uint64_t& b = value[1];
switch (exp->opType) {
- case Expression::kOpAdd:
+ case ExpressionOpType::kAdd:
result = a + b;
break;
- case Expression::kOpSub:
+ case ExpressionOpType::kSub:
result = a - b;
break;
- case Expression::kOpMul:
+ case ExpressionOpType::kMul:
result = a * b;
break;
- case Expression::kOpSll:
+ case ExpressionOpType::kSll:
result = (b > 63) ? uint64_t(0) : uint64_t(a << b);
break;
- case Expression::kOpSrl:
+ case ExpressionOpType::kSrl:
result = (b > 63) ? uint64_t(0) : uint64_t(a >> b);
break;
- case Expression::kOpSra:
+ case ExpressionOpType::kSra:
result = Support::sar(a, Support::min(b, 63));
break;
@@ -835,9 +843,8 @@ static Error CodeHolder_evaluateExpression(CodeHolder* self, Expression* exp, ui
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Utilities]
-// ============================================================================
+// CodeHolder - Utilities
+// ======================
Error CodeHolder::flatten() noexcept {
uint64_t offset = 0;
@@ -917,7 +924,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
// Relocate all recorded locations.
for (const RelocEntry* re : _relocations) {
// Possibly deleted or optimized-out entry.
- if (re->relocType() == RelocEntry::kTypeNone)
+ if (re->relocType() == RelocType::kNone)
continue;
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();
switch (re->relocType()) {
- case RelocEntry::kTypeExpression: {
+ case RelocType::kExpression: {
Expression* expression = (Expression*)(uintptr_t(value));
ASMJIT_PROPAGATE(CodeHolder_evaluateExpression(this, expression, &value));
break;
}
- case RelocEntry::kTypeAbsToAbs: {
+ case RelocType::kAbsToAbs: {
break;
}
- case RelocEntry::kTypeRelToAbs: {
+ case RelocType::kRelToAbs: {
// Value is currently a relative offset from the start of its section.
// We have to convert it to an absolute offset (including base address).
if (ASMJIT_UNLIKELY(!targetSection))
@@ -961,14 +968,14 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
break;
}
- case RelocEntry::kTypeAbsToRel: {
+ case RelocType::kAbsToRel: {
value -= baseAddress + sectionOffset + sourceOffset + regionSize;
if (addressSize > 4 && !Support::isInt32(int64_t(value)))
return DebugUtils::errored(kErrorRelocOffsetOutOfRange);
break;
}
- case RelocEntry::kTypeX64AddressEntry: {
+ case RelocType::kX64AddressEntry: {
if (re->format().valueSize() != 4 || valueOffset < 2)
return DebugUtils::errored(kErrorInvalidRelocEntry);
@@ -1055,7 +1062,7 @@ Error CodeHolder::relocateToBase(uint64_t baseAddress) noexcept {
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)))
return DebugUtils::errored(kErrorInvalidSection);
@@ -1067,7 +1074,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId,
memcpy(dst, section->data(), bufferSize);
- if (bufferSize < dstSize && (copyOptions & kCopyPadSectionBuffer)) {
+ if (bufferSize < dstSize && Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer)) {
size_t paddingSize = dstSize - bufferSize;
memset(static_cast(dst) + bufferSize, 0, paddingSize);
}
@@ -1075,7 +1082,7 @@ Error CodeHolder::copySectionData(void* dst, size_t dstSize, uint32_t sectionId,
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;
for (Section* section : _sectionsByOrder) {
if (section->offset() > dstSize)
@@ -1091,7 +1098,7 @@ Error CodeHolder::copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOpti
size_t paddingSize = 0;
memcpy(dstTarget, section->data(), bufferSize);
- if ((copyOptions & kCopyPadSectionBuffer) && bufferSize < section->virtualSize()) {
+ if (Support::test(copyFlags, CopySectionFlags::kPadSectionBuffer) && bufferSize < section->virtualSize()) {
paddingSize = Support::min(dstSize - offset, size_t(section->virtualSize())) - bufferSize;
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);
}
- if (end < dstSize && (copyOptions & kCopyPadTargetBuffer)) {
+ if (end < dstSize && Support::test(copyFlags, CopySectionFlags::kPadTargetBuffer)) {
memset(static_cast(dst) + end, 0, dstSize - end);
}
return kErrorOk;
}
-// ============================================================================
-// [asmjit::CodeHolder - Unit]
-// ============================================================================
+// CodeHolder - Tests
+// ==================
#if defined(ASMJIT_TEST)
UNIT(code_holder) {
@@ -1116,34 +1122,33 @@ UNIT(code_holder) {
INFO("Verifying CodeHolder::init()");
Environment env;
- env.init(Environment::kArchX86);
+ env.init(Arch::kX86);
code.init(env);
- EXPECT(code.arch() == Environment::kArchX86);
+ EXPECT(code.arch() == Arch::kX86);
INFO("Verifying named labels");
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(code.labelIdByName("NamedLabel") == le->id());
INFO("Verifying section ordering");
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.sectionsByOrder()[0] == section1);
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.sectionsByOrder()[0] == section0);
EXPECT(code.sectionsByOrder()[1] == section1);
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.sectionsByOrder()[3] == section3);
-
}
#endif
diff --git a/src/asmjit/core/codeholder.h b/src/asmjit/core/codeholder.h
index 2a6ee49..b6257f2 100644
--- a/src/asmjit/core/codeholder.h
+++ b/src/asmjit/core/codeholder.h
@@ -1,32 +1,13 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_CODEHOLDER_H_INCLUDED
#define ASMJIT_CORE_CODEHOLDER_H_INCLUDED
#include "../core/archtraits.h"
#include "../core/codebuffer.h"
-#include "../core/datatypes.h"
#include "../core/errorhandler.h"
#include "../core/operand.h"
#include "../core/string.h"
@@ -43,65 +24,41 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class BaseEmitter;
class CodeHolder;
class LabelEntry;
class Logger;
-// ============================================================================
-// [asmjit::AlignMode]
-// ============================================================================
-
-//! Align mode.
-enum AlignMode : uint32_t {
- //! Align executable code.
- kAlignCode = 0,
- //! Align non-executable code.
- kAlignData = 1,
- //! Align by a sequence of zeros.
- kAlignZero = 2,
- //! Count of alignment modes.
- kAlignCount = 3
+//! Operator type that can be used within an \ref Expression.
+enum class ExpressionOpType : uint8_t {
+ //! Addition.
+ kAdd = 0,
+ //! Subtraction.
+ kSub = 1,
+ //! Multiplication
+ kMul = 2,
+ //! Logical left shift.
+ kSll = 3,
+ //! Logical right shift.
+ kSrl = 4,
+ //! Arithmetic right shift.
+ kSra = 5
};
-// ============================================================================
-// [asmjit::Expression]
-// ============================================================================
+//! Value tyoe that can be used within an \ref Expression.
+enum class ExpressionValueType : uint8_t {
+ //! No value or invalid.
+ kNone = 0,
+ //! Value is 64-bit unsigned integer (constant).
+ kConstant = 1,
+ //! Value is \ref LabelEntry, which references a \ref Label.
+ kLabel = 2,
+ //! Value is \ref Expression
+ kExpression = 3
+};
//! Expression node that can reference constants, labels, and another expressions.
struct Expression {
- //! Operation type.
- enum OpType : uint8_t {
- //! Addition.
- kOpAdd = 0,
- //! Subtraction.
- kOpSub = 1,
- //! Multiplication
- kOpMul = 2,
- //! Logical left shift.
- kOpSll = 3,
- //! Logical right shift.
- kOpSrl = 4,
- //! Arithmetic right shift.
- kOpSra = 5
- };
-
- //! Type of \ref Value.
- enum ValueType : uint8_t {
- //! No value or invalid.
- kValueNone = 0,
- //! Value is 64-bit unsigned integer (constant).
- kValueConstant = 1,
- //! Value is \ref LabelEntry, which references a \ref Label.
- kValueLabel = 2,
- //! Value is \ref Expression
- kValueExpression = 3
- };
-
//! Expression value.
union Value {
//! Constant.
@@ -112,50 +69,93 @@ struct Expression {
LabelEntry* label;
};
+ //! \name Members
+ //! \{
+
//! Operation type.
- uint8_t opType;
+ ExpressionOpType opType;
//! Value types of \ref value.
- uint8_t valueType[2];
+ ExpressionValueType valueType[2];
//! Reserved for future use, should be initialized to zero.
uint8_t reserved[5];
//! Expression left and right values.
Value value[2];
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
//! Resets the whole expression.
//!
- //! Changes both values to \ref kValueNone.
+ //! Changes both values to \ref ExpressionValueType::kNone.
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
- //! Sets the value type at `index` to \ref kValueConstant and its content to `constant`.
+ //! Sets the value type at `index` to \ref ExpressionValueType::kConstant and its content to `constant`.
inline void setValueAsConstant(size_t index, uint64_t constant) noexcept {
- valueType[index] = kValueConstant;
+ valueType[index] = ExpressionValueType::kConstant;
value[index].constant = constant;
}
- //! Sets the value type at `index` to \ref kValueLabel and its content to `labelEntry`.
+ //! Sets the value type at `index` to \ref ExpressionValueType::kLabel and its content to `labelEntry`.
inline void setValueAsLabel(size_t index, LabelEntry* labelEntry) noexcept {
- valueType[index] = kValueLabel;
+ valueType[index] = ExpressionValueType::kLabel;
value[index].label = labelEntry;
}
- //! Sets the value type at `index` to \ref kValueExpression and its content to `expression`.
+ //! Sets the value type at `index` to \ref ExpressionValueType::kExpression and its content to `expression`.
inline void setValueAsExpression(size_t index, Expression* expression) noexcept {
- valueType[index] = kValueLabel;
+ valueType[index] = ExpressionValueType::kExpression;
value[index].expression = expression;
}
+
+ //! \}
};
-// ============================================================================
-// [asmjit::Section]
-// ============================================================================
+//! Section flags, used by \ref Section.
+enum class SectionFlags : uint32_t {
+ //! No flags.
+ kNone = 0,
+ //! Executable (.text sections).
+ kExecutable = 0x00000001u,
+ //! Read-only (.text and .data sections).
+ kReadOnly = 0x00000002u,
+ //! Zero initialized by the loader (BSS).
+ kZeroInitialized = 0x00000004u,
+ //! Info / comment flag.
+ kComment = 0x00000008u,
+ //! Section created implicitly, can be deleted by \ref Target.
+ kImplicit = 0x80000000u
+};
+ASMJIT_DEFINE_ENUM_FLAGS(SectionFlags)
+
+//! Flags that can be used with \ref CodeHolder::copySectionData() and \ref CodeHolder::copyFlattenedData().
+enum class CopySectionFlags : uint32_t {
+ //! No flags.
+ kNone = 0,
+
+ //! If virtual size of a section is greater than the size of its \ref CodeBuffer then all bytes between the buffer
+ //! size and virtual size will be zeroed. If this option is not set then those bytes would be left as is, which
+ //! means that if the user didn't initialize them they would have a previous content, which may be unwanted.
+ kPadSectionBuffer = 0x00000001u,
+
+ //! Clears the target buffer if the flattened data is less than the destination size. This option works
+ //! only with \ref CodeHolder::copyFlattenedData() as it processes multiple sections. It is ignored by
+ //! \ref CodeHolder::copySectionData().
+ kPadTargetBuffer = 0x00000002u
+};
+ASMJIT_DEFINE_ENUM_FLAGS(CopySectionFlags)
//! Section entry.
class Section {
public:
+ //! \name Members
+ //! \{
+
//! Section id.
uint32_t _id;
//! Section flags.
- uint32_t _flags;
+ SectionFlags _flags;
//! Section alignment requirements (0 if no requirements).
uint32_t _alignment;
//! Order (lower value means higher priority).
@@ -169,19 +169,7 @@ public:
//! Code or data buffer.
CodeBuffer _buffer;
- //! Section flags.
- enum Flags : uint32_t {
- //! Executable (.text sections).
- kFlagExec = 0x00000001u,
- //! Read-only (.text and .data sections).
- kFlagConst = 0x00000002u,
- //! Zero initialized by the loader (BSS).
- kFlagZero = 0x00000004u,
- //! Info / comment flag.
- kFlagInfo = 0x00000008u,
- //! Section created implicitly and can be deleted by \ref Target.
- kFlagImplicit = 0x80000000u
- };
+ //! \}
//! \name Accessors
//! \{
@@ -196,14 +184,14 @@ public:
//! \overload
inline const uint8_t* data() const noexcept { return _buffer.data(); }
- //! Returns the section flags, see \ref Flags.
- inline uint32_t flags() const noexcept { return _flags; }
+ //! Returns the section flags.
+ inline SectionFlags flags() const noexcept { return _flags; }
//! Tests whether the section has the given `flag`.
- inline bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
+ inline bool hasFlag(SectionFlags flag) const noexcept { return Support::test(_flags, flag); }
//! Adds `flags` to the section flags.
- inline void addFlags(uint32_t flags) noexcept { _flags |= flags; }
+ inline void addFlags(SectionFlags flags) noexcept { _flags |= flags; }
//! Removes `flags` from the section flags.
- inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
+ inline void clearFlags(SectionFlags flags) noexcept { _flags &= ~flags; }
//! Returns the minimum section alignment
inline uint32_t alignment() const noexcept { return _alignment; }
@@ -220,9 +208,8 @@ public:
//! Returns the virtual size of the section.
//!
- //! Virtual size is initially zero and is never changed by AsmJit. It's normal
- //! if virtual size is smaller than size returned by `bufferSize()` as the buffer
- //! stores real data emitted by assemblers or appended by users.
+ //! Virtual size is initially zero and is never changed by AsmJit. It's normal if virtual size is smaller than
+ //! size returned by `bufferSize()` as the buffer stores real data emitted by assemblers or appended by users.
//!
//! Use `realSize()` to get the real and final size of this section.
inline uint64_t virtualSize() const noexcept { return _virtualSize; }
@@ -242,346 +229,21 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::OffsetFormat]
-// ============================================================================
-
-//! Provides information about formatting offsets, absolute addresses, or their
-//! parts. Offset format is used by both \ref RelocEntry and \ref LabelLink.
-//!
-//! The illustration above describes the relation of region size and offset size.
-//! Region size is the size of the whole unit whereas offset size is the size of
-//! the unit that will be patched.
-//!
-//! ```
-//! +-> Code buffer | The subject of the relocation (region) |
-//! | | (Word-Offset) (Word-Size) |
-//! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx->
-//! | |
-//! [Word Offset points here]----+ +--- [WordOffset + WordSize]
-//! ```
-//!
-//! Once the offset word has been located it can be patched like this:
-//!
-//! ```
-//! |ImmDiscardLSB (discard LSB bits).
-//! |..
-//! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit)
-//! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB.
-//! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift.
-//! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit)
-//! |...............|
-//! (ImmBitCount) +- ImmBitShift
-//! ```
-struct OffsetFormat {
- //! Type of the displacement.
- uint8_t _type;
- //! Encoding flags.
- uint8_t _flags;
- //! Size of the region (in bytes) containing the offset value, if the offset
- //! value is part of an instruction, otherwise it would be the same as
- //! `_valueSize`.
- uint8_t _regionSize;
- //! Size of the offset value, in bytes (1, 2, 4, or 8).
- uint8_t _valueSize;
- //! Offset of the offset value, in bytes, relative to the start of the region
- //! or data. Value offset would be zero if both region size and value size are
- //! equal.
- uint8_t _valueOffset;
- //! Size of the displacement immediate value in bits.
- uint8_t _immBitCount;
- //! Shift of the displacement immediate value in bits in the target word.
- uint8_t _immBitShift;
- //! Number of least significant bits to discard before writing the immediate
- //! to the destination. All discarded bits must be zero otherwise the value
- //! is invalid.
- uint8_t _immDiscardLsb;
-
- //! Type of the displacement.
- enum Type : uint8_t {
- //! A value having `_immBitCount` bits and shifted by `_immBitShift`.
- //!
- //! This displacement type is sufficient for both X86/X64 and many other
- //! architectures that store displacement as continuous bits within a machine
- //! word.
- kTypeCommon = 0,
- //! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
- kTypeAArch64_ADR,
- //! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
- kTypeAArch64_ADRP,
-
- //! Count of displacement types.
- kTypeCount
- };
-
- //! Returns the type of the displacement.
- inline uint32_t type() const noexcept { return _type; }
-
- //! Returns flags.
- inline uint32_t flags() const noexcept { return _flags; }
-
- //! Returns the size of the region/instruction where the displacement is encoded.
- inline uint32_t regionSize() const noexcept { return _regionSize; }
-
- //! Returns the the offset of the word relative to the start of the region
- //! where the displacement is.
- inline uint32_t valueOffset() const noexcept { return _valueOffset; }
-
- //! Returns the size of the data-type (word) that contains the displacement, in bytes.
- inline uint32_t valueSize() const noexcept { return _valueSize; }
- //! Returns the count of bits of the displacement value in the data it's stored in.
- inline uint32_t immBitCount() const noexcept { return _immBitCount; }
- //! Returns the bit-shift of the displacement value in the data it's stored in.
- inline uint32_t immBitShift() const noexcept { return _immBitShift; }
- //! Returns the number of least significant bits of the displacement value,
- //! that must be zero and that are not part of the encoded data.
- inline uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; }
-
- //! Resets this offset format to a simple data value of `dataSize` bytes.
- //!
- //! The region will be the same size as data and immediate bits would correspond
- //! to `dataSize * 8`. There will be no immediate bit shift or discarded bits.
- inline void resetToDataValue(size_t dataSize) noexcept {
- ASMJIT_ASSERT(dataSize <= 8u);
-
- _type = uint8_t(kTypeCommon);
- _flags = uint8_t(0);
- _regionSize = uint8_t(dataSize);
- _valueSize = uint8_t(dataSize);
- _valueOffset = uint8_t(0);
- _immBitCount = uint8_t(dataSize * 8u);
- _immBitShift = uint8_t(0);
- _immDiscardLsb = uint8_t(0);
- }
-
- inline void resetToImmValue(uint32_t type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept {
- ASMJIT_ASSERT(valueSize <= 8u);
- ASMJIT_ASSERT(immBitShift < valueSize * 8u);
- ASMJIT_ASSERT(immBitCount <= 64u);
- ASMJIT_ASSERT(immDiscardLsb <= 64u);
-
- _type = uint8_t(type);
- _flags = uint8_t(0);
- _regionSize = uint8_t(valueSize);
- _valueSize = uint8_t(valueSize);
- _valueOffset = uint8_t(0);
- _immBitCount = uint8_t(immBitCount);
- _immBitShift = uint8_t(immBitShift);
- _immDiscardLsb = uint8_t(immDiscardLsb);
- }
-
- inline void setRegion(size_t regionSize, size_t valueOffset) noexcept {
- _regionSize = uint8_t(regionSize);
- _valueOffset = uint8_t(valueOffset);
- }
-
- inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept {
- _regionSize = uint8_t(leadingSize + trailingSize + _valueSize);
- _valueOffset = uint8_t(leadingSize);
- }
-};
-
-// ============================================================================
-// [asmjit::RelocEntry]
-// ============================================================================
-
-//! Relocation entry.
-struct RelocEntry {
- //! Relocation id.
- uint32_t _id;
- //! Type of the relocation.
- uint32_t _relocType;
- //! Format of the relocated value.
- OffsetFormat _format;
- //! Source section id.
- uint32_t _sourceSectionId;
- //! Target section id.
- uint32_t _targetSectionId;
- //! Source offset (relative to start of the section).
- uint64_t _sourceOffset;
- //! Payload (target offset, target address, expression, etc).
- uint64_t _payload;
-
- //! Relocation type.
- enum RelocType : uint32_t {
- //! None/deleted (no relocation).
- kTypeNone = 0,
- //! Expression evaluation, `_payload` is pointer to `Expression`.
- kTypeExpression = 1,
- //! Relocate absolute to absolute.
- kTypeAbsToAbs = 2,
- //! Relocate relative to absolute.
- kTypeRelToAbs = 3,
- //! Relocate absolute to relative.
- kTypeAbsToRel = 4,
- //! Relocate absolute to relative or use trampoline.
- kTypeX64AddressEntry = 5
- };
-
- //! \name Accessors
- //! \{
-
- inline uint32_t id() const noexcept { return _id; }
-
- inline uint32_t relocType() const noexcept { return _relocType; }
- inline const OffsetFormat& format() const noexcept { return _format; }
-
- inline uint32_t sourceSectionId() const noexcept { return _sourceSectionId; }
- inline uint32_t targetSectionId() const noexcept { return _targetSectionId; }
-
- inline uint64_t sourceOffset() const noexcept { return _sourceOffset; }
- inline uint64_t payload() const noexcept { return _payload; }
-
- Expression* payloadAsExpression() const noexcept {
- return reinterpret_cast(uintptr_t(_payload));
- }
-
- //! \}
-};
-
-// ============================================================================
-// [asmjit::LabelLink]
-// ============================================================================
-
-//! Data structure used to link either unbound labels or cross-section links.
-struct LabelLink {
- //! Next link (single-linked list).
- LabelLink* next;
- //! Section id where the label is bound.
- uint32_t sectionId;
- //! Relocation id or Globals::kInvalidId.
- uint32_t relocId;
- //! Label offset relative to the start of the section.
- size_t offset;
- //! Inlined rel8/rel32.
- intptr_t rel;
- //! Offset format information.
- OffsetFormat format;
-};
-
-// ============================================================================
-// [asmjit::LabelEntry]
-// ============================================================================
-
-//! Label entry.
-//!
-//! Contains the following properties:
-//! * Label id - This is the only thing that is set to the `Label` operand.
-//! * Label name - Optional, used mostly to create executables and libraries.
-//! * Label type - Type of the label, default `Label::kTypeAnonymous`.
-//! * Label parent id - Derived from many assemblers that allow to define a
-//! local label that falls under a global label. This allows to define
-//! many labels of the same name that have different parent (global) label.
-//! * Offset - offset of the label bound by `Assembler`.
-//! * Links - single-linked list that contains locations of code that has
-//! to be patched when the label gets bound. Every use of unbound label
-//! adds one link to `_links` list.
-//! * HVal - Hash value of label's name and optionally parentId.
-//! * HashNext - Hash-table implementation detail.
-class LabelEntry : public ZoneHashNode {
-public:
- // Let's round the size of `LabelEntry` to 64 bytes (as `ZoneAllocator` has
- // granularity of 32 bytes anyway). This gives `_name` the remaining space,
- // which is should be 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
- enum : uint32_t {
- kStaticNameSize =
- 64 - (sizeof(ZoneHashNode) + 8 + sizeof(Section*) + sizeof(size_t) + sizeof(LabelLink*))
- };
-
- //! Label type, see `Label::LabelType`.
- uint8_t _type;
- //! Must be zero.
- uint8_t _flags;
- //! Reserved.
- uint16_t _reserved16;
- //! Label parent id or zero.
- uint32_t _parentId;
- //! Label offset relative to the start of the `_section`.
- uint64_t _offset;
- //! Section where the label was bound.
- Section* _section;
- //! Label links.
- LabelLink* _links;
- //! Label name.
- ZoneString _name;
-
- //! \name Accessors
- //! \{
-
- // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode
- // to fill a padding that a C++ compiler targeting 64-bit CPU will add to align
- // the structure to 64-bits.
-
- //! Returns label id.
- inline uint32_t id() const noexcept { return _customData; }
- //! Sets label id (internal, used only by `CodeHolder`).
- inline void _setId(uint32_t id) noexcept { _customData = id; }
-
- //! Returns label type, see `Label::LabelType`.
- inline uint32_t type() const noexcept { return _type; }
- //! Returns label flags, returns 0 at the moment.
- inline uint32_t flags() const noexcept { return _flags; }
-
- //! Tests whether the label has a parent label.
- inline bool hasParent() const noexcept { return _parentId != Globals::kInvalidId; }
- //! Returns label's parent id.
- inline uint32_t parentId() const noexcept { return _parentId; }
-
- //! Returns the section where the label was bound.
- //!
- //! If the label was not yet bound the return value is `nullptr`.
- inline Section* section() const noexcept { return _section; }
-
- //! Tests whether the label has name.
- inline bool hasName() const noexcept { return !_name.empty(); }
-
- //! Returns the label's name.
- //!
- //! \note Local labels will return their local name without their parent
- //! part, for example ".L1".
- inline const char* name() const noexcept { return _name.data(); }
-
- //! Returns size of label's name.
- //!
- //! \note Label name is always null terminated, so you can use `strlen()` to
- //! get it, however, it's also cached in `LabelEntry` itself, so if you want
- //! to know the size the fastest way is to call `LabelEntry::nameSize()`.
- inline uint32_t nameSize() const noexcept { return _name.size(); }
-
- //! Returns links associated with this label.
- inline LabelLink* links() const noexcept { return _links; }
-
- //! Tests whether the label is bound.
- inline bool isBound() const noexcept { return _section != nullptr; }
- //! Tests whether the label is bound to a the given `sectionId`.
- inline bool isBoundTo(Section* section) const noexcept { return _section == section; }
-
- //! Returns the label offset (only useful if the label is bound).
- inline uint64_t offset() const noexcept { return _offset; }
-
- //! Returns the hash-value of label's name and its parent label (if any).
- //!
- //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function
- //! is implemented in `Support::hashString()` and `Support::hashRound()`.
- inline uint32_t hashCode() const noexcept { return _hashCode; }
-
- //! \}
-};
-
-// ============================================================================
-// [asmjit::AddressTableEntry]
-// ============================================================================
-
//! Entry in an address table.
class AddressTableEntry : public ZoneTreeNodeT {
public:
ASMJIT_NONCOPYABLE(AddressTableEntry)
+ //! \name Members
+ //! \{
+
//! Address.
uint64_t _address;
//! Slot.
uint32_t _slot;
+ //! \}
+
//! \name Construction & Destruction
//! \{
@@ -608,24 +270,371 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::CodeHolder]
-// ============================================================================
+//! Offset format type, used by \ref OffsetFormat.
+enum class OffsetType : uint8_t {
+ //! A value having `_immBitCount` bits and shifted by `_immBitShift`.
+ //!
+ //! This offset type is sufficient for many targets that store offset as a continuous set bits within an
+ //! instruction word / sequence of bytes.
+ kCommon = 0,
-//! Contains basic information about the target architecture and its options.
+ // AArch64 Specific Offset Formats
+ // -------------------------------
+
+ //! AARCH64 ADR format of `[.|immlo:2|.....|immhi:19|.....]`.
+ kAArch64_ADR,
+
+ //! AARCH64 ADRP format of `[.|immlo:2|.....|immhi:19|.....]` (4kB pages).
+ kAArch64_ADRP,
+
+ //! Maximum value of `OffsetFormatType`.
+ kMaxValue = kAArch64_ADRP
+};
+
+//! Provides information about formatting offsets, absolute addresses, or their parts. Offset format is used by both
+//! \ref RelocEntry and \ref LabelLink. The illustration below describes the relation of region size and offset size.
+//! Region size is the size of the whole unit whereas offset size is the size of the unit that will be patched.
//!
-//! In addition, it holds assembled code & data (including sections, labels, and
-//! relocation information). `CodeHolder` can store both binary and intermediate
-//! representation of assembly, which can be generated by \ref BaseAssembler,
-//! \ref BaseBuilder, and \ref BaseCompiler
+//! ```
+//! +-> Code buffer | The subject of the relocation (region) |
+//! | | (Word-Offset) (Word-Size) |
+//! |xxxxxxxxxxxxxxx|................|*PATCHED*|................|xxxxxxxxxxxx->
+//! | |
+//! [Word Offset points here]----+ +--- [WordOffset + WordSize]
+//! ```
//!
-//! \note `CodeHolder` has an ability to attach an \ref ErrorHandler, however,
-//! the error handler is not triggered by `CodeHolder` itself, it's instead
-//! propagated to all emitters that attach to it.
+//! Once the offset word has been located it can be patched like this:
+//!
+//! ```
+//! |ImmDiscardLSB (discard LSB bits).
+//! |..
+//! [0000000000000iiiiiiiiiiiiiiiiiDD] - Offset value (32-bit)
+//! [000000000000000iiiiiiiiiiiiiiiii] - Offset value after discard LSB.
+//! [00000000000iiiiiiiiiiiiiiiii0000] - Offset value shifted by ImmBitShift.
+//! [xxxxxxxxxxxiiiiiiiiiiiiiiiiixxxx] - Patched word (32-bit)
+//! |...............|
+//! (ImmBitCount) +- ImmBitShift
+//! ```
+struct OffsetFormat {
+ //! \name Members
+ //! \{
+
+ //! Type of the offset.
+ OffsetType _type;
+ //! Encoding flags.
+ uint8_t _flags;
+ //! Size of the region (in bytes) containing the offset value, if the offset value is part of an instruction,
+ //! otherwise it would be the same as `_valueSize`.
+ uint8_t _regionSize;
+ //! Size of the offset value, in bytes (1, 2, 4, or 8).
+ uint8_t _valueSize;
+ //! Offset of the offset value, in bytes, relative to the start of the region or data. Value offset would be
+ //! zero if both region size and value size are equal.
+ uint8_t _valueOffset;
+ //! Size of the offset immediate value in bits.
+ uint8_t _immBitCount;
+ //! Shift of the offset immediate value in bits in the target word.
+ uint8_t _immBitShift;
+ //! Number of least significant bits to discard before writing the immediate to the destination. All discarded
+ //! bits must be zero otherwise the value is invalid.
+ uint8_t _immDiscardLsb;
+
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
+ //! Returns the type of the offset.
+ inline OffsetType type() const noexcept { return _type; }
+
+ //! Returns flags.
+ inline uint32_t flags() const noexcept { return _flags; }
+
+ //! Returns the size of the region/instruction where the offset is encoded.
+ inline uint32_t regionSize() const noexcept { return _regionSize; }
+
+ //! Returns the the offset of the word relative to the start of the region where the offset is.
+ inline uint32_t valueOffset() const noexcept { return _valueOffset; }
+
+ //! Returns the size of the data-type (word) that contains the offset, in bytes.
+ inline uint32_t valueSize() const noexcept { return _valueSize; }
+ //! Returns the count of bits of the offset value in the data it's stored in.
+ inline uint32_t immBitCount() const noexcept { return _immBitCount; }
+ //! Returns the bit-shift of the offset value in the data it's stored in.
+ inline uint32_t immBitShift() const noexcept { return _immBitShift; }
+ //! Returns the number of least significant bits of the offset value, that must be zero and that are not part of
+ //! the encoded data.
+ inline uint32_t immDiscardLsb() const noexcept { return _immDiscardLsb; }
+
+ //! Resets this offset format to a simple data value of `dataSize` bytes.
+ //!
+ //! The region will be the same size as data and immediate bits would correspond to `dataSize * 8`. There will be
+ //! no immediate bit shift or discarded bits.
+ inline void resetToDataValue(size_t dataSize) noexcept {
+ ASMJIT_ASSERT(dataSize <= 8u);
+
+ _type = OffsetType::kCommon;
+ _flags = uint8_t(0);
+ _regionSize = uint8_t(dataSize);
+ _valueSize = uint8_t(dataSize);
+ _valueOffset = uint8_t(0);
+ _immBitCount = uint8_t(dataSize * 8u);
+ _immBitShift = uint8_t(0);
+ _immDiscardLsb = uint8_t(0);
+ }
+
+ inline void resetToImmValue(OffsetType type, size_t valueSize, uint32_t immBitShift, uint32_t immBitCount, uint32_t immDiscardLsb) noexcept {
+ ASMJIT_ASSERT(valueSize <= 8u);
+ ASMJIT_ASSERT(immBitShift < valueSize * 8u);
+ ASMJIT_ASSERT(immBitCount <= 64u);
+ ASMJIT_ASSERT(immDiscardLsb <= 64u);
+
+ _type = type;
+ _flags = uint8_t(0);
+ _regionSize = uint8_t(valueSize);
+ _valueSize = uint8_t(valueSize);
+ _valueOffset = uint8_t(0);
+ _immBitCount = uint8_t(immBitCount);
+ _immBitShift = uint8_t(immBitShift);
+ _immDiscardLsb = uint8_t(immDiscardLsb);
+ }
+
+ inline void setRegion(size_t regionSize, size_t valueOffset) noexcept {
+ _regionSize = uint8_t(regionSize);
+ _valueOffset = uint8_t(valueOffset);
+ }
+
+ inline void setLeadingAndTrailingSize(size_t leadingSize, size_t trailingSize) noexcept {
+ _regionSize = uint8_t(leadingSize + trailingSize + _valueSize);
+ _valueOffset = uint8_t(leadingSize);
+ }
+
+ //! \}
+};
+
+//! Relocation type.
+enum class RelocType : uint32_t {
+ //! None/deleted (no relocation).
+ kNone = 0,
+ //! Expression evaluation, `_payload` is pointer to `Expression`.
+ kExpression = 1,
+ //! Relocate absolute to absolute.
+ kAbsToAbs = 2,
+ //! Relocate relative to absolute.
+ kRelToAbs = 3,
+ //! Relocate absolute to relative.
+ kAbsToRel = 4,
+ //! Relocate absolute to relative or use trampoline.
+ kX64AddressEntry = 5
+};
+
+//! Relocation entry.
+struct RelocEntry {
+ //! \name Members
+ //! \{
+
+ //! Relocation id.
+ uint32_t _id;
+ //! Type of the relocation.
+ RelocType _relocType;
+ //! Format of the relocated value.
+ OffsetFormat _format;
+ //! Source section id.
+ uint32_t _sourceSectionId;
+ //! Target section id.
+ uint32_t _targetSectionId;
+ //! Source offset (relative to start of the section).
+ uint64_t _sourceOffset;
+ //! Payload (target offset, target address, expression, etc).
+ uint64_t _payload;
+
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
+ inline uint32_t id() const noexcept { return _id; }
+
+ inline RelocType relocType() const noexcept { return _relocType; }
+ inline const OffsetFormat& format() const noexcept { return _format; }
+
+ inline uint32_t sourceSectionId() const noexcept { return _sourceSectionId; }
+ inline uint32_t targetSectionId() const noexcept { return _targetSectionId; }
+
+ inline uint64_t sourceOffset() const noexcept { return _sourceOffset; }
+ inline uint64_t payload() const noexcept { return _payload; }
+
+ Expression* payloadAsExpression() const noexcept {
+ return reinterpret_cast(uintptr_t(_payload));
+ }
+
+ //! \}
+};
+
+//! Type of the \ref Label.
+enum class LabelType : uint8_t {
+ //! Anonymous label that can optionally have a name, which is only used for debugging purposes.
+ kAnonymous = 0,
+ //! Local label (always has parentId).
+ kLocal = 1,
+ //! Global label (never has parentId).
+ kGlobal = 2,
+ //! External label (references an external symbol).
+ kExternal = 3,
+
+ //! Maximum value of `LabelType`.
+ kMaxValue = kExternal
+};
+
+//! Data structure used to link either unbound labels or cross-section links.
+struct LabelLink {
+ //! Next link (single-linked list).
+ LabelLink* next;
+ //! Section id where the label is bound.
+ uint32_t sectionId;
+ //! Relocation id or Globals::kInvalidId.
+ uint32_t relocId;
+ //! Label offset relative to the start of the section.
+ size_t offset;
+ //! Inlined rel8/rel32.
+ intptr_t rel;
+ //! Offset format information.
+ OffsetFormat format;
+};
+
+//! Label entry.
+//!
+//! Contains the following properties:
+//! - Label id - This is the only thing that is set to the `Label` operand.
+//! - Label name - Optional, used mostly to create executables and libraries.
+//! - Label type - Type of the label, default `LabelType::kAnonymous`.
+//! - Label parent id - Derived from many assemblers that allow to define a local label that falls under a global
+//! label. This allows to define many labels of the same name that have different parent (global) label.
+//! - Offset - offset of the label bound by `Assembler`.
+//! - Links - single-linked list that contains locations of code that has to be patched when the label gets bound.
+//! Every use of unbound label adds one link to `_links` list.
+//! - HVal - Hash value of label's name and optionally parentId.
+//! - HashNext - Hash-table implementation detail.
+class LabelEntry : public ZoneHashNode {
+public:
+ //! \name Constants
+ //! \{
+
+ enum : uint32_t {
+ //! SSO size of \ref _name.
+ //!
+ //! \cond INTERNAL
+ //! Let's round the size of `LabelEntry` to 64 bytes (as `ZoneAllocator` has granularity of 32 bytes anyway). This
+ //! gives `_name` the remaining space, which is should be 16 bytes on 64-bit and 28 bytes on 32-bit architectures.
+ //! \endcond
+ kStaticNameSize = 64 - (sizeof(ZoneHashNode) + 8 + sizeof(Section*) + sizeof(size_t) + sizeof(LabelLink*))
+ };
+
+ //! \}
+
+ //! \name Members
+ //! \{
+
+ //! Type of the label.
+ LabelType _type;
+ //! Must be zero.
+ uint8_t _reserved[3];
+ //! Label parent id or zero.
+ uint32_t _parentId;
+ //! Label offset relative to the start of the `_section`.
+ uint64_t _offset;
+ //! Section where the label was bound.
+ Section* _section;
+ //! Label links.
+ LabelLink* _links;
+ //! Label name.
+ ZoneString _name;
+
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
+ // NOTE: Label id is stored in `_customData`, which is provided by ZoneHashNode to fill a padding that a C++
+ // compiler targeting 64-bit CPU will add to align the structure to 64-bits.
+
+ //! Returns label id.
+ inline uint32_t id() const noexcept { return _customData; }
+ //! Sets label id (internal, used only by `CodeHolder`).
+ inline void _setId(uint32_t id) noexcept { _customData = id; }
+
+ //! Returns label type.
+ inline LabelType type() const noexcept { return _type; }
+
+ //! Tests whether the label has a parent label.
+ inline bool hasParent() const noexcept { return _parentId != Globals::kInvalidId; }
+ //! Returns label's parent id.
+ inline uint32_t parentId() const noexcept { return _parentId; }
+
+ //! Returns the section where the label was bound.
+ //!
+ //! If the label was not yet bound the return value is `nullptr`.
+ inline Section* section() const noexcept { return _section; }
+
+ //! Tests whether the label has name.
+ inline bool hasName() const noexcept { return !_name.empty(); }
+
+ //! Returns the label's name.
+ //!
+ //! \note Local labels will return their local name without their parent part, for example ".L1".
+ inline const char* name() const noexcept { return _name.data(); }
+
+ //! Returns size of label's name.
+ //!
+ //! \note Label name is always null terminated, so you can use `strlen()` to get it, however, it's also cached in
+ //! `LabelEntry` itself, so if you want to know the size the fastest way is to call `LabelEntry::nameSize()`.
+ inline uint32_t nameSize() const noexcept { return _name.size(); }
+
+ //! Returns links associated with this label.
+ inline LabelLink* links() const noexcept { return _links; }
+
+ //! Tests whether the label is bound.
+ inline bool isBound() const noexcept { return _section != nullptr; }
+ //! Tests whether the label is bound to a the given `sectionId`.
+ inline bool isBoundTo(Section* section) const noexcept { return _section == section; }
+
+ //! Returns the label offset (only useful if the label is bound).
+ inline uint64_t offset() const noexcept { return _offset; }
+
+ //! Returns the hash-value of label's name and its parent label (if any).
+ //!
+ //! Label hash is calculated as `HASH(Name) ^ ParentId`. The hash function is implemented in `Support::hashString()`
+ //! and `Support::hashRound()`.
+ inline uint32_t hashCode() const noexcept { return _hashCode; }
+
+ //! \}
+};
+
+//! Holds assembled code and data (including sections, labels, and relocation information).
+//!
+//! CodeHolder connects emitters with their targets. It provides them interface that can be used to query information
+//! about the target environment (architecture, etc...) and API to create labels, sections, relocations, and to write
+//! data to a \ref CodeBuffer, which is always part of \ref Section. More than one emitter can be attached to a single
+//! CodeHolder instance at a time, which is used in practice
+//!
+//! CodeHolder provides interface for all emitter types. Assemblers use CodeHolder to write into \ref CodeBuffer, and
+//! higher level emitters like Builder and Compiler use CodeHolder to manage labels and sections so higher level code
+//! can be serialized to Assembler by \ref BaseEmitter::finalize() and \ref BaseBuilder::serializeTo().
+//!
+//! In order to use CodeHolder, it must be first initialized by \ref init(). After the CodeHolder has been successfully
+//! initialized it can be used to hold assembled code, sections, labels, relocations, and to attach / detach code
+//! emitters. After the end of code generation it can be used to query physical locations of labels and to relocate
+//! the assembled code into the right address.
+//!
+//! \note \ref CodeHolder has an ability to attach an \ref ErrorHandler, however, the error handler is not triggered
+//! by \ref CodeHolder itself, it's instead propagated to all emitters that attach to it.
class CodeHolder {
public:
ASMJIT_NONCOPYABLE(CodeHolder)
+ //! \name Members
+ //! \{
+
//! Environment information.
Environment _environment;
//! Base address or \ref Globals::kNoBaseAddress.
@@ -661,31 +670,22 @@ public:
//! Address table entries.
ZoneTree _addressTableEntries;
- //! Options that can be used with \ref copySectionData() and \ref copyFlattenedData().
- enum CopyOptions : uint32_t {
- //! If virtual size of a section is greater than the size of its \ref CodeBuffer
- //! then all bytes between the buffer size and virtual size will be zeroed.
- //! If this option is not set then those bytes would be left as is, which
- //! means that if the user didn't initialize them they would have a previous
- //! content, which may be unwanted.
- kCopyPadSectionBuffer = 0x00000001u,
-
-#ifndef ASMJIT_NO_DEPRECATED
- kCopyWithPadding = kCopyPadSectionBuffer,
-#endif // !ASMJIT_NO_DEPRECATED
-
- //! Zeroes the target buffer if the flattened data is less than the destination
- //! size. This option works only with \ref copyFlattenedData() as it processes
- //! multiple sections. It is ignored by \ref copySectionData().
- kCopyPadTargetBuffer = 0x00000002u
- };
+ //! \}
//! \name Construction & Destruction
//! \{
//! Creates an uninitialized CodeHolder (you must init() it before it can be used).
- ASMJIT_API CodeHolder() noexcept;
- //! Destroys the CodeHolder.
+ //!
+ //! An optional `temporary` argument can be used to initialize the first block of \ref Zone that the CodeHolder
+ //! uses into a temporary memory provided by the user.
+ ASMJIT_API explicit CodeHolder(const Support::Temporary* temporary = nullptr) noexcept;
+
+ //! \overload
+ inline explicit CodeHolder(const Support::Temporary& temporary) noexcept
+ : CodeHolder(&temporary) {}
+
+ //! Destroys the CodeHolder and frees all resources it has allocated.
ASMJIT_API ~CodeHolder() noexcept;
//! Tests whether the `CodeHolder` has been initialized.
@@ -693,10 +693,10 @@ public:
//! Emitters can be only attached to initialized `CodeHolder` instances.
inline bool isInitialized() const noexcept { return _environment.isInitialized(); }
- //! Initializes CodeHolder to hold code described by code `info`.
+ //! Initializes CodeHolder to hold code described by the given `environment` and `baseAddress`.
ASMJIT_API Error init(const Environment& environment, uint64_t baseAddress = Globals::kNoBaseAddress) noexcept;
//! Detaches all code-generators attached and resets the `CodeHolder`.
- ASMJIT_API void reset(uint32_t resetPolicy = Globals::kResetSoft) noexcept;
+ ASMJIT_API void reset(ResetPolicy resetPolicy = ResetPolicy::kSoft) noexcept;
//! \}
@@ -715,10 +715,9 @@ public:
//! Returns the allocator that the `CodeHolder` uses.
//!
- //! \note This should be only used for AsmJit's purposes. Code holder uses
- //! arena allocator to allocate everything, so anything allocated through
- //! this allocator will be invalidated by \ref CodeHolder::reset() or by
- //! CodeHolder's destructor.
+ //! \note This should be only used for AsmJit's purposes. Code holder uses arena allocator to allocate everything,
+ //! so anything allocated through this allocator will be invalidated by \ref CodeHolder::reset() or by CodeHolder's
+ //! destructor.
inline ZoneAllocator* allocator() const noexcept { return const_cast(&_allocator); }
//! \}
@@ -726,13 +725,13 @@ public:
//! \name Code & Architecture
//! \{
- //! Returns the target environment information, see \ref Environment.
+ //! Returns the target environment information.
inline const Environment& environment() const noexcept { return _environment; }
//! Returns the target architecture.
- inline uint32_t arch() const noexcept { return environment().arch(); }
+ inline Arch arch() const noexcept { return environment().arch(); }
//! Returns the target sub-architecture.
- inline uint32_t subArch() const noexcept { return environment().subArch(); }
+ inline SubArch subArch() const noexcept { return environment().subArch(); }
//! Tests whether a static base-address is set.
inline bool hasBaseAddress() const noexcept { return _baseAddress != Globals::kNoBaseAddress; }
@@ -752,7 +751,7 @@ public:
//! \name Logging
//! \{
- //! Returns the attached logger, see \ref Logger.
+ //! Returns the attached logger.
inline Logger* logger() const noexcept { return _logger; }
//! Attaches a `logger` to CodeHolder and propagates it to all attached emitters.
ASMJIT_API void setLogger(Logger* logger) noexcept;
@@ -778,14 +777,12 @@ public:
//! Makes sure that at least `n` bytes can be added to CodeHolder's buffer `cb`.
//!
- //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the
- //! behavior of the function is undefined.
+ //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
ASMJIT_API Error growBuffer(CodeBuffer* cb, size_t n) noexcept;
//! Reserves the size of `cb` to at least `n` bytes.
//!
- //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the
- //! behavior of the function is undefined.
+ //! \note The buffer `cb` must be managed by `CodeHolder` - otherwise the behavior of the function is undefined.
ASMJIT_API Error reserveBuffer(CodeBuffer* cb, size_t n) noexcept;
//! \}
@@ -806,7 +803,7 @@ public:
//! Creates a new section and return its pointer in `sectionOut`.
//!
//! Returns `Error`, does not report a possible error to `ErrorHandler`.
- ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, uint32_t flags = 0, uint32_t alignment = 1, int32_t order = 0) noexcept;
+ ASMJIT_API Error newSection(Section** sectionOut, const char* name, size_t nameSize = SIZE_MAX, SectionFlags flags = SectionFlags::kNone, uint32_t alignment = 1, int32_t order = 0) noexcept;
//! Returns a section entry of the given index.
inline Section* sectionById(uint32_t sectionId) const noexcept { return _sections[sectionId]; }
@@ -838,14 +835,12 @@ public:
//! Used to add an address to an address table.
//!
- //! This implicitly calls `ensureAddressTableSection()` and then creates
- //! `AddressTableEntry` that is inserted to `_addressTableEntries`. If the
- //! address already exists this operation does nothing as the same addresses
+ //! This implicitly calls `ensureAddressTableSection()` and then creates `AddressTableEntry` that is inserted
+ //! to `_addressTableEntries`. If the address already exists this operation does nothing as the same addresses
//! use the same slot.
//!
- //! This function should be considered internal as it's used by assemblers to
- //! insert an absolute address into the address table. Inserting address into
- //! address table without creating a particula relocation entry makes no sense.
+ //! This function should be considered internal as it's used by assemblers to insert an absolute address into the
+ //! address table. Inserting address into address table without creating a particula relocation entry makes no sense.
ASMJIT_API Error addAddressToAddressTable(uint64_t address) noexcept;
//! \}
@@ -893,8 +888,8 @@ public:
//! Returns offset of a `Label` by its `labelId`.
//!
- //! The offset returned is relative to the start of the section. Zero offset
- //! is returned for unbound labels, which is their initial offset value.
+ //! The offset returned is relative to the start of the section. Zero offset is returned for unbound labels,
+ //! which is their initial offset value.
inline uint64_t labelOffset(uint32_t labelId) const noexcept {
ASMJIT_ASSERT(isLabelValid(labelId));
return _labelEntries[labelId]->offset();
@@ -907,9 +902,8 @@ public:
//! Returns offset of a label by it's `labelId` relative to the base offset.
//!
- //! \remarks The offset of the section where the label is bound must be valid
- //! in order to use this function, otherwise the value returned will not be
- //! reliable.
+ //! \remarks The offset of the section where the label is bound must be valid in order to use this function,
+ //! otherwise the value returned will not be reliable.
inline uint64_t labelOffsetFromBase(uint32_t labelId) const noexcept {
ASMJIT_ASSERT(isLabelValid(labelId));
const LabelEntry* le = _labelEntries[labelId];
@@ -930,20 +924,18 @@ public:
//!
//! \param entryOut Where to store the created \ref LabelEntry.
//! \param name The name of the label.
- //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is
- //! a null terminated string, which means that the `CodeHolder` will
- //! use `strlen()` to determine the length.
- //! \param type The type of the label to create, see \ref Label::LabelType.
- //! \param parentId Parent id of a local label, otherwise it must be
- //! \ref Globals::kInvalidId.
+ //! \param nameSize The length of `name` argument, or `SIZE_MAX` if `name` is a null terminated string, which
+ //! means that the `CodeHolder` will use `strlen()` to determine the length.
+ //! \param type The type of the label to create, see \ref LabelType.
+ //! \param parentId Parent id of a local label, otherwise it must be \ref Globals::kInvalidId.
+ //! \retval Always returns \ref Error, does not report a possible error to the attached \ref ErrorHandler.
//!
- //! \retval Always returns \ref Error, does not report a possible error to
- //! the attached \ref ErrorHandler.
- //!
- //! AsmJit has a support for local labels (\ref Label::kTypeLocal) which
- //! require a parent label id (parentId). The names of local labels can
- //! conflict with names of other local labels that have a different parent.
- ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, uint32_t type, uint32_t parentId = Globals::kInvalidId) noexcept;
+ //! AsmJit has a support for local labels (\ref LabelType::kLocal) which require a parent label id (parentId).
+ //! The names of local labels can conflict with names of other local labels that have a different parent. In
+ //! addition, AsmJit supports named anonymous labels, which are useful only for debugging purposes as the
+ //! anonymous name will have a name, which will be formatted, but the label itself cannot be queried by such
+ //! name.
+ ASMJIT_API Error newNamedLabelEntry(LabelEntry** entryOut, const char* name, size_t nameSize, LabelType type, uint32_t parentId = Globals::kInvalidId) noexcept;
//! Returns a label by name.
//!
@@ -968,10 +960,9 @@ public:
//! Returns `null` if the allocation failed.
ASMJIT_API LabelLink* newLabelLink(LabelEntry* le, uint32_t sectionId, size_t offset, intptr_t rel, const OffsetFormat& format) noexcept;
- //! Resolves cross-section links (`LabelLink`) associated with each label that
- //! was used as a destination in code of a different section. It's only useful
- //! to people that use multiple sections as it will do nothing if the code only
- //! contains a single section in which cross-section links are not possible.
+ //! Resolves cross-section links (`LabelLink`) associated with each label that was used as a destination in code
+ //! of a different section. It's only useful to people that use multiple sections as it will do nothing if the code
+ //! only contains a single section in which cross-section links are not possible.
ASMJIT_API Error resolveUnresolvedLinks() noexcept;
//! Binds a label to a given `sectionId` and `offset` (relative to start of the section).
@@ -995,7 +986,7 @@ public:
//! Creates a new relocation entry of type `relocType`.
//!
//! Additional fields can be set after the relocation entry was created.
- ASMJIT_API Error newRelocEntry(RelocEntry** dst, uint32_t relocType) noexcept;
+ ASMJIT_API Error newRelocEntry(RelocEntry** dst, RelocType relocType) noexcept;
//! \}
@@ -1009,49 +1000,29 @@ public:
//! Returns computed the size of code & data of all sections.
//!
- //! \note All sections will be iterated over and the code size returned
- //! would represent the minimum code size of all combined sections after
- //! applying minimum alignment. Code size may decrease after calling
- //! `flatten()` and `relocateToBase()`.
+ //! \note All sections will be iterated over and the code size returned would represent the minimum code size of
+ //! all combined sections after applying minimum alignment. Code size may decrease after calling `flatten()` and
+ //! `relocateToBase()`.
ASMJIT_API size_t codeSize() const noexcept;
//! Relocates the code to the given `baseAddress`.
//!
- //! \param baseAddress Absolute base address where the code will be relocated
- //! to. Please note that nothing is copied to such base address, it's just an
- //! absolute value used by the relocator to resolve all stored relocations.
+ //! \param baseAddress Absolute base address where the code will be relocated to. Please note that nothing is
+ //! copied to such base address, it's just an absolute value used by the relocator to resolve all stored relocations.
//!
//! \note This should never be called more than once.
ASMJIT_API Error relocateToBase(uint64_t baseAddress) noexcept;
//! Copies a single section into `dst`.
- ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, uint32_t copyOptions = 0) noexcept;
+ ASMJIT_API Error copySectionData(void* dst, size_t dstSize, uint32_t sectionId, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
//! Copies all sections into `dst`.
//!
- //! This should only be used if the data was flattened and there are no gaps
- //! between the sections. The `dstSize` is always checked and the copy will
- //! never write anything outside the provided buffer.
- ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, uint32_t copyOptions = 0) noexcept;
+ //! This should only be used if the data was flattened and there are no gaps between the sections. The `dstSize`
+ //! is always checked and the copy will never write anything outside the provided buffer.
+ ASMJIT_API Error copyFlattenedData(void* dst, size_t dstSize, CopySectionFlags copyFlags = CopySectionFlags::kNone) noexcept;
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use 'CodeHolder::init(const Environment& environment, uint64_t baseAddress)' instead")
- inline Error init(const CodeInfo& codeInfo) noexcept { return init(codeInfo._environment, codeInfo._baseAddress); }
-
- ASMJIT_DEPRECATED("Use nevironment() instead")
- inline CodeInfo codeInfo() const noexcept { return CodeInfo(_environment, _baseAddress); }
-
- ASMJIT_DEPRECATED("Use BaseEmitter::encodingOptions() - this function always returns zero")
- inline uint32_t emitterOptions() const noexcept { return 0; }
-
- ASMJIT_DEPRECATED("Use BaseEmitter::addEncodingOptions() - this function does nothing")
- inline void addEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); }
-
- ASMJIT_DEPRECATED("Use BaseEmitter::clearEncodingOptions() - this function does nothing")
- inline void clearEmitterOptions(uint32_t options) noexcept { DebugUtils::unused(options); }
-#endif // !ASMJIT_NO_DEPRECATED
};
//! \}
diff --git a/src/asmjit/core/codewriter.cpp b/src/asmjit/core/codewriter.cpp
index 6097c0e..772146e 100644
--- a/src/asmjit/core/codewriter.cpp
+++ b/src/asmjit/core/codewriter.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/codeholder.h"
@@ -50,13 +32,13 @@ bool CodeWriterUtils::encodeOffset32(uint32_t* dst, int64_t offset64, const Offs
return false;
switch (format.type()) {
- case OffsetFormat::kTypeCommon: {
+ case OffsetType::kCommon: {
*dst = (uint32_t(offset32) & Support::lsbMask(bitCount)) << bitShift;
return true;
}
- case OffsetFormat::kTypeAArch64_ADR:
- case OffsetFormat::kTypeAArch64_ADRP: {
+ case OffsetType::kAArch64_ADR:
+ case OffsetType::kAArch64_ADRP: {
// Sanity checks.
if (format.valueSize() != 4 || bitCount != 21 || bitShift != 5)
return false;
@@ -91,7 +73,7 @@ bool CodeWriterUtils::encodeOffset64(uint64_t* dst, int64_t offset64, const Offs
return false;
switch (format.type()) {
- case OffsetFormat::kTypeCommon: {
+ case OffsetType::kCommon: {
*dst = (uint64_t(offset64) & Support::lsbMask(bitCount)) << format.immBitShift();
return true;
}
diff --git a/src/asmjit/core/codewriter_p.h b/src/asmjit/core/codewriter_p.h
index 61c9101..8b120bd 100644
--- a/src/asmjit/core/codewriter_p.h
+++ b/src/asmjit/core/codewriter_p.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
#define ASMJIT_CORE_CODEBUFFERWRITER_P_H_INCLUDED
@@ -34,25 +16,17 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_assembler
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
struct OffsetFormat;
-// ============================================================================
-// [asmjit::CodeWriter]
-// ============================================================================
-
//! Helper that is used to write into a \ref CodeBuffer held by \ref BaseAssembler.
class CodeWriter {
public:
uint8_t* _cursor;
- ASMJIT_INLINE explicit CodeWriter(BaseAssembler* a) noexcept
+ ASMJIT_FORCE_INLINE explicit CodeWriter(BaseAssembler* a) noexcept
: _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);
if (ASMJIT_UNLIKELY(remainingSpace < n)) {
CodeBuffer& buffer = a->_section->_buffer;
@@ -64,24 +38,24 @@ public:
return kErrorOk;
}
- ASMJIT_INLINE uint8_t* cursor() const noexcept { return _cursor; }
- ASMJIT_INLINE void setCursor(uint8_t* cursor) noexcept { _cursor = cursor; }
- ASMJIT_INLINE void advance(size_t n) noexcept { _cursor += n; }
+ ASMJIT_FORCE_INLINE uint8_t* cursor() const noexcept { return _cursor; }
+ ASMJIT_FORCE_INLINE void setCursor(uint8_t* cursor) noexcept { _cursor = cursor; }
+ 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);
return (size_t)(_cursor - from);
}
template
- ASMJIT_INLINE void emit8(T val) noexcept {
+ ASMJIT_FORCE_INLINE void emit8(T val) noexcept {
typedef typename std::make_unsigned::type U;
_cursor[0] = uint8_t(U(val) & U(0xFF));
_cursor++;
}
template
- ASMJIT_INLINE void emit8If(T val, Y cond) noexcept {
+ ASMJIT_FORCE_INLINE void emit8If(T val, Y cond) noexcept {
typedef typename std::make_unsigned::type U;
ASMJIT_ASSERT(size_t(cond) <= 1u);
@@ -90,41 +64,41 @@ public:
}
template
- ASMJIT_INLINE void emit16uLE(T val) noexcept {
+ ASMJIT_FORCE_INLINE void emit16uLE(T val) noexcept {
typedef typename std::make_unsigned::type U;
Support::writeU16uLE(_cursor, uint32_t(U(val) & 0xFFFFu));
_cursor += 2;
}
template
- ASMJIT_INLINE void emit16uBE(T val) noexcept {
+ ASMJIT_FORCE_INLINE void emit16uBE(T val) noexcept {
typedef typename std::make_unsigned::type U;
Support::writeU16uBE(_cursor, uint32_t(U(val) & 0xFFFFu));
_cursor += 2;
}
template
- ASMJIT_INLINE void emit32uLE(T val) noexcept {
+ ASMJIT_FORCE_INLINE void emit32uLE(T val) noexcept {
typedef typename std::make_unsigned::type U;
Support::writeU32uLE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
_cursor += 4;
}
template
- ASMJIT_INLINE void emit32uBE(T val) noexcept {
+ ASMJIT_FORCE_INLINE void emit32uBE(T val) noexcept {
typedef typename std::make_unsigned::type U;
Support::writeU32uBE(_cursor, uint32_t(U(val) & 0xFFFFFFFFu));
_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);
memcpy(_cursor, data, size);
_cursor += size;
}
template
- 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::type U;
ASMJIT_ASSERT(size <= sizeof(T));
@@ -137,7 +111,7 @@ public:
}
template
- 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::type U;
ASMJIT_ASSERT(size <= sizeof(T));
@@ -149,13 +123,13 @@ public:
_cursor += size;
}
- ASMJIT_INLINE void emitZeros(size_t size) noexcept {
+ ASMJIT_FORCE_INLINE void emitZeros(size_t size) noexcept {
ASMJIT_ASSERT(size != 0);
memset(_cursor, 0, size);
_cursor += size;
}
- ASMJIT_INLINE void remove8(uint8_t* where) noexcept {
+ ASMJIT_FORCE_INLINE void remove8(uint8_t* where) noexcept {
ASMJIT_ASSERT(where < _cursor);
uint8_t* p = where;
@@ -165,7 +139,7 @@ public:
}
template
- 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;
while (p != where) {
@@ -177,7 +151,7 @@ public:
_cursor++;
}
- ASMJIT_INLINE void done(BaseAssembler* a) noexcept {
+ ASMJIT_FORCE_INLINE void done(BaseAssembler* a) noexcept {
CodeBuffer& buffer = a->_section->_buffer;
size_t newSize = (size_t)(_cursor - a->_bufferData);
ASMJIT_ASSERT(newSize <= buffer.capacity());
@@ -187,10 +161,7 @@ public:
}
};
-// ============================================================================
-// [asmjit::CodeWriterUtils]
-// ============================================================================
-
+//! Code writer utilities.
namespace CodeWriterUtils {
bool encodeOffset32(uint32_t* dst, int64_t offset64, const OffsetFormat& format) noexcept;
diff --git a/src/asmjit/core/compiler.cpp b/src/asmjit/core/compiler.cpp
index 6bd889f..bfa84f3 100644
--- a/src/asmjit/core/compiler.cpp
+++ b/src/asmjit/core/compiler.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#ifndef ASMJIT_NO_COMPILER
@@ -35,11 +17,11 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::GlobalConstPoolPass]
-// ============================================================================
+// GlobalConstPoolPass
+// ===================
class GlobalConstPoolPass : public Pass {
+public:
typedef Pass Base;
public:
ASMJIT_NONCOPYABLE(GlobalConstPoolPass)
@@ -51,53 +33,50 @@ public:
// Flush the global constant pool.
BaseCompiler* compiler = static_cast(_cb);
- if (compiler->_globalConstPool) {
- compiler->addAfter(compiler->_globalConstPool, compiler->lastNode());
- compiler->_globalConstPool = nullptr;
+ ConstPoolNode* globalConstPool = compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)];
+
+ if (globalConstPool) {
+ compiler->addAfter(globalConstPool, compiler->lastNode());
+ compiler->_constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
}
return kErrorOk;
}
};
-// ============================================================================
-// [asmjit::BaseCompiler - Construction / Destruction]
-// ============================================================================
+// BaseCompiler - Construction & Destruction
+// =========================================
BaseCompiler::BaseCompiler() noexcept
: BaseBuilder(),
_func(nullptr),
_vRegZone(4096 - Zone::kBlockOverhead),
_vRegArray(),
- _localConstPool(nullptr),
- _globalConstPool(nullptr) {
-
- _emitterType = uint8_t(kTypeCompiler);
- _validationFlags = uint8_t(InstAPI::kValidationFlagVirtRegs);
+ _constPools { nullptr, nullptr } {
+ _emitterType = EmitterType::kCompiler;
+ _validationFlags = ValidationFlags::kEnableVirtRegs;
}
BaseCompiler::~BaseCompiler() noexcept {}
-// ============================================================================
-// [asmjit::BaseCompiler - Function Management]
-// ============================================================================
+// BaseCompiler - Function Management
+// ==================================
-Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature) {
+Error BaseCompiler::newFuncNode(FuncNode** out, const FuncSignature& signature) {
*out = nullptr;
// Create FuncNode together with all the required surrounding nodes.
FuncNode* funcNode;
ASMJIT_PROPAGATE(_newNodeT(&funcNode));
- ASMJIT_PROPAGATE(_newLabelNode(&funcNode->_exitNode));
- ASMJIT_PROPAGATE(_newNodeT(&funcNode->_end, SentinelNode::kSentinelFuncEnd));
+ ASMJIT_PROPAGATE(newLabelNode(&funcNode->_exitNode));
+ ASMJIT_PROPAGATE(_newNodeT(&funcNode->_end, SentinelType::kFuncEnd));
// Initialize the function's detail info.
Error err = funcNode->detail().init(signature, environment());
if (ASMJIT_UNLIKELY(err))
return reportError(err);
- // If the Target guarantees greater stack alignment than required by the
- // calling convention then override it as we can prevent having to perform
- // dynamic stack alignment
+ // If the Target guarantees greater stack alignment than required by the calling convention
+ // then override it as we can prevent having to perform dynamic stack alignment
uint32_t environmentStackAlignment = _environment.stackAlignment();
if (funcNode->_funcDetail._callConv.naturalStackAlignment() < environmentStackAlignment)
@@ -123,13 +102,13 @@ Error BaseCompiler::_newFuncNode(FuncNode** out, const FuncSignature& signature)
return kErrorOk;
}
-Error BaseCompiler::_addFuncNode(FuncNode** out, const FuncSignature& signature) {
- ASMJIT_PROPAGATE(_newFuncNode(out, signature));
+Error BaseCompiler::addFuncNode(FuncNode** out, const FuncSignature& signature) {
+ ASMJIT_PROPAGATE(newFuncNode(out, signature));
addFunc(*out);
return kErrorOk;
}
-Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
+Error BaseCompiler::newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
uint32_t opCount = !o1.isNone() ? 2u : !o0.isNone() ? 1u : 0u;
FuncRetNode* node;
@@ -143,8 +122,8 @@ Error BaseCompiler::_newRetNode(FuncRetNode** out, const Operand_& o0, const Ope
return kErrorOk;
}
-Error BaseCompiler::_addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
- ASMJIT_PROPAGATE(_newRetNode(out, o0, o1));
+Error BaseCompiler::addFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1) {
+ ASMJIT_PROPAGATE(newFuncRetNode(out, o0, o1));
addNode(*out);
return kErrorOk;
}
@@ -169,10 +148,11 @@ Error BaseCompiler::endFunc() {
return reportError(DebugUtils::errored(kErrorInvalidState));
// 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());
- addNode(_localConstPool);
- _localConstPool = nullptr;
+ addNode(localConstPool);
+ _constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
}
// Mark as finished.
@@ -184,28 +164,12 @@ Error BaseCompiler::endFunc() {
return kErrorOk;
}
-Error BaseCompiler::_setArg(size_t argIndex, size_t valueIndex, const BaseReg& r) {
- FuncNode* func = _func;
+// BaseCompiler - Function Invocation
+// ==================================
- if (ASMJIT_UNLIKELY(!func))
- 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) {
+Error BaseCompiler::newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
InvokeNode* node;
- ASMJIT_PROPAGATE(_newNodeT(&node, instId, 0u));
+ ASMJIT_PROPAGATE(_newNodeT(&node, instId, InstOptions::kNone));
node->setOpCount(1);
node->setOp(0, o0);
@@ -228,15 +192,14 @@ Error BaseCompiler::_newInvokeNode(InvokeNode** out, uint32_t instId, const Oper
return kErrorOk;
}
-Error BaseCompiler::_addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
- ASMJIT_PROPAGATE(_newInvokeNode(out, instId, o0, signature));
+Error BaseCompiler::addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature) {
+ ASMJIT_PROPAGATE(newInvokeNode(out, instId, o0, signature));
addNode(*out);
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseCompiler - Virtual Registers]
-// ============================================================================
+// BaseCompiler - Virtual Registers
+// ================================
static void BaseCompiler_assignGenericName(BaseCompiler* self, VirtReg* vReg) {
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));
}
-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;
uint32_t index = _vRegArray.size();
@@ -262,10 +225,10 @@ Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signatur
if (ASMJIT_UNLIKELY(!vReg))
return reportError(DebugUtils::errored(kErrorOutOfMemory));
- uint32_t size = Type::sizeOf(typeId);
+ uint32_t size = TypeUtils::sizeOf(typeId);
uint32_t alignment = Support::min(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
if (name && name[0] != '\0')
@@ -282,22 +245,22 @@ Error BaseCompiler::newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signatur
return kErrorOk;
}
-Error BaseCompiler::_newReg(BaseReg* out, uint32_t typeId, const char* name) {
- RegInfo regInfo;
+Error BaseCompiler::_newReg(BaseReg* out, TypeId typeId, const char* name) {
+ OperandSignature regSignature;
out->reset();
- Error err = ArchUtils::typeIdToRegInfo(arch(), typeId, &typeId, ®Info);
+ Error err = ArchUtils::typeIdToRegSignature(arch(), typeId, &typeId, ®Signature);
if (ASMJIT_UNLIKELY(err))
return reportError(err);
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;
}
-Error BaseCompiler::_newRegFmt(BaseReg* out, uint32_t typeId, const char* fmt, ...) {
+Error BaseCompiler::_newRegFmt(BaseReg* out, TypeId typeId, const char* fmt, ...) {
va_list ap;
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) {
out->reset();
- RegInfo regInfo;
- uint32_t typeId;
+ OperandSignature regSignature;
+ TypeId typeId;
if (isVirtRegValid(ref)) {
VirtReg* vRef = virtRegByReg(ref);
typeId = vRef->typeId();
- // NOTE: It's possible to cast one register type to another if it's the
- // same register group. However, VirtReg always contains the TypeId that
- // was used to create the register. This means that in some cases we may
- // end up having different size of `ref` and `vRef`. In such case we
- // adjust the TypeId to match the `ref` register type instead of the
- // original register type, which should be the expected behavior.
- uint32_t typeSize = Type::sizeOf(typeId);
+ // NOTE: It's possible to cast one register type to another if it's the same register group. However, VirtReg
+ // always contains the TypeId that was used to create the register. This means that in some cases we may end
+ // up having different size of `ref` and `vRef`. In such case we adjust the TypeId to match the `ref` register
+ // type instead of the original register type, which should be the expected behavior.
+ uint32_t typeSize = TypeUtils::sizeOf(typeId);
uint32_t refSize = ref.size();
if (typeSize != refSize) {
- if (Type::isInt(typeId)) {
+ if (TypeUtils::isInt(typeId)) {
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
switch (refSize) {
- case 1: typeId = Type::kIdI8 | (typeId & 1); break;
- case 2: typeId = Type::kIdI16 | (typeId & 1); break;
- case 4: typeId = Type::kIdI32 | (typeId & 1); break;
- case 8: typeId = Type::kIdI64 | (typeId & 1); break;
- default: typeId = Type::kIdVoid; break;
+ case 1: typeId = TypeId(uint32_t(TypeId::kInt8 ) | (uint32_t(typeId) & 1)); break;
+ case 2: typeId = TypeId(uint32_t(TypeId::kInt16) | (uint32_t(typeId) & 1)); break;
+ case 4: typeId = TypeId(uint32_t(TypeId::kInt32) | (uint32_t(typeId) & 1)); break;
+ case 8: typeId = TypeId(uint32_t(TypeId::kInt64) | (uint32_t(typeId) & 1)); break;
+ default: typeId = TypeId::kVoid; break;
}
}
- else if (Type::isMmx(typeId)) {
+ else if (TypeUtils::isMmx(typeId)) {
// 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.
switch (refSize) {
- case 1: typeId = Type::kIdMask8; break;
- case 2: typeId = Type::kIdMask16; break;
- case 4: typeId = Type::kIdMask32; break;
- case 8: typeId = Type::kIdMask64; break;
- default: typeId = Type::kIdVoid; break;
+ case 1: typeId = TypeId::kMask8; break;
+ case 2: typeId = TypeId::kMask16; break;
+ case 4: typeId = TypeId::kMask32; break;
+ case 8: typeId = TypeId::kMask64; break;
+ default: typeId = TypeId::kVoid; break;
}
}
else {
- // VEC register - change TypeId to match `ref` size, keep vector metadata.
- uint32_t elementTypeId = Type::baseOf(typeId);
-
+ // Vector register - change TypeId to match `ref` size, keep vector metadata.
+ TypeId scalarTypeId = TypeUtils::scalarOf(typeId);
switch (refSize) {
- case 16: typeId = Type::_kIdVec128Start + (elementTypeId - Type::kIdI8); break;
- case 32: typeId = Type::_kIdVec256Start + (elementTypeId - Type::kIdI8); break;
- case 64: typeId = Type::_kIdVec512Start + (elementTypeId - Type::kIdI8); break;
- default: typeId = Type::kIdVoid; break;
+ case 16: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec128Start); break;
+ case 32: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec256Start); break;
+ case 64: typeId = TypeUtils::scalarToVector(scalarTypeId, TypeId::_kVec512Start); break;
+ default: typeId = TypeId::kVoid; break;
}
}
- if (typeId == Type::kIdVoid)
+ if (typeId == TypeId::kVoid)
return reportError(DebugUtils::errored(kErrorInvalidState));
}
}
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))
return reportError(err);
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;
}
@@ -410,14 +370,17 @@ Error BaseCompiler::_newStack(BaseMem* out, uint32_t size, uint32_t alignment, c
alignment = 64;
VirtReg* vReg;
- ASMJIT_PROPAGATE(newVirtReg(&vReg, 0, 0, name));
+ ASMJIT_PROPAGATE(newVirtReg(&vReg, TypeId::kVoid, OperandSignature(0), name));
vReg->_virtSize = size;
vReg->_isStack = true;
vReg->_alignment = uint8_t(alignment);
// Set the memory operand to GPD/GPQ and its id to VirtReg.
- *out = BaseMem(BaseMem::Decomposed { _gpRegInfo.type(), vReg->id(), BaseReg::kTypeNone, 0, 0, 0, BaseMem::kSignatureMemRegHomeFlag });
+ *out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
+ OperandSignature::fromMemBaseType(_gpSignature.regType()) |
+ OperandSignature::fromBits(OperandSignature::kMemRegHomeFlag),
+ vReg->id(), 0, 0);
return kErrorOk;
}
@@ -438,9 +401,8 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new
if (newAlignment)
vReg->_alignment = uint8_t(newAlignment);
- // This is required if the RAPass is already running. There is a chance that
- // a stack-slot has been already allocated and in that case it has to be
- // updated as well, otherwise we would allocate wrong amount of memory.
+ // This is required if the RAPass is already running. There is a chance that a stack-slot has been already
+ // allocated and in that case it has to be updated as well, otherwise we would allocate wrong amount of memory.
RAWorkReg* workReg = vReg->_workReg;
if (workReg && workReg->_stackSlot) {
workReg->_stackSlot->_size = vReg->_virtSize;
@@ -450,37 +412,26 @@ Error BaseCompiler::setStackSize(uint32_t virtId, uint32_t newSize, uint32_t new
return kErrorOk;
}
-Error BaseCompiler::_newConst(BaseMem* out, uint32_t scope, const void* data, size_t size) {
+Error BaseCompiler::_newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size) {
out->reset();
- ConstPoolNode** pPool;
- if (scope == ConstPool::kScopeLocal)
- pPool = &_localConstPool;
- else if (scope == ConstPool::kScopeGlobal)
- pPool = &_globalConstPool;
- else
+ if (uint32_t(scope) > 1)
return reportError(DebugUtils::errored(kErrorInvalidArgument));
- if (!*pPool)
- ASMJIT_PROPAGATE(_newConstPoolNode(pPool));
+ if (!_constPools[uint32_t(scope)])
+ ASMJIT_PROPAGATE(newConstPoolNode(&_constPools[uint32_t(scope)]));
- ConstPoolNode* pool = *pPool;
+ ConstPoolNode* pool = _constPools[uint32_t(scope)];
size_t off;
Error err = pool->add(data, size, off);
if (ASMJIT_UNLIKELY(err))
return reportError(err);
- *out = BaseMem(BaseMem::Decomposed {
- Label::kLabelTag, // Base type.
- pool->labelId(), // Base id.
- 0, // Index type.
- 0, // Index id.
- int32_t(off), // Offset.
- uint32_t(size), // Size.
- 0 // Flags.
- });
-
+ *out = BaseMem(OperandSignature::fromOpType(OperandType::kMem) |
+ OperandSignature::fromMemBaseType(RegType::kLabelTag) |
+ OperandSignature::fromSize(uint32_t(size)),
+ pool->labelId(), 0, int32_t(off));
return kErrorOk;
}
@@ -505,11 +456,10 @@ void BaseCompiler::rename(const BaseReg& reg, const char* fmt, ...) {
}
}
-// ============================================================================
-// [asmjit::BaseCompiler - Jump Annotations]
-// ============================================================================
+// 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();
uint32_t opCount = 1;
@@ -524,8 +474,8 @@ Error BaseCompiler::newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOp
return kErrorOk;
}
-Error BaseCompiler::emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation) {
- uint32_t options = instOptions() | forcedInstOptions();
+Error BaseCompiler::emitAnnotatedJump(InstId instId, const Operand_& o0, JumpAnnotation* annotation) {
+ InstOptions options = instOptions() | forcedInstOptions();
RegOnly extra = extraReg();
const char* comment = inlineComment();
@@ -562,16 +512,15 @@ JumpAnnotation* BaseCompiler::newJumpAnnotation() {
return jumpAnnotation;
}
-// ============================================================================
-// [asmjit::BaseCompiler - Events]
-// ============================================================================
+// BaseCompiler - Events
+// =====================
Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
ASMJIT_PROPAGATE(Base::onAttach(code));
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
- uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
- _gpRegInfo.setSignature(archTraits.regTypeToSignature(nativeRegType));
+ RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
+ _gpSignature = archTraits.regTypeToSignature(nativeRegType);
Error err = addPassT();
if (ASMJIT_UNLIKELY(err)) {
@@ -584,8 +533,8 @@ Error BaseCompiler::onAttach(CodeHolder* code) noexcept {
Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
_func = nullptr;
- _localConstPool = nullptr;
- _globalConstPool = nullptr;
+ _constPools[uint32_t(ConstPoolScope::kLocal)] = nullptr;
+ _constPools[uint32_t(ConstPoolScope::kGlobal)] = nullptr;
_vRegArray.reset();
_vRegZone.reset();
@@ -593,32 +542,30 @@ Error BaseCompiler::onDetach(CodeHolder* code) noexcept {
return Base::onDetach(code);
}
-// ============================================================================
-// [asmjit::FuncPass - Construction / Destruction]
-// ============================================================================
+// FuncPass - Construction & Destruction
+// =====================================
FuncPass::FuncPass(const char* name) noexcept
: Pass(name) {}
-// ============================================================================
-// [asmjit::FuncPass - Run]
-// ============================================================================
+// FuncPass - Run
+// ==============
Error FuncPass::run(Zone* zone, Logger* logger) {
BaseNode* node = cb()->firstNode();
if (!node) return kErrorOk;
do {
- if (node->type() == BaseNode::kNodeFunc) {
+ if (node->type() == NodeType::kFunc) {
FuncNode* func = node->as();
node = func->endNode();
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 {
node = node->next();
- } while (node && node->type() != BaseNode::kNodeFunc);
+ } while (node && node->type() != NodeType::kFunc);
} while (node);
return kErrorOk;
diff --git a/src/asmjit/core/compiler.h b/src/asmjit/core/compiler.h
index 4c4cd33..1331e62 100644
--- a/src/asmjit/core/compiler.h
+++ b/src/asmjit/core/compiler.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_COMPILER_H_INCLUDED
#define ASMJIT_CORE_COMPILER_H_INCLUDED
@@ -40,10 +22,6 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class JumpAnnotation;
class JumpNode;
class FuncNode;
@@ -53,25 +31,18 @@ class InvokeNode;
//! \addtogroup asmjit_compiler
//! \{
-// ============================================================================
-// [asmjit::BaseCompiler]
-// ============================================================================
-
//! Code emitter that uses virtual registers and performs register allocation.
//!
-//! Compiler is a high-level code-generation tool that provides register
-//! allocation and automatic handling of function calling conventions. It was
-//! primarily designed for merging multiple parts of code into a function
-//! without worrying about registers and function calling conventions.
+//! Compiler is a high-level code-generation tool that provides register allocation and automatic handling of function
+//! calling conventions. It was primarily designed for merging multiple parts of code into a function without worrying
+//! about registers and function calling conventions.
//!
-//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and
-//! 64-bit code generation within a single code base.
+//! BaseCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit code generation within a single code
+//! base.
//!
-//! BaseCompiler is based on BaseBuilder and contains all the features it
-//! provides. It means that the code it stores can be modified (removed, added,
-//! injected) and analyzed. When the code is finalized the compiler can emit
-//! the code into an Assembler to translate the abstract representation into a
-//! machine code.
+//! BaseCompiler is based on BaseBuilder and contains all the features it provides. It means that the code it stores
+//! can be modified (removed, added, injected) and analyzed. When the code is finalized the compiler can emit the code
+//! into an Assembler to translate the abstract representation into a machine code.
//!
//! Check out architecture specific compilers for more details and examples:
//!
@@ -81,6 +52,9 @@ public:
ASMJIT_NONCOPYABLE(BaseCompiler)
typedef BaseBuilder Base;
+ //! \name Members
+ //! \{
+
//! Current function.
FuncNode* _func;
//! Allocates `VirtReg` objects.
@@ -90,10 +64,12 @@ public:
//! Stores jump annotations.
ZoneVector _jumpAnnotations;
- //! Local constant pool, flushed at the end of each function.
- ConstPoolNode* _localConstPool;
- //! Global constant pool, flushed by `finalize()`.
- ConstPoolNode* _globalConstPool;
+ //! Local and global constant pools.
+ //!
+ //! Local constant pool is flushed with each function, global constant pool is flushed only by \ref finalize().
+ ConstPoolNode* _constPools[2];
+
+ //! \}
//! \name Construction & Destruction
//! \{
@@ -108,31 +84,31 @@ public:
//! \name Function Management
//! \{
- //! Returns the current function.
- inline FuncNode* func() const noexcept { return _func; }
-
//! Creates a new \ref FuncNode.
- ASMJIT_API Error _newFuncNode(FuncNode** out, const FuncSignature& signature);
- //! Creates a new \ref FuncNode adds it to the compiler.
- ASMJIT_API Error _addFuncNode(FuncNode** out, const FuncSignature& signature);
+ ASMJIT_API Error newFuncNode(FuncNode** out, const FuncSignature& signature);
+ //! Creates a new \ref FuncNode adds it to the instruction stream.
+ ASMJIT_API Error addFuncNode(FuncNode** out, const FuncSignature& signature);
//! Creates a new \ref FuncRetNode.
- ASMJIT_API Error _newRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
- //! Creates a new \ref FuncRetNode and adds it to the compiler.
- ASMJIT_API Error _addRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
+ ASMJIT_API Error newFuncRetNode(FuncRetNode** out, const Operand_& o0, const Operand_& o1);
+ //! Creates a new \ref FuncRetNode and adds it to the instruction stream.
+ 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.
inline FuncNode* newFunc(const FuncSignature& signature) {
FuncNode* node;
- _newFuncNode(&node, signature);
+ newFuncNode(&node, signature);
return node;
}
- //! Creates a new \ref FuncNode with the given `signature`, adds it to the
- //! compiler by using the \ref addFunc(FuncNode*) overload, and returns it.
+ //! Creates a new \ref FuncNode with the given `signature`, adds it to the instruction stream by using
+ //! the \ref addFunc(FuncNode*) overload, and returns it.
inline FuncNode* addFunc(const FuncSignature& signature) {
FuncNode* node;
- _addFuncNode(&node, signature);
+ addFuncNode(&node, signature);
return node;
}
@@ -141,23 +117,21 @@ public:
//! Emits a sentinel that marks the end of the current function.
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`.
+ 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); }
+
//! 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); }
+#endif
- inline FuncRetNode* newRet(const Operand_& o0, const Operand_& o1) {
+ inline Error addRet(const Operand_& o0, const Operand_& o1) {
FuncRetNode* node;
- _newRetNode(&node, o0, o1);
- return node;
- }
-
- inline FuncRetNode* addRet(const Operand_& o0, const Operand_& o1) {
- FuncRetNode* node;
- _addRetNode(&node, o0, o1);
- return node;
+ return addFuncRetNode(&node, o0, o1);
}
//! \}
@@ -166,23 +140,9 @@ public:
//! \{
//! Creates a new \ref InvokeNode.
- ASMJIT_API Error _newInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
- //! Creates a new \ref InvokeNode and adds it to Compiler.
- ASMJIT_API Error _addInvokeNode(InvokeNode** out, uint32_t instId, const Operand_& o0, const FuncSignature& signature);
-
- //! Creates a new `InvokeNode`.
- inline InvokeNode* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
- InvokeNode* node;
- _newInvokeNode(&node, instId, o0, signature);
- return node;
- }
-
- //! Adds a new `InvokeNode`.
- inline InvokeNode* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& signature) {
- InvokeNode* node;
- _addInvokeNode(&node, instId, o0, signature);
- return node;
- }
+ ASMJIT_API Error newInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature);
+ //! Creates a new \ref InvokeNode and adds it to the instruction stream.
+ ASMJIT_API Error addInvokeNode(InvokeNode** out, InstId instId, const Operand_& o0, const FuncSignature& signature);
//! \}
@@ -191,18 +151,17 @@ public:
//! 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
- //! by AsmJit users, use architecture-specific `newReg()` functionality instead
- //! or functions like \ref _newReg() and \ref _newRegFmt().
- ASMJIT_API Error newVirtReg(VirtReg** out, uint32_t typeId, uint32_t signature, const char* name);
+ //! \note This function is public, but it's not generally recommended to be used by AsmJit users, use architecture
+ //! specific `newReg()` functionality instead or functions like \ref _newReg() and \ref _newRegFmt().
+ ASMJIT_API Error newVirtReg(VirtReg** out, TypeId typeId, OperandSignature signature, const char* name);
//! 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.
//!
//! \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`.
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`.
//!
- //! \note This is not the same as virtual register id. The conversion between
- //! id and its index is implemented by \ref Operand_::virtIdToIndex() and \ref
- //! Operand_::indexToVirtId() functions.
+ //! \note This is not the same as virtual register id. The conversion between id and its index is implemented
+ //! by \ref Operand_::virtIdToIndex() and \ref Operand_::indexToVirtId() functions.
inline VirtReg* virtRegByIndex(uint32_t index) const noexcept { return _vRegArray[index]; }
//! Returns an array of all virtual registers managed by the Compiler.
@@ -262,11 +220,11 @@ public:
//! \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
- //! ConstPool and stores the reference to that constant to the `out` operand.
- ASMJIT_API Error _newConst(BaseMem* out, uint32_t scope, const void* data, size_t size);
+ //! This function adds a constant of the given `size` to the built-in \ref ConstPool and stores the reference to that
+ //! constant to the `out` operand.
+ ASMJIT_API Error _newConst(BaseMem* out, ConstPoolScope scope, const void* data, size_t size);
//! \}
@@ -285,23 +243,15 @@ public:
return _jumpAnnotations;
}
- ASMJIT_API Error newJumpNode(JumpNode** out, uint32_t instId, uint32_t instOptions, const Operand_& o0, JumpAnnotation* annotation);
- ASMJIT_API Error emitAnnotatedJump(uint32_t instId, const Operand_& o0, JumpAnnotation* annotation);
+ ASMJIT_API Error newJumpNode(JumpNode** out, InstId instId, InstOptions instOptions, 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
- //! possible targets of a jump where the target is not a label, for example
- //! to implement jump tables.
+ //! Returns a new `JumpAnnotation` instance, which can be used to aggregate possible targets of a jump where the
+ //! target is not a label, for example to implement jump tables.
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
//! \{
@@ -311,22 +261,19 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::JumpAnnotation]
-// ============================================================================
-
//! Jump annotation used to annotate jumps.
//!
-//! \ref BaseCompiler allows to emit jumps where the target is either register
-//! or memory operand. Such jumps cannot be trivially inspected, so instead of
-//! doing heuristics AsmJit allows to annotate such jumps with possible targets.
-//! Register allocator then use the annotation to construct control-flow, which
-//! is then used by liveness analysis and other tools to prepare ground for
-//! register allocation.
+//! \ref BaseCompiler allows to emit jumps where the target is either register or memory operand. Such jumps cannot be
+//! trivially inspected, so instead of doing heuristics AsmJit allows to annotate such jumps with possible targets.
+//! Register allocator then uses the annotation to construct control-flow, which is then used by liveness analysis and
+//! other tools to prepare ground for register allocation.
class JumpAnnotation {
public:
ASMJIT_NONCOPYABLE(JumpAnnotation)
+ //! \name Members
+ //! \{
+
//! Compiler that owns this JumpAnnotation.
BaseCompiler* _compiler;
//! Annotation identifier.
@@ -334,10 +281,20 @@ public:
//! Vector of label identifiers, see \ref labelIds().
ZoneVector _labelIds;
+ //! \}
+
+ //! \name Construction & Destruction
+ //! \{
+
inline JumpAnnotation(BaseCompiler* compiler, uint32_t annotationId) noexcept
: _compiler(compiler),
_annotationId(annotationId) {}
+ //! \}
+
+ //! \name Accessors
+ //! \{
+
//! Returns the compiler that owns this JumpAnnotation.
inline BaseCompiler* compiler() const noexcept { return _compiler; }
//! Returns the annotation id.
@@ -350,35 +307,42 @@ public:
//! Tests whether the given `labelId` is a target of this JumpAnnotation.
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.
inline Error addLabel(const Label& label) noexcept { return addLabelId(label.id()); }
//! Adds the `labelId` to the list of targets of this JumpAnnotation.
inline Error addLabelId(uint32_t labelId) noexcept { return _labelIds.append(&_compiler->_allocator, labelId); }
-};
-// ============================================================================
-// [asmjit::JumpNode]
-// ============================================================================
+ //! \}
+};
//! Jump instruction with \ref JumpAnnotation.
//!
-//! \note This node should be only used to represent jump where the jump target
-//! cannot be deduced by examining instruction operands. For example if the jump
-//! target is register or memory location. This pattern is often used to perform
-//! indirect jumps that use jump table, e.g. to implement `switch{}` statement.
+//! \note This node should be only used to represent jump where the jump target cannot be deduced by examining
+//! instruction operands. For example if the jump target is register or memory location. This pattern is often
+//! used to perform indirect jumps that use jump table, e.g. to implement `switch{}` statement.
class JumpNode : public InstNode {
public:
ASMJIT_NONCOPYABLE(JumpNode)
+ //! \name Members
+ //! \{
+
JumpAnnotation* _annotation;
+ //! \}
+
//! \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),
_annotation(annotation) {
- setType(kNodeJump);
+ setType(NodeType::kJump);
}
//! \}
@@ -396,31 +360,24 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::FuncNode]
-// ============================================================================
-
//! Function node represents a function used by \ref BaseCompiler.
//!
//! A function is composed of the following:
//!
-//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit.
-//! To get the entry, simply use \ref FuncNode::label(), which is the same
-//! as \ref LabelNode::label().
+//! - Function entry, \ref FuncNode acts as a label, so the entry is implicit. To get the entry, simply use
+//! \ref FuncNode::label(), which is the same as \ref LabelNode::label().
//!
-//! - Function exit, which is represented by \ref FuncNode::exitNode(). A
-//! helper function \ref FuncNode::exitLabel() exists and returns an exit
-//! label instead of node.
+//! - Function exit, which is represented by \ref FuncNode::exitNode(). A helper function
+//! \ref FuncNode::exitLabel() exists and returns an exit label instead of node.
//!
-//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of
-//! a function - there should be no code that belongs to the function after
-//! this node, but the Compiler doesn't enforce that at the moment.
+//! - Function \ref FuncNode::endNode() sentinel. This node marks the end of a function - there should be no
+//! code that belongs to the function after this node, but the Compiler doesn't enforce that at the moment.
//!
//! - Function detail, see \ref FuncNode::detail().
//!
//! - Function frame, see \ref FuncNode::frame().
//!
-//! - Function arguments mapped to virtual registers, see \ref FuncNode::args().
+//! - Function arguments mapped to virtual registers, see \ref FuncNode::argPacks().
//!
//! In a node list, the function and its body looks like the following:
//!
@@ -439,29 +396,30 @@ public:
//! [...] - Anything after the function.
//! \endcode
//!
-//! When a function is added to the compiler by \ref BaseCompiler::addFunc() it
-//! actually inserts 3 nodes (FuncNode, ExitLabel, and FuncEnd) and sets the
-//! current cursor to be FuncNode. When \ref BaseCompiler::endFunc() is called
-//! the cursor is set to FuncEnd. This guarantees that user can use ExitLabel
-//! as a marker after additional code or data can be placed, and it's a common
-//! practice.
+//! When a function is added to the instruction stream by \ref BaseCompiler::addFunc() it actually inserts 3 nodes
+//! (FuncNode, ExitLabel, and FuncEnd) and sets the current cursor to be FuncNode. When \ref BaseCompiler::endFunc()
+//! is called the cursor is set to FuncEnd. This guarantees that user can use ExitLabel as a marker after additional
+//! code or data can be placed, which is a common practice.
class FuncNode : public LabelNode {
public:
ASMJIT_NONCOPYABLE(FuncNode)
//! Arguments pack.
struct ArgPack {
- VirtReg* _data[Globals::kMaxValuePack];
+ RegOnly _data[Globals::kMaxValuePack];
inline void reset() noexcept {
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 VirtReg* const& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
+ inline RegOnly& operator[](size_t valueIndex) noexcept { return _data[valueIndex]; }
+ inline const RegOnly& operator[](size_t valueIndex) const noexcept { return _data[valueIndex]; }
};
+ //! \name Members
+ //! \{
+
//! Function detail.
FuncDetail _funcDetail;
//! Function frame.
@@ -470,24 +428,25 @@ public:
LabelNode* _exitNode;
//! Function end (sentinel).
SentinelNode* _end;
-
//! Argument packs.
ArgPack* _args;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! Creates a new `FuncNode` instance.
//!
- //! Always use `BaseCompiler::addFunc()` to create `FuncNode`.
- ASMJIT_INLINE FuncNode(BaseBuilder* cb) noexcept
+ //! Always use `BaseCompiler::addFunc()` to create a new `FuncNode`.
+ inline FuncNode(BaseBuilder* cb) noexcept
: LabelNode(cb),
_funcDetail(),
_frame(),
_exitNode(nullptr),
_end(nullptr),
_args(nullptr) {
- setType(kNodeFunc);
+ setType(NodeType::kFunc);
}
//! \}
@@ -500,12 +459,12 @@ public:
//! Returns function exit 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; }
- //! Returns function declaration.
+ //! Returns function detail.
inline FuncDetail& detail() noexcept { return _funcDetail; }
- //! Returns function declaration.
+ //! Returns function detail.
inline const FuncDetail& detail() const noexcept { return _funcDetail; }
//! Returns function frame.
@@ -513,14 +472,19 @@ public:
//! Returns function frame.
inline const FuncFrame& frame() const noexcept { return _frame; }
- //! Tests whether the function has a return value.
- inline bool hasRet() const noexcept { return _funcDetail.hasRet(); }
+ //! Returns function attributes.
+ 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.
inline uint32_t argCount() const noexcept { return _funcDetail.argCount(); }
-
//! Returns argument packs.
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`.
inline ArgPack& argPack(size_t argIndex) const noexcept {
ASMJIT_ASSERT(argIndex < argCount());
@@ -528,15 +492,27 @@ public:
}
//! 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());
- _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`.
- 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());
- _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`.
@@ -548,21 +524,12 @@ public:
//! Resets argument pack at `argIndex`.
inline void resetArg(size_t argIndex, size_t valueIndex) noexcept {
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.
class FuncRetNode : public InstNode {
public:
@@ -572,27 +539,21 @@ public:
//! \{
//! Creates a new `FuncRetNode` instance.
- inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, 0, 0) {
- _any._nodeType = kNodeFuncRet;
+ inline FuncRetNode(BaseBuilder* cb) noexcept : InstNode(cb, BaseInst::kIdAbstract, InstOptions::kNone, 0) {
+ _any._nodeType = NodeType::kFuncRet;
}
//! \}
};
-// ============================================================================
-// [asmjit::InvokeNode]
-// ============================================================================
-
//! Function invocation, used by \ref BaseCompiler.
class InvokeNode : public InstNode {
public:
ASMJIT_NONCOPYABLE(InvokeNode)
- //! Operand pack provides multiple operands that can be associated with a
- //! single return value of function argument. Sometimes this is necessary to
- //! express an argument or return value that requires multiple registers, for
- //! example 64-bit value in 32-bit mode or passing / returning homogeneous data
- //! structures.
+ //! Operand pack provides multiple operands that can be associated with a single return value of function
+ //! argument. Sometims this is necessary to express an argument or return value that requires multiple
+ //! registers, for example 64-bit value in 32-bit mode or passing / returning homogeneous data structures.
struct OperandPack {
//! Operands.
Operand_ _data[Globals::kMaxValuePack];
@@ -616,6 +577,9 @@ public:
}
};
+ //! \name Members
+ //! \{
+
//! Function detail.
FuncDetail _funcDetail;
//! Function return value(s).
@@ -623,18 +587,20 @@ public:
//! Function arguments.
OperandPack* _args;
+ //! \}
+
//! \name Construction & Destruction
//! \{
//! 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),
_funcDetail(),
_args(nullptr) {
- setType(kNodeInvoke);
+ setType(NodeType::kInvoke);
_resetOps();
_rets.reset();
- addFlags(kFlagIsRemovable);
+ addFlags(NodeFlags::kIsRemovable);
}
//! \}
@@ -718,10 +684,6 @@ public:
//! \}
};
-// ============================================================================
-// [asmjit::FuncPass]
-// ============================================================================
-
//! Function pass extends \ref Pass with \ref FuncPass::runOnFunction().
class ASMJIT_VIRTAPI FuncPass : public Pass {
public:
@@ -743,7 +705,7 @@ public:
//! \}
- //! \name Run
+ //! \name Pass Interface
//! \{
//! 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
diff --git a/src/asmjit/core/compilerdefs.h b/src/asmjit/core/compilerdefs.h
index 32f0757..f2e7a4e 100644
--- a/src/asmjit/core/compilerdefs.h
+++ b/src/asmjit/core/compilerdefs.h
@@ -1,63 +1,41 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
#define ASMJIT_CORE_COMPILERDEFS_H_INCLUDED
#include "../core/api-config.h"
#include "../core/operand.h"
+#include "../core/type.h"
#include "../core/zonestring.h"
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class RAWorkReg;
//! \addtogroup asmjit_compiler
//! \{
-// ============================================================================
-// [asmjit::VirtReg]
-// ============================================================================
-
//! Virtual register data, managed by \ref BaseCompiler.
class VirtReg {
public:
ASMJIT_NONCOPYABLE(VirtReg)
+ //! \name Members
+ //! \{
+
+ //! Virtual register signature.
+ OperandSignature _signature {};
//! Virtual register id.
uint32_t _id = 0;
- //! Virtual register info (signature).
- RegInfo _info = {};
- //! Virtual register size (can be smaller than `regInfo._size`).
+ //! Virtual register size (can be smaller than `_signature._size`).
uint32_t _virtSize = 0;
//! Virtual register alignment (for spilling).
uint8_t _alignment = 0;
//! Type-id.
- uint8_t _typeId = 0;
+ TypeId _typeId = TypeId::kVoid;
//! Virtual register weight for alloc/spill decisions.
uint8_t _weight = 1;
//! True if this is a fixed register, never reallocated.
@@ -69,24 +47,23 @@ public:
//! Virtual register name (user provided or automatically generated).
ZoneString<16> _name {};
- // -------------------------------------------------------------------------
- // The following members are used exclusively by RAPass. They are initialized
- // when the VirtReg is created to NULL pointers and then changed during RAPass
- // execution. RAPass sets them back to NULL before it returns.
- // -------------------------------------------------------------------------
+ // The following members are used exclusively by RAPass. They are initialized 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.
RAWorkReg* _workReg = nullptr;
+ //! \}
+
//! \name Construction & Destruction
//! \{
- inline VirtReg(uint32_t id, uint32_t signature, uint32_t virtSize, uint32_t alignment, uint32_t typeId) noexcept
- : _id(id),
- _info { signature },
+ inline VirtReg(const OperandSignature& signature, uint32_t id, uint32_t virtSize, uint32_t alignment, TypeId typeId) noexcept
+ : _signature(signature),
+ _id(id),
_virtSize(virtSize),
_alignment(uint8_t(alignment)),
- _typeId(uint8_t(typeId)),
+ _typeId(typeId),
_isFixed(false),
_isStack(false),
_reserved(0) {}
@@ -104,56 +81,50 @@ public:
//! Returns the size of the virtual register name.
inline uint32_t nameSize() const noexcept { return _name.size(); }
- //! Returns a register information that wraps the register signature.
- inline const RegInfo& info() const noexcept { return _info; }
+ //! Returns a register signature of this virtual register.
+ inline OperandSignature signature() const noexcept { return _signature; }
//! 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).
- 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.
//!
- //! For example if this is a 128-bit SIMD register used for a scalar single
- //! precision floating point value then its virtSize would be 4, however, the
- //! `regSize` would still say 16 (128-bits), because it's the smallest size
+ //! For example if this is a 128-bit SIMD register used for a scalar single precision floating point value then
+ //! its virtSize would be 4, however, the `regSize` would still say 16 (128-bits), because it's the smallest size
//! of that register type.
- inline uint32_t regSize() const noexcept { return _info.size(); }
-
- //! Returns a register signature of this virtual register.
- inline uint32_t signature() const noexcept { return _info.signature(); }
+ inline uint32_t regSize() const noexcept { return _signature.size(); }
//! Returns the virtual register size.
//!
- //! The virtual register size describes how many bytes the virtual register
- //! needs to store its content. It can be smaller than the physical register
- //! size, see `regSize()`.
+ //! The virtual register size describes how many bytes the virtual register needs to store its content. It can be
+ //! smaller than the physical register size, see `regSize()`.
inline uint32_t virtSize() const noexcept { return _virtSize; }
//! Returns the virtual register alignment.
inline uint32_t alignment() const noexcept { return _alignment; }
- //! Returns the virtual register type id, see `Type::Id`.
- inline uint32_t typeId() const noexcept { return _typeId; }
+ //! Returns the virtual register type id.
+ inline TypeId typeId() const noexcept { return _typeId; }
- //! Returns the virtual register weight - the register allocator can use it
- //! as explicit hint for alloc/spill decisions.
+ //! Returns the virtual register weight - the register allocator can use it as explicit hint for alloc/spill
+ //! decisions.
inline uint32_t weight() const noexcept { return _weight; }
- //! Sets the virtual register weight (0 to 255) - the register allocator can
- //! use it as explicit hint for alloc/spill decisions and initial bin-packing.
+ //! Sets the virtual register weight (0 to 255) - the register allocator can use it as explicit hint for
+ //! alloc/spill decisions and initial bin-packing.
inline void setWeight(uint32_t weight) noexcept { _weight = uint8_t(weight); }
- //! Returns whether the virtual register is always allocated to a fixed
- //! physical register (and never reallocated).
+ //! Returns whether the virtual register is always allocated to a fixed physical register (and never reallocated).
//!
//! \note This is only used for special purposes and it's mostly internal.
inline bool isFixed() const noexcept { return bool(_isFixed); }
- //! Returns whether the virtual register is indeed a stack that only uses
- //! the virtual register id for making it accessible.
+ //! Tests whether the virtual register is in fact a stack that only uses the virtual register id.
//!
//! \note It's an error if a stack is accessed as a register.
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 RAWorkReg* workReg() const noexcept { return _workReg; }
inline void setWorkReg(RAWorkReg* workReg) noexcept { _workReg = workReg; }
diff --git a/src/asmjit/core/constpool.cpp b/src/asmjit/core/constpool.cpp
index 84d7cd3..ad5fe4f 100644
--- a/src/asmjit/core/constpool.cpp
+++ b/src/asmjit/core/constpool.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/constpool.h"
@@ -27,16 +9,14 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::ConstPool - Construction / Destruction]
-// ============================================================================
+// ConstPool - Construction & Destruction
+// ======================================
ConstPool::ConstPool(Zone* zone) noexcept { reset(zone); }
ConstPool::~ConstPool() noexcept {}
-// ============================================================================
-// [asmjit::ConstPool - Reset]
-// ============================================================================
+// ConstPool - Reset
+// =================
void ConstPool::reset(Zone* zone) noexcept {
_zone = zone;
@@ -55,11 +35,10 @@ void ConstPool::reset(Zone* zone) noexcept {
_minItemSize = 0;
}
-// ============================================================================
-// [asmjit::ConstPool - Ops]
-// ============================================================================
+// ConstPool - Operations
+// ======================
-static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
+static inline ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcept {
ConstPool::Gap* gap = self->_gapPool;
if (!gap)
return self->_zone->allocT();
@@ -68,7 +47,7 @@ static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) noexcep
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;
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 gapSize;
- if (size >= 16 && Support::isAligned(offset, 16)) {
+ if (size >= 32 && Support::isAligned(offset, 32)) {
+ gapIndex = ConstPool::kIndex32;
+ gapSize = 32;
+ }
+ else if (size >= 16 && Support::isAligned(offset, 16)) {
gapIndex = ConstPool::kIndex16;
gapSize = 16;
}
@@ -101,9 +84,8 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t size) noexce
gapSize = 1;
}
- // We don't have to check for errors here, if this failed nothing really
- // happened (just the gap won't be visible) and it will fail again at
- // place where the same check would generate `kErrorOutOfMemory` error.
+ // We don't have to check for errors here, if this failed nothing really happened (just the gap won't be
+ // visible) and it will fail again at place where the same check would generate `kErrorOutOfMemory` error.
ConstPool::Gap* gap = ConstPool_allocGap(self);
if (!gap)
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 {
size_t treeIndex;
- if (size == 32)
+ if (size == 64)
+ treeIndex = kIndex64;
+ else if (size == 32)
treeIndex = kIndex32;
else if (size == 16)
treeIndex = kIndex16;
@@ -143,8 +127,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
return kErrorOk;
}
- // Before incrementing the current offset try if there is a gap that can
- // be used for the requested data.
+ // Before incrementing the current offset try if there is a gap that can be used for the requested data.
size_t offset = ~size_t(0);
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)) {
- // Get how many bytes have to be skipped so the address is aligned accordingly
- // to the 'size'.
+ // Get how many bytes have to be skipped so the address is aligned accordingly to the 'size'.
size_t diff = Support::alignUpDiff(_size, size);
if (diff != 0) {
@@ -195,9 +177,8 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
dstOffset = offset;
- // Now create a bunch of shared constants that are based on the data pattern.
- // We stop at size 4, it probably doesn't make sense to split constants down
- // to 1 byte.
+ // Now create a bunch of shared constants that are based on the data pattern. We stop at size 4,
+ // it probably doesn't make sense to split constants down to 1 byte.
size_t pCount = 1;
size_t smallerSize = size;
@@ -226,9 +207,8 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) noexcept
return kErrorOk;
}
-// ============================================================================
-// [asmjit::ConstPool - Reset]
-// ============================================================================
+// ConstPool - Reset
+// =================
struct ConstPoolFill {
inline ConstPoolFill(uint8_t* dst, size_t dataSize) noexcept :
@@ -255,9 +235,8 @@ void ConstPool::fill(void* dst) const noexcept {
}
}
-// ============================================================================
-// [asmjit::ConstPool - Unit]
-// ============================================================================
+// ConstPool - Tests
+// =================
#if defined(ASMJIT_TEST)
UNIT(const_pool) {
diff --git a/src/asmjit/core/constpool.h b/src/asmjit/core/constpool.h
index fc0e0bc..32b84b1 100644
--- a/src/asmjit/core/constpool.h
+++ b/src/asmjit/core/constpool.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_CONSTPOOL_H_INCLUDED
#define ASMJIT_CORE_CONSTPOOL_H_INCLUDED
@@ -33,23 +15,22 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_utilities
//! \{
-// ============================================================================
-// [asmjit::ConstPool]
-// ============================================================================
+//! Constant pool scope.
+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.
class ConstPool {
public:
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
//! Index of a given size in const-pool table.
@@ -60,7 +41,8 @@ public:
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
- kIndexCount = 6
+ kIndex64 = 6,
+ kIndexCount = 7
};
//! Zone-allocated const-pool gap created by two differently aligned constants.
@@ -193,6 +175,9 @@ public:
//! \endcond
+ //! \name Members
+ //! \{
+
//! Zone allocator.
Zone* _zone;
//! Tree per size.
@@ -209,6 +194,8 @@ public:
//! Minimum item size in the pool.
size_t _minItemSize;
+ //! \}
+
//! \name Construction & Destruction
//! \{
@@ -238,21 +225,18 @@ public:
//! 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 is added to the pool only if it doesn't not exist, otherwise
- //! cached value is returned.
+ //! The constant must have known size, which is 1, 2, 4, 8, 16 or 32 bytes. The constant is added to the pool only
+ //! if it doesn't not exist, otherwise cached value is returned.
//!
- //! AsmJit is able to subdivide added constants, so for example if you add
- //! 8-byte constant 0x1122334455667788 it will create the following slots:
+ //! AsmJit is able to subdivide added constants, so for example if you add 8-byte constant 0x1122334455667788 it
+ //! will create the following slots:
//!
//! 8-byte: 0x1122334455667788
//! 4-byte: 0x11223344, 0x55667788
//!
- //! The reason is that when combining MMX/SSE/AVX code some patterns are used
- //! frequently. However, AsmJit is not able to reallocate a constant that has
- //! been already added. For example if you try to add 4-byte constant and then
- //! 8-byte constant having the same 4-byte pattern as the previous one, two
- //! independent slots will be generated by the pool.
+ //! The reason is that when combining MMX/SSE/AVX code some patterns are used frequently. However, AsmJit is not
+ //! able to reallocate a constant that has been already added. For example if you try to add 4-byte constant and
+ //! then 8-byte constant having the same 4-byte pattern as the previous one, two independent slots will be used.
ASMJIT_API Error add(const void* data, size_t size, size_t& dstOffset) noexcept;
//! Fills the destination with the content of this constant pool.
diff --git a/src/asmjit/core/cpuinfo.cpp b/src/asmjit/core/cpuinfo.cpp
index a281a4a..ef152cd 100644
--- a/src/asmjit/core/cpuinfo.cpp
+++ b/src/asmjit/core/cpuinfo.cpp
@@ -1,28 +1,11 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/cpuinfo.h"
+#include "../core/support.h"
#if !defined(_WIN32)
#include
@@ -30,11 +13,27 @@
#include
#endif
+// Required by `getauxval()` on Linux.
+#if defined(__linux__)
+ #include
+#endif
+
+//! Required to detect CPU and features on Apple platforms.
+#if defined(__APPLE__)
+ #include
+ #include
+ #include
+#endif
+
+// Required by `__cpuidex()` and `_xgetbv()`.
+#if defined(_MSC_VER)
+ #include
+#endif
+
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::CpuInfo - Detect - CPU NumThreads]
-// ============================================================================
+// CpuInfo - Detect - HW-Thread Count
+// ==================================
#if defined(_WIN32)
static inline uint32_t detectHWThreadCount() noexcept {
@@ -53,37 +52,1103 @@ static inline uint32_t detectHWThreadCount() noexcept {
}
#endif
-// ============================================================================
-// [asmjit::CpuInfo - Detect - CPU Features]
-// ============================================================================
+// CpuInfo - Detect - X86
+// ======================
-#if !defined(ASMJIT_NO_X86) && ASMJIT_ARCH_X86
-namespace x86 { void detectCpu(CpuInfo& cpu) noexcept; }
+#if ASMJIT_ARCH_X86
+
+struct cpuid_t { uint32_t eax, ebx, ecx, edx; };
+struct xgetbv_t { uint32_t eax, edx; };
+
+// Executes `cpuid` instruction.
+static inline void cpuidQuery(cpuid_t* out, uint32_t inEax, uint32_t inEcx = 0) noexcept {
+#if defined(_MSC_VER)
+ __cpuidex(reinterpret_cast(out), inEax, inEcx);
+#elif defined(__GNUC__) && ASMJIT_ARCH_X86 == 32
+ __asm__ __volatile__(
+ "mov %%ebx, %%edi\n"
+ "cpuid\n"
+ "xchg %%edi, %%ebx\n" : "=a"(out->eax), "=D"(out->ebx), "=c"(out->ecx), "=d"(out->edx) : "a"(inEax), "c"(inEcx));
+#elif defined(__GNUC__) && ASMJIT_ARCH_X86 == 64
+ __asm__ __volatile__(
+ "mov %%rbx, %%rdi\n"
+ "cpuid\n"
+ "xchg %%rdi, %%rbx\n" : "=a"(out->eax), "=D"(out->ebx), "=c"(out->ecx), "=d"(out->edx) : "a"(inEax), "c"(inEcx));
+#else
+ #error "[asmjit] x86::cpuidQuery() - Unsupported compiler."
+#endif
+}
+
+// Executes 'xgetbv' instruction.
+static inline void xgetbvQuery(xgetbv_t* out, uint32_t inEcx) noexcept {
+#if defined(_MSC_VER)
+ uint64_t value = _xgetbv(inEcx);
+ out->eax = uint32_t(value & 0xFFFFFFFFu);
+ out->edx = uint32_t(value >> 32);
+#elif defined(__GNUC__)
+ uint32_t outEax;
+ uint32_t outEdx;
+
+ // Replaced, because the world is not perfect:
+ // __asm__ __volatile__("xgetbv" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
+ __asm__ __volatile__(".byte 0x0F, 0x01, 0xD0" : "=a"(outEax), "=d"(outEdx) : "c"(inEcx));
+
+ out->eax = outEax;
+ out->edx = outEdx;
+#else
+ out->eax = 0;
+ out->edx = 0;
+#endif
+}
+
+// Map a 12-byte vendor string returned by `cpuid` into a `CpuInfo::Vendor` ID.
+static inline void simplifyCpuVendor(CpuInfo& cpu, uint32_t d0, uint32_t d1, uint32_t d2) noexcept {
+ struct Vendor {
+ char normalized[8];
+ union { char text[12]; uint32_t d[3]; };
+ };
+
+ static const Vendor table[] = {
+ { { 'A', 'M', 'D' }, {{ 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' }} },
+ { { 'I', 'N', 'T', 'E', 'L' }, {{ 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' }} },
+ { { 'V', 'I', 'A' }, {{ 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' }} },
+ { { 'V', 'I', 'A' }, {{ 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 }} },
+ { { 'U', 'N', 'K', 'N', 'O', 'W', 'N' }, {{ 0 }} }
+ };
+
+ uint32_t i;
+ for (i = 0; i < ASMJIT_ARRAY_SIZE(table) - 1; i++)
+ if (table[i].d[0] == d0 && table[i].d[1] == d1 && table[i].d[2] == d2)
+ break;
+ memcpy(cpu._vendor.str, table[i].normalized, 8);
+}
+
+static ASMJIT_FAVOR_SIZE void simplifyCpuBrand(char* s) noexcept {
+ char* d = s;
+
+ char c = s[0];
+ char prev = 0;
+
+ // Used to always clear the current character to ensure that the result
+ // doesn't contain garbage after a new null terminator is placed at the end.
+ s[0] = '\0';
+
+ for (;;) {
+ if (!c)
+ break;
+
+ if (!(c == ' ' && (prev == '@' || s[1] == ' ' || s[1] == '@'))) {
+ *d++ = c;
+ prev = c;
+ }
+
+ c = *++s;
+ s[0] = '\0';
+ }
+
+ d[0] = '\0';
+}
+
+static ASMJIT_FAVOR_SIZE void detectX86Cpu(CpuInfo& cpu) noexcept {
+ using Support::bitTest;
+
+ cpuid_t regs;
+ xgetbv_t xcr0 { 0, 0 };
+ CpuFeatures::X86& features = cpu.features().x86();
+
+ cpu._wasDetected = true;
+ cpu._maxLogicalProcessors = 1;
+
+ // We are gonna execute CPUID, which was introduced by I486, so it's the requirement.
+ features.add(CpuFeatures::X86::kI486);
+
+ // CPUID EAX=0
+ // -----------
+
+ // Get vendor string/id.
+ cpuidQuery(®s, 0x0);
+
+ uint32_t maxId = regs.eax;
+ uint32_t maxSubLeafId_0x7 = 0;
+
+ simplifyCpuVendor(cpu, regs.ebx, regs.edx, regs.ecx);
+
+ // CPUID EAX=1
+ // -----------
+
+ if (maxId >= 0x1) {
+ // Get feature flags in ECX/EDX and family/model in EAX.
+ cpuidQuery(®s, 0x1);
+
+ // Fill family and model fields.
+ uint32_t modelId = (regs.eax >> 4) & 0x0F;
+ uint32_t familyId = (regs.eax >> 8) & 0x0F;
+
+ // Use extended family and model fields.
+ if (familyId == 0x06u || familyId == 0x0Fu)
+ modelId += (((regs.eax >> 16) & 0x0Fu) << 4);
+
+ if (familyId == 0x0Fu)
+ familyId += ((regs.eax >> 20) & 0xFFu);
+
+ cpu._modelId = modelId;
+ cpu._familyId = familyId;
+ cpu._brandId = ((regs.ebx ) & 0xFF);
+ cpu._processorType = ((regs.eax >> 12) & 0x03);
+ cpu._maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
+ cpu._stepping = ((regs.eax ) & 0x0F);
+ cpu._cacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
+
+ features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kSSE3);
+ features.addIf(bitTest(regs.ecx, 1), CpuFeatures::X86::kPCLMULQDQ);
+ features.addIf(bitTest(regs.ecx, 3), CpuFeatures::X86::kMONITOR);
+ features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kVMX);
+ features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kSMX);
+ features.addIf(bitTest(regs.ecx, 9), CpuFeatures::X86::kSSSE3);
+ features.addIf(bitTest(regs.ecx, 13), CpuFeatures::X86::kCMPXCHG16B);
+ features.addIf(bitTest(regs.ecx, 19), CpuFeatures::X86::kSSE4_1);
+ features.addIf(bitTest(regs.ecx, 20), CpuFeatures::X86::kSSE4_2);
+ features.addIf(bitTest(regs.ecx, 22), CpuFeatures::X86::kMOVBE);
+ features.addIf(bitTest(regs.ecx, 23), CpuFeatures::X86::kPOPCNT);
+ features.addIf(bitTest(regs.ecx, 25), CpuFeatures::X86::kAESNI);
+ features.addIf(bitTest(regs.ecx, 26), CpuFeatures::X86::kXSAVE);
+ features.addIf(bitTest(regs.ecx, 27), CpuFeatures::X86::kOSXSAVE);
+ features.addIf(bitTest(regs.ecx, 30), CpuFeatures::X86::kRDRAND);
+ features.addIf(bitTest(regs.edx, 0), CpuFeatures::X86::kFPU);
+ features.addIf(bitTest(regs.edx, 4), CpuFeatures::X86::kRDTSC);
+ features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kMSR);
+ features.addIf(bitTest(regs.edx, 8), CpuFeatures::X86::kCMPXCHG8B);
+ features.addIf(bitTest(regs.edx, 15), CpuFeatures::X86::kCMOV);
+ features.addIf(bitTest(regs.edx, 19), CpuFeatures::X86::kCLFLUSH);
+ features.addIf(bitTest(regs.edx, 23), CpuFeatures::X86::kMMX);
+ features.addIf(bitTest(regs.edx, 24), CpuFeatures::X86::kFXSR);
+ features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kSSE);
+ features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kSSE, CpuFeatures::X86::kSSE2);
+ features.addIf(bitTest(regs.edx, 28), CpuFeatures::X86::kMT);
+
+ // Get the content of XCR0 if supported by the CPU and enabled by the OS.
+ if (features.hasXSAVE() && features.hasOSXSAVE()) {
+ xgetbvQuery(&xcr0, 0);
+ }
+
+ // Detect AVX+.
+ if (bitTest(regs.ecx, 28)) {
+ // - XCR0[2:1] == 11b
+ // XMM & YMM states need to be enabled by OS.
+ if ((xcr0.eax & 0x00000006u) == 0x00000006u) {
+ features.add(CpuFeatures::X86::kAVX);
+ features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kFMA);
+ features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kF16C);
+ }
+ }
+ }
+
+ constexpr uint32_t kXCR0_AMX_Bits = 0x3u << 17;
+ bool amxEnabledByOS = (xcr0.eax & kXCR0_AMX_Bits) == kXCR0_AMX_Bits;
+
+#if defined(__APPLE__)
+ // Apple platform provides on-demand AVX512 support. When an AVX512 instruction is used the first time it results
+ // in #UD, which would cause the thread being promoted to use AVX512 support by the OS in addition to enabling the
+ // necessary bits in XCR0 register.
+ bool avx512EnabledByOS = true;
+#else
+ // - XCR0[2:1] == 11b - XMM/YMM states need to be enabled by OS.
+ // - XCR0[7:5] == 111b - Upper 256-bit of ZMM0-XMM15 and ZMM16-ZMM31 need to be enabled by OS.
+ constexpr uint32_t kXCR0_AVX512_Bits = (0x3u << 1) | (0x7u << 5);
+ bool avx512EnabledByOS = (xcr0.eax & kXCR0_AVX512_Bits) == kXCR0_AVX512_Bits;
#endif
-#if defined(ASMJIT_BUILD_ARM) && ASMJIT_ARCH_ARM
-namespace arm { void detectCpu(CpuInfo& cpu) noexcept; }
+ // CPUID EAX=7 ECX=0
+ // -----------------
+
+ // Detect new features if the processor supports CPUID-07.
+ bool maybeMPX = false;
+
+ if (maxId >= 0x7) {
+ cpuidQuery(®s, 0x7);
+
+ maybeMPX = bitTest(regs.ebx, 14);
+ maxSubLeafId_0x7 = regs.eax;
+
+ features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kFSGSBASE);
+ features.addIf(bitTest(regs.ebx, 3), CpuFeatures::X86::kBMI);
+ features.addIf(bitTest(regs.ebx, 4), CpuFeatures::X86::kHLE);
+ features.addIf(bitTest(regs.ebx, 7), CpuFeatures::X86::kSMEP);
+ features.addIf(bitTest(regs.ebx, 8), CpuFeatures::X86::kBMI2);
+ features.addIf(bitTest(regs.ebx, 9), CpuFeatures::X86::kERMS);
+ features.addIf(bitTest(regs.ebx, 11), CpuFeatures::X86::kRTM);
+ features.addIf(bitTest(regs.ebx, 18), CpuFeatures::X86::kRDSEED);
+ features.addIf(bitTest(regs.ebx, 19), CpuFeatures::X86::kADX);
+ features.addIf(bitTest(regs.ebx, 20), CpuFeatures::X86::kSMAP);
+ features.addIf(bitTest(regs.ebx, 23), CpuFeatures::X86::kCLFLUSHOPT);
+ features.addIf(bitTest(regs.ebx, 24), CpuFeatures::X86::kCLWB);
+ features.addIf(bitTest(regs.ebx, 29), CpuFeatures::X86::kSHA);
+ features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kPREFETCHWT1);
+ features.addIf(bitTest(regs.ecx, 4), CpuFeatures::X86::kOSPKE);
+ features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kWAITPKG);
+ features.addIf(bitTest(regs.ecx, 7), CpuFeatures::X86::kCET_SS);
+ features.addIf(bitTest(regs.ecx, 8), CpuFeatures::X86::kGFNI);
+ features.addIf(bitTest(regs.ecx, 9), CpuFeatures::X86::kVAES);
+ features.addIf(bitTest(regs.ecx, 10), CpuFeatures::X86::kVPCLMULQDQ);
+ features.addIf(bitTest(regs.ecx, 22), CpuFeatures::X86::kRDPID);
+ features.addIf(bitTest(regs.ecx, 25), CpuFeatures::X86::kCLDEMOTE);
+ features.addIf(bitTest(regs.ecx, 27), CpuFeatures::X86::kMOVDIRI);
+ features.addIf(bitTest(regs.ecx, 28), CpuFeatures::X86::kMOVDIR64B);
+ features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kENQCMD);
+ features.addIf(bitTest(regs.edx, 5), CpuFeatures::X86::kUINTR);
+ features.addIf(bitTest(regs.edx, 14), CpuFeatures::X86::kSERIALIZE);
+ features.addIf(bitTest(regs.edx, 16), CpuFeatures::X86::kTSXLDTRK);
+ features.addIf(bitTest(regs.edx, 18), CpuFeatures::X86::kPCONFIG);
+ features.addIf(bitTest(regs.edx, 20), CpuFeatures::X86::kCET_IBT);
+
+ // Detect 'TSX' - Requires at least one of `HLE` and `RTM` features.
+ if (features.hasHLE() || features.hasRTM())
+ features.add(CpuFeatures::X86::kTSX);
+
+ // Detect 'AVX2' - Requires AVX as well.
+ if (bitTest(regs.ebx, 5) && features.hasAVX())
+ features.add(CpuFeatures::X86::kAVX2);
+
+ // Detect 'AVX512'.
+ if (avx512EnabledByOS && bitTest(regs.ebx, 16)) {
+ features.add(CpuFeatures::X86::kAVX512_F);
+
+ features.addIf(bitTest(regs.ebx, 17), CpuFeatures::X86::kAVX512_DQ);
+ features.addIf(bitTest(regs.ebx, 21), CpuFeatures::X86::kAVX512_IFMA);
+ features.addIf(bitTest(regs.ebx, 26), CpuFeatures::X86::kAVX512_PFI);
+ features.addIf(bitTest(regs.ebx, 27), CpuFeatures::X86::kAVX512_ERI);
+ features.addIf(bitTest(regs.ebx, 28), CpuFeatures::X86::kAVX512_CDI);
+ features.addIf(bitTest(regs.ebx, 30), CpuFeatures::X86::kAVX512_BW);
+ features.addIf(bitTest(regs.ebx, 31), CpuFeatures::X86::kAVX512_VL);
+ features.addIf(bitTest(regs.ecx, 1), CpuFeatures::X86::kAVX512_VBMI);
+ features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kAVX512_VBMI2);
+ features.addIf(bitTest(regs.ecx, 11), CpuFeatures::X86::kAVX512_VNNI);
+ features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kAVX512_BITALG);
+ features.addIf(bitTest(regs.ecx, 14), CpuFeatures::X86::kAVX512_VPOPCNTDQ);
+ features.addIf(bitTest(regs.edx, 2), CpuFeatures::X86::kAVX512_4VNNIW);
+ features.addIf(bitTest(regs.edx, 3), CpuFeatures::X86::kAVX512_4FMAPS);
+ features.addIf(bitTest(regs.edx, 8), CpuFeatures::X86::kAVX512_VP2INTERSECT);
+ features.addIf(bitTest(regs.edx, 23), CpuFeatures::X86::kAVX512_FP16);
+ }
+
+ // Detect 'AMX'.
+ if (amxEnabledByOS) {
+ features.addIf(bitTest(regs.edx, 22), CpuFeatures::X86::kAMX_BF16);
+ features.addIf(bitTest(regs.edx, 24), CpuFeatures::X86::kAMX_TILE);
+ features.addIf(bitTest(regs.edx, 25), CpuFeatures::X86::kAMX_INT8);
+ }
+ }
+
+ // CPUID EAX=7 ECX=1
+ // -----------------
+
+ if (features.hasAVX512_F() && maxSubLeafId_0x7 >= 1) {
+ cpuidQuery(®s, 0x7, 1);
+
+ features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kAVX_VNNI);
+ features.addIf(bitTest(regs.eax, 5), CpuFeatures::X86::kAVX512_BF16);
+ features.addIf(bitTest(regs.eax, 22), CpuFeatures::X86::kHRESET);
+ }
+
+ // CPUID EAX=13 ECX=0
+ // ------------------
+
+ if (maxId >= 0xD) {
+ cpuidQuery(®s, 0xD, 0);
+
+ // Both CPUID result and XCR0 has to be enabled to have support for MPX.
+ if (((regs.eax & xcr0.eax) & 0x00000018u) == 0x00000018u && maybeMPX)
+ features.add(CpuFeatures::X86::kMPX);
+
+ cpuidQuery(®s, 0xD, 1);
+
+ features.addIf(bitTest(regs.eax, 0), CpuFeatures::X86::kXSAVEOPT);
+ features.addIf(bitTest(regs.eax, 1), CpuFeatures::X86::kXSAVEC);
+ features.addIf(bitTest(regs.eax, 3), CpuFeatures::X86::kXSAVES);
+ }
+
+ // CPUID EAX=14 ECX=0
+ // ------------------
+
+ if (maxId >= 0xE) {
+ cpuidQuery(®s, 0xE, 0);
+
+ features.addIf(bitTest(regs.ebx, 4), CpuFeatures::X86::kPTWRITE);
+ }
+
+ // CPUID EAX=0x80000000...maxId
+ // ----------------------------
+
+ maxId = 0x80000000u;
+ uint32_t i = maxId;
+
+ // The highest EAX that we understand.
+ constexpr uint32_t kHighestProcessedEAX = 0x8000001Fu;
+
+ // Several CPUID calls are required to get the whole branc string. It's easier
+ // to copy one DWORD at a time instead of copying the string a byte by byte.
+ uint32_t* brand = cpu._brand.u32;
+ do {
+ cpuidQuery(®s, i);
+ switch (i) {
+ case 0x80000000u:
+ maxId = Support::min(regs.eax, kHighestProcessedEAX);
+ break;
+
+ case 0x80000001u:
+ features.addIf(bitTest(regs.ecx, 0), CpuFeatures::X86::kLAHFSAHF);
+ features.addIf(bitTest(regs.ecx, 2), CpuFeatures::X86::kSVM);
+ features.addIf(bitTest(regs.ecx, 5), CpuFeatures::X86::kLZCNT);
+ features.addIf(bitTest(regs.ecx, 6), CpuFeatures::X86::kSSE4A);
+ features.addIf(bitTest(regs.ecx, 7), CpuFeatures::X86::kMSSE);
+ features.addIf(bitTest(regs.ecx, 8), CpuFeatures::X86::kPREFETCHW);
+ features.addIf(bitTest(regs.ecx, 12), CpuFeatures::X86::kSKINIT);
+ features.addIf(bitTest(regs.ecx, 15), CpuFeatures::X86::kLWP);
+ features.addIf(bitTest(regs.ecx, 21), CpuFeatures::X86::kTBM);
+ features.addIf(bitTest(regs.ecx, 29), CpuFeatures::X86::kMONITORX);
+ features.addIf(bitTest(regs.edx, 20), CpuFeatures::X86::kNX);
+ features.addIf(bitTest(regs.edx, 21), CpuFeatures::X86::kFXSROPT);
+ features.addIf(bitTest(regs.edx, 22), CpuFeatures::X86::kMMX2);
+ features.addIf(bitTest(regs.edx, 27), CpuFeatures::X86::kRDTSCP);
+ features.addIf(bitTest(regs.edx, 29), CpuFeatures::X86::kPREFETCHW);
+ features.addIf(bitTest(regs.edx, 30), CpuFeatures::X86::k3DNOW2, CpuFeatures::X86::kMMX2);
+ features.addIf(bitTest(regs.edx, 31), CpuFeatures::X86::kPREFETCHW);
+
+ if (features.hasAVX()) {
+ features.addIf(bitTest(regs.ecx, 11), CpuFeatures::X86::kXOP);
+ features.addIf(bitTest(regs.ecx, 16), CpuFeatures::X86::kFMA4);
+ }
+
+ // This feature seems to be only supported by AMD.
+ if (cpu.isVendor("AMD")) {
+ features.addIf(bitTest(regs.ecx, 4), CpuFeatures::X86::kALTMOVCR8);
+ }
+ break;
+
+ case 0x80000002u:
+ case 0x80000003u:
+ case 0x80000004u:
+ *brand++ = regs.eax;
+ *brand++ = regs.ebx;
+ *brand++ = regs.ecx;
+ *brand++ = regs.edx;
+
+ // Go directly to the next one we are interested in.
+ if (i == 0x80000004u)
+ i = 0x80000008u - 1;
+ break;
+
+ case 0x80000008u:
+ features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kCLZERO);
+ features.addIf(bitTest(regs.ebx, 0), CpuFeatures::X86::kRDPRU);
+ features.addIf(bitTest(regs.ebx, 8), CpuFeatures::X86::kMCOMMIT);
+ features.addIf(bitTest(regs.ebx, 9), CpuFeatures::X86::kWBNOINVD);
+
+ // Go directly to the next one we are interested in.
+ i = 0x8000001Fu - 1;
+ break;
+
+ case 0x8000001Fu:
+ features.addIf(bitTest(regs.eax, 4), CpuFeatures::X86::kSNP);
+ break;
+ }
+ } while (++i <= maxId);
+
+ // Simplify CPU brand string a bit by removing some unnecessary spaces.
+ simplifyCpuBrand(cpu._brand.str);
+}
+
+#endif // ASMJIT_ARCH_X86
+
+// CpuInfo - Detect - ARM
+// ======================
+
+// The most relevant and accurate information can be found here:
+// https://github.com/llvm-project/llvm/blob/master/lib/Target/AArch64/AArch64.td
+// https://github.com/apple/llvm-project/blob/apple/main/llvm/lib/Target/AArch64/AArch64.td (Apple fork)
+//
+// Other resources:
+// https://en.wikipedia.org/wiki/AArch64
+// https://en.wikipedia.org/wiki/Apple_silicon#List_of_Apple_processors
+// https://developer.arm.com/architectures/learn-the-architecture/understanding-the-armv8-x-extensions/single-page
+
+#if ASMJIT_ARCH_ARM
+
+static inline void populateBaseARMFeatures(CpuInfo& cpu) noexcept {
+#if ASMJIT_ARCH_ARM == 32
+ // No baseline flags at the moment.
+ DebugUtils::unused(cpu);
+#else
+ // AArch64 is based on ARMv8-A and later.
+ cpu.addFeature(CpuFeatures::ARM::kARMv6);
+ cpu.addFeature(CpuFeatures::ARM::kARMv7);
+ cpu.addFeature(CpuFeatures::ARM::kARMv8a);
+
+ // AArch64 comes with these features by default.
+ cpu.addFeature(CpuFeatures::ARM::kVFPv2);
+ cpu.addFeature(CpuFeatures::ARM::kVFPv3);
+ cpu.addFeature(CpuFeatures::ARM::kVFPv4);
+ cpu.addFeature(CpuFeatures::ARM::kASIMD);
+ cpu.addFeature(CpuFeatures::ARM::kIDIVA);
+#endif
+}
+
+// Detects ARM version by macros defined at compile time. This means that AsmJit will report features forced at
+// compile time that should always be provided by the target CPU. This also means that if we don't provide any
+// means to detect CPU features the features reported by AsmJit will at least not report less features than the
+// target it was compiled to.
+ASMJIT_MAYBE_UNUSED
+static ASMJIT_FAVOR_SIZE void detectARMFeaturesViaCompilerFlags(CpuInfo& cpu) noexcept {
+ DebugUtils::unused(cpu);
+
+#if ASMJIT_ARCH_ARM == 32
+
+ // ARM targets have no baseline at the moment.
+# if defined(__ARM_ARCH_7A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv7);
+# endif
+# if defined(__ARM_ARCH_8A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8a);
+# endif
+
+# if defined(__TARGET_ARCH_THUMB)
+ cpu.addFeature(CpuFeatures::ARM::kTHUMB);
+# if __TARGET_ARCH_THUMB >= 4
+ cpu.addFeature(CpuFeatures::ARM::kTHUMBv2);
+# endif
+# endif
+
+# if defined(__ARM_FEATURE_FMA)
+ cpu.addFeature(CpuFeatures::ARM::kVFPv3);
+ cpu.addFeature(CpuFeatures::ARM::kVFPv4);
+# endif
+
+# if defined(__ARM_NEON)
+ cpu.addFeature(CpuFeatures::ARM::kASIMD);
+# endif
+
+# if defined(__ARM_FEATURE_IDIV) && defined(__TARGET_ARCH_THUMB)
+ cpu.addFeature(CpuFeatures::ARM::kIDIVT);
+#endif
+# if defined(__ARM_FEATURE_IDIV) && !defined(__TARGET_ARCH_THUMB)
+ cpu.addFeature(CpuFeatures::ARM::kIDIVA);
+# endif
+
#endif
-// ============================================================================
-// [asmjit::CpuInfo - Detect - Static Initializer]
-// ============================================================================
+#if defined(__ARM_ARCH_8_1A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_1a);
+#endif
+#if defined(__ARM_ARCH_8_2A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_2a);
+#endif
+#if defined(__ARM_ARCH_8_3A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_3a);
+#endif
+#if defined(__ARM_ARCH_8_4A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_4a);
+#endif
+#if defined(__ARM_ARCH_8_5A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_5a);
+#endif
+#if defined(__ARM_ARCH_8_6A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_6a);
+#endif
+#if defined(__ARM_ARCH_8_7A__)
+ cpu.addFeature(CpuFeatures::ARM::kARMv8_7a);
+#endif
+
+#if defined(__ARM_FEATURE_AES)
+ cpu.addFeature(CpuFeatures::ARM::kAES);
+#endif
+
+#if defined(__ARM_FEATURE_BF16_SCALAR_ARITHMETIC) && defined(__ARM_FEATURE_BF16_VECTOR_ARITHMETIC)
+ cpu.addFeature(CpuFeatures::ARM::kBF16);
+#endif
+
+#if defined(__ARM_FEATURE_CRC32)
+ cpu.addFeature(CpuFeatures::ARM::kCRC32);
+#endif
+
+#if defined(__ARM_FEATURE_CRYPTO)
+ cpu.addFeature(CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+#endif
+
+#if defined(__ARM_FEATURE_DOTPROD)
+ cpu.addFeature(CpuFeatures::ARM::kDOTPROD);
+#endif
+
+#if defined(__ARM_FEATURE_FP16FML) || defined(__ARM_FEATURE_FP16_FML)
+ cpu.addFeature(CpuFeatures::ARM::kFP16FML);
+#endif
+
+#if defined(__ARM_FEATURE_FP16_SCALAR_ARITHMETIC)
+ cpu.addFeature(CpuFeatures::ARM::kFP16FULL);
+#endif
+
+#if defined(__ARM_FEATURE_FRINT)
+ cpu.addFeature(CpuFeatures::ARM::kFRINT);
+#endif
+
+#if defined(__ARM_FEATURE_JCVT)
+ cpu.addFeature(CpuFeatures::ARM::kFJCVTZS);
+#endif
+
+#if defined(__ARM_FEATURE_MATMUL_INT8)
+ cpu.addFeature(CpuFeatures::ARM::kI8MM);
+#endif
+
+#if defined(__ARM_FEATURE_ATOMICS)
+ cpu.addFeature(CpuFeatures::ARM::kLSE);
+#endif
+
+#if defined(__ARM_FEATURE_MEMORY_TAGGING)
+ cpu.addFeature(CpuFeatures::ARM::kMTE);
+#endif
+
+#if defined(__ARM_FEATURE_QRDMX)
+ cpu.addFeature(CpuFeatures::ARM::kRDM);
+#endif
+
+#if defined(__ARM_FEATURE_RNG)
+ cpu.addFeature(CpuFeatures::ARM::kRNG);
+#endif
+
+#if defined(__ARM_FEATURE_SHA2)
+ cpu.addFeature(CpuFeatures::ARM::kSHA2);
+#endif
+
+#if defined(__ARM_FEATURE_SHA3)
+ cpu.addFeature(CpuFeatures::ARM::kSHA3);
+#endif
+
+#if defined(__ARM_FEATURE_SHA512)
+ cpu.addFeature(CpuFeatures::ARM::kSHA512);
+#endif
+
+#if defined(__ARM_FEATURE_SM3)
+ cpu.addFeature(CpuFeatures::ARM::kSM3);
+#endif
+
+#if defined(__ARM_FEATURE_SM4)
+ cpu.addFeature(CpuFeatures::ARM::kSM4);
+#endif
+
+#if defined(__ARM_FEATURE_SVE) || defined(__ARM_FEATURE_SVE_VECTOR_OPERATORS)
+ cpu.addFeature(CpuFeatures::ARM::kSVE);
+#endif
+
+#if defined(__ARM_FEATURE_SVE_MATMUL_INT8)
+ cpu.addFeature(CpuFeatures::ARM::kSVE_I8MM);
+#endif
+
+#if defined(__ARM_FEATURE_SVE_MATMUL_FP32)
+ cpu.addFeature(CpuFeatures::ARM::kSVE_F32MM);
+#endif
+
+#if defined(__ARM_FEATURE_SVE_MATMUL_FP64)
+ cpu.addFeature(CpuFeatures::ARM::kSVE_F64MM);
+#endif
+
+#if defined(__ARM_FEATURE_SVE2)
+ cpu.addFeature(CpuFeatures::ARM::kSVE2);
+#endif
+
+#if defined(__ARM_FEATURE_SVE2_AES)
+ cpu.addFeature(CpuFeatures::ARM::kSVE2_AES);
+#endif
+
+#if defined(__ARM_FEATURE_SVE2_BITPERM)
+ cpu.addFeature(CpuFeatures::ARM::kSVE2_BITPERM);
+#endif
+
+#if defined(__ARM_FEATURE_SVE2_SHA3)
+ cpu.addFeature(CpuFeatures::ARM::kSVE2_SHA3);
+#endif
+
+#if defined(__ARM_FEATURE_SVE2_SM4)
+ cpu.addFeature(CpuFeatures::ARM::kSVE2_SM4);
+#endif
+
+#if defined(__ARM_FEATURE_TME)
+ cpu.addFeature(CpuFeatures::ARM::kTME);
+#endif
+}
+
+ASMJIT_MAYBE_UNUSED
+static ASMJIT_FAVOR_SIZE void expandARMFeaturesByVersion(CpuInfo& cpu) noexcept {
+ CpuFeatures::ARM& features = cpu.features().arm();
+
+ if (features.hasARMv8_7a()) {
+ features.add(CpuFeatures::ARM::kARMv8_6a);
+ }
+
+ if (features.hasARMv8_6a()) {
+ features.add(CpuFeatures::ARM::kARMv8_5a,
+ CpuFeatures::ARM::kBF16);
+
+ if (features.hasSVE())
+ features.add(CpuFeatures::ARM::kSVE_I8MM);
+ }
+
+ if (features.hasARMv8_5a()) {
+ features.add(CpuFeatures::ARM::kARMv8_4a,
+ CpuFeatures::ARM::kALTNZCV,
+ CpuFeatures::ARM::kBTI,
+ CpuFeatures::ARM::kFRINT,
+ CpuFeatures::ARM::kSB,
+ CpuFeatures::ARM::kSSBS);
+ }
+
+ if (features.hasARMv8_4a()) {
+ features.add(CpuFeatures::ARM::kARMv8_3a,
+ CpuFeatures::ARM::kDIT,
+ CpuFeatures::ARM::kDOTPROD,
+ CpuFeatures::ARM::kFLAGM,
+ CpuFeatures::ARM::kPMU,
+ CpuFeatures::ARM::kRCPC_IMMO);
+ }
+
+ if (features.hasARMv8_3a()) {
+ features.add(CpuFeatures::ARM::kARMv8_2a,
+ CpuFeatures::ARM::kFCMA,
+ CpuFeatures::ARM::kFJCVTZS);
+ }
+
+ if (features.hasARMv8_2a()) {
+ features.add(CpuFeatures::ARM::kARMv8_1a);
+ }
+
+ if (features.hasARMv8_1a()) {
+ features.add(CpuFeatures::ARM::kARMv8a,
+ CpuFeatures::ARM::kCRC32,
+ CpuFeatures::ARM::kLSE,
+ CpuFeatures::ARM::kRDM);
+ }
+
+ if (features.hasARMv8a()) {
+ features.add(CpuFeatures::ARM::kARMv7,
+ CpuFeatures::ARM::kVFPv2,
+ CpuFeatures::ARM::kVFPv3,
+ CpuFeatures::ARM::kVFPv4,
+ CpuFeatures::ARM::kVFP_D32,
+ CpuFeatures::ARM::kASIMD,
+ CpuFeatures::ARM::kIDIVA);
+ }
+}
+
+// CpuInfo - Detect - ARM [Windows]
+// ================================
+
+#if defined(_WIN32)
+struct WinPFPMapping {
+ uint8_t featureId;
+ uint8_t pfpFeatureId;
+};
+
+static ASMJIT_FAVOR_SIZE void detectPFPFeatures(CpuInfo& cpu, const WinPFPMapping* mapping, size_t size) noexcept {
+ for (size_t i = 0; i < size; i++)
+ if (::IsProcessorFeaturePresent(mapping[i].pfpFeatureId))
+ cpu.addFeature(mapping[i].featureId);
+}
+
+//! Detect ARM CPU features on Windows.
+//!
+//! The detection is based on `IsProcessorFeaturePresent()` API call.
+static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
+ cpu._wasDetected = true;
+ populateBaseARMFeatures(cpu);
+
+ CpuFeatures::ARM& features = cpu.features().arm();
+
+ // Win32 for ARM requires ARMv7 with DSP extensions, VFPv3, and uses THUMBv2 by default.
+#if ASMJIT_ARCH_ARM == 32
+ features.add(CpuFeatures::ARM::kTHUMB);
+ features.add(CpuFeatures::ARM::kTHUMBv2);
+ features.add(CpuFeatures::ARM::kARMv6);
+ features.add(CpuFeatures::ARM::kARMv7);
+ features.add(CpuFeatures::ARM::kEDSP);
+ features.add(CpuFeatures::ARM::kVFPv2);
+ features.add(CpuFeatures::ARM::kVFPv3);
+#endif
+
+ // Windows for ARM requires ASIMD.
+ features.add(CpuFeatures::ARM::kASIMD);
+
+ // Detect additional CPU features by calling `IsProcessorFeaturePresent()`.
+ static const WinPFPMapping mapping[] = {
+#if ASMJIT_ARCH_ARM == 32
+ { uint8_t(CpuFeatures::ARM::kVFP_D32) , 18 }, // PF_ARM_VFP_32_REGISTERS_AVAILABLE
+ { uint8_t(CpuFeatures::ARM::kIDIVT) , 24 }, // PF_ARM_DIVIDE_INSTRUCTION_AVAILABLE
+ { uint8_t(CpuFeatures::ARM::kVFPv4) , 27 }, // PF_ARM_FMAC_INSTRUCTIONS_AVAILABLE
+ { uint8_t(CpuFeatures::ARM::kARMv8a) , 29 }, // PF_ARM_V8_INSTRUCTIONS_AVAILABLE
+#endif
+ { uint8_t(CpuFeatures::ARM::kAES) , 30 }, // PF_ARM_V8_CRYPTO_INSTRUCTIONS_AVAILABLE
+ { uint8_t(CpuFeatures::ARM::kCRC32) , 31 }, // PF_ARM_V8_CRC32_INSTRUCTIONS_AVAILABLE
+ { uint8_t(CpuFeatures::ARM::kLSE) , 34 } // PF_ARM_V81_ATOMIC_INSTRUCTIONS_AVAILABLE
+
+ };
+ detectPFPFeatures(cpu, mapping, ASMJIT_ARRAY_SIZE(mapping));
+
+ // Windows provides several instructions under a single flag:
+ if (features.hasAES()) {
+ features.add(CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ }
+
+ expandARMFeaturesByVersion(cpu);
+}
+
+// CpuInfo - Detect - ARM [Linux]
+// ==============================
+
+#elif defined(__linux__)
+
+struct LinuxHWCapMapping {
+ uint8_t featureId;
+ uint8_t hwCapBit;
+};
+
+static ASMJIT_FAVOR_SIZE void detectHWCaps(CpuInfo& cpu, unsigned long type, const LinuxHWCapMapping* mapping, size_t size) noexcept {
+ unsigned long mask = getauxval(type);
+ for (size_t i = 0; i < size; i++)
+ cpu.features().addIf(Support::bitTest(mask, mapping[i].hwCapBit), mapping[i].featureId);
+}
+
+#if ASMJIT_ARCH_ARM == 32
+
+// `AT_HWCAP` provides ARMv7 (and less) related flags.
+static const LinuxHWCapMapping hwCapMapping[] = {
+ { uint8_t(CpuFeatures::ARM::kVFPv2) , 6 }, // HWCAP_VFP
+ { uint8_t(CpuFeatures::ARM::kEDSP) , 7 }, // HWCAP_EDSP
+ { uint8_t(CpuFeatures::ARM::kASIMD) , 12 }, // HWCAP_NEON
+ { uint8_t(CpuFeatures::ARM::kVFPv3) , 13 }, // HWCAP_VFPv3
+ { uint8_t(CpuFeatures::ARM::kVFPv4) , 16 }, // HWCAP_VFPv4
+ { uint8_t(CpuFeatures::ARM::kIDIVA) , 17 }, // HWCAP_IDIVA
+ { uint8_t(CpuFeatures::ARM::kIDIVT) , 18 }, // HWCAP_IDIVT
+ { uint8_t(CpuFeatures::ARM::kVFP_D32) , 19 } // HWCAP_VFPD32
+};
+
+// `AT_HWCAP2` provides ARMv8+ related flags.
+static const LinuxHWCapMapping hwCap2Mapping[] = {
+ { uint8_t(CpuFeatures::ARM::kAES) , 0 }, // HWCAP2_AES
+ { uint8_t(CpuFeatures::ARM::kPMULL) , 1 }, // HWCAP2_PMULL
+ { uint8_t(CpuFeatures::ARM::kSHA1) , 2 }, // HWCAP2_SHA1
+ { uint8_t(CpuFeatures::ARM::kSHA2) , 3 }, // HWCAP2_SHA2
+ { uint8_t(CpuFeatures::ARM::kCRC32) , 4 } // HWCAP2_CRC32
+};
+
+static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
+ cpu._wasDetected = true;
+
+ populateBaseARMFeatures(cpu);
+
+ CpuFeatures::ARM& features = cpu.features().arm();
+
+ detectHWCaps(cpu, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
+ detectHWCaps(cpu, AT_HWCAP2, hwCap2Mapping, ASMJIT_ARRAY_SIZE(hwCap2Mapping));
+
+ // VFPv3 implies VFPv2.
+ if (features.hasVFPv3())
+ features.add(CpuFeatures::ARM::kVFPv2);
+
+ // VFPv2 implies ARMv6.
+ if (features.hasVFPv2())
+ features.add(CpuFeatures::ARM::kARMv6);
+
+ // ARMv7 provides VFPv3|ASIMD.
+ if (features.hasVFPv3() || features.hasASIMD())
+ features.add(CpuFeatures::ARM::kARMv7);
+
+ // ARMv8 provives AES, CRC32, PMULL, SHA1, and SHA2.
+ if (features.hasAES() || features.hasCRC32() || features.hasPMULL() || features.hasSHA1() || features.hasSHA2())
+ features.add(CpuFeatures::ARM::kARMv8a);
+}
+
+#else
+
+// `AT_HWCAP` provides ARMv8+ related flags.
+static const LinuxHWCapMapping hwCapMapping[] = {
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 0 }, // HWCAP_FP
+ */
+ { uint8_t(CpuFeatures::ARM::kASIMD) , 1 }, // HWCAP_ASIMD
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 2 }, // HWCAP_EVTSTRM
+ */
+ { uint8_t(CpuFeatures::ARM::kAES) , 3 }, // HWCAP_AES
+ { uint8_t(CpuFeatures::ARM::kPMULL) , 4 }, // HWCAP_PMULL
+ { uint8_t(CpuFeatures::ARM::kSHA1) , 5 }, // HWCAP_SHA1
+ { uint8_t(CpuFeatures::ARM::kSHA2) , 6 }, // HWCAP_SHA2
+ { uint8_t(CpuFeatures::ARM::kCRC32) , 7 }, // HWCAP_CRC32
+ { uint8_t(CpuFeatures::ARM::kLSE) , 8 }, // HWCAP_ATOMICS
+ { uint8_t(CpuFeatures::ARM::kFP16CONV) , 9 }, // HWCAP_FPHP
+ { uint8_t(CpuFeatures::ARM::kFP16FULL) , 10 }, // HWCAP_ASIMDHP
+ { uint8_t(CpuFeatures::ARM::kCPUID) , 11 }, // HWCAP_CPUID
+ { uint8_t(CpuFeatures::ARM::kRDM) , 12 }, // HWCAP_ASIMDRDM
+ { uint8_t(CpuFeatures::ARM::kFJCVTZS) , 13 }, // HWCAP_JSCVT
+ { uint8_t(CpuFeatures::ARM::kFCMA) , 14 }, // HWCAP_FCMA
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 15 }, // HWCAP_LRCPC
+ { uint8_t(CpuFeatures::ARM::k) , 16 }, // HWCAP_DCPOP
+ */
+ { uint8_t(CpuFeatures::ARM::kSHA3) , 17 }, // HWCAP_SHA3
+ { uint8_t(CpuFeatures::ARM::kSM3) , 18 }, // HWCAP_SM3
+ { uint8_t(CpuFeatures::ARM::kSM4) , 19 }, // HWCAP_SM4
+ { uint8_t(CpuFeatures::ARM::kDOTPROD) , 20 }, // HWCAP_ASIMDDP
+ { uint8_t(CpuFeatures::ARM::kSHA512) , 21 }, // HWCAP_SHA512
+ { uint8_t(CpuFeatures::ARM::kSVE) , 22 }, // HWCAP_SVE
+ { uint8_t(CpuFeatures::ARM::kFP16FML) , 23 }, // HWCAP_ASIMDFHM
+ { uint8_t(CpuFeatures::ARM::kDIT) , 24 }, // HWCAP_DIT
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 25 }, // HWCAP_USCAT
+ { uint8_t(CpuFeatures::ARM::k) , 26 }, // HWCAP_ILRCPC
+ */
+ { uint8_t(CpuFeatures::ARM::kFLAGM) , 27 }, // HWCAP_FLAGM
+ { uint8_t(CpuFeatures::ARM::kSSBS) , 28 }, // HWCAP_SSBS
+ { uint8_t(CpuFeatures::ARM::kSB) , 29 } // HWCAP_SB
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 30 }, // HWCAP_PACA
+ { uint8_t(CpuFeatures::ARM::k) , 31 } // HWCAP_PACG
+ */
+};
+
+// `AT_HWCAP2` provides ARMv8+ related flags.
+static const LinuxHWCapMapping hwCapMapping2[] = {
+ /*
+ { uint8_t(CpuFeatures::ARM::k) , 0 }, // HWCAP2_DCPODP
+ */
+ { uint8_t(CpuFeatures::ARM::kSVE2) , 1 }, // HWCAP2_SVE2
+ { uint8_t(CpuFeatures::ARM::kSVE2_AES) , 2 }, // HWCAP2_SVEAES
+ { uint8_t(CpuFeatures::ARM::kSVE_PMULL) , 3 }, // HWCAP2_SVEPMULL
+ { uint8_t(CpuFeatures::ARM::kSVE2_BITPERM), 4 }, // HWCAP2_SVEBITPERM
+ { uint8_t(CpuFeatures::ARM::kSVE2_SHA3) , 5 }, // HWCAP2_SVESHA3
+ { uint8_t(CpuFeatures::ARM::kSVE2_SM4) , 6 }, // HWCAP2_SVESM4
+ { uint8_t(CpuFeatures::ARM::kALTNZCV) , 7 }, // HWCAP2_FLAGM2
+ { uint8_t(CpuFeatures::ARM::kFRINT) , 8 }, // HWCAP2_FRINT
+ { uint8_t(CpuFeatures::ARM::kSVE_I8MM) , 9 }, // HWCAP2_SVEI8MM
+ { uint8_t(CpuFeatures::ARM::kSVE_F32MM) , 10 }, // HWCAP2_SVEF32MM
+ { uint8_t(CpuFeatures::ARM::kSVE_F64MM) , 11 }, // HWCAP2_SVEF64MM
+ { uint8_t(CpuFeatures::ARM::kSVE_BF16) , 12 }, // HWCAP2_SVEBF16
+ { uint8_t(CpuFeatures::ARM::kI8MM) , 13 }, // HWCAP2_I8MM
+ { uint8_t(CpuFeatures::ARM::kBF16) , 14 }, // HWCAP2_BF16
+ { uint8_t(CpuFeatures::ARM::kDGH) , 15 }, // HWCAP2_DGH
+ { uint8_t(CpuFeatures::ARM::kRNG) , 16 }, // HWCAP2_RNG
+ { uint8_t(CpuFeatures::ARM::kBTI) , 17 }, // HWCAP2_BTI
+ { uint8_t(CpuFeatures::ARM::kMTE) , 18 } // HWCAP2_MTE
+};
+
+static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
+ cpu._wasDetected = true;
+ populateBaseARMFeatures(cpu);
+
+ detectHWCaps(cpu, AT_HWCAP, hwCapMapping, ASMJIT_ARRAY_SIZE(hwCapMapping));
+ detectHWCaps(cpu, AT_HWCAP2, hwCapMapping2, ASMJIT_ARRAY_SIZE(hwCapMapping2));
+}
+
+#endif
+
+// CpuInfo - Detect - ARM [Apple]
+// ==============================
+
+#elif defined(__APPLE__)
+
+namespace AppleHWId {
+ enum CpuFamily : uint32_t {
+ // Generic ARM.
+ kCpuFamily_ARM_9 = 0xE73283AEu,
+ kCpuFamily_ARM_11 = 0x8FF620D8u,
+ kCpuFamily_ARM_12 = 0xBD1B0AE9u,
+ kCpuFamily_ARM_13 = 0x0CC90E64u,
+ kCpuFamily_ARM_14 = 0x96077EF1u,
+ kCpuFamily_ARM_15 = 0xA8511BCAu,
+
+ // Apple design.
+ kCpuFamily_SWIFT = 0x1E2D6381u,
+ kCpuFamily_CYCLONE = 0x37A09642u,
+ kCpuFamily_TYPHOON = 0x2C91A47Eu,
+ kCpuFamily_TWISTER = 0x92FB37C8u,
+ kCpuFamily_HURRICANE = 0x67CEEE93u,
+ kCpuFamily_MONSOON_MISTRAL = 0xE81E7EF6u,
+ kCpuFamily_VORTEX_TEMPEST = 0x07D34B9Fu,
+ kCpuFamily_LIGHTNING_THUNDER = 0x462504D2u,
+ kCpuFamily_FIRESTORM_ICESTORM = 0x1B588BB3u
+ };
+};
+
+static ASMJIT_FAVOR_SIZE uint32_t queryARMCpuFamilyId() noexcept {
+ uint32_t result = 0;
+ size_t size = sizeof(cpuFamily);
+
+ int res = sysctlbyname("hw.cpufamily", &result, &size, nullptr, 0);
+ if (res != 0)
+ return 0;
+ else
+ return result;
+}
+
+static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
+ cpu._wasDetected = true;
+ populateBaseARMFeatures(cpu);
+
+ uint32_t cpuFamilyId = queryARMCpuFamilyId();
+ CpuFeatures::ARM& features = cpu.features().arm();
+
+ switch (cpuFamilyId) {
+ case AppleHWId::kCpuFamily_ARM_9:
+ case AppleHWId::kCpuFamily_ARM_11:
+ case AppleHWId::kCpuFamily_ARM_12:
+ break;
+
+ // ARM Cortex A8.
+ case AppleHWId::kCpuFamily_ARM_13:
+ break;
+
+ // ARM Cortex A9.
+ case AppleHWId::kCpuFamily_ARM_14:
+ break;
+
+ // ARM Cortex A7 - ARMv7k.
+ case AppleHWId::kCpuFamily_ARM_15:
+ features.add(CpuFeatures::ARM::kARMv7);
+ break;
+
+ // Apple A6/A6X - ARMv7s.
+ case AppleHWId::kCpuFamily_SWIFT:
+ features.add(CpuFeatures::ARM::kARMv7);
+ break;
+
+ // Apple A7 - ARMv8.0-A.
+ case AppleHWId::kCpuFamily_CYCLONE:
+ features.add(CpuFeatures::ARM::kARMv8a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ break;
+
+ // Apple A8 - ARMv8.0-A.
+ case AppleHWId::kCpuFamily_TYPHOON:
+ features.add(CpuFeatures::ARM::kARMv8a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ break;
+
+ // Apple A9 - ARMv8.0-A.
+ case AppleHWId::kCpuFamily_TWISTER:
+ features.add(CpuFeatures::ARM::kARMv8a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ break;
+
+ // Apple A10 - ARMv8.1-A.
+ case AppleHWId::kCpuFamily_HURRICANE:
+ features.add(CpuFeatures::ARM::kARMv8_1a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kRDM,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+
+ break;
+
+ // Apple A11 - ARMv8.2-A.
+ case AppleHWId::kCpuFamily_MONSOON_MISTRAL:
+ features.add(CpuFeatures::ARM::kARMv8_2a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kFP16FULL,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ break;
+
+ // Apple A12 - ARMv8.3-A.
+ case AppleHWId::kCpuFamily_VORTEX_TEMPEST:
+ features.add(CpuFeatures::ARM::kARMv8_3a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kFP16FULL,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2);
+ break;
+
+ // Apple A13 - ARMv8.4-A.
+ case AppleHWId::kCpuFamily_LIGHTNING_THUNDER:
+ features.add(CpuFeatures::ARM::kARMv8_4a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kFP16FML,
+ CpuFeatures::ARM::kFP16FULL,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2,
+ CpuFeatures::ARM::kSHA3,
+ CpuFeatures::ARM::kSHA512);
+ break;
+
+ // Apple A14/M1 - ARMv8.5-A.
+ case AppleHWId::kCpuFamily_FIRESTORM_ICESTORM:
+ features.add(CpuFeatures::ARM::kARMv8_4a,
+ CpuFeatures::ARM::kAES,
+ CpuFeatures::ARM::kALTNZCV,
+ CpuFeatures::ARM::kFP16FML,
+ CpuFeatures::ARM::kFP16FULL,
+ CpuFeatures::ARM::kFRINT,
+ CpuFeatures::ARM::kSB,
+ CpuFeatures::ARM::kSHA1,
+ CpuFeatures::ARM::kSHA2,
+ CpuFeatures::ARM::kSHA3,
+ CpuFeatures::ARM::kSHA512,
+ CpuFeatures::ARM::kSSBS);
+ break;
+
+ default:
+ cpu._wasDetected = false;
+ break;
+ }
+
+ expandARMFeaturesByVersion(cpu);
+}
+
+// CpuInfo - Detect - ARM [Unknown]
+// ================================
+
+#else
+
+#if ASMJIT_ARCH_ARM == 64
+ #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown OS with AArch64 CPU)")
+#else
+ #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown OS with ARM CPU)")
+#endif
+
+static ASMJIT_FAVOR_SIZE void detectARMCpu(CpuInfo& cpu) noexcept {
+ populateBaseARMFeatures(cpu);
+ detectARMFeaturesViaCompilerFlags(cpu);
+ expandARMFeaturesByVersion(cpu);
+}
+#endif
+
+#endif
+
+// CpuInfo - Detect - Host
+// =======================
static uint32_t cpuInfoInitialized;
static CpuInfo cpuInfoGlobal(Globals::NoInit);
const CpuInfo& CpuInfo::host() noexcept {
- // This should never cause a problem as the resulting information should
- // always be the same.
+ // This should never cause a problem as the resulting information should always be the same. In the worst case we
+ // would just overwrite it non-atomically.
if (!cpuInfoInitialized) {
CpuInfo cpuInfoLocal;
-#if !defined(ASMJIT_NO_X86) && ASMJIT_ARCH_X86
- x86::detectCpu(cpuInfoLocal);
-#endif
+ cpuInfoLocal._arch = Arch::kHost;
+ cpuInfoLocal._subArch = SubArch::kHost;
-#if defined(ASMJIT_BUILD_ARM) && ASMJIT_ARCH_ARM
- arm::detectCpu(cpuInfoLocal);
+#if ASMJIT_ARCH_X86
+ detectX86Cpu(cpuInfoLocal);
+#elif ASMJIT_ARCH_ARM
+ detectARMCpu(cpuInfoLocal);
+#else
+ #pragma message("[asmjit] Disabling runtime CPU detection - unsupported OS/CPU combination (Unknown CPU)")
#endif
cpuInfoLocal._hwThreadCount = detectHWThreadCount();
diff --git a/src/asmjit/core/cpuinfo.h b/src/asmjit/core/cpuinfo.h
index 83bb8c1..974fb3e 100644
--- a/src/asmjit/core/cpuinfo.h
+++ b/src/asmjit/core/cpuinfo.h
@@ -1,52 +1,679 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_CPUINFO_H_INCLUDED
#define ASMJIT_CORE_CPUINFO_H_INCLUDED
#include "../core/archtraits.h"
-#include "../core/features.h"
+#include "../core/environment.h"
#include "../core/globals.h"
#include "../core/string.h"
+#include "../core/support.h"
ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [asmjit::CpuInfo]
-// ============================================================================
+//! CPU features information.
+//!
+//! 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 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 _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(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
+ 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
+ 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
+ ASMJIT_FORCE_INLINE void add(const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
+ add(featureId);
+ add(std::forward(otherFeatureIds)...);
+ }
+
+ template
+ 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
+ ASMJIT_FORCE_INLINE void addIf(bool condition, const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
+ addIf(condition, featureId);
+ addIf(condition, std::forward(otherFeatureIds)...);
+ }
+
+ //! Removes the given CPU `featureId` from the list of features.
+ template
+ 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
+ ASMJIT_FORCE_INLINE void remove(const FeatureId& featureId, Args&&... otherFeatureIds) noexcept {
+ remove(featureId);
+ remove(std::forward(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
+ inline T& data() noexcept { return static_cast(_data); }
+
+ //! Casts this base class into a derived type `T` (const).
+ template
+ inline const T& data() const noexcept { return static_cast(_data); }
+
+ //! Returns CpuFeatures::Data as \ref CpuFeatures::X86.
+ inline X86& x86() noexcept { return data(); }
+ //! Returns CpuFeatures::Data as \ref CpuFeatures::X86 (const).
+ inline const X86& x86() const noexcept { return data(); }
+
+ //! Returns CpuFeatures::Data as \ref CpuFeatures::ARM.
+ inline ARM& arm() noexcept { return data(); }
+ //! Returns CpuFeatures::Data as \ref CpuFeatures::ARM (const).
+ inline const ARM& arm() const noexcept { return data(); }
+
+ //! 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
+ 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
+ inline void add(Args&&... args) noexcept { return _data.add(std::forward(args)...); }
+
+ //! Adds the given CPU `featureId` to the list of features if `condition` is true.
+ template
+ inline void addIf(bool condition, Args&&... args) noexcept { return _data.addIf(condition, std::forward(args)...); }
+
+ //! Removes the given CPU `featureId` from the list of features.
+ template
+ inline void remove(Args&&... args) noexcept { return _data.remove(std::forward(args)...); }
+
+ //! Tests whether this CPU features matches `other`.
+ inline bool eq(const CpuFeatures& other) const noexcept { return _data.eq(other._data); }
+
+ //! \}
+};
//! CPU information.
class CpuInfo {
public:
+ //! \name Members
+ //! \{
+
//! Architecture.
- uint8_t _arch;
+ Arch _arch;
//! 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.
- uint16_t _reserved;
+ uint8_t _reserved;
//! CPU family ID.
uint32_t _familyId;
//! CPU model ID.
@@ -69,7 +696,9 @@ public:
//! CPU brand string.
FixedString<64> _brand;
//! CPU features.
- BaseFeatures _features;
+ CpuFeatures _features;
+
+ //! \}
//! \name Construction & Destruction
//! \{
@@ -83,10 +712,10 @@ public:
//! Returns the host CPU information.
ASMJIT_API static const CpuInfo& host() noexcept;
- //! Initializes CpuInfo to the given architecture, see \ref Environment.
- inline void initArch(uint32_t arch, uint32_t subArch = 0u) noexcept {
- _arch = uint8_t(arch);
- _subArch = uint8_t(subArch);
+ //! Initializes CpuInfo architecture and sub-architecture members to `arch` and `subArch`, respectively.
+ inline void initArch(Arch arch, SubArch subArch = SubArch::kUnknown) noexcept {
+ _arch = arch;
+ _subArch = subArch;
}
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
@@ -103,46 +732,76 @@ public:
//! \name Accessors
//! \{
- //! Returns the CPU architecture id, see \ref Environment::Arch.
- inline uint32_t arch() const noexcept { return _arch; }
- //! Returns the CPU architecture sub-id, see \ref Environment::SubArch.
- inline uint32_t subArch() const noexcept { return _subArch; }
+ //! Returns the CPU architecture this information relates to.
+ inline Arch arch() const noexcept { return _arch; }
+
+ //! 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.
+ //!
+ //! Family identifier matches the FamilyId read by using CPUID on X86 architecture.
inline uint32_t familyId() const noexcept { return _familyId; }
+
//! 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; }
//! 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; }
+
//! 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; }
+
//! Returns the processor type.
+ //!
+ //! Family identifier matches the ProcessorType read by using CPUID on X86 architecture.
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; }
//! Returns the size of a cache line flush.
inline uint32_t cacheLineSize() const noexcept { return _cacheLineSize; }
+
//! Returns number of hardware threads available.
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; }
- //! 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); }
- //! Returns the CPU brand string.
+ //! Returns a CPU brand string.
inline const char* brand() const noexcept { return _brand.str; }
- //! Returns all CPU features as `BaseFeatures`, cast to your arch-specific class
- //! if needed.
- template
- inline const T& features() const noexcept { return _features.as(); }
+ //! Returns CPU features.
+ inline CpuFeatures& features() noexcept { return _features; }
+ //! Returns CPU features (const).
+ inline const CpuFeatures& features() const noexcept { return _features; }
//! Tests whether the CPU has the given `feature`.
- inline bool hasFeature(uint32_t featureId) const noexcept { return _features.has(featureId); }
- //! Adds the given CPU `feature` to the list of this CpuInfo features.
- inline CpuInfo& addFeature(uint32_t featureId) noexcept { _features.add(featureId); return *this; }
+ template
+ inline bool hasFeature(const FeatureId& featureId) const noexcept { return _features.has(featureId); }
+
+ //! Adds the given CPU `featureId` to the list of features.
+ template
+ inline void addFeature(Args&&... args) noexcept { return _features.add(std::forward(args)...); }
+
+ //! Removes the given CPU `featureId` from the list of features.
+ template
+ inline void removeFeature(Args&&... args) noexcept { return _features.remove(std::forward(args)...); }
//! \}
};
diff --git a/src/asmjit/core/datatypes.h b/src/asmjit/core/datatypes.h
deleted file mode 100644
index 2f6cc1e..0000000
--- a/src/asmjit/core/datatypes.h
+++ /dev/null
@@ -1,1071 +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_DATATYPES_H_INCLUDED
-#define ASMJIT_CORE_DATATYPES_H_INCLUDED
-
-#include "../core/globals.h"
-
-#ifndef ASMJIT_NO_DEPRECATED
-
-ASMJIT_BEGIN_NAMESPACE
-
-// ============================================================================
-// [asmjit::Data64]
-// ============================================================================
-
-//! 64-bit data useful for creating SIMD constants.
-union ASMJIT_DEPRECATED_STRUCT("Data64 is deprecated and will be removed in the future") Data64 {
- //! Array of eight 8-bit signed integers.
- int8_t sb[8];
- //! Array of eight 8-bit unsigned integers.
- uint8_t ub[8];
- //! Array of four 16-bit signed integers.
- int16_t sw[4];
- //! Array of four 16-bit unsigned integers.
- uint16_t uw[4];
- //! Array of two 32-bit signed integers.
- int32_t sd[2];
- //! Array of two 32-bit unsigned integers.
- uint32_t ud[2];
- //! Array of one 64-bit signed integer.
- int64_t sq[1];
- //! Array of one 64-bit unsigned integer.
- uint64_t uq[1];
-
- //! Array of two SP-FP values.
- float sf[2];
- //! Array of one DP-FP value.
- double df[1];
-
- //! \name Construction & Destruction
- //! \{
-
- //! Sets all eight 8-bit signed integers.
- static inline Data64 fromI8(int8_t x0) noexcept {
- Data64 self;
- self.setI8(x0);
- return self;
- }
-
- //! Sets all eight 8-bit unsigned integers.
- static inline Data64 fromU8(uint8_t x0) noexcept {
- Data64 self;
- self.setU8(x0);
- return self;
- }
-
- //! Sets all eight 8-bit signed integers.
- static inline Data64 fromI8(
- int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept {
-
- Data64 self;
- self.setI8(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all eight 8-bit unsigned integers.
- static inline Data64 fromU8(
- uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept {
-
- Data64 self;
- self.setU8(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all four 16-bit signed integers.
- static inline Data64 fromI16(int16_t x0) noexcept {
- Data64 self;
- self.setI16(x0);
- return self;
- }
-
- //! Sets all four 16-bit unsigned integers.
- static inline Data64 fromU16(uint16_t x0) noexcept {
- Data64 self;
- self.setU16(x0);
- return self;
- }
-
- //! Sets all four 16-bit signed integers.
- static inline Data64 fromI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept {
- Data64 self;
- self.setI16(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all four 16-bit unsigned integers.
- static inline Data64 fromU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept {
- Data64 self;
- self.setU16(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all two 32-bit signed integers.
- static inline Data64 fromI32(int32_t x0) noexcept {
- Data64 self;
- self.setI32(x0);
- return self;
- }
-
- //! Sets all two 32-bit unsigned integers.
- static inline Data64 fromU32(uint32_t x0) noexcept {
- Data64 self;
- self.setU32(x0);
- return self;
- }
-
- //! Sets all two 32-bit signed integers.
- static inline Data64 fromI32(int32_t x0, int32_t x1) noexcept {
- Data64 self;
- self.setI32(x0, x1);
- return self;
- }
-
- //! Sets all two 32-bit unsigned integers.
- static inline Data64 fromU32(uint32_t x0, uint32_t x1) noexcept {
- Data64 self;
- self.setU32(x0, x1);
- return self;
- }
-
- //! Sets 64-bit signed integer.
- static inline Data64 fromI64(int64_t x0) noexcept {
- Data64 self;
- self.setI64(x0);
- return self;
- }
-
- //! Sets 64-bit unsigned integer.
- static inline Data64 fromU64(uint64_t x0) noexcept {
- Data64 self;
- self.setU64(x0);
- return self;
- }
-
- //! Sets all two SP-FP values.
- static inline Data64 fromF32(float x0) noexcept {
- Data64 self;
- self.setF32(x0);
- return self;
- }
-
- //! Sets all two SP-FP values.
- static inline Data64 fromF32(float x0, float x1) noexcept {
- Data64 self;
- self.setF32(x0, x1);
- return self;
- }
-
- //! Sets all two SP-FP values.
- static inline Data64 fromF64(double x0) noexcept {
- Data64 self;
- self.setF64(x0);
- return self;
- }
-
- //! \}
-
- //! \name Accessors
- //! \{
-
- //! Sets all eight 8-bit signed integers.
- inline void setI8(int8_t x0) noexcept {
- setU8(uint8_t(x0));
- }
-
- //! Sets all eight 8-bit unsigned integers.
- inline void setU8(uint8_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0101010101010101u;
- uq[0] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x01010101u;
- ud[0] = xd;
- ud[1] = xd;
- }
- }
-
- //! Sets all eight 8-bit signed integers.
- inline void setI8(
- int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) noexcept {
-
- sb[0] = x0; sb[1] = x1; sb[2] = x2; sb[3] = x3;
- sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7;
- }
-
- //! Sets all eight 8-bit unsigned integers.
- inline void setU8(
- uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) noexcept {
-
- ub[0] = x0; ub[1] = x1; ub[2] = x2; ub[3] = x3;
- ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7;
- }
-
- //! Sets all four 16-bit signed integers.
- inline void setI16(int16_t x0) noexcept {
- setU16(uint16_t(x0));
- }
-
- //! Sets all four 16-bit unsigned integers.
- inline void setU16(uint16_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0001000100010001u;
- uq[0] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x00010001u;
- ud[0] = xd;
- ud[1] = xd;
- }
- }
-
- //! Sets all four 16-bit signed integers.
- inline void setI16(int16_t x0, int16_t x1, int16_t x2, int16_t x3) noexcept {
- sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3;
- }
-
- //! Sets all four 16-bit unsigned integers.
- inline void setU16(uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) noexcept {
- uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3;
- }
-
- //! Sets all two 32-bit signed integers.
- inline void setI32(int32_t x0) noexcept {
- sd[0] = x0; sd[1] = x0;
- }
-
- //! Sets all two 32-bit unsigned integers.
- inline void setU32(uint32_t x0) noexcept {
- ud[0] = x0; ud[1] = x0;
- }
-
- //! Sets all two 32-bit signed integers.
- inline void setI32(int32_t x0, int32_t x1) noexcept {
- sd[0] = x0; sd[1] = x1;
- }
-
- //! Sets all two 32-bit unsigned integers.
- inline void setU32(uint32_t x0, uint32_t x1) noexcept {
- ud[0] = x0; ud[1] = x1;
- }
-
- //! Sets 64-bit signed integer.
- inline void setI64(int64_t x0) noexcept {
- sq[0] = x0;
- }
-
- //! Sets 64-bit unsigned integer.
- inline void setU64(uint64_t x0) noexcept {
- uq[0] = x0;
- }
-
- //! Sets all two SP-FP values.
- inline void setF32(float x0) noexcept {
- sf[0] = x0; sf[1] = x0;
- }
-
- //! Sets all two SP-FP values.
- inline void setF32(float x0, float x1) noexcept {
- sf[0] = x0; sf[1] = x1;
- }
-
- //! Sets all two SP-FP values.
- inline void setF64(double x0) noexcept {
- df[0] = x0;
- }
-};
-
-// ============================================================================
-// [asmjit::Data128]
-// ============================================================================
-
-//! 128-bit data useful for creating SIMD constants.
-union ASMJIT_DEPRECATED_STRUCT("Data128 is deprecated and will be removed in the future") Data128 {
- //! Array of sixteen 8-bit signed integers.
- int8_t sb[16];
- //! Array of sixteen 8-bit unsigned integers.
- uint8_t ub[16];
- //! Array of eight 16-bit signed integers.
- int16_t sw[8];
- //! Array of eight 16-bit unsigned integers.
- uint16_t uw[8];
- //! Array of four 32-bit signed integers.
- int32_t sd[4];
- //! Array of four 32-bit unsigned integers.
- uint32_t ud[4];
- //! Array of two 64-bit signed integers.
- int64_t sq[2];
- //! Array of two 64-bit unsigned integers.
- uint64_t uq[2];
-
- //! Array of four 32-bit single precision floating points.
- float sf[4];
- //! Array of two 64-bit double precision floating points.
- double df[2];
-
- //! \name Construction & Destruction
- //! \{
-
- //! Sets all sixteen 8-bit signed integers.
- static inline Data128 fromI8(int8_t x0) noexcept {
- Data128 self;
- self.setI8(x0);
- return self;
- }
-
- //! Sets all sixteen 8-bit unsigned integers.
- static inline Data128 fromU8(uint8_t x0) noexcept {
- Data128 self;
- self.setU8(x0);
- return self;
- }
-
- //! Sets all sixteen 8-bit signed integers.
- static inline Data128 fromI8(
- int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
- int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
- int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
- int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept {
-
- Data128 self;
- self.setI8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
- return self;
- }
-
- //! Sets all sixteen 8-bit unsigned integers.
- static inline Data128 fromU8(
- uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
- uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
- uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
- uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept {
-
- Data128 self;
- self.setU8(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
- return self;
- }
-
- //! Sets all eight 16-bit signed integers.
- static inline Data128 fromI16(int16_t x0) noexcept {
- Data128 self;
- self.setI16(x0);
- return self;
- }
-
- //! Sets all eight 16-bit unsigned integers.
- static inline Data128 fromU16(uint16_t x0) noexcept {
- Data128 self;
- self.setU16(x0);
- return self;
- }
-
- //! Sets all eight 16-bit signed integers.
- static inline Data128 fromI16(
- int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept {
-
- Data128 self;
- self.setI16(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all eight 16-bit unsigned integers.
- static inline Data128 fromU16(
- uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept {
-
- Data128 self;
- self.setU16(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all four 32-bit signed integers.
- static inline Data128 fromI32(int32_t x0) noexcept {
- Data128 self;
- self.setI32(x0);
- return self;
- }
-
- //! Sets all four 32-bit unsigned integers.
- static inline Data128 fromU32(uint32_t x0) noexcept {
- Data128 self;
- self.setU32(x0);
- return self;
- }
-
- //! Sets all four 32-bit signed integers.
- static inline Data128 fromI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept {
- Data128 self;
- self.setI32(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all four 32-bit unsigned integers.
- static inline Data128 fromU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept {
- Data128 self;
- self.setU32(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all two 64-bit signed integers.
- static inline Data128 fromI64(int64_t x0) noexcept {
- Data128 self;
- self.setI64(x0);
- return self;
- }
-
- //! Sets all two 64-bit unsigned integers.
- static inline Data128 fromU64(uint64_t x0) noexcept {
- Data128 self;
- self.setU64(x0);
- return self;
- }
-
- //! Sets all two 64-bit signed integers.
- static inline Data128 fromI64(int64_t x0, int64_t x1) noexcept {
- Data128 self;
- self.setI64(x0, x1);
- return self;
- }
-
- //! Sets all two 64-bit unsigned integers.
- static inline Data128 fromU64(uint64_t x0, uint64_t x1) noexcept {
- Data128 self;
- self.setU64(x0, x1);
- return self;
- }
-
- //! Sets all four SP-FP floats.
- static inline Data128 fromF32(float x0) noexcept {
- Data128 self;
- self.setF32(x0);
- return self;
- }
-
- //! Sets all four SP-FP floats.
- static inline Data128 fromF32(float x0, float x1, float x2, float x3) noexcept {
- Data128 self;
- self.setF32(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all two DP-FP floats.
- static inline Data128 fromF64(double x0) noexcept {
- Data128 self;
- self.setF64(x0);
- return self;
- }
-
- //! Sets all two DP-FP floats.
- static inline Data128 fromF64(double x0, double x1) noexcept {
- Data128 self;
- self.setF64(x0, x1);
- return self;
- }
-
- //! \}
-
- //! \name Accessors
- //! \{
-
- //! Sets all sixteen 8-bit signed integers.
- inline void setI8(int8_t x0) noexcept {
- setU8(uint8_t(x0));
- }
-
- //! Sets all sixteen 8-bit unsigned integers.
- inline void setU8(uint8_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0101010101010101u;
- uq[0] = xq;
- uq[1] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x01010101u;
- ud[0] = xd;
- ud[1] = xd;
- ud[2] = xd;
- ud[3] = xd;
- }
- }
-
- //! Sets all sixteen 8-bit signed integers.
- inline void setI8(
- int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
- int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
- int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
- int8_t x12, int8_t x13, int8_t x14, int8_t x15) noexcept {
-
- sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ;
- sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ;
- sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11;
- sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15;
- }
-
- //! Sets all sixteen 8-bit unsigned integers.
- inline void setU8(
- uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
- uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
- uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
- uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) noexcept {
-
- ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ;
- ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ;
- ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11;
- ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15;
- }
-
- //! Sets all eight 16-bit signed integers.
- inline void setI16(int16_t x0) noexcept {
- setU16(uint16_t(x0));
- }
-
- //! Sets all eight 16-bit unsigned integers.
- inline void setU16(uint16_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0001000100010001u;
- uq[0] = xq;
- uq[1] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x00010001u;
- ud[0] = xd;
- ud[1] = xd;
- ud[2] = xd;
- ud[3] = xd;
- }
- }
-
- //! Sets all eight 16-bit signed integers.
- inline void setI16(
- int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) noexcept {
-
- sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3;
- sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7;
- }
-
- //! Sets all eight 16-bit unsigned integers.
- inline void setU16(
- uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) noexcept {
-
- uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3;
- uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7;
- }
-
- //! Sets all four 32-bit signed integers.
- inline void setI32(int32_t x0) noexcept {
- setU32(uint32_t(x0));
- }
-
- //! Sets all four 32-bit unsigned integers.
- inline void setU32(uint32_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t t = (uint64_t(x0) << 32) + x0;
- uq[0] = t;
- uq[1] = t;
- }
- else {
- ud[0] = x0;
- ud[1] = x0;
- ud[2] = x0;
- ud[3] = x0;
- }
- }
-
- //! Sets all four 32-bit signed integers.
- inline void setI32(int32_t x0, int32_t x1, int32_t x2, int32_t x3) noexcept {
- sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3;
- }
-
- //! Sets all four 32-bit unsigned integers.
- inline void setU32(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) noexcept {
- ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3;
- }
-
- //! Sets all two 64-bit signed integers.
- inline void setI64(int64_t x0) noexcept {
- sq[0] = x0; sq[1] = x0;
- }
-
- //! Sets all two 64-bit unsigned integers.
- inline void setU64(uint64_t x0) noexcept {
- uq[0] = x0; uq[1] = x0;
- }
-
- //! Sets all two 64-bit signed integers.
- inline void setI64(int64_t x0, int64_t x1) noexcept {
- sq[0] = x0; sq[1] = x1;
- }
-
- //! Sets all two 64-bit unsigned integers.
- inline void setU64(uint64_t x0, uint64_t x1) noexcept {
- uq[0] = x0; uq[1] = x1;
- }
-
- //! Sets all four SP-FP floats.
- inline void setF32(float x0) noexcept {
- sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0;
- }
-
- //! Sets all four SP-FP floats.
- inline void setF32(float x0, float x1, float x2, float x3) noexcept {
- sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3;
- }
-
- //! Sets all two DP-FP floats.
- inline void setF64(double x0) noexcept {
- df[0] = x0; df[1] = x0;
- }
-
- //! Sets all two DP-FP floats.
- inline void setF64(double x0, double x1) noexcept {
- df[0] = x0; df[1] = x1;
- }
-};
-
-// ============================================================================
-// [asmjit::Data256]
-// ============================================================================
-
-//! 256-bit data useful for creating SIMD constants.
-union ASMJIT_DEPRECATED_STRUCT("Data256 is deprecated and will be removed in the future") Data256 {
- //! Array of thirty two 8-bit signed integers.
- int8_t sb[32];
- //! Array of thirty two 8-bit unsigned integers.
- uint8_t ub[32];
- //! Array of sixteen 16-bit signed integers.
- int16_t sw[16];
- //! Array of sixteen 16-bit unsigned integers.
- uint16_t uw[16];
- //! Array of eight 32-bit signed integers.
- int32_t sd[8];
- //! Array of eight 32-bit unsigned integers.
- uint32_t ud[8];
- //! Array of four 64-bit signed integers.
- int64_t sq[4];
- //! Array of four 64-bit unsigned integers.
- uint64_t uq[4];
-
- //! Array of eight 32-bit single precision floating points.
- float sf[8];
- //! Array of four 64-bit double precision floating points.
- double df[4];
-
- //! \name Construction & Destruction
- //! \{
-
- //! Sets all thirty two 8-bit signed integers.
- static inline Data256 fromI8(int8_t x0) noexcept {
- Data256 self;
- self.setI8(x0);
- return self;
- }
-
- //! Sets all thirty two 8-bit unsigned integers.
- static inline Data256 fromU8(uint8_t x0) noexcept {
- Data256 self;
- self.setU8(x0);
- return self;
- }
-
- //! Sets all thirty two 8-bit signed integers.
- static inline Data256 fromI8(
- int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
- int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
- int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
- int8_t x12, int8_t x13, int8_t x14, int8_t x15,
- int8_t x16, int8_t x17, int8_t x18, int8_t x19,
- int8_t x20, int8_t x21, int8_t x22, int8_t x23,
- int8_t x24, int8_t x25, int8_t x26, int8_t x27,
- int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept {
-
- Data256 self;
- self.setI8(
- x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15,
- x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31);
- return self;
- }
-
- //! Sets all thirty two 8-bit unsigned integers.
- static inline Data256 fromU8(
- uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
- uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
- uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
- uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15,
- uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19,
- uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23,
- uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27,
- uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept {
-
- Data256 self;
- self.setU8(
- x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15,
- x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31);
- return self;
- }
-
- //! Sets all sixteen 16-bit signed integers.
- static inline Data256 fromI16(int16_t x0) noexcept {
- Data256 self;
- self.setI16(x0);
- return self;
- }
-
- //! Sets all sixteen 16-bit unsigned integers.
- static inline Data256 fromU16(uint16_t x0) noexcept {
- Data256 self;
- self.setU16(x0);
- return self;
- }
-
- //! Sets all sixteen 16-bit signed integers.
- static inline Data256 fromI16(
- int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7 ,
- int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept {
-
- Data256 self;
- self.setI16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
- return self;
- }
-
- //! Sets all sixteen 16-bit unsigned integers.
- static inline Data256 fromU16(
- uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7 ,
- uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept {
-
- Data256 self;
- self.setU16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
- return self;
- }
-
- //! Sets all eight 32-bit signed integers.
- static inline Data256 fromI32(int32_t x0) noexcept {
- Data256 self;
- self.setI32(x0);
- return self;
- }
-
- //! Sets all eight 32-bit unsigned integers.
- static inline Data256 fromU32(uint32_t x0) noexcept {
- Data256 self;
- self.setU32(x0);
- return self;
- }
-
- //! Sets all eight 32-bit signed integers.
- static inline Data256 fromI32(
- int32_t x0, int32_t x1, int32_t x2, int32_t x3,
- int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept {
-
- Data256 self;
- self.setI32(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all eight 32-bit unsigned integers.
- static inline Data256 fromU32(
- uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3,
- uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept {
-
- Data256 self;
- self.setU32(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all four 64-bit signed integers.
- static inline Data256 fromI64(int64_t x0) noexcept {
- Data256 self;
- self.setI64(x0);
- return self;
- }
-
- //! Sets all four 64-bit unsigned integers.
- static inline Data256 fromU64(uint64_t x0) noexcept {
- Data256 self;
- self.setU64(x0);
- return self;
- }
-
- //! Sets all four 64-bit signed integers.
- static inline Data256 fromI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept {
- Data256 self;
- self.setI64(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all four 64-bit unsigned integers.
- static inline Data256 fromU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept {
- Data256 self;
- self.setU64(x0, x1, x2, x3);
- return self;
- }
-
- //! Sets all eight SP-FP floats.
- static inline Data256 fromF32(float x0) noexcept {
- Data256 self;
- self.setF32(x0);
- return self;
- }
-
- //! Sets all eight SP-FP floats.
- static inline Data256 fromF32(
- float x0, float x1, float x2, float x3,
- float x4, float x5, float x6, float x7) noexcept {
-
- Data256 self;
- self.setF32(x0, x1, x2, x3, x4, x5, x6, x7);
- return self;
- }
-
- //! Sets all four DP-FP floats.
- static inline Data256 fromF64(double x0) noexcept {
- Data256 self;
- self.setF64(x0);
- return self;
- }
-
- //! Sets all four DP-FP floats.
- static inline Data256 fromF64(double x0, double x1, double x2, double x3) noexcept {
- Data256 self;
- self.setF64(x0, x1, x2, x3);
- return self;
- }
-
- //! \}
-
- //! \name Accessors
- //! \{
-
- //! Sets all thirty two 8-bit signed integers.
- inline void setI8(int8_t x0) noexcept {
- setU8(uint8_t(x0));
- }
-
- //! Sets all thirty two 8-bit unsigned integers.
- inline void setU8(uint8_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0101010101010101u;
- uq[0] = xq;
- uq[1] = xq;
- uq[2] = xq;
- uq[3] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x01010101u;
- ud[0] = xd;
- ud[1] = xd;
- ud[2] = xd;
- ud[3] = xd;
- ud[4] = xd;
- ud[5] = xd;
- ud[6] = xd;
- ud[7] = xd;
- }
- }
-
- //! Sets all thirty two 8-bit signed integers.
- inline void setI8(
- int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
- int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
- int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
- int8_t x12, int8_t x13, int8_t x14, int8_t x15,
- int8_t x16, int8_t x17, int8_t x18, int8_t x19,
- int8_t x20, int8_t x21, int8_t x22, int8_t x23,
- int8_t x24, int8_t x25, int8_t x26, int8_t x27,
- int8_t x28, int8_t x29, int8_t x30, int8_t x31) noexcept {
-
- sb[0 ] = x0 ; sb[1 ] = x1 ; sb[2 ] = x2 ; sb[3 ] = x3 ;
- sb[4 ] = x4 ; sb[5 ] = x5 ; sb[6 ] = x6 ; sb[7 ] = x7 ;
- sb[8 ] = x8 ; sb[9 ] = x9 ; sb[10] = x10; sb[11] = x11;
- sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15;
- sb[16] = x16; sb[17] = x17; sb[18] = x18; sb[19] = x19;
- sb[20] = x20; sb[21] = x21; sb[22] = x22; sb[23] = x23;
- sb[24] = x24; sb[25] = x25; sb[26] = x26; sb[27] = x27;
- sb[28] = x28; sb[29] = x29; sb[30] = x30; sb[31] = x31;
- }
-
- //! Sets all thirty two 8-bit unsigned integers.
- inline void setU8(
- uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
- uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
- uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
- uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15,
- uint8_t x16, uint8_t x17, uint8_t x18, uint8_t x19,
- uint8_t x20, uint8_t x21, uint8_t x22, uint8_t x23,
- uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27,
- uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) noexcept {
-
- ub[0 ] = x0 ; ub[1 ] = x1 ; ub[2 ] = x2 ; ub[3 ] = x3 ;
- ub[4 ] = x4 ; ub[5 ] = x5 ; ub[6 ] = x6 ; ub[7 ] = x7 ;
- ub[8 ] = x8 ; ub[9 ] = x9 ; ub[10] = x10; ub[11] = x11;
- ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15;
- ub[16] = x16; ub[17] = x17; ub[18] = x18; ub[19] = x19;
- ub[20] = x20; ub[21] = x21; ub[22] = x22; ub[23] = x23;
- ub[24] = x24; ub[25] = x25; ub[26] = x26; ub[27] = x27;
- ub[28] = x28; ub[29] = x29; ub[30] = x30; ub[31] = x31;
- }
-
- //! Sets all sixteen 16-bit signed integers.
- inline void setI16(int16_t x0) noexcept {
- setU16(uint16_t(x0));
- }
-
- //! Sets all eight 16-bit unsigned integers.
- inline void setU16(uint16_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = uint64_t(x0) * 0x0001000100010001u;
- uq[0] = xq;
- uq[1] = xq;
- uq[2] = xq;
- uq[3] = xq;
- }
- else {
- uint32_t xd = uint32_t(x0) * 0x00010001u;
- ud[0] = xd;
- ud[1] = xd;
- ud[2] = xd;
- ud[3] = xd;
- ud[4] = xd;
- ud[5] = xd;
- ud[6] = xd;
- ud[7] = xd;
- }
- }
-
- //! Sets all sixteen 16-bit signed integers.
- inline void setI16(
- int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7,
- int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) noexcept {
-
- sw[0 ] = x0 ; sw[1 ] = x1 ; sw[2 ] = x2 ; sw[3 ] = x3 ;
- sw[4 ] = x4 ; sw[5 ] = x5 ; sw[6 ] = x6 ; sw[7 ] = x7 ;
- sw[8 ] = x8 ; sw[9 ] = x9 ; sw[10] = x10; sw[11] = x11;
- sw[12] = x12; sw[13] = x13; sw[14] = x14; sw[15] = x15;
- }
-
- //! Sets all sixteen 16-bit unsigned integers.
- inline void setU16(
- uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7,
- uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) noexcept {
-
- uw[0 ] = x0 ; uw[1 ] = x1 ; uw[2 ] = x2 ; uw[3 ] = x3 ;
- uw[4 ] = x4 ; uw[5 ] = x5 ; uw[6 ] = x6 ; uw[7 ] = x7 ;
- uw[8 ] = x8 ; uw[9 ] = x9 ; uw[10] = x10; uw[11] = x11;
- uw[12] = x12; uw[13] = x13; uw[14] = x14; uw[15] = x15;
- }
-
- //! Sets all eight 32-bit signed integers.
- inline void setI32(int32_t x0) noexcept {
- setU32(uint32_t(x0));
- }
-
- //! Sets all eight 32-bit unsigned integers.
- inline void setU32(uint32_t x0) noexcept {
- if (ASMJIT_ARCH_BITS >= 64) {
- uint64_t xq = (uint64_t(x0) << 32) + x0;
- uq[0] = xq;
- uq[1] = xq;
- uq[2] = xq;
- uq[3] = xq;
- }
- else {
- ud[0] = x0;
- ud[1] = x0;
- ud[2] = x0;
- ud[3] = x0;
- ud[4] = x0;
- ud[5] = x0;
- ud[6] = x0;
- ud[7] = x0;
- }
- }
-
- //! Sets all eight 32-bit signed integers.
- inline void setI32(
- int32_t x0, int32_t x1, int32_t x2, int32_t x3,
- int32_t x4, int32_t x5, int32_t x6, int32_t x7) noexcept {
-
- sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3;
- sd[4] = x4; sd[5] = x5; sd[6] = x6; sd[7] = x7;
- }
-
- //! Sets all eight 32-bit unsigned integers.
- inline void setU32(
- uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3,
- uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) noexcept {
-
- ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3;
- ud[4] = x4; ud[5] = x5; ud[6] = x6; ud[7] = x7;
- }
-
- //! Sets all four 64-bit signed integers.
- inline void setI64(int64_t x0) noexcept {
- sq[0] = x0; sq[1] = x0; sq[2] = x0; sq[3] = x0;
- }
-
- //! Sets all four 64-bit unsigned integers.
- inline void setU64(uint64_t x0) noexcept {
- uq[0] = x0; uq[1] = x0; uq[2] = x0; uq[3] = x0;
- }
-
- //! Sets all four 64-bit signed integers.
- inline void setI64(int64_t x0, int64_t x1, int64_t x2, int64_t x3) noexcept {
- sq[0] = x0; sq[1] = x1; sq[2] = x2; sq[3] = x3;
- }
-
- //! Sets all four 64-bit unsigned integers.
- inline void setU64(uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) noexcept {
- uq[0] = x0; uq[1] = x1; uq[2] = x2; uq[3] = x3;
- }
-
- //! Sets all eight SP-FP floats.
- inline void setF32(float x0) noexcept {
- sf[0] = x0; sf[1] = x0; sf[2] = x0; sf[3] = x0;
- sf[4] = x0; sf[5] = x0; sf[6] = x0; sf[7] = x0;
- }
-
- //! Sets all eight SP-FP floats.
- inline void setF32(
- float x0, float x1, float x2, float x3,
- float x4, float x5, float x6, float x7) noexcept {
-
- sf[0] = x0; sf[1] = x1; sf[2] = x2; sf[3] = x3;
- sf[4] = x4; sf[5] = x5; sf[6] = x6; sf[7] = x7;
- }
-
- //! Sets all four DP-FP floats.
- inline void setF64(double x0) noexcept {
- df[0] = x0; df[1] = x0; df[2] = x0; df[3] = x0;
- }
-
- //! Sets all four DP-FP floats.
- inline void setF64(double x0, double x1, double x2, double x3) noexcept {
- df[0] = x0; df[1] = x1; df[2] = x2; df[3] = x3;
- }
-
- //! \}
-};
-
-ASMJIT_END_NAMESPACE
-
-#endif // !ASMJIT_NO_DEPRECATED
-#endif // ASMJIT_CORE_DATATYPES_H_INCLUDED
diff --git a/src/asmjit/core/emithelper.cpp b/src/asmjit/core/emithelper.cpp
index a77211e..bcdf098 100644
--- a/src/asmjit/core/emithelper.cpp
+++ b/src/asmjit/core/emithelper.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/archtraits.h"
@@ -33,12 +15,11 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::BaseEmitHelper - Formatting]
-// ============================================================================
+// BaseEmitHelper - Formatting
+// ===========================
#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());
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 {
typedef FuncArgsContext::Var Var;
- uint32_t arch = ctx.arch();
+ Arch arch = ctx.arch();
uint32_t varCount = ctx.varCount();
for (uint32_t i = 0; i < varCount; i++) {
@@ -80,9 +61,8 @@ static void dumpAssignment(String& sb, const FuncArgsContext& ctx) noexcept {
}
#endif
-// ============================================================================
-// [asmjit::BaseEmitHelper - EmitArgsAssignment]
-// ============================================================================
+// BaseEmitHelper - EmitArgsAssignment
+// ===================================
ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args) {
typedef FuncArgsContext::Var Var;
@@ -95,7 +75,7 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
kWorkPostponed = 0x04
};
- uint32_t arch = frame.arch();
+ Arch arch = frame.arch();
const ArchTraits& archTraits = ArchTraits::byArch(arch);
RAConstraints constraints;
@@ -112,11 +92,11 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
}
#endif
+ auto& workData = ctx._workData;
uint32_t varCount = ctx._varCount;
- WorkData* workData = ctx._workData;
-
uint32_t saVarId = ctx._saVarId;
- BaseReg sp = BaseReg::fromSignatureAndId(_emitter->_gpRegInfo.signature(), archTraits.spRegId());
+
+ BaseReg sp = BaseReg(_emitter->_gpSignature, archTraits.spRegId());
BaseReg sa = sp;
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());
}
- // --------------------------------------------------------------------------
// 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.
- // --------------------------------------------------------------------------
if (ctx._stackDstMask) {
// 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()) {
WorkData& wd = workData[archTraits.regTypeToGroup(cur.regType())];
- uint32_t rId = cur.regId();
+ uint32_t regId = cur.regId();
- reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), rId);
- wd.unassign(varId, rId);
+ reg.setSignatureAndId(archTraits.regTypeToSignature(cur.regType()), regId);
+ wd.unassign(varId, regId);
}
else {
- // Stack to reg move - tricky since we move stack to stack we can decide which
- // register to use. In general we follow the rule that IntToInt moves will use
- // GP regs with possibility to signature or zero extend, and all other moves will
- // either use GP or VEC regs depending on the size of the move.
- RegInfo rInfo = getSuitableRegForMemToMemMove(arch, out.typeId(), cur.typeId());
- if (ASMJIT_UNLIKELY(!rInfo.isValid()))
+ // Stack to reg move - tricky since we move stack to stack we can decide which register to use. In general
+ // we follow the rule that IntToInt moves will use GP regs with possibility to signature or zero extend,
+ // and all other moves will either use GP or VEC regs depending on the size of the move.
+ OperandSignature signature = getSuitableRegForMemToMemMove(arch, out.typeId(), cur.typeId());
+ if (ASMJIT_UNLIKELY(!signature.isValid()))
return DebugUtils::errored(kErrorInvalidState);
- WorkData& wd = workData[rInfo.group()];
- uint32_t availableRegs = wd.availableRegs();
+ WorkData& wd = workData[signature.regGroup()];
+ RegMask availableRegs = wd.availableRegs();
if (ASMJIT_UNLIKELY(!availableRegs))
return DebugUtils::errored(kErrorInvalidState);
- uint32_t rId = Support::ctz(availableRegs);
- reg.setSignatureAndId(rInfo.signature(), rId);
+ uint32_t availableId = Support::ctz(availableRegs);
+ reg.setSignatureAndId(signature, availableId);
ASMJIT_PROPAGATE(emitArgMove(reg, out.typeId(), srcStackPtr, cur.typeId()));
}
if (cur.isIndirect() && cur.isReg())
- workData[BaseReg::kGroupGp].unassign(varId, cur.regId());
+ workData[RegGroup::kGp].unassign(varId, cur.regId());
// Register to stack move.
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;
for (;;) {
@@ -212,8 +186,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
FuncValue& cur = var.cur;
FuncValue& out = var.out;
- uint32_t curGroup = archTraits.regTypeToGroup(cur.regType());
- uint32_t outGroup = archTraits.regTypeToGroup(out.regType());
+ RegGroup curGroup = archTraits.regTypeToGroup(cur.regType());
+ RegGroup outGroup = archTraits.regTypeToGroup(out.regType());
uint32_t curId = cur.regId();
uint32_t outId = out.regId();
@@ -228,8 +202,8 @@ ASMJIT_FAVOR_SIZE Error BaseEmitHelper::emitArgsAssignment(const FuncFrame& fram
EmitMove:
ASMJIT_PROPAGATE(
emitArgMove(
- BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
- BaseReg::fromSignatureAndId(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
+ BaseReg(archTraits.regTypeToSignature(out.regType()), outId), out.typeId(),
+ BaseReg(archTraits.regTypeToSignature(cur.regType()), curId), cur.typeId()));
wd.reassign(varId, outId, curId);
cur.initReg(out.regType(), outId, out.typeId());
@@ -244,15 +218,15 @@ EmitMove:
if (!altVar.out.isInitialized() || (altVar.out.isReg() && altVar.out.regId() == curId)) {
// Only few architectures provide swap operations, and only for few register groups.
- if (archTraits.hasSwap(curGroup)) {
- uint32_t highestType = Support::max(cur.regType(), altVar.cur.regType());
- if (Support::isBetween(highestType, BaseReg::kTypeGp8Lo, BaseReg::kTypeGp16))
- highestType = BaseReg::kTypeGp32;
+ if (archTraits.hasInstRegSwap(curGroup)) {
+ RegType highestType = Support::max(cur.regType(), altVar.cur.regType());
+ if (Support::isBetween(highestType, RegType::kGp8Lo, RegType::kGp16))
+ highestType = RegType::kGp32;
- uint32_t signature = archTraits.regTypeToSignature(highestType);
+ OperandSignature signature = archTraits.regTypeToSignature(highestType);
ASMJIT_PROPAGATE(
- emitRegSwap(BaseReg::fromSignatureAndId(signature, outId),
- BaseReg::fromSignatureAndId(signature, curId)));
+ emitRegSwap(BaseReg(signature, outId), BaseReg(signature, curId)));
+
wd.swap(varId, curId, altId, outId);
cur.setRegId(outId);
var.markDone();
@@ -264,9 +238,9 @@ EmitMove:
}
else {
// 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) {
- uint32_t inOutRegs = wd.dstRegs();
+ RegMask inOutRegs = wd.dstRegs();
if (availableRegs & ~inOutRegs)
availableRegs &= ~inOutRegs;
outId = Support::ctz(availableRegs);
@@ -294,10 +268,8 @@ EmitMove:
workFlags = (workFlags & kWorkDidSome) ? kWorkNone : kWorkPostponed;
}
- // --------------------------------------------------------------------------
// Load arguments passed by stack into registers. This is pretty simple and
// it never requires multiple iterations like the previous phase.
- // --------------------------------------------------------------------------
if (ctx._hasStackSrc) {
uint32_t iterCount = 1;
@@ -317,12 +289,12 @@ EmitMove:
ASMJIT_ASSERT(var.out.isReg());
uint32_t outId = var.out.regId();
- uint32_t outType = var.out.regType();
+ RegType outType = var.out.regType();
- uint32_t group = archTraits.regTypeToGroup(outType);
- WorkData& wd = ctx._workData[group];
+ RegGroup group = archTraits.regTypeToGroup(outType);
+ 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`.
if (iterCount == 1) {
iterCount++;
@@ -331,7 +303,7 @@ EmitMove:
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());
ASMJIT_PROPAGATE(emitArgMove(
diff --git a/src/asmjit/core/emithelper_p.h b/src/asmjit/core/emithelper_p.h
index cb8ddf0..0333959 100644
--- a/src/asmjit/core/emithelper_p.h
+++ b/src/asmjit/core/emithelper_p.h
@@ -1,26 +1,7 @@
-
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
#define ASMJIT_CORE_EMITHELPER_P_H_INCLUDED
@@ -35,10 +16,6 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [asmjit::BaseEmitHelper]
-// ============================================================================
-
//! Helper class that provides utilities for each supported architecture.
class BaseEmitHelper {
public:
@@ -50,12 +27,11 @@ public:
inline BaseEmitter* emitter() const noexcept { return _emitter; }
inline void setEmitter(BaseEmitter* emitter) noexcept { _emitter = emitter; }
- //! Emits a pure move operation between two registers or the same type or
- //! between a register and its home slot. This function does not handle
- //! register conversion.
+ //! Emits a pure move operation between two registers or the same type or between a register and its home
+ //! slot. This function does not handle register conversion.
virtual Error emitRegMove(
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.
virtual Error emitRegSwap(
@@ -64,13 +40,12 @@ public:
//! Emits move from a function argument (either register or stack) to a register.
//!
- //! This function can handle the necessary conversion from one argument to
- //! another, and from one register type to another, if it's possible. Any
- //! attempt of conversion that requires third register of a different group
+ //! This function can handle the necessary conversion from one argument to another, and from one register type
+ //! to another, if it's possible. Any attempt of conversion that requires third register of a different group
//! (for example conversion from K to MMX on X86/X64) will fail.
virtual Error emitArgMove(
- const BaseReg& dst_, uint32_t dstTypeId,
- const Operand_& src_, uint32_t srcTypeId, const char* comment = nullptr) = 0;
+ const BaseReg& dst_, TypeId dstTypeId,
+ const Operand_& src_, TypeId srcTypeId, const char* comment = nullptr) = 0;
Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
};
diff --git a/src/asmjit/core/emitter.cpp b/src/asmjit/core/emitter.cpp
index 2877dc8..38061b5 100644
--- a/src/asmjit/core/emitter.cpp
+++ b/src/asmjit/core/emitter.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/emitterutils_p.h"
@@ -39,91 +21,85 @@
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::BaseEmitter - Construction / Destruction]
-// ============================================================================
+// BaseEmitter - Construction & Destruction
+// ========================================
-BaseEmitter::BaseEmitter(uint32_t emitterType) noexcept
- : _emitterType(uint8_t(emitterType)) {}
+BaseEmitter::BaseEmitter(EmitterType emitterType) noexcept
+ : _emitterType(emitterType) {}
BaseEmitter::~BaseEmitter() noexcept {
if (_code) {
- _addEmitterFlags(kFlagDestroyed);
+ _addEmitterFlags(EmitterFlags::kDestroyed);
_code->detach(this);
}
}
-// ============================================================================
-// [asmjit::BaseEmitter - Finalize]
-// ============================================================================
+// BaseEmitter - Finalize
+// ======================
Error BaseEmitter::finalize() {
// Does nothing by default, overridden by `BaseBuilder` and `BaseCompiler`.
return kErrorOk;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Internals]
-// ============================================================================
+// 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 {
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.
emitComments = self->_code != nullptr && self->_logger != nullptr;
- hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionAssembler);
+ hasDiagnosticOptions = self->hasDiagnosticOption(DiagnosticOptions::kValidateAssembler);
}
else {
// Builder/Compiler: Always emit comments, we cannot assume they won't be used.
emitComments = self->_code != nullptr;
- hasValidationOptions = self->hasValidationOption(BaseEmitter::kValidationOptionIntermediate);
+ hasDiagnosticOptions = self->hasDiagnosticOption(DiagnosticOptions::kValidateIntermediate);
}
if (emitComments)
- self->_addEmitterFlags(BaseEmitter::kFlagLogComments);
+ self->_addEmitterFlags(EmitterFlags::kLogComments);
else
- self->_clearEmitterFlags(BaseEmitter::kFlagLogComments);
+ self->_clearEmitterFlags(EmitterFlags::kLogComments);
- // The reserved option tells emitter (Assembler/Builder/Compiler) that there
- // may be either a border case (CodeHolder not attached, for example) or that
- // logging or validation is required.
- if (self->_code == nullptr || self->_logger || hasValidationOptions)
- self->_forcedInstOptions |= BaseInst::kOptionReserved;
+ // The reserved option tells emitter (Assembler/Builder/Compiler) that there may be either a border
+ // case (CodeHolder not attached, for example) or that logging or validation is required.
+ if (self->_code == nullptr || self->_logger || hasDiagnosticOptions)
+ self->_forcedInstOptions |= InstOptions::kReserved;
else
- self->_forcedInstOptions &= ~BaseInst::kOptionReserved;
+ self->_forcedInstOptions &= ~InstOptions::kReserved;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Validation Options]
-// ============================================================================
+// BaseEmitter - Diagnostic Options
+// ================================
-void BaseEmitter::addValidationOptions(uint32_t options) noexcept {
- _validationOptions = uint8_t(_validationOptions | options);
+void BaseEmitter::addDiagnosticOptions(DiagnosticOptions options) noexcept {
+ _diagnosticOptions |= options;
BaseEmitter_updateForcedOptions(this);
}
-void BaseEmitter::clearValidationOptions(uint32_t options) noexcept {
- _validationOptions = uint8_t(_validationOptions | options);
+void BaseEmitter::clearDiagnosticOptions(DiagnosticOptions options) noexcept {
+ _diagnosticOptions &= ~options;
BaseEmitter_updateForcedOptions(this);
}
-// ============================================================================
-// [asmjit::BaseEmitter - Logging]
-// ============================================================================
+// BaseEmitter - Logging
+// =====================
void BaseEmitter::setLogger(Logger* logger) noexcept {
#ifndef ASMJIT_NO_LOGGING
if (logger) {
_logger = logger;
- _addEmitterFlags(kFlagOwnLogger);
+ _addEmitterFlags(EmitterFlags::kOwnLogger);
}
else {
_logger = nullptr;
- _clearEmitterFlags(kFlagOwnLogger);
+ _clearEmitterFlags(EmitterFlags::kOwnLogger);
if (_code)
_logger = _code->logger();
}
@@ -133,18 +109,17 @@ void BaseEmitter::setLogger(Logger* logger) noexcept {
#endif
}
-// ============================================================================
-// [asmjit::BaseEmitter - Error Handling]
-// ============================================================================
+// BaseEmitter - Error Handling
+// ============================
void BaseEmitter::setErrorHandler(ErrorHandler* errorHandler) noexcept {
if (errorHandler) {
_errorHandler = errorHandler;
- _addEmitterFlags(kFlagOwnErrorHandler);
+ _addEmitterFlags(EmitterFlags::kOwnErrorHandler);
}
else {
_errorHandler = nullptr;
- _clearEmitterFlags(kFlagOwnErrorHandler);
+ _clearEmitterFlags(EmitterFlags::kOwnErrorHandler);
if (_code)
_errorHandler = _code->errorHandler();
}
@@ -160,58 +135,55 @@ Error BaseEmitter::reportError(Error err, const char* message) {
return err;
}
-// ============================================================================
-// [asmjit::BaseEmitter - Labels]
-// ============================================================================
+// BaseEmitter - Labels
+// ====================
Label BaseEmitter::labelByName(const char* name, size_t nameSize, uint32_t parentId) noexcept {
- return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : uint32_t(Globals::kInvalidId));
+ return Label(_code ? _code->labelIdByName(name, nameSize, parentId) : Globals::kInvalidId);
}
bool BaseEmitter::isLabelValid(uint32_t labelId) const noexcept {
return _code && labelId < _code->labelCount();
}
-// ============================================================================
-// [asmjit::BaseEmitter - Emit (Low-Level)]
-// ============================================================================
+// BaseEmitter - Emit (Low-Level)
+// ==============================
using EmitterUtils::noExt;
-Error BaseEmitter::_emitI(uint32_t instId) {
+Error BaseEmitter::_emitI(InstId instId) {
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);
}
-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);
}
-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);
}
-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 };
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 };
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 };
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;
-
Operand_ opExt[3];
switch (opCount) {
@@ -247,9 +219,8 @@ Error BaseEmitter::_emitOpArray(uint32_t instId, const Operand_* operands, size_
}
}
-// ============================================================================
-// [asmjit::BaseEmitter - Emit (High-Level)]
-// ============================================================================
+// BaseEmitter - Emit (High-Level)
+// ===============================
ASMJIT_FAVOR_SIZE Error BaseEmitter::emitProlog(const FuncFrame& frame) {
if (ASMJIT_UNLIKELY(!_code))
@@ -314,13 +285,12 @@ ASMJIT_FAVOR_SIZE Error BaseEmitter::emitArgsAssignment(const FuncFrame& frame,
return DebugUtils::errored(kErrorInvalidArch);
}
-// ============================================================================
-// [asmjit::BaseEmitter - Comment]
-// ============================================================================
+// BaseEmitter - Comment
+// =====================
Error BaseEmitter::commentf(const char* fmt, ...) {
- if (!hasEmitterFlag(kFlagLogComments)) {
- if (!hasEmitterFlag(kFlagAttached))
+ if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
+ if (!hasEmitterFlag(EmitterFlags::kAttached))
return reportError(DebugUtils::errored(kErrorNotInitialized));
return kErrorOk;
}
@@ -342,8 +312,8 @@ Error BaseEmitter::commentf(const char* fmt, ...) {
}
Error BaseEmitter::commentv(const char* fmt, va_list ap) {
- if (!hasEmitterFlag(kFlagLogComments)) {
- if (!hasEmitterFlag(kFlagAttached))
+ if (!hasEmitterFlag(EmitterFlags::kLogComments)) {
+ if (!hasEmitterFlag(EmitterFlags::kAttached))
return reportError(DebugUtils::errored(kErrorNotInitialized));
return kErrorOk;
}
@@ -360,18 +330,17 @@ Error BaseEmitter::commentv(const char* fmt, va_list ap) {
#endif
}
-// ============================================================================
-// [asmjit::BaseEmitter - Events]
-// ============================================================================
+// BaseEmitter - Events
+// ====================
Error BaseEmitter::onAttach(CodeHolder* code) noexcept {
_code = code;
_environment = code->environment();
- _addEmitterFlags(kFlagAttached);
+ _addEmitterFlags(EmitterFlags::kAttached);
const ArchTraits& archTraits = ArchTraits::byArch(code->arch());
- uint32_t nativeRegType = Environment::is32Bit(code->arch()) ? BaseReg::kTypeGp32 : BaseReg::kTypeGp64;
- _gpRegInfo.setSignature(archTraits._regInfo[nativeRegType].signature());
+ RegType nativeRegType = Environment::is32Bit(code->arch()) ? RegType::kGp32 : RegType::kGp64;
+ _gpSignature = archTraits.regTypeToSignature(nativeRegType);
onSettingsUpdated();
return kErrorOk;
@@ -387,13 +356,13 @@ Error BaseEmitter::onDetach(CodeHolder* code) noexcept {
_errorHandler = nullptr;
_clearEmitterFlags(~kEmitterPreservedFlags);
- _forcedInstOptions = BaseInst::kOptionReserved;
+ _forcedInstOptions = InstOptions::kReserved;
_privateData = 0;
_environment.reset();
- _gpRegInfo.reset();
+ _gpSignature.reset();
- _instOptions = 0;
+ _instOptions = InstOptions::kNone;
_extraReg.reset();
_inlineComment = nullptr;
diff --git a/src/asmjit/core/emitter.h b/src/asmjit/core/emitter.h
index 44cda70..17a98ba 100644
--- a/src/asmjit/core/emitter.h
+++ b/src/asmjit/core/emitter.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_EMITTER_H_INCLUDED
#define ASMJIT_CORE_EMITTER_H_INCLUDED
@@ -35,41 +17,203 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class ConstPool;
class FuncFrame;
class FuncArgsAssignment;
-// ============================================================================
-// [asmjit::BaseEmitter]
-// ============================================================================
+//! Align mode, used by \ref BaseEmitter::align().
+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
-//! `BaseBuilder`.
+ //! Maximum value of `AlignMode`.
+ 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 {
public:
ASMJIT_BASE_CLASS(BaseEmitter)
- //! See \ref EmitterType.
- 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;
+ //! \name Members
+ //! \{
- //! Encoding options, see \ref EncodingOptions.
- uint32_t _encodingOptions = 0;
+ //! See \ref EmitterType.
+ 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().
- uint32_t _forcedInstOptions = BaseInst::kOptionReserved;
+ InstOptions _forcedInstOptions = InstOptions::kReserved;
//! Internal private data used freely by any emitter.
uint32_t _privateData = 0;
@@ -83,143 +227,21 @@ public:
//! Describes the target environment, matches \ref CodeHolder::environment().
Environment _environment {};
//! Native GP register signature and signature related information.
- RegInfo _gpRegInfo {};
+ OperandSignature _gpSignature {};
//! 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).
RegOnly _extraReg {};
//! Inline comment of the next instruction (affects the next instruction).
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
//! \{
- ASMJIT_API explicit BaseEmitter(uint32_t emitterType) noexcept;
+ ASMJIT_API explicit BaseEmitter(EmitterType emitterType) noexcept;
ASMJIT_API virtual ~BaseEmitter() noexcept;
//! \}
@@ -239,28 +261,28 @@ public:
//! \{
//! 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`.
- inline uint32_t emitterFlags() const noexcept { return _emitterFlags; }
+ inline EmitterFlags emitterFlags() const noexcept { return _emitterFlags; }
//! 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`.
//!
//! \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`.
- 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.
- 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.
- 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).
- 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 _clearEmitterFlags(uint32_t flags) noexcept { _emitterFlags = uint8_t(_emitterFlags & ~flags); }
+ inline void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
+ inline void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
//! \}
@@ -270,7 +292,7 @@ public:
//! Returns the CodeHolder this emitter is attached to.
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().
inline const Environment& environment() const noexcept { return _environment; }
@@ -281,9 +303,9 @@ public:
inline bool is64Bit() const noexcept { return environment().is64Bit(); }
//! 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.
- 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).
inline uint32_t registerSize() const noexcept { return environment().registerSize(); }
@@ -298,12 +320,10 @@ public:
//! Finalizes this emitter.
//!
- //! Materializes the content of the emitter by serializing it to the attached
- //! \ref CodeHolder through an architecture specific \ref BaseAssembler. This
- //! function won't do anything if the emitter inherits from \ref BaseAssembler
- //! as assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder.
- //! However, if this is an emitter that inherits from \ref BaseBuilder or \ref
- //! BaseCompiler then these emitters need the materialization phase as they
+ //! Materializes the content of the emitter by serializing it to the attached \ref CodeHolder through an architecture
+ //! specific \ref BaseAssembler. This function won't do anything if the emitter inherits from \ref BaseAssembler as
+ //! assemblers emit directly to a \ref CodeBuffer held by \ref CodeHolder. However, if this is an emitter that
+ //! inherits from \ref BaseBuilder or \ref BaseCompiler then these emitters need the materialization phase as they
//! store their content in a representation not visible to \ref CodeHolder.
ASMJIT_API virtual Error finalize();
@@ -317,29 +337,27 @@ public:
//! Tests whether the emitter has its own logger.
//!
- //! Own logger means that it overrides the possible logger that may be used
- //! by \ref CodeHolder this emitter is attached to.
- inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(kFlagOwnLogger); }
+ //! Own logger means that it overrides the possible logger that may be used by \ref CodeHolder this emitter is
+ //! attached to.
+ inline bool hasOwnLogger() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnLogger); }
//! Returns the logger this emitter uses.
//!
- //! The returned logger is either the emitter's own logger or it's logger
- //! used by \ref CodeHolder this emitter is attached to.
+ //! The returned logger is either the emitter's own logger or it's logger used by \ref CodeHolder this emitter
+ //! is attached to.
inline Logger* logger() const noexcept { return _logger; }
//! Sets or resets the logger of the emitter.
//!
- //! If the `logger` argument is non-null then the logger will be considered
- //! emitter's own logger, see \ref hasOwnLogger() for more details. If the
- //! given `logger` is null then the emitter will automatically use logger
+ //! If the `logger` argument is non-null then the logger will be considered emitter's own logger, see \ref
+ //! hasOwnLogger() for more details. If the given `logger` is null then the emitter will automatically use logger
//! that is attached to the \ref CodeHolder this emitter is attached to.
ASMJIT_API void setLogger(Logger* logger) noexcept;
//! Resets the logger of this emitter.
//!
- //! The emitter will bail to using a logger attached to \ref CodeHolder this
- //! emitter is attached to, or no logger at all if \ref CodeHolder doesn't
- //! have one.
+ //! The emitter will bail to using a logger attached to \ref CodeHolder this emitter is attached to, or no logger
+ //! at all if \ref CodeHolder doesn't have one.
inline void resetLogger() noexcept { return setLogger(nullptr); }
//! \}
@@ -352,14 +370,14 @@ public:
//! Tests whether the emitter has its own error handler.
//!
- //! Own error handler means that it overrides the possible error handler that
- //! may be used by \ref CodeHolder this emitter is attached to.
- inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(kFlagOwnErrorHandler); }
+ //! Own error handler means that it overrides the possible error handler that may be used by \ref CodeHolder this
+ //! emitter is attached to.
+ inline bool hasOwnErrorHandler() const noexcept { return hasEmitterFlag(EmitterFlags::kOwnErrorHandler); }
//! Returns the error handler this emitter uses.
//!
- //! The returned error handler is either the emitter's own error handler or
- //! it's error handler used by \ref CodeHolder this emitter is attached to.
+ //! The returned error handler is either the emitter's own error handler or it's error handler used by
+ //! \ref CodeHolder this emitter is attached to.
inline ErrorHandler* errorHandler() const noexcept { return _errorHandler; }
//! Sets or resets the error handler of the emitter.
@@ -369,11 +387,9 @@ public:
inline void resetErrorHandler() noexcept { setErrorHandler(nullptr); }
//! Handles the given error in the following way:
- //! 1. If the emitter has \ref ErrorHandler attached, it calls its
- //! \ref ErrorHandler::handleError() member function first, and
- //! then returns the error. The `handleError()` function may throw.
- //! 2. if the emitter doesn't have \ref ErrorHandler, the error is
- //! simply returned.
+ //! 1. If the emitter has \ref ErrorHandler attached, it calls its \ref ErrorHandler::handleError() member function
+ //! first, and then returns the error. The `handleError()` function may throw.
+ //! 2. if the emitter doesn't have \ref ErrorHandler, the error is simply returned.
ASMJIT_API Error reportError(Error err, const char* message = nullptr);
//! \}
@@ -381,61 +397,51 @@ public:
//! \name Encoding Options
//! \{
- //! Returns encoding options, see \ref EncodingOptions.
- inline uint32_t encodingOptions() const noexcept { return _encodingOptions; }
+ //! Returns encoding options.
+ inline EncodingOptions encodingOptions() const noexcept { return _encodingOptions; }
//! 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.
- inline void addEncodingOptions(uint32_t options) noexcept { _encodingOptions |= options; }
- //! Disables the given encoding `options`, see \ref EncodingOptions.
- inline void clearEncodingOptions(uint32_t options) noexcept { _encodingOptions &= ~options; }
+ //! Enables the given encoding `options`.
+ inline void addEncodingOptions(EncodingOptions options) noexcept { _encodingOptions |= options; }
+ //! Disables the given encoding `options`.
+ inline void clearEncodingOptions(EncodingOptions options) noexcept { _encodingOptions &= ~options; }
//! \}
- //! \name Validation Options
+ //! \name Diagnostic Options
//! \{
- //! Returns the emitter's validation options, see \ref ValidationOptions.
- inline uint32_t validationOptions() const noexcept {
- return _validationOptions;
- }
+ //! Returns the emitter's diagnostic options.
+ inline DiagnosticOptions diagnosticOptions() const noexcept { return _diagnosticOptions; }
- //! Tests whether the given `option` is present in validation options.
- inline bool hasValidationOption(uint32_t option) const noexcept {
- return (_validationOptions & option) != 0;
- }
+ //! Tests whether the given `option` is present in the emitter's diagnostic options.
+ inline bool hasDiagnosticOption(DiagnosticOptions option) const noexcept { return Support::test(_diagnosticOptions, option); }
- //! Activates the given validation `options`, see \ref ValidationOptions.
+ //! Activates the given diagnostic `options`.
//!
- //! This function is used to activate explicit validation options that will
- //! be then used by all emitter implementations. There are in general two
- //! possibilities:
+ //! This function is used to activate explicit validation options that will be then used by all emitter
+ //! implementations. There are in general two possibilities:
//!
- //! - Architecture specific assembler is used. In this case a
- //! \ref kValidationOptionAssembler can be used to turn on explicit
- //! validation that will be used before an instruction is emitted.
- //! This means that internally an extra step will be performed to
- //! make sure that the instruction is correct. This is needed, because
- //! by default assemblers prefer speed over strictness.
+ //! - Architecture specific assembler is used. In this case a \ref DiagnosticOptions::kValidateAssembler can be
+ //! used to turn on explicit validation that will be used before an instruction is emitted. This means that
+ //! internally an extra step will be performed to make sure that the instruction is correct. This is needed,
+ //! because by default assemblers prefer speed over strictness.
//!
//! This option should be used in debug builds as it's pretty expensive.
//!
- //! - Architecture specific builder or compiler is used. In this case
- //! the user can turn on \ref kValidationOptionIntermediate option
- //! that adds explicit validation step before the Builder or Compiler
- //! creates an \ref InstNode to represent an emitted instruction. Error
- //! will be returned if the instruction is ill-formed. In addition,
- //! also \ref kValidationOptionAssembler can be used, which would not be
- //! consumed by Builder / Compiler directly, but it would be propagated
- //! to an architecture specific \ref BaseAssembler implementation it
- //! creates during \ref BaseEmitter::finalize().
- ASMJIT_API void addValidationOptions(uint32_t options) noexcept;
+ //! - Architecture specific builder or compiler is used. In this case the user can turn on
+ //! \ref DiagnosticOptions::kValidateIntermediate option that adds explicit validation step before the Builder
+ //! or Compiler creates an \ref InstNode to represent an emitted instruction. Error will be returned if the
+ //! instruction is ill-formed. In addition, also \ref DiagnosticOptions::kValidateAssembler can be used, which
+ //! would not be consumed by Builder / Compiler directly, but it would be propagated to an architecture specific
+ //! \ref BaseAssembler implementation it creates during \ref BaseEmitter::finalize().
+ ASMJIT_API void addDiagnosticOptions(DiagnosticOptions options) noexcept;
//! Deactivates the given validation `options`.
//!
- //! See \ref addValidationOptions() and \ref ValidationOptions for more details.
- ASMJIT_API void clearValidationOptions(uint32_t options) noexcept;
+ //! See \ref addDiagnosticOptions() and \ref DiagnosticOptions for more details.
+ ASMJIT_API void clearDiagnosticOptions(DiagnosticOptions options) noexcept;
//! \}
@@ -444,20 +450,19 @@ public:
//! Returns forced instruction options.
//!
- //! Forced instruction options are merged with next instruction options before
- //! the instruction is encoded. These options have some bits reserved that are
- //! used by error handling, logging, and instruction validation purposes. Other
- //! options are globals that affect each instruction.
- inline uint32_t forcedInstOptions() const noexcept { return _forcedInstOptions; }
+ //! Forced instruction options are merged with next instruction options before the instruction is encoded. These
+ //! options have some bits reserved that are used by error handling, logging, and instruction validation purposes.
+ //! Other options are globals that affect each instruction.
+ inline InstOptions forcedInstOptions() const noexcept { return _forcedInstOptions; }
//! 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.
- inline void setInstOptions(uint32_t options) noexcept { _instOptions = options; }
+ inline void setInstOptions(InstOptions options) noexcept { _instOptions = options; }
//! 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.
- inline void resetInstOptions() noexcept { _instOptions = 0; }
+ inline void resetInstOptions() noexcept { _instOptions = InstOptions::kNone; }
//! Tests whether the extra register operand is valid.
inline bool hasExtraReg() const noexcept { return _extraReg.isReg(); }
@@ -474,9 +479,8 @@ public:
inline const char* inlineComment() const noexcept { return _inlineComment; }
//! Sets comment/annotation of the next instruction.
//!
- //! \note This string is set back to null by `_emit()`, but until that it has
- //! to remain valid as the Emitter is not required to make a copy of it (and
- //! it would be slow to do that for each instruction).
+ //! \note This string is set back to null by `_emit()`, but until that it has to remain valid as the Emitter is not
+ //! required to make a copy of it (and it would be slow to do that for each instruction).
inline void setInlineComment(const char* s) noexcept { _inlineComment = s; }
//! Resets the comment/annotation to nullptr.
inline void resetInlineComment() noexcept { _inlineComment = nullptr; }
@@ -496,19 +500,19 @@ public:
//! Creates a new label.
virtual Label newLabel() = 0;
//! 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.
- inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) {
- return newNamedLabel(name, nameSize, Label::kTypeExternal);
- }
+ inline Label newExternalLabel(const char* name, size_t nameSize = SIZE_MAX) { return newNamedLabel(name, nameSize, LabelType::kExternal); }
//! Returns `Label` by `name`.
//!
//! 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
- //! or no such label exist. You must always check the validity of the `Label` returned.
+ //! \note This function doesn't trigger ErrorHandler in case the name is invalid or no such label exist. You must
+ //! 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;
//! Binds the `label` to the current position of the current section.
@@ -526,41 +530,39 @@ public:
//! \name Emit
//! \{
- // NOTE: These `emit()` helpers are designed to address a code-bloat generated
- // by C++ compilers to call a function having many arguments. Each parameter to
- // `_emit()` requires some code to pass it, which means that if we default to
- // 5 arguments in `_emit()` and instId the C++ compiler would have to generate
- // a virtual function call having 5 parameters and additional `this` argument,
- // which is quite a lot. Since by default most instructions have 2 to 3 operands
- // it's better to introduce helpers that pass from 0 to 6 operands that help to
- // reduce the size of emit(...) function call.
+ // NOTE: These `emit()` helpers are designed to address a code-bloat generated by C++ compilers to call a function
+ // having many arguments. Each parameter to `_emit()` requires some code to pass it, which means that if we default
+ // to 5 arguments in `_emit()` and instId the C++ compiler would have to generate a virtual function call having 5
+ // parameters and additional `this` argument, which is quite a lot. Since by default most instructions have 2 to 3
+ // operands it's better to introduce helpers that pass from 0 to 6 operands that help to reduce the size of emit(...)
+ // function call.
//! Emits an instruction (internal).
- ASMJIT_API Error _emitI(uint32_t instId);
+ ASMJIT_API Error _emitI(InstId instId);
//! \overload
- ASMJIT_API Error _emitI(uint32_t instId, const Operand_& o0);
+ ASMJIT_API Error _emitI(InstId instId, const Operand_& o0);
//! \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
- 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
- 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
- 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
- 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`.
template
- ASMJIT_INLINE Error emit(uint32_t instId, Args&&... operands) {
+ ASMJIT_FORCE_INLINE Error emit(InstId instId, Args&&... operands) {
return _emitI(instId, Support::ForwardOp::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);
}
- 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());
setExtraReg(inst.extraReg());
return _emitOpArray(inst.id(), operands, opCount);
@@ -568,9 +570,9 @@ public:
//! \cond INTERNAL
//! 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.
- 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
//! \}
@@ -589,9 +591,10 @@ public:
//! Aligns the current CodeBuffer position to the `alignment` specified.
//!
- //! The sequence that is used to fill the gap between the aligned location
- //! and the current location depends on the align `mode`, see \ref AlignMode.
- virtual Error align(uint32_t alignMode, uint32_t alignment) = 0;
+ //! The sequence that is used to fill the gap between the aligned location and the current location depends on the
+ //! align `mode`, see \ref AlignMode. The `alignment` argument specifies alignment in bytes, so for example when
+ //! 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.
//!
//! This is the most flexible function for embedding data as it allows to:
- //! - Assign a `typeId` to the data, so the emitter knows the type of
- //! items stored in `data`. Binary data should use \ref Type::kIdU8.
- //! - Repeat the given data `repeatCount` times, so the data can be used
- //! as a fill pattern for example, or as a pattern used by SIMD instructions.
- virtual Error embedDataArray(uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) = 0;
+ //!
+ //! - Assign a `typeId` to the data, so the emitter knows the type of items stored in `data`. Binary data should
+ //! use \ref TypeId::kUInt8.
+ //!
+ //! - 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`.
- 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`.
- 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`.
- 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`.
- 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`.
- 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`.
- 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`.
- 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`.
- 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`.
- 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::kTypeId), &value, 1, repeatCount); }
//! Embeds a floating point `value` repeated by `repeatCount`.
- inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(Type::IdOfT::kTypeId, &value, 1, repeatCount); }
+ inline Error embedDouble(double value, size_t repeatCount = 1) { return embedDataArray(TypeId(TypeUtils::TypeIdOfT::kTypeId), &value, 1, repeatCount); }
//! Embeds a constant pool at the current offset by performing the following:
- //! 1. Aligns by using kAlignData to the minimum `pool` alignment.
+ //! 1. Aligns by using AlignMode::kData to the minimum `pool` alignment.
//! 2. Binds the ConstPool label so it's bound to an aligned location.
//! 3. Emits ConstPool content.
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
//! Embeds an absolute `label` address as data.
//!
- //! The `dataSize` is an optional argument that can be used to specify the
- //! size of the address data. If it's zero (default) the address size is
- //! deduced from the target architecture (either 4 or 8 bytes).
+ //! The `dataSize` is an optional argument that can be used to specify the size of the address data. If it's zero
+ //! (default) the address size is deduced from the target architecture (either 4 or 8 bytes).
virtual Error embedLabel(const Label& label, size_t dataSize = 0) = 0;
- //! Embeds a delta (distance) between the `label` and `base` calculating it
- //! as `label - base`. This function was designed to make it easier to embed
- //! lookup tables where each index is a relative distance of two labels.
+ //! Embeds a delta (distance) between the `label` and `base` calculating it as `label - base`. This function was
+ //! designed to make it easier to embed lookup tables where each index is a relative distance of two labels.
virtual Error embedLabelDelta(const Label& label, const Label& base, size_t dataSize = 0) = 0;
//! \}
@@ -672,48 +675,20 @@ public:
//! Called after the emitter was detached from `CodeHolder`.
virtual Error onDetach(CodeHolder* code) noexcept = 0;
- //! Called when \ref CodeHolder has updated an important setting, which
- //! involves the following:
+ //! Called when \ref CodeHolder has updated an important setting, which involves the following:
//!
- //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been
- //! called).
- //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler()
- //! has been called).
+ //! - \ref Logger has been changed (\ref CodeHolder::setLogger() has been called).
//!
- //! This function ensures that the settings are properly propagated from
- //! \ref CodeHolder to the emitter.
+ //! - \ref ErrorHandler has been changed (\ref CodeHolder::setErrorHandler() has been called).
//!
- //! \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.
+ //! This function ensures that the settings are properly propagated from \ref CodeHolder to the emitter.
+ //!
+ //! \note This function is virtual and can be overridden, however, if you do so, always call \ref
+ //! BaseEmitter::onSettingsUpdated() within your own implementation to ensure that the emitter is
+ //! in a consistent state.
ASMJIT_API virtual void onSettingsUpdated() noexcept;
//! \}
-
-#ifndef ASMJIT_NO_DEPRECATED
- ASMJIT_DEPRECATED("Use environment() instead")
- inline CodeInfo codeInfo() const noexcept {
- return CodeInfo(_environment, _code ? _code->baseAddress() : Globals::kNoBaseAddress);
- }
-
- ASMJIT_DEPRECATED("Use arch() instead")
- inline uint32_t archId() const noexcept { return arch(); }
-
- ASMJIT_DEPRECATED("Use registerSize() instead")
- inline uint32_t gpSize() const noexcept { return registerSize(); }
-
- ASMJIT_DEPRECATED("Use encodingOptions() instead")
- inline uint32_t emitterOptions() const noexcept { return encodingOptions(); }
-
- ASMJIT_DEPRECATED("Use addEncodingOptions() instead")
- inline void addEmitterOptions(uint32_t options) noexcept { addEncodingOptions(options); }
-
- ASMJIT_DEPRECATED("Use clearEncodingOptions() instead")
- inline void clearEmitterOptions(uint32_t options) noexcept { clearEncodingOptions(options); }
-
- ASMJIT_DEPRECATED("Use forcedInstOptions() instead")
- inline uint32_t globalInstOptions() const noexcept { return forcedInstOptions(); }
-#endif // !ASMJIT_NO_DEPRECATED
};
//! \}
diff --git a/src/asmjit/core/emitterutils.cpp b/src/asmjit/core/emitterutils.cpp
index 1115934..ba79787 100644
--- a/src/asmjit/core/emitterutils.cpp
+++ b/src/asmjit/core/emitterutils.cpp
@@ -1,57 +1,33 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/assembler.h"
#include "../core/emitterutils_p.h"
-#include "../core/formatter.h"
+#include "../core/formatter_p.h"
#include "../core/logger.h"
#include "../core/support.h"
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::EmitterUtils]
-// ============================================================================
-
namespace EmitterUtils {
#ifndef ASMJIT_NO_LOGGING
-Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept {
- size_t currentSize = sb.size();
- size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0;
-
- ASMJIT_ASSERT(binSize >= dispSize);
+Error finishFormattedLine(String& sb, const FormatOptions& formatOptions, const uint8_t* binData, size_t binSize, size_t offsetSize, size_t immSize, const char* comment) noexcept {
+ ASMJIT_ASSERT(binSize >= offsetSize);
const size_t kNoBinSize = SIZE_MAX;
+ size_t commentSize = comment ? Support::strLen(comment, Globals::kMaxCommentSize) : 0;
+
if ((binSize != 0 && binSize != kNoBinSize) || commentSize) {
- size_t align = kMaxInstLineSize;
char sep = ';';
+ size_t padding = Formatter::paddingFromOptions(formatOptions, FormatPaddingGroup::kRegularLine);
for (size_t i = (binSize == kNoBinSize); i < 2; i++) {
- size_t begin = sb.size();
- ASMJIT_PROPAGATE(sb.padEnd(align));
+ ASMJIT_PROPAGATE(sb.padEnd(padding));
if (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.
if (i == 0) {
- ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - dispSize - immSize));
- ASMJIT_PROPAGATE(sb.appendChars('.', dispSize * 2));
+ ASMJIT_PROPAGATE(sb.appendHex(binData, binSize - offsetSize - immSize));
+ ASMJIT_PROPAGATE(sb.appendChars('.', offsetSize * 2));
ASMJIT_PROPAGATE(sb.appendHex(binData + binSize - immSize, immSize));
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));
}
- currentSize += sb.size() - begin;
- align += kMaxBinarySize;
sep = '|';
+ padding += Formatter::paddingFromOptions(formatOptions, FormatPaddingGroup::kMachineCode);
}
}
@@ -82,55 +57,59 @@ void logLabelBound(BaseAssembler* self, const Label& label) noexcept {
Logger* logger = self->logger();
StringTmp<512> sb;
- size_t binSize = logger->hasFlag(FormatOptions::kFlagMachineCode) ? size_t(0) : SIZE_MAX;
+ 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());
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());
}
void logInstructionEmitted(
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) {
Logger* logger = self->logger();
ASMJIT_ASSERT(logger != nullptr);
StringTmp<256> sb;
- uint32_t flags = logger->flags();
+ FormatFlags formatFlags = logger->flags();
uint8_t* beforeCursor = self->bufferPtr();
intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
Operand_ opArray[Globals::kMaxOpCount];
- EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
+ opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
- sb.appendChars(' ', logger->indentation(FormatOptions::kIndentationCode));
- Formatter::formatInstruction(sb, flags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
+ sb.appendChars(' ', logger->indentation(FormatIndentationGroup::kCode));
+ Formatter::formatInstruction(sb, formatFlags, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
- if ((flags & FormatOptions::kFlagMachineCode) != 0)
- EmitterUtils::formatLine(sb, self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment());
+ if (Support::test(formatFlags, FormatFlags::kMachineCode))
+ finishFormattedLine(sb, logger->options(), self->bufferPtr(), size_t(emittedSize), relSize, immSize, self->inlineComment());
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);
}
Error logInstructionFailed(
BaseAssembler* self,
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;
sb.append(DebugUtils::errorAsString(err));
sb.append(": ");
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()) {
sb.append(" ; ");
diff --git a/src/asmjit/core/emitterutils_p.h b/src/asmjit/core/emitterutils_p.h
index 7e222d3..b7610e7 100644
--- a/src/asmjit/core/emitterutils_p.h
+++ b/src/asmjit/core/emitterutils_p.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
#define ASMJIT_CORE_EMITTERUTILS_P_H_INCLUDED
@@ -30,26 +12,26 @@
ASMJIT_BEGIN_NAMESPACE
class BaseAssembler;
+class FormatOptions;
//! \cond INTERNAL
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [asmjit::EmitterUtils]
-// ============================================================================
-
+//! Utilities used by various emitters, mostly Assembler implementations.
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,
kOp4 = 1,
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;
if (opExt[kOp3].isNone()) {
@@ -67,7 +49,7 @@ static ASMJIT_INLINE uint32_t opCountFromEmitArgs(const Operand_& o0, const Oper
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[1].copyFrom(o1);
dst[2].copyFrom(o2);
@@ -77,25 +59,23 @@ static ASMJIT_INLINE void opArrayFromEmitArgs(Operand_ dst[Globals::kMaxOpCount]
}
#ifndef ASMJIT_NO_LOGGING
-enum : uint32_t {
- // Has to be big to be able to hold all metadata compiler can assign to a
- // single instruction.
- kMaxInstLineSize = 44,
- kMaxBinarySize = 26
-};
-
-Error formatLine(String& sb, const uint8_t* binData, size_t binSize, size_t dispSize, size_t immSize, const char* comment) noexcept;
+Error finishFormattedLine(String& sb, const FormatOptions& formatOptions, const uint8_t* binData, size_t binSize, size_t offsetSize, size_t immSize, const char* comment) noexcept;
void logLabelBound(BaseAssembler* self, const Label& label) noexcept;
void logInstructionEmitted(
BaseAssembler* self,
- uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt,
+ 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);
Error logInstructionFailed(
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
}
diff --git a/src/asmjit/core/environment.cpp b/src/asmjit/core/environment.cpp
index 3be2b15..9a694af 100644
--- a/src/asmjit/core/environment.cpp
+++ b/src/asmjit/core/environment.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/environment.h"
diff --git a/src/asmjit/core/environment.h b/src/asmjit/core/environment.h
index 58e8734..8225ef2 100644
--- a/src/asmjit/core/environment.h
+++ b/src/asmjit/core/environment.h
@@ -1,30 +1,12 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
#define ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
-#include "../core/globals.h"
+#include "../core/archtraits.h"
#if defined(__APPLE__)
#include
@@ -35,301 +17,222 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_core
//! \{
-// ============================================================================
-// [asmjit::Environment]
-// ============================================================================
+//! Vendor.
+//!
+//! \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.
//!
-//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is
-//! sometimes called "Triple" (historically it used to be 3 only parts) or
-//! "Tuple", which is a convention used by Debian Linux.
+//! Environment has usually an 'arch-subarch-vendor-os-abi' format, which is sometimes called "Triple" (historically
+//! it used to be 3 only parts) or "Tuple", which is a convention used by Debian Linux.
//!
-//! AsmJit doesn't support all possible combinations or architectures and ABIs,
-//! however, it models the environment similarly to other compilers for future
-//! extensibility.
+//! AsmJit doesn't support all possible combinations or architectures and ABIs, however, it models the environment
+//! similarly to other compilers for future extensibility.
class Environment {
public:
- //! Architecture type, see \ref Arch.
- uint8_t _arch;
- //! Sub-architecture type, see \ref SubArch.
- uint8_t _subArch;
- //! Vendor type, see \ref Vendor.
- uint8_t _vendor;
- //! Platform type, see \ref Platform.
- uint8_t _platform;
- //! ABI type, see \ref Abi.
- uint8_t _abi;
- //! Object format, see \ref Format.
- uint8_t _format;
- //! Reserved for future use, must be zero.
- uint16_t _reserved;
-
- //! Architecture.
- enum Arch : uint32_t {
- //! Unknown or uninitialized architecture.
- kArchUnknown = 0,
-
- //! Mask used by 32-bit architectures (odd are 32-bit, even are 64-bit).
- kArch32BitMask = 0x01,
- //! Mask used by big-endian architectures.
- kArchBigEndianMask = 0x80u,
-
- //! 32-bit X86 architecture.
- kArchX86 = 1,
- //! 64-bit X86 architecture also known as X86_64 and AMD64.
- kArchX64 = 2,
-
- //! 32-bit RISC-V architecture.
- kArchRISCV32 = 3,
- //! 64-bit RISC-V architecture.
- kArchRISCV64 = 4,
-
- //! 32-bit ARM architecture (little endian).
- kArchARM = 5,
- //! 32-bit ARM architecture (big endian).
- kArchARM_BE = kArchARM | kArchBigEndianMask,
- //! 64-bit ARM architecture in (little endian).
- kArchAArch64 = 6,
- //! 64-bit ARM architecture in (big endian).
- kArchAArch64_BE = kArchAArch64 | kArchBigEndianMask,
- //! 32-bit ARM in Thumb mode (little endian).
- kArchThumb = 7,
- //! 32-bit ARM in Thumb mode (big endian).
- kArchThumb_BE = kArchThumb | kArchBigEndianMask,
-
- // 8 is not used, even numbers are 64-bit architectures.
-
- //! 32-bit MIPS architecture in (little endian).
- 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
+ //! \name Members
//! \{
-#ifdef _DOXYGEN
- //! Architecture detected at compile-time (architecture of the host).
- static constexpr Arch kArchHost = DETECTED_AT_COMPILE_TIME;
- //! Sub-architecture detected at compile-time (sub-architecture of the host).
- static constexpr SubArch kSubArchHost = DETECTED_AT_COMPILE_TIME;
- //! Vendor detected at compile-time (vendor of the host).
- static constexpr Vendor kVendorHost = DETECTED_AT_COMPILE_TIME;
- //! Platform detected at compile-time (platform of the host).
- static constexpr Platform kPlatformHost = DETECTED_AT_COMPILE_TIME;
- //! ABI detected at compile-time (ABI of the host).
- static constexpr Abi kAbiHost = DETECTED_AT_COMPILE_TIME;
-#else
- static constexpr Arch kArchHost =
- ASMJIT_ARCH_X86 == 32 ? kArchX86 :
- ASMJIT_ARCH_X86 == 64 ? kArchX64 :
-
- ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_LE ? kArchARM :
- ASMJIT_ARCH_ARM == 32 && ASMJIT_ARCH_BE ? kArchARM_BE :
- ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_LE ? kArchAArch64 :
- ASMJIT_ARCH_ARM == 64 && ASMJIT_ARCH_BE ? kArchAArch64_BE :
-
- ASMJIT_ARCH_MIPS == 32 && ASMJIT_ARCH_LE ? 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
+ //! Architecture.
+ Arch _arch;
+ //! Sub-architecture type.
+ SubArch _subArch;
+ //! Vendor type.
+ Vendor _vendor;
+ //! Platform.
+ Platform _platform;
+ //! Platform ABI.
+ PlatformABI _platformABI;
+ //! Object format.
+ ObjectFormat _objectFormat;
+ //! Reserved for future use, must be zero.
+ uint8_t _reserved[2];
//! \}
- //! \name Construction / Destruction
+ //! \name Construction & Destruction
//! \{
inline Environment() noexcept :
- _arch(uint8_t(kArchUnknown)),
- _subArch(uint8_t(kSubArchUnknown)),
- _vendor(uint8_t(kVendorUnknown)),
- _platform(uint8_t(kPlatformUnknown)),
- _abi(uint8_t(kAbiUnknown)),
- _format(uint8_t(kFormatUnknown)),
- _reserved(0) {}
+ _arch(Arch::kUnknown),
+ _subArch(SubArch::kUnknown),
+ _vendor(Vendor::kUnknown),
+ _platform(Platform::kUnknown),
+ _platformABI(PlatformABI::kUnknown),
+ _objectFormat(ObjectFormat::kUnknown),
+ _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 explicit Environment(uint32_t arch,
- uint32_t subArch = kSubArchUnknown,
- uint32_t vendor = kVendorUnknown,
- uint32_t platform = kPlatformUnknown,
- uint32_t abi = kAbiUnknown,
- uint32_t format = kFormatUnknown) noexcept {
- init(arch, subArch, vendor, platform, abi, format);
+ //! 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 inline Environment host() noexcept {
+ return Environment(Arch::kHost, SubArch::kHost, Vendor::kHost, Platform::kHost, PlatformABI::kHost, ObjectFormat::kUnknown);
}
//! \}
@@ -358,7 +261,7 @@ public:
//! Tests whether the environment is initialized, which means it must have
//! a valid architecture.
inline bool isInitialized() const noexcept {
- return _arch != kArchUnknown;
+ return _arch != Arch::kUnknown;
}
inline uint64_t _packed() const noexcept {
@@ -369,56 +272,60 @@ public:
//! Resets all members of the environment to zero / unknown.
inline void reset() noexcept {
- _arch = uint8_t(kArchUnknown);
- _subArch = uint8_t(kSubArchUnknown);
- _vendor = uint8_t(kVendorUnknown);
- _platform = uint8_t(kPlatformUnknown);
- _abi = uint8_t(kAbiUnknown);
- _format = uint8_t(kFormatUnknown);
- _reserved = 0;
+ _arch = Arch::kUnknown;
+ _subArch = SubArch::kUnknown;
+ _vendor = Vendor::kUnknown;
+ _platform = Platform::kUnknown;
+ _platformABI = PlatformABI::kUnknown;
+ _objectFormat = ObjectFormat::kUnknown;
+ _reserved[0] = 0;
+ _reserved[1] = 0;
}
inline bool equals(const Environment& other) const noexcept {
return _packed() == other._packed();
}
- //! Returns the architecture, see \ref Arch.
- inline uint32_t arch() const noexcept { return _arch; }
- //! Returns the sub-architecture, see \ref SubArch.
- inline uint32_t subArch() const noexcept { return _subArch; }
- //! Returns vendor, see \ref Vendor.
- inline uint32_t vendor() const noexcept { return _vendor; }
- //! Returns target's platform or operating system, see \ref Platform.
- inline uint32_t platform() const noexcept { return _platform; }
- //! Returns target's ABI, see \ref Abi.
- inline uint32_t abi() const noexcept { return _abi; }
- //! Returns target's object format, see \ref Format.
- inline uint32_t format() const noexcept { return _format; }
+ //! Returns the architecture.
+ inline Arch arch() const noexcept { return _arch; }
+ //! Returns the sub-architecture.
+ inline SubArch subArch() const noexcept { return _subArch; }
+ //! Returns vendor.
+ inline Vendor vendor() const noexcept { return _vendor; }
+ //! Returns target's platform or operating system.
+ inline Platform platform() const noexcept { return _platform; }
+ //! Returns target's ABI.
+ inline PlatformABI platformABI() const noexcept { return _platformABI; }
+ //! Returns target's object format.
+ inline ObjectFormat objectFormat() const noexcept { return _objectFormat; }
- inline void init(uint32_t arch,
- uint32_t subArch = kSubArchUnknown,
- uint32_t vendor = kVendorUnknown,
- uint32_t platform = kPlatformUnknown,
- uint32_t abi = kAbiUnknown,
- uint32_t format = kFormatUnknown) noexcept {
- _arch = uint8_t(arch);
- _subArch = uint8_t(subArch);
- _vendor = uint8_t(vendor);
- _platform = uint8_t(platform);
- _abi = uint8_t(abi);
- _format = uint8_t(format);
- _reserved = 0;
+ inline void init(
+ Arch arch,
+ SubArch subArch = SubArch::kUnknown,
+ Vendor vendor = Vendor::kUnknown,
+ Platform platform = Platform::kUnknown,
+ PlatformABI platformABI = PlatformABI::kUnknown,
+ ObjectFormat objectFormat = ObjectFormat::kUnknown) noexcept {
+
+ _arch = arch;
+ _subArch = subArch;
+ _vendor = vendor;
+ _platform = platform;
+ _platformABI = platformABI;
+ _objectFormat = objectFormat;
+ _reserved[0] = 0;
+ _reserved[1] = 0;
}
- inline bool isArchX86() const noexcept { return _arch == kArchX86; }
- inline bool isArchX64() const noexcept { return _arch == kArchX64; }
- inline bool isArchRISCV32() const noexcept { return _arch == kArchRISCV32; }
- inline bool isArchRISCV64() const noexcept { return _arch == kArchRISCV64; }
- inline bool isArchARM() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchARM; }
- inline bool isArchThumb() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchThumb; }
- inline bool isArchAArch64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchAArch64; }
- inline bool isArchMIPS32() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS32_LE; }
- inline bool isArchMIPS64() const noexcept { return (_arch & ~kArchBigEndianMask) == kArchMIPS64_LE; }
+ inline bool isArchX86() const noexcept { return _arch == Arch::kX86; }
+ inline bool isArchX64() const noexcept { return _arch == Arch::kX64; }
+ inline bool isArchARM() const noexcept { return isArchARM(_arch); }
+ inline bool isArchThumb() const noexcept { return isArchThumb(_arch); }
+ inline bool isArchAArch64() const noexcept { return isArchAArch64(_arch); }
+ inline bool isArchMIPS32() const noexcept { return isArchMIPS32(_arch); }
+ inline bool isArchMIPS64() const noexcept { return isArchMIPS64(_arch); }
+ inline bool isArchRISCV32() const noexcept { return _arch == Arch::kRISCV32; }
+ inline bool isArchRISCV64() const noexcept { return _arch == Arch::kRISCV64; }
//! Tests whether the architecture is 32-bit.
inline bool is32Bit() const noexcept { return is32Bit(_arch); }
@@ -432,45 +339,45 @@ public:
//! Tests whether this architecture is of X86 family.
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.
inline bool isFamilyARM() const noexcept { return isFamilyARM(_arch); }
//! Tests whether this architecture family is MISP or MIPS64.
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.
- inline bool isPlatformWindows() const noexcept { return _platform == kPlatformWindows; }
+ inline bool isPlatformWindows() const noexcept { return _platform == Platform::kWindows; }
//! 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.
- inline bool isPlatformHurd() const noexcept { return _platform == kPlatformHurd; }
+ inline bool isPlatformHurd() const noexcept { return _platform == Platform::kHurd; }
//! 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.
inline bool isPlatformBSD() const noexcept {
- return _platform == kPlatformFreeBSD ||
- _platform == kPlatformOpenBSD ||
- _platform == kPlatformNetBSD ||
- _platform == kPlatformDragonFlyBSD;
+ return _platform == Platform::kFreeBSD ||
+ _platform == Platform::kOpenBSD ||
+ _platform == Platform::kNetBSD ||
+ _platform == Platform::kDragonFlyBSD;
}
//! Tests whether the environment platform is any Apple platform (OSX, iOS, TVOS, WatchOS).
inline bool isPlatformApple() const noexcept {
- return _platform == kPlatformOSX ||
- _platform == kPlatformIOS ||
- _platform == kPlatformTVOS ||
- _platform == kPlatformWatchOS;
+ return _platform == Platform::kOSX ||
+ _platform == Platform::kIOS ||
+ _platform == Platform::kTVOS ||
+ _platform == Platform::kWatchOS;
}
//! 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.
- 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.
ASMJIT_API uint32_t stackAlignment() const noexcept;
@@ -479,134 +386,109 @@ public:
uint32_t registerSize() const noexcept { return registerSizeFromArch(_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`.
- inline void setSubArch(uint32_t subArch) noexcept { _subArch = uint8_t(subArch); }
+ inline void setSubArch(SubArch subArch) noexcept { _subArch = subArch; }
//! 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`.
- inline void setPlatform(uint32_t platform) noexcept { _platform = uint8_t(platform); }
- //! Sets the ABI to `abi`.
- inline void setAbi(uint32_t abi) noexcept { _abi = uint8_t(abi); }
- //! Sets the object format to `format`.
- inline void setFormat(uint32_t format) noexcept { _format = uint8_t(format); }
+ inline void setPlatform(Platform platform) noexcept { _platform = platform; }
+ //! Sets the ABI to `platformABI`.
+ inline void setPlatformABI(PlatformABI platformABI) noexcept { _platformABI = platformABI; }
+ //! Sets the object format to `objectFormat`.
+ inline void setObjectFormat(ObjectFormat objectFormat) noexcept { _objectFormat = objectFormat; }
//! \}
//! \name Static Utilities
//! \{
- static inline bool isValidArch(uint32_t arch) noexcept {
- return (arch & ~kArchBigEndianMask) != 0 &&
- (arch & ~kArchBigEndianMask) < kArchCount;
+ static inline bool isDefinedArch(Arch arch) noexcept {
+ return uint32_t(arch) <= uint32_t(Arch::kMaxValue);
+ }
+
+ 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.
- static inline bool is32Bit(uint32_t arch) noexcept {
- return (arch & kArch32BitMask) == kArch32BitMask;
+ static inline bool is32Bit(Arch arch) noexcept {
+ return (uint32_t(arch) & uint32_t(Arch::k32BitMask)) == uint32_t(Arch::k32BitMask);
}
//! Tests whether the given architecture `arch` is 64-bit.
- static inline bool is64Bit(uint32_t arch) noexcept {
- return (arch & kArch32BitMask) == 0;
+ static inline bool is64Bit(Arch arch) noexcept {
+ return (uint32_t(arch) & uint32_t(Arch::k32BitMask)) == 0;
}
//! Tests whether the given architecture `arch` is little endian.
- static inline bool isLittleEndian(uint32_t arch) noexcept {
- return (arch & kArchBigEndianMask) == 0;
+ static inline bool isLittleEndian(Arch arch) noexcept {
+ return uint32_t(arch) < uint32_t(Arch::kBigEndian);
}
//! Tests whether the given architecture `arch` is big endian.
- static inline bool isBigEndian(uint32_t arch) noexcept {
- return (arch & kArchBigEndianMask) == kArchBigEndianMask;
+ static inline bool isBigEndian(Arch arch) noexcept {
+ return uint32_t(arch) >= uint32_t(Arch::kBigEndian);
}
- //! Tests whether the given architecture is AArch64.
- static inline bool isArchAArch64(uint32_t arch) noexcept {
- arch &= ~kArchBigEndianMask;
- return arch == kArchAArch64;
+ //! Tests whether the given architecture is ARM or ARM_BE.
+ static inline bool isArchARM(Arch arch) noexcept {
+ return arch == Arch::kARM || arch == Arch::kARM_BE;
+ }
+
+ //! 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.
- static inline bool isFamilyX86(uint32_t arch) noexcept {
- return arch == kArchX86 ||
- arch == kArchX64;
- }
-
- //! Tests whether the given architecture family is RISC-V (both 32-bit and 64-bit).
- static inline bool isFamilyRISCV(uint32_t arch) noexcept {
- return arch == kArchRISCV32 ||
- arch == kArchRISCV64;
+ static inline bool isFamilyX86(Arch arch) noexcept {
+ return arch == Arch::kX86 || arch == Arch::kX64;
}
//! Tests whether the given architecture family is ARM, Thumb, or AArch64.
- static inline bool isFamilyARM(uint32_t arch) noexcept {
- arch &= ~kArchBigEndianMask;
- return arch == kArchARM ||
- arch == kArchAArch64 ||
- arch == kArchThumb;
+ static inline bool isFamilyARM(Arch arch) noexcept {
+ return isArchARM(arch) || isArchAArch64(arch) || isArchThumb(arch);
}
//! Tests whether the given architecture family is MISP or MIPS64.
- static inline bool isFamilyMIPS(uint32_t arch) noexcept {
- arch &= ~kArchBigEndianMask;
- return arch == kArchMIPS32_LE ||
- arch == kArchMIPS64_LE;
+ static inline bool isFamilyMIPS(Arch arch) noexcept {
+ return isArchMIPS32(arch) || isArchMIPS64(arch);
+ }
+
+ //! 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.
- static uint32_t registerSizeFromArch(uint32_t arch) noexcept {
+ static inline uint32_t registerSizeFromArch(Arch arch) noexcept {
return is32Bit(arch) ? 4u : 8u;
}
//! \}
};
-//! Returns the host environment constructed from preprocessor macros defined
-//! by the compiler.
-//!
-//! The returned environment should precisely match the target host architecture,
-//! sub-architecture, platform, and ABI.
-static ASMJIT_INLINE Environment hostEnvironment() noexcept {
- return Environment(Environment::kArchHost,
- Environment::kSubArchHost,
- Environment::kVendorHost,
- Environment::kPlatformHost,
- Environment::kAbiHost,
- Environment::kFormatUnknown);
-}
-
static_assert(sizeof(Environment) == 8,
"Environment must occupy exactly 8 bytes.");
//! \}
-#ifndef ASMJIT_NO_DEPRECATED
-class ASMJIT_DEPRECATED_STRUCT("Use Environment instead") ArchInfo : public Environment {
-public:
- inline ArchInfo() noexcept : Environment() {}
-
- inline ArchInfo(const Environment& other) noexcept : Environment(other) {}
- inline explicit ArchInfo(uint32_t arch, uint32_t subArch = kSubArchUnknown) noexcept
- : Environment(arch, subArch) {}
-
- enum Id : uint32_t {
- kIdNone = Environment::kArchUnknown,
- kIdX86 = Environment::kArchX86,
- kIdX64 = Environment::kArchX64,
- kIdA32 = Environment::kArchARM,
- kIdA64 = Environment::kArchAArch64,
- kIdHost = Environment::kArchHost
- };
-
- enum SubType : uint32_t {
- kSubIdNone = Environment::kSubArchUnknown
- };
-
- static inline ArchInfo host() noexcept { return ArchInfo(hostEnvironment()); }
-};
-#endif // !ASMJIT_NO_DEPRECATED
-
ASMJIT_END_NAMESPACE
#endif // ASMJIT_CORE_ENVIRONMENT_H_INCLUDED
diff --git a/src/asmjit/core/errorhandler.cpp b/src/asmjit/core/errorhandler.cpp
index 8372d75..5a7dac5 100644
--- a/src/asmjit/core/errorhandler.cpp
+++ b/src/asmjit/core/errorhandler.cpp
@@ -1,36 +1,13 @@
-
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#include "../core/errorhandler.h"
ASMJIT_BEGIN_NAMESPACE
-// ============================================================================
-// [asmjit::ErrorHandler]
-// ============================================================================
-
ErrorHandler::ErrorHandler() noexcept {}
ErrorHandler::~ErrorHandler() noexcept {}
diff --git a/src/asmjit/core/errorhandler.h b/src/asmjit/core/errorhandler.h
index b26a654..5151d43 100644
--- a/src/asmjit/core/errorhandler.h
+++ b/src/asmjit/core/errorhandler.h
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
#define ASMJIT_CORE_ERRORHANDLER_H_INCLUDED
@@ -31,41 +13,28 @@ ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_error_handling
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
class BaseEmitter;
-// ============================================================================
-// [asmjit::ErrorHandler]
-// ============================================================================
-
//! Error handler can be used to override the default behavior of error handling.
//!
-//! It's available to all classes that inherit `BaseEmitter`. Override
-//! \ref ErrorHandler::handleError() to implement your own error handler.
+//! It's available to all classes that inherit `BaseEmitter`. Override \ref ErrorHandler::handleError() to implement
+//! your own error handler.
//!
//! The following use-cases are supported:
//!
-//! - Record the error and continue code generation. This is the simplest
-//! approach that can be used to at least log possible errors.
-//! - Throw an exception. AsmJit doesn't use exceptions and is completely
-//! exception-safe, but it's perfectly legal to throw an exception from
-//! the error handler.
-//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler,
-//! Builder and Compiler to a consistent state before calling \ref handleError(),
-//! so `longjmp()` can be used without issues to cancel the code-generation if
-//! an error occurred. This method can be used if exception handling in your
-//! project is turned off and you still want some comfort. In most cases it
-//! should be safe as AsmJit uses \ref Zone memory and the ownership of memory
-//! it allocates always ends with the instance that allocated it. If using this
-//! approach please never jump outside the life-time of \ref CodeHolder and
-//! \ref BaseEmitter.
+//! - Record the error and continue code generation. This is the simplest approach that can be used to at least log
+//! possible errors.
+//! - Throw an exception. AsmJit doesn't use exceptions and is completely exception-safe, but it's perfectly legal
+//! to throw an exception from the error handler.
+//! - Use plain old C's `setjmp()` and `longjmp()`. Asmjit always puts Assembler, Builder and Compiler to
+//! a consistent state before calling \ref handleError(), so `longjmp()` can be used without issues to cancel the
+//! code generation if an error occurred. This method can be used if exception handling in your project is turned
+//! off and you still want some comfort. In most cases it should be safe as AsmJit uses \ref Zone memory and the
+//! ownership of memory it allocates always ends with the instance that allocated it. If using this approach please
+//! never jump outside the life-time of \ref CodeHolder and \ref BaseEmitter.
//!
-//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter,
-//! which has a priority. The example below uses error handler that just prints
-//! the error, but lets AsmJit continue:
+//! \ref ErrorHandler can be attached to \ref CodeHolder or \ref BaseEmitter, which has a priority. The example below
+//! uses error handler that just prints the error, but lets AsmJit continue:
//!
//! ```
//! // Error Handling #1 - Logging and returning Error.
@@ -108,12 +77,10 @@ class BaseEmitter;
//! }
//! ```
//!
-//! If error happens during instruction emitting / encoding the assembler behaves
-//! transactionally - the output buffer won't advance if encoding failed, thus
-//! either a fully encoded instruction or nothing is emitted. The error handling
-//! shown above is useful, but it's still not the best way of dealing with errors
-//! in AsmJit. The following example shows how to use exception handling to handle
-//! errors in a more C++ way:
+//! If error happens during instruction emitting / encoding the assembler behaves transactionally - the output buffer
+//! won't advance if encoding failed, thus either a fully encoded instruction or nothing is emitted. The error handling
+//! shown above is useful, but it's still not the best way of dealing with errors in AsmJit. The following example
+//! shows how to use exception handling to handle errors in a more C++ way:
//!
//! ```
//! // Error Handling #2 - Throwing an exception.
@@ -168,13 +135,10 @@ class BaseEmitter;
//! }
//! ```
//!
-//! If C++ exceptions are not what you like or your project turns off them
-//! completely there is still a way of reducing the error handling to a minimum
-//! by using a standard setjmp/longjmp approach. AsmJit is exception-safe and
-//! cleans up everything before calling the ErrorHandler, so any approach is
-//! safe. You can simply jump from the error handler without causing any
-//! side-effects or memory leaks. The following example demonstrates how it
-//! could be done:
+//! If C++ exceptions are not what you like or your project turns off them completely there is still a way of reducing
+//! the error handling to a minimum by using a standard setjmp/longjmp approach. AsmJit is exception-safe and cleans
+//! up everything before calling the ErrorHandler, so any approach is safe. You can simply jump from the error handler
+//! without causing any side-effects or memory leaks. The following example demonstrates how it could be done:
//!
//! ```
//! // Error Handling #3 - Using setjmp/longjmp if exceptions are not allowed.
@@ -223,40 +187,37 @@ class ASMJIT_VIRTAPI ErrorHandler {
public:
ASMJIT_BASE_CLASS(ErrorHandler)
- // --------------------------------------------------------------------------
- // [Construction / Destruction]
- // --------------------------------------------------------------------------
+ //! \name Construction & Destruction
+ //! \{
//! Creates a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler() noexcept;
//! Destroys the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler() noexcept;
- // --------------------------------------------------------------------------
- // [Handle Error]
- // --------------------------------------------------------------------------
+ //! \}
+
+ //! \name Interface
+ //! \{
//! Error handler (must be reimplemented).
//!
- //! Error handler is called after an error happened and before it's propagated
- //! to the caller. There are multiple ways how the error handler can be used:
+ //! Error handler is called after an error happened and before it's propagated to the caller. There are multiple
+ //! ways how the error handler can be used:
//!
- //! 1. User-based error handling without throwing exception or using C's
- //! `longjmp()`. This is for users that don't use exceptions and want
- //! customized error handling.
+ //! 1. User-based error handling without throwing exception or using C's`longjmp()`. This is for users that don't
+ //! use exceptions and want customized error handling.
//!
- //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely
- //! exception-safe, but you can throw exception from your error handler if
- //! this way is the preferred way of handling errors in your project.
+ //! 2. Throwing an exception. AsmJit doesn't use exceptions and is completely exception-safe, but you can throw
+ //! exception from your error handler if this way is the preferred way of handling errors in your project.
//!
- //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts
- //! `BaseEmitter` to a consistent state before calling `handleError()`
- //! so `longjmp()` can be used without any issues to cancel the code
- //! generation if an error occurred. There is no difference between
- //! exceptions and `longjmp()` from AsmJit's perspective, however,
- //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you
- //! would leak memory.
+ //! 3. Using plain old C's `setjmp()` and `longjmp()`. Asmjit always puts `BaseEmitter` to a consistent state before
+ //! calling `handleError()` so `longjmp()` can be used without any issues to cancel the code generation if an
+ //! error occurred. There is no difference between exceptions and `longjmp()` from AsmJit's perspective, however,
+ //! never jump outside of `CodeHolder` and `BaseEmitter` scope as you would leak memory.
virtual void handleError(Error err, const char* message, BaseEmitter* origin) = 0;
+
+ //! \}
};
//! \}
diff --git a/src/asmjit/core/features.h b/src/asmjit/core/features.h
deleted file mode 100644
index 0f2cfe2..0000000
--- a/src/asmjit/core/features.h
+++ /dev/null
@@ -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 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
- inline T& as() noexcept { return static_cast(*this); }
-
- //! Casts this base class into a derived type `T` (const).
- template
- inline const T& as() const noexcept { return static_cast(*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
- 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
- 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
diff --git a/src/asmjit/core/formatter.cpp b/src/asmjit/core/formatter.cpp
index 124eebf..efa0c47 100644
--- a/src/asmjit/core/formatter.cpp
+++ b/src/asmjit/core/formatter.cpp
@@ -1,25 +1,7 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#include "../core/api-build_p.h"
#ifndef ASMJIT_NO_LOGGING
@@ -29,7 +11,7 @@
#include "../core/codeholder.h"
#include "../core/compiler.h"
#include "../core/emitter.h"
-#include "../core/formatter.h"
+#include "../core/formatter_p.h"
#include "../core/string.h"
#include "../core/support.h"
#include "../core/type.h"
@@ -48,10 +30,6 @@ ASMJIT_BEGIN_NAMESPACE
class VirtReg;
#endif
-// ============================================================================
-// [asmjit::Formatter]
-// ============================================================================
-
namespace Formatter {
static const char wordNameTable[][8] = {
@@ -72,40 +50,44 @@ static const char wordNameTable[][8] = {
};
-Error formatTypeId(String& sb, uint32_t typeId) noexcept {
- if (typeId == Type::kIdVoid)
+Error formatTypeId(String& sb, TypeId typeId) noexcept {
+ if (typeId == TypeId::kVoid)
return sb.append("void");
- if (!Type::isValid(typeId))
+ if (!TypeUtils::isValid(typeId))
return sb.append("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 (baseId) {
- case Type::kIdIntPtr : typeName = "iptr" ; break;
- case Type::kIdUIntPtr: typeName = "uptr" ; break;
- case Type::kIdI8 : typeName = "i8" ; break;
- case Type::kIdU8 : typeName = "u8" ; break;
- case Type::kIdI16 : typeName = "i16" ; break;
- case Type::kIdU16 : typeName = "u16" ; break;
- case Type::kIdI32 : typeName = "i32" ; break;
- case Type::kIdU32 : typeName = "u32" ; break;
- case Type::kIdI64 : typeName = "i64" ; break;
- case Type::kIdU64 : typeName = "u64" ; break;
- case Type::kIdF32 : typeName = "f32" ; break;
- case Type::kIdF64 : typeName = "f64" ; break;
- case Type::kIdF80 : typeName = "f80" ; break;
- case Type::kIdMask8 : typeName = "mask8" ; break;
- case Type::kIdMask16 : typeName = "mask16"; break;
- case Type::kIdMask32 : typeName = "mask32"; break;
- case Type::kIdMask64 : typeName = "mask64"; break;
- case Type::kIdMmx32 : typeName = "mmx32" ; break;
- case Type::kIdMmx64 : typeName = "mmx64" ; break;
+ switch (scalarType) {
+ case TypeId::kIntPtr : typeName = "intptr" ; break;
+ case TypeId::kUIntPtr: typeName = "uintptr"; break;
+ case TypeId::kInt8 : typeName = "int8" ; break;
+ case TypeId::kUInt8 : typeName = "uint8" ; break;
+ case TypeId::kInt16 : typeName = "int16" ; break;
+ case TypeId::kUInt16 : typeName = "uint16" ; break;
+ case TypeId::kInt32 : typeName = "int32" ; break;
+ case TypeId::kUInt32 : typeName = "uint32" ; break;
+ case TypeId::kInt64 : typeName = "int64" ; break;
+ case TypeId::kUInt64 : typeName = "uint64" ; break;
+ case TypeId::kFloat32: typeName = "float32"; break;
+ case TypeId::kFloat64: typeName = "float64"; break;
+ case TypeId::kFloat80: typeName = "float80"; break;
+ case TypeId::kMask8 : typeName = "mask8" ; break;
+ case TypeId::kMask16 : typeName = "mask16" ; break;
+ case TypeId::kMask32 : typeName = "mask32" ; break;
+ case TypeId::kMask64 : typeName = "mask64" ; break;
+ case TypeId::kMmx32 : typeName = "mmx32" ; break;
+ case TypeId::kMmx64 : typeName = "mmx64" ; break;
+
+ default:
+ typeName = "unknown";
+ break;
}
- uint32_t baseSize = Type::sizeOf(baseId);
+ uint32_t baseSize = TypeUtils::sizeOf(scalarType);
if (typeSize > baseSize) {
uint32_t count = typeSize / baseSize;
return sb.appendFormat("%sx%u", typeName, unsigned(count));
@@ -117,7 +99,7 @@ Error formatTypeId(String& sb, uint32_t typeId) noexcept {
Error formatFeature(
String& sb,
- uint32_t arch,
+ Arch arch,
uint32_t featureId) noexcept {
#if !defined(ASMJIT_NO_X86)
@@ -135,7 +117,7 @@ Error formatFeature(
Error formatLabel(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
uint32_t labelId) noexcept {
@@ -159,6 +141,9 @@ Error formatLabel(
ASMJIT_PROPAGATE(sb.append('.'));
}
+
+ if (le->type() == LabelType::kAnonymous)
+ ASMJIT_PROPAGATE(sb.append("L%u@", labelId));
return sb.append(le->name());
}
else {
@@ -168,10 +153,10 @@ Error formatLabel(
Error formatRegister(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
- uint32_t regType,
+ Arch arch,
+ RegType regType,
uint32_t regId) noexcept {
#if !defined(ASMJIT_NO_X86)
@@ -189,9 +174,9 @@ Error formatRegister(
Error formatOperand(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
+ Arch arch,
const Operand_& op) noexcept {
#if !defined(ASMJIT_NO_X86)
@@ -209,21 +194,21 @@ Error formatOperand(
ASMJIT_API Error formatDataType(
String& sb,
- uint32_t formatFlags,
- uint32_t arch,
- uint32_t typeId) noexcept
+ FormatFlags formatFlags,
+ Arch arch,
+ TypeId typeId) noexcept
{
DebugUtils::unused(formatFlags);
- if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
+ if (ASMJIT_UNLIKELY(uint32_t(arch) > uint32_t(Arch::kMaxValue)))
return DebugUtils::errored(kErrorInvalidArch);
- uint32_t typeSize = Type::sizeOf(typeId);
+ uint32_t typeSize = TypeUtils::sizeOf(typeId);
if (typeSize == 0 || typeSize > 8)
return DebugUtils::errored(kErrorInvalidState);
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 {
@@ -232,7 +217,7 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
sb.append(' ');
for (size_t i = 0; i < itemCount; i++) {
- uint64_t v;
+ uint64_t v = 0;
if (i != 0)
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;
}
- ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, String::kFormatAlternate));
+ ASMJIT_PROPAGATE(sb.appendUInt(v, 16, typeSize * 2, StringFormatFlags::kAlternate));
data += typeSize;
}
@@ -253,16 +238,16 @@ static Error formatDataHelper(String& sb, const char* typeName, uint32_t typeSiz
Error formatData(
String& sb,
- uint32_t formatFlags,
- uint32_t arch,
- uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount) noexcept
+ FormatFlags formatFlags,
+ Arch arch,
+ TypeId typeId, const void* data, size_t itemCount, size_t repeatCount) noexcept
{
DebugUtils::unused(formatFlags);
- if (ASMJIT_UNLIKELY(arch >= Environment::kArchCount))
+ if (ASMJIT_UNLIKELY(!Environment::isDefinedArch(arch)))
return DebugUtils::errored(kErrorInvalidArch);
- uint32_t typeSize = Type::sizeOf(typeId);
+ uint32_t typeSize = TypeUtils::sizeOf(typeId);
if (typeSize == 0)
return DebugUtils::errored(kErrorInvalidState);
@@ -277,7 +262,7 @@ Error formatData(
}
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)
ASMJIT_PROPAGATE(sb.appendFormat(".repeat %zu ", repeatCount));
@@ -287,9 +272,9 @@ Error formatData(
Error formatInstruction(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
+ Arch arch,
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
#if !defined(ASMJIT_NO_X86)
@@ -308,8 +293,8 @@ Error formatInstruction(
#ifndef ASMJIT_NO_BUILDER
#ifndef ASMJIT_NO_COMPILER
-static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept {
- uint32_t typeId = value.typeId();
+static Error formatFuncValue(String& sb, FormatFlags formatFlags, const BaseEmitter* emitter, FuncValue value) noexcept {
+ TypeId typeId = value.typeId();
ASMJIT_PROPAGATE(formatTypeId(sb, typeId));
if (value.isAssigned()) {
@@ -338,10 +323,10 @@ static Error formatFuncValue(String& sb, uint32_t formatFlags, const BaseEmitter
static Error formatFuncValuePack(
String& sb,
- uint32_t formatFlags,
- const BaseEmitter* emitter,
+ FormatFlags formatFlags,
+ const BaseCompiler* cc,
const FuncValuePack& pack,
- VirtReg* const* vRegs) noexcept {
+ const RegOnly* vRegs) noexcept {
size_t count = pack.count();
if (!count)
@@ -358,11 +343,16 @@ static Error formatFuncValuePack(
if (valueIndex)
ASMJIT_PROPAGATE(sb.append(", "));
- ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, emitter, value));
+ ASMJIT_PROPAGATE(formatFuncValue(sb, formatFlags, cc, value));
if (vRegs) {
- static const char nullRet[] = "";
- ASMJIT_PROPAGATE(sb.appendFormat(" %s", vRegs[valueIndex] ? vRegs[valueIndex]->name() : nullRet));
+ const VirtReg* virtReg = nullptr;
+ static const char nullReg[] = "";
+
+ 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(
String& sb,
- uint32_t formatFlags,
- const BaseEmitter* emitter,
+ FormatFlags formatFlags,
+ const BaseCompiler* cc,
const FuncDetail& fd) noexcept {
- return formatFuncValuePack(sb, formatFlags, emitter, fd.retPack(), nullptr);
+ return formatFuncValuePack(sb, formatFlags, cc, fd.retPack(), nullptr);
}
static Error formatFuncArgs(
String& sb,
- uint32_t formatFlags,
- const BaseEmitter* emitter,
+ FormatFlags formatFlags,
+ const BaseCompiler* cc,
const FuncDetail& fd,
const FuncNode::ArgPack* argPacks) noexcept {
@@ -396,7 +386,7 @@ static Error formatFuncArgs(
if (argIndex)
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;
@@ -405,25 +395,26 @@ static Error formatFuncArgs(
Error formatNode(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder,
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()));
+ size_t startLineIndex = sb.size();
+
switch (node->type()) {
- case BaseNode::kNodeInst:
- case BaseNode::kNodeJump: {
+ case NodeType::kInst:
+ case NodeType::kJump: {
const InstNode* instNode = node->as();
- ASMJIT_PROPAGATE(
- formatInstruction(sb, formatFlags, builder,
- builder->arch(),
- instNode->baseInst(), instNode->operands(), instNode->opCount()));
+ ASMJIT_PROPAGATE(formatInstruction(sb, formatOptions.flags(), builder,
+ builder->arch(),
+ instNode->baseInst(), instNode->operands(), instNode->opCount()));
break;
}
- case BaseNode::kNodeSection: {
+ case NodeType::kSection: {
const SectionNode* sectionNode = node->as();
if (builder->_code->isSectionValid(sectionNode->id())) {
const Section* section = builder->_code->sectionById(sectionNode->id());
@@ -432,65 +423,64 @@ Error formatNode(
break;
}
- case BaseNode::kNodeLabel: {
+ case NodeType::kLabel: {
const LabelNode* labelNode = node->as();
- ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, labelNode->labelId()));
+ ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, labelNode->labelId()));
ASMJIT_PROPAGATE(sb.append(":"));
break;
}
- case BaseNode::kNodeAlign: {
+ case NodeType::kAlign: {
const AlignNode* alignNode = node->as();
- ASMJIT_PROPAGATE(
- sb.appendFormat(".align %u (%s)",
- alignNode->alignment(),
- alignNode->alignMode() == kAlignCode ? "code" : "data"));
+ ASMJIT_PROPAGATE(sb.appendFormat(".align %u (%s)",
+ alignNode->alignment(),
+ alignNode->alignMode() == AlignMode::kCode ? "code" : "data"));
break;
}
- case BaseNode::kNodeEmbedData: {
+ case NodeType::kEmbedData: {
const EmbedDataNode* embedNode = node->as();
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()));
break;
}
- case BaseNode::kNodeEmbedLabel: {
+ case NodeType::kEmbedLabel: {
const EmbedLabelNode* embedNode = node->as();
ASMJIT_PROPAGATE(sb.append(".label "));
- ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, embedNode->labelId()));
+ ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, embedNode->labelId()));
break;
}
- case BaseNode::kNodeEmbedLabelDelta: {
+ case NodeType::kEmbedLabelDelta: {
const EmbedLabelDeltaNode* embedNode = node->as();
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(formatLabel(sb, formatFlags, builder, embedNode->baseLabelId()));
+ ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, embedNode->baseLabelId()));
ASMJIT_PROPAGATE(sb.append(")"));
break;
}
- case BaseNode::kNodeConstPool: {
+ case NodeType::kConstPool: {
const ConstPoolNode* constPoolNode = node->as();
ASMJIT_PROPAGATE(sb.appendFormat("[ConstPool Size=%zu Alignment=%zu]", constPoolNode->size(), constPoolNode->alignment()));
break;
};
- case BaseNode::kNodeComment: {
+ case NodeType::kComment: {
const CommentNode* commentNode = node->as();
ASMJIT_PROPAGATE(sb.appendFormat("; %s", commentNode->inlineComment()));
break;
}
- case BaseNode::kNodeSentinel: {
+ case NodeType::kSentinel: {
const SentinelNode* sentinelNode = node->as();
const char* sentinelName = nullptr;
switch (sentinelNode->sentinelType()) {
- case SentinelNode::kSentinelFuncEnd:
+ case SentinelType::kFuncEnd:
sentinelName = "[FuncEnd]";
break;
@@ -504,20 +494,22 @@ Error formatNode(
}
#ifndef ASMJIT_NO_COMPILER
- case BaseNode::kNodeFunc: {
+ case NodeType::kFunc: {
const FuncNode* funcNode = node->as();
- ASMJIT_PROPAGATE(formatLabel(sb, formatFlags, builder, funcNode->labelId()));
- ASMJIT_PROPAGATE(sb.append(": "));
+ if (builder->isCompiler()) {
+ ASMJIT_PROPAGATE(formatLabel(sb, formatOptions.flags(), builder, funcNode->labelId()));
+ ASMJIT_PROPAGATE(sb.append(": "));
- ASMJIT_PROPAGATE(formatFuncRets(sb, formatFlags, builder, funcNode->detail()));
- ASMJIT_PROPAGATE(sb.append(" Func("));
- ASMJIT_PROPAGATE(formatFuncArgs(sb, formatFlags, builder, funcNode->detail(), funcNode->argPacks()));
- ASMJIT_PROPAGATE(sb.append(")"));
+ ASMJIT_PROPAGATE(formatFuncRets(sb, formatOptions.flags(), static_cast(builder), funcNode->detail()));
+ ASMJIT_PROPAGATE(sb.append(" Func("));
+ ASMJIT_PROPAGATE(formatFuncArgs(sb, formatOptions.flags(), static_cast(builder), funcNode->detail(), funcNode->argPacks()));
+ ASMJIT_PROPAGATE(sb.append(")"));
+ }
break;
}
- case BaseNode::kNodeFuncRet: {
+ case NodeType::kFuncRet: {
const FuncRetNode* retNode = node->as();
ASMJIT_PROPAGATE(sb.append("[FuncRet]"));
@@ -525,18 +517,17 @@ Error formatNode(
const Operand_& op = retNode->_opArray[i];
if (!op.isNone()) {
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;
}
- case BaseNode::kNodeInvoke: {
+ case NodeType::kInvoke: {
const InvokeNode* invokeNode = node->as();
- ASMJIT_PROPAGATE(
- formatInstruction(sb, formatFlags, builder,
- builder->arch(),
- invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount()));
+ ASMJIT_PROPAGATE(formatInstruction(sb, formatOptions.flags(), builder,
+ builder->arch(),
+ invokeNode->baseInst(), invokeNode->operands(), invokeNode->opCount()));
break;
}
#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;
}
-
Error formatNodeList(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder) noexcept {
- return formatNodeList(sb, formatFlags, builder, builder->firstNode(), nullptr);
+ return formatNodeList(sb, formatOptions, builder, builder->firstNode(), nullptr);
}
Error formatNodeList(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder,
const BaseNode* begin,
const BaseNode* end) noexcept {
const BaseNode* node = begin;
while (node != end) {
- ASMJIT_PROPAGATE(formatNode(sb, formatFlags, builder, node));
+ ASMJIT_PROPAGATE(formatNode(sb, formatOptions, builder, node));
ASMJIT_PROPAGATE(sb.append('\n'));
node = node->next();
}
diff --git a/src/asmjit/core/formatter.h b/src/asmjit/core/formatter.h
index 513d764..d7a4b93 100644
--- a/src/asmjit/core/formatter.h
+++ b/src/asmjit/core/formatter.h
@@ -1,126 +1,98 @@
-// AsmJit - Machine code generation for C++
+// This file is part of AsmJit project
//
-// * 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.
+// See asmjit.h or LICENSE.md for license and copyright information
+// SPDX-License-Identifier: Zlib
#ifndef ASMJIT_CORE_FORMATTER_H_INCLUDED
#define ASMJIT_CORE_FORMATTER_H_INCLUDED
+#include "../core/globals.h"
#include "../core/inst.h"
#include "../core/string.h"
-
-#ifndef ASMJIT_NO_LOGGING
+#include "../core/support.h"
ASMJIT_BEGIN_NAMESPACE
//! \addtogroup asmjit_logging
//! \{
-// ============================================================================
-// [Forward Declarations]
-// ============================================================================
-
+class BaseBuilder;
class BaseEmitter;
+class BaseNode;
struct Operand_;
-#ifndef ASMJIT_NO_BUILDER
-class BaseBuilder;
-class BaseNode;
-#endif
+//! Format flags used by \ref Logger and \ref FormatOptions.
+enum class FormatFlags : uint32_t {
+ //! No formatting flags.
+ kNone = 0u,
-#ifndef ASMJIT_NO_COMPILER
-class BaseCompiler;
-#endif
+ //! Show also binary form of each logged instruction (Assembler).
+ kMachineCode = 0x00000001u,
+ //! 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)
-// ============================================================================
-// [asmjit::FormatOptions]
-// ============================================================================
+//! Format indentation group, used by \ref 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.
class FormatOptions {
public:
- //! Format flags, see \ref Flags.
- uint32_t _flags;
- //! Indentation by type, see \ref IndentationType.
- uint8_t _indentation[4];
-
- //! Flags can enable a logging feature.
- enum Flags : uint32_t {
- //! No flags.
- kNoFlags = 0u,
-
- //! Show also binary form of each logged instruction (Assembler).
- kFlagMachineCode = 0x00000001u,
- //! Show a text explanation of some immediate values.
- kFlagExplainImms = 0x00000002u,
- //! Use hexadecimal notation of immediate values.
- kFlagHexImms = 0x00000004u,
- //! Use hexadecimal notation of address offsets.
- kFlagHexOffsets = 0x00000008u,
- //! Show casts between virtual register types (Compiler).
- kFlagRegCasts = 0x00000010u,
- //! Show positions associated with nodes (Compiler).
- kFlagPositions = 0x00000020u,
- //! Annotate nodes that are lowered by passes.
- kFlagAnnotations = 0x00000040u,
-
- // TODO: These must go, keep this only for formatting.
- //! Show an additional output from passes.
- kFlagDebugPasses = 0x00000080u,
- //! Show an additional output from RA.
- kFlagDebugRA = 0x00000100u
- };
-
- //! Describes indentation type of code, label, or comment in logger output.
- enum IndentationType : uint32_t {
- //! Indentation used for instructions and directives.
- kIndentationCode = 0u,
- //! Indentation used for labels and function nodes.
- kIndentationLabel = 1u,
- //! Indentation used for comments (not inline comments).
- kIndentationComment = 2u,
- //! \cond INTERNAL
- //! Reserved for future use.
- kIndentationReserved = 3u
- //! \endcond
- };
-
- //! \name Construction & Destruction
+ //! \name Members
//! \{
- //! Creates a default-initialized FormatOptions.
- constexpr FormatOptions() noexcept
- : _flags(0),
- _indentation { 0, 0, 0, 0 } {}
+ //! Format flags.
+ FormatFlags _flags = FormatFlags::kNone;
+ //! Indentations for each indentation group.
+ Support::Array _indentation {};
+ //! Paddings for each padding group.
+ Support::Array _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.
inline void reset() noexcept {
- _flags = 0;
- _indentation[0] = 0;
- _indentation[1] = 0;
- _indentation[2] = 0;
- _indentation[3] = 0;
+ _flags = FormatFlags::kNone;
+ _indentation.fill(uint8_t(0));
+ _padding.fill(uint16_t(0));
}
//! \}
@@ -129,104 +101,109 @@ public:
//! \{
//! 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.
- constexpr bool hasFlag(uint32_t flag) const noexcept { return (_flags & flag) != 0; }
- //! Resets all format flags to `flags`.
- inline void setFlags(uint32_t flags) noexcept { _flags = flags; }
- //! Adds `flags` to format flags.
- inline void addFlags(uint32_t flags) noexcept { _flags |= flags; }
- //! Removes `flags` from format flags.
- inline void clearFlags(uint32_t flags) noexcept { _flags &= ~flags; }
+ inline bool hasFlag(FormatFlags flag) const noexcept { return Support::test(_flags, flag); }
- //! Returns indentation for the given `type`, see \ref IndentationType.
- constexpr uint8_t indentation(uint32_t type) const noexcept { return _indentation[type]; }
- //! Sets indentation for the given `type`, see \ref IndentationType.
- inline void setIndentation(uint32_t type, uint32_t n) noexcept { _indentation[type] = uint8_t(n); }
- //! Resets indentation for the given `type` to zero.
- inline void resetIndentation(uint32_t type) noexcept { _indentation[type] = uint8_t(0); }
+ //! Resets all format flags to `flags`.
+ inline void setFlags(FormatFlags flags) noexcept { _flags = flags; }
+ //! Adds `flags` to format flags.
+ inline void addFlags(FormatFlags flags) noexcept { _flags |= flags; }
+ //! Removes `flags` from format flags.
+ 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.
namespace Formatter {
+#ifndef ASMJIT_NO_LOGGING
+
//! Appends a formatted `typeId` to the output string `sb`.
ASMJIT_API Error formatTypeId(
String& sb,
- uint32_t typeId) noexcept;
+ TypeId typeId) noexcept;
//! Appends a formatted `featureId` to the output string `sb`.
//!
-//! See \ref BaseFeatures.
+//! See \ref CpuFeatures.
ASMJIT_API Error formatFeature(
String& sb,
- uint32_t arch,
+ Arch arch,
uint32_t featureId) noexcept;
//! Appends a formatted register to the output string `sb`.
//!
-//! \note Emitter is optional, but it's required to format virtual registers,
-//! which won't be formatted properly if the `emitter` is not provided.
+//! \note Emitter is optional, but it's required to format virtual registers, which won't be formatted properly
+//! if the `emitter` is not provided.
ASMJIT_API Error formatRegister(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
- uint32_t regType,
+ Arch arch,
+ RegType regType,
uint32_t regId) noexcept;
//! Appends a formatted label to the output string `sb`.
//!
-//! \note Emitter is optional, but it's required to format named labels
-//! properly, otherwise the formatted as it is an anonymous label.
+//! \note Emitter is optional, but it's required to format named labels properly, otherwise the formatted as
+//! it is an anonymous label.
ASMJIT_API Error formatLabel(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
uint32_t labelId) noexcept;
//! Appends a formatted operand to the output string `sb`.
//!
-//! \note Emitter is optional, but it's required to format named labels and
-//! virtual registers. See \ref formatRegister() and \ref formatLabel() for
-//! more details.
+//! \note Emitter is optional, but it's required to format named labels and virtual registers. See
+//! \ref formatRegister() and \ref formatLabel() for more details.
ASMJIT_API Error formatOperand(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
+ Arch arch,
const Operand_& op) noexcept;
//! Appends a formatted data-type to the output string `sb`.
ASMJIT_API Error formatDataType(
String& sb,
- uint32_t formatFlags,
- uint32_t arch,
- uint32_t typeId) noexcept;
+ FormatFlags formatFlags,
+ Arch arch,
+ TypeId typeId) noexcept;
//! Appends a formatted data to the output string `sb`.
ASMJIT_API Error formatData(
String& sb,
- uint32_t formatFlags,
- uint32_t arch,
- uint32_t typeId, const void* data, size_t itemCount, size_t repeatCount = 1) noexcept;
+ FormatFlags formatFlags,
+ Arch arch,
+ TypeId typeId, const void* data, size_t itemCount, size_t repeatCount = 1) noexcept;
//! Appends a formatted instruction to the output string `sb`.
//!
-//! \note Emitter is optional, but it's required to format named labels and
-//! virtual registers. See \ref formatRegister() and \ref formatLabel() for
-//! more details.
+//! \note Emitter is optional, but it's required to format named labels and virtual registers. See
+//! \ref formatRegister() and \ref formatLabel() for more details.
ASMJIT_API Error formatInstruction(
String& sb,
- uint32_t formatFlags,
+ FormatFlags formatFlags,
const BaseEmitter* emitter,
- uint32_t arch,
+ Arch arch,
const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept;
#ifndef ASMJIT_NO_BUILDER
@@ -235,7 +212,7 @@ ASMJIT_API Error formatInstruction(
//! The `node` must belong to the provided `builder`.
ASMJIT_API Error formatNode(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder,
const BaseNode* node) noexcept;
@@ -244,27 +221,27 @@ ASMJIT_API Error formatNode(
//! All nodes that are part of the given `builder` will be appended.
ASMJIT_API Error formatNodeList(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder) noexcept;
//! Appends formatted nodes to the output string `sb`.
//!
-//! This function works the same as \ref formatNode(), but appends more nodes
-//! to the output string, separating each node with a newline '\n' character.
+//! This function works the same as \ref formatNode(), but appends more nodes to the output string,
+//! separating each node with a newline '\n' character.
ASMJIT_API Error formatNodeList(
String& sb,
- uint32_t formatFlags,
+ const FormatOptions& formatOptions,
const BaseBuilder* builder,
const BaseNode* begin,
const BaseNode* end) noexcept;
#endif
+#endif
+
} // {Formatter}
//! \}
ASMJIT_END_NAMESPACE
-#endif
-
#endif // ASMJIT_CORE_FORMATTER_H_INCLUDED
diff --git a/src/asmjit/core/formatter_p.h b/src/asmjit/core/formatter_p.h
new file mode 100644
index 0000000..6070fd7
--- /dev/null
+++ b/src/asmjit/core/formatter_p.h
@@ -0,0 +1,34 @@
+// This file is part of AsmJit project