- Moved to cxxtool to generate build.h compiler and platform based definitions.

- Compiler no longer works on its own, it requires Assembler.
- Labels created by Assembler and Compiler now share their IDs, so they can be used nearly interchangeably without weird side-effects and hacks.
- Renamed getError() and setError() to getLastError() and setLastError().
- Renamed compiler nodes to "HL" nodes (preparation for HLStream).
- Renamed FuncConv to CallConv.
- Function calling convention is now part of FuncPrototype.
- Added a possibility to align by inserting zeros (kAlignZero)
- Fixed assertion in X86Compiler that didn't like unhandled function argument(s).
- Added Compiler::embedConstPool() helper, which can be handy if you use your own ConstPool.
- Code refactorization and other minor changes.
- CpuTicks::now() renamed to Utils::getTickCount().
- error.h merged with globals.h
- Documentation updates related to recent API changes.
This commit is contained in:
kobalicek
2015-12-07 07:34:25 +01:00
parent 6758955e8c
commit 3fcd65cf80
90 changed files with 11737 additions and 13230 deletions

View File

@@ -21,15 +21,26 @@ matrix:
compiler: gcc compiler: gcc
before_install: before_install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo add-apt-repository ppa:kubuntu-ppa/backports -y; fi; - if [ "$TRAVIS_OS_NAME" = "linux" ]; then
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update; fi; CMAKE_PACKAGE="cmake-3.3.2-Linux-x86_64"
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake gcc-multilib g++-multilib valgrind; fi; && wget https://www.cmake.org/files/v3.3/${CMAKE_PACKAGE}.tar.gz --no-check-certificate
&& sudo apt-get -qq update
&& sudo apt-get -qq install gcc-multilib g++-multilib valgrind
&& tar -xzf ${CMAKE_PACKAGE}.tar.gz
&& sudo cp -fR ${CMAKE_PACKAGE}/* /usr
;
else
brew update
&& brew unlink cmake
&& brew install -v cmake
;
fi
before_script: before_script:
- mkdir build - mkdir build
- cd build - cd build
- cmake --version - cmake --version
- cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 - cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE="$BUILD_TYPE" -DASMJIT_BUILD_TEST=1
- cd .. - cd ..
script: script:

66
BREAKING.md Normal file
View File

@@ -0,0 +1,66 @@
2015-12-07
----------
Compiler now attaches to Assembler. This change was required to create resource sharing where Assembler is the central part and Compiler is a "high-level" part that serializes to it. It's an incremental work to implement sections and to allow code generators to create executables and libraries.
Also, Compiler has no longer Logger interface, it uses Assembler's one after it's attached to it.
```
JitRuntime runtime;
X86Compiler c(&runtime);
// ... code generation ...
void* p = c.make();
```
to
```
JitRuntime runtime;
X86Assembler a(&runtime);
X86Compiler c(&a);
// ... code generation ...
c.finalize();
void* p = a.make();
```
All nodes were prefixed with HL, except for platform-specific nodes, change:
```
Node -> HLNode
FuncNode -> HLFunc
X86FuncNode -> X86Func
X86CallNode -> X86Call
```
`FuncConv` renamed to `CallConv` and is now part of a function prototype, change:
```
compiler.addFunc(kFuncConvHost, FuncBuilder0<Void>());
```
to
```
compiler.addFunc(FuncBuilder0<Void>(kCallConvHost));
```
Operand constructors that accept Assembler or Compiler are deprecated. Variables can now be created by using handy shortcuts like newInt32(), newIntPtr(), newXmmPd(), etc... Change:
```
X86Compiler c(...);
Label L(c);
X86GpVar x(c, kVarTypeIntPtr, "x");
```
to
```
X86Compiler c(...);
Label L = c.newLabel();
X86GpVar x = c.newIntPtr("x");
```

View File

@@ -1,264 +1,202 @@
# ============================================================================= cmake_minimum_required(VERSION 3.1)
# [AsmJit - CMakeLists.txt]
# =============================================================================
CMake_Minimum_Required(VERSION 2.8.12)
# ============================================================================= # =============================================================================
# [AsmJit - Configuration] # [AsmJit - Configuration]
# ============================================================================= # =============================================================================
# Whether not to build anything (default FALSE). # Embedding mode, asmjit will not create any targets (default FALSE).
# Set(ASMJIT_EMBED FALSE) # set(ASMJIT_EMBED FALSE)
# Whether to build static library (default FALSE). # Whether to build a static library (default FALSE).
# Set(ASMJIT_STATIC FALSE) # set(ASMJIT_STATIC FALSE)
# Whether to build tests (default FALSE). # Whether to build tests and samples (default FALSE).
# Set(ASMJIT_BUILD_TEST FALSE) # set(ASMJIT_BUILD_TEST FALSE)
# Whether to build samples (default FALSE).
# Set(ASMJIT_BUILD_SAMPLES FALSE)
# ============================================================================= # =============================================================================
# [AsmJit - Build] # [AsmJit - Build / Embed]
# ============================================================================= # =============================================================================
If(ASMJIT_EMBED) # Do not create a project if this CMakeLists.txt is included from another
Set(ASMJIT_STATIC TRUE) # project. This makes it easy to embed or create a static library.
EndIf() if(NOT CMAKE_PROJECT_NAME OR "${CMAKE_PROJECT_NAME}" MATCHES "^asmjit$")
project(asmjit C CXX)
set(ASMJIT_SIGNATURE "Standalone")
else()
set(ASMJIT_SIGNATURE "Included")
endif()
If(NOT CMAKE_PROJECT_NAME OR CMAKE_PROJECT_NAME MATCHES "^asmjit$") if(ASMJIT_EMBED)
Project(asmjit C CXX) set(ASMJIT_SIGNATURE "${ASMJIT_SIGNATURE} | Mode=Embed")
Set(ASMJIT_PROJECT_STR "Project") set(ASMJIT_STATIC TRUE) # Implies ASMJIT_STATIC.
Else() elseif(ASMJIT_STATIC)
# Do not create a project if this CMakeLists.txt is included by a different set(ASMJIT_SIGNATURE "${ASMJIT_SIGNATURE} | Mode=Static")
# project. This allows easy static library build including debugger support. else()
Set(ASMJIT_PROJECT_STR "Include") set(ASMJIT_SIGNATURE "${ASMJIT_SIGNATURE} | Mode=Shared")
EndIf() endif()
If(ASMJIT_STATIC) if(ASMJIT_BUILD_TEST)
Set(ASMJIT_PROJECT_STR "${ASMJIT_PROJECT_STR}|Static") set(ASMJIT_SIGNATURE "${ASMJIT_SIGNATURE} | Test=On")
Else() else()
Set(ASMJIT_PROJECT_STR "${ASMJIT_PROJECT_STR}|Shared") set(ASMJIT_SIGNATURE "${ASMJIT_SIGNATURE} | Test=Off")
EndIf() endif()
Message("") if(NOT ASMJIT_DIR)
Message("== ====================================================") set(ASMJIT_DIR ${CMAKE_CURRENT_LIST_DIR})
Message("== [AsmJit ${ASMJIT_PROJECT_STR}]") endif()
Message("== ====================================================")
Message("")
# ============================================================================= message("-- [asmjit] ${ASMJIT_SIGNATURE}")
# [AsmJit - Directories] message("-- [asmjit] ASMJIT_DIR=${ASMJIT_DIR}")
# =============================================================================
If(NOT ASMJIT_DIR)
Set(ASMJIT_DIR ${CMAKE_CURRENT_LIST_DIR})
Message("-- Initializing ASMJIT_DIR=${ASMJIT_DIR}")
Else()
Message("-- Using Custom ASMJIT_DIR=${ASMJIT_DIR}")
EndIf()
Set(ASMJIT_SRC_DIR "${ASMJIT_DIR}/src")
Set(ASMJIT_INC_DIR "${ASMJIT_SRC_DIR}")
Include_Directories(${ASMJIT_SRC_DIR})
# ============================================================================= # =============================================================================
# [AsmJit - Flags / Deps] # [AsmJit - Flags / Deps]
# ============================================================================= # =============================================================================
Set(ASMJIT_DEPS) set(ASMJIT_SOURCE_DIR "${ASMJIT_DIR}/src") # Asmjit source directory.
Set(ASMJIT_LFLAGS) set(ASMJIT_INCLUDE_DIR "${ASMJIT_SOURCE_DIR}") # Asmjit include directory.
Set(ASMJIT_CFLAGS) set(ASMJIT_DEPS) # Asmjit dependencies (list of libraries) for the linker.
Set(ASMJIT_CFLAGS_DBG) set(ASMJIT_LIBS) # Asmjit dependencies with asmjit included, for consumers.
Set(ASMJIT_CFLAGS_REL)
Set(ASMJIT_DEFINE "-D") # Internal, never use.
set(ASMJIT_D "-D") # Used to define a C/C++ preprocessor parameter (-D or /D).
set(ASMJIT_PRIVATE_CFLAGS) # Compiler flags independent of build type.
set(ASMJIT_PRIVATE_LFLAGS "") # Linker flags used by the library and tests.
# MSVC. set(ASMJIT_PRIVATE_CFLAGS_DBG) # Compiler flags used only by debug build.
If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") set(ASMJIT_PRIVATE_CFLAGS_REL) # Compiler flags used only by release build.
Message("-- Using MSVC")
Set(ASMJIT_DEFINE "/D") if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
Set(ASMJIT_LFLAGS "/OPT:REF /OPT:ICF") set(ASMJIT_D "/D")
Set(ASMJIT_CFLAGS /GF) set(ASMJIT_PRIVATE_LFLAGS "/OPT:REF /OPT:ICF")
Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-)
Set(ASMJIT_CFLAGS_REL /DASMJIT_RELEASE /Oi /Oy /GS- /GR-)
# Enable multi-process compilation. list(APPEND ASMJIT_PRIVATE_CFLAGS /GF)
If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71) list(APPEND ASMJIT_PRIVATE_CFLAGS_DBG /GS /GR-)
List(APPEND ASMJIT_CFLAGS /MP) list(APPEND ASMJIT_PRIVATE_CFLAGS_REL /Oi /Oy /GS- /GR-)
EndIf() if(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71)
EndIf() list(APPEND ASMJIT_PRIVATE_CFLAGS /MP) # Enable multi-process compilation.
endif()
endif()
# GCC if("${CMAKE_CXX_COMPILER_ID}" MATCHES "^(GNU|Clang)$")
If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") list(APPEND ASMJIT_PRIVATE_CFLAGS -fno-exceptions)
Message("-- Using GCC") list(APPEND ASMJIT_PRIVATE_CFLAGS_REL -fmerge-all-constants)
endif()
Set(ASMJIT_CFLAGS if(ASMJIT_EMBED)
-fno-exceptions) list(APPEND ASMJIT_PRIVATE_CFLAGS "${ASMJIT_D}ASMJIT_EMBED")
Set(ASMJIT_CFLAGS_DBG elseif(ASMJIT_STATIC)
-DASMJIT_DEBUG -O0) list(APPEND ASMJIT_PRIVATE_CFLAGS "${ASMJIT_D}ASMJIT_STATIC")
Set(ASMJIT_CFLAGS_REL endif()
-DASMJIT_RELEASE -O2
-finline-functions
-fomit-frame-pointer
-fmerge-all-constants
-fno-keep-static-consts)
EndIf()
# Clang. if(WIN32)
If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") list(APPEND ASMJIT_PRIVATE_CFLAGS "${ASMJIT_D}_UNICODE")
Message("-- Using Clang") else()
list(APPEND ASMJIT_DEPS pthread)
endif()
Set(ASMJIT_CFLAGS if("${CMAKE_SYSTEM_NAME}" MATCHES "Linux")
-fno-exceptions) list(APPEND ASMJIT_DEPS rt)
Set(ASMJIT_CFLAGS_DBG endif()
-DASMJIT_DEBUG -O0)
Set(ASMJIT_CFLAGS_REL
-DASMJIT_RELEASE -O2
-fomit-frame-pointer
-fmerge-all-constants)
EndIf()
# Use Unicode by default on Windows target. set(ASMJIT_LIBS ${ASMJIT_DEPS})
If(WIN32) if(NOT ASMJIT_EMBED)
List(APPEND ASMJIT_CFLAGS "${ASMJIT_DEFINE}_UNICODE") list(INSERT ASMJIT_LIBS 0 asmjit)
EndIf() endif()
# Static library. set(ASMJIT_PRIVATE_CFLAGS_DBG ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_PRIVATE_CFLAGS_DBG})
If(ASMJIT_STATIC) set(ASMJIT_PRIVATE_CFLAGS_REL ${ASMJIT_PRIVATE_CFLAGS} ${ASMJIT_PRIVATE_CFLAGS_REL})
List(APPEND ASMJIT_CFLAGS "${ASMJIT_DEFINE}ASMJIT_STATIC")
EndIf()
# Dependencies - pthread (Unix). message("-- [asmjit] ASMJIT_DEPS=${ASMJIT_DEPS}")
If(NOT WIN32) message("-- [asmjit] ASMJIT_LIBS=${ASMJIT_LIBS}")
List(APPEND ASMJIT_DEPS pthread)
EndIf()
# Dependencies - librt (Linux).
IF(${CMAKE_SYSTEM_NAME} MATCHES "Linux")
LIST(APPEND ASMJIT_DEPS rt)
ENDIF()
Set(ASMJIT_CFLAGS_DBG ${ASMJIT_CFLAGS} ${ASMJIT_CFLAGS_DBG})
Set(ASMJIT_CFLAGS_REL ${ASMJIT_CFLAGS} ${ASMJIT_CFLAGS_REL})
# ============================================================================= # =============================================================================
# [AsmJit - Macros] # [AsmJit - Macros]
# ============================================================================= # =============================================================================
Macro(AsmJit_AddSource in_dst in_path) macro(asmjit_add_source _out_dst _src_dir)
Set(__list "") set(_src_path "${ASMJIT_SOURCE_DIR}/${_src_dir}")
Set(__path "${ASMJIT_SRC_DIR}/${in_path}") set(_src_list)
ForEach(__name ${ARGN}) foreach(_arg ${ARGN})
Set(__file "${__path}/${__name}") set(_src_file "${_src_path}/${_arg}")
Set(__cflags ${ASMJIT_CFLAGS}) list(APPEND _src_list ${_src_file})
endforeach()
If(__name MATCHES "\\.cpp|\\.h") list(APPEND "${_out_dst}" ${_src_list})
If("${__cflags}") source_group(${_src_dir} FILES ${_src_list})
Set_Source_Files_Properties(${__name} PROPERTIES COMPILE_FLAGS ${__cflags}) endmacro()
EndIf()
List(APPEND __list ${__file})
EndIf()
EndForEach()
List(APPEND "${in_dst}" ${__list}) macro(asmjit_add_library _target _src _deps _cflags _cflags_dbg _cflags_rel)
Source_Group(${in_path} FILES ${__list}) if(NOT ASMJIT_STATIC)
EndMacro() add_library(${_target} SHARED ${_src})
else()
add_library(${_target} STATIC ${_src})
endif()
Macro(AsmJit_AddLibrary in_name in_src in_deps in_cflags in_cflags_dbg in_cflags_rel) target_link_libraries(${_target} ${_deps})
If(NOT ASMJIT_STATIC) set_target_properties(${_target} PROPERTIES LINK_FLAGS "${ASMJIT_PRIVATE_LFLAGS}")
Set(__type "SHARED")
Else()
Set(__type "STATIC")
EndIf()
Add_Library(${in_name} ${__type} ${in_src}) if(CMAKE_BUILD_TYPE)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_options(${_target} PRIVATE ${_cflags} ${_cflags_dbg})
else()
target_compile_options(${_target} PRIVATE ${_cflags} ${_cflags_rel})
endif()
else()
target_compile_options(${_target} PRIVATE ${_cflags}
$<$<CONFIG:Debug>:${_cflags_dbg}>
$<$<NOT:$<CONFIG:Debug>>:${_cflags_rel}>)
endif()
# Dependencies. if(NOT ASMJIT_STATIC)
Target_Link_Libraries(${in_name} ${in_deps}) install(TARGETS ${_target} DESTINATION "lib${LIB_SUFFIX}")
endif()
# Compiler Flags. endmacro()
If(${CMAKE_BUILD_TYPE})
If(${CMAKE_BUILD_TYPE} MATCHES "Debug")
Set_Target_Properties(${in_name} PROPERTIES COMPILE_FLAGS ${in_cflags} ${in_cflags_dbg})
Else()
Set_Target_Properties(${in_name} PROPERTIES COMPILE_FLAGS ${in_cflags} ${in_cflags_rel})
EndIf()
Else()
Target_Compile_Options(${in_name} PUBLIC ${in_cflags}
$<$<CONFIG:Debug>:${in_cflags_dbg}>
$<$<NOT:$<CONFIG:Debug>>:${in_cflags_rel}>)
EndIf()
# Linker Flags.
Set_Target_Properties(${in_name} PROPERTIES LINK_FLAGS "${ASMJIT_LFLAGS}")
# Install Instructions.
If(NOT ASMJIT_EMBED)
Install(TARGETS ${in_name} LIBRARY DESTINATION lib${LIB_SUFFIX}
ARCHIVE DESTINATION lib${LIB_SUFFIX}
RUNTIME DESTINATION bin)
EndIf()
Unset(__type)
EndMacro()
# ============================================================================= # =============================================================================
# [AsmJit - Source] # [AsmJit - Source]
# ============================================================================= # =============================================================================
Set(ASMJIT_SRC "") set(ASMJIT_SRC "")
AsmJit_AddSource(ASMJIT_SRC asmjit asmjit_add_source(ASMJIT_SRC asmjit
apibegin.h apibegin.h
apiend.h apiend.h
asmjit.h asmjit.h
base.h base.h
build.h build.h
config.h
host.h host.h
x86.h x86.h
) )
AsmJit_AddSource(ASMJIT_SRC asmjit/base asmjit_add_source(ASMJIT_SRC asmjit/base
assembler.cpp assembler.cpp
assembler.h assembler.h
codegen.cpp
codegen.h
compiler.cpp compiler.cpp
compiler.h compiler.h
compilercontext.cpp
compilercontext_p.h
compilerfunc.h
constpool.cpp constpool.cpp
constpool.h constpool.h
containers.cpp containers.cpp
containers.h containers.h
context.cpp
context_p.h
cpuinfo.cpp cpuinfo.cpp
cpuinfo.h cpuinfo.h
cputicks.cpp
cputicks.h
error.cpp
error.h
globals.cpp globals.cpp
globals.h globals.h
intutil.cpp hlstream.cpp
intutil.h hlstream.h
lock.h
logger.cpp logger.cpp
logger.h logger.h
operand.cpp operand.cpp
operand.h operand.h
runtime.cpp runtime.cpp
runtime.h runtime.h
string.cpp utils.cpp
string.h utils.h
vectypes.h vectypes.h
vmem.cpp vmem.cpp
vmem.h vmem.h
@@ -266,13 +204,15 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
zone.h zone.h
) )
AsmJit_AddSource(ASMJIT_SRC asmjit/x86 asmjit_add_source(ASMJIT_SRC asmjit/x86
x86assembler.cpp x86assembler.cpp
x86assembler.h x86assembler.h
x86compiler.cpp x86compiler.cpp
x86compiler.h x86compiler.h
x86context.cpp x86compilercontext.cpp
x86context_p.h x86compilercontext_p.h
x86compilerfunc.cpp
x86compilerfunc.h
x86cpuinfo.cpp x86cpuinfo.cpp
x86cpuinfo.h x86cpuinfo.h
x86inst.cpp x86inst.cpp
@@ -285,81 +225,55 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/x86
) )
# ============================================================================= # =============================================================================
# [AsmJit - Headers] # [AsmJit - Targets]
# ============================================================================= # =============================================================================
If(NOT ASMJIT_EMBED) if(NOT ASMJIT_EMBED)
ForEach(i ${ASMJIT_SRC}) # Add `asmjit` library.
Get_Filename_Component(path ${i} PATH) asmjit_add_library(asmjit
Get_Filename_Component(name ${i} NAME)
String(REGEX REPLACE "^${ASMJIT_SRC_DIR}/" "" targetpath "${path}")
If(name MATCHES ".h$")
If(NOT name MATCHES "_p.h$")
Install(FILES ${i} DESTINATION "include/${targetpath}")
EndIf()
EndIf()
EndForEach()
EndIf()
# =============================================================================
# [Asmjit - Library]
# =============================================================================
If(NOT ASMJIT_EMBED)
AsmJit_AddLibrary(asmjit
"${ASMJIT_SRC}" "${ASMJIT_SRC}"
"${ASMJIT_DEPS}" "${ASMJIT_DEPS}"
"${ASMJIT_CFLAGS}" ""
"${ASMJIT_CFLAGS_DBG}" "${ASMJIT_PRIVATE_CFLAGS_DBG}"
"${ASMJIT_CFLAGS_REL}" "${ASMJIT_PRIVATE_CFLAGS_REL}"
)
EndIf()
# =============================================================================
# [Asmjit - Testing]
# =============================================================================
# AsmJit library is always embedded into the tests executable. This way it's
# much easier to test private functions than just linking to `libasmjit.so`.
If(ASMJIT_BUILD_TEST)
AsmJit_AddSource(ASMJIT_TEST_SRC test asmjit_test_unit.cpp broken.cpp broken.h)
Set(ASMJIT_TEST_CFLAGS
${ASMJIT_CFLAGS}
${ASMJIT_DEFINE}ASMJIT_STATIC
${ASMJIT_DEFINE}ASMJIT_TEST)
Add_Executable(asmjit_test_unit ${ASMJIT_SRC} ${ASMJIT_TEST_SRC})
Target_Link_Libraries(asmjit_test_unit ${ASMJIT_DEPS})
If(${CMAKE_BUILD_TYPE})
If(${CMAKE_BUILD_TYPE} MATCHES "Debug")
Set_Target_Properties(asmjit_test_unit PROPERTIES COMPILE_FLAGS ${ASMJIT_TEST_CFLAGS} ${ASMJIT_CFLAGS_DBG})
Else()
Set_Target_Properties(asmjit_test_unit PROPERTIES COMPILE_FLAGS ${ASMJIT_TEST_CFLAGS} ${ASMJIT_CFLAGS_REL})
EndIf()
Else()
Target_Compile_Options(asmjit_test_unit PUBLIC ${ASMJIT_TEST_CFLAGS}
$<$<CONFIG:Debug>:${ASMJIT_CFLAGS_DBG}>
$<$<NOT:$<CONFIG:Debug>>:${ASMJIT_CFLAGS_REL}>)
EndIf()
Set_Target_Properties(asmjit_test_unit PROPERTIES LINK_FLAGS "${ASMJIT_LFLAGS}")
EndIf()
# =============================================================================
# [Asmjit - Samples]
# =============================================================================
If(ASMJIT_BUILD_SAMPLES)
Set(ASMJIT_SRC_SAMPLES
asmjit_bench_x86
asmjit_test_opcode
asmjit_test_x86
) )
ForEach(file ${ASMJIT_SRC_SAMPLES}) foreach(_src_file ${ASMJIT_SRC})
Add_Executable(${file} src/test/${file}.cpp) get_filename_component(_src_dir ${_src_file} PATH)
Target_Link_Libraries(${file} asmjit ${ASMJIT_DEPS}) get_filename_component(_src_name ${_src_file} NAME)
EndForEach(file) string(REGEX REPLACE "^${ASMJIT_SOURCE_DIR}/" "" targetpath "${_src_dir}")
EndIf() if("${_src_name}" MATCHES ".h$")
if(NOT "${_src_name}" MATCHES "_p.h$")
install(FILES ${_src_file} DESTINATION "include/${targetpath}")
endif()
endif()
endforeach()
# Add `asmjit` tests and samples.
if(ASMJIT_BUILD_TEST)
set(ASMJIT_TEST_SRC "")
set(ASMJIT_TEST_CFLAGS ${ASMJIT_D}ASMJIT_TEST ${ASMJIT_D}ASMJIT_EMBED)
asmjit_add_source(ASMJIT_TEST_SRC test asmjit_test_unit.cpp broken.cpp broken.h)
add_executable(asmjit_test_unit ${ASMJIT_SRC} ${ASMJIT_TEST_SRC})
target_link_libraries(asmjit_test_unit ${ASMJIT_DEPS})
set_target_properties(asmjit_test_unit PROPERTIES LINK_FLAGS "${ASMJIT_PRIVATE_LFLAGS}")
if(CMAKE_BUILD_TYPE)
if("${CMAKE_BUILD_TYPE}" STREQUAL "Debug")
target_compile_options(asmjit_test_unit PRIVATE ${ASMJIT_TEST_CFLAGS} ${ASMJIT_PRIVATE_CFLAGS_DBG})
else()
target_compile_options(asmjit_test_unit PRIVATE ${ASMJIT_TEST_CFLAGS} ${ASMJIT_PRIVATE_CFLAGS_REL})
endif()
else()
target_compile_options(asmjit_test_unit PRIVATE ${ASMJIT_TEST_CFLAGS}
$<$<CONFIG:Debug>:${ASMJIT_PRIVATE_CFLAGS_DBG}>
$<$<NOT:$<CONFIG:Debug>>:${ASMJIT_PRIVATE_CFLAGS_REL}>)
endif()
foreach(_target asmjit_bench_x86 asmjit_test_opcode asmjit_test_x86)
add_executable(${_target} "src/test/${_target}.cpp")
target_link_libraries(${_target} ${ASMJIT_LIBS})
endforeach()
endif()
endif()

359
README.md
View File

@@ -9,44 +9,44 @@ Complete x86/x64 JIT and Remote Assembler for C++.
Introduction Introduction
------------ ------------
AsmJit is a complete JIT and remote assembler for C++ language. It can generate native code for x86 and x64 architectures and supports the whole x86/x64 instruction set - from legacy MMX to the newest AVX2. It has a type-safe API that allows C++ compiler to do a semantic checks at compile-time even before the assembled code is generated or run. AsmJit is a complete JIT and remote assembler for C++ language. It can generate native code for x86 and x64 architectures and supports the whole x86/x64 instruction set - from legacy MMX to the newest AVX2. It has a type-safe API that allows C++ compiler to do semantic checks at compile-time even before the assembled code is generated and executed.
AsmJit is not a virtual machine nor tries to be. It's a tool that can be used to encode instructions into their machine code representations and tries to make such process easy and fun. AsmJit has been used so far in software encryption, image/sound processing, emulators and as a JIT backend in virtual machines. AsmJit is not a virtual machine (VM). It doesn't have functionality to implement VM out of the box; however, it can be be used as a JIT backend of your own VM. The usage of AsmJit is not limited at all; it's suitable for multimedia, VM backends, remote code generation, and many other tasks.
Features Features
-------- --------
* Complete x86/x64 instruction set - MMX, SSE, AVX, BMI, XOP, FMA..., * Complete x86/x64 instruction set - MMX, SSEx, AVX1/2, BMI, XOP, FMA3, and FMA4 (AVX-512 in progress)
* Low-level and high-level code generation, * Low-level and high-level code generation concepts
* Built-in CPU detection, * Built-in CPU features detection
* Virtual Memory management, * Virtual Memory management similar to malloc/free
* Pretty logging and error handling, * Powerful logging and error handling
* Small and embeddable, around 150-200kB compiled, * Small and embeddable, around 150-200kB compiled
* Zero dependencies, not even STL or RTTI. * Zero dependencies, not even STL or RTTI
Supported Environments Supported Environments
---------------------- ----------------------
### Operating Systems ### Operating Systems
* BSDs * BSDs (not tested regularly)
* Linux * Linux (tested by Travis-CI)
* Mac * Mac (tested by Travis-CI)
* Windows * Windows (tested manually)
### C++ Compilers ### C++ Compilers
* BorlandC++ * BorlandC++ (not tested regularly)
* Clang (Travis-CI) * CLang (tested by Travis-CI)
* Gcc (Travis-CI) * GCC (tested by Travis-CI)
* MinGW * MinGW (tested manually)
* MSVC * MSVC (tested manually)
* Other compilers require testing and support in `asmjit/build.h` header * Other compilers require some testing and support in `asmjit/build.h` header
### Backends ### Backends
* X86 * X86 (tested by Travis-CI)
* X64 * X64 (tested by Travis-CI)
Project Organization Project Organization
-------------------- --------------------
@@ -54,22 +54,21 @@ Project Organization
* `/` - Project root * `/` - Project root
* `src` - Source code * `src` - Source code
* `asmjit` - Public header files (always include from here) * `asmjit` - Public header files (always include from here)
* `base` - Base files, used by the AsmJit and all backends * `base` - Base files, used by AsmJit and all backends
* `contrib` - Contributions that extend the base functionality
* `test` - Unit testing support (don't include in your project)
* `x86` - X86/X64 specific files, used only by X86/X64 backend * `x86` - X86/X64 specific files, used only by X86/X64 backend
* `test` - Unit and integration tests (don't embed in your project)
* `tools` - Tools used for configuring, documenting and generating files * `tools` - Tools used for configuring, documenting and generating files
Code Generation Concepts Code Generation Concepts
------------------------ ------------------------
AsmJit has two completely different code generation concepts. The difference is in how the code is generated. The first concept, also referred as the low level concept, is called `Assembler` and it's the same as writing RAW assembly by using physical registers directly. In this case AsmJit does only instruction encoding, verification and optionally code-relocation. AsmJit has two completely different code generation concepts. The difference is in how the code is generated. The first concept, also referred as a low level concept, is called `Assembler` and it's the same as writing RAW assembly by inserting instructions that use physical registers directly. In this case AsmJit does only instruction encoding, verification and final code relocation.
The second concept, also referred as the high level concept, is called `Compiler`. Compiler lets you use virtually unlimited number of registers (called variables) significantly simplifying the code generation process. Compiler allocates these virtual registers to physical registers after the code generation is done. This requires some extra effort - Compiler has to generate information for each node (instruction, function declaration, function call) in the code, perform a variable liveness analysis and translate the code having variables into code having only registers. The second concept, also referred as a high level concept, is called `Compiler`. Compiler lets you use virtually unlimited number of registers (it calls them variables), which significantly simplifies the code generation process. Compiler allocates these virtual registers to physical registers after the code generation is done. This requires some extra effort - Compiler has to generate information for each node (instruction, function declaration, function call, etc...) in the code, perform a variable liveness analysis and translate the code using variables to a code that uses only physical registers.
In addition, Compiler understands functions and function calling conventions. It has been designed in a way that the code generated is always a function having a prototype like in a programming language. By having a function prototype the Compiler is able to insert prolog and epilog to a function being generated and it is able to call a function inside a generated one. In addition, Compiler understands functions and their calling conventions. It has been designed in a way that the code generated is always a function having a prototype like a real programming language. By having a function prototype the Compiler is able to insert prolog and epilog sequence to the function being generated and it's able to also generate a necessary code to call other function from your own code.
There is no conclusion on which concept is better. Assembler brings full control on how the code is generated, while Compiler makes the generation easier and more portable. However, Compiler does sometimes relatively bad job when it comes to register allocation, so for projects where there is already an analysis performed, pure Assembler code generator is the preferred way. There is no conclusion on which concept is better. `Assembler` brings full control and the best performance, while `Compiler` makes the code-generation more fun and more portable.
Configuring & Building Configuring & Building
---------------------- ----------------------
@@ -101,16 +100,14 @@ AsmJit is designed to be easy embeddable in any kind project. However, it has so
### Features ### Features
* `ASMJIT_DISABLE_COMPILER` - Disable `Compiler` completely. Use this flag if you don't use Compiler and want slimmer binary. * `ASMJIT_DISABLE_COMPILER` - Disable `Compiler` completely. Use this flag if you don't use Compiler and want a slimmer binary.
* `ASMJIT_DISABLE_LOGGER` - Disable `Logger` completely. Use this flag if you don't need `Logger` functionality and want slimmer binary. AsmJit compiled with or without `Logger` support is binary compatible (all classes that use Logger pointer will simply use `void*`), but the Logger interface and in general instruction dumps won't be available anymore.
* `ASMJIT_DISABLE_LOGGER` - Disable `Logger` completely. Use this flag if you don't need `Logger` functionality and want slimmer binary. AsmJit compiled with or without `Logger` support is binary compatible (all classes that use Logger pointer will simply use `void*`), but the Logger interface and in general instruction dumps are not available. * `ASMJIT_DISABLE_NAMES` - Disable everything that uses strings and that causes certain strings to be stored in the resulting binary. For example when this flag is enabled all instruction and error names (and related APIs) will not be available. This flag has to be disabled together with `ASMJIT_DISABLE_LOGGER`.
* `ASMJIT_DISABLE_NAMES` - Disable everything that uses strings and that causes certain strings to be stored in the resulting binary. For example when this flag is enabled instruction or error names (and related APIs) will not be available. This flag has to be disabled together with `ASMJIT_DISABLE_LOGGER`.
Using AsmJit Using AsmJit
------------ ------------
AsmJit library uses one global namespace called `asmjit`, which contains the basics. Architecture specific code is prefixed by the architecture and architecture registers and operand builders are in its own namespace. For example classes for both x86 and x64 code generation are prefixed by `X86`, enums by `kX86`, registers and operand builders are accessible through `x86` namespace. This design is very different from the initial version of AsmJit and it seems now as the most convenient one. AsmJit library uses one global namespace called `asmjit`, which contains the basics. Architecture specific code is prefixed by the architecture and architecture specific registers and operand builders are in its own namespace. For example classes for both x86 and x64 code generation are prefixed by `X86`, enums by `kX86`, registers and operand builders are accessible through `x86` namespace. This design is very different from the initial version of AsmJit and it seems now as the most convenient one.
### Runtime & Code-Generators ### Runtime & Code-Generators
@@ -118,7 +115,7 @@ AsmJit contains two classes that are required to generate a machine code. `Runti
### Instruction Operands ### Instruction Operands
Operand is a part of CPU instruction which specifies the data the instruction will operate on. There are five types of operands in AsmJit: Operand is a part of an instruction, which specifies the data the instruction will operate on. There are five types of operands in AsmJit:
* `Reg` - Physical register, used only by `Assembler` * `Reg` - Physical register, used only by `Assembler`
* `Var` - Virtual register, used only by `Compiler` * `Var` - Virtual register, used only by `Compiler`
@@ -138,47 +135,52 @@ AsmJit needs to know the prototype of the function it will generate or call. Asm
Let's put all together and generate a first function that sums its two arguments and returns the result. At the end the generated function is called from a C++ code. Let's put all together and generate a first function that sums its two arguments and returns the result. At the end the generated function is called from a C++ code.
```C++ ```c++
#include <asmjit/asmjit.h> #include <asmjit/asmjit.h>
using namespace asmjit; using namespace asmjit;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Create JitRuntime and X86 Compiler. // Create JitRuntime and X86 Assembler/Compiler.
JitRuntime runtime; JitRuntime runtime;
X86Compiler c(&runtime); X86Assembler a(&runtime);
X86Compiler c(&a);
// Build function having two arguments and a return value of type 'int'. // Build function having two arguments and a return value of type 'int'.
// First type in function builder describes the return value. kFuncConvHost // First type in function builder describes the return value. kCallConvHost
// tells compiler to use a host calling convention. // tells the compiler to use the host calling convention.
c.addFunc(kFuncConvHost, FuncBuilder2<int, int, int>()); c.addFunc(FuncBuilder2<int, int, int>(kCallConvHost));
// Create 32-bit variables (virtual registers) and assign some names to // Create 32-bit variables (virtual registers) and assign some names to
// them. Using names is purely optional and only greatly helps while // them. Using variable names is not necessary, however, it can make
// debugging. // debugging easier.
X86GpVar a(c, kVarTypeInt32, "a"); X86GpVar x = c.newInt32("x");
X86GpVar b(c, kVarTypeInt32, "b"); X86GpVar y = c.newInt32("y");
// Tell asmjit to use these variables as function arguments. // Tell asmjit to use these variables as function arguments.
c.setArg(0, a); c.setArg(0, x);
c.setArg(1, b); c.setArg(1, y);
// a = a + b; // x = x + y;
c.add(a, b); c.add(x, y);
// Tell asmjit to return 'a'. // Tell asmjit to return `x`.
c.ret(a); c.ret(x);
// Finalize the current function. // Finalize the current function.
c.endFunc(); c.endFunc();
// Now the Compiler contains the whole function, but the code is not yet // Now the Compiler contains the whole function, but the code is not yet
// generated. To tell compiler to generate the function make() has to be // generated. To tell the compiler to serialize the code to `Assembler`
// called. // `c.finalize()` has to be called. After finalization the `Compiler`
// won't contain the code anymore and will be detached from the `Assembler`.
c.finalize();
// Make uses the JitRuntime passed to Compiler constructor to allocate a // After finalization the code has been send to `Assembler`. It contains
// buffer for the function and make it executable. // a handy method `make()`, which returns a pointer that points to the
void* funcPtr = c.make(); // first byte of the generated code, which is the function entry in our
// case.
void* funcPtr = a.make();
// In order to run 'funcPtr' it has to be casted to the desired type. // In order to run 'funcPtr' it has to be casted to the desired type.
// Typedef is a recommended and safe way to create a function-type. // Typedef is a recommended and safe way to create a function-type.
@@ -189,25 +191,25 @@ int main(int argc, char* argv[]) {
FuncType func = asmjit_cast<FuncType>(funcPtr); FuncType func = asmjit_cast<FuncType>(funcPtr);
// Finally, run it and do something with the result... // Finally, run it and do something with the result...
int x = func(1, 2); int z = func(1, 2);
printf("x=%d\n", x); // Outputs "x=3". printf("z=%d\n", z); // Outputs "z=3".
// The function will remain in memory after Compiler is destroyed, but // The function will remain in memory after Compiler and Assembler are
// will be destroyed together with Runtime. This is just simple example // destroyed. This is why the `JitRuntime` is used - it keeps track of
// where we can just destroy both at the end of the scope and that's it. // the code generated. When `Runtime` is destroyed it also invalidates
// However, it's a good practice to clean-up resources after they are // all code relocated by it (which is in our case also our `func`). So
// not needed and using runtime.release() is the preferred way to free // it's safe to just do nothing in our case, because destroying `Runtime`
// a function added to JitRuntime. // will free `func` as well, however, it's always better to release the
// generated code that is not needed anymore manually.
runtime.release((void*)func); runtime.release((void*)func);
// Runtime and Compiler will be destroyed at the end of the scope.
return 0; return 0;
} }
``` ```
The code should be self explanatory, however there are some details to be clarified. The code should be self explanatory, however there are some details to be clarified.
The code above generates and calls a function of `kFuncConvHost` calling convention. 32-bit architecture contains a wide range of function calling conventions that can be all used by a single program, so it's important to know which calling convention is used by your C/C++ compiler so you can call the function. However, most compilers should generate CDecl by default. In 64-bit mode there are only two calling conventions, one is specific for Windows (Win64 calling convention) and the other for Unix (AMD64 calling convention). The `kFuncConvHost` is defined to be one of CDecl, Win64 or AMD64 depending on your architecture and operating system. The code above generates and calls a function of `kCallConvHost` calling convention. 32-bit architecture contains a wide range of function calling conventions that can be all used by a single program, so it's important to know which calling convention is used by your C/C++ compiler so you can call the function. However, most compilers should generate CDecl by default. In 64-bit mode there are only two calling conventions, one is specific for Windows (Win64 calling convention) and the other for Unix (AMD64 calling convention). The `kCallConvHost` is defined to be one of CDecl, Win64 or AMD64 depending on your architecture and operating system.
Default integer size is platform specific, virtual types `kVarTypeIntPtr` and `kVarTypeUIntPtr` can be used to make the code more portable and they should be always used when a pointer type is needed. When no type is specified AsmJit always defaults to `kVarTypeIntPtr`. The code above works with integers where the default behavior has been overidden to 32-bits. Note it's always a good practice to specify the type of the variable used. Alternative form of creating a variable is `c.newGpVar(...)`, `c.newMmVar(...)`, `c.newXmmVar` and so on... Default integer size is platform specific, virtual types `kVarTypeIntPtr` and `kVarTypeUIntPtr` can be used to make the code more portable and they should be always used when a pointer type is needed. When no type is specified AsmJit always defaults to `kVarTypeIntPtr`. The code above works with integers where the default behavior has been overidden to 32-bits. Note it's always a good practice to specify the type of the variable used. Alternative form of creating a variable is `c.newGpVar(...)`, `c.newMmVar(...)`, `c.newXmmVar` and so on...
@@ -217,70 +219,72 @@ The function starts with `c.addFunc()` and ends with `c.endFunc()`. It's not all
Labels are essential for making jumps, function calls or to refer to a data that is embedded in the code section. Label has to be explicitly created by using `newLabel()` method of your code generator in order to be used. The following example executes a code that depends on the condition by using a `Label` and conditional jump instruction. If the first parameter is zero it returns `a + b`, otherwise `a - b`. Labels are essential for making jumps, function calls or to refer to a data that is embedded in the code section. Label has to be explicitly created by using `newLabel()` method of your code generator in order to be used. The following example executes a code that depends on the condition by using a `Label` and conditional jump instruction. If the first parameter is zero it returns `a + b`, otherwise `a - b`.
```C++ ```c++
#include <asmjit/asmjit.h> #include <asmjit/asmjit.h>
using namespace asmjit; using namespace asmjit;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
X86Compiler c(&runtime); X86Assembler a(&runtime);
X86Compiler c(&a);
// This function uses 3 arguments. // This function uses 3 arguments.
c.addFunc(kFuncConvHost, FuncBuilder3<int, int, int, int>()); c.addFunc(FuncBuilder3<int, int, int, int>(kCallConvHost));
// New variable 'op' added. // New variable 'op' added.
X86GpVar op(c, kVarTypeInt32, "op"); X86GpVar op = c.newInt32("op");
X86GpVar a(c, kVarTypeInt32, "a"); X86GpVar x = c.newInt32("x");
X86GpVar b(c, kVarTypeInt32, "b"); X86GpVar y = c.newInt32("y");
c.setArg(0, op); c.setArg(0, op);
c.setArg(1, a); c.setArg(1, x);
c.setArg(2, b); c.setArg(2, y);
// Create labels. // Create labels.
Label L_Subtract(c); Label L_Sub = c.newLabel();
Label L_Skip(c); Label L_Skip = c.newLabel();
// If (op != 0) // If (op != 0)
// goto L_Subtract; // goto L_Sub;
c.test(op, op); c.test(op, op);
c.jne(L_Subtract); c.jne(L_Sub);
// a = a + b; // x = x + y;
// goto L_Skip; // goto L_Skip;
c.add(a, b); c.add(x, y);
c.jmp(L_Skip); c.jmp(L_Skip);
// L_Subtract: // L_Sub:
// a = a - b; // x = x - y;
c.bind(L_Subtract); c.bind(L_Sub);
c.sub(a, b); c.sub(x, y);
// L_Skip: // L_Skip:
c.bind(L_Skip); c.bind(L_Skip);
c.ret(a); c.ret(x);
c.endFunc(); c.endFunc();
c.finalize();
// The prototype of the generated function changed also here. // The prototype of the generated function.
typedef int (*FuncType)(int, int, int); typedef int (*FuncType)(int, int, int);
FuncType func = asmjit_cast<FuncType>(c.make()); FuncType func = asmjit_cast<FuncType>(a.make());
int x = func(0, 1, 2); int res0 = func(0, 1, 2);
int y = func(1, 1, 2); int res1 = func(1, 1, 2);
printf("x=%d\n", x); // Outputs "x=3". printf("res0=%d\n", res0); // Outputs "res0=3".
printf("y=%d\n", y); // Outputs "y=-1". printf("res1=%d\n", res1); // Outputs "res1=-1".
runtime.release((void*)func); runtime.release((void*)func);
return 0; return 0;
} }
``` ```
In this example conditional and unconditional jumps were used with labels together. Labels are created explicitly by the `Compiler` by passing a `Compiler` instance to a `Label` constructor or by using a `Label l = c.newLabel()` form. Each label as an unique ID that identifies it, however it's not a string and there is no way to query for a `Label` instance that already exists. Label is like any other operand moved by value, so the copy of the label will still reference the same label and changing a copied label will not change the original label. In this example conditional and unconditional jumps were used with labels together. Labels have to be created explicitely by `Compiler` by using a `Label L = c.newLabel()` form. Each label as an unique ID that identifies it, however it's not a string and there is no way to query for a `Label` instance that already exists at the moment. Label is like any other operand moved by value, so the copy of the label will still reference the same label and changing a copied label will not change the original label.
Each label has to be bound to the location in the code by using `c.bind()`; however, it can be only bound once! Trying to bind the same label multiple times has undefined behavior - it will trigger an assertion failure in the best case. Each label has to be bound to the location in the code by using `bind()`; however, it can be bound only once! Trying to bind the same label multiple times has undefined behavior - assertion failure is the best case.
### Memory Addressing ### Memory Addressing
@@ -288,62 +292,64 @@ X86/X64 architectures have several memory addressing modes which can be used to
In the following example various memory addressing modes are used to demonstrate how to construct and use them. It creates a function that accepts an array and two indexes which specify which elements to sum and return. In the following example various memory addressing modes are used to demonstrate how to construct and use them. It creates a function that accepts an array and two indexes which specify which elements to sum and return.
```C++ ```c++
#include <asmjit/asmjit.h> #include <asmjit/asmjit.h>
using namespace asmjit; using namespace asmjit;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
X86Compiler c(&runtime); X86Assembler a(&runtime);
X86Compiler c(&a);
// Function returning 'int' accepting pointer and two indexes. // Function returning 'int' accepting pointer and two indexes.
c.addFunc(kFuncConvHost, FuncBuilder3<int, const int*, intptr_t, intptr_t>()); c.addFunc(FuncBuilder3<int, const int*, intptr_t, intptr_t>(kCallConvHost));
X86GpVar p(c, kVarTypeIntPtr, "p"); X86GpVar p = c.newIntPtr("p");
X86GpVar aIndex(c, kVarTypeIntPtr, "aIndex"); X86GpVar xIndex = c.newIntPtr("xIndex");
X86GpVar bIndex(c, kVarTypeIntPtr, "bIndex"); X86GpVar yIndex = c.newIntPtr("yIndex");
c.setArg(0, p); c.setArg(0, p);
c.setArg(1, aIndex); c.setArg(1, xIndex);
c.setArg(2, bIndex); c.setArg(2, yIndex);
X86GpVar a(c, kVarTypeInt32, "a"); X86GpVar x = c.newInt32("x");
X86GpVar b(c, kVarTypeInt32, "b"); X86GpVar y = c.newInt32("y");
// Read 'a' by using a memory operand having base register, index register // Read `x` by using a memory operand having base register, index register
// and scale. Translates to 'mov a, dword ptr [p + aIndex << 2]'. // and scale. Translates to `mov x, dword ptr [p + xIndex << 2]`.
c.mov(a, ptr(p, aIndex, 2)); c.mov(x, x86::ptr(p, xIndex, 2));
// Read 'b' by using a memory operand having base register only. Variables // Read `y` by using a memory operand having base register only. Variables
// 'p' and 'bIndex' are both modified. // `p` and `yIndex` are both modified.
// Shift bIndex by 2 (exactly the same as multiplying by 4). // Shift bIndex by 2 (exactly the same as multiplying by 4).
// And add scaled 'bIndex' to 'p' resulting in 'p = p + bIndex * 4'. // And add scaled 'bIndex' to 'p' resulting in 'p = p + bIndex * 4'.
c.shl(bIndex, 2); c.shl(yIndex, 2);
c.add(p, bIndex); c.add(p, yIndex);
// Read 'b'. // Read `y`.
c.mov(b, ptr(p)); c.mov(y, x86::ptr(p));
// a = a + b; // x = x + y;
c.add(a, b); c.add(x, y);
c.ret(a); c.ret(x);
c.endFunc(); c.endFunc();
c.finalize();
// The prototype of the generated function changed also here. // The prototype of the generated function.
typedef int (*FuncType)(const int*, intptr_t, intptr_t); typedef int (*FuncType)(const int*, intptr_t, intptr_t);
FuncType func = asmjit_cast<FuncType>(c.make()); FuncType func = asmjit_cast<FuncType>(a.make());
// Array passed to 'func' // Array passed to `func`.
const int array[] = { 1, 2, 3, 5, 8, 13 }; static const int array[] = { 1, 2, 3, 5, 8, 13 };
int x = func(array, 1, 2); int xVal = func(array, 1, 2);
int y = func(array, 3, 5); int yVal = func(array, 3, 5);
printf("x=%d\n", x); // Outputs "x=5". printf("xVal=%d\n", xVal); // Outputs "xVal=5".
printf("y=%d\n", y); // Outputs "y=18". printf("yVal=%d\n", yVal); // Outputs "yVal=18".
runtime.release((void*)func); runtime.release((void*)func);
return 0; return 0;
@@ -356,42 +362,44 @@ AsmJit uses stack automatically to spill variables if there is not enough regist
In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values. In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values.
```C++ ```c++
#include <asmjit/asmjit.h> #include <asmjit/asmjit.h>
using namespace asmjit; using namespace asmjit;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
X86Compiler c(&runtime); X86Assembler a(&runtime);
X86Compiler c(&a);
// Function returning 'int' without any arguments. // Function returning 'int' without any arguments.
c.addFunc(kFuncConvHost, FuncBuilder0<int>()); c.addFunc(FuncBuilder0<int>(kCallConvHost));
// Allocate a function stack of size 256 aligned to 4 bytes. // Allocate 256 bytes on the stack aligned to 4 bytes.
X86Mem stack = c.newStack(256, 4); X86Mem stack = c.newStack(256, 4);
X86GpVar p(c, kVarTypeIntPtr, "p"); X86GpVar p = c.newIntPtr("p");
X86GpVar i(c, kVarTypeIntPtr, "i"); X86GpVar i = c.newIntPtr("i");
// Load a stack address to 'p'. This step is purely optional and shows // Load a stack address to `p`. This step is purely optional and shows
// that 'lea' is useful to load a memory operands address (even absolute) // that `lea` is useful to load a memory operands address (even absolute)
// to a general purpose register. // to a general purpose register.
c.lea(p, stack); c.lea(p, stack);
// Clear 'i'. Notice that xor_() is used instead of xor(), because xor is // Clear `i`. Notice that `xor_()` is used instead of `xor()` as it's keyword.
// unfortunately a keyword in C++.
c.xor_(i, i); c.xor_(i, i);
Label L1 = c.newLabel();
Label L2 = c.newLabel();
// First loop, fill the stack allocated by a sequence of bytes from 0 to 255. // First loop, fill the stack allocated by a sequence of bytes from 0 to 255.
Label L1(c);
c.bind(L1); c.bind(L1);
// Mov [p + i], i. // Mov byte ptr[p + i], i.
// //
// Any operand can be cloned and modified. By cloning 'stack' and calling // Any operand can be cloned and modified. By cloning `stack` and calling
// 'setIndex' we created a new memory operand based on stack having an // `setIndex()` we created a new memory operand based on stack having an
// index register set. // index register assigned to it.
c.mov(stack.clone().setIndex(i), i.r8()); c.mov(stack.clone().setIndex(i), i.r8());
// if (++i < 256) // if (++i < 256)
@@ -400,20 +408,19 @@ int main(int argc, char* argv[]) {
c.cmp(i, 256); c.cmp(i, 256);
c.jb(L1); c.jb(L1);
// Second loop, sum all bytes stored in 'stack'. // Second loop, sum all bytes stored in `stack`.
X86GpVar a(c, kVarTypeInt32, "a"); X86GpVar sum = c.newInt32("sum");
X86GpVar t(c, kVarTypeInt32, "t"); X86GpVar val = c.newInt32("val");
c.xor_(i, i); c.xor_(i, i);
c.xor_(a, a); c.xor_(sum, sum);
Label L2(c);
c.bind(L2); c.bind(L2);
// Movzx t, byte ptr [stack + i] // Movzx val, byte ptr [stack + i]
c.movzx(t, stack.clone().setIndex(i).setSize(1)); c.movzx(val, stack.clone().setIndex(i).setSize(1));
// a += t; // sum += val;
c.add(a, t); c.add(sum, val);
// if (++i < 256) // if (++i < 256)
// goto L2; // goto L2;
@@ -421,13 +428,14 @@ int main(int argc, char* argv[]) {
c.cmp(i, 256); c.cmp(i, 256);
c.jb(L2); c.jb(L2);
c.ret(a); c.ret(sum);
c.endFunc(); c.endFunc();
c.finalize();
typedef int (*FuncType)(void); typedef int (*FuncType)(void);
FuncType func = asmjit_cast<FuncType>(a.make());
FuncType func = asmjit_cast<FuncType>(c.make()); printf("sum=%d\n", func()); // Outputs "sum=32640".
printf("a=%d\n", func()); // Outputs "a=32640".
runtime.release((void*)func); runtime.release((void*)func);
return 0; return 0;
@@ -453,33 +461,34 @@ Loggers can be assigned to any code generator and there is no restriction of ass
The following snippet describes how to log into `FILE*`: The following snippet describes how to log into `FILE*`:
```C++ ```c++
// Create logger logging to `stdout`. Logger life-time should always be // Create logger logging to `stdout`. Logger life-time should always be
// greater than lifetime of the code generator. // greater than a life-time of the code generator. Alternatively the
// logger can be reset before it's destroyed.
FileLogger logger(stdout); FileLogger logger(stdout);
// Create a code generator and assign our logger into it. // Create runtime and assembler and attach a logger to the assembler.
X86Compiler c(...); JitRuntime runtime;
c.setLogger(&logger); X86Assembler a(&runtime);
a.setLogger(&logger);
// ... Generate the code ... // ... Generate the code ...
``` ```
The following snippet describes how to log into a string: The following snippet describes how to log into a string:
```C++ ```c++
StringLogger logger; StringLogger logger;
// Create a code generator and assign our logger into it. JitRuntime runtime;
X86Compiler c(...); X86Assembler a(&runtime);
c.setLogger(&logger); a.setLogger(&logger);
// ... Generate the code ... // ... Generate the code ...
printf("Logger Content:\n%s", logger.getString()); printf("Logger Content:\n%s", logger.getString());
// You can also use `logger.clearString()` if the logger // You can use `logger.clearString()` if the intend is to reuse the logger.
// instance will be reused.
``` ```
Logger can be configured to show more information by using `logger.setOption()` method. The following options are available: Logger can be configured to show more information by using `logger.setOption()` method. The following options are available:
@@ -496,29 +505,29 @@ Code injection was one of key concepts of Compiler from the beginning. Compiler
To manipulate the current cursor use Compiler's `getCursor()` and `setCursor()` methods. The following snippet demonstrates the proper way of code injection. To manipulate the current cursor use Compiler's `getCursor()` and `setCursor()` methods. The following snippet demonstrates the proper way of code injection.
```C++ ```c++
X86Compiler c(...); X86Compiler c(...);
X86GpVar a(c, kVarTypeInt32, "a"); X86GpVar x = c.newInt32("x");
X86GpVar b(c, kVarTypeInt32, "b"); X86GpVar y = c.newInt32("y");
Node* here = c.getCursor(); ASNode* here = c.getCursor();
c.mov(b, 2); c.mov(y, 2);
// Now, 'here' can be used to inject something before 'mov b, 2'. To inject // Now, `here` can be used to inject something before `mov y, 2`. To inject
// anything it's good to remember the current cursor so it can be set back // something it's always good to remember the current cursor so it can be set
// after the injecting is done. When setCursor() is called it returns the old // back after the injecting is done. When `setCursor()` is called it returns
// cursor. // the old cursor to be remembered.
Node* oldCursor = c.setCursor(here); ASNode* prev = c.setCursor(here);
c.mov(a, 1); c.mov(x, 1);
c.setCursor(oldCursor); c.setCursor(prev);
``` ```
The resulting code would look like: The resulting code would look like:
``` ```
c.mov(a, 1); c.mov(x, 1);
c.mov(b, 2); c.mov(y, 2);
``` ```
Support Support

16
cxxconfig.js Normal file
View File

@@ -0,0 +1,16 @@
module.exports = {
product: "asmjit",
version: "1.0.0",
prefix: "ASMJIT",
source: "src/asmjit",
tools: {
NoTabs : true,
NoTrailingLines : true,
NoTrailingSpaces: true,
UnixEOL : true,
SortIncludes : true,
ExpandTemplates : true
}
};

View File

@@ -13,14 +13,14 @@
#if !defined(ASMJIT_API_SCOPE) #if !defined(ASMJIT_API_SCOPE)
# define ASMJIT_API_SCOPE # define ASMJIT_API_SCOPE
#else #else
# error "AsmJit - Api-Scope is already active, previous scope not closed by apiend.h?" # error "[asmjit] Api-Scope is already active, previous scope not closed by apiend.h?"
#endif // ASMJIT_API_SCOPE #endif // ASMJIT_API_SCOPE
// ============================================================================ // ============================================================================
// [Override] // [Override]
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_CC_HAS_OVERRIDE) && !defined(override) #if !ASMJIT_CC_HAS_OVERRIDE && !defined(override)
# define override # define override
# define ASMJIT_UNDEF_OVERRIDE # define ASMJIT_UNDEF_OVERRIDE
#endif // !ASMJIT_CC_HAS_OVERRIDE && !override #endif // !ASMJIT_CC_HAS_OVERRIDE && !override
@@ -29,7 +29,7 @@
// [NoExcept] // [NoExcept]
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_CC_HAS_NOEXCEPT) && !defined(noexcept) #if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept)
# define noexcept ASMJIT_NOEXCEPT # define noexcept ASMJIT_NOEXCEPT
# define ASMJIT_UNDEF_NOEXCEPT # define ASMJIT_UNDEF_NOEXCEPT
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept #endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept

View File

@@ -8,7 +8,7 @@
#if defined(ASMJIT_API_SCOPE) #if defined(ASMJIT_API_SCOPE)
# undef ASMJIT_API_SCOPE # undef ASMJIT_API_SCOPE
#else #else
# error "AsmJit - Api-Scope not active, forgot to include apibegin.h?" # error "[asmjit] Api-Scope not active, forgot to include apibegin.h?"
#endif // ASMJIT_API_SCOPE #endif // ASMJIT_API_SCOPE
// ============================================================================ // ============================================================================

View File

@@ -12,57 +12,57 @@
// [asmjit_mainpage] // [asmjit_mainpage]
// ============================================================================ // ============================================================================
//! @mainpage //! \mainpage
//! //!
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++. //! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
//! //!
//! AsmJit is a complete JIT and remote assembler for C++ language. It can //! A complete JIT and remote assembler for C++ language. It can generate native
//! generate native code for x86 and x64 architectures having support for //! code for x86 and x64 architectures and supports the whole x86/x64 instruction
//! a full instruction set, from legacy MMX to the newest AVX2. It has a //! set - from legacy MMX to the newest AVX2. It has a type-safe API that allows
//! type-safe API that allows C++ compiler to do a semantic checks at //! C++ compiler to do semantic checks at compile-time even before the assembled
//! compile-time even before the assembled code is generated or run. //! code is generated and executed.
//! //!
//! AsmJit is not a virtual machine (VM). It doesn't have functionality to //! AsmJit is not a virtual machine (VM). It doesn't have functionality to
//! implement VM out of the box; however, it can be be used as a JIT backend //! implement VM out of the box; however, it can be be used as a JIT backend
//! for your own VM. The usage of AsmJit is not limited at all; it's suitable //! of your own VM. The usage of AsmJit is not limited at all; it's suitable
//! for multimedia, VM backends or remote code generation. //! for multimedia, VM backends, remote code generation, and many other tasks.
//! //!
//! @section AsmJit_Concepts Code Generation Concepts //! \section AsmJit_Main_Concepts Code Generation Concepts
//! //!
//! AsmJit has two completely different code generation concepts. The difference //! AsmJit has two completely different code generation concepts. The difference
//! is in how the code is generated. The first concept, also referred as the low //! is in how the code is generated. The first concept, also referred as a low
//! level concept, is called 'Assembler' and it's the same as writing RAW //! level concept, is called `Assembler` and it's the same as writing RAW
//! assembly by using physical registers directly. In this case AsmJit does only //! assembly by inserting instructions that use physical registers directly. In
//! instruction encoding, verification and relocation. //! this case AsmJit does only instruction encoding, verification and final code
//! relocation.
//! //!
//! The second concept, also referred as the high level concept, is called //! The second concept, also referred as a high level concept, is called
//! 'Compiler'. Compiler lets you use virtually unlimited number of registers //! `Compiler`. Compiler lets you use virtually unlimited number of registers
//! (called variables) significantly simplifying the code generation process. //! (it calls them variables), which significantly simplifies the code generation
//! Compiler allocates these virtual registers to physical registers after the //! process. Compiler allocates these virtual registers to physical registers
//! code generation is done. This requires some extra effort - Compiler has to //! after the code generation is done. This requires some extra effort - Compiler
//! generate information for each node (instruction, function declaration, //! has to generate information for each node (instruction, function declaration,
//! function call) in the code, perform a variable liveness analysis and //! function call, etc...) in the code, perform a variable liveness analysis and
//! translate the code having variables into code having only registers. //! translate the code using variables to a code that uses only physical registers.
//! //!
//! In addition, Compiler understands functions and function calling conventions. //! In addition, Compiler understands functions and their calling conventions.
//! It has been designed in a way that the code generated is always a function //! It has been designed in a way that the code generated is always a function
//! having prototype like in a programming language. By having a function //! having a prototype like a real programming language. By having a function
//! prototype the Compiler is able to insert prolog and epilog to a function //! prototype the Compiler is able to insert prolog and epilog sequence to the
//! being generated and it is able to call a function inside a generated one. //! function being generated and it's able to also generate a necessary code
//! to call other function from your own code.
//! //!
//! There is no conclusion on which concept is better. Assembler brings full //! There is no conclusion on which concept is better. `Assembler` brings full
//! control on how the code is generated, while Compiler makes the generation //! control and the best performance, while `Compiler` makes the code-generation
//! more portable. //! more fun and more portable.
//! //!
//! @section AsmJit_Main_CodeGeneration Code Generation //! \section AsmJit_Main_Sections Documentation Sections
//! //!
//! - \ref asmjit_base_general "Assembler core" - Operands, intrinsics and low-level assembler. //! AsmJit documentation is structured into the following sections:
//! - \ref asmjit_compiler "Compiler" - High level code generation. //! - \ref asmjit_base "Base" - Base API (architecture independent).
//! - \ref asmjit_cpuinfo "Cpu Information" - Get information about host processor. //! - \ref asmjit_x86 "X86/X64" - X86/X64 API.
//! - \ref asmjit_logging "Logging" - Logging and error handling.
//! - \ref AsmJit_MemoryManagement "Memory Management" - Virtual memory management.
//! //!
//! @section AsmJit_Main_HomePage AsmJit Homepage //! \section AsmJit_Main_HomePage AsmJit Homepage
//! //!
//! - https://github.com/kobalicek/asmjit //! - https://github.com/kobalicek/asmjit
@@ -70,89 +70,116 @@
// [asmjit_base] // [asmjit_base]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_base AsmJit //! \defgroup asmjit_base AsmJit Base API (architecture independent)
//! //!
//! \brief AsmJit. //! \brief Base API.
// ============================================================================
// [asmjit_base_general]
// ============================================================================
//! \defgroup asmjit_base_general AsmJit General API
//! \ingroup asmjit_base
//! //!
//! \brief AsmJit general API. //! Base API contains all classes that are platform and architecture independent.
//! //!
//! Contains all `asmjit` classes and helper functions that are architecture //! Code-Generation and Operands
//! independent or abstract. Abstract classes are implemented by the backend, //! ----------------------------
//! for example `Assembler` is implemented by `X86Assembler`.
//! //!
//! - See `Assembler` for low level code generation documentation. //! List of the most useful code-generation and operand classes:
//! - See `Compiler` for high level code generation documentation. //! - \ref asmjit::Assembler - Low-level code-generation.
//! - See `Operand` for operand's overview. //! - \ref asmjit::CodeGen - Astract code-generation that serializes to `Assembler`:
//! - \ref asmjit::Compiler - High-level code-generation.
//! - \ref asmjit::Runtime - Describes where the code is stored and how it's executed:
//! - \ref asmjit::HostRuntime - Runtime that runs on the host machine:
//! - \ref asmjit::JitRuntime - Runtime designed for JIT code generation and execution.
//! - \ref asmjit::StaticRuntime - Runtime for code that starts at a specific address.
//! - \ref asmjit::Stream - Stream is a list of \ref HLNode objects stored as a double
//! linked list:
//! - \ref asmjit::HLNode - Base node interface:
//! - \ref asmjit::HLInst - Instruction node.
//! - \ref asmjit::HLData - Data node.
//! - \ref asmjit::HLAlign - Align directive node.
//! - \ref asmjit::HLLabel - Label node.
//! - \ref asmjit::HLComment - Comment node.
//! - \ref asmjit::HLSentinel - Sentinel node.
//! - \ref asmjit::HLHint - Instruction node.
//! - \ref asmjit::HLFunc - Function declaration node.
//! - \ref asmjit::HLRet - Function return node.
//! - \ref asmjit::HLCall - Function call node.
//! - \ref asmjit::HLCallArg - Function call argument node.
//! - \ref asmjit::Operand - base class for all operands:
//! - \ref asmjit::Reg - Register operand (`Assembler` only).
//! - \ref asmjit::Var - Variable operand (`Compiler` only).
//! - \ref asmjit::Mem - Memory operand.
//! - \ref asmjit::Imm - Immediate operand.
//! - \ref asmjit::Label - Label operand.
//!
//! The following snippet shows how to setup a basic JIT code generation:
//!
//! ~~~
//! using namespace asmjit;
//!
//! int main(int argc, char* argv[]) {
//! // JIT runtime is designed for JIT code generation and execution.
//! JitRuntime runtime;
//!
//! // Assembler instance requires to know the runtime to function.
//! X86Assembler a(&runtime);
//!
//! // Compiler (if you indend to use it) requires an assembler instance.
//! X86Compiler c(&a);
//!
//! return 0;
//! }
//! ~~~
//! //!
//! Logging and Error Handling //! Logging and Error Handling
//! -------------------------- //! --------------------------
//! //!
//! AsmJit contains robust interface that can be used to log the generated code //! AsmJit contains a robust interface that can be used to log the generated code
//! and to handle possible errors. Base logging interface is defined in `Logger` //! and to handle possible errors. Base logging interface is provided by \ref
//! class that is abstract and can be overridden. AsmJit contains two loggers //! Logger, which is abstract and can be used as a base for your own logger.
//! that can be used out of the box - `FileLogger` that logs into a pure C //! AsmJit also implements some trivial logging concepts out of the box to
//! `FILE*` stream and `StringLogger` that just concatenates all log messages //! simplify the development. \ref FileLogger logs into a C `FILE*` stream and
//! by using a `StringBuilder` class. //! \ref StringLogger concatenates all log messages into a single string.
//! //!
//! The following snippet shows how to setup a logger that logs to `stderr`: //! The following snippet shows how to setup a basic logger and error handler:
//! //!
//! ~~~ //! ~~~
//! // `FileLogger` instance. //! using namespace asmjit;
//!
//! struct MyErrorHandler : public ErrorHandler {
//! virtual bool handleError(Error code, const char* message, void* origin) {
//! printf("Error 0x%0.8X: %s\n", code, message);
//!
//! // True - error handled and code generation can continue.
//! // False - error not handled, code generation should stop.
//! return false;
//! }
//! }
//!
//! int main(int argc, char* argv[]) {
//! JitRuntime runtime;
//! FileLogger logger(stderr); //! FileLogger logger(stderr);
//! MyErrorHandler eh;
//! //!
//! // `Compiler` or any other `CodeGen` interface. //! X86Assembler a(&runtime);
//! host::Compiler c; //! a.setLogger(&logger);
//! a.setErrorHandler(&eh);
//! //!
//! // use `setLogger` to replace the `CodeGen` logger. //! ...
//! c.setLogger(&logger); //!
//! return 0;
//! }
//! ~~~ //! ~~~
//! //!
//! \sa \ref Logger, \ref FileLogger, \ref StringLogger. //! AsmJit also contains an \ref ErrorHandler, which is an abstract class that
//! can be used to implement your own error handling. It can be associated with
// ============================================================================ //! \ref Assembler and used to report all errors. It's a very convenient way to
// [asmjit_base_compiler] //! be aware of any error that happens during the code generation without making
// ============================================================================ //! the error handling complicated.
//! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base
//! //!
//! \brief AsmJit code-tree used by Compiler. //! List of the most useful logging and error handling classes:
//! //! - \ref asmjit::Logger - abstract logging interface:
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes //! - \ref asmjit::FileLogger - A logger that logs to `FILE*`.
//! that represent assembler instructions, directives, labels and high-level //! - \ref asmjit::StringLogger - A logger that concatenates to a single string.
//! constructs compiler is using to represent functions and function calls. The //! - \ref asmjit::ErrorHandler - Easy way to handle \ref Assembler and \ref
//! node list can only be used together with \ref Compiler. //! Compiler
//! //! errors.
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \defgroup asmjit_base_util AsmJit Utilities
//! \ingroup asmjit_base
//!
//! \brief AsmJit utility classes.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//!
//! POD Containers
//! --------------
//!
//! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref PodVector - Simple growing array-like container for POD data.
//! - \ref StringBuilder - Simple string builder that can append string
//! and integers.
//! //!
//! Zone Memory Allocator //! Zone Memory Allocator
//! --------------------- //! ---------------------
@@ -163,51 +190,60 @@
//! is to increment a pointer and return its previous address. See \ref Zone //! is to increment a pointer and return its previous address. See \ref Zone
//! for more details. //! for more details.
//! //!
//! CPU Ticks //! The whole AsmJit library is based on zone memory allocation for performance
//! --------- //! reasons. It has many other benefits, but the performance was the main one
//! when designing the library.
//! //!
//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See //! POD Containers
//! \ref CpuTicks class for more details. //! --------------
//! //!
//! Integer Utilities //! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref asmjit::BitArray - A fixed bit-array that is used internally.
//! - \ref asmjit::PodVector<T> - A simple array-like container for storing
//! POD data.
//! - \ref asmjit::PodList<T> - A single linked list.
//! - \ref asmjit::StringBuilder - A string builder that can append strings
//! and integers.
//!
//! Utility Functions
//! ----------------- //! -----------------
//! //!
//! Integer utilities are all implemented by a static class \ref IntUtil. //! Utility functions are implementated static class \ref Utils. There are
//! There are utilities for bit manipulation and bit counting, utilities to get //! utilities for bit manipulation and bit counting, utilities to get an
//! an integer minimum / maximum and various other helpers required to perform //! integer minimum / maximum and various other helpers required to perform
//! alignment checks and binary casting from float to integer and vica versa. //! alignment checks and binary casting from float to integer and vice versa.
//! //!
//! Vector Utilities //! String utilities are also implemented by a static class \ref Utils. They
//! ---------------- //! are mostly used by AsmJit internals and not really important to end users.
//!
//! SIMD Utilities
//! --------------
//! //!
//! SIMD code generation often requires to embed constants after each function //! SIMD code generation often requires to embed constants after each function
//! or a block of functions generated. AsmJit contains classes `Vec64`, //! or at the end of the whole code block. AsmJit contains `Vec64`, `Vec128`
//! `Vec128` and `Vec256` that can be used to prepare data useful when //! and `Vec256` classes that can be used to prepare data useful when generating
//! generating SIMD code. //! SIMD code.
//! //!
//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm` //! X86/X64 code generators contain member functions `dmm`, `dxmm`, and `dymm`,
//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into //! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
//! machine code (both assembler and compiler are supported). //! the machine code.
//!
//! \note Compiler contains a constant pool, which should be used instead of
//! embedding constants manually after the function body.
// ============================================================================ // ============================================================================
// [asmjit_x86] // [asmjit_x86]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86 X86/X64 //! \defgroup asmjit_x86 AsmJit X86/X64 API
//! //!
//! \brief X86/X64 module //! \brief X86/X64 API
// ============================================================================
// [asmjit_x86_general]
// ============================================================================
//! \defgroup asmjit_x86_general X86/X64 General API
//! \ingroup asmjit_x86
//! //!
//! \brief X86/X64 general API. //! X86/X64 Code Generation
//! -----------------------
//!
//! X86/X64 code generation is realized throught:
//! - \ref X86Assembler - low-level code generation.
//! - \ref X86Compiler - high-level code generation.
//! //!
//! X86/X64 Registers //! X86/X64 Registers
//! ----------------- //! -----------------
@@ -216,16 +252,17 @@
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through //! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
//! these functions: //! these functions:
//! //!
//! - `asmjit::gpb_lo()` - Get Gpb-lo register. //! - `asmjit::x86::gpb_lo()` - Get an 8-bit Gpb low register.
//! - `asmjit::gpb_hi()` - Get Gpb-hi register. //! - `asmjit::x86::gpb_hi()` - Get an 8-hi Gpb hugh register.
//! - `asmjit::gpw()` - Get Gpw register. //! - `asmjit::x86::gpw()` - Get a 16-bit Gpw register.
//! - `asmjit::gpd()` - Get Gpd register. //! - `asmjit::x86::gpd()` - Get a 32-bit Gpd register.
//! - `asmjit::gpq()` - Get Gpq Gp register. //! - `asmjit::x86::gpq()` - Get a 64-bit Gpq Gp register.
//! - `asmjit::gpz()` - Get Gpd/Gpq register. //! - `asmjit::x86::gpz()` - Get a 32-bit or 64-bit Gpd/Gpq register.
//! - `asmjit::fp()` - Get Fp register. //! - `asmjit::x86::fp()` - Get a 80-bit Fp register.
//! - `asmjit::mm()` - Get Mm register. //! - `asmjit::x86::mm()` - Get a 64-bit Mm register.
//! - `asmjit::xmm()` - Get Xmm register. //! - `asmjit::x86::xmm()` - Get a 128-bit Xmm register.
//! - `asmjit::ymm()` - Get Ymm register. //! - `asmjit::x86::ymm()` - Get a 256-bit Ymm register.
//! - `asmjit::x86::amm()` - Get a 512-bit Zmm register.
//! //!
//! X86/X64 Addressing //! X86/X64 Addressing
//! ------------------ //! ------------------
@@ -235,32 +272,33 @@
//! `BaseMem` class. These functions are used to make operands that represents //! `BaseMem` class. These functions are used to make operands that represents
//! memory addresses: //! memory addresses:
//! //!
//! - `asmjit::ptr()` - Address size not specified. //! - `asmjit::x86::ptr()` - Address size not specified.
//! - `asmjit::byte_ptr()` - 1 byte. //! - `asmjit::x86::byte_ptr()` - 1 byte.
//! - `asmjit::word_ptr()` - 2 bytes (Gpw size). //! - `asmjit::x86::word_ptr()` - 2 bytes (Gpw size).
//! - `asmjit::dword_ptr()` - 4 bytes (Gpd size). //! - `asmjit::x86::dword_ptr()` - 4 bytes (Gpd size).
//! - `asmjit::qword_ptr()` - 8 bytes (Gpq/Mm size). //! - `asmjit::x86::qword_ptr()` - 8 bytes (Gpq/Mm size).
//! - `asmjit::tword_ptr()` - 10 bytes (FPU). //! - `asmjit::x86::tword_ptr()` - 10 bytes (FPU size).
//! - `asmjit::oword_ptr()` - 16 bytes (Xmm size). //! - `asmjit::x86::oword_ptr()` - 16 bytes (Xmm size).
//! - `asmjit::yword_ptr()` - 32 bytes (Ymm size). //! - `asmjit::x86::yword_ptr()` - 32 bytes (Ymm size).
//! - `asmjit::zword_ptr()` - 64 bytes (Zmm size). //! - `asmjit::x86::zword_ptr()` - 64 bytes (Zmm size).
//! //!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates //! Most useful function to make pointer should be `asmjit::x86::ptr()`. It
//! pointer to the target with unspecified size. Unspecified size works in all //! creates a pointer to the target with an unspecified size. Unspecified size
//! intrinsics where are used registers (this means that size is specified by //! works in all intrinsics where are used registers (this means that size is
//! register operand or by instruction itself). For example `asmjit::ptr()` //! specified by register operand or by instruction itself). For example
//! can't be used with `Assembler::inc()` instruction. In this case size must //! `asmjit::x86::ptr()` can't be used with `Assembler::inc()` instruction. In
//! be specified and it's also reason to make difference between pointer sizes. //! this case the size must be specified and it's also reason to differentiate
//! between pointer sizes.
//! //!
//! Supported are simple address forms `[base + displacement]` and complex //! X86 and X86 support simple address forms like `[base + displacement]` and
//! address forms `[base + index * scale + displacement]`. //! also complex address forms like `[base + index * scale + displacement]`.
//! //!
//! X86/X64 Immediates //! X86/X64 Immediates
//! ------------------ //! ------------------
//! //!
//! Immediate values are constants thats passed directly after instruction //! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use `imm()` or `imm_u()` methods to create //! opcode. To create such value use `asmjit::imm()` or `asmjit::imm_u()`
//! signed or unsigned immediate value. //! methods to create a signed or unsigned immediate value.
//! //!
//! X86/X64 CPU Information //! X86/X64 CPU Information
//! ----------------------- //! -----------------------
@@ -290,7 +328,7 @@
//! use certain CPU features. For example there used to be a SSE/SSE2 detection //! use certain CPU features. For example there used to be a SSE/SSE2 detection
//! in the past and today there is often AVX/AVX2 detection. //! in the past and today there is often AVX/AVX2 detection.
//! //!
//! The example below shows how to detect SSE2: //! The example below shows how to detect SSE4.1:
//! //!
//! ~~~ //! ~~~
//! using namespace asmjit; //! using namespace asmjit;
@@ -298,11 +336,11 @@
//! // Get `X86CpuInfo` global instance. //! // Get `X86CpuInfo` global instance.
//! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost(); //! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
//! //!
//! if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) { //! if (cpuInfo->hasFeature(kX86CpuFeatureSSE4_1)) {
//! // Processor has SSE2. //! // Processor has SSE4.1.
//! } //! }
//! else if (cpuInfo->hasFeature(kX86CpuFeatureMMX)) { //! else if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) {
//! // Processor doesn't have SSE2, but has MMX. //! // Processor doesn't have SSE4.1, but has SSE2.
//! } //! }
//! else { //! else {
//! // Processor is archaic; it's a wonder AsmJit works here! //! // Processor is archaic; it's a wonder AsmJit works here!
@@ -314,56 +352,21 @@
//! ~~~ //! ~~~
//! using namespace asmjit; //! using namespace asmjit;
//! //!
//! // Call cpuid, first two arguments are passed in Eax/Ecx. //! // Call CPUID, first two arguments are passed in EAX/ECX.
//! X86CpuId out; //! X86CpuId out;
//! X86CpuUtil::callCpuId(0, 0, &out); //! X86CpuUtil::callCpuId(0, 0, &out);
//! //!
//! // If Eax argument is 0, Ebx, Ecx and Edx registers are filled with a cpu vendor. //! // If EAX argument is 0, EBX, ECX and EDX registers are filled with a CPU vendor.
//! char cpuVendor[13]; //! char cpuVendor[13];
//! ::memcpy(cpuVendor, &out.ebx, 4); //! ::memcpy(cpuVendor, &out.ebx, 4);
//! ::memcpy(cpuVendor + 4, &out.edx, 4); //! ::memcpy(cpuVendor + 4, &out.edx, 4);
//! ::memcpy(cpuVendor + 8, &out.ecx, 4); //! ::memcpy(cpuVendor + 8, &out.ecx, 4);
//! vendor[12] = '\0'; //! vendor[12] = '\0';
//! //!
//! // Print a CPU vendor retrieved from CPUID. //! // Print the CPU vendor retrieved from CPUID.
//! ::printf("%s", cpuVendor); //! ::printf("CPU Vendor: %s\n", cpuVendor);
//! ~~~ //! ~~~
// ============================================================================
// [asmjit_x86_compiler]
// ============================================================================
//! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 code-tree and helpers.
// ============================================================================
// [asmjit_x86_inst]
// ============================================================================
//! \defgroup asmjit_x86_inst X86/X64 Instructions
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 low-level instruction definitions.
// ============================================================================
// [asmjit_x86_util]
// ============================================================================
//! \defgroup asmjit_x86_util X86/X64 Utilities
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 utility classes.
// ============================================================================
// [asmjit_contrib]
// ============================================================================
//! \defgroup asmjit_contrib Contributions
//!
//! \brief Contributions.
// [Dependencies - Base] // [Dependencies - Base]
#include "./base.h" #include "./base.h"

View File

@@ -12,23 +12,23 @@
#include "./build.h" #include "./build.h"
#include "./base/assembler.h" #include "./base/assembler.h"
#include "./base/codegen.h"
#include "./base/compiler.h"
#include "./base/constpool.h" #include "./base/constpool.h"
#include "./base/containers.h" #include "./base/containers.h"
#include "./base/cpuinfo.h" #include "./base/cpuinfo.h"
#include "./base/cputicks.h"
#include "./base/error.h"
#include "./base/globals.h" #include "./base/globals.h"
#include "./base/intutil.h"
#include "./base/lock.h"
#include "./base/logger.h" #include "./base/logger.h"
#include "./base/operand.h" #include "./base/operand.h"
#include "./base/runtime.h" #include "./base/runtime.h"
#include "./base/string.h" #include "./base/utils.h"
#include "./base/vectypes.h" #include "./base/vectypes.h"
#include "./base/vmem.h" #include "./base/vmem.h"
#include "./base/zone.h" #include "./base/zone.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
#include "./base/hlstream.h"
#include "./base/compiler.h"
#include "./base/compilerfunc.h"
#endif // !ASMJIT_DISABLE_COMPILER
// [Guard] // [Guard]
#endif // _ASMJIT_BASE_H #endif // _ASMJIT_BASE_H

View File

@@ -9,7 +9,7 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/assembler.h" #include "../base/assembler.h"
#include "../base/intutil.h" #include "../base/utils.h"
#include "../base/vmem.h" #include "../base/vmem.h"
// [Dependenceis - C] // [Dependenceis - C]
@@ -21,35 +21,116 @@
namespace asmjit { namespace asmjit {
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Construction / Destruction] // [asmjit::ErrorHandler]
// ============================================================================ // ============================================================================
Assembler::Assembler(Runtime* runtime) : ErrorHandler::ErrorHandler() {}
CodeGen(runtime), ErrorHandler::~ErrorHandler() {}
_buffer(NULL),
_end(NULL),
_cursor(NULL),
_trampolineSize(0),
_comment(NULL),
_unusedLinks(NULL) {}
Assembler::~Assembler() { ErrorHandler* ErrorHandler::addRef() const {
reset(true); return const_cast<ErrorHandler*>(this);
}
void ErrorHandler::release() {}
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
CodeGen::CodeGen()
: _assembler(NULL),
_hlId(0),
_arch(kArchNone),
_regSize(0),
_finalized(false),
_reserved(0),
_lastError(kErrorNotInitialized) {}
CodeGen::~CodeGen() {}
Error CodeGen::setLastError(Error error, const char* message) {
// Special case, reset the last error the error is `kErrorOk`.
if (error == kErrorOk) {
_lastError = kErrorOk;
return kErrorOk;
}
// Don't do anything if the code-generator doesn't have associated assembler.
Assembler* assembler = getAssembler();
if (assembler == NULL)
return error;
if (message == NULL)
message = DebugUtils::errorAsString(error);
// Logging is skipped if the error is handled by `ErrorHandler.
ErrorHandler* eh = assembler->getErrorHandler();
ASMJIT_TLOG("[ERROR (CodeGen)] %s (0x%0.8u) %s\n", message,
static_cast<unsigned int>(error),
!eh ? "(Possibly unhandled?)" : "");
if (eh != NULL && eh->handleError(error, message, this))
return error;
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = assembler->getLogger();
if (logger != NULL)
logger->logFormat(kLoggerStyleComment,
"*** ERROR (CodeGen): %s (0x%0.8u).\n", message,
static_cast<unsigned int>(error));
#endif // !ASMJIT_DISABLE_LOGGER
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of `setLastError()`. This is the reason why
// we have delayed changing the `_error` member until now.
_lastError = error;
return error;
} }
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Clear / Reset] // [asmjit::Assembler - Construction / Destruction]
// ============================================================================
Assembler::Assembler(Runtime* runtime)
: _runtime(runtime),
_logger(NULL),
_errorHandler(NULL),
_arch(kArchNone),
_regSize(0),
_reserved(0),
_features(Utils::mask(kAssemblerFeatureOptimizedAlign)),
_instOptions(0),
_lastError(runtime ? kErrorOk : kErrorNotInitialized),
_hlIdGenerator(0),
_hlAttachedCount(0),
_zoneAllocator(8192 - Zone::kZoneOverhead),
_buffer(NULL),
_end(NULL),
_cursor(NULL),
_trampolinesSize(0),
_comment(NULL),
_unusedLinks(NULL),
_labelList(),
_relocList() {}
Assembler::~Assembler() {
reset(true);
if (_errorHandler != NULL)
_errorHandler->release();
}
// ============================================================================
// [asmjit::Assembler - Reset]
// ============================================================================ // ============================================================================
void Assembler::reset(bool releaseMemory) { void Assembler::reset(bool releaseMemory) {
// CodeGen members. _features = Utils::mask(kAssemblerFeatureOptimizedAlign);
_baseAddress = kNoBaseAddress;
_instOptions = 0; _instOptions = 0;
_error = kErrorOk; _lastError = kErrorOk;
_hlIdGenerator = 0;
_hlAttachedCount = 0;
_baseZone.reset(releaseMemory); _zoneAllocator.reset(releaseMemory);
// Assembler members.
if (releaseMemory && _buffer != NULL) { if (releaseMemory && _buffer != NULL) {
ASMJIT_FREE(_buffer); ASMJIT_FREE(_buffer);
_buffer = NULL; _buffer = NULL;
@@ -57,7 +138,7 @@ void Assembler::reset(bool releaseMemory) {
} }
_cursor = _buffer; _cursor = _buffer;
_trampolineSize = 0; _trampolinesSize = 0;
_comment = NULL; _comment = NULL;
_unusedLinks = NULL; _unusedLinks = NULL;
@@ -66,6 +147,57 @@ void Assembler::reset(bool releaseMemory) {
_relocList.reset(releaseMemory); _relocList.reset(releaseMemory);
} }
// ============================================================================
// [asmjit::Assembler - Logging & Error Handling]
// ============================================================================
Error Assembler::setLastError(Error error, const char* message) {
// Special case, reset the last error the error is `kErrorOk`.
if (error == kErrorOk) {
_lastError = kErrorOk;
return kErrorOk;
}
if (message == NULL)
message = DebugUtils::errorAsString(error);
// Logging is skipped if the error is handled by `ErrorHandler.
ErrorHandler* eh = _errorHandler;
ASMJIT_TLOG("[ERROR (Assembler)] %s (0x%0.8u) %s\n", message,
static_cast<unsigned int>(error),
!eh ? "(Possibly unhandled?)" : "");
if (eh != NULL && eh->handleError(error, message, this))
return error;
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = _logger;
if (logger != NULL)
logger->logFormat(kLoggerStyleComment,
"*** ERROR (Assembler): %s (0x%0.8u).\n", message,
static_cast<unsigned int>(error));
#endif // !ASMJIT_DISABLE_LOGGER
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of `setLastError()`. This is the reason why
// we have delayed changing the `_error` member until now.
_lastError = error;
return error;
}
Error Assembler::setErrorHandler(ErrorHandler* handler) {
ErrorHandler* oldHandler = _errorHandler;
if (oldHandler != NULL)
oldHandler->release();
if (handler != NULL)
handler = handler->addRef();
_errorHandler = handler;
return kErrorOk;
}
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Buffer] // [asmjit::Assembler - Buffer]
// ============================================================================ // ============================================================================
@@ -75,8 +207,8 @@ Error Assembler::_grow(size_t n) {
size_t after = getOffset() + n; size_t after = getOffset() + n;
// Overflow. // Overflow.
if (n > IntUtil::maxUInt<uintptr_t>() - capacity) if (n > IntTraits<uintptr_t>::maxValue() - capacity)
return setError(kErrorNoHeapMemory); return setLastError(kErrorNoHeapMemory);
// Grow is called when allocation is needed, so it shouldn't happen, but on // Grow is called when allocation is needed, so it shouldn't happen, but on
// the other hand it is simple to catch and it's not an error. // the other hand it is simple to catch and it's not an error.
@@ -98,7 +230,7 @@ Error Assembler::_grow(size_t n) {
// Overflow. // Overflow.
if (oldCapacity > capacity) if (oldCapacity > capacity)
return setError(kErrorNoHeapMemory); return setLastError(kErrorNoHeapMemory);
} while (capacity - kMemAllocOverhead < after); } while (capacity - kMemAllocOverhead < after);
capacity -= kMemAllocOverhead; capacity -= kMemAllocOverhead;
@@ -117,7 +249,7 @@ Error Assembler::_reserve(size_t n) {
newBuffer = static_cast<uint8_t*>(ASMJIT_REALLOC(_buffer, n)); newBuffer = static_cast<uint8_t*>(ASMJIT_REALLOC(_buffer, n));
if (newBuffer == NULL) if (newBuffer == NULL)
return setError(kErrorNoHeapMemory); return setLastError(kErrorNoHeapMemory);
size_t offset = getOffset(); size_t offset = getOffset();
@@ -132,41 +264,23 @@ Error Assembler::_reserve(size_t n) {
// [asmjit::Assembler - Label] // [asmjit::Assembler - Label]
// ============================================================================ // ============================================================================
Error Assembler::_registerIndexedLabels(size_t index) { Error Assembler::_newLabelId() {
size_t i = _labelList.getLength(); LabelData* data = _zoneAllocator.allocT<LabelData>();
if (index < i)
return kErrorOk;
if (_labelList._grow(index - i) != kErrorOk) data->offset = -1;
return setError(kErrorNoHeapMemory); data->links = NULL;
data->hlId = 0;
data->hlData = NULL;
LabelData data; uint32_t id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labelList.getLength()));
data.offset = -1; Error error = _labelList.append(data);
data.links = NULL;
do { if (error != kErrorOk) {
_labelList.append(data); setLastError(kErrorNoHeapMemory);
} while (++i < index); return kInvalidValue;
return kErrorOk;
} }
Error Assembler::_newLabel(Label* dst) { return id;
dst->_label.op = kOperandTypeLabel;
dst->_label.size = 0;
dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labelList.getLength()));
LabelData data;
data.offset = -1;
data.links = NULL;
if (_labelList.append(data) != kErrorOk)
goto _NoMemory;
return kErrorOk;
_NoMemory:
dst->_label.id = kInvalidValue;
return setError(kErrorNoHeapMemory);
} }
LabelLink* Assembler::_newLabelLink() { LabelLink* Assembler::_newLabelLink() {
@@ -176,7 +290,7 @@ LabelLink* Assembler::_newLabelLink() {
_unusedLinks = link->prev; _unusedLinks = link->prev;
} }
else { else {
link = _baseZone.allocT<LabelLink>(); link = _zoneAllocator.allocT<LabelLink>();
if (link == NULL) if (link == NULL)
return NULL; return NULL;
} }
@@ -196,11 +310,11 @@ Error Assembler::bind(const Label& label) {
// Label can be bound only once. // Label can be bound only once.
if (data->offset != -1) if (data->offset != -1)
return setError(kErrorLabelAlreadyBound); return setLastError(kErrorLabelAlreadyBound);
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGER)
if (_logger) { if (_logger) {
StringBuilderT<256> sb; StringBuilderTmp<256> sb;
sb.setFormat("L%u:", index); sb.setFormat("L%u:", index);
size_t binSize = 0; size_t binSize = 0;
@@ -241,7 +355,7 @@ Error Assembler::bind(const Label& label) {
} }
else { else {
ASMJIT_ASSERT(size == 1); ASMJIT_ASSERT(size == 1);
if (IntUtil::isInt8(patchedValue)) if (Utils::isInt8(patchedValue))
setByteAt(offset, static_cast<uint8_t>(patchedValue & 0xFF)); setByteAt(offset, static_cast<uint8_t>(patchedValue & 0xFF));
else else
error = kErrorIllegalDisplacement; error = kErrorIllegalDisplacement;
@@ -267,7 +381,7 @@ Error Assembler::bind(const Label& label) {
data->links = NULL; data->links = NULL;
if (error != kErrorOk) if (error != kErrorOk)
return setError(error); return setLastError(error);
_comment = NULL; _comment = NULL;
return error; return error;
@@ -281,7 +395,7 @@ Error Assembler::embed(const void* data, uint32_t size) {
if (getRemainingSpace() < size) { if (getRemainingSpace() < size) {
Error error = _grow(size); Error error = _grow(size);
if (error != kErrorOk) if (error != kErrorOk)
return setError(error); return setLastError(error);
} }
uint8_t* cursor = getCursor(); uint8_t* cursor = getCursor();
@@ -302,10 +416,7 @@ Error Assembler::embed(const void* data, uint32_t size) {
size_t Assembler::relocCode(void* dst, Ptr baseAddress) const { size_t Assembler::relocCode(void* dst, Ptr baseAddress) const {
if (baseAddress == kNoBaseAddress) if (baseAddress == kNoBaseAddress)
baseAddress = hasBaseAddress() ? getBaseAddress() : static_cast<Ptr>((uintptr_t)dst); baseAddress = static_cast<Ptr>((uintptr_t)dst);
else if (getBaseAddress() != baseAddress)
return 0;
return _relocCode(dst, baseAddress); return _relocCode(dst, baseAddress);
} }
@@ -315,14 +426,14 @@ size_t Assembler::relocCode(void* dst, Ptr baseAddress) const {
void* Assembler::make() { void* Assembler::make() {
// Do nothing on error condition or if no instruction has been emitted. // Do nothing on error condition or if no instruction has been emitted.
if (_error != kErrorOk || getCodeSize() == 0) if (_lastError != kErrorOk || getCodeSize() == 0)
return NULL; return NULL;
void* p; void* p;
Error error = _runtime->add(&p, this); Error error = _runtime->add(&p, this);
if (error != kErrorOk) if (error != kErrorOk)
setError(error); setLastError(error);
return p; return p;
} }
@@ -349,6 +460,10 @@ Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const
return _emit(code, o0, o1, o2, NA); return _emit(code, o0, o1, o2, NA);
} }
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
return _emit(code, o0, o1, o2, o3);
}
Error Assembler::emit(uint32_t code, int o0) { Error Assembler::emit(uint32_t code, int o0) {
return _emit(code, Imm(o0), NA, NA, NA); return _emit(code, Imm(o0), NA, NA, NA);
} }

View File

@@ -9,9 +9,7 @@
#define _ASMJIT_BASE_ASSEMBLER_H #define _ASMJIT_BASE_ASSEMBLER_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/codegen.h"
#include "../base/containers.h" #include "../base/containers.h"
#include "../base/error.h"
#include "../base/logger.h" #include "../base/logger.h"
#include "../base/operand.h" #include "../base/operand.h"
#include "../base/runtime.h" #include "../base/runtime.h"
@@ -22,9 +20,51 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================
// [asmjit::AssemblerFeatures]
// ============================================================================
//! Features of \ref Assembler.
ASMJIT_ENUM(AssemblerFeatures) {
//! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
//!
//! Default `true`.
//!
//! X86/X64
//! -------
//!
//! Default align sequence used by X86/X64 architecture is one-byte 0x90
//! opcode that is mostly shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled asmjit will generate specialized sequences
//! for alignment between 1 to 11 bytes. Also when `X86Compiler` is used,
//! it can add REX prefixes into the code to make some instructions greater
//! so no alignment sequence is needed.
kAssemblerFeatureOptimizedAlign = 0,
//! Emit jump-prediction hints (`Assembler` and `Compiler`).
//!
//! Default `false`.
//!
//! X86/X64
//! -------
//!
//! 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 that ignores any static hints.
kAssemblerFeaturePredictedJumps = 1
};
// ============================================================================ // ============================================================================
// [asmjit::InstId] // [asmjit::InstId]
// ============================================================================ // ============================================================================
@@ -44,30 +84,43 @@ ASMJIT_ENUM(InstOptions) {
//! No instruction options. //! No instruction options.
kInstOptionNone = 0x00000000, kInstOptionNone = 0x00000000,
//! Emit short form of the instruction. //! Emit short form of the instruction (X86/X64 only).
//! //!
//! X86/X64: //! X86/X64 Specific
//! ----------------
//! //!
//! Short form is mostly related to jmp and jcc instructions, but can be used //! Short form is mostly related to jmp and jcc instructions, but can be used
//! by other instructions supporting 8-bit or 32-bit immediates. This option //! by other instructions supporting 8-bit or 32-bit immediates. This option
//! can be dangerous if the short jmp/jcc is required, but not encodable due //! can be dangerous if the short jmp/jcc is required, but not encodable due
//! to large displacement, in such case an error happens and the whole //! to a large displacement, in such case an error is reported.
//! assembler/compiler stream is unusable.
kInstOptionShortForm = 0x00000001, kInstOptionShortForm = 0x00000001,
//! Emit long form of the instruction. //! Emit long form of the instruction (X86/X64 only).
//! //!
//! X86/X64: //! X86/X64 Specific
//! ----------------
//! //!
//! Long form is mosrlt related to jmp and jcc instructions, but like the //! Long form is mostly related to jmp and jcc instructions, but like the
//! `kInstOptionShortForm` option it can be used by other instructions //! `kInstOptionShortForm` option it can be used by other instructions
//! supporting both 8-bit and 32-bit immediates. //! supporting both 8-bit and 32-bit immediates.
kInstOptionLongForm = 0x00000002, kInstOptionLongForm = 0x00000002,
//! Condition is likely to be taken. //! Condition is likely to be taken.
//!
//! X86/X64 Specific
//! ----------------
//!
//! This option has no effect at the moment. Intel stopped supporting
//! conditional hints after P4 and AMD has never supported them.
kInstOptionTaken = 0x00000004, kInstOptionTaken = 0x00000004,
//! Condition is unlikely to be taken. //! Condition is unlikely to be taken.
//!
//! X86/X64 Specific
//! ----------------
//!
//! This option has no effect at the moment. Intel stopped supporting
//! conditional hints after P4 and AMD has never supported them.
kInstOptionNotTaken = 0x00000008, kInstOptionNotTaken = 0x00000008,
//! Don't follow the jump (Compiler-only). //! Don't follow the jump (Compiler-only).
@@ -76,6 +129,36 @@ ASMJIT_ENUM(InstOptions) {
kInstOptionUnfollow = 0x00000010 kInstOptionUnfollow = 0x00000010
}; };
// ============================================================================
// [asmjit::AlignMode]
// ============================================================================
//! Code aligning mode.
ASMJIT_ENUM(AlignMode) {
//! Align by emitting a sequence that can be executed (code).
kAlignCode = 0,
//! Align by emitting a sequence that shouldn't be executed (data).
kAlignData = 1,
//! Align by emitting a sequence of zeros.
kAlignZero = 2
};
// ============================================================================
// [asmjit::RelocMode]
// ============================================================================
//! Relocation mode.
ASMJIT_ENUM(RelocMode) {
//! Relocate an absolute address to an absolute address.
kRelocAbsToAbs = 0,
//! Relocate a relative address to an absolute address.
kRelocRelToAbs = 1,
//! Relocate an absolute address to a relative address.
kRelocAbsToRel = 2,
//! Relocate an absolute address to a relative address or use trampoline.
kRelocTrampoline = 3
};
// ============================================================================ // ============================================================================
// [asmjit::LabelLink] // [asmjit::LabelLink]
// ============================================================================ // ============================================================================
@@ -90,7 +173,7 @@ struct LabelLink {
intptr_t offset; intptr_t offset;
//! Inlined displacement. //! Inlined displacement.
intptr_t displacement; intptr_t displacement;
//! RelocId if link must be absolute when relocated. //! RelocId in case the link has to be absolute after relocated.
intptr_t relocId; intptr_t relocId;
}; };
@@ -106,17 +189,24 @@ struct LabelData {
intptr_t offset; intptr_t offset;
//! Label links chain. //! Label links chain.
LabelLink* links; LabelLink* links;
//! An ID of a code-generator that created this label.
uint64_t hlId;
//! Pointer to the data the code-generator associated with the label.
void* hlData;
}; };
// ============================================================================ // ============================================================================
// [asmjit::RelocData] // [asmjit::RelocData]
// ============================================================================ // ============================================================================
//! \internal //! \internal
//! //!
//! Code relocation data (relative vs absolute addresses). //! Code relocation data (relative vs. absolute addresses).
//! //!
//! X86/X64: //! X86/X64 Specific
//! ----------------
//! //!
//! X86 architecture uses 32-bit absolute addressing model by memory operands, //! X86 architecture uses 32-bit absolute addressing model by memory operands,
//! but 64-bit mode uses relative addressing model (RIP + displacement). In //! but 64-bit mode uses relative addressing model (RIP + displacement). In
@@ -135,17 +225,198 @@ struct RelocData {
Ptr data; Ptr data;
}; };
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
//! Error handler.
//!
//! Error handler can be used to override the default behavior of `CodeGen`
//! error handling and propagation. See `handleError()` on how to override it.
//!
//! Please note that `addRef` and `release` functions are used, but there is
//! no reference counting implemented by default, reimplement to change the
//! default behavior.
struct ASMJIT_VIRTAPI ErrorHandler {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler();
//! Destroy the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler();
// --------------------------------------------------------------------------
// [AddRef / Release]
// --------------------------------------------------------------------------
//! Reference this error handler.
//!
//! \note This member function is provided for convenience. The default
//! implementation does nothing. If you are working in environment where
//! multiple `ErrorHandler` instances are used by a different code generators
//! you may provide your own functionality for reference counting. In that
//! case `addRef()` and `release()` functions should be overridden.
ASMJIT_API virtual ErrorHandler* addRef() const;
//! Release this error handler.
//!
//! \note This member function is provided for convenience. See `addRef()`
//! for more detailed information related to reference counting.
ASMJIT_API virtual void release();
// --------------------------------------------------------------------------
// [Handle Error]
// --------------------------------------------------------------------------
//! Error handler (pure).
//!
//! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `Assembler` and
//! `Compiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons.
//!
//! AsmJit library doesn't use exceptions and can be compiled with or without
//! exception handling support. Even if the AsmJit library is compiled without
//! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the
//! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
//! throwing an exception is using `setjmp()` and `longjmp()` pair available
//! in the standard C library.
//!
//! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
//! execution (instruction serialization) can continue. However if the error
//! happened during any phase that translates or modifies the stored code
//! (for example relocation done by `Assembler` or analysis/translation
//! done by `Compiler`) the execution can't continue and the error will
//! be also stored in `Assembler` or `Compiler`.
//!
//! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible handling by returning from your
//! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution, but `false` sets the error immediately to the
//! `Assembler` or `Compiler` and execution shouldn't continue (this is the
//! default behavior in case no error handler is used).
virtual bool handleError(Error code, const char* message, void* origin) = 0;
};
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
//! Interface to implement an external code generator (i.e. `Compiler`).
struct ASMJIT_VIRTAPI CodeGen {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API CodeGen();
ASMJIT_API virtual ~CodeGen();
// --------------------------------------------------------------------------
// [Attach / Reset]
// --------------------------------------------------------------------------
//! \internal
//!
//! Called to attach this code generator to the `assembler`.
virtual Error attach(Assembler* assembler) = 0;
//! Reset the code-generator (also detaches if attached).
virtual void reset(bool releaseMemory) = 0;
// --------------------------------------------------------------------------
// [Finalize]
// --------------------------------------------------------------------------
//! Finalize the code-generation.
//!
//! The finalization has two passes:
//! - serializes code to the attached assembler.
//! - resets the `CodeGen` (detaching from the `Assembler as well) so it can
//! be reused or destroyed.
virtual Error finalize() = 0;
// --------------------------------------------------------------------------
// [Runtime / Assembler]
// --------------------------------------------------------------------------
//! Get the `Runtime` instance that is associated with the code-generator.
ASMJIT_INLINE Runtime* getRuntime() const { return _runtime; }
//! Get the `Assembler` instance that is associated with the code-generator.
ASMJIT_INLINE Assembler* getAssembler() const { return _assembler; }
// --------------------------------------------------------------------------
// [Architecture]
// --------------------------------------------------------------------------
//! Get the target architecture.
ASMJIT_INLINE uint32_t getArch() const { return _arch; }
//! Get the default register size - 4 or 8 bytes, depends on the target.
ASMJIT_INLINE uint32_t getRegSize() const { return _regSize; }
// --------------------------------------------------------------------------
// [Error Handling]
// --------------------------------------------------------------------------
//! Get the last error code.
ASMJIT_INLINE Error getLastError() const { return _lastError; }
//! Set the last error code and propagate it through the error handler.
ASMJIT_API Error setLastError(Error error, const char* message = NULL);
//! Clear the last error code.
ASMJIT_INLINE void resetLastError() { _lastError = kErrorOk; }
// --------------------------------------------------------------------------
// [CodeGen]
// --------------------------------------------------------------------------
//! Get the code-generator ID, provided by `Assembler` when attached to it.
ASMJIT_INLINE uint64_t getHLId() const { return _hlId; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Associated runtime.
Runtime* _runtime;
//! Associated assembler.
Assembler* _assembler;
//! High-level ID, provided by `Assembler`.
//!
//! If multiple high-evel code generators are associated with a single
//! assembler the `_hlId` member can be used to distinguish between them and
//! to provide a mechanism to check whether the high-level code generator is
//! accessing the resource it really owns.
uint64_t _hlId;
//! Target architecture ID.
uint8_t _arch;
//! Target architecture GP register size in bytes (4 or 8).
uint8_t _regSize;
//! The code generator has been finalized.
uint8_t _finalized;
//! \internal
uint8_t _reserved;
//! Last error code.
uint32_t _lastError;
};
// ============================================================================ // ============================================================================
// [asmjit::Assembler] // [asmjit::Assembler]
// ============================================================================ // ============================================================================
//! Base assembler. //! Base assembler.
//! //!
//! This class implements the base interface to an assembler. The architecture //! This class implements the base interface that is used by architecture
//! specific API is implemented by backends. //! specific assemblers.
//! //!
//! \sa Compiler. //! \sa Compiler.
struct ASMJIT_VCLASS Assembler : public CodeGen { struct ASMJIT_VIRTAPI Assembler {
ASMJIT_NO_COPY(Assembler) ASMJIT_NO_COPY(Assembler)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -167,35 +438,160 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_API void reset(bool releaseMemory = false); ASMJIT_API void reset(bool releaseMemory = false);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Buffer] // [Runtime]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get capacity of the code buffer. //! Get the runtime associated with the assembler.
ASMJIT_INLINE size_t getCapacity() const { //!
return (size_t)(_end - _buffer); //! NOTE: Runtime is persistent across `reset()` calls.
ASMJIT_INLINE Runtime* getRuntime() const { return _runtime; }
// --------------------------------------------------------------------------
// [Architecture]
// --------------------------------------------------------------------------
//! Get the target architecture.
ASMJIT_INLINE uint32_t getArch() const { return _arch; }
//! Get the default register size - 4 or 8 bytes, depends on the target.
ASMJIT_INLINE uint32_t getRegSize() const { return _regSize; }
// --------------------------------------------------------------------------
// [Logging]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Get whether the assembler has a logger.
ASMJIT_INLINE bool hasLogger() const { return _logger != NULL; }
//! Get the logger.
ASMJIT_INLINE Logger* getLogger() const { return _logger; }
//! Set the logger to `logger`.
ASMJIT_INLINE void setLogger(Logger* logger) { _logger = logger; }
#endif // !ASMJIT_DISABLE_LOGGER
// --------------------------------------------------------------------------
// [Error Handling]
// --------------------------------------------------------------------------
//! Get the error handler.
ASMJIT_INLINE ErrorHandler* getErrorHandler() const { return _errorHandler; }
//! Set the error handler.
ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
//! Clear the error handler.
ASMJIT_INLINE Error resetErrorHandler() { return setErrorHandler(NULL); }
//! Get the last error code.
ASMJIT_INLINE Error getLastError() const { return _lastError; }
//! Set the last error code and propagate it through the error handler.
ASMJIT_API Error setLastError(Error error, const char* message = NULL);
//! Clear the last error code.
ASMJIT_INLINE void resetLastError() { _lastError = kErrorOk; }
// --------------------------------------------------------------------------
// [External CodeGen]
// --------------------------------------------------------------------------
//! \internal
//!
//! Called after the code generator `cg` has been attached to the assembler.
ASMJIT_INLINE void _attached(CodeGen* cg) {
cg->_runtime = getRuntime();
cg->_assembler = this;
cg->_hlId = _nextExternalId();
_hlAttachedCount++;
} }
//! Get the number of remaining bytes (space between cursor and the end of //! \internal
//! the buffer). //!
ASMJIT_INLINE size_t getRemainingSpace() const { //! Called after the code generator `cg` has been detached from the assembler.
return (size_t)(_end - _cursor); ASMJIT_INLINE void _detached(CodeGen* cg) {
cg->_runtime = NULL;
cg->_assembler = NULL;
cg->_hlId = 0;
_hlAttachedCount--;
} }
//! Get buffer. //! \internal
ASMJIT_INLINE uint8_t* getBuffer() const { //!
return _buffer; //! Return a new code-gen ID (always greater than zero).
ASMJIT_INLINE uint64_t _nextExternalId() {
ASMJIT_ASSERT(_hlIdGenerator != ASMJIT_UINT64_C(0xFFFFFFFFFFFFFFFF));
return ++_hlIdGenerator;
} }
//! Get the end of the buffer (points to the first byte that is outside). // --------------------------------------------------------------------------
ASMJIT_INLINE uint8_t* getEnd() const { // [Assembler Features]
return _end; // --------------------------------------------------------------------------
//! Get code-generator features.
ASMJIT_INLINE uint32_t getFeatures() const { return _features; }
//! Set code-generator features.
ASMJIT_INLINE void setFeatures(uint32_t features) { _features = features; }
//! Get code-generator `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
ASMJIT_ASSERT(feature < 32);
return (_features & (1 << feature)) != 0;
} }
//! Get the current position in the buffer. //! Set code-generator `feature` to `value`.
ASMJIT_INLINE uint8_t* getCursor() const { ASMJIT_INLINE void setFeature(uint32_t feature, bool value) {
return _cursor; ASMJIT_ASSERT(feature < 32);
feature = static_cast<uint32_t>(value) << feature;
_features = (_features & ~feature) | feature;
} }
// --------------------------------------------------------------------------
// [Instruction Options]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getInstOptions() const { return _instOptions; }
//! Set options of the next instruction.
ASMJIT_INLINE void setInstOptions(uint32_t instOptions) { _instOptions = instOptions; }
//! Get options of the next instruction and reset them.
ASMJIT_INLINE uint32_t getInstOptionsAndReset() {
uint32_t instOptions = _instOptions;
_instOptions = 0;
return instOptions;
};
// --------------------------------------------------------------------------
// [Code-Buffer]
// --------------------------------------------------------------------------
//! Grow the code-buffer.
//!
//! The internal code-buffer will grow at least by `n` bytes so `n` bytes can
//! be added to it. If `n` is zero or `getOffset() + n` is not greater than
//! the current capacity of the code-buffer this function does nothing.
ASMJIT_API Error _grow(size_t n);
//! Reserve the code-buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Get capacity of the code-buffer.
ASMJIT_INLINE size_t getCapacity() const { return (size_t)(_end - _buffer); }
//! Get the number of remaining bytes in code-buffer.
ASMJIT_INLINE size_t getRemainingSpace() const { return (size_t)(_end - _cursor); }
//! Get current offset in buffer, same as `getOffset() + getTramplineSize()`.
ASMJIT_INLINE size_t getCodeSize() const { return getOffset() + getTrampolinesSize(); }
//! Get size of all possible trampolines.
//!
//! Trampolines are needed to successfuly generate relative jumps to absolute
//! addresses. This value is only non-zero if jmp of call instructions were
//! used with immediate operand (this means jumping or calling an absolute
//! address directly).
ASMJIT_INLINE size_t getTrampolinesSize() const { return _trampolinesSize; }
//! Get code-buffer.
ASMJIT_INLINE uint8_t* getBuffer() const { return _buffer; }
//! Get the end of the code-buffer (points to the first byte that is invalid).
ASMJIT_INLINE uint8_t* getEnd() const { return _end; }
//! Get the current position in the code-buffer.
ASMJIT_INLINE uint8_t* getCursor() const { return _cursor; }
//! Set the current position in the buffer. //! Set the current position in the buffer.
ASMJIT_INLINE void setCursor(uint8_t* cursor) { ASMJIT_INLINE void setCursor(uint8_t* cursor) {
ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end); ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
@@ -203,12 +599,8 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
} }
//! Get the current offset in the buffer. //! Get the current offset in the buffer.
ASMJIT_INLINE size_t getOffset() const { ASMJIT_INLINE size_t getOffset() const { return (size_t)(_cursor - _buffer); }
return (size_t)(_cursor - _buffer); //! Set the current offset in the buffer to `offset` and return the previous value.
}
//! Set the current offset in the buffer to `offset` and get the previous
//! offset value.
ASMJIT_INLINE size_t setOffset(size_t offset) { ASMJIT_INLINE size_t setOffset(size_t offset) {
ASMJIT_ASSERT(offset < getCapacity()); ASMJIT_ASSERT(offset < getCapacity());
@@ -217,16 +609,6 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
return oldOffset; return oldOffset;
} }
//! Grow the internal buffer.
//!
//! The internal buffer will grow at least by `n` bytes so `n` bytes can be
//! added to it. If `n` is zero or `getOffset() + n` is not greater than the
//! current capacity of the buffer this function does nothing.
ASMJIT_API Error _grow(size_t n);
//! Reserve the internal buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Get BYTE at position `pos`. //! Get BYTE at position `pos`.
ASMJIT_INLINE uint8_t getByteAt(size_t pos) const { ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer)); ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
@@ -300,27 +682,21 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [GetCodeSize] // [Embed]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get current offset in buffer, same as `getOffset() + getTramplineSize()`. //! Embed raw data into the code-buffer.
ASMJIT_INLINE size_t getCodeSize() const { ASMJIT_API virtual Error embed(const void* data, uint32_t size);
return getOffset() + getTrampolineSize();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [GetTrampolineSize] // [Align]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get size of all possible trampolines. //! Align target buffer to the `offset` specified.
//! //!
//! Trampolines are needed to successfuly generate relative jumps to absolute //! The sequence that is used to fill the gap between the aligned location
//! addresses. This value is only non-zero if jmp of call instructions were //! and the current depends on `alignMode`, see \ref AlignMode.
//! used with immediate operand (this means jumping or calling an absolute virtual Error align(uint32_t alignMode, uint32_t offset) = 0;
//! address directly).
ASMJIT_INLINE size_t getTrampolineSize() const {
return _trampolineSize;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Label] // [Label]
@@ -331,11 +707,11 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
return _labelList.getLength(); return _labelList.getLength();
} }
//! Get whether the `label` is valid (created by the assembler). //! Get whether the `label` is valid (i.e. registered).
ASMJIT_INLINE bool isLabelValid(const Label& label) const { ASMJIT_INLINE bool isLabelValid(const Label& label) const {
return isLabelValid(label.getId()); return isLabelValid(label.getId());
} }
//! \overload //! Get whether the label `id` is valid (i.e. registered).
ASMJIT_INLINE bool isLabelValid(uint32_t id) const { ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
return static_cast<size_t>(id) < _labelList.getLength(); return static_cast<size_t>(id) < _labelList.getLength();
} }
@@ -353,17 +729,17 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_INLINE bool isLabelBound(uint32_t id) const { ASMJIT_INLINE bool isLabelBound(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id)); ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset != -1; return _labelList[id]->offset != -1;
} }
//! Get `label` offset or -1 if the label is not yet bound. //! Get a `label` offset or -1 if the label is not yet bound.
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const { ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
return getLabelOffset(label.getId()); return getLabelOffset(label.getId());
} }
//! \overload //! \overload
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const { ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id)); ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset; return _labelList[id]->offset;
} }
//! Get `LabelData` by `label`. //! Get `LabelData` by `label`.
@@ -373,18 +749,13 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
//! \overload //! \overload
ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const { ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id)); ASMJIT_ASSERT(isLabelValid(id));
return const_cast<LabelData*>(&_labelList[id]); return const_cast<LabelData*>(_labelList[id]);
} }
//! \internal //! \internal
//! //!
//! Register labels for other code generator, i.e. `Compiler`. //! Create a new label and return its ID.
ASMJIT_API Error _registerIndexedLabels(size_t index); ASMJIT_API uint32_t _newLabelId();
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
//! \internal //! \internal
//! //!
@@ -392,48 +763,26 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_API LabelLink* _newLabelLink(); ASMJIT_API LabelLink* _newLabelLink();
//! Create and return a new `Label`. //! Create and return a new `Label`.
ASMJIT_INLINE Label newLabel() { ASMJIT_INLINE Label newLabel() { return Label(_newLabelId()); }
Label result(NoInit);
_newLabel(&result);
return result;
}
//! Bind label to the current offset. //! Bind the `label` to the current offset.
//! //!
//! \note Label can be bound only once! //! \note Label can be bound only once!
ASMJIT_API virtual Error bind(const Label& label); ASMJIT_API virtual Error bind(const Label& label);
// --------------------------------------------------------------------------
// [Embed]
// --------------------------------------------------------------------------
//! Embed data into the code buffer.
ASMJIT_API virtual Error embed(const void* data, uint32_t size);
// --------------------------------------------------------------------------
// [Align]
// --------------------------------------------------------------------------
//! Align target buffer to `m` bytes.
//!
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
virtual Error align(uint32_t mode, uint32_t offset) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reloc] // [Reloc]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Relocate the code to `baseAddress` and copy to `dst`. //! Relocate the code to `baseAddress` and copy it to `dst`.
//! //!
//! \param dst Contains the location where the relocated code should be //! \param dst Contains the location where the relocated code should be
//! copied. The pointer can be address returned by virtual memory allocator //! copied. The pointer can be address returned by virtual memory allocator
//! or any other address that has sufficient space. //! or any other address that has sufficient space.
//! //!
//! \param base Base address used for relocation. The `JitRuntime` always //! \param baseAddress Base address used for relocation. The `JitRuntime`
//! sets the `base` address to be the same as `dst`, but other runtimes, for //! always sets the `baseAddress` address to be the same as `dst`, but other
//! example `StaticRuntime`, do not have to follow this rule. //! runtimes, for example `StaticRuntime`, do not have to follow this rule.
//! //!
//! \retval The number bytes actually used. If the code generator reserved //! \retval The number bytes actually used. If the code generator reserved
//! space for possible trampolines, but didn't use it, the number of bytes //! space for possible trampolines, but didn't use it, the number of bytes
@@ -459,6 +808,9 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
// [Emit] // [Emit]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Emit an instruction (virtual).
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
//! Emit an instruction. //! Emit an instruction.
ASMJIT_API Error emit(uint32_t code); ASMJIT_API Error emit(uint32_t code);
//! \overload //! \overload
@@ -468,11 +820,9 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
//! \overload //! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2); ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
//! \overload //! \overload
ASMJIT_INLINE Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) { ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3);
return _emit(code, o0, o1, o2, o3);
}
//! Emit an instruction with integer immediate operand. //! Emit an instruction that has an immediate operand.
ASMJIT_API Error emit(uint32_t code, int o0); ASMJIT_API Error emit(uint32_t code, int o0);
//! \overload //! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1); ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
@@ -490,27 +840,54 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
//! \overload //! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3); ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3);
//! Emit an instruction (virtual).
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Buffer where the code is emitted (either live or temporary). //! Associated runtime.
//! Runtime* _runtime;
//! This is actually the base pointer of the buffer, to get the current
//! position (cursor) look at the `_cursor` member. #if !defined(ASMJIT_DISABLE_LOGGER)
//! Associated logger.
Logger* _logger;
#else
//! Makes libraries built with or without logging support binary compatible.
void* _logger;
#endif // ASMJIT_DISABLE_LOGGER
//! Associated error handler, triggered by \ref setLastError().
ErrorHandler* _errorHandler;
//! Target architecture ID.
uint8_t _arch;
//! Target architecture GP register size in bytes (4 or 8).
uint8_t _regSize;
//! \internal
uint16_t _reserved;
//! Assembler features, used by \ref hasFeature() and \ref setFeature().
uint32_t _features;
//! Options affecting the next instruction.
uint32_t _instOptions;
//! Last error code.
uint32_t _lastError;
//! CodeGen ID generator.
uint64_t _hlIdGenerator;
//! Count of high-level code generators attached.
size_t _hlAttachedCount;
//! General purpose zone allocator.
Zone _zoneAllocator;
//! Start of the code-buffer.
uint8_t* _buffer; uint8_t* _buffer;
//! The end of the buffer (points to the first invalid byte). //! End of the code-buffer (points to the first invalid byte).
//!
//! The end of the buffer is calculated as <code>_buffer + size</code>.
uint8_t* _end; uint8_t* _end;
//! The current position in code `_buffer`. //! The current position in code `_buffer`.
uint8_t* _cursor; uint8_t* _cursor;
//! Size of possible trampolines. //! Size of all possible trampolines.
uint32_t _trampolineSize; uint32_t _trampolinesSize;
//! Inline comment that will be logged by the next instruction and set to NULL. //! Inline comment that will be logged by the next instruction and set to NULL.
const char* _comment; const char* _comment;
@@ -518,7 +895,7 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
LabelLink* _unusedLinks; LabelLink* _unusedLinks;
//! LabelData list. //! LabelData list.
PodVector<LabelData> _labelList; PodVector<LabelData*> _labelList;
//! RelocData list. //! RelocData list.
PodVector<RelocData> _relocList; PodVector<RelocData> _relocList;
}; };
@@ -529,8 +906,10 @@ struct ASMJIT_VCLASS Assembler : public CodeGen {
// [Defined-Later] // [Defined-Later]
// ============================================================================ // ============================================================================
ASMJIT_INLINE Label::Label(Assembler& a) ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
: Operand(NoInit) { a._newLabel(this); } reset();
_label.id = a._newLabelId();
}
} // asmjit namespace } // asmjit namespace

View File

@@ -1,111 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/codegen.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeGen - Construction / Destruction]
// ============================================================================
CodeGen::CodeGen(Runtime* runtime) :
_runtime(runtime),
_logger(NULL),
_errorHandler(NULL),
_baseAddress(runtime->getBaseAddress()),
_arch(kArchNone),
_regSize(0),
_reserved(0),
_features(IntUtil::mask(kCodeGenOptimizedAlign)),
_instOptions(0),
_error(kErrorOk),
_baseZone(16384 - kZoneOverhead) {}
CodeGen::~CodeGen() {
if (_errorHandler != NULL)
_errorHandler->release();
}
// ============================================================================
// [asmjit::CodeGen - Logging]
// ============================================================================
#if !defined(ASMJIT_DISABLE_LOGGER)
Error CodeGen::setLogger(Logger* logger) {
_logger = logger;
return kErrorOk;
}
#endif // !ASMJIT_DISABLE_LOGGER
// ============================================================================
// [asmjit::CodeGen - Error]
// ============================================================================
Error CodeGen::setError(Error error, const char* message) {
if (error == kErrorOk) {
_error = kErrorOk;
return kErrorOk;
}
if (message == NULL) {
#if !defined(ASMJIT_DISABLE_NAMES)
message = ErrorUtil::asString(error);
#else
static const char noMessage[] = "";
message = noMessage;
#endif // ASMJIT_DISABLE_NAMES
}
// Error handler is called before logger so logging can be skipped if error
// has been handled.
ErrorHandler* handler = _errorHandler;
ASMJIT_TLOG("[ERROR] %s %s\n", message, !handler ? "(Possibly unhandled?)" : "");
if (handler != NULL && handler->handleError(error, message))
return error;
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = _logger;
if (logger != NULL) {
logger->logFormat(kLoggerStyleComment,
"*** ERROR: %s (%u).\n", message, static_cast<unsigned int>(error));
}
#endif // !ASMJIT_DISABLE_LOGGER
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of setError(). This is the reason why we have
// delayed changing the _error member until now.
_error = error;
return error;
}
Error CodeGen::setErrorHandler(ErrorHandler* handler) {
ErrorHandler* oldHandler = _errorHandler;
if (oldHandler != NULL)
oldHandler->release();
if (handler != NULL)
handler = handler->addRef();
_errorHandler = handler;
return kErrorOk;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,337 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEGEN_H
#define _ASMJIT_BASE_CODEGEN_H
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/runtime.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::CodeGenFeatures]
// ============================================================================
//! Features of \ref CodeGen.
ASMJIT_ENUM(CodeGenFeatures) {
//! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
//!
//! Default `true`.
//!
//! X86/X64
//! -------
//!
//! Default align sequence used by X86/X64 architecture is one-byte 0x90
//! opcode that is mostly shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled asmjit will generate specialized sequences
//! for alignment between 1 to 11 bytes. Also when `X86Compiler` is used,
//! it can add REX prefixes into the code to make some instructions greater
//! so no alignment sequence is needed.
kCodeGenOptimizedAlign = 0,
//! Emit jump-prediction hints (`Assembler` and `Compiler`).
//!
//! Default `false`.
//!
//! X86/X64
//! -------
//!
//! 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 that ignores any static hints.
kCodeGenPredictedJumps = 1,
//! Schedule instructions so they can be executed faster (`Compiler` only).
//!
//! Default `false` - has to be explicitly enabled as the scheduler needs
//! some time to run.
//!
//! X86/X64
//! -------
//!
//! If scheduling is enabled AsmJit will try to reorder instructions to
//! minimize dependency chain. Scheduler always runs after the registers are
//! allocated so it doesn't change count of register allocs/spills.
//!
//! This feature is highly experimental and untested.
kCodeGenEnableScheduler = 2
};
// ============================================================================
// [asmjit::AlignMode]
// ============================================================================
//! Code aligning mode.
ASMJIT_ENUM(AlignMode) {
//! Align by emitting a sequence that can be executed (code).
kAlignCode = 0,
//! Align by emitting sequence that shouldn't be executed (data).
kAlignData = 1
};
// ============================================================================
// [asmjit::RelocMode]
// ============================================================================
//! Relocation mode.
ASMJIT_ENUM(RelocMode) {
//! Relocate an absolute address to an absolute address.
kRelocAbsToAbs = 0,
//! Relocate a relative address to an absolute address.
kRelocRelToAbs = 1,
//! Relocate an absolute address to a relative address.
kRelocAbsToRel = 2,
//! Relocate an absolute address to a relative address or use trampoline.
kRelocTrampoline = 3
};
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
//! Abstract class defining basics of \ref Assembler and \ref Compiler.
struct ASMJIT_VCLASS CodeGen {
ASMJIT_NO_COPY(CodeGen)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeGen` instance.
ASMJIT_API CodeGen(Runtime* runtime);
//! Destroy the `CodeGen` instance.
ASMJIT_API virtual ~CodeGen();
// --------------------------------------------------------------------------
// [Runtime]
// --------------------------------------------------------------------------
//! Get runtime.
ASMJIT_INLINE Runtime* getRuntime() const {
return _runtime;
}
// --------------------------------------------------------------------------
// [Logger]
// --------------------------------------------------------------------------
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Get whether the code generator has a logger.
ASMJIT_INLINE bool hasLogger() const {
return _logger != NULL;
}
//! Get logger.
ASMJIT_INLINE Logger* getLogger() const {
return _logger;
}
//! Set logger to `logger`.
ASMJIT_API Error setLogger(Logger* logger);
#endif // !ASMJIT_DISABLE_LOGGER
// --------------------------------------------------------------------------
// [Arch]
// --------------------------------------------------------------------------
//! Get target architecture.
ASMJIT_INLINE uint32_t getArch() const {
return _arch;
}
//! Get default register size (4 or 8 bytes).
ASMJIT_INLINE uint32_t getRegSize() const {
return _regSize;
}
// --------------------------------------------------------------------------
// [BaseAddress]
// --------------------------------------------------------------------------
//! Get whether the code-generator has a base address.
//!
//! \sa \ref getBaseAddress()
ASMJIT_INLINE bool hasBaseAddress() const {
return _baseAddress != kNoBaseAddress;
}
//! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const {
return _baseAddress;
}
//! Set the base address to `baseAddress`.
ASMJIT_INLINE void setBaseAddress(Ptr baseAddress) {
_baseAddress = baseAddress;
}
//! Reset the base address.
ASMJIT_INLINE void resetBaseAddress() {
setBaseAddress(kNoBaseAddress);
}
// --------------------------------------------------------------------------
// [LastError / ErrorHandler]
// --------------------------------------------------------------------------
//! Get last error code.
ASMJIT_INLINE Error getError() const {
return _error;
}
//! Set last error code and propagate it through the error handler.
ASMJIT_API Error setError(Error error, const char* message = NULL);
//! Clear the last error code.
ASMJIT_INLINE void resetError() {
_error = kErrorOk;
}
//! Get error handler.
ASMJIT_INLINE ErrorHandler* getErrorHandler() const {
return _errorHandler;
}
//! Set error handler.
ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
//! Clear error handler.
ASMJIT_INLINE Error resetErrorHandler() {
return setErrorHandler(NULL);
}
// --------------------------------------------------------------------------
// [Code-Generation Features]
// --------------------------------------------------------------------------
//! Get code-generator `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
ASMJIT_ASSERT(feature < 32);
return (_features & (1 << feature)) != 0;
}
//! Set code-generator `feature` to `value`.
ASMJIT_INLINE void setFeature(uint32_t feature, bool value) {
ASMJIT_ASSERT(feature < 32);
feature = static_cast<uint32_t>(value) << feature;
_features = (_features & ~feature) | feature;
}
//! Get code-generator features.
ASMJIT_INLINE uint32_t getFeatures() const {
return _features;
}
//! Set code-generator features.
ASMJIT_INLINE void setFeatures(uint32_t features) {
_features = features;
}
// --------------------------------------------------------------------------
// [Instruction Options]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getInstOptions() const {
return _instOptions;
}
//! Get options of the next instruction and reset them.
ASMJIT_INLINE uint32_t getInstOptionsAndReset() {
uint32_t instOptions = _instOptions;
_instOptions = 0;
return instOptions;
};
//! Set options of the next instruction.
ASMJIT_INLINE void setInstOptions(uint32_t instOptions) {
_instOptions = instOptions;
}
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
//! Make is a convenience method to make and relocate the current code and
//! add it to the associated `Runtime`.
//!
//! What is needed is only to cast the returned pointer to your function type
//! and then use it. If there was an error during `make()` `NULL` is returned
//! and the last error code can be obtained by calling `getError()`.
virtual void* make() = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Target runtime.
Runtime* _runtime;
#if !defined(ASMJIT_DISABLE_LOGGER)
//! Logger.
Logger* _logger;
#else
//! \internal
//!
//! Makes libraries built with or without logging support binary compatible.
void* _logger;
#endif // ASMJIT_DISABLE_LOGGER
//! Error handler, called by \ref setError().
ErrorHandler* _errorHandler;
//! Base address (-1 if unknown/not used).
Ptr _baseAddress;
//! Target architecture ID.
uint8_t _arch;
//! Target architecture GP register size in bytes (4 or 8).
uint8_t _regSize;
//! \internal
uint16_t _reserved;
//! Code-Generation features, used by \ref hasFeature() and \ref setFeature().
uint32_t _features;
//! Options affecting the next instruction.
uint32_t _instOptions;
//! Last error code.
uint32_t _error;
//! Base zone.
Zone _baseZone;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEGEN_H

View File

@@ -14,10 +14,10 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/assembler.h" #include "../base/assembler.h"
#include "../base/compiler.h" #include "../base/compiler.h"
#include "../base/context_p.h" #include "../base/compilercontext_p.h"
#include "../base/cpuinfo.h" #include "../base/cpuinfo.h"
#include "../base/intutil.h"
#include "../base/logger.h" #include "../base/logger.h"
#include "../base/utils.h"
// [Dependencies - C] // [Dependencies - C]
#include <stdarg.h> #include <stdarg.h>
@@ -32,55 +32,55 @@ namespace asmjit {
// ============================================================================ // ============================================================================
static const char noName[1] = { '\0' }; static const char noName[1] = { '\0' };
enum { kBaseCompilerDefaultLookAhead = 64 }; enum { kCompilerDefaultLookAhead = 64 };
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Construction / Destruction] // [asmjit::Compiler - Construction / Destruction]
// ============================================================================ // ============================================================================
Compiler::Compiler(Runtime* runtime) : Compiler::Compiler() :
CodeGen(runtime), _features(0),
_assembler(NULL), _maxLookAhead(kCompilerDefaultLookAhead),
_instOptions(0),
_tokenGenerator(0),
_nodeFlowId(0), _nodeFlowId(0),
_nodeFlags(0), _nodeFlags(0),
_maxLookAhead(kBaseCompilerDefaultLookAhead),
_targetVarMapping(NULL), _targetVarMapping(NULL),
_firstNode(NULL), _firstNode(NULL),
_lastNode(NULL), _lastNode(NULL),
_cursor(NULL), _cursor(NULL),
_func(NULL), _func(NULL),
_varZone(4096 - kZoneOverhead), _zoneAllocator(8192 - Zone::kZoneOverhead),
_stringZone(4096 - kZoneOverhead), _varAllocator(4096 - Zone::kZoneOverhead),
_localConstZone(4096 - kZoneOverhead), _stringAllocator(4096 - Zone::kZoneOverhead),
_localConstPool(&_localConstZone), _constAllocator(4096 - Zone::kZoneOverhead),
_globalConstPool(&_baseZone) {} _localConstPool(&_constAllocator),
_globalConstPool(&_zoneAllocator) {}
Compiler::~Compiler() { Compiler::~Compiler() {}
reset(true);
if (_assembler != NULL)
delete _assembler;
}
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Clear / Reset] // [asmjit::Compiler - Attach / Reset]
// ============================================================================ // ============================================================================
void Compiler::reset(bool releaseMemory) { void Compiler::reset(bool releaseMemory) {
// CodeGen members. Assembler* assembler = getAssembler();
_baseAddress = kNoBaseAddress; if (assembler != NULL)
assembler->_detached(this);
_arch = kArchNone;
_regSize = 0;
_finalized = false;
_lastError = kErrorNotInitialized;
_features = 0;
_maxLookAhead = kCompilerDefaultLookAhead;
_instOptions = 0; _instOptions = 0;
_error = kErrorOk; _tokenGenerator = 0;
_baseZone.reset(releaseMemory);
// Compiler members.
_nodeFlowId = 0; _nodeFlowId = 0;
_nodeFlags = 0; _nodeFlags = 0;
if (_assembler != NULL)
_assembler->reset(releaseMemory);
_firstNode = NULL; _firstNode = NULL;
_lastNode = NULL; _lastNode = NULL;
@@ -93,25 +93,79 @@ void Compiler::reset(bool releaseMemory) {
_localConstPoolLabel.reset(); _localConstPoolLabel.reset();
_globalConstPoolLabel.reset(); _globalConstPoolLabel.reset();
_varZone.reset(releaseMemory); _zoneAllocator.reset(releaseMemory);
_stringZone.reset(releaseMemory); _varAllocator.reset(releaseMemory);
_localConstZone.reset(releaseMemory); _stringAllocator.reset(releaseMemory);
_constAllocator.reset(releaseMemory);
_targetList.reset(releaseMemory);
_varList.reset(releaseMemory); _varList.reset(releaseMemory);
} }
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Node Management] // [asmjit::Compiler - Node-Factory]
// ============================================================================ // ============================================================================
Node* Compiler::setCursor(Node* node) { HLData* Compiler::newDataNode(const void* data, uint32_t size) {
Node* old = _cursor; if (size > HLData::kInlineBufferSize) {
_cursor = node; void* clonedData = _stringAllocator.alloc(size);
return old; if (clonedData == NULL)
return NULL;
if (data != NULL)
::memcpy(clonedData, data, size);
data = clonedData;
} }
Node* Compiler::addNode(Node* node) { return newNode<HLData>(const_cast<void*>(data), size);
}
HLAlign* Compiler::newAlignNode(uint32_t alignMode, uint32_t offset) {
return newNode<HLAlign>(alignMode, offset);
}
HLLabel* Compiler::newLabelNode() {
Assembler* assembler = getAssembler();
if (assembler == NULL) return NULL;
uint32_t id = assembler->_newLabelId();
LabelData* ld = assembler->getLabelData(id);
HLLabel* node = newNode<HLLabel>(id);
if (node == NULL) return NULL;
// These have to be zero now.
ASMJIT_ASSERT(ld->hlId == 0);
ASMJIT_ASSERT(ld->hlData == NULL);
ld->hlId = _hlId;
ld->hlData = node;
return node;
}
HLComment* Compiler::newCommentNode(const char* str) {
if (str != NULL && str[0]) {
str = _stringAllocator.sdup(str);
if (str == NULL)
return NULL;
}
return newNode<HLComment>(str);
}
HLHint* Compiler::newHintNode(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue)
return NULL;
VarData* vd = getVd(var);
return newNode<HLHint>(vd, hint, value);
}
// ============================================================================
// [asmjit::Compiler - Code-Stream]
// ============================================================================
HLNode* Compiler::addNode(HLNode* node) {
ASMJIT_ASSERT(node != NULL); ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL); ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL); ASMJIT_ASSERT(node->_next == NULL);
@@ -128,8 +182,8 @@ Node* Compiler::addNode(Node* node) {
} }
} }
else { else {
Node* prev = _cursor; HLNode* prev = _cursor;
Node* next = _cursor->_next; HLNode* next = _cursor->_next;
node->_prev = prev; node->_prev = prev;
node->_next = next; node->_next = next;
@@ -145,14 +199,14 @@ Node* Compiler::addNode(Node* node) {
return node; return node;
} }
Node* Compiler::addNodeBefore(Node* node, Node* ref) { HLNode* Compiler::addNodeBefore(HLNode* node, HLNode* ref) {
ASMJIT_ASSERT(node != NULL); ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL); ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL); ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL); ASMJIT_ASSERT(ref != NULL);
Node* prev = ref->_prev; HLNode* prev = ref->_prev;
Node* next = ref; HLNode* next = ref;
node->_prev = prev; node->_prev = prev;
node->_next = next; node->_next = next;
@@ -166,14 +220,14 @@ Node* Compiler::addNodeBefore(Node* node, Node* ref) {
return node; return node;
} }
Node* Compiler::addNodeAfter(Node* node, Node* ref) { HLNode* Compiler::addNodeAfter(HLNode* node, HLNode* ref) {
ASMJIT_ASSERT(node != NULL); ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL); ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL); ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL); ASMJIT_ASSERT(ref != NULL);
Node* prev = ref; HLNode* prev = ref;
Node* next = ref->_next; HLNode* next = ref->_next;
node->_prev = prev; node->_prev = prev;
node->_next = next; node->_next = next;
@@ -187,17 +241,17 @@ Node* Compiler::addNodeAfter(Node* node, Node* ref) {
return node; return node;
} }
static ASMJIT_INLINE void BaseCompiler_nodeRemoved(Compiler* self, Node* node_) { static ASMJIT_INLINE void Compiler_nodeRemoved(Compiler* self, HLNode* node_) {
if (node_->isJmpOrJcc()) { if (node_->isJmpOrJcc()) {
JumpNode* node = static_cast<JumpNode*>(node_); HLJump* node = static_cast<HLJump*>(node_);
TargetNode* target = node->getTarget(); HLLabel* label = node->getTarget();
if (target != NULL) { if (label != NULL) {
// Disconnect. // Disconnect.
JumpNode** pPrev = &target->_from; HLJump** pPrev = &label->_from;
for (;;) { for (;;) {
ASMJIT_ASSERT(*pPrev != NULL); ASMJIT_ASSERT(*pPrev != NULL);
JumpNode* current = *pPrev; HLJump* current = *pPrev;
if (current == NULL) if (current == NULL)
break; break;
@@ -210,14 +264,14 @@ static ASMJIT_INLINE void BaseCompiler_nodeRemoved(Compiler* self, Node* node_)
pPrev = &current->_jumpNext; pPrev = &current->_jumpNext;
} }
target->subNumRefs(); label->subNumRefs();
} }
} }
} }
Node* Compiler::removeNode(Node* node) { HLNode* Compiler::removeNode(HLNode* node) {
Node* prev = node->_prev; HLNode* prev = node->_prev;
Node* next = node->_next; HLNode* next = node->_next;
if (_firstNode == node) if (_firstNode == node)
_firstNode = next; _firstNode = next;
@@ -234,19 +288,19 @@ Node* Compiler::removeNode(Node* node) {
if (_cursor == node) if (_cursor == node)
_cursor = prev; _cursor = prev;
BaseCompiler_nodeRemoved(this, node); Compiler_nodeRemoved(this, node);
return node; return node;
} }
void Compiler::removeNodes(Node* first, Node* last) { void Compiler::removeNodes(HLNode* first, HLNode* last) {
if (first == last) { if (first == last) {
removeNode(first); removeNode(first);
return; return;
} }
Node* prev = first->_prev; HLNode* prev = first->_prev;
Node* next = last->_next; HLNode* next = last->_next;
if (_firstNode == first) if (_firstNode == first)
_firstNode = next; _firstNode = next;
@@ -258,9 +312,9 @@ void Compiler::removeNodes(Node* first, Node* last) {
else else
next->_prev = prev; next->_prev = prev;
Node* node = first; HLNode* node = first;
for (;;) { for (;;) {
Node* next = node->getNext(); HLNode* next = node->getNext();
ASMJIT_ASSERT(next != NULL); ASMJIT_ASSERT(next != NULL);
node->_prev = NULL; node->_prev = NULL;
@@ -268,7 +322,7 @@ void Compiler::removeNodes(Node* first, Node* last) {
if (_cursor == node) if (_cursor == node)
_cursor = prev; _cursor = prev;
BaseCompiler_nodeRemoved(this, node); Compiler_nodeRemoved(this, node);
if (node == last) if (node == last)
break; break;
@@ -276,76 +330,62 @@ void Compiler::removeNodes(Node* first, Node* last) {
} }
} }
HLNode* Compiler::setCursor(HLNode* node) {
HLNode* old = _cursor;
_cursor = node;
return old;
}
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Align] // [asmjit::Compiler - Align]
// ============================================================================ // ============================================================================
AlignNode* Compiler::newAlign(uint32_t mode, uint32_t offset) { Error Compiler::align(uint32_t alignMode, uint32_t offset) {
AlignNode* node = newNode<AlignNode>(mode, offset); HLAlign* node = newAlignNode(alignMode, offset);
if (node == NULL) if (node == NULL)
goto _NoMemory; return setLastError(kErrorNoHeapMemory);
return node;
_NoMemory: addNode(node);
setError(kErrorNoHeapMemory); return kErrorOk;
return NULL;
}
AlignNode* Compiler::addAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newAlign(mode, offset);
if (node == NULL)
return NULL;
return static_cast<AlignNode*>(addNode(node));
}
// ============================================================================
// [asmjit::Compiler - Target]
// ============================================================================
TargetNode* Compiler::newTarget() {
TargetNode* node = newNode<TargetNode>(
OperandUtil::makeLabelId(static_cast<uint32_t>(_targetList.getLength())));
if (node == NULL || _targetList.append(node) != kErrorOk)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
TargetNode* Compiler::addTarget() {
TargetNode* node = newTarget();
if (node == NULL)
return NULL;
return static_cast<TargetNode*>(addNode(node));
} }
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Label] // [asmjit::Compiler - Label]
// ============================================================================ // ============================================================================
Error Compiler::_newLabel(Label* dst) { HLLabel* Compiler::getHLLabel(uint32_t id) const {
dst->_init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue); Assembler* assembler = getAssembler();
dst->_init_packed_d2_d3(0, 0); if (assembler == NULL) return NULL;
TargetNode* node = newTarget(); LabelData* ld = assembler->getLabelData(id);
if (node == NULL) if (ld->hlId == _hlId)
goto _NoMemory; return static_cast<HLLabel*>(ld->hlData);
else
return NULL;
}
dst->_label.id = node->getLabelId(); bool Compiler::isLabelValid(uint32_t id) const {
return kErrorOk; Assembler* assembler = getAssembler();
if (assembler == NULL) return false;
_NoMemory: return static_cast<size_t>(id) < assembler->getLabelsCount();
return setError(kErrorNoHeapMemory); }
uint32_t Compiler::_newLabelId() {
HLLabel* node = newLabelNode();
if (node == NULL) {
setLastError(kErrorNoHeapMemory);
return kInvalidValue;
}
return node->getLabelId();
} }
Error Compiler::bind(const Label& label) { Error Compiler::bind(const Label& label) {
uint32_t index = label.getId(); HLLabel* node = getHLLabel(label);
ASMJIT_ASSERT(index < _targetList.getLength()); if (node == NULL)
return setLastError(kErrorInvalidState);
addNode(_targetList[index]); addNode(node);
return kErrorOk; return kErrorOk;
} }
@@ -353,67 +393,37 @@ Error Compiler::bind(const Label& label) {
// [asmjit::Compiler - Embed] // [asmjit::Compiler - Embed]
// ============================================================================ // ============================================================================
EmbedNode* Compiler::newEmbed(const void* data, uint32_t size) { Error Compiler::embed(const void* data, uint32_t size) {
EmbedNode* node; HLData* node = newDataNode(data, size);
if (node == NULL)
return setLastError(kErrorNoHeapMemory);
if (size > EmbedNode::kInlineBufferSize) { addNode(node);
void* clonedData = _stringZone.alloc(size); return kErrorOk;
if (clonedData == NULL)
goto _NoMemory;
if (data != NULL)
::memcpy(clonedData, data, size);
data = clonedData;
} }
node = newNode<EmbedNode>(const_cast<void*>(data), size); Error Compiler::embedConstPool(const Label& label, const ConstPool& pool) {
if (node == NULL) if (label.getId() == kInvalidValue)
goto _NoMemory; return kErrorInvalidState;
return node;
_NoMemory: align(kAlignData, static_cast<uint32_t>(pool.getAlignment()));
setError(kErrorNoHeapMemory); bind(label);
return NULL;
}
EmbedNode* Compiler::addEmbed(const void* data, uint32_t size) { HLData* embedNode = newDataNode(NULL, static_cast<uint32_t>(pool.getSize()));
EmbedNode* node = newEmbed(data, size); if (embedNode == NULL)
if (node == NULL) return kErrorNoHeapMemory;
return node;
return static_cast<EmbedNode*>(addNode(node)); pool.fill(embedNode->getData());
addNode(embedNode);
return kErrorOk;
} }
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Comment] // [asmjit::Compiler - Comment]
// ============================================================================ // ============================================================================
CommentNode* Compiler::newComment(const char* str) { Error Compiler::comment(const char* fmt, ...) {
CommentNode* node;
if (str != NULL && str[0]) {
str = _stringZone.sdup(str);
if (str == NULL)
goto _NoMemory;
}
node = newNode<CommentNode>(str);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
CommentNode* Compiler::addComment(const char* str) {
CommentNode* node = newComment(str);
if (node == NULL)
return NULL;
return static_cast<CommentNode*>(addNode(node));
}
CommentNode* Compiler::comment(const char* fmt, ...) {
char buf[256]; char buf[256];
char* p = buf; char* p = buf;
@@ -425,36 +435,29 @@ CommentNode* Compiler::comment(const char* fmt, ...) {
} }
p[0] = '\0'; p[0] = '\0';
return addComment(buf);
HLComment* node = newCommentNode(buf);
if (node == NULL)
return setLastError(kErrorNoHeapMemory);
addNode(node);
return kErrorOk;
} }
// ============================================================================ // ============================================================================
// [asmjit::Compiler - Hint] // [asmjit::Compiler - Hint]
// ============================================================================ // ============================================================================
HintNode* Compiler::newHint(Var& var, uint32_t hint, uint32_t value) { Error Compiler::_hint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue)
return NULL;
VarData* vd = getVd(var);
HintNode* node = newNode<HintNode>(vd, hint, value);
if (node == NULL)
goto _NoMemory;
return node;
_NoMemory:
setError(kErrorNoHeapMemory);
return NULL;
}
HintNode* Compiler::addHint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return NULL; return NULL;
HintNode* node = newHint(var, hint, value); HLHint* node = newHintNode(var, hint, value);
if (node == NULL) if (node == NULL)
return NULL; return setLastError(kErrorNoHeapMemory);
return static_cast<HintNode*>(addNode(node));
addNode(node);
return kErrorOk;
} }
// ============================================================================ // ============================================================================
@@ -462,17 +465,19 @@ HintNode* Compiler::addHint(Var& var, uint32_t hint, uint32_t value) {
// ============================================================================ // ============================================================================
VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char* name) { VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char* name) {
VarData* vd = reinterpret_cast<VarData*>(_varZone.alloc(sizeof(VarData))); VarData* vd = reinterpret_cast<VarData*>(_varAllocator.alloc(sizeof(VarData)));
if (vd == NULL) if (vd == NULL)
goto _NoMemory; goto _NoMemory;
vd->_name = noName; vd->_name = noName;
vd->_id = OperandUtil::makeVarId(static_cast<uint32_t>(_varList.getLength())); vd->_id = OperandUtil::makeVarId(static_cast<uint32_t>(_varList.getLength()));
vd->_contextId = kInvalidValue; vd->_localId = kInvalidValue;
#if !defined(ASMJIT_DISABLE_LOGGER)
if (name != NULL && name[0] != '\0') { if (name != NULL && name[0] != '\0') {
vd->_name = _stringZone.sdup(name); vd->_name = _stringAllocator.sdup(name);
} }
#endif // !ASMJIT_DISABLE_LOGGER
vd->_type = static_cast<uint8_t>(type); vd->_type = static_cast<uint8_t>(type);
vd->_class = static_cast<uint8_t>(c); vd->_class = static_cast<uint8_t>(c);
@@ -487,7 +492,7 @@ VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char*
vd->_saveOnUnuse = false; vd->_saveOnUnuse = false;
vd->_modified = false; vd->_modified = false;
vd->_reserved0 = 0; vd->_reserved0 = 0;
vd->_alignment = static_cast<uint8_t>(IntUtil::iMin<uint32_t>(size, 64)); vd->_alignment = static_cast<uint8_t>(Utils::iMin<uint32_t>(size, 64));
vd->_size = size; vd->_size = size;
vd->_homeMask = 0; vd->_homeMask = 0;
@@ -507,44 +512,44 @@ VarData* Compiler::_newVd(uint32_t type, uint32_t size, uint32_t c, const char*
return vd; return vd;
_NoMemory: _NoMemory:
setError(kErrorNoHeapMemory); setLastError(kErrorNoHeapMemory);
return NULL; return NULL;
} }
void Compiler::alloc(Var& var) { Error Compiler::alloc(Var& var) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintAlloc, kInvalidValue); return _hint(var, kVarHintAlloc, kInvalidValue);
} }
void Compiler::alloc(Var& var, uint32_t regIndex) { Error Compiler::alloc(Var& var, uint32_t regIndex) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintAlloc, regIndex); return _hint(var, kVarHintAlloc, regIndex);
} }
void Compiler::alloc(Var& var, const Reg& reg) { Error Compiler::alloc(Var& var, const Reg& reg) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintAlloc, reg.getRegIndex()); return _hint(var, kVarHintAlloc, reg.getRegIndex());
} }
void Compiler::save(Var& var) { Error Compiler::save(Var& var) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintSave, kInvalidValue); return _hint(var, kVarHintSave, kInvalidValue);
} }
void Compiler::spill(Var& var) { Error Compiler::spill(Var& var) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintSpill, kInvalidValue); return _hint(var, kVarHintSpill, kInvalidValue);
} }
void Compiler::unuse(Var& var) { Error Compiler::unuse(Var& var) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return kErrorOk;
addHint(var, kVarHintUnuse, kInvalidValue); return _hint(var, kVarHintUnuse, kInvalidValue);
} }
uint32_t Compiler::getPriority(Var& var) const { uint32_t Compiler::getPriority(Var& var) const {
@@ -582,45 +587,27 @@ void Compiler::setSaveOnUnuse(Var& var, bool value) {
vd->_saveOnUnuse = value; vd->_saveOnUnuse = value;
} }
void Compiler::rename(Var& var, const char* name) { void Compiler::rename(Var& var, const char* fmt, ...) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return;
VarData* vd = getVdById(var.getId()); VarData* vd = getVdById(var.getId());
vd->_name = noName; vd->_name = noName;
if (name != NULL && name[0] != '\0') { if (fmt != NULL && fmt[0] != '\0') {
vd->_name = _stringZone.sdup(name); char buf[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
vd->_name = _stringAllocator.sdup(buf);
va_end(ap);
} }
} }
// ============================================================================
// [asmjit::Compiler - Assembler]
// ============================================================================
Assembler* Compiler::getAssembler() {
Assembler* a = _assembler;
if (a != NULL) {
a->reset(false);
}
else {
a = _newAssembler();
_assembler = a;
}
#if !defined(ASMJIT_DISABLE_LOGGER)
Logger* logger = _logger;
if (logger != NULL)
a->setLogger(logger);
#endif // !ASMJIT_DISABLE_LOGGER
a->setBaseAddress(_baseAddress);
a->setFeatures(_features);
return a;
}
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

File diff suppressed because it is too large Load Diff

View File

@@ -12,8 +12,8 @@
#if !defined(ASMJIT_DISABLE_COMPILER) #if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/context_p.h" #include "../base/compilercontext_p.h"
#include "../base/intutil.h" #include "../base/utils.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -26,7 +26,7 @@ namespace asmjit {
Context::Context(Compiler* compiler) : Context::Context(Compiler* compiler) :
_compiler(compiler), _compiler(compiler),
_baseZone(8192 - kZoneOverhead), _zoneAllocator(8192 - Zone::kZoneOverhead),
_varMapToVaListOffset(0) { _varMapToVaListOffset(0) {
Context::reset(); Context::reset();
@@ -39,7 +39,7 @@ Context::~Context() {}
// ============================================================================ // ============================================================================
void Context::reset(bool releaseMemory) { void Context::reset(bool releaseMemory) {
_baseZone.reset(releaseMemory); _zoneAllocator.reset(releaseMemory);
_func = NULL; _func = NULL;
_start = NULL; _start = NULL;
@@ -94,10 +94,10 @@ static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) {
return 1; return 1;
} }
MemCell* Context::_newVarCell(VarData* vd) { VarCell* Context::_newVarCell(VarData* vd) {
ASMJIT_ASSERT(vd->_memCell == NULL); ASMJIT_ASSERT(vd->_memCell == NULL);
MemCell* cell; VarCell* cell;
uint32_t size = vd->getSize(); uint32_t size = vd->getSize();
if (vd->isStack()) { if (vd->isStack()) {
@@ -107,7 +107,7 @@ MemCell* Context::_newVarCell(VarData* vd) {
return NULL; return NULL;
} }
else { else {
cell = static_cast<MemCell*>(_baseZone.alloc(sizeof(MemCell))); cell = static_cast<VarCell*>(_zoneAllocator.alloc(sizeof(VarCell)));
if (cell == NULL) if (cell == NULL)
goto _NoMemory; goto _NoMemory;
@@ -118,7 +118,7 @@ MemCell* Context::_newVarCell(VarData* vd) {
cell->_size = size; cell->_size = size;
cell->_alignment = size; cell->_alignment = size;
_memMaxAlign = IntUtil::iMax<uint32_t>(_memMaxAlign, size); _memMaxAlign = Utils::iMax<uint32_t>(_memMaxAlign, size);
_memVarTotal += size; _memVarTotal += size;
switch (size) { switch (size) {
@@ -137,12 +137,12 @@ MemCell* Context::_newVarCell(VarData* vd) {
return cell; return cell;
_NoMemory: _NoMemory:
_compiler->setError(kErrorNoHeapMemory); _compiler->setLastError(kErrorNoHeapMemory);
return NULL; return NULL;
} }
MemCell* Context::_newStackCell(uint32_t size, uint32_t alignment) { VarCell* Context::_newStackCell(uint32_t size, uint32_t alignment) {
MemCell* cell = static_cast<MemCell*>(_baseZone.alloc(sizeof(MemCell))); VarCell* cell = static_cast<VarCell*>(_zoneAllocator.alloc(sizeof(VarCell)));
if (cell == NULL) if (cell == NULL)
goto _NoMemory; goto _NoMemory;
@@ -152,13 +152,13 @@ MemCell* Context::_newStackCell(uint32_t size, uint32_t alignment) {
if (alignment > 64) if (alignment > 64)
alignment = 64; alignment = 64;
ASMJIT_ASSERT(IntUtil::isPowerOf2(alignment)); ASMJIT_ASSERT(Utils::isPowerOf2(alignment));
size = IntUtil::alignTo<uint32_t>(size, alignment); size = Utils::alignTo<uint32_t>(size, alignment);
// Insert it sorted according to the alignment and size. // Insert it sorted according to the alignment and size.
{ {
MemCell** pPrev = &_memStackCells; VarCell** pPrev = &_memStackCells;
MemCell* cur = *pPrev; VarCell* cur = *pPrev;
for (cur = *pPrev; cur != NULL; cur = cur->_next) { for (cur = *pPrev; cur != NULL; cur = cur->_next) {
if (cur->getAlignment() > alignment) if (cur->getAlignment() > alignment)
@@ -176,20 +176,20 @@ MemCell* Context::_newStackCell(uint32_t size, uint32_t alignment) {
*pPrev = cell; *pPrev = cell;
_memStackCellsUsed++; _memStackCellsUsed++;
_memMaxAlign = IntUtil::iMax<uint32_t>(_memMaxAlign, alignment); _memMaxAlign = Utils::iMax<uint32_t>(_memMaxAlign, alignment);
_memStackTotal += size; _memStackTotal += size;
} }
return cell; return cell;
_NoMemory: _NoMemory:
_compiler->setError(kErrorNoHeapMemory); _compiler->setLastError(kErrorNoHeapMemory);
return NULL; return NULL;
} }
Error Context::resolveCellOffsets() { Error Context::resolveCellOffsets() {
MemCell* varCell = _memVarCells; VarCell* varCell = _memVarCells;
MemCell* stackCell = _memStackCells; VarCell* stackCell = _memStackCells;
uint32_t stackAlignment = 0; uint32_t stackAlignment = 0;
if (stackCell != NULL) if (stackCell != NULL)
@@ -208,8 +208,9 @@ Error Context::resolveCellOffsets() {
uint32_t gapAlignment = stackAlignment; uint32_t gapAlignment = stackAlignment;
uint32_t gapSize = 0; uint32_t gapSize = 0;
// TODO: Not used!
if (gapAlignment) if (gapAlignment)
IntUtil::deltaTo(stackPos, gapAlignment); Utils::alignDiff(stackPos, gapAlignment);
stackPos += gapSize; stackPos += gapSize;
uint32_t gapPos = stackPos; uint32_t gapPos = stackPos;
@@ -273,14 +274,14 @@ Error Context::resolveCellOffsets() {
Error Context::removeUnreachableCode() { Error Context::removeUnreachableCode() {
Compiler* compiler = getCompiler(); Compiler* compiler = getCompiler();
PodList<Node*>::Link* link = _unreachableList.getFirst(); PodList<HLNode*>::Link* link = _unreachableList.getFirst();
Node* stop = getStop(); HLNode* stop = getStop();
while (link != NULL) { while (link != NULL) {
Node* node = link->getValue(); HLNode* node = link->getValue();
if (node != NULL && node->getPrev() != NULL && node != stop) { if (node != NULL && node->getPrev() != NULL && node != stop) {
// Locate all unreachable nodes. // Locate all unreachable nodes.
Node* first = node; HLNode* first = node;
do { do {
if (node->isFetched()) if (node->isFetched())
break; break;
@@ -289,11 +290,11 @@ Error Context::removeUnreachableCode() {
// Remove unreachable nodes that are neither informative nor directives. // Remove unreachable nodes that are neither informative nor directives.
if (node != first) { if (node != first) {
Node* end = node; HLNode* end = node;
node = first; node = first;
do { do {
Node* next = node->getNext(); HLNode* next = node->getNext();
if (!node->isInformative() && node->getType() != kNodeTypeAlign) { if (!node->isInformative() && node->getType() != kHLNodeTypeAlign) {
ASMJIT_TLOG("[%05d] Unreachable\n", node->getFlowId()); ASMJIT_TLOG("[%05d] Unreachable\n", node->getFlowId());
compiler->removeNode(node); compiler->removeNode(node);
} }
@@ -318,32 +319,32 @@ struct LivenessTarget {
LivenessTarget* prev; LivenessTarget* prev;
//! Target node. //! Target node.
TargetNode* node; HLLabel* node;
//! Jumped from. //! Jumped from.
JumpNode* from; HLJump* from;
}; };
Error Context::livenessAnalysis() { Error Context::livenessAnalysis() {
uint32_t bLen = static_cast<uint32_t>( uint32_t bLen = static_cast<uint32_t>(
((_contextVd.getLength() + VarBits::kEntityBits - 1) / VarBits::kEntityBits)); ((_contextVd.getLength() + BitArray::kEntityBits - 1) / BitArray::kEntityBits));
// No variables. // No variables.
if (bLen == 0) if (bLen == 0)
return kErrorOk; return kErrorOk;
FuncNode* func = getFunc(); HLFunc* func = getFunc();
JumpNode* from = NULL; HLJump* from = NULL;
LivenessTarget* ltCur = NULL; LivenessTarget* ltCur = NULL;
LivenessTarget* ltUnused = NULL; LivenessTarget* ltUnused = NULL;
PodList<Node*>::Link* retPtr = _returningList.getFirst(); PodList<HLNode*>::Link* retPtr = _returningList.getFirst();
ASMJIT_ASSERT(retPtr != NULL); ASMJIT_ASSERT(retPtr != NULL);
Node* node = retPtr->getValue(); HLNode* node = retPtr->getValue();
size_t varMapToVaListOffset = _varMapToVaListOffset; size_t varMapToVaListOffset = _varMapToVaListOffset;
VarBits* bCur = newBits(bLen); BitArray* bCur = newBits(bLen);
if (bCur == NULL) if (bCur == NULL)
goto _NoMemory; goto _NoMemory;
@@ -358,7 +359,7 @@ _OnVisit:
goto _OnDone; goto _OnDone;
} }
VarBits* bTmp = copyBits(bCur, bLen); BitArray* bTmp = copyBits(bCur, bLen);
if (bTmp == NULL) if (bTmp == NULL)
goto _NoMemory; goto _NoMemory;
@@ -374,9 +375,9 @@ _OnVisit:
VarData* vd = va->getVd(); VarData* vd = va->getVd();
uint32_t flags = va->getFlags(); uint32_t flags = va->getFlags();
uint32_t ctxId = vd->getContextId(); uint32_t ctxId = vd->getLocalId();
if ((flags & kVarAttrOutAll) && !(flags & kVarAttrInAll)) { if ((flags & kVarAttrWAll) && !(flags & kVarAttrRAll)) {
// Write-Only. // Write-Only.
bTmp->setBit(ctxId); bTmp->setBit(ctxId);
bCur->delBit(ctxId); bCur->delBit(ctxId);
@@ -389,7 +390,7 @@ _OnVisit:
} }
} }
if (node->getType() == kNodeTypeTarget) if (node->getType() == kHLNodeTypeLabel)
goto _OnTarget; goto _OnTarget;
if (node == func) if (node == func)
@@ -403,12 +404,12 @@ _OnVisit:
_OnPatch: _OnPatch:
for (;;) { for (;;) {
ASMJIT_ASSERT(node->hasLiveness()); ASMJIT_ASSERT(node->hasLiveness());
VarBits* bNode = node->getLiveness(); BitArray* bNode = node->getLiveness();
if (!bNode->_addBitsDelSource(bCur, bLen)) if (!bNode->_addBitsDelSource(bCur, bLen))
goto _OnDone; goto _OnDone;
if (node->getType() == kNodeTypeTarget) if (node->getType() == kHLNodeTypeLabel)
goto _OnTarget; goto _OnTarget;
if (node == func) if (node == func)
@@ -418,7 +419,7 @@ _OnPatch:
} }
_OnTarget: _OnTarget:
if (static_cast<TargetNode*>(node)->getNumRefs() != 0) { if (static_cast<HLLabel*>(node)->getNumRefs() != 0) {
// Push a new LivenessTarget onto the stack if needed. // Push a new LivenessTarget onto the stack if needed.
if (ltCur == NULL || ltCur->node != node) { if (ltCur == NULL || ltCur->node != node) {
// Allocate a new LivenessTarget object (from pool or zone). // Allocate a new LivenessTarget object (from pool or zone).
@@ -428,8 +429,8 @@ _OnTarget:
ltUnused = ltUnused->prev; ltUnused = ltUnused->prev;
} }
else { else {
ltTmp = _baseZone.allocT<LivenessTarget>( ltTmp = _zoneAllocator.allocT<LivenessTarget>(
sizeof(LivenessTarget) - sizeof(VarBits) + bLen * sizeof(uintptr_t)); sizeof(LivenessTarget) - sizeof(BitArray) + bLen * sizeof(uintptr_t));
if (ltTmp == NULL) if (ltTmp == NULL)
goto _NoMemory; goto _NoMemory;
@@ -437,10 +438,10 @@ _OnTarget:
// Initialize and make current - ltTmp->from will be set later on. // Initialize and make current - ltTmp->from will be set later on.
ltTmp->prev = ltCur; ltTmp->prev = ltCur;
ltTmp->node = static_cast<TargetNode*>(node); ltTmp->node = static_cast<HLLabel*>(node);
ltCur = ltTmp; ltCur = ltTmp;
from = static_cast<TargetNode*>(node)->getFrom(); from = static_cast<HLLabel*>(node)->getFrom();
ASMJIT_ASSERT(from != NULL); ASMJIT_ASSERT(from != NULL);
} }
else { else {
@@ -508,7 +509,7 @@ _OnDone:
return kErrorOk; return kErrorOk;
_NoMemory: _NoMemory:
return setError(kErrorNoHeapMemory); return setLastError(kErrorNoHeapMemory);
} }
// ============================================================================ // ============================================================================
@@ -530,7 +531,7 @@ void Context::cleanup() {
for (size_t i = 0; i < length; i++) { for (size_t i = 0; i < length; i++) {
VarData* vd = array[i]; VarData* vd = array[i];
vd->resetContextId(); vd->resetLocalId();
vd->resetRegIndex(); vd->resetRegIndex();
} }
@@ -542,9 +543,9 @@ void Context::cleanup() {
// [asmjit::Context - CompileFunc] // [asmjit::Context - CompileFunc]
// ============================================================================ // ============================================================================
Error Context::compile(FuncNode* func) { Error Context::compile(HLFunc* func) {
Node* end = func->getEnd(); HLNode* end = func->getEnd();
Node* stop = end->getNext(); HLNode* stop = end->getNext();
_func = func; _func = func;
_stop = stop; _stop = stop;
@@ -557,13 +558,13 @@ Error Context::compile(FuncNode* func) {
Compiler* compiler = getCompiler(); Compiler* compiler = getCompiler();
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGER)
if (compiler->hasLogger()) if (compiler->getAssembler()->hasLogger())
ASMJIT_PROPAGATE_ERROR(annotate()); ASMJIT_PROPAGATE_ERROR(annotate());
#endif // !ASMJIT_DISABLE_LOGGER #endif // !ASMJIT_DISABLE_LOGGER
ASMJIT_PROPAGATE_ERROR(translate()); ASMJIT_PROPAGATE_ERROR(translate());
if (compiler->hasFeature(kCodeGenEnableScheduler)) if (compiler->hasFeature(kCompilerFeatureEnableScheduler))
ASMJIT_PROPAGATE_ERROR(schedule()); ASMJIT_PROPAGATE_ERROR(schedule());
// We alter the compiler cursor, because it doesn't make sense to reference // We alter the compiler cursor, because it doesn't make sense to reference

View File

@@ -0,0 +1,914 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_COMPILERCONTEXT_P_H
#define _ASMJIT_BASE_COMPILERCONTEXT_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/compiler.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::VarFlags]
// ============================================================================
//! \internal
//!
//! X86/X64 variable flags.
ASMJIT_ENUM(VarFlags) {
//! Variable contains single-precision floating-point(s).
kVarFlagSp = 0x10,
//! Variable contains double-precision floating-point(s).
kVarFlagDp = 0x20,
//! Variable is packed, i.e. packed floats, doubles, ...
kVarFlagPacked = 0x40
};
// ============================================================================
// [asmjit::VarAttrFlags]
// ============================================================================
//! \internal
//!
//! Variable attribute flags.
ASMJIT_ENUM(VarAttrFlags) {
//! Read from register.
kVarAttrRReg = 0x00000001,
//! Write to register.
kVarAttrWReg = 0x00000002,
//! Read/Write from/to register.
kVarAttrXReg = 0x00000003,
//! Read from memory.
kVarAttrRMem = 0x00000004,
//! Write to memory.
kVarAttrWMem = 0x00000008,
//! Read/Write from/to memory.
kVarAttrXMem = 0x0000000C,
//! Register allocator can decide if input will be in register or memory.
kVarAttrRDecide = 0x00000010,
//! Register allocator can decide if output will be in register or memory.
kVarAttrWDecide = 0x00000020,
//! Register allocator can decide if in/out will be in register or memory.
kVarAttrXDecide = 0x00000030,
//! Variable is converted to other type/class on the input.
kVarAttrRConv = 0x00000040,
//! Variable is converted from other type/class on the output.
kVarAttrWConv = 0x00000080,
//! Combination of `kVarAttrRConv` and `kVarAttrWConv`.
kVarAttrXConv = 0x000000C0,
//! Variable is a function call operand.
kVarAttrRCall = 0x00000100,
//! Variable is a function argument passed in register.
kVarAttrRFunc = 0x00000200,
//! Variable is a function return value passed in register.
kVarAttrWFunc = 0x00000400,
//! Variable should be spilled.
kVarAttrSpill = 0x00000800,
//! Variable should be unused at the end of the instruction/node.
kVarAttrUnuse = 0x00001000,
//! All in-flags.
kVarAttrRAll = kVarAttrRReg | kVarAttrRMem | kVarAttrRDecide | kVarAttrRCall | kVarAttrRFunc,
//! All out-flags.
kVarAttrWAll = kVarAttrWReg | kVarAttrWMem | kVarAttrWDecide | kVarAttrWFunc,
//! Variable is already allocated on the input.
kVarAttrAllocRDone = 0x00400000,
//! Variable is already allocated on the output.
kVarAttrAllocWDone = 0x00800000,
kVarAttrX86GpbLo = 0x10000000,
kVarAttrX86GpbHi = 0x20000000,
kVarAttrX86Fld4 = 0x40000000,
kVarAttrX86Fld8 = 0x80000000
};
// ============================================================================
// [asmjit::VarHint]
// ============================================================================
//! \internal
//!
//! Variable hint (used by `Compiler)`.
//!
//! \sa Compiler.
ASMJIT_ENUM(VarHint) {
//! Alloc variable.
kVarHintAlloc = 0,
//! Spill variable.
kVarHintSpill = 1,
//! Save variable if modified.
kVarHintSave = 2,
//! Save variable if modified and mark it as unused.
kVarHintSaveAndUnuse = 3,
//! Mark variable as unused.
kVarHintUnuse = 4
};
// ============================================================================
// [asmjit::kVarState]
// ============================================================================
// TODO: Rename `kVarState` or `VarState`.
//! \internal
//!
//! State of variable.
//!
//! \note Variable states are used only during register allocation.
ASMJIT_ENUM(kVarState) {
//! Variable is currently not used.
kVarStateNone = 0,
//! Variable is currently allocated in register.
kVarStateReg = 1,
//! Variable is currently allocated in memory (or has been spilled).
kVarStateMem = 2
};
// ============================================================================
// [asmjit::VarCell]
// ============================================================================
struct VarCell {
ASMJIT_NO_COPY(VarCell)
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get cell offset.
ASMJIT_INLINE int32_t getOffset() const { return _offset; }
//! Set cell offset.
ASMJIT_INLINE void setOffset(int32_t offset) { _offset = offset; }
//! Get cell size.
ASMJIT_INLINE uint32_t getSize() const { return _size; }
//! Set cell size.
ASMJIT_INLINE void setSize(uint32_t size) { _size = size; }
//! Get cell alignment.
ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; }
//! Set cell alignment.
ASMJIT_INLINE void setAlignment(uint32_t alignment) { _alignment = alignment; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Next active cell.
VarCell* _next;
//! Offset, relative to base-offset.
int32_t _offset;
//! Size.
uint32_t _size;
//! Alignment.
uint32_t _alignment;
};
// ============================================================================
// [asmjit::VarData]
// ============================================================================
//! HL variable data (base).
struct VarData {
// --------------------------------------------------------------------------
// [Accessors - Base]
// --------------------------------------------------------------------------
//! Get variable name.
ASMJIT_INLINE const char* getName() const { return _name; }
//! Get variable id.
ASMJIT_INLINE uint32_t getId() const { return _id; }
//! Get variable type.
ASMJIT_INLINE uint32_t getType() const { return _type; }
//! Get variable class.
ASMJIT_INLINE uint32_t getClass() const { return _class; }
// --------------------------------------------------------------------------
// [Accessors - LocalId]
// --------------------------------------------------------------------------
//! Get whether the variable has a local id.
ASMJIT_INLINE bool hasLocalId() const { return _localId != kInvalidValue; }
//! Get a variable's local id.
ASMJIT_INLINE uint32_t getLocalId() const { return _localId; }
//! Set a variable's local id.
ASMJIT_INLINE void setLocalId(uint32_t localId) { _localId = localId; }
//! Reset a variable's local id.
ASMJIT_INLINE void resetLocalId() { _localId = kInvalidValue; }
// --------------------------------------------------------------------------
// [Accessors - Priority]
// --------------------------------------------------------------------------
//! Get variable priority, used by compiler to decide which variable to spill.
ASMJIT_INLINE uint32_t getPriority() const { return _priority; }
//! Set variable priority.
ASMJIT_INLINE void setPriority(uint32_t priority) {
ASMJIT_ASSERT(priority <= 0xFF);
_priority = static_cast<uint8_t>(priority);
}
// --------------------------------------------------------------------------
// [Accessors - State]
// --------------------------------------------------------------------------
//! Get variable state, only used by `Context`.
ASMJIT_INLINE uint32_t getState() const { return _state; }
//! Set variable state, only used by `Context`.
ASMJIT_INLINE void setState(uint32_t state) {
ASMJIT_ASSERT(state <= 0xFF);
_state = static_cast<uint8_t>(state);
}
// --------------------------------------------------------------------------
// [Accessors - RegIndex]
// --------------------------------------------------------------------------
//! Get register index.
ASMJIT_INLINE uint32_t getRegIndex() const { return _regIndex; }
//! Set register index.
ASMJIT_INLINE void setRegIndex(uint32_t regIndex) {
ASMJIT_ASSERT(regIndex <= kInvalidReg);
_regIndex = static_cast<uint8_t>(regIndex);
}
//! Reset register index.
ASMJIT_INLINE void resetRegIndex() {
_regIndex = static_cast<uint8_t>(kInvalidReg);
}
// --------------------------------------------------------------------------
// [Accessors - HomeIndex/Mask]
// --------------------------------------------------------------------------
//! Get home registers mask.
ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; }
//! Add a home register index to the home registers mask.
ASMJIT_INLINE void addHomeIndex(uint32_t regIndex) { _homeMask |= Utils::mask(regIndex); }
// --------------------------------------------------------------------------
// [Accessors - Flags]
// --------------------------------------------------------------------------
//! Get variable flags.
ASMJIT_INLINE uint32_t getFlags() const { return _flags; }
//! Get whether the VarData is only memory allocated on the stack.
ASMJIT_INLINE bool isStack() const { return static_cast<bool>(_isStack); }
//! Get whether the variable is a function argument passed through memory.
ASMJIT_INLINE bool isMemArg() const { return static_cast<bool>(_isMemArg); }
//! Get variable content can be calculated by a simple instruction.
ASMJIT_INLINE bool isCalculated() const { return static_cast<bool>(_isCalculated); }
//! Get whether to save variable when it's unused (spill).
ASMJIT_INLINE bool saveOnUnuse() const { return static_cast<bool>(_saveOnUnuse); }
//! Get whether the variable was changed.
ASMJIT_INLINE bool isModified() const { return static_cast<bool>(_modified); }
//! Set whether the variable was changed.
ASMJIT_INLINE void setModified(bool modified) { _modified = modified; }
//! Get variable alignment.
ASMJIT_INLINE uint32_t getAlignment() const { return _alignment; }
//! Get variable size.
ASMJIT_INLINE uint32_t getSize() const { return _size; }
//! Get home memory offset.
ASMJIT_INLINE int32_t getMemOffset() const { return _memOffset; }
//! Set home memory offset.
ASMJIT_INLINE void setMemOffset(int32_t offset) { _memOffset = offset; }
//! Get home memory cell.
ASMJIT_INLINE VarCell* getMemCell() const { return _memCell; }
//! Set home memory cell.
ASMJIT_INLINE void setMemCell(VarCell* cell) { _memCell = cell; }
// --------------------------------------------------------------------------
// [Accessors - Temporary Usage]
// --------------------------------------------------------------------------
//! Get temporary VarAttr.
ASMJIT_INLINE VarAttr* getVa() const { return _va; }
//! Set temporary VarAttr.
ASMJIT_INLINE void setVa(VarAttr* va) { _va = va; }
//! Reset temporary VarAttr.
ASMJIT_INLINE void resetVa() { _va = NULL; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Variable name.
const char* _name;
//! Variable id.
uint32_t _id;
//! Variable's local id (initially `kInvalidValue`).
uint32_t _localId;
//! Variable type.
uint8_t _type;
//! Variable class.
uint8_t _class;
//! Variable flags.
uint8_t _flags;
//! Variable priority.
uint8_t _priority;
//! Variable state (connected with actual `VarState)`.
uint8_t _state;
//! Actual register index (only used by `Context)`, during translate.
uint8_t _regIndex;
//! Whether the variable is only used as memory allocated on the stack.
uint8_t _isStack : 1;
//! Whether the variable is a function argument passed through memory.
uint8_t _isMemArg : 1;
//! Whether variable content can be calculated by a simple instruction.
//!
//! This is used mainly by MMX and SSE2 code. This flag indicates that
//! register allocator should never reserve memory for this variable, because
//! the content can be generated by a single instruction (for example PXOR).
uint8_t _isCalculated : 1;
//! Save on unuse (at end of the variable scope).
uint8_t _saveOnUnuse : 1;
//! Whether variable was changed (connected with actual `VarState)`.
uint8_t _modified : 1;
//! \internal
uint8_t _reserved0 : 3;
//! Variable natural alignment.
uint8_t _alignment;
//! Variable size.
uint32_t _size;
//! Mask of all registers variable has been allocated to.
uint32_t _homeMask;
//! Home memory offset.
int32_t _memOffset;
//! Home memory cell, used by `Context` (initially NULL).
VarCell* _memCell;
//! Register read access statistics.
uint32_t rReadCount;
//! Register write access statistics.
uint32_t rWriteCount;
//! Memory read statistics.
uint32_t mReadCount;
//! Memory write statistics.
uint32_t mWriteCount;
// --------------------------------------------------------------------------
// [Members - Temporary Usage]
// --------------------------------------------------------------------------
// These variables are only used during register allocation. They are
// initialized by init() phase and reset by cleanup() phase.
union {
//! Temporary link to VarAttr* used by the `Context` used in
//! various phases, but always set back to NULL when finished.
//!
//! This temporary data is designed to be used by algorithms that need to
//! store some data into variables themselves during compilation. But it's
//! expected that after variable is compiled & translated the data is set
//! back to zero/null. Initial value is NULL.
VarAttr* _va;
//! \internal
//!
//! Same as `_va` just provided as `uintptr_t`.
uintptr_t _vaUInt;
};
};
// ============================================================================
// [asmjit::VarAttr]
// ============================================================================
struct VarAttr {
// --------------------------------------------------------------------------
// [Setup]
// --------------------------------------------------------------------------
ASMJIT_INLINE void setup(VarData* vd, uint32_t flags = 0, uint32_t inRegs = 0, uint32_t allocableRegs = 0) {
_vd = vd;
_flags = flags;
_varCount = 0;
_inRegIndex = kInvalidReg;
_outRegIndex = kInvalidReg;
_reserved = 0;
_inRegs = inRegs;
_allocableRegs = allocableRegs;
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get VarData.
ASMJIT_INLINE VarData* getVd() const { return _vd; }
//! Set VarData.
ASMJIT_INLINE void setVd(VarData* vd) { _vd = vd; }
//! Get flags.
ASMJIT_INLINE uint32_t getFlags() const { return _flags; }
//! Set flags.
ASMJIT_INLINE void setFlags(uint32_t flags) { _flags = flags; }
//! Get whether `flag` is on.
ASMJIT_INLINE bool hasFlag(uint32_t flag) { return (_flags & flag) != 0; }
//! Add `flags`.
ASMJIT_INLINE void orFlags(uint32_t flags) { _flags |= flags; }
//! Mask `flags`.
ASMJIT_INLINE void andFlags(uint32_t flags) { _flags &= flags; }
//! Clear `flags`.
ASMJIT_INLINE void andNotFlags(uint32_t flags) { _flags &= ~flags; }
//! Get how many times the variable is used by the instruction/node.
ASMJIT_INLINE uint32_t getVarCount() const { return _varCount; }
//! Set how many times the variable is used by the instruction/node.
ASMJIT_INLINE void setVarCount(uint32_t count) { _varCount = static_cast<uint8_t>(count); }
//! Add how many times the variable is used by the instruction/node.
ASMJIT_INLINE void addVarCount(uint32_t count = 1) { _varCount += static_cast<uint8_t>(count); }
//! Get whether the variable has to be allocated in a specific input register.
ASMJIT_INLINE uint32_t hasInRegIndex() const { return _inRegIndex != kInvalidReg; }
//! Get the input register index or `kInvalidReg`.
ASMJIT_INLINE uint32_t getInRegIndex() const { return _inRegIndex; }
//! Set the input register index.
ASMJIT_INLINE void setInRegIndex(uint32_t index) { _inRegIndex = static_cast<uint8_t>(index); }
//! Reset the input register index.
ASMJIT_INLINE void resetInRegIndex() { _inRegIndex = kInvalidReg; }
//! Get whether the variable has to be allocated in a specific output register.
ASMJIT_INLINE uint32_t hasOutRegIndex() const { return _outRegIndex != kInvalidReg; }
//! Get the output register index or `kInvalidReg`.
ASMJIT_INLINE uint32_t getOutRegIndex() const { return _outRegIndex; }
//! Set the output register index.
ASMJIT_INLINE void setOutRegIndex(uint32_t index) { _outRegIndex = static_cast<uint8_t>(index); }
//! Reset the output register index.
ASMJIT_INLINE void resetOutRegIndex() { _outRegIndex = kInvalidReg; }
//! Get whether the mandatory input registers are in used.
ASMJIT_INLINE bool hasInRegs() const { return _inRegs != 0; }
//! Get mandatory input registers (mask).
ASMJIT_INLINE uint32_t getInRegs() const { return _inRegs; }
//! Set mandatory input registers (mask).
ASMJIT_INLINE void setInRegs(uint32_t mask) { _inRegs = mask; }
//! Add mandatory input registers (mask).
ASMJIT_INLINE void addInRegs(uint32_t mask) { _inRegs |= mask; }
//! And mandatory input registers (mask).
ASMJIT_INLINE void andInRegs(uint32_t mask) { _inRegs &= mask; }
//! Clear mandatory input registers (mask).
ASMJIT_INLINE void delInRegs(uint32_t mask) { _inRegs &= ~mask; }
//! Get allocable input registers (mask).
ASMJIT_INLINE uint32_t getAllocableRegs() const { return _allocableRegs; }
//! Set allocable input registers (mask).
ASMJIT_INLINE void setAllocableRegs(uint32_t mask) { _allocableRegs = mask; }
//! Add allocable input registers (mask).
ASMJIT_INLINE void addAllocableRegs(uint32_t mask) { _allocableRegs |= mask; }
//! And allocable input registers (mask).
ASMJIT_INLINE void andAllocableRegs(uint32_t mask) { _allocableRegs &= mask; }
//! Clear allocable input registers (mask).
ASMJIT_INLINE void delAllocableRegs(uint32_t mask) { _allocableRegs &= ~mask; }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE VarAttr& operator=(const VarAttr& other) {
::memcpy(this, &other, sizeof(VarAttr));
return *this;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
VarData* _vd;
//! Flags.
uint32_t _flags;
union {
struct {
//! How many times the variable is used by the instruction/node.
uint8_t _varCount;
//! Input register index or `kInvalidReg` if it's not given.
//!
//! Even if the input register index is not given (i.e. it may by any
//! register), register allocator should assign an index that will be
//! used to persist a variable into this specific index. It's helpful
//! in situations where one variable has to be allocated in multiple
//! registers to determine the register which will be persistent.
uint8_t _inRegIndex;
//! Output register index or `kInvalidReg` if it's not given.
//!
//! Typically `kInvalidReg` if variable is only used on input.
uint8_t _outRegIndex;
//! \internal
uint8_t _reserved;
};
//! \internal
//!
//! Packed data #0.
uint32_t _packed;
};
//! Mandatory input registers.
//!
//! Mandatory input registers are required by the instruction even if
//! there are duplicates. This schema allows us to allocate one variable
//! in one or more register when needed. Required mostly by instructions
//! that have implicit register operands (imul, cpuid, ...) and function
//! call.
uint32_t _inRegs;
//! Allocable input registers.
//!
//! Optional input registers is a mask of all allocable registers for a given
//! variable where we have to pick one of them. This mask is usually not used
//! when _inRegs is set. If both masks are used then the register
//! allocator tries first to find an intersection between these and allocates
//! an extra slot if not found.
uint32_t _allocableRegs;
};
// ============================================================================
// [asmjit::VarMap]
// ============================================================================
//! Variables' map related to a single node (instruction / other node).
struct VarMap {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get count of variables (all).
ASMJIT_INLINE uint32_t getVaCount() const {
return _vaCount;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Variables count.
uint32_t _vaCount;
};
// ============================================================================
// [asmjit::VarState]
// ============================================================================
//! Variables' state.
struct VarState {};
// ============================================================================
// [asmjit::Context]
// ============================================================================
//! \internal
//!
//! Code generation context is the logic behind `Compiler`. The context is
//! used to compile the code stored in `Compiler`.
struct Context {
ASMJIT_NO_COPY(Context)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
Context(Compiler* compiler);
virtual ~Context();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the whole context.
virtual void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get compiler.
ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; }
//! Get function.
ASMJIT_INLINE HLFunc* getFunc() const { return _func; }
//! Get stop node.
ASMJIT_INLINE HLNode* getStop() const { return _stop; }
//! Get start of the current scope.
ASMJIT_INLINE HLNode* getStart() const { return _start; }
//! Get end of the current scope.
ASMJIT_INLINE HLNode* getEnd() const { return _end; }
//! Get extra block.
ASMJIT_INLINE HLNode* getExtraBlock() const { return _extraBlock; }
//! Set extra block.
ASMJIT_INLINE void setExtraBlock(HLNode* node) { _extraBlock = node; }
// --------------------------------------------------------------------------
// [Error]
// --------------------------------------------------------------------------
//! Get the last error code.
ASMJIT_INLINE Error getLastError() const {
return getCompiler()->getLastError();
}
//! Set the last error code and propagate it through the error handler.
ASMJIT_INLINE Error setLastError(Error error, const char* message = NULL) {
return getCompiler()->setLastError(error, message);
}
// --------------------------------------------------------------------------
// [State]
// --------------------------------------------------------------------------
//! Get current state.
ASMJIT_INLINE VarState* getState() const { return _state; }
//! Load current state from `target` state.
virtual void loadState(VarState* src) = 0;
//! Save current state, returning new `VarState` instance.
virtual VarState* saveState() = 0;
//! Change the current state to `target` state.
virtual void switchState(VarState* src) = 0;
//! Change the current state to the intersection of two states `a` and `b`.
virtual void intersectStates(VarState* a, VarState* b) = 0;
// --------------------------------------------------------------------------
// [Context]
// --------------------------------------------------------------------------
ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
if (vd->hasLocalId())
return kErrorOk;
uint32_t cid = static_cast<uint32_t>(_contextVd.getLength());
ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd));
vd->setLocalId(cid);
return kErrorOk;
}
// --------------------------------------------------------------------------
// [Mem]
// --------------------------------------------------------------------------
VarCell* _newVarCell(VarData* vd);
VarCell* _newStackCell(uint32_t size, uint32_t alignment);
ASMJIT_INLINE VarCell* getVarCell(VarData* vd) {
VarCell* cell = vd->getMemCell();
return cell ? cell : _newVarCell(vd);
}
virtual Error resolveCellOffsets();
// --------------------------------------------------------------------------
// [Bits]
// --------------------------------------------------------------------------
ASMJIT_INLINE BitArray* newBits(uint32_t len) {
return static_cast<BitArray*>(
_zoneAllocator.allocZeroed(static_cast<size_t>(len) * BitArray::kEntitySize));
}
ASMJIT_INLINE BitArray* copyBits(const BitArray* src, uint32_t len) {
return static_cast<BitArray*>(
_zoneAllocator.dup(src, static_cast<size_t>(len) * BitArray::kEntitySize));
}
// --------------------------------------------------------------------------
// [Fetch]
// --------------------------------------------------------------------------
//! Fetch.
//!
//! Fetch iterates over all nodes and gathers information about all variables
//! used. The process generates information required by register allocator,
//! variable liveness analysis and translator.
virtual Error fetch() = 0;
// --------------------------------------------------------------------------
// [Unreachable Code]
// --------------------------------------------------------------------------
//! Add unreachable-flow data to the unreachable flow list.
ASMJIT_INLINE Error addUnreachableNode(HLNode* node) {
PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>();
if (link == NULL)
return setLastError(kErrorNoHeapMemory);
link->setValue(node);
_unreachableList.append(link);
return kErrorOk;
}
//! Remove unreachable code.
virtual Error removeUnreachableCode();
// --------------------------------------------------------------------------
// [Code-Flow]
// --------------------------------------------------------------------------
//! Add returning node (i.e. node that returns and where liveness analysis
//! should start).
ASMJIT_INLINE Error addReturningNode(HLNode* node) {
PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>();
if (link == NULL)
return setLastError(kErrorNoHeapMemory);
link->setValue(node);
_returningList.append(link);
return kErrorOk;
}
//! Add jump-flow data to the jcc flow list.
ASMJIT_INLINE Error addJccNode(HLNode* node) {
PodList<HLNode*>::Link* link = _zoneAllocator.allocT<PodList<HLNode*>::Link>();
if (link == NULL)
return setLastError(kErrorNoHeapMemory);
link->setValue(node);
_jccList.append(link);
return kErrorOk;
}
// --------------------------------------------------------------------------
// [Analyze]
// --------------------------------------------------------------------------
//! Perform variable liveness analysis.
//!
//! Analysis phase iterates over nodes in reverse order and generates a bit
//! array describing variables that are alive at every node in the function.
//! When the analysis start all variables are assumed dead. When a read or
//! read/write operations of a variable is detected the variable becomes
//! alive; when only write operation is detected the variable becomes dead.
//!
//! When a label is found all jumps to that label are followed and analysis
//! repeats until all variables are resolved.
virtual Error livenessAnalysis();
// --------------------------------------------------------------------------
// [Annotate]
// --------------------------------------------------------------------------
virtual Error annotate() = 0;
// --------------------------------------------------------------------------
// [Translate]
// --------------------------------------------------------------------------
//! Translate code by allocating registers and handling state changes.
virtual Error translate() = 0;
// --------------------------------------------------------------------------
// [Schedule]
// --------------------------------------------------------------------------
virtual Error schedule();
// --------------------------------------------------------------------------
// [Cleanup]
// --------------------------------------------------------------------------
virtual void cleanup();
// --------------------------------------------------------------------------
// [Compile]
// --------------------------------------------------------------------------
virtual Error compile(HLFunc* func);
// --------------------------------------------------------------------------
// [Serialize]
// --------------------------------------------------------------------------
virtual Error serialize(Assembler* assembler, HLNode* start, HLNode* stop) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Compiler.
Compiler* _compiler;
//! Function.
HLFunc* _func;
//! Zone allocator.
Zone _zoneAllocator;
//! \internal
//!
//! Offset (how many bytes to add) to `VarMap` to get `VarAttr` array. Used
//! by liveness analysis shared across all backends. This is needed because
//! `VarMap` is a base class for a specialized version that liveness analysis
//! doesn't use, it just needs `VarAttr` array.
uint32_t _varMapToVaListOffset;
//! Start of the current active scope.
HLNode* _start;
//! End of the current active scope.
HLNode* _end;
//! Node that is used to insert extra code after the function body.
HLNode* _extraBlock;
//! Stop node.
HLNode* _stop;
//! Unreachable nodes.
PodList<HLNode*> _unreachableList;
//! Returning nodes.
PodList<HLNode*> _returningList;
//! Jump nodes.
PodList<HLNode*> _jccList;
//! All variables used by the current function.
PodVector<VarData*> _contextVd;
//! Memory used to spill variables.
VarCell* _memVarCells;
//! Memory used to alloc memory on the stack.
VarCell* _memStackCells;
//! Count of 1-byte cells.
uint32_t _mem1ByteVarsUsed;
//! Count of 2-byte cells.
uint32_t _mem2ByteVarsUsed;
//! Count of 4-byte cells.
uint32_t _mem4ByteVarsUsed;
//! Count of 8-byte cells.
uint32_t _mem8ByteVarsUsed;
//! Count of 16-byte cells.
uint32_t _mem16ByteVarsUsed;
//! Count of 32-byte cells.
uint32_t _mem32ByteVarsUsed;
//! Count of 64-byte cells.
uint32_t _mem64ByteVarsUsed;
//! Count of stack memory cells.
uint32_t _memStackCellsUsed;
//! Maximum memory alignment used by the function.
uint32_t _memMaxAlign;
//! Count of bytes used by variables.
uint32_t _memVarTotal;
//! Count of bytes used by stack.
uint32_t _memStackTotal;
//! Count of bytes used by variables and stack after alignment.
uint32_t _memAllTotal;
//! Default lenght of annotated instruction.
uint32_t _annotationLength;
//! Current state (used by register allocator).
VarState* _state;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_COMPILERCONTEXT_P_H

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/constpool.h" #include "../base/constpool.h"
#include "../base/intutil.h" #include "../base/utils.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -21,14 +21,14 @@ namespace asmjit {
// get, insert and traverse. // get, insert and traverse.
// ============================================================================ // ============================================================================
// [asmjit::ConstPoolTree - Ops] // [asmjit::ConstPool::Tree - Ops]
// ============================================================================ // ============================================================================
//! \internal //! \internal
//! //!
//! Remove left horizontal links. //! Remove left horizontal links.
static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node) { static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_skewNode(ConstPool::Node* node) {
ConstPoolNode* link = node->_link[0]; ConstPool::Node* link = node->_link[0];
uint32_t level = node->_level; uint32_t level = node->_level;
if (level != 0 && link != NULL && link->_level == level) { if (level != 0 && link != NULL && link->_level == level) {
@@ -44,8 +44,8 @@ static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node)
//! \internal //! \internal
//! //!
//! Remove consecutive horizontal links. //! Remove consecutive horizontal links.
static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_splitNode(ConstPoolNode* node) { static ASMJIT_INLINE ConstPool::Node* ConstPoolTree_splitNode(ConstPool::Node* node) {
ConstPoolNode* link = node->_link[1]; ConstPool::Node* link = node->_link[1];
uint32_t level = node->_level; uint32_t level = node->_level;
if (level != 0 && link != NULL && link->_link[1] != NULL && link->_link[1]->_level == level) { if (level != 0 && link != NULL && link->_link[1] != NULL && link->_link[1]->_level == level) {
@@ -59,8 +59,8 @@ static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_splitNode(ConstPoolNode* node)
return node; return node;
} }
ConstPoolNode* ConstPoolTree::get(const void* data) { ConstPool::Node* ConstPool::Tree::get(const void* data) {
ConstPoolNode* node = _root; ConstPool::Node* node = _root;
size_t dataSize = _dataSize; size_t dataSize = _dataSize;
while (node != NULL) { while (node != NULL) {
@@ -73,7 +73,7 @@ ConstPoolNode* ConstPoolTree::get(const void* data) {
return NULL; return NULL;
} }
void ConstPoolTree::put(ConstPoolNode* newNode) { void ConstPool::Tree::put(ConstPool::Node* newNode) {
size_t dataSize = _dataSize; size_t dataSize = _dataSize;
_length++; _length++;
@@ -82,8 +82,8 @@ void ConstPoolTree::put(ConstPoolNode* newNode) {
return; return;
} }
ConstPoolNode* node = _root; ConstPool::Node* node = _root;
ConstPoolNode* stack[kHeightLimit]; ConstPool::Node* stack[kHeightLimit];
unsigned int top = 0; unsigned int top = 0;
unsigned int dir; unsigned int dir;
@@ -93,7 +93,7 @@ void ConstPoolTree::put(ConstPoolNode* newNode) {
stack[top++] = node; stack[top++] = node;
dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0; dir = ::memcmp(node->getData(), newNode->getData(), dataSize) < 0;
ConstPoolNode* link = node->_link[dir]; ConstPool::Node* link = node->_link[dir];
if (link == NULL) if (link == NULL)
break; break;
@@ -162,16 +162,16 @@ void ConstPool::reset() {
// [asmjit::ConstPool - Ops] // [asmjit::ConstPool - Ops]
// ============================================================================ // ============================================================================
static ASMJIT_INLINE ConstPoolGap* ConstPool_allocGap(ConstPool* self) { static ASMJIT_INLINE ConstPool::Gap* ConstPool_allocGap(ConstPool* self) {
ConstPoolGap* gap = self->_gapPool; ConstPool::Gap* gap = self->_gapPool;
if (gap == NULL) if (gap == NULL)
return self->_zone->allocT<ConstPoolGap>(); return self->_zone->allocT<ConstPool::Gap>();
self->_gapPool = gap->_next; self->_gapPool = gap->_next;
return gap; return gap;
} }
static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPoolGap* gap) { static ASMJIT_INLINE void ConstPool_freeGap(ConstPool* self, ConstPool::Gap* gap) {
gap->_next = self->_gapPool; gap->_next = self->_gapPool;
self->_gapPool = gap; self->_gapPool = gap;
} }
@@ -183,19 +183,19 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) {
size_t gapIndex; size_t gapIndex;
size_t gapLength; size_t gapLength;
if (length >= 16 && IntUtil::isAligned<size_t>(offset, 16)) { if (length >= 16 && Utils::isAligned<size_t>(offset, 16)) {
gapIndex = ConstPool::kIndex16; gapIndex = ConstPool::kIndex16;
gapLength = 16; gapLength = 16;
} }
else if (length >= 8 && IntUtil::isAligned<size_t>(offset, 8)) { else if (length >= 8 && Utils::isAligned<size_t>(offset, 8)) {
gapIndex = ConstPool::kIndex8; gapIndex = ConstPool::kIndex8;
gapLength = 8; gapLength = 8;
} }
else if (length >= 4 && IntUtil::isAligned<size_t>(offset, 4)) { else if (length >= 4 && Utils::isAligned<size_t>(offset, 4)) {
gapIndex = ConstPool::kIndex4; gapIndex = ConstPool::kIndex4;
gapLength = 4; gapLength = 4;
} }
else if (length >= 2 && IntUtil::isAligned<size_t>(offset, 2)) { else if (length >= 2 && Utils::isAligned<size_t>(offset, 2)) {
gapIndex = ConstPool::kIndex2; gapIndex = ConstPool::kIndex2;
gapLength = 2; gapLength = 2;
} }
@@ -207,7 +207,7 @@ static void ConstPool_addGap(ConstPool* self, size_t offset, size_t length) {
// We don't have to check for errors here, if this failed nothing really // We don't have to check for errors here, if this failed nothing really
// happened (just the gap won't be visible) and it will fail again at // happened (just the gap won't be visible) and it will fail again at
// place where checking will cause kErrorNoHeapMemory. // place where checking will cause kErrorNoHeapMemory.
ConstPoolGap* gap = ConstPool_allocGap(self); ConstPool::Gap* gap = ConstPool_allocGap(self);
if (gap == NULL) if (gap == NULL)
return; return;
@@ -240,7 +240,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
else else
return kErrorInvalidArgument; return kErrorInvalidArgument;
ConstPoolNode* node = _tree[treeIndex].get(data); ConstPool::Node* node = _tree[treeIndex].get(data);
if (node != NULL) { if (node != NULL) {
dstOffset = node->_offset; dstOffset = node->_offset;
return kErrorOk; return kErrorOk;
@@ -252,7 +252,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
size_t gapIndex = treeIndex; size_t gapIndex = treeIndex;
while (gapIndex != kIndexCount - 1) { while (gapIndex != kIndexCount - 1) {
ConstPoolGap* gap = _gaps[treeIndex]; ConstPool::Gap* gap = _gaps[treeIndex];
// Check if there is a gap. // Check if there is a gap.
if (gap != NULL) { if (gap != NULL) {
@@ -264,7 +264,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
ConstPool_freeGap(this, gap); ConstPool_freeGap(this, gap);
offset = gapOffset; offset = gapOffset;
ASMJIT_ASSERT(IntUtil::isAligned<size_t>(offset, size)); ASMJIT_ASSERT(Utils::isAligned<size_t>(offset, size));
gapLength -= size; gapLength -= size;
if (gapLength > 0) if (gapLength > 0)
@@ -277,11 +277,11 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
if (offset == ~static_cast<size_t>(0)) { if (offset == ~static_cast<size_t>(0)) {
// Get how many bytes have to be skipped so the address is aligned accordingly // Get how many bytes have to be skipped so the address is aligned accordingly
// to the 'size'. // to the 'size'.
size_t deltaTo = IntUtil::deltaTo<size_t>(_size, size); size_t diff = Utils::alignDiff<size_t>(_size, size);
if (deltaTo != 0) { if (diff != 0) {
ConstPool_addGap(this, _size, deltaTo); ConstPool_addGap(this, _size, diff);
_size += deltaTo; _size += diff;
} }
offset = _size; offset = _size;
@@ -289,12 +289,12 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
} }
// Add the initial node to the right index. // Add the initial node to the right index.
node = ConstPoolTree::_newNode(_zone, data, size, offset, false); node = ConstPool::Tree::_newNode(_zone, data, size, offset, false);
if (node == NULL) if (node == NULL)
return kErrorNoHeapMemory; return kErrorNoHeapMemory;
_tree[treeIndex].put(node); _tree[treeIndex].put(node);
_alignment = IntUtil::iMax<size_t>(_alignment, size); _alignment = Utils::iMax<size_t>(_alignment, size);
dstOffset = offset; dstOffset = offset;
@@ -316,7 +316,7 @@ Error ConstPool::add(const void* data, size_t size, size_t& dstOffset) {
if (node != NULL) if (node != NULL)
continue; continue;
node = ConstPoolTree::_newNode(_zone, pData, size, offset + (i * size), true); node = ConstPool::Tree::_newNode(_zone, pData, size, offset + (i * size), true);
_tree[treeIndex].put(node); _tree[treeIndex].put(node);
} }
} }
@@ -333,7 +333,7 @@ struct ConstPoolFill {
_dst(dst), _dst(dst),
_dataSize(dataSize) {} _dataSize(dataSize) {}
ASMJIT_INLINE void visit(const ConstPoolNode* node) { ASMJIT_INLINE void visit(const ConstPool::Node* node) {
if (!node->_shared) if (!node->_shared)
::memcpy(_dst + node->_offset, node->getData(), _dataSize); ::memcpy(_dst + node->_offset, node->getData(), _dataSize);
} }
@@ -342,7 +342,7 @@ struct ConstPoolFill {
size_t _dataSize; size_t _dataSize;
}; };
void ConstPool::fill(void* dst) { void ConstPool::fill(void* dst) const {
// Clears possible gaps, asmjit should never emit garbage to the output. // Clears possible gaps, asmjit should never emit garbage to the output.
::memset(dst, 0, _size); ::memset(dst, 0, _size);
@@ -359,7 +359,7 @@ void ConstPool::fill(void* dst) {
#if defined(ASMJIT_TEST) #if defined(ASMJIT_TEST)
UNIT(base_constpool) { UNIT(base_constpool) {
Zone zone(32384 - kZoneOverhead); Zone zone(32384 - Zone::kZoneOverhead);
ConstPool pool(&zone); ConstPool pool(&zone);
uint32_t i; uint32_t i;

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_CONSTPOOL_H #define _ASMJIT_BASE_CONSTPOOL_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/zone.h" #include "../base/zone.h"
// [Api-Begin] // [Api-Begin]
@@ -17,23 +16,57 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::ConstPoolNode] // [asmjit::ConstPool]
// ============================================================================ // ============================================================================
//! Constant pool.
struct ConstPool {
ASMJIT_NO_COPY(ConstPool)
enum {
kIndex1 = 0,
kIndex2 = 1,
kIndex4 = 2,
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
kIndexCount = 6
};
// --------------------------------------------------------------------------
// [Gap]
// --------------------------------------------------------------------------
//! \internal //! \internal
//! //!
//! Zone-allocated constant-pool node. //! Zone-allocated const-pool gap.
struct ConstPoolNode { struct Gap {
//! Link to the next gap
Gap* _next;
//! Offset of the gap.
size_t _offset;
//! Remaining bytes of the gap (basically a gap size).
size_t _length;
};
// --------------------------------------------------------------------------
// [Node]
// --------------------------------------------------------------------------
//! \internal
//!
//! Zone-allocated const-pool node.
struct Node {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE void* getData() const { ASMJIT_INLINE void* getData() const {
return static_cast<void*>(const_cast<ConstPoolNode*>(this) + 1); return static_cast<void*>(const_cast<ConstPool::Node*>(this) + 1);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -41,7 +74,7 @@ struct ConstPoolNode {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Left/Right nodes. //! Left/Right nodes.
ConstPoolNode* _link[2]; Node* _link[2];
//! Horizontal level for balance. //! Horizontal level for balance.
uint32_t _level : 31; uint32_t _level : 31;
//! Whether this constant is shared with another. //! Whether this constant is shared with another.
@@ -50,14 +83,14 @@ struct ConstPoolNode {
uint32_t _offset; uint32_t _offset;
}; };
// ============================================================================ // --------------------------------------------------------------------------
// [asmjit::ConstPoolTree] // [Tree]
// ============================================================================ // --------------------------------------------------------------------------
//! \internal //! \internal
//! //!
//! Zone-allocated constant-pool tree. //! Zone-allocated const-pool tree.
struct ConstPoolTree { struct Tree {
enum { enum {
//! Maximum tree height == log2(1 << 64). //! Maximum tree height == log2(1 << 64).
kHeightLimit = 64 kHeightLimit = 64
@@ -67,11 +100,11 @@ struct ConstPoolTree {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE ConstPoolTree(size_t dataSize = 0) : ASMJIT_INLINE Tree(size_t dataSize = 0)
_root(NULL), : _root(NULL),
_length(0), _length(0),
_dataSize(dataSize) {} _dataSize(dataSize) {}
ASMJIT_INLINE ~ConstPoolTree() {} ASMJIT_INLINE ~Tree() {}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Reset]
@@ -86,13 +119,8 @@ struct ConstPoolTree {
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const { ASMJIT_INLINE bool isEmpty() const { return _length == 0; }
return _length == 0; ASMJIT_INLINE size_t getLength() const { return _length; }
}
ASMJIT_INLINE size_t getLength() const {
return _length;
}
ASMJIT_INLINE void setDataSize(size_t dataSize) { ASMJIT_INLINE void setDataSize(size_t dataSize) {
ASMJIT_ASSERT(isEmpty()); ASMJIT_ASSERT(isEmpty());
@@ -103,8 +131,8 @@ struct ConstPoolTree {
// [Ops] // [Ops]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API ConstPoolNode* get(const void* data); ASMJIT_API Node* get(const void* data);
ASMJIT_API void put(ConstPoolNode* node); ASMJIT_API void put(Node* node);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Iterate] // [Iterate]
@@ -112,10 +140,10 @@ struct ConstPoolTree {
template<typename Visitor> template<typename Visitor>
ASMJIT_INLINE void iterate(Visitor& visitor) const { ASMJIT_INLINE void iterate(Visitor& visitor) const {
ConstPoolNode* node = const_cast<ConstPoolNode*>(_root); Node* node = const_cast<Node*>(_root);
ConstPoolNode* link; Node* link;
ConstPoolNode* stack[kHeightLimit]; Node* stack[kHeightLimit];
if (node == NULL) if (node == NULL)
return; return;
@@ -154,8 +182,8 @@ _Visit:
// [Helpers] // [Helpers]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
static ASMJIT_INLINE ConstPoolNode* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) { static ASMJIT_INLINE Node* _newNode(Zone* zone, const void* data, size_t size, size_t offset, bool shared) {
ConstPoolNode* node = zone->allocT<ConstPoolNode>(sizeof(ConstPoolNode) + size); Node* node = zone->allocT<Node>(sizeof(Node) + size);
if (node == NULL) if (node == NULL)
return NULL; return NULL;
@@ -174,47 +202,13 @@ _Visit:
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Root of the tree //! Root of the tree
ConstPoolNode* _root; Node* _root;
//! Length of the tree (count of nodes). //! Length of the tree (count of nodes).
size_t _length; size_t _length;
//! Size of the data. //! Size of the data.
size_t _dataSize; size_t _dataSize;
}; };
// ============================================================================
// [asmjit::ConstPoolGap]
// ============================================================================
//! \internal
//!
//! Zone-allocated constant-pool gap.
struct ConstPoolGap {
//! Link to the next gap
ConstPoolGap* _next;
//! Offset of the gap.
size_t _offset;
//! Remaining bytes of the gap (basically a gap size).
size_t _length;
};
// ============================================================================
// [asmjit::ConstPool]
// ============================================================================
//! Constant pool.
struct ConstPool {
ASMJIT_NO_COPY(ConstPool)
enum {
kIndex1 = 0,
kIndex2 = 1,
kIndex4 = 2,
kIndex8 = 3,
kIndex16 = 4,
kIndex32 = 5,
kIndexCount = 6
};
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -233,19 +227,11 @@ struct ConstPool {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the constant-pool is empty. //! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const { ASMJIT_INLINE bool isEmpty() const { return _size == 0; }
return _size == 0;
}
//! Get the size of the constant-pool in bytes. //! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const { ASMJIT_INLINE size_t getSize() const { return _size; }
return _size;
}
//! Get minimum alignment. //! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const { ASMJIT_INLINE size_t getAlignment() const { return _alignment; }
return _alignment;
}
//! Add a constant to the constant pool. //! Add a constant to the constant pool.
//! //!
@@ -271,7 +257,7 @@ struct ConstPool {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Fill the destination with the constants from the pool. //! Fill the destination with the constants from the pool.
ASMJIT_API void fill(void* dst); ASMJIT_API void fill(void* dst) const;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -280,11 +266,11 @@ struct ConstPool {
//! Zone allocator. //! Zone allocator.
Zone* _zone; Zone* _zone;
//! Tree per size. //! Tree per size.
ConstPoolTree _tree[kIndexCount]; Tree _tree[kIndexCount];
//! Gaps per size. //! Gaps per size.
ConstPoolGap* _gaps[kIndexCount]; Gap* _gaps[kIndexCount];
//! Gaps pool //! Gaps pool
ConstPoolGap* _gapPool; Gap* _gapPool;
//! Size of the pool (in bytes). //! Size of the pool (in bytes).
size_t _size; size_t _size;

View File

@@ -9,7 +9,7 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/containers.h" #include "../base/containers.h"
#include "../base/intutil.h" #include "../base/utils.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -53,7 +53,7 @@ Error PodVectorBase::_grow(size_t n, size_t sizeOfT) {
size_t capacity = d->capacity; size_t capacity = d->capacity;
size_t after = d->length; size_t after = d->length;
if (IntUtil::maxUInt<size_t>() - n < after) if (IntTraits<size_t>::maxValue() - n < after)
return kErrorNoHeapMemory; return kErrorNoHeapMemory;
after += n; after += n;
@@ -110,6 +110,358 @@ Error PodVectorBase::_reserve(size_t n, size_t sizeOfT) {
return kErrorOk; return kErrorOk;
} }
// Should be placed in read-only memory.
static const char StringBuilder_empty[4] = { 0 };
// ============================================================================
// [asmjit::StringBuilder - Construction / Destruction]
// ============================================================================
StringBuilder::StringBuilder()
: _data(const_cast<char*>(StringBuilder_empty)),
_length(0),
_capacity(0),
_canFree(false) {}
StringBuilder::~StringBuilder() {
if (_canFree)
ASMJIT_FREE(_data);
}
// ============================================================================
// [asmjit::StringBuilder - Prepare / Reserve]
// ============================================================================
char* StringBuilder::prepare(uint32_t op, size_t len) {
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
if (op == kStringOpSet) {
// We don't care here, but we can't return a NULL pointer since it indicates
// failure in memory allocation.
if (len == 0) {
if (_data != StringBuilder_empty)
_data[0] = 0;
_length = 0;
return _data;
}
if (_capacity < len) {
if (len >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2)
return NULL;
size_t to = Utils::alignTo<size_t>(len, sizeof(intptr_t));
if (to < 256 - sizeof(intptr_t))
to = 256 - sizeof(intptr_t);
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL) {
clear();
return NULL;
}
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
}
_data[len] = 0;
_length = len;
ASMJIT_ASSERT(_length <= _capacity);
return _data;
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
else {
// We don't care here, but we can't return a NULL pointer since it indicates
// failure in memory allocation.
if (len == 0)
return _data + _length;
// Overflow.
if (IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2 - _length < len)
return NULL;
size_t after = _length + len;
if (_capacity < after) {
size_t to = _capacity;
if (to < 256)
to = 256;
while (to < 1024 * 1024 && to < after)
to *= 2;
if (to < after) {
to = after;
if (to < (IntTraits<size_t>::maxValue() - 1024 * 32))
to = Utils::alignTo<size_t>(to, 1024 * 32);
}
to = Utils::alignTo<size_t>(to, sizeof(intptr_t));
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL)
return NULL;
::memcpy(newData, _data, _length);
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
}
char* ret = _data + _length;
_data[after] = 0;
_length = after;
ASMJIT_ASSERT(_length <= _capacity);
return ret;
}
}
bool StringBuilder::reserve(size_t to) {
if (_capacity >= to)
return true;
if (to >= IntTraits<size_t>::maxValue() - sizeof(intptr_t) * 2)
return false;
to = Utils::alignTo<size_t>(to, sizeof(intptr_t));
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL)
return false;
::memcpy(newData, _data, _length + 1);
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
return true;
}
// ============================================================================
// [asmjit::StringBuilder - Clear]
// ============================================================================
void StringBuilder::clear() {
if (_data != StringBuilder_empty)
_data[0] = 0;
_length = 0;
}
// ============================================================================
// [asmjit::StringBuilder - Methods]
// ============================================================================
bool StringBuilder::_opString(uint32_t op, const char* str, size_t len) {
if (len == kInvalidIndex)
len = str != NULL ? ::strlen(str) : static_cast<size_t>(0);
char* p = prepare(op, len);
if (p == NULL)
return false;
::memcpy(p, str, len);
return true;
}
bool StringBuilder::_opChar(uint32_t op, char c) {
char* p = prepare(op, 1);
if (p == NULL)
return false;
*p = c;
return true;
}
bool StringBuilder::_opChars(uint32_t op, char c, size_t len) {
char* p = prepare(op, len);
if (p == NULL)
return false;
::memset(p, c, len);
return true;
}
static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
bool StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) {
if (base < 2 || base > 36)
base = 10;
char buf[128];
char* p = buf + ASMJIT_ARRAY_SIZE(buf);
uint64_t orig = i;
char sign = '\0';
// --------------------------------------------------------------------------
// [Sign]
// --------------------------------------------------------------------------
if ((flags & kStringFormatSigned) != 0 && static_cast<int64_t>(i) < 0) {
i = static_cast<uint64_t>(-static_cast<int64_t>(i));
sign = '-';
}
else if ((flags & kStringFormatShowSign) != 0) {
sign = '+';
}
else if ((flags & kStringFormatShowSpace) != 0) {
sign = ' ';
}
// --------------------------------------------------------------------------
// [Number]
// --------------------------------------------------------------------------
do {
uint64_t d = i / base;
uint64_t r = i % base;
*--p = StringBuilder_numbers[r];
i = d;
} while (i);
size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
// --------------------------------------------------------------------------
// [Alternate Form]
// --------------------------------------------------------------------------
if ((flags & kStringFormatAlternate) != 0) {
if (base == 8) {
if (orig != 0)
*--p = '0';
}
if (base == 16) {
*--p = 'x';
*--p = '0';
}
}
// --------------------------------------------------------------------------
// [Width]
// --------------------------------------------------------------------------
if (sign != 0)
*--p = sign;
if (width > 256)
width = 256;
if (width <= numberLength)
width = 0;
else
width -= numberLength;
// --------------------------------------------------------------------------
// Write]
// --------------------------------------------------------------------------
size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength;
char* data = prepare(op, prefixLength + width + numberLength);
if (data == NULL)
return false;
::memcpy(data, p, prefixLength);
data += prefixLength;
::memset(data, '0', width);
data += width;
::memcpy(data, p + prefixLength, numberLength);
return true;
}
bool StringBuilder::_opHex(uint32_t op, const void* data, size_t len) {
if (len >= IntTraits<size_t>::maxValue() / 2)
return false;
char* dst = prepare(op, len * 2);
if (dst == NULL)
return false;
const char* src = static_cast<const char*>(data);
for (size_t i = 0; i < len; i++, dst += 2, src += 1)
{
dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF];
dst[1] = StringBuilder_numbers[(src[0] ) & 0xF];
}
return true;
}
bool StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) {
char buf[1024];
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
return _opString(op, buf);
}
bool StringBuilder::setFormat(const char* fmt, ...) {
bool result;
va_list ap;
va_start(ap, fmt);
result = _opVFormat(kStringOpSet, fmt, ap);
va_end(ap);
return result;
}
bool StringBuilder::appendFormat(const char* fmt, ...) {
bool result;
va_list ap;
va_start(ap, fmt);
result = _opVFormat(kStringOpAppend, fmt, ap);
va_end(ap);
return result;
}
bool StringBuilder::eq(const char* str, size_t len) const {
const char* aData = _data;
const char* bData = str;
size_t aLength = _length;
size_t bLength = len;
if (bLength == kInvalidIndex) {
size_t i;
for (i = 0; i < aLength; i++) {
if (aData[i] != bData[i] || bData[i] == 0)
return false;
}
return bData[i] == 0;
}
else {
if (aLength != bLength)
return false;
return ::memcmp(aData, bData, aLength) == 0;
}
}
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_CONTAINERS_H #define _ASMJIT_BASE_CONTAINERS_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/globals.h" #include "../base/globals.h"
// [Api-Begin] // [Api-Begin]
@@ -17,9 +16,125 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================
// [asmjit::BitArray]
// ============================================================================
//! Fixed size bit-array.
//!
//! Used by variable liveness analysis.
struct BitArray {
// --------------------------------------------------------------------------
// [Enums]
// --------------------------------------------------------------------------
enum {
kEntitySize = static_cast<int>(sizeof(uintptr_t)),
kEntityBits = kEntitySize * 8
};
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE uintptr_t getBit(uint32_t index) const {
return (data[index / kEntityBits] >> (index % kEntityBits)) & 1;
}
ASMJIT_INLINE void setBit(uint32_t index) {
data[index / kEntityBits] |= static_cast<uintptr_t>(1) << (index % kEntityBits);
}
ASMJIT_INLINE void delBit(uint32_t index) {
data[index / kEntityBits] &= ~(static_cast<uintptr_t>(1) << (index % kEntityBits));
}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Copy bits from `s0`, returns `true` if at least one bit is set in `s0`.
ASMJIT_INLINE bool copyBits(const BitArray* s0, uint32_t len) {
uintptr_t r = 0;
for (uint32_t i = 0; i < len; i++) {
uintptr_t t = s0->data[i];
data[i] = t;
r |= t;
}
return r != 0;
}
ASMJIT_INLINE bool addBits(const BitArray* s0, uint32_t len) {
return addBits(this, s0, len);
}
ASMJIT_INLINE bool addBits(const BitArray* s0, const BitArray* s1, uint32_t len) {
uintptr_t r = 0;
for (uint32_t i = 0; i < len; i++) {
uintptr_t t = s0->data[i] | s1->data[i];
data[i] = t;
r |= t;
}
return r != 0;
}
ASMJIT_INLINE bool andBits(const BitArray* s1, uint32_t len) {
return andBits(this, s1, len);
}
ASMJIT_INLINE bool andBits(const BitArray* s0, const BitArray* s1, uint32_t len) {
uintptr_t r = 0;
for (uint32_t i = 0; i < len; i++) {
uintptr_t t = s0->data[i] & s1->data[i];
data[i] = t;
r |= t;
}
return r != 0;
}
ASMJIT_INLINE bool delBits(const BitArray* s1, uint32_t len) {
return delBits(this, s1, len);
}
ASMJIT_INLINE bool delBits(const BitArray* s0, const BitArray* s1, uint32_t len) {
uintptr_t r = 0;
for (uint32_t i = 0; i < len; i++) {
uintptr_t t = s0->data[i] & ~s1->data[i];
data[i] = t;
r |= t;
}
return r != 0;
}
ASMJIT_INLINE bool _addBitsDelSource(BitArray* s1, uint32_t len) {
return _addBitsDelSource(this, s1, len);
}
ASMJIT_INLINE bool _addBitsDelSource(const BitArray* s0, BitArray* s1, uint32_t len) {
uintptr_t r = 0;
for (uint32_t i = 0; i < len; i++) {
uintptr_t a = s0->data[i];
uintptr_t b = s1->data[i];
this->data[i] = a | b;
b &= ~a;
s1->data[i] = b;
r |= b;
}
return r != 0;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uintptr_t data[1];
};
// ============================================================================ // ============================================================================
// [asmjit::PodVectorData] // [asmjit::PodVectorData]
// ============================================================================ // ============================================================================
@@ -31,9 +146,7 @@ struct PodVectorData {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get data. //! Get data.
ASMJIT_INLINE void* getData() const { ASMJIT_INLINE void* getData() const { return (void*)(this + 1); }
return (void*)(this + 1);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -58,13 +171,9 @@ struct PodVectorBase {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a new instance of `PodVectorBase`. //! Create a new instance of `PodVectorBase`.
ASMJIT_INLINE PodVectorBase() : ASMJIT_INLINE PodVectorBase() : _d(const_cast<PodVectorData*>(&_nullData)) {}
_d(const_cast<PodVectorData*>(&_nullData)) {}
//! Destroy the `PodVectorBase` and data. //! Destroy the `PodVectorBase` and data.
ASMJIT_INLINE ~PodVectorBase() { ASMJIT_INLINE ~PodVectorBase() { reset(true); }
reset(true);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Reset]
@@ -121,43 +230,24 @@ struct PodVector : PodVectorBase {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the vector is empty. //! Get whether the vector is empty.
ASMJIT_INLINE bool isEmpty() const { ASMJIT_INLINE bool isEmpty() const { return _d->length == 0; }
return _d->length == 0;
}
//! Get length. //! Get length.
ASMJIT_INLINE size_t getLength() const { ASMJIT_INLINE size_t getLength() const { return _d->length; }
return _d->length;
}
//! Get capacity. //! Get capacity.
ASMJIT_INLINE size_t getCapacity() const { ASMJIT_INLINE size_t getCapacity() const { return _d->capacity; }
return _d->capacity;
}
//! Get data. //! Get data.
ASMJIT_INLINE T* getData() { ASMJIT_INLINE T* getData() { return static_cast<T*>(_d->getData()); }
return static_cast<T*>(_d->getData());
}
//! \overload //! \overload
ASMJIT_INLINE const T* getData() const { ASMJIT_INLINE const T* getData() const { return static_cast<const T*>(_d->getData()); }
return static_cast<const T*>(_d->getData());
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Grow / Reserve] // [Grow / Reserve]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Called to grow the buffer to fit at least `n` elements more. //! Called to grow the buffer to fit at least `n` elements more.
ASMJIT_INLINE Error _grow(size_t n) { ASMJIT_INLINE Error _grow(size_t n) { return PodVectorBase::_grow(n, sizeof(T)); }
return PodVectorBase::_grow(n, sizeof(T));
}
//! Realloc internal array to fit at least `n` items. //! Realloc internal array to fit at least `n` items.
ASMJIT_INLINE Error _reserve(size_t n) { ASMJIT_INLINE Error _reserve(size_t n) { return PodVectorBase::_reserve(n, sizeof(T)); }
return PodVectorBase::_reserve(n, sizeof(T));
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Ops] // [Ops]
@@ -339,6 +429,324 @@ struct PodList {
Link* _last; Link* _last;
}; };
// ============================================================================
// [asmjit::StringBuilder]
// ============================================================================
//! String builder.
//!
//! String builder was designed to be able to build a string using append like
//! operation to append numbers, other strings, or signle characters. It can
//! allocate it's own buffer or use a buffer created on the stack.
//!
//! String builder contains method specific to AsmJit functionality, used for
//! logging or HTML output.
struct StringBuilder {
ASMJIT_NO_COPY(StringBuilder)
// --------------------------------------------------------------------------
// [Enums]
// --------------------------------------------------------------------------
//! \internal
//!
//! String operation.
ASMJIT_ENUM(StringOp) {
//! Replace the current string by a given content.
kStringOpSet = 0,
//! Append a given content to the current string.
kStringOpAppend = 1
};
//! \internal
//!
//! String format flags.
ASMJIT_ENUM(StringFormatFlags) {
kStringFormatShowSign = 0x00000001,
kStringFormatShowSpace = 0x00000002,
kStringFormatAlternate = 0x00000004,
kStringFormatSigned = 0x80000000
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API StringBuilder();
ASMJIT_API ~StringBuilder();
ASMJIT_INLINE StringBuilder(const _NoInit&) {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get string builder capacity.
ASMJIT_INLINE size_t getCapacity() const { return _capacity; }
//! Get length.
ASMJIT_INLINE size_t getLength() const { return _length; }
//! Get null-terminated string data.
ASMJIT_INLINE char* getData() { return _data; }
//! Get null-terminated string data (const).
ASMJIT_INLINE const char* getData() const { return _data; }
// --------------------------------------------------------------------------
// [Prepare / Reserve]
// --------------------------------------------------------------------------
//! Prepare to set/append.
ASMJIT_API char* prepare(uint32_t op, size_t len);
//! Reserve `to` bytes in string builder.
ASMJIT_API bool reserve(size_t to);
// --------------------------------------------------------------------------
// [Clear]
// --------------------------------------------------------------------------
//! Clear the content in String builder.
ASMJIT_API void clear();
// --------------------------------------------------------------------------
// [Op]
// --------------------------------------------------------------------------
ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidIndex);
ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap);
ASMJIT_API bool _opChar(uint32_t op, char c);
ASMJIT_API bool _opChars(uint32_t op, char c, size_t len);
ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0);
ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t len);
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
//! Replace the current content by `str` of `len`.
ASMJIT_INLINE bool setString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpSet, str, len);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_INLINE bool setVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpSet, fmt, ap);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_API bool setFormat(const char* fmt, ...);
//! Replace the current content by `c` character.
ASMJIT_INLINE bool setChar(char c) {
return _opChar(kStringOpSet, c);
}
//! Replace the current content by `c` of `len`.
ASMJIT_INLINE bool setChars(char c, size_t len) {
return _opChars(kStringOpSet, c, len);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags);
}
//! Replace the current content by the given `data` converted to a HEX string.
ASMJIT_INLINE bool setHex(const void* data, size_t len) {
return _opHex(kStringOpSet, data, len);
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`.
ASMJIT_INLINE bool appendString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpAppend, str, len);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_INLINE bool appendVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpAppend, fmt, ap);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_API bool appendFormat(const char* fmt, ...);
//! Append `c` character.
ASMJIT_INLINE bool appendChar(char c) {
return _opChar(kStringOpAppend, c);
}
//! Append `c` of `len`.
ASMJIT_INLINE bool appendChars(char c, size_t len) {
return _opChars(kStringOpAppend, c, len);
}
//! Append `i`.
ASMJIT_INLINE bool appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, static_cast<uint64_t>(i), base, width, flags | kStringFormatSigned);
}
//! Append `i`.
ASMJIT_INLINE bool appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, i, base, width, flags);
}
//! Append the given `data` converted to a HEX string.
ASMJIT_INLINE bool appendHex(const void* data, size_t len) {
return _opHex(kStringOpAppend, data, len);
}
// --------------------------------------------------------------------------
// [_Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendString(const char* str, size_t len = kInvalidIndex) {
// len should be a constant if we are inlining.
if (len == kInvalidIndex) {
char* p = &_data[_length];
while (*str) {
ASMJIT_ASSERT(p < _data + _capacity);
*p++ = *str++;
}
*p = '\0';
_length = (size_t)(p - _data);
}
else {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = *str++;
*p = '\0';
_length += len;
}
}
//! Append `c` character, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChar(char c) {
ASMJIT_ASSERT(_capacity - _length >= 1);
_data[_length] = c;
_length++;
_data[_length] = '\0';
}
//! Append `c` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChars(char c, size_t len) {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = c;
*p = '\0';
_length += len;
}
ASMJIT_INLINE void _appendUInt32(uint32_t i) {
char buf_[32];
char* pEnd = buf_ + ASMJIT_ARRAY_SIZE(buf_);
char* pBuf = pEnd;
do {
uint32_t d = i / 10;
uint32_t r = i % 10;
*--pBuf = static_cast<uint8_t>(r + '0');
i = d;
} while (i);
ASMJIT_ASSERT(_capacity - _length >= (size_t)(pEnd - pBuf));
char* p = &_data[_length];
do {
*p++ = *pBuf;
} while (++pBuf != pEnd);
*p = '\0';
_length = (size_t)(p - _data);
}
// --------------------------------------------------------------------------
// [Eq]
// --------------------------------------------------------------------------
//! Check for equality with other `str` of `len`.
ASMJIT_API bool eq(const char* str, size_t len = kInvalidIndex) const;
//! Check for equality with `other`.
ASMJIT_INLINE bool eq(const StringBuilder& other) const { return eq(other._data); }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool operator==(const StringBuilder& other) const { return eq(other); }
ASMJIT_INLINE bool operator!=(const StringBuilder& other) const { return !eq(other); }
ASMJIT_INLINE bool operator==(const char* str) const { return eq(str); }
ASMJIT_INLINE bool operator!=(const char* str) const { return !eq(str); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! String data.
char* _data;
//! Length.
size_t _length;
//! Capacity.
size_t _capacity;
//! Whether the string can be freed.
size_t _canFree;
};
// ============================================================================
// [asmjit::StringBuilderTmp]
// ============================================================================
//! Temporary string builder, has statically allocated `N` bytes.
template<size_t N>
struct StringBuilderTmp : public StringBuilder {
ASMJIT_NO_COPY(StringBuilderTmp<N>)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE StringBuilderTmp() : StringBuilder(NoInit) {
_data = _embeddedData;
_data[0] = 0;
_length = 0;
_capacity = N;
_canFree = false;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Embedded data.
char _embeddedData[static_cast<size_t>(
N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)];
};
//! \} //! \}
} // asmjit namespace } // asmjit namespace

View File

@@ -1,350 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CONTEXT_P_H
#define _ASMJIT_BASE_CONTEXT_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/compiler.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_compiler
//! \{
// ============================================================================
// [asmjit::Context]
// ============================================================================
//! \internal
//!
//! Code generation context is the logic behind `Compiler`. The context is
//! used to compile the code stored in `Compiler`.
struct Context {
ASMJIT_NO_COPY(Context)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
Context(Compiler* compiler);
virtual ~Context();
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the whole context.
virtual void reset(bool releaseMemory = false);
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get compiler.
ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; }
//! Get function.
ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
//! Get stop node.
ASMJIT_INLINE Node* getStop() const { return _stop; }
//! Get start of the current scope.
ASMJIT_INLINE Node* getStart() const { return _start; }
//! Get end of the current scope.
ASMJIT_INLINE Node* getEnd() const { return _end; }
//! Get extra block.
ASMJIT_INLINE Node* getExtraBlock() const { return _extraBlock; }
//! Set extra block.
ASMJIT_INLINE void setExtraBlock(Node* node) { _extraBlock = node; }
// --------------------------------------------------------------------------
// [Error]
// --------------------------------------------------------------------------
//! Get the last error code.
ASMJIT_INLINE Error getError() const {
return getCompiler()->getError();
}
//! Set the last error code and propagate it through the error handler.
ASMJIT_INLINE Error setError(Error error, const char* message = NULL) {
return getCompiler()->setError(error, message);
}
// --------------------------------------------------------------------------
// [State]
// --------------------------------------------------------------------------
//! Get current state.
ASMJIT_INLINE VarState* getState() const {
return _state;
}
//! Load current state from `target` state.
virtual void loadState(VarState* src) = 0;
//! Save current state, returning new `VarState` instance.
virtual VarState* saveState() = 0;
//! Change the current state to `target` state.
virtual void switchState(VarState* src) = 0;
//! Change the current state to the intersection of two states `a` and `b`.
virtual void intersectStates(VarState* a, VarState* b) = 0;
// --------------------------------------------------------------------------
// [Context]
// --------------------------------------------------------------------------
ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
if (vd->hasContextId())
return kErrorOk;
uint32_t cid = static_cast<uint32_t>(_contextVd.getLength());
ASMJIT_PROPAGATE_ERROR(_contextVd.append(vd));
vd->setContextId(cid);
return kErrorOk;
}
// --------------------------------------------------------------------------
// [Mem]
// --------------------------------------------------------------------------
MemCell* _newVarCell(VarData* vd);
MemCell* _newStackCell(uint32_t size, uint32_t alignment);
ASMJIT_INLINE MemCell* getVarCell(VarData* vd) {
MemCell* cell = vd->getMemCell();
return cell ? cell : _newVarCell(vd);
}
virtual Error resolveCellOffsets();
// --------------------------------------------------------------------------
// [Bits]
// --------------------------------------------------------------------------
ASMJIT_INLINE VarBits* newBits(uint32_t len) {
return static_cast<VarBits*>(
_baseZone.allocZeroed(static_cast<size_t>(len) * VarBits::kEntitySize));
}
ASMJIT_INLINE VarBits* copyBits(const VarBits* src, uint32_t len) {
return static_cast<VarBits*>(
_baseZone.dup(src, static_cast<size_t>(len) * VarBits::kEntitySize));
}
// --------------------------------------------------------------------------
// [Fetch]
// --------------------------------------------------------------------------
//! Fetch.
//!
//! Fetch iterates over all nodes and gathers information about all variables
//! used. The process generates information required by register allocator,
//! variable liveness analysis and translator.
virtual Error fetch() = 0;
// --------------------------------------------------------------------------
// [Unreachable Code]
// --------------------------------------------------------------------------
//! Add unreachable-flow data to the unreachable flow list.
ASMJIT_INLINE Error addUnreachableNode(Node* node) {
PodList<Node*>::Link* link = _baseZone.allocT<PodList<Node*>::Link>();
if (link == NULL)
return setError(kErrorNoHeapMemory);
link->setValue(node);
_unreachableList.append(link);
return kErrorOk;
}
//! Remove unreachable code.
virtual Error removeUnreachableCode();
// --------------------------------------------------------------------------
// [Code-Flow]
// --------------------------------------------------------------------------
//! Add returning node (i.e. node that returns and where liveness analysis
//! should start).
ASMJIT_INLINE Error addReturningNode(Node* node) {
PodList<Node*>::Link* link = _baseZone.allocT<PodList<Node*>::Link>();
if (link == NULL)
return setError(kErrorNoHeapMemory);
link->setValue(node);
_returningList.append(link);
return kErrorOk;
}
//! Add jump-flow data to the jcc flow list.
ASMJIT_INLINE Error addJccNode(Node* node) {
PodList<Node*>::Link* link = _baseZone.allocT<PodList<Node*>::Link>();
if (link == NULL)
return setError(kErrorNoHeapMemory);
link->setValue(node);
_jccList.append(link);
return kErrorOk;
}
// --------------------------------------------------------------------------
// [Analyze]
// --------------------------------------------------------------------------
//! Perform variable liveness analysis.
//!
//! Analysis phase iterates over nodes in reverse order and generates a bit
//! array describing variables that are alive at every node in the function.
//! When the analysis start all variables are assumed dead. When a read or
//! read/write operations of a variable is detected the variable becomes
//! alive; when only write operation is detected the variable becomes dead.
//!
//! When a label is found all jumps to that label are followed and analysis
//! repeats until all variables are resolved.
virtual Error livenessAnalysis();
// --------------------------------------------------------------------------
// [Annotate]
// --------------------------------------------------------------------------
virtual Error annotate() = 0;
// --------------------------------------------------------------------------
// [Translate]
// --------------------------------------------------------------------------
//! Translate code by allocating registers and handling state changes.
virtual Error translate() = 0;
// --------------------------------------------------------------------------
// [Schedule]
// --------------------------------------------------------------------------
virtual Error schedule();
// --------------------------------------------------------------------------
// [Cleanup]
// --------------------------------------------------------------------------
virtual void cleanup();
// --------------------------------------------------------------------------
// [Compile]
// --------------------------------------------------------------------------
virtual Error compile(FuncNode* func);
// --------------------------------------------------------------------------
// [Serialize]
// --------------------------------------------------------------------------
virtual Error serialize(Assembler* assembler, Node* start, Node* stop) = 0;
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Compiler.
Compiler* _compiler;
//! Function.
FuncNode* _func;
//! Zone allocator.
Zone _baseZone;
//! \internal
//!
//! Offset (how many bytes to add) to `VarMap` to get `VarAttr` array. Used
//! by liveness analysis shared across all backends. This is needed because
//! `VarMap` is a base class for a specialized version that liveness analysis
//! doesn't use, it just needs `VarAttr` array.
uint32_t _varMapToVaListOffset;
//! Start of the current active scope.
Node* _start;
//! End of the current active scope.
Node* _end;
//! Node that is used to insert extra code after the function body.
Node* _extraBlock;
//! Stop node.
Node* _stop;
//! Unreachable nodes.
PodList<Node*> _unreachableList;
//! Returning nodes.
PodList<Node*> _returningList;
//! Jump nodes.
PodList<Node*> _jccList;
//! All variables used by the current function.
PodVector<VarData*> _contextVd;
//! Memory used to spill variables.
MemCell* _memVarCells;
//! Memory used to alloc memory on the stack.
MemCell* _memStackCells;
//! Count of 1-byte cells.
uint32_t _mem1ByteVarsUsed;
//! Count of 2-byte cells.
uint32_t _mem2ByteVarsUsed;
//! Count of 4-byte cells.
uint32_t _mem4ByteVarsUsed;
//! Count of 8-byte cells.
uint32_t _mem8ByteVarsUsed;
//! Count of 16-byte cells.
uint32_t _mem16ByteVarsUsed;
//! Count of 32-byte cells.
uint32_t _mem32ByteVarsUsed;
//! Count of 64-byte cells.
uint32_t _mem64ByteVarsUsed;
//! Count of stack memory cells.
uint32_t _memStackCellsUsed;
//! Maximum memory alignment used by the function.
uint32_t _memMaxAlign;
//! Count of bytes used by variables.
uint32_t _memVarTotal;
//! Count of bytes used by stack.
uint32_t _memStackTotal;
//! Count of bytes used by variables and stack after alignment.
uint32_t _memAllTotal;
//! Default lenght of annotated instruction.
uint32_t _annotationLength;
//! Current state (used by register allocator).
VarState* _state;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_CONTEXT_P_H

View File

@@ -10,14 +10,14 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/cpuinfo.h" #include "../base/cpuinfo.h"
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
#include "../x86/x86cpuinfo.h" #include "../x86/x86cpuinfo.h"
#else #else
// ? // ?
#endif #endif
// [Dependencies - Posix] // [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX) #if ASMJIT_OS_POSIX
# include <errno.h> # include <errno.h>
# include <sys/statvfs.h> # include <sys/statvfs.h>
# include <sys/utsname.h> # include <sys/utsname.h>
@@ -34,11 +34,11 @@ namespace asmjit {
// ============================================================================ // ============================================================================
uint32_t CpuInfo::detectHwThreadsCount() { uint32_t CpuInfo::detectHwThreadsCount() {
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
SYSTEM_INFO info; SYSTEM_INFO info;
::GetSystemInfo(&info); ::GetSystemInfo(&info);
return info.dwNumberOfProcessors; return info.dwNumberOfProcessors;
#elif defined(ASMJIT_OS_POSIX) && defined(_SC_NPROCESSORS_ONLN) #elif ASMJIT_OS_POSIX && defined(_SC_NPROCESSORS_ONLN)
// It seems that sysconf returns the number of "logical" processors on both // It seems that sysconf returns the number of "logical" processors on both
// mac and linux. So we get the number of "online logical" processors. // mac and linux. So we get the number of "online logical" processors.
long res = ::sysconf(_SC_NPROCESSORS_ONLN); long res = ::sysconf(_SC_NPROCESSORS_ONLN);
@@ -54,21 +54,21 @@ uint32_t CpuInfo::detectHwThreadsCount() {
// [asmjit::CpuInfo - GetHost] // [asmjit::CpuInfo - GetHost]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
struct AutoX86CpuInfo : public X86CpuInfo { struct AutoX86CpuInfo : public X86CpuInfo {
ASMJIT_INLINE AutoX86CpuInfo() : X86CpuInfo() { ASMJIT_INLINE AutoX86CpuInfo() : X86CpuInfo() {
X86CpuUtil::detect(this); X86CpuUtil::detect(this);
} }
}; };
#else #else
#error "AsmJit - Unsupported CPU." #error "[asmjit] Unsupported CPU."
#endif #endif
const CpuInfo* CpuInfo::getHost() { const CpuInfo* CpuInfo::getHost() {
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
static AutoX86CpuInfo cpuInfo; static AutoX86CpuInfo cpuInfo;
#else #else
#error "AsmJit - Unsupported CPU." #error "[asmjit] Unsupported CPU."
#endif #endif
return &cpuInfo; return &cpuInfo;
} }

View File

@@ -16,7 +16,7 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -37,9 +37,9 @@ ASMJIT_ENUM(CpuVendor) {
//! Intel vendor. //! Intel vendor.
kCpuVendorIntel = 1, kCpuVendorIntel = 1,
//! AMD vendor. //! AMD vendor.
kCpuVendorAmd = 2, kCpuVendorAMD = 2,
//! VIA vendor. //! VIA vendor.
kCpuVendorVia = 3 kCpuVendorVIA = 3
}; };
// ============================================================================ // ============================================================================

View File

@@ -1,131 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/cputicks.h"
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <time.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX
// [Dependencies - Mac]
#if defined(ASMJIT_OS_MAC)
# include <mach/mach_time.h>
#endif // ASMJIT_OS_MAC
// [Dependencies - Windows]
#if defined(ASMJIT_OS_WINDOWS)
// `_InterlockedCompareExchange` is only available as intrinsic (MS Compiler).
# if defined(_MSC_VER) && _MSC_VER >= 1400
# include <intrin.h>
# pragma intrinsic(_InterlockedCompareExchange)
# else
# define _InterlockedCompareExchange InterlockedCompareExchange
# endif // _MSC_VER
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CpuTicks - Windows]
// ============================================================================
#if defined(ASMJIT_OS_WINDOWS)
static volatile uint32_t CpuTicks_hiResOk;
static volatile double CpuTicks_hiResFreq;
uint32_t CpuTicks::now() {
do {
uint32_t hiResOk = CpuTicks_hiResOk;
if (hiResOk == 1) {
LARGE_INTEGER now;
if (!::QueryPerformanceCounter(&now))
break;
return (int64_t)(double(now.QuadPart) / CpuTicks_hiResFreq);
}
if (hiResOk == 0) {
LARGE_INTEGER qpf;
if (!::QueryPerformanceFrequency(&qpf)) {
_InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
break;
}
LARGE_INTEGER now;
if (!::QueryPerformanceCounter(&now)) {
_InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 0xFFFFFFFF, 0);
break;
}
double freqDouble = double(qpf.QuadPart) / 1000.0;
CpuTicks_hiResFreq = freqDouble;
_InterlockedCompareExchange((LONG*)&CpuTicks_hiResOk, 1, 0);
return static_cast<uint32_t>(
static_cast<int64_t>(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF);
}
} while (0);
// Bail to a less precise GetTickCount().
return ::GetTickCount();
}
// ============================================================================
// [asmjit::CpuTicks - Mac]
// ============================================================================
#elif defined(ASMJIT_OS_MAC)
static mach_timebase_info_data_t CpuTicks_machTime;
uint32_t CpuTicks::now() {
// Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
if (CpuTicks_machTime.denom == 0) {
if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS)
return 0;
}
// mach_absolute_time() returns nanoseconds, we need just milliseconds.
uint64_t t = mach_absolute_time() / 1000000;
t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom;
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}
// ============================================================================
// [asmjit::CpuTicks - Posix]
// ============================================================================
#else
uint32_t CpuTicks::now() {
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
return 0;
uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
#else // _POSIX_MONOTONIC_CLOCK
#error "AsmJit - Unsupported OS."
return 0;
#endif // _POSIX_MONOTONIC_CLOCK
}
#endif // ASMJIT_OS
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,40 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CPUTICKS_H
#define _ASMJIT_BASE_CPUTICKS_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::CpuTicks]
// ============================================================================
//! CPU ticks utilities.
struct CpuTicks {
//! Get the current CPU ticks for benchmarking (1ms resolution).
static ASMJIT_API uint32_t now();
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CPUTICKS_H

View File

@@ -1,83 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::ErrorHandler - Construction / Destruction]
// ============================================================================
ErrorHandler::ErrorHandler() {}
ErrorHandler::~ErrorHandler() {}
// ============================================================================
// [asmjit::ErrorHandler - Interface]
// ============================================================================
ErrorHandler* ErrorHandler::addRef() const {
return const_cast<ErrorHandler*>(this);
}
void ErrorHandler::release() {}
// ============================================================================
// [asmjit::ErrorUtil - AsString]
// ============================================================================
#if !defined(ASMJIT_DISABLE_NAMES)
static const char errorMessages[] = {
"Ok\0"
"No heap memory\0"
"No virtual memory\0"
"Invalid argument\0"
"Invalid state\0"
"No code generated\0"
"Code too large\0"
"Label already bound\0"
"Unknown instruction\0"
"Illegal instruction\0"
"Illegal addressing\0"
"Illegal displacement\0"
"Overlapped arguments\0"
"Unknown error\0"
};
static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId) {
uint32_t i = 0;
if (id > maxId)
id = maxId;
while (i < id) {
while (p[0])
p++;
p++;
i++;
}
return p;
}
const char* ErrorUtil::asString(Error e) {
return findPackedString(errorMessages, e, kErrorCount);
}
#endif // ASMJIT_DISABLE_NAMES
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,218 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ERROR_H
#define _ASMJIT_BASE_ERROR_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::ErrorCode]
// ============================================================================
//! AsmJit error codes.
ASMJIT_ENUM(ErrorCode) {
//! No error (success).
//!
//! This is default state and state you want.
kErrorOk = 0,
//! Heap memory allocation failed.
kErrorNoHeapMemory = 1,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory = 2,
//! Invalid argument.
kErrorInvalidArgument = 3,
//! Invalid state.
kErrorInvalidState = 4,
//! No code generated.
//!
//! Returned by runtime if the code-generator contains no code.
kErrorNoCodeGenerated = 5,
//! Code generated is too large to fit in memory reserved.
//!
//! Returned by `StaticRuntime` in case that the code generated is too large
//! to fit in the memory already reserved for it.
kErrorCodeTooLarge = 6,
//! Label is already bound.
kErrorLabelAlreadyBound = 7,
//! Unknown instruction (an instruction ID is out of bounds or instruction
//! name is invalid).
kErrorUnknownInst = 8,
//! Illegal instruction.
//!
//! This status code can also be returned in X64 mode if AH, BH, CH or DH
//! registers have been used together with a REX prefix. The instruction
//! is not encodable in such case.
//!
//! Example of raising `kErrorIllegalInst` error.
//!
//! ~~~
//! // Invalid address size.
//! a.mov(dword_ptr(eax), al);
//!
//! // Undecodable instruction - AH used with R10, however R10 can only be
//! // encoded by using REX prefix, which conflicts with AH.
//! a.mov(byte_ptr(r10), ah);
//! ~~~
//!
//! \note In debug mode assertion is raised instead of returning an error.
kErrorIllegalInst = 9,
//! Illegal (unencodable) addressing used.
kErrorIllegalAddresing = 10,
//! Illegal (unencodable) displacement used.
//!
//! X86/X64
//! -------
//!
//! Short form of jump instruction has been used, but the displacement is out
//! of bounds.
kErrorIllegalDisplacement = 11,
//! A variable has been assigned more than once to a function argument (Compiler).
kErrorOverlappedArgs = 12,
//! Count of AsmJit error codes.
kErrorCount = 13
};
// ============================================================================
// [asmjit::Error]
// ============================================================================
//! AsmJit error type (unsigned integer).
typedef uint32_t Error;
// ============================================================================
// [asmjit::ErrorHandler]
// ============================================================================
//! Error handler.
//!
//! Error handler can be used to override the default behavior of `CodeGen`
//! error handling and propagation. See `handleError` on how to override it.
//!
//! Please note that `addRef` and `release` functions are used, but there is
//! no reference counting implemented by default, reimplement to change the
//! default behavior.
struct ASMJIT_VCLASS ErrorHandler {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `ErrorHandler` instance.
ASMJIT_API ErrorHandler();
//! Destroy the `ErrorHandler` instance.
ASMJIT_API virtual ~ErrorHandler();
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Reference this error handler.
//!
//! \note This member function is provided for convenience. The default
//! implementation does nothing. If you are working in environment where
//! multiple `ErrorHandler` instances are used by a different code generators
//! you may provide your own functionality for reference counting. In that
//! case `addRef()` and `release()` functions should be overridden.
ASMJIT_API virtual ErrorHandler* addRef() const;
//! Release this error handler.
//!
//! \note This member function is provided for convenience. See `addRef()`
//! for more detailed information related to reference counting.
ASMJIT_API virtual void release();
//! Error handler (pure).
//!
//! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `Assembler` and
//! `Compiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons.
//!
//! AsmJit library doesn't use exceptions and can be compiled with or without
//! exception handling support. Even if the AsmJit library is compiled without
//! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the
//! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
//! throwing an exception is using `setjmp()` and `longjmp()` pair available
//! in the standard C library.
//!
//! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
//! execution (instruction serialization) can continue. However if the error
//! happened during any phase that translates or modifies the stored code
//! (for example relocation done by `Assembler` or analysis/translation
//! done by `Compiler`) the execution can't continue and the error will
//! be also stored in `Assembler` or `Compiler`.
//!
//! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible handling by returning from your
//! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution, but `false` sets the rror immediately to the
//! `Assembler` or `Compiler` and execution shouldn't continue (this
//! is the default behavior in case no error handler is used).
virtual bool handleError(Error code, const char* message) = 0;
};
// ============================================================================
// [asmjit::ErrorUtil]
// ============================================================================
//! Error utilities.
struct ErrorUtil {
#if !defined(ASMJIT_DISABLE_NAMES)
//! Get a printable version of AsmJit `Error` code.
static ASMJIT_API const char* asString(Error code);
#endif // ASMJIT_DISABLE_NAMES
};
//! \}
// ============================================================================
// [ASMJIT_PROPAGATE_ERROR]
// ============================================================================
//! \internal
//!
//! Used by AsmJit to return the `_Exp_` result if it's an error.
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
do { \
::asmjit::Error errval_ = (_Exp_); \
if (errval_ != ::asmjit::kErrorOk) \
return errval_; \
} while (0)
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ERROR_H

View File

@@ -16,11 +16,75 @@
namespace asmjit { namespace asmjit {
// ============================================================================ // ============================================================================
// [asmjit::Assert] // [asmjit::DebugUtils]
// ============================================================================ // ============================================================================
void assertionFailed(const char* exp, const char* file, int line) { #if !defined(ASMJIT_DISABLE_NAMES)
::fprintf(stderr, "Assertion failed: %s\n, file %s, line %d\n", exp, file, line); static const char errorMessages[] = {
"Ok\0"
"No heap memory\0"
"No virtual memory\0"
"Invalid argument\0"
"Invalid state\0"
"Invalid architecture\0"
"Not initialized\0"
"No code generated\0"
"Code too large\0"
"Label already bound\0"
"Unknown instruction\0"
"Illegal instruction\0"
"Illegal addressing\0"
"Illegal displacement\0"
"Overlapped arguments\0"
"Unknown error\0"
};
static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId) {
uint32_t i = 0;
if (id > maxId)
id = maxId;
while (i < id) {
while (p[0])
p++;
p++;
i++;
}
return p;
}
#endif // ASMJIT_DISABLE_NAMES
const char* DebugUtils::errorAsString(Error e) {
#if !defined(ASMJIT_DISABLE_NAMES)
return findPackedString(errorMessages, e, kErrorCount);
#else
static const char noMessage[] = "";
return noMessage;
#endif
}
void DebugUtils::debugOutput(const char* str) {
#if ASMJIT_OS_WINDOWS
::OutputDebugStringA(str);
#else
::fputs(str, stderr);
#endif
}
void DebugUtils::assertionFailed(const char* file, int line, const char* msg) {
char str[1024];
snprintf(str, 1024,
"[asmjit] Assertion failed at %s (line %d):\n"
"[asmjit] %s\n", file, line, msg);
// Support buggy `snprintf` implementations.
str[1023] = '\0';
debugOutput(str);
::abort(); ::abort();
} }

View File

@@ -16,21 +16,24 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::Ptr / SignedPtr] // [asmjit::TypeDefs]
// ============================================================================ // ============================================================================
//! AsmJit error core (unsigned integer).
typedef uint32_t Error;
//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators. //! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
//! //!
//! This is the preferred pointer type to use with AsmJit library. It has a //! This is the preferred pointer type to use with AsmJit library. It has a
//! capability to hold any pointer for any architecture making it an ideal //! capability to hold any pointer for any architecture making it an ideal
//! candidate for cross-platform code generation. //! candidate for a cross-platform code generator.
typedef uint64_t Ptr; typedef uint64_t Ptr;
//! 64-bit signed pointer, like \ref Ptr, but made signed. //! like \ref Ptr, but signed.
typedef int64_t SignedPtr; typedef int64_t SignedPtr;
// ============================================================================ // ============================================================================
@@ -60,8 +63,8 @@ ASMJIT_ENUM(GlobalDefs) {
//! Host memory allocator overhead. //! Host memory allocator overhead.
//! //!
//! The overhead is decremented from all zone allocators so the operating //! The overhead is decremented from all zone allocators so the operating
//! system doesn't have allocate extra virtual page to keep tract of the //! system doesn't have to allocate one extra virtual page to keep tract of
//! requested memory block. //! the requested memory block.
//! //!
//! The number is actually a guess. //! The number is actually a guess.
kMemAllocOverhead = sizeof(intptr_t) * 4, kMemAllocOverhead = sizeof(intptr_t) * 4,
@@ -82,30 +85,119 @@ ASMJIT_ENUM(ArchId) {
//! No/Unknown architecture. //! No/Unknown architecture.
kArchNone = 0, kArchNone = 0,
//! X86 architecture. //! X86 architecture (32-bit).
kArchX86 = 1, kArchX86 = 1,
//! X64 architecture, also called AMD64. //! X64 architecture (64-bit), also called AMD64.
kArchX64 = 2, kArchX64 = 2,
//! Arm architecture. //! X32 architecture (64-bit with 32-bit pointers) (NOT USED ATM).
kArchX32 = 3,
//! Arm architecture (32-bit).
kArchArm = 4, kArchArm = 4,
//! Arm64 architecture (64-bit).
kArchArm64 = 5,
#if defined(ASMJIT_ARCH_X86) #if ASMJIT_ARCH_X86
kArchHost = kArchX86, kArchHost = kArchX86,
#endif // ASMJIT_ARCH_X86 #elif ASMJIT_ARCH_X64
#if defined(ASMJIT_ARCH_X64)
kArchHost = kArchX64, kArchHost = kArchX64,
#endif // ASMJIT_ARCH_X64 #elif ASMJIT_ARCH_ARM
#if defined(ASMJIT_ARCH_ARM)
kArchHost = kArchArm, kArchHost = kArchArm,
#endif // ASMJIT_ARCH_ARM #elif ASMJIT_ARCH_ARM64
kArchHost = kArchArm64,
#endif
//! Whether the host is 64-bit. //! Whether the host is 64-bit.
kArchHost64Bit = sizeof(intptr_t) >= 8 kArchHost64Bit = sizeof(intptr_t) >= 8
}; };
// ============================================================================
// [asmjit::ErrorCode]
// ============================================================================
//! AsmJit error codes.
ASMJIT_ENUM(ErrorCode) {
//! No error (success).
//!
//! This is default state and state you want.
kErrorOk = 0,
//! Heap memory allocation failed.
kErrorNoHeapMemory,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory,
//! Invalid argument.
kErrorInvalidArgument,
//! Invalid state.
kErrorInvalidState,
//! Invalid architecture.
kErrorInvalidArch,
//! The object is not initialized.
kErrorNotInitialized,
//! No code generated.
//!
//! Returned by runtime if the code-generator contains no code.
kErrorNoCodeGenerated,
//! Code generated is too large to fit in memory reserved.
//!
//! Returned by `StaticRuntime` in case that the code generated is too large
//! to fit in the memory already reserved for it.
kErrorCodeTooLarge,
//! Label is already bound.
kErrorLabelAlreadyBound,
//! Unknown instruction (an instruction ID is out of bounds or instruction
//! name is invalid).
kErrorUnknownInst,
//! Illegal instruction.
//!
//! This status code can also be returned in X64 mode if AH, BH, CH or DH
//! registers have been used together with a REX prefix. The instruction
//! is not encodable in such case.
//!
//! Example of raising `kErrorIllegalInst` error.
//!
//! ~~~
//! // Invalid address size.
//! a.mov(dword_ptr(eax), al);
//!
//! // Undecodable instruction - AH used with R10, however R10 can only be
//! // encoded by using REX prefix, which conflicts with AH.
//! a.mov(byte_ptr(r10), ah);
//! ~~~
//!
//! \note In debug mode assertion is raised instead of returning an error.
kErrorIllegalInst,
//! Illegal (unencodable) addressing used.
kErrorIllegalAddresing,
//! Illegal (unencodable) displacement used.
//!
//! X86/X64
//! -------
//!
//! Short form of jump instruction has been used, but the displacement is out
//! of bounds.
kErrorIllegalDisplacement,
//! A variable has been assigned more than once to a function argument (Compiler).
kErrorOverlappedArgs,
//! Count of AsmJit error codes.
kErrorCount
};
//! \} //! \}
// ============================================================================ // ============================================================================
@@ -121,41 +213,74 @@ static const _NoInit NoInit = {};
#endif // !ASMJIT_DOCGEN #endif // !ASMJIT_DOCGEN
// ============================================================================ // ============================================================================
// [asmjit::Assert] // [asmjit::DebugUtils]
// ============================================================================ // ============================================================================
//! \addtogroup asmjit_base_general namespace DebugUtils {
//! Get a printable version of AsmJit `Error` code.
ASMJIT_API const char* errorAsString(Error code);
//! \addtogroup asmjit_base
//! \{ //! \{
//! Called in debug build to output a debugging message caused by assertion
//! failure or tracing.
ASMJIT_API void debugOutput(const char* str);
//! Called in debug build on assertion failure. //! Called in debug build on assertion failure.
//! //!
//! \param exp Expression that failed.
//! \param file Source file name where it happened. //! \param file Source file name where it happened.
//! \param line Line in the source file. //! \param line Line in the source file.
//! \param msg Message to display.
//! //!
//! If you have problems with assertions put a breakpoint at assertionFailed() //! If you have problems with assertions put a breakpoint at assertionFailed()
//! function (asmjit/base/globals.cpp) and check the call stack to locate the //! function (asmjit/base/globals.cpp) and check the call stack to locate the
//! failing code. //! failing code.
ASMJIT_API void assertionFailed(const char* exp, const char* file, int line); ASMJIT_API void assertionFailed(const char* file, int line, const char* msg);
#if defined(ASMJIT_DEBUG)
#define ASMJIT_ASSERT(_Exp_) \
do { \
if (!(_Exp_)) ::asmjit::assertionFailed(#_Exp_, __FILE__, __LINE__); \
} while (0)
#else
#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
#endif // DEBUG
//! \} //! \}
} // DebugUtils namespace
} // asmjit namespace } // asmjit namespace
// ============================================================================
// [ASMJIT_ASSERT]
// ============================================================================
#if defined(ASMJIT_DEBUG)
# define ASMJIT_ASSERT(exp) \
do { \
if (!(exp)) { \
::asmjit::DebugUtils::assertionFailed( \
__FILE__ + ::asmjit::DebugUtils::kSourceRelativePathOffset, \
__LINE__, \
#exp); \
} \
} while (0)
#else
# define ASMJIT_ASSERT(exp) ASMJIT_NOP
#endif // DEBUG
// ============================================================================
// [ASMJIT_PROPAGATE_ERROR]
// ============================================================================
//! \internal
//!
//! Used by AsmJit to return the `_Exp_` result if it's an error.
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
do { \
::asmjit::Error _errval = (_Exp_); \
if (_errval != ::asmjit::kErrorOk) \
return _errval; \
} while (0)
// ============================================================================ // ============================================================================
// [asmjit_cast<>] // [asmjit_cast<>]
// ============================================================================ // ============================================================================
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
//! Cast used to cast pointer to function. It's like reinterpret_cast<>, //! Cast used to cast pointer to function. It's like reinterpret_cast<>,

View File

@@ -0,0 +1,20 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/hlstream.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

1135
src/asmjit/base/hlstream.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,217 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/intutil.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
#if defined(ASMJIT_TEST)
UNIT(base_intutil) {
uint32_t i;
INFO("IntTraits<>.");
EXPECT(IntTraits<signed char>::kIsSigned,
"IntTraits<signed char> should report signed.");
EXPECT(IntTraits<unsigned char>::kIsUnsigned,
"IntTraits<unsigned char> should report unsigned.");
EXPECT(IntTraits<signed short>::kIsSigned,
"IntTraits<signed short> should report signed.");
EXPECT(IntTraits<unsigned short>::kIsUnsigned,
"IntTraits<unsigned short> should report unsigned.");
EXPECT(IntTraits<int>::kIsSigned,
"IntTraits<int> should report signed.");
EXPECT(IntTraits<unsigned int>::kIsUnsigned,
"IntTraits<unsigned int> should report unsigned.");
EXPECT(IntTraits<long>::kIsSigned,
"IntTraits<long> should report signed.");
EXPECT(IntTraits<unsigned long>::kIsUnsigned,
"IntTraits<unsigned long> should report unsigned.");
EXPECT(IntTraits<intptr_t>::kIsSigned,
"IntTraits<intptr_t> should report signed.");
EXPECT(IntTraits<uintptr_t>::kIsUnsigned,
"IntTraits<uintptr_t> should report unsigned.");
EXPECT(IntTraits<intptr_t>::kIsIntPtr,
"IntTraits<intptr_t> should report intptr_t type.");
EXPECT(IntTraits<uintptr_t>::kIsIntPtr,
"IntTraits<uintptr_t> should report intptr_t type.");
INFO("IntUtil::iMin()/iMax().");
EXPECT(IntUtil::iMin<int>(0, -1) == -1,
"IntUtil::iMin<int> should return a minimum value.");
EXPECT(IntUtil::iMin<int>(-1, -2) == -2,
"IntUtil::iMin<int> should return a minimum value.");
EXPECT(IntUtil::iMin<int>(1, 2) == 1,
"IntUtil::iMin<int> should return a minimum value.");
EXPECT(IntUtil::iMax<int>(0, -1) == 0,
"IntUtil::iMax<int> should return a maximum value.");
EXPECT(IntUtil::iMax<int>(-1, -2) == -1,
"IntUtil::iMax<int> should return a maximum value.");
EXPECT(IntUtil::iMax<int>(1, 2) == 2,
"IntUtil::iMax<int> should return a maximum value.");
INFO("IntUtil::inInterval().");
EXPECT(IntUtil::inInterval<int>(11, 10, 20) == true,
"IntUtil::inInterval<int> should return true if inside.");
EXPECT(IntUtil::inInterval<int>(101, 10, 20) == false,
"IntUtil::inInterval<int> should return false if outside.");
INFO("IntUtil::isInt8().");
EXPECT(IntUtil::isInt8(-128) == true,
"IntUtil::isInt8<> should return true if inside.");
EXPECT(IntUtil::isInt8(127) == true,
"IntUtil::isInt8<> should return true if inside.");
EXPECT(IntUtil::isInt8(-129) == false,
"IntUtil::isInt8<> should return false if outside.");
EXPECT(IntUtil::isInt8(128) == false,
"IntUtil::isInt8<> should return false if outside.");
INFO("IntUtil::isUInt8().");
EXPECT(IntUtil::isUInt8(255) == true,
"IntUtil::isUInt8<> should return true if inside.");
EXPECT(IntUtil::isUInt8(256) == false,
"IntUtil::isUInt8<> should return false if outside.");
EXPECT(IntUtil::isUInt8(-1) == false,
"IntUtil::isUInt8<> should return false if negative.");
INFO("IntUtil::isInt16().");
EXPECT(IntUtil::isInt16(-32768) == true,
"IntUtil::isInt16<> should return true if inside.");
EXPECT(IntUtil::isInt16(32767) == true,
"IntUtil::isInt16<> should return true if inside.");
EXPECT(IntUtil::isInt16(-32769) == false,
"IntUtil::isInt16<> should return false if outside.");
EXPECT(IntUtil::isInt16(32768) == false,
"IntUtil::isInt16<> should return false if outside.");
INFO("IntUtil::isUInt16().");
EXPECT(IntUtil::isUInt16(65535) == true,
"IntUtil::isUInt16<> should return true if inside.");
EXPECT(IntUtil::isUInt16(65536) == false,
"IntUtil::isUInt16<> should return false if outside.");
EXPECT(IntUtil::isUInt16(-1) == false,
"IntUtil::isUInt16<> should return false if negative.");
INFO("IntUtil::isInt32().");
EXPECT(IntUtil::isInt32(2147483647) == true,
"IntUtil::isInt32<int> should return true if inside.");
EXPECT(IntUtil::isInt32(-2147483647 - 1) == true,
"IntUtil::isInt32<int> should return true if inside.");
EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(2147483648)) == false,
"IntUtil::isInt32<int> should return false if outside.");
EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false,
"IntUtil::isInt32<int> should return false if outside.");
EXPECT(IntUtil::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false,
"IntUtil::isInt32<int> should return false if outside.");
INFO("IntUtil::isUInt32().");
EXPECT(IntUtil::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true,
"IntUtil::isUInt32<int> should return true if inside.");
EXPECT(IntUtil::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false,
"IntUtil::isUInt32<int> should return false if outside.");
EXPECT(IntUtil::isUInt32(-1) == false,
"IntUtil::isUInt32<int> should return false if negative.");
INFO("IntUtil::isPower2().");
for (i = 0; i < 64; i++) {
EXPECT(IntUtil::isPowerOf2(static_cast<uint64_t>(1) << i) == true,
"IntUtil::isPower2() didn't report power of 2.");
EXPECT(IntUtil::isPowerOf2((static_cast<uint64_t>(1) << i) ^ 0x001101) == false,
"IntUtil::isPower2() didn't report not power of 2.");
}
INFO("IntUtil::mask().");
for (i = 0; i < 32; i++) {
EXPECT(IntUtil::mask(i) == (1 << i),
"IntUtil::mask(%u) should return %X.", i, (1 << i));
}
INFO("IntUtil::bits().");
for (i = 0; i < 32; i++) {
uint32_t expectedBits = 0;
for (uint32_t b = 0; b < i; b++)
expectedBits |= static_cast<uint32_t>(1) << b;
EXPECT(IntUtil::bits(i) == expectedBits,
"IntUtil::bits(%u) should return %X.", i, expectedBits);
}
INFO("IntUtil::hasBit().");
for (i = 0; i < 32; i++) {
EXPECT(IntUtil::hasBit((1 << i), i) == true,
"IntUtil::hasBit(%X, %u) should return true.", (1 << i), i);
}
INFO("IntUtil::bitCount().");
for (i = 0; i < 32; i++) {
EXPECT(IntUtil::bitCount((1 << i)) == 1,
"IntUtil::bitCount(%X) should return true.", (1 << i));
}
EXPECT(IntUtil::bitCount(0x000000F0) == 4, "");
EXPECT(IntUtil::bitCount(0x10101010) == 4, "");
EXPECT(IntUtil::bitCount(0xFF000000) == 8, "");
EXPECT(IntUtil::bitCount(0xFFFFFFF7) == 31, "");
EXPECT(IntUtil::bitCount(0x7FFFFFFF) == 31, "");
INFO("IntUtil::findFirstBit().");
for (i = 0; i < 32; i++) {
EXPECT(IntUtil::findFirstBit((1 << i)) == i,
"IntUtil::findFirstBit(%X) should return %u.", (1 << i), i);
}
INFO("IntUtil::keepNOnesFromRight().");
EXPECT(IntUtil::keepNOnesFromRight(0xF, 1) == 0x1, "");
EXPECT(IntUtil::keepNOnesFromRight(0xF, 2) == 0x3, "");
EXPECT(IntUtil::keepNOnesFromRight(0xF, 3) == 0x7, "");
EXPECT(IntUtil::keepNOnesFromRight(0x5, 2) == 0x5, "");
EXPECT(IntUtil::keepNOnesFromRight(0xD, 2) == 0x5, "");
INFO("IntUtil::isAligned().");
EXPECT(IntUtil::isAligned<size_t>(0xFFFF, 4) == false, "");
EXPECT(IntUtil::isAligned<size_t>(0xFFF4, 4) == true , "");
EXPECT(IntUtil::isAligned<size_t>(0xFFF8, 8) == true , "");
EXPECT(IntUtil::isAligned<size_t>(0xFFF0, 16) == true , "");
INFO("IntUtil::alignTo().");
EXPECT(IntUtil::alignTo<size_t>(0xFFFF, 4) == 0x10000, "");
EXPECT(IntUtil::alignTo<size_t>(0xFFF4, 4) == 0x0FFF4, "");
EXPECT(IntUtil::alignTo<size_t>(0xFFF8, 8) == 0x0FFF8, "");
EXPECT(IntUtil::alignTo<size_t>(0xFFF0, 16) == 0x0FFF0, "");
EXPECT(IntUtil::alignTo<size_t>(0xFFF0, 32) == 0x10000, "");
INFO("IntUtil::alignToPowerOf2().");
EXPECT(IntUtil::alignToPowerOf2<size_t>(0xFFFF) == 0x10000, "");
EXPECT(IntUtil::alignToPowerOf2<size_t>(0xF123) == 0x10000, "");
EXPECT(IntUtil::alignToPowerOf2<size_t>(0x0F00) == 0x01000, "");
EXPECT(IntUtil::alignToPowerOf2<size_t>(0x0100) == 0x00100, "");
EXPECT(IntUtil::alignToPowerOf2<size_t>(0x1001) == 0x02000, "");
INFO("IntUtil::deltaTo().");
EXPECT(IntUtil::deltaTo<size_t>(0xFFFF, 4) == 1, "");
EXPECT(IntUtil::deltaTo<size_t>(0xFFF4, 4) == 0, "");
EXPECT(IntUtil::deltaTo<size_t>(0xFFF8, 8) == 0, "");
EXPECT(IntUtil::deltaTo<size_t>(0xFFF0, 16) == 0, "");
EXPECT(IntUtil::deltaTo<size_t>(0xFFF0, 32) == 16, "");
}
#endif // ASMJIT_TEST
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,131 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_LOCK_H
#define _ASMJIT_BASE_LOCK_H
// [Dependencies - AsmJit]
#include "../build.h"
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <pthread.h>
#endif // ASMJIT_OS_POSIX
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Lock]
// ============================================================================
//! Lock - used in thread-safe code for locking.
struct Lock {
ASMJIT_NO_COPY(Lock)
// --------------------------------------------------------------------------
// [Windows]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
typedef CRITICAL_SECTION Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { InitializeCriticalSection(&_handle); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { DeleteCriticalSection(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { EnterCriticalSection(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { LeaveCriticalSection(&_handle); }
#endif // ASMJIT_OS_WINDOWS
// --------------------------------------------------------------------------
// [Posix]
// --------------------------------------------------------------------------
#if defined(ASMJIT_OS_POSIX)
typedef pthread_mutex_t Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { pthread_mutex_init(&_handle, NULL); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { pthread_mutex_destroy(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { pthread_mutex_lock(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { pthread_mutex_unlock(&_handle); }
#endif // ASMJIT_OS_POSIX
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get handle.
ASMJIT_INLINE Handle& getHandle() {
return _handle;
}
//! \overload
ASMJIT_INLINE const Handle& getHandle() const {
return _handle;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Handle.
Handle _handle;
};
// ============================================================================
// [asmjit::AutoLock]
// ============================================================================
//! Scoped lock.
struct AutoLock {
ASMJIT_NO_COPY(AutoLock)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Autolock `target`, scoped.
ASMJIT_INLINE AutoLock(Lock& target) : _target(target) {
_target.lock();
}
//! Autounlock `target`.
ASMJIT_INLINE ~AutoLock() {
_target.unlock();
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Pointer to target (lock).
Lock& _target;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_LOCK_H

View File

@@ -12,9 +12,9 @@
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGER)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/intutil.h" #include "../base/containers.h"
#include "../base/logger.h" #include "../base/logger.h"
#include "../base/string.h" #include "../base/utils.h"
// [Dependencies - C] // [Dependencies - C]
#include <stdarg.h> #include <stdarg.h>
@@ -30,7 +30,7 @@ namespace asmjit {
bool LogUtil::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) { bool LogUtil::formatLine(StringBuilder& sb, const uint8_t* binData, size_t binLen, size_t dispLen, size_t imLen, const char* comment) {
size_t currentLen = sb.getLength(); size_t currentLen = sb.getLength();
size_t commentLen = comment ? StringUtil::nlen(comment, kMaxCommentLength) : 0; size_t commentLen = comment ? Utils::strLen(comment, kMaxCommentLength) : 0;
ASMJIT_ASSERT(binLen >= dispLen); ASMJIT_ASSERT(binLen >= dispLen);
@@ -119,7 +119,7 @@ void Logger::logBinary(uint32_t style, const void* data, size_t size) {
::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1); ::memcpy(buffer, prefix, ASMJIT_ARRAY_SIZE(prefix) - 1);
while (i) { while (i) {
uint32_t n = static_cast<uint32_t>(IntUtil::iMin<size_t>(i, 16)); uint32_t n = static_cast<uint32_t>(Utils::iMin<size_t>(i, 16));
char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1; char* p = buffer + ASMJIT_ARRAY_SIZE(prefix) - 1;
i -= n; i -= n;
@@ -163,7 +163,7 @@ void Logger::setIndentation(const char* indentation) {
if (!indentation) if (!indentation)
return; return;
size_t length = StringUtil::nlen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1); size_t length = Utils::strLen(indentation, ASMJIT_ARRAY_SIZE(_indentation) - 1);
::memcpy(_indentation, indentation, length); ::memcpy(_indentation, indentation, length);
} }

View File

@@ -12,7 +12,7 @@
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGER)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/string.h" #include "../base/containers.h"
// [Dependencies - C] // [Dependencies - C]
#include <stdarg.h> #include <stdarg.h>
@@ -22,7 +22,7 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -87,7 +87,7 @@ struct LogUtil {
//! //!
//! This class also contain `_enabled` member that can be used to enable //! This class also contain `_enabled` member that can be used to enable
//! or disable logging. //! or disable logging.
struct ASMJIT_VCLASS Logger { struct ASMJIT_VIRTAPI Logger {
ASMJIT_NO_COPY(Logger) ASMJIT_NO_COPY(Logger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -162,7 +162,7 @@ struct ASMJIT_VCLASS Logger {
// ============================================================================ // ============================================================================
//! Logger that can log to standard C `FILE*` stream. //! Logger that can log to standard C `FILE*` stream.
struct ASMJIT_VCLASS FileLogger : public Logger { struct ASMJIT_VIRTAPI FileLogger : public Logger {
ASMJIT_NO_COPY(FileLogger) ASMJIT_NO_COPY(FileLogger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -211,7 +211,7 @@ struct ASMJIT_VCLASS FileLogger : public Logger {
// ============================================================================ // ============================================================================
//! String logger. //! String logger.
struct ASMJIT_VCLASS StringLogger : public Logger { struct ASMJIT_VIRTAPI StringLogger : public Logger {
ASMJIT_NO_COPY(StringLogger) ASMJIT_NO_COPY(StringLogger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@@ -21,16 +21,29 @@ namespace asmjit {
// Prevent static initialization. // Prevent static initialization.
struct Operand { struct Operand {
struct BaseOp {
uint8_t op; uint8_t op;
uint8_t size; uint8_t size;
uint8_t reserved_2_1; uint8_t reserved_2_1;
uint8_t reserved_3_1; uint8_t reserved_3_1;
uint32_t id; uint32_t id;
uint64_t reserved_8_8;
uint32_t reserved_8_4;
uint32_t reserved_12_4;
}; };
ASMJIT_VAR const Operand noOperand; // Kept in union to prevent LTO warnings.
const Operand noOperand = { 0, 0, 0, 0, kInvalidValue, 0 }; union {
BaseOp _base;
// Required to properly align this _fake_ `Operand`, not used.
uint64_t _data[2];
};
};
ASMJIT_VARAPI const Operand noOperand;
const Operand noOperand = {{ 0, 0, 0, 0, kInvalidValue, 0, 0 }};
} // asmjit namespace } // asmjit namespace

View File

@@ -9,7 +9,7 @@
#define _ASMJIT_BASE_OPERAND_H #define _ASMJIT_BASE_OPERAND_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/intutil.h" #include "../base/utils.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -23,7 +23,7 @@ namespace asmjit {
struct Assembler; struct Assembler;
struct Compiler; struct Compiler;
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -125,6 +125,49 @@ ASMJIT_ENUM(MemType) {
kMemTypeRip = 4 kMemTypeRip = 4
}; };
// ============================================================================
// [asmjit::VarType]
// ============================================================================
ASMJIT_ENUM(VarType) {
//! Variable is 8-bit signed integer.
kVarTypeInt8 = 0,
//! Variable is 8-bit unsigned integer.
kVarTypeUInt8 = 1,
//! Variable is 16-bit signed integer.
kVarTypeInt16 = 2,
//! Variable is 16-bit unsigned integer.
kVarTypeUInt16 = 3,
//! Variable is 32-bit signed integer.
kVarTypeInt32 = 4,
//! Variable is 32-bit unsigned integer.
kVarTypeUInt32 = 5,
//! Variable is 64-bit signed integer.
kVarTypeInt64 = 6,
//! Variable is 64-bit unsigned integer.
kVarTypeUInt64 = 7,
//! Variable is target `intptr_t`, compatible with the target's `intptr_t` (not hosts).
kVarTypeIntPtr = 8,
//! Variable is target `uintptr_t`, compatible with the target's `uintptr_t` (not hosts).
kVarTypeUIntPtr = 9,
//! Variable is 32-bit floating point (single precision).
kVarTypeFp32 = 10,
//! Variable is 64-bit floating point (double precision).
kVarTypeFp64 = 11,
//! \internal
_kVarTypeIntStart = kVarTypeInt8,
//! \internal
_kVarTypeIntEnd = kVarTypeUIntPtr,
//! \internal
_kVarTypeFpStart = kVarTypeFp32,
//! \internal
_kVarTypeFpEnd = kVarTypeFp64
};
// ============================================================================ // ============================================================================
// [asmjit::Operand] // [asmjit::Operand]
// ============================================================================ // ============================================================================
@@ -174,7 +217,7 @@ struct Operand {
//! Register type and index access. //! Register type and index access.
struct { struct {
#if defined(ASMJIT_ARCH_LE) #if ASMJIT_ARCH_LE
//! Register index. //! Register index.
uint8_t index; uint8_t index;
//! Register type. //! Register type.
@@ -202,8 +245,7 @@ struct Operand {
//! \internal //! \internal
//! //!
//! This is not needed or used, it's just to force compiler to always //! This is not needed or used, it's just to force compiler to always
//! align this struct to 8-bytes (so the struct is compatible to others //! align this struct to 8-bytes (it should fix LTO warning as well).
//! when it comes to alignment). It should fix VS linker warning as well.
uint64_t reserved8_8; uint64_t reserved8_8;
}; };
}; };
@@ -319,10 +361,8 @@ struct Operand {
// [Operand] // [Operand]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Clone `Operand`. //! Clone the `Operand`.
ASMJIT_INLINE Operand clone() const { ASMJIT_INLINE Operand clone() const { return Operand(*this); }
return Operand(*this);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Init & Copy] // [Init & Copy]
@@ -342,11 +382,11 @@ struct Operand {
// write. Because the 'a', 'b', 'c' and 'd' variables are usually compile // write. Because the 'a', 'b', 'c' and 'd' variables are usually compile
// time constants the compiler can do a really nice job if they are joined // time constants the compiler can do a really nice job if they are joined
// by using bitwise operations. // by using bitwise operations.
_packed[0].setPacked_2x32(IntUtil::pack32_4x8(op, sz, r0, r1), id); _packed[0].setPacked_2x32(Utils::pack32_4x8(op, sz, r0, r1), id);
} }
ASMJIT_INLINE void _init_packed_op_sz_w0_id(uint32_t op, uint32_t sz, uint32_t w0, uint32_t id) { ASMJIT_INLINE void _init_packed_op_sz_w0_id(uint32_t op, uint32_t sz, uint32_t w0, uint32_t id) {
_packed[0].setPacked_2x32(IntUtil::pack32_2x8_1x16(op, sz, w0), id); _packed[0].setPacked_2x32(Utils::pack32_2x8_1x16(op, sz, w0), id);
} }
ASMJIT_INLINE void _init_packed_d0_d1(uint32_t u0, uint32_t u1) { ASMJIT_INLINE void _init_packed_d0_d1(uint32_t u0, uint32_t u1) {
@@ -369,14 +409,10 @@ struct Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
template<typename T> template<typename T>
ASMJIT_INLINE T& getData() { ASMJIT_INLINE T& getData() { return reinterpret_cast<T&>(_base); }
return reinterpret_cast<T&>(_base);
}
template<typename T> template<typename T>
ASMJIT_INLINE const T& getData() const { ASMJIT_INLINE const T& getData() const { return reinterpret_cast<const T&>(_base); }
return reinterpret_cast<const T&>(_base);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Type] // [Type]
@@ -403,23 +439,18 @@ struct Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get register type. //! Get register type.
ASMJIT_INLINE uint32_t getRegType() const { ASMJIT_INLINE uint32_t getRegType() const { return _vreg.type; }
return _vreg.type;
}
//! Get register index. //! Get register index.
ASMJIT_INLINE uint32_t getRegIndex() const { ASMJIT_INLINE uint32_t getRegIndex() const { return _vreg.index; }
return _vreg.index;
}
//! Get whether the operand is register of `type`. //! Get whether the operand is register of `type`.
ASMJIT_INLINE bool isRegType(uint32_t type) const { ASMJIT_INLINE bool isRegType(uint32_t type) const {
return (_packed[0].u32[0] & IntUtil::pack32_2x8_1x16(0xFF, 0, 0xFF00)) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8)); return (_packed[0].u32[0] & Utils::pack32_2x8_1x16(0xFF, 0, 0xFF00)) == Utils::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8));
} }
//! Get whether the operand is register and of `type` and `index`. //! Get whether the operand is register and of `type` and `index`.
ASMJIT_INLINE bool isRegCode(uint32_t type, uint32_t index) const { ASMJIT_INLINE bool isRegCode(uint32_t type, uint32_t index) const {
return (_packed[0].u32[0] & IntUtil::pack32_2x8_1x16(0xFF, 0, 0xFFFF)) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8) + index); return (_packed[0].u32[0] & Utils::pack32_2x8_1x16(0xFF, 0, 0xFFFF)) == Utils::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8) + index);
} }
//! Get whether the operand is a register or memory. //! Get whether the operand is a register or memory.
@@ -441,9 +472,7 @@ struct Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get size of the operand in bytes. //! Get size of the operand in bytes.
ASMJIT_INLINE uint32_t getSize() const { ASMJIT_INLINE uint32_t getSize() const { return _base.size; }
return _base.size;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Id] // [Id]
@@ -455,9 +484,7 @@ struct Operand {
//! //!
//! There is no way to change or remove operand id. Unneeded operands can be //! There is no way to change or remove operand id. Unneeded operands can be
//! simply reassigned by `operator=`. //! simply reassigned by `operator=`.
ASMJIT_INLINE uint32_t getId() const { ASMJIT_INLINE uint32_t getId() const { return _base.id; }
return _base.id;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -763,19 +790,19 @@ struct Imm : public Operand {
} }
//! Get whether the immediate can be casted to 8-bit signed integer. //! Get whether the immediate can be casted to 8-bit signed integer.
ASMJIT_INLINE bool isInt8() const { return IntUtil::isInt8(_imm.value._i64[0]); } ASMJIT_INLINE bool isInt8() const { return Utils::isInt8(_imm.value._i64[0]); }
//! Get whether the immediate can be casted to 8-bit unsigned integer. //! Get whether the immediate can be casted to 8-bit unsigned integer.
ASMJIT_INLINE bool isUInt8() const { return IntUtil::isUInt8(_imm.value._i64[0]); } ASMJIT_INLINE bool isUInt8() const { return Utils::isUInt8(_imm.value._i64[0]); }
//! Get whether the immediate can be casted to 16-bit signed integer. //! Get whether the immediate can be casted to 16-bit signed integer.
ASMJIT_INLINE bool isInt16() const { return IntUtil::isInt16(_imm.value._i64[0]); } ASMJIT_INLINE bool isInt16() const { return Utils::isInt16(_imm.value._i64[0]); }
//! Get whether the immediate can be casted to 16-bit unsigned integer. //! Get whether the immediate can be casted to 16-bit unsigned integer.
ASMJIT_INLINE bool isUInt16() const { return IntUtil::isUInt16(_imm.value._i64[0]); } ASMJIT_INLINE bool isUInt16() const { return Utils::isUInt16(_imm.value._i64[0]); }
//! Get whether the immediate can be casted to 32-bit signed integer. //! Get whether the immediate can be casted to 32-bit signed integer.
ASMJIT_INLINE bool isInt32() const { return IntUtil::isInt32(_imm.value._i64[0]); } ASMJIT_INLINE bool isInt32() const { return Utils::isInt32(_imm.value._i64[0]); }
//! Get whether the immediate can be casted to 32-bit unsigned integer. //! Get whether the immediate can be casted to 32-bit unsigned integer.
ASMJIT_INLINE bool isUInt32() const { return IntUtil::isUInt32(_imm.value._i64[0]); } ASMJIT_INLINE bool isUInt32() const { return Utils::isUInt32(_imm.value._i64[0]); }
//! Get immediate value as 8-bit signed integer. //! Get immediate value as 8-bit signed integer.
ASMJIT_INLINE int8_t getInt8() const { return _imm.value._i8[_ASMJIT_ARCH_INDEX(8, 0)]; } ASMJIT_INLINE int8_t getInt8() const { return _imm.value._i8[_ASMJIT_ARCH_INDEX(8, 0)]; }
@@ -1046,9 +1073,7 @@ struct Label : public Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the label has been initialized by `Assembler` or `Compiler`. //! Get whether the label has been initialized by `Assembler` or `Compiler`.
ASMJIT_INLINE bool isInitialized() const { ASMJIT_INLINE bool isInitialized() const { return _label.id != kInvalidValue; }
return _label.id != kInvalidValue;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Operator Overload] // [Operator Overload]
@@ -1060,29 +1085,70 @@ struct Label : public Operand {
ASMJIT_INLINE bool operator!=(const Label& other) const { return _base.id != other._base.id; } ASMJIT_INLINE bool operator!=(const Label& other) const { return _base.id != other._base.id; }
}; };
// ============================================================================
// [asmjit::Var]
// ============================================================================
#if !defined(ASMJIT_DISABLE_COMPILER)
//! Base class for all variables.
struct Var : public Operand {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE Var() : Operand(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeVar, 0, 0, 0, kInvalidValue);
_init_packed_d2_d3(kInvalidValue, kInvalidValue);
}
ASMJIT_INLINE Var(const Var& other) : Operand(other) {}
explicit ASMJIT_INLINE Var(const _NoInit&) : Operand(NoInit) {}
// --------------------------------------------------------------------------
// [Var Specific]
// --------------------------------------------------------------------------
//! Clone `Var` operand.
ASMJIT_INLINE Var clone() const { return Var(*this); }
//! Reset Var operand.
ASMJIT_INLINE void reset() {
_init_packed_op_sz_b0_b1_id(kOperandTypeVar, 0, kInvalidReg, kInvalidReg, kInvalidValue);
_init_packed_d2_d3(kInvalidValue, kInvalidValue);
}
//! Get whether the variable has been initialized by `Compiler`.
ASMJIT_INLINE bool isInitialized() const { return _vreg.id != kInvalidValue; }
//! Get variable type.
ASMJIT_INLINE uint32_t getVarType() const { return _vreg.vType; }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE Var& operator=(const Var& other) { _copy(other); return *this; }
ASMJIT_INLINE bool operator==(const Var& other) const { return _packed[0] == other._packed[0]; }
ASMJIT_INLINE bool operator!=(const Var& other) const { return !operator==(other); }
};
#endif // !ASMJIT_DISABLE_COMPILER
// ============================================================================ // ============================================================================
// [asmjit::Operand - Globals] // [asmjit::Operand - Globals]
// ============================================================================ // ============================================================================
//! No operand, can be used to reset an operand by assignment or to refer to an //! No operand, can be used to reset an operand by assignment or to refer to an
//! operand that doesn't exist. //! operand that doesn't exist.
ASMJIT_VAR const Operand noOperand; ASMJIT_VARAPI const Operand noOperand;
//! Create signed immediate value operand. //! Create a signed immediate operand.
static ASMJIT_INLINE Imm imm(int64_t val) { static ASMJIT_INLINE Imm imm(int64_t val) { return Imm(val); }
return Imm(val); //! Create an unsigned immediate operand.
} static ASMJIT_INLINE Imm imm_u(uint64_t val) { return Imm(static_cast<int64_t>(val)); }
//! Create a `void*` immediate operand.
//! Create unsigned immediate value operand.
static ASMJIT_INLINE Imm imm_u(uint64_t val) {
return Imm(static_cast<int64_t>(val));
}
//! Create a `void*` immediate value operand.
template<typename T> template<typename T>
static ASMJIT_INLINE Imm imm_ptr(T p) { static ASMJIT_INLINE Imm imm_ptr(T p) { return Imm(static_cast<int64_t>((intptr_t)p)); }
return Imm(static_cast<int64_t>((intptr_t)p));
}
//! \} //! \}

View File

@@ -10,7 +10,6 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/assembler.h" #include "../base/assembler.h"
#include "../base/cpuinfo.h" #include "../base/cpuinfo.h"
#include "../base/error.h"
#include "../base/runtime.h" #include "../base/runtime.h"
// [Api-Begin] // [Api-Begin]
@@ -24,24 +23,19 @@ namespace asmjit {
Runtime::Runtime() { Runtime::Runtime() {
_sizeLimit = 0; _sizeLimit = 0;
_baseAddress = kNoBaseAddress;
_runtimeType = kRuntimeTypeNone; _runtimeType = kRuntimeTypeNone;
_allocType = kVMemAllocFreeable; _allocType = kVMemAllocFreeable;
::memset(_reserved, 0, sizeof(_reserved)); ::memset(_reserved, 0, sizeof(_reserved));
_baseAddress = kNoBaseAddress;
} }
Runtime::~Runtime() {} Runtime::~Runtime() {}
// ============================================================================ // ============================================================================
// [asmjit::HostRuntime - Construction / Destruction] // [asmjit::HostRuntime - Construction / Destruction]
// ============================================================================ // ============================================================================
HostRuntime::HostRuntime() { HostRuntime::HostRuntime() { _runtimeType = kRuntimeTypeJit; }
_runtimeType = kRuntimeTypeJit;
}
HostRuntime::~HostRuntime() {} HostRuntime::~HostRuntime() {}
// ============================================================================ // ============================================================================
@@ -55,21 +49,11 @@ const CpuInfo* HostRuntime::getCpuInfo() {
uint32_t HostRuntime::getStackAlignment() { uint32_t HostRuntime::getStackAlignment() {
uint32_t alignment = sizeof(intptr_t); uint32_t alignment = sizeof(intptr_t);
#if defined(ASMJIT_ARCH_X86)
// Modern Linux, APPLE and UNIX guarantees 16-byte stack alignment, but I'm // Modern Linux, APPLE and UNIX guarantees 16-byte stack alignment, but I'm
// not sure about all other UNIX operating systems, because 16-byte alignment // not sure about all other UNIX operating systems, because 16-byte alignment
// is addition to an older specification. // is addition to an older specification.
# if (defined(__linux__) || \ #if (ASMJIT_ARCH_X64) || \
defined(__linux) || \ (ASMJIT_ARCH_X86 && (ASMJIT_OS_LINUX || ASMJIT_OS_BSD || ASMJIT_OS_MAC))
defined(__unix__) || \
defined(__FreeBSD__) || \
defined(__NetBSD__) || \
defined(__OpenBSD__) || \
defined(__DARWIN__) || \
defined(__APPLE__) )
alignment = 16;
# endif
#elif defined(ASMJIT_ARCH_X64)
alignment = 16; alignment = 16;
#endif #endif
@@ -78,10 +62,10 @@ uint32_t HostRuntime::getStackAlignment() {
void HostRuntime::flush(void* p, size_t size) { void HostRuntime::flush(void* p, size_t size) {
// Only useful on non-x86 architectures. // Only useful on non-x86 architectures.
#if !defined(ASMJIT_ARCH_X86) && !defined(ASMJIT_ARCH_X64) #if !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64
// Windows has built-in support in kernel32.dll. // Windows has built-in support in kernel32.dll.
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
::FlushInstructionCache(_memMgr.getProcessHandle(), p, size); ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size);
#endif // ASMJIT_OS_WINDOWS #endif // ASMJIT_OS_WINDOWS
@@ -96,7 +80,6 @@ StaticRuntime::StaticRuntime(void* baseAddress, size_t sizeLimit) {
_sizeLimit = sizeLimit; _sizeLimit = sizeLimit;
_baseAddress = static_cast<Ptr>((uintptr_t)baseAddress); _baseAddress = static_cast<Ptr>((uintptr_t)baseAddress);
} }
StaticRuntime::~StaticRuntime() {} StaticRuntime::~StaticRuntime() {}
// ============================================================================ // ============================================================================

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_RUNTIME_H #define _ASMJIT_BASE_RUNTIME_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/vmem.h" #include "../base/vmem.h"
// [Api-Begin] // [Api-Begin]
@@ -24,7 +23,7 @@ namespace asmjit {
struct Assembler; struct Assembler;
struct CpuInfo; struct CpuInfo;
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -42,7 +41,7 @@ ASMJIT_ENUM(RuntimeType) {
// ============================================================================ // ============================================================================
//! Base runtime. //! Base runtime.
struct ASMJIT_VCLASS Runtime { struct ASMJIT_VIRTAPI Runtime {
ASMJIT_NO_COPY(Runtime) ASMJIT_NO_COPY(Runtime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -59,21 +58,12 @@ struct ASMJIT_VCLASS Runtime {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get runtime type. //! Get runtime type.
ASMJIT_INLINE uint32_t getRuntimeType() const { ASMJIT_INLINE uint32_t getRuntimeType() const { return _runtimeType; }
return _runtimeType;
}
//! Get whether the runtime has a base address. //! Get whether the runtime has a base address.
//! ASMJIT_INLINE bool hasBaseAddress() const { return _baseAddress != kNoBaseAddress; }
//! \sa \ref getBaseAddress()
ASMJIT_INLINE bool hasBaseAddress() const {
return _baseAddress == kNoBaseAddress;
}
//! Get the base address. //! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const { ASMJIT_INLINE Ptr getBaseAddress() const { return _baseAddress; }
return _baseAddress;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Interface] // [Interface]
@@ -118,7 +108,7 @@ struct ASMJIT_VCLASS Runtime {
// ============================================================================ // ============================================================================
//! Base runtime for JIT code generation. //! Base runtime for JIT code generation.
struct ASMJIT_VCLASS HostRuntime : public Runtime { struct ASMJIT_VIRTAPI HostRuntime : public Runtime {
ASMJIT_NO_COPY(HostRuntime) ASMJIT_NO_COPY(HostRuntime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -159,7 +149,7 @@ struct ASMJIT_VCLASS HostRuntime : public Runtime {
//! //!
//! JIT static runtime can be used to generate code to a memory location that //! JIT static runtime can be used to generate code to a memory location that
//! is known. //! is known.
struct ASMJIT_VCLASS StaticRuntime : public HostRuntime { struct ASMJIT_VIRTAPI StaticRuntime : public HostRuntime {
ASMJIT_NO_COPY(StaticRuntime) ASMJIT_NO_COPY(StaticRuntime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -181,15 +171,12 @@ struct ASMJIT_VCLASS StaticRuntime : public HostRuntime {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get the base address. //! Get the base address.
ASMJIT_INLINE Ptr getBaseAddress() const { ASMJIT_INLINE Ptr getBaseAddress() const { return _baseAddress; }
return _baseAddress;
}
//! Get the maximum size of the code that can be relocated to the target //! Get the maximum size of the code that can be relocated/stored in the target.
//! address or zero if unlimited. //!
ASMJIT_INLINE size_t getSizeLimit() const { //! Returns zero if unlimited.
return _sizeLimit; ASMJIT_INLINE size_t getSizeLimit() const { return _sizeLimit; }
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Interface] // [Interface]
@@ -204,7 +191,7 @@ struct ASMJIT_VCLASS StaticRuntime : public HostRuntime {
// ============================================================================ // ============================================================================
//! JIT runtime. //! JIT runtime.
struct ASMJIT_VCLASS JitRuntime : public HostRuntime { struct ASMJIT_VIRTAPI JitRuntime : public HostRuntime {
ASMJIT_NO_COPY(JitRuntime) ASMJIT_NO_COPY(JitRuntime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -221,19 +208,12 @@ struct ASMJIT_VCLASS JitRuntime : public HostRuntime {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get the type of allocation. //! Get the type of allocation.
ASMJIT_INLINE uint32_t getAllocType() const { ASMJIT_INLINE uint32_t getAllocType() const { return _allocType; }
return _allocType;
}
//! Set the type of allocation. //! Set the type of allocation.
ASMJIT_INLINE void setAllocType(uint32_t allocType) { ASMJIT_INLINE void setAllocType(uint32_t allocType) { _allocType = allocType; }
_allocType = allocType;
}
//! Get the virtual memory manager. //! Get the virtual memory manager.
ASMJIT_INLINE VMemMgr* getMemMgr() const { ASMJIT_INLINE VMemMgr* getMemMgr() const { return const_cast<VMemMgr*>(&_memMgr); }
return const_cast<VMemMgr*>(&_memMgr);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Interface] // [Interface]

View File

@@ -1,374 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/intutil.h"
#include "../base/string.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// Should be placed in read-only memory.
static const char StringBuilder_empty[4] = { 0 };
// ============================================================================
// [asmjit::StringBuilder - Construction / Destruction]
// ============================================================================
StringBuilder::StringBuilder() :
_data(const_cast<char*>(StringBuilder_empty)),
_length(0),
_capacity(0),
_canFree(false) {}
StringBuilder::~StringBuilder() {
if (_canFree)
ASMJIT_FREE(_data);
}
// ============================================================================
// [asmjit::StringBuilder - Prepare / Reserve]
// ============================================================================
char* StringBuilder::prepare(uint32_t op, size_t len) {
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
if (op == kStringOpSet) {
// We don't care here, but we can't return a NULL pointer since it indicates
// failure in memory allocation.
if (len == 0) {
if (_data != StringBuilder_empty)
_data[0] = 0;
_length = 0;
return _data;
}
if (_capacity < len) {
if (len >= IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2)
return NULL;
size_t to = IntUtil::alignTo<size_t>(len, sizeof(intptr_t));
if (to < 256 - sizeof(intptr_t))
to = 256 - sizeof(intptr_t);
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL) {
clear();
return NULL;
}
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
}
_data[len] = 0;
_length = len;
ASMJIT_ASSERT(_length <= _capacity);
return _data;
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
else {
// We don't care here, but we can't return a NULL pointer since it indicates
// failure in memory allocation.
if (len == 0)
return _data + _length;
// Overflow.
if (IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2 - _length < len)
return NULL;
size_t after = _length + len;
if (_capacity < after) {
size_t to = _capacity;
if (to < 256)
to = 256;
while (to < 1024 * 1024 && to < after)
to *= 2;
if (to < after) {
to = after;
if (to < (IntUtil::maxUInt<size_t>() - 1024 * 32))
to = IntUtil::alignTo<size_t>(to, 1024 * 32);
}
to = IntUtil::alignTo<size_t>(to, sizeof(intptr_t));
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL)
return NULL;
::memcpy(newData, _data, _length);
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
}
char* ret = _data + _length;
_data[after] = 0;
_length = after;
ASMJIT_ASSERT(_length <= _capacity);
return ret;
}
}
bool StringBuilder::reserve(size_t to) {
if (_capacity >= to)
return true;
if (to >= IntUtil::maxUInt<size_t>() - sizeof(intptr_t) * 2)
return false;
to = IntUtil::alignTo<size_t>(to, sizeof(intptr_t));
char* newData = static_cast<char*>(ASMJIT_ALLOC(to + sizeof(intptr_t)));
if (newData == NULL)
return false;
::memcpy(newData, _data, _length + 1);
if (_canFree)
ASMJIT_FREE(_data);
_data = newData;
_capacity = to + sizeof(intptr_t) - 1;
_canFree = true;
return true;
}
// ============================================================================
// [asmjit::StringBuilder - Clear]
// ============================================================================
void StringBuilder::clear() {
if (_data != StringBuilder_empty)
_data[0] = 0;
_length = 0;
}
// ============================================================================
// [asmjit::StringBuilder - Methods]
// ============================================================================
bool StringBuilder::_opString(uint32_t op, const char* str, size_t len) {
if (len == kInvalidIndex)
len = str != NULL ? ::strlen(str) : static_cast<size_t>(0);
char* p = prepare(op, len);
if (p == NULL)
return false;
::memcpy(p, str, len);
return true;
}
bool StringBuilder::_opChar(uint32_t op, char c) {
char* p = prepare(op, 1);
if (p == NULL)
return false;
*p = c;
return true;
}
bool StringBuilder::_opChars(uint32_t op, char c, size_t len) {
char* p = prepare(op, len);
if (p == NULL)
return false;
::memset(p, c, len);
return true;
}
static const char StringBuilder_numbers[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
bool StringBuilder::_opNumber(uint32_t op, uint64_t i, uint32_t base, size_t width, uint32_t flags) {
if (base < 2 || base > 36)
base = 10;
char buf[128];
char* p = buf + ASMJIT_ARRAY_SIZE(buf);
uint64_t orig = i;
char sign = '\0';
// --------------------------------------------------------------------------
// [Sign]
// --------------------------------------------------------------------------
if ((flags & kStringFormatSigned) != 0 && static_cast<int64_t>(i) < 0) {
i = static_cast<uint64_t>(-static_cast<int64_t>(i));
sign = '-';
}
else if ((flags & kStringFormatShowSign) != 0) {
sign = '+';
}
else if ((flags & kStringFormatShowSpace) != 0) {
sign = ' ';
}
// --------------------------------------------------------------------------
// [Number]
// --------------------------------------------------------------------------
do {
uint64_t d = i / base;
uint64_t r = i % base;
*--p = StringBuilder_numbers[r];
i = d;
} while (i);
size_t numberLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p);
// --------------------------------------------------------------------------
// [Alternate Form]
// --------------------------------------------------------------------------
if ((flags & kStringFormatAlternate) != 0) {
if (base == 8) {
if (orig != 0)
*--p = '0';
}
if (base == 16) {
*--p = 'x';
*--p = '0';
}
}
// --------------------------------------------------------------------------
// [Width]
// --------------------------------------------------------------------------
if (sign != 0)
*--p = sign;
if (width > 256)
width = 256;
if (width <= numberLength)
width = 0;
else
width -= numberLength;
// --------------------------------------------------------------------------
// Write]
// --------------------------------------------------------------------------
size_t prefixLength = (size_t)(buf + ASMJIT_ARRAY_SIZE(buf) - p) - numberLength;
char* data = prepare(op, prefixLength + width + numberLength);
if (data == NULL)
return false;
::memcpy(data, p, prefixLength);
data += prefixLength;
::memset(data, '0', width);
data += width;
::memcpy(data, p + prefixLength, numberLength);
return true;
}
bool StringBuilder::_opHex(uint32_t op, const void* data, size_t len) {
if (len >= IntUtil::maxUInt<size_t>() / 2)
return false;
char* dst = prepare(op, len * 2);
if (dst == NULL)
return false;
const char* src = static_cast<const char*>(data);
for (size_t i = 0; i < len; i++, dst += 2, src += 1)
{
dst[0] = StringBuilder_numbers[(src[0] >> 4) & 0xF];
dst[1] = StringBuilder_numbers[(src[0] ) & 0xF];
}
return true;
}
bool StringBuilder::_opVFormat(uint32_t op, const char* fmt, va_list ap) {
char buf[1024];
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
return _opString(op, buf);
}
bool StringBuilder::setFormat(const char* fmt, ...) {
bool result;
va_list ap;
va_start(ap, fmt);
result = _opVFormat(kStringOpSet, fmt, ap);
va_end(ap);
return result;
}
bool StringBuilder::appendFormat(const char* fmt, ...) {
bool result;
va_list ap;
va_start(ap, fmt);
result = _opVFormat(kStringOpAppend, fmt, ap);
va_end(ap);
return result;
}
bool StringBuilder::eq(const char* str, size_t len) const {
const char* aData = _data;
const char* bData = str;
size_t aLength = _length;
size_t bLength = len;
if (bLength == kInvalidIndex) {
size_t i;
for (i = 0; i < aLength; i++) {
if (aData[i] != bData[i] || bData[i] == 0)
return false;
}
return bData[i] == 0;
}
else {
if (aLength != bLength)
return false;
return ::memcmp(aData, bData, aLength) == 0;
}
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,372 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_STRING_H
#define _ASMJIT_BASE_STRING_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Dependencies - C]
#include <stdarg.h>
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::StringOp]
// ============================================================================
//! \internal
//!
//! String operation.
ASMJIT_ENUM(StringOp) {
//! Replace the current string by a given content.
kStringOpSet = 0,
//! Append a given content to the current string.
kStringOpAppend = 1
};
// ============================================================================
// [asmjit::StringFormatFlags]
// ============================================================================
//! \internal
//!
//! String format flags.
ASMJIT_ENUM(StringFormatFlags) {
kStringFormatShowSign = 0x00000001,
kStringFormatShowSpace = 0x00000002,
kStringFormatAlternate = 0x00000004,
kStringFormatSigned = 0x80000000
};
// ============================================================================
// [asmjit::StringUtil]
// ============================================================================
//! String utilities.
struct StringUtil {
static ASMJIT_INLINE size_t nlen(const char* s, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++)
if (!s[i])
break;
return i;
}
};
// ============================================================================
// [asmjit::StringBuilder]
// ============================================================================
//! String builder.
//!
//! String builder was designed to be able to build a string using append like
//! operation to append numbers, other strings, or signle characters. It can
//! allocate it's own buffer or use a buffer created on the stack.
//!
//! String builder contains method specific to AsmJit functionality, used for
//! logging or HTML output.
struct StringBuilder {
ASMJIT_NO_COPY(StringBuilder)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API StringBuilder();
ASMJIT_API ~StringBuilder();
ASMJIT_INLINE StringBuilder(const _NoInit&) {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get string builder capacity.
ASMJIT_INLINE size_t getCapacity() const { return _capacity; }
//! Get length.
ASMJIT_INLINE size_t getLength() const { return _length; }
//! Get null-terminated string data.
ASMJIT_INLINE char* getData() { return _data; }
//! Get null-terminated string data (const).
ASMJIT_INLINE const char* getData() const { return _data; }
// --------------------------------------------------------------------------
// [Prepare / Reserve]
// --------------------------------------------------------------------------
//! Prepare to set/append.
ASMJIT_API char* prepare(uint32_t op, size_t len);
//! Reserve `to` bytes in string builder.
ASMJIT_API bool reserve(size_t to);
// --------------------------------------------------------------------------
// [Clear]
// --------------------------------------------------------------------------
//! Clear the content in String builder.
ASMJIT_API void clear();
// --------------------------------------------------------------------------
// [Op]
// --------------------------------------------------------------------------
ASMJIT_API bool _opString(uint32_t op, const char* str, size_t len = kInvalidIndex);
ASMJIT_API bool _opVFormat(uint32_t op, const char* fmt, va_list ap);
ASMJIT_API bool _opChar(uint32_t op, char c);
ASMJIT_API bool _opChars(uint32_t op, char c, size_t len);
ASMJIT_API bool _opNumber(uint32_t op, uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0);
ASMJIT_API bool _opHex(uint32_t op, const void* data, size_t len);
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
//! Replace the current content by `str` of `len`.
ASMJIT_INLINE bool setString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpSet, str, len);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_INLINE bool setVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpSet, fmt, ap);
}
//! Replace the current content by formatted string `fmt`.
ASMJIT_API bool setFormat(const char* fmt, ...);
//! Replace the current content by `c` character.
ASMJIT_INLINE bool setChar(char c) {
return _opChar(kStringOpSet, c);
}
//! Replace the current content by `c` of `len`.
ASMJIT_INLINE bool setChars(char c, size_t len) {
return _opChars(kStringOpSet, c, len);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags | kStringFormatSigned);
}
//! Replace the current content by formatted integer `i`.
ASMJIT_INLINE bool setUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpSet, i, base, width, flags);
}
//! Replace the current content by the given `data` converted to a HEX string.
ASMJIT_INLINE bool setHex(const void* data, size_t len) {
return _opHex(kStringOpSet, data, len);
}
// --------------------------------------------------------------------------
// [Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`.
ASMJIT_INLINE bool appendString(const char* str, size_t len = kInvalidIndex) {
return _opString(kStringOpAppend, str, len);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_INLINE bool appendVFormat(const char* fmt, va_list ap) {
return _opVFormat(kStringOpAppend, fmt, ap);
}
//! Append a formatted string `fmt` to the current content.
ASMJIT_API bool appendFormat(const char* fmt, ...);
//! Append `c` character.
ASMJIT_INLINE bool appendChar(char c) {
return _opChar(kStringOpAppend, c);
}
//! Append `c` of `len`.
ASMJIT_INLINE bool appendChars(char c, size_t len) {
return _opChars(kStringOpAppend, c, len);
}
//! Append `i`.
ASMJIT_INLINE bool appendInt(int64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, static_cast<uint64_t>(i), base, width, flags | kStringFormatSigned);
}
//! Append `i`.
ASMJIT_INLINE bool appendUInt(uint64_t i, uint32_t base = 0, size_t width = 0, uint32_t flags = 0) {
return _opNumber(kStringOpAppend, i, base, width, flags);
}
//! Append the given `data` converted to a HEX string.
ASMJIT_INLINE bool appendHex(const void* data, size_t len) {
return _opHex(kStringOpAppend, data, len);
}
// --------------------------------------------------------------------------
// [_Append]
// --------------------------------------------------------------------------
//! Append `str` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendString(const char* str, size_t len = kInvalidIndex) {
// len should be a constant if we are inlining.
if (len == kInvalidIndex) {
char* p = &_data[_length];
while (*str) {
ASMJIT_ASSERT(p < _data + _capacity);
*p++ = *str++;
}
*p = '\0';
_length = (size_t)(p - _data);
}
else {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = *str++;
*p = '\0';
_length += len;
}
}
//! Append `c` character, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChar(char c) {
ASMJIT_ASSERT(_capacity - _length >= 1);
_data[_length] = c;
_length++;
_data[_length] = '\0';
}
//! Append `c` of `len`, inlined, without buffer overflow check.
ASMJIT_INLINE void _appendChars(char c, size_t len) {
ASMJIT_ASSERT(_capacity - _length >= len);
char* p = &_data[_length];
char* pEnd = p + len;
while (p < pEnd)
*p++ = c;
*p = '\0';
_length += len;
}
ASMJIT_INLINE void _appendUInt32(uint32_t i) {
char buf_[32];
char* pEnd = buf_ + ASMJIT_ARRAY_SIZE(buf_);
char* pBuf = pEnd;
do {
uint32_t d = i / 10;
uint32_t r = i % 10;
*--pBuf = static_cast<uint8_t>(r + '0');
i = d;
} while (i);
ASMJIT_ASSERT(_capacity - _length >= (size_t)(pEnd - pBuf));
char* p = &_data[_length];
do {
*p++ = *pBuf;
} while (++pBuf != pEnd);
*p = '\0';
_length = (size_t)(p - _data);
}
// --------------------------------------------------------------------------
// [Eq]
// --------------------------------------------------------------------------
//! Check for equality with other `str` of `len`.
ASMJIT_API bool eq(const char* str, size_t len = kInvalidIndex) const;
//! Check for equality with `other`.
ASMJIT_INLINE bool eq(const StringBuilder& other) const {
return eq(other._data);
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool operator==(const StringBuilder& other) const { return eq(other); }
ASMJIT_INLINE bool operator!=(const StringBuilder& other) const { return !eq(other); }
ASMJIT_INLINE bool operator==(const char* str) const { return eq(str); }
ASMJIT_INLINE bool operator!=(const char* str) const { return !eq(str); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! String data.
char* _data;
//! Length.
size_t _length;
//! Capacity.
size_t _capacity;
//! Whether the string can be freed.
size_t _canFree;
};
// ============================================================================
// [asmjit::StringBuilderT]
// ============================================================================
//! \internal
template<size_t N>
struct StringBuilderT : public StringBuilder {
ASMJIT_NO_COPY(StringBuilderT<N>)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE StringBuilderT() : StringBuilder(NoInit) {
_data = _embeddedData;
_data[0] = 0;
_length = 0;
_capacity = N;
_canFree = false;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Embedded data.
char _embeddedData[static_cast<size_t>(
N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)];
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_STRING_H

291
src/asmjit/base/utils.cpp Normal file
View File

@@ -0,0 +1,291 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/utils.h"
// [Dependencies - Posix]
#if ASMJIT_OS_POSIX
# include <time.h>
# include <unistd.h>
#endif // ASMJIT_OS_POSIX
// [Dependencies - Mac]
#if ASMJIT_OS_MAC
# include <mach/mach_time.h>
#endif // ASMJIT_OS_MAC
// [Dependencies - Windows]
#if ASMJIT_OS_WINDOWS
// `_InterlockedCompareExchange` is only available as intrinsic (MS Compiler).
# if defined(_MSC_VER) && _MSC_VER >= 1400
# include <intrin.h>
# pragma intrinsic(_InterlockedCompareExchange)
# else
# define _InterlockedCompareExchange InterlockedCompareExchange
# endif // _MSC_VER
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CpuTicks - Windows]
// ============================================================================
#if ASMJIT_OS_WINDOWS
static volatile uint32_t Utils_hiResTicks;
static volatile double Utils_hiResFreq;
uint32_t Utils::getTickCount() {
do {
uint32_t hiResOk = Utils_hiResTicks;
if (hiResOk == 1) {
LARGE_INTEGER now;
if (!::QueryPerformanceCounter(&now))
break;
return (int64_t)(double(now.QuadPart) / Utils_hiResFreq);
}
if (hiResOk == 0) {
LARGE_INTEGER qpf;
if (!::QueryPerformanceFrequency(&qpf)) {
_InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 0xFFFFFFFF, 0);
break;
}
LARGE_INTEGER now;
if (!::QueryPerformanceCounter(&now)) {
_InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 0xFFFFFFFF, 0);
break;
}
double freqDouble = double(qpf.QuadPart) / 1000.0;
Utils_hiResFreq = freqDouble;
_InterlockedCompareExchange((LONG*)&Utils_hiResTicks, 1, 0);
return static_cast<uint32_t>(
static_cast<int64_t>(double(now.QuadPart) / freqDouble) & 0xFFFFFFFF);
}
} while (0);
// Bail to a less precise GetTickCount().
return ::GetTickCount();
}
// ============================================================================
// [asmjit::CpuTicks - Mac]
// ============================================================================
#elif ASMJIT_OS_MAC
static mach_timebase_info_data_t CpuTicks_machTime;
uint32_t Utils::getTickCount() {
// Initialize the first time CpuTicks::now() is called (See Apple's QA1398).
if (CpuTicks_machTime.denom == 0) {
if (mach_timebase_info(&CpuTicks_machTime) != KERN_SUCCESS)
return 0;
}
// mach_absolute_time() returns nanoseconds, we need just milliseconds.
uint64_t t = mach_absolute_time() / 1000000;
t = t * CpuTicks_machTime.numer / CpuTicks_machTime.denom;
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
}
// ============================================================================
// [asmjit::CpuTicks - Posix]
// ============================================================================
#else
uint32_t Utils::getTickCount() {
#if defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
struct timespec ts;
if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
return 0;
uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
return static_cast<uint32_t>(t & 0xFFFFFFFFU);
#else // _POSIX_MONOTONIC_CLOCK
#error "[asmjit] Utils::getTickCount() is not implemented for your target OS."
return 0;
#endif // _POSIX_MONOTONIC_CLOCK
}
#endif // ASMJIT_OS
#if defined(ASMJIT_TEST)
UNIT(base_utils) {
uint32_t i;
INFO("IntTraits<>.");
EXPECT(IntTraits<signed char>::kIsSigned,"IntTraits<signed char> should report signed.");
EXPECT(IntTraits<short>::kIsSigned, "IntTraits<signed short> should report signed.");
EXPECT(IntTraits<int>::kIsSigned, "IntTraits<int> should report signed.");
EXPECT(IntTraits<long>::kIsSigned, "IntTraits<long> should report signed.");
EXPECT(IntTraits<unsigned char>::kIsUnsigned, "IntTraits<unsigned char> should report unsigned.");
EXPECT(IntTraits<unsigned short>::kIsUnsigned, "IntTraits<unsigned short> should report unsigned.");
EXPECT(IntTraits<unsigned int>::kIsUnsigned, "IntTraits<unsigned int> should report unsigned.");
EXPECT(IntTraits<unsigned long>::kIsUnsigned, "IntTraits<unsigned long> should report unsigned.");
EXPECT(IntTraits<intptr_t>::kIsSigned, "IntTraits<intptr_t> should report signed.");
EXPECT(IntTraits<uintptr_t>::kIsUnsigned, "IntTraits<uintptr_t> should report unsigned.");
EXPECT(IntTraits<intptr_t>::kIsIntPtr, "IntTraits<intptr_t> should report intptr_t type.");
EXPECT(IntTraits<uintptr_t>::kIsIntPtr, "IntTraits<uintptr_t> should report intptr_t type.");
INFO("Utils::iMin()/iMax().");
EXPECT(Utils::iMin<int>( 0, -1) == -1, "Utils::iMin<int> should return a minimum value.");
EXPECT(Utils::iMin<int>(-1, -2) == -2, "Utils::iMin<int> should return a minimum value.");
EXPECT(Utils::iMin<int>( 1, 2) == 1, "Utils::iMin<int> should return a minimum value.");
EXPECT(Utils::iMax<int>( 0, -1) == 0, "Utils::iMax<int> should return a maximum value.");
EXPECT(Utils::iMax<int>(-1, -2) == -1, "Utils::iMax<int> should return a maximum value.");
EXPECT(Utils::iMax<int>( 1, 2) == 2, "Utils::iMax<int> should return a maximum value.");
INFO("Utils::inInterval().");
EXPECT(Utils::inInterval<int>(11 , 10, 20) == true , "Utils::inInterval<int> should return true if inside.");
EXPECT(Utils::inInterval<int>(101, 10, 20) == false, "Utils::inInterval<int> should return false if outside.");
INFO("Utils::isInt8().");
EXPECT(Utils::isInt8(-128) == true , "Utils::isInt8<> should return true if inside.");
EXPECT(Utils::isInt8( 127) == true , "Utils::isInt8<> should return true if inside.");
EXPECT(Utils::isInt8(-129) == false, "Utils::isInt8<> should return false if outside.");
EXPECT(Utils::isInt8( 128) == false, "Utils::isInt8<> should return false if outside.");
INFO("Utils::isInt16().");
EXPECT(Utils::isInt16(-32768) == true , "Utils::isInt16<> should return true if inside.");
EXPECT(Utils::isInt16( 32767) == true , "Utils::isInt16<> should return true if inside.");
EXPECT(Utils::isInt16(-32769) == false, "Utils::isInt16<> should return false if outside.");
EXPECT(Utils::isInt16( 32768) == false, "Utils::isInt16<> should return false if outside.");
INFO("Utils::isInt32().");
EXPECT(Utils::isInt32( 2147483647 ) == true, "Utils::isInt32<int> should return true if inside.");
EXPECT(Utils::isInt32(-2147483647 - 1) == true, "Utils::isInt32<int> should return true if inside.");
EXPECT(Utils::isInt32(ASMJIT_UINT64_C(2147483648)) == false, "Utils::isInt32<int> should return false if outside.");
EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == false, "Utils::isInt32<int> should return false if outside.");
EXPECT(Utils::isInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isInt32<int> should return false if outside.");
INFO("Utils::isUInt8().");
EXPECT(Utils::isUInt8(0) == true , "Utils::isUInt8<> should return true if inside.");
EXPECT(Utils::isUInt8(255) == true , "Utils::isUInt8<> should return true if inside.");
EXPECT(Utils::isUInt8(256) == false, "Utils::isUInt8<> should return false if outside.");
EXPECT(Utils::isUInt8(-1) == false, "Utils::isUInt8<> should return false if negative.");
INFO("Utils::isUInt12().");
EXPECT(Utils::isUInt12(0) == true , "Utils::isUInt12<> should return true if inside.");
EXPECT(Utils::isUInt12(4095) == true , "Utils::isUInt12<> should return true if inside.");
EXPECT(Utils::isUInt12(4096) == false, "Utils::isUInt12<> should return false if outside.");
EXPECT(Utils::isUInt12(-1) == false, "Utils::isUInt12<> should return false if negative.");
INFO("Utils::isUInt16().");
EXPECT(Utils::isUInt16(0) == true , "Utils::isUInt16<> should return true if inside.");
EXPECT(Utils::isUInt16(65535) == true , "Utils::isUInt16<> should return true if inside.");
EXPECT(Utils::isUInt16(65536) == false, "Utils::isUInt16<> should return false if outside.");
EXPECT(Utils::isUInt16(-1) == false, "Utils::isUInt16<> should return false if negative.");
INFO("Utils::isUInt32().");
EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF)) == true, "Utils::isUInt32<uint64_t> should return true if inside.");
EXPECT(Utils::isUInt32(ASMJIT_UINT64_C(0xFFFFFFFF) + 1) == false, "Utils::isUInt32<uint64_t> should return false if outside.");
EXPECT(Utils::isUInt32(-1) == false, "Utils::isUInt32<int> should return false if negative.");
INFO("Utils::isPower2().");
for (i = 0; i < 64; i++) {
EXPECT(Utils::isPowerOf2(static_cast<uint64_t>(1) << i) == true,
"Utils::isPower2() didn't report power of 2.");
EXPECT(Utils::isPowerOf2((static_cast<uint64_t>(1) << i) ^ 0x001101) == false,
"Utils::isPower2() didn't report not power of 2.");
}
INFO("Utils::mask().");
for (i = 0; i < 32; i++) {
EXPECT(Utils::mask(i) == (1 << i),
"Utils::mask(%u) should return %X.", i, (1 << i));
}
INFO("Utils::bits().");
for (i = 0; i < 32; i++) {
uint32_t expectedBits = 0;
for (uint32_t b = 0; b < i; b++)
expectedBits |= static_cast<uint32_t>(1) << b;
EXPECT(Utils::bits(i) == expectedBits,
"Utils::bits(%u) should return %X.", i, expectedBits);
}
INFO("Utils::hasBit().");
for (i = 0; i < 32; i++) {
EXPECT(Utils::hasBit((1 << i), i) == true,
"Utils::hasBit(%X, %u) should return true.", (1 << i), i);
}
INFO("Utils::bitCount().");
for (i = 0; i < 32; i++) {
EXPECT(Utils::bitCount((1 << i)) == 1,
"Utils::bitCount(%X) should return true.", (1 << i));
}
EXPECT(Utils::bitCount(0x000000F0) == 4, "");
EXPECT(Utils::bitCount(0x10101010) == 4, "");
EXPECT(Utils::bitCount(0xFF000000) == 8, "");
EXPECT(Utils::bitCount(0xFFFFFFF7) == 31, "");
EXPECT(Utils::bitCount(0x7FFFFFFF) == 31, "");
INFO("Utils::findFirstBit().");
for (i = 0; i < 32; i++) {
EXPECT(Utils::findFirstBit((1 << i)) == i,
"Utils::findFirstBit(%X) should return %u.", (1 << i), i);
}
INFO("Utils::keepNOnesFromRight().");
EXPECT(Utils::keepNOnesFromRight(0xF, 1) == 0x1, "");
EXPECT(Utils::keepNOnesFromRight(0xF, 2) == 0x3, "");
EXPECT(Utils::keepNOnesFromRight(0xF, 3) == 0x7, "");
EXPECT(Utils::keepNOnesFromRight(0x5, 2) == 0x5, "");
EXPECT(Utils::keepNOnesFromRight(0xD, 2) == 0x5, "");
INFO("Utils::isAligned().");
EXPECT(Utils::isAligned<size_t>(0xFFFF, 4) == false, "");
EXPECT(Utils::isAligned<size_t>(0xFFF4, 4) == true , "");
EXPECT(Utils::isAligned<size_t>(0xFFF8, 8) == true , "");
EXPECT(Utils::isAligned<size_t>(0xFFF0, 16) == true , "");
INFO("Utils::alignTo().");
EXPECT(Utils::alignTo<size_t>(0xFFFF, 4) == 0x10000, "");
EXPECT(Utils::alignTo<size_t>(0xFFF4, 4) == 0x0FFF4, "");
EXPECT(Utils::alignTo<size_t>(0xFFF8, 8) == 0x0FFF8, "");
EXPECT(Utils::alignTo<size_t>(0xFFF0, 16) == 0x0FFF0, "");
EXPECT(Utils::alignTo<size_t>(0xFFF0, 32) == 0x10000, "");
INFO("Utils::alignToPowerOf2().");
EXPECT(Utils::alignToPowerOf2<size_t>(0xFFFF) == 0x10000, "");
EXPECT(Utils::alignToPowerOf2<size_t>(0xF123) == 0x10000, "");
EXPECT(Utils::alignToPowerOf2<size_t>(0x0F00) == 0x01000, "");
EXPECT(Utils::alignToPowerOf2<size_t>(0x0100) == 0x00100, "");
EXPECT(Utils::alignToPowerOf2<size_t>(0x1001) == 0x02000, "");
INFO("Utils::alignDiff().");
EXPECT(Utils::alignDiff<size_t>(0xFFFF, 4) == 1, "");
EXPECT(Utils::alignDiff<size_t>(0xFFF4, 4) == 0, "");
EXPECT(Utils::alignDiff<size_t>(0xFFF8, 8) == 0, "");
EXPECT(Utils::alignDiff<size_t>(0xFFF0, 16) == 0, "");
EXPECT(Utils::alignDiff<size_t>(0xFFF0, 32) == 16, "");
}
#endif // ASMJIT_TEST
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -5,8 +5,8 @@
// Zlib - See LICENSE.md file in the package. // Zlib - See LICENSE.md file in the package.
// [Guard] // [Guard]
#ifndef _ASMJIT_BASE_INTUTIL_H #ifndef _ASMJIT_BASE_UTILS_H
#define _ASMJIT_BASE_INTUTIL_H #define _ASMJIT_BASE_UTILS_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/globals.h" #include "../base/globals.h"
@@ -21,13 +21,32 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::IntTraits] // [asmjit::IntTraits]
// ============================================================================ // ============================================================================
//! \internal
//! \{
template<size_t Size, int IsSigned>
struct IntTraitsPrivate {
// Let it fail if not specialized!
};
template<> struct IntTraitsPrivate<1, 0> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; };
template<> struct IntTraitsPrivate<1, 1> { typedef int IntType; typedef int8_t SignedType; typedef uint8_t UnsignedType; };
template<> struct IntTraitsPrivate<2, 0> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; };
template<> struct IntTraitsPrivate<2, 1> { typedef int IntType; typedef int16_t SignedType; typedef uint16_t UnsignedType; };
template<> struct IntTraitsPrivate<4, 0> { typedef int64_t IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template<> struct IntTraitsPrivate<4, 1> { typedef int IntType; typedef int32_t SignedType; typedef uint32_t UnsignedType; };
template<> struct IntTraitsPrivate<8, 0> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; };
template<> struct IntTraitsPrivate<8, 1> { typedef int64_t IntType; typedef int64_t SignedType; typedef uint64_t UnsignedType; };
//! \internal //! \internal
template<typename T> template<typename T>
struct IntTraits { struct IntTraits {
@@ -42,99 +61,87 @@ struct IntTraits {
kIsIntPtr = sizeof(T) == sizeof(intptr_t) kIsIntPtr = sizeof(T) == sizeof(intptr_t)
}; };
};
// \internal typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::IntType IntType;
template<size_t Size, int IsSigned> typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::SignedType SignedType;
struct AsInt_ { typedef int64_t Int; }; typedef typename IntTraitsPrivate<sizeof(T), kIsSigned>::UnsignedType UnsignedType;
template<> struct AsInt_<1, 0> { typedef int Int; }; //! Get a minimum value of `T`.
template<> struct AsInt_<1, 1> { typedef int Int; }; static ASMJIT_INLINE T minValue() {
template<> struct AsInt_<2, 0> { typedef int Int; }; if (kIsSigned)
template<> struct AsInt_<2, 1> { typedef int Int; }; return static_cast<T>((~static_cast<UnsignedType>(0) >> 1) + static_cast<UnsignedType>(1));
template<> struct AsInt_<4, 1> { typedef int Int; }; else
return static_cast<T>(0);
// \internal
//
// Map an integer `T` to an `int` or `int64_t`, depending on the type. Used
// internally by AsmJit to dispatch an argument of arbitrary integer type into
// a function that accepts either `int` or `int64_t`.
template<typename T>
struct AsInt {
typedef typename AsInt_<sizeof(T), IntTraits<T>::kIsSigned>::Int Int;
};
template<typename T>
ASMJIT_INLINE typename AsInt<T>::Int asInt(T value) {
return static_cast<typename AsInt<T>::Int>(value);
} }
//! Get a maximum value of `T`.
static ASMJIT_INLINE T maxValue() {
if (kIsSigned)
return static_cast<T>(~static_cast<UnsignedType>(0) >> 1);
else
return ~static_cast<T>(0);
}
};
//! \}
// ============================================================================ // ============================================================================
// [asmjit::IntUtil] // [asmjit::Utils]
// ============================================================================ // ============================================================================
//! Integer utilities. //! AsmJit utilities - integer, string, etc...
struct IntUtil { struct Utils {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Float <-> Int] // [Float <-> Int]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! \internal //! \internal
union Float { union FloatBits {
int32_t i; int32_t i;
float f; float f;
}; };
//! \internal //! \internal
union Double { union DoubleBits {
int64_t i; int64_t i;
double d; double d;
}; };
//! Bit-cast `float` to 32-bit integer. //! Bit-cast `float` to 32-bit integer.
static ASMJIT_INLINE int32_t floatAsInt(float f) { Float m; m.f = f; return m.i; } static ASMJIT_INLINE int32_t floatAsInt(float f) { FloatBits m; m.f = f; return m.i; }
//! Bit-cast 32-bit integer to `float`. //! Bit-cast 32-bit integer to `float`.
static ASMJIT_INLINE float intAsFloat(int32_t i) { Float m; m.i = i; return m.f; } static ASMJIT_INLINE float intAsFloat(int32_t i) { FloatBits m; m.i = i; return m.f; }
//! Bit-cast `double` to 64-bit integer. //! Bit-cast `double` to 64-bit integer.
static ASMJIT_INLINE int64_t doubleAsInt(double d) { Double m; m.d = d; return m.i; } static ASMJIT_INLINE int64_t doubleAsInt(double d) { DoubleBits m; m.d = d; return m.i; }
//! Bit-cast 64-bit integer to `double`. //! Bit-cast 64-bit integer to `double`.
static ASMJIT_INLINE double intAsDouble(int64_t i) { Double m; m.i = i; return m.d; } static ASMJIT_INLINE double intAsDouble(int64_t i) { DoubleBits m; m.i = i; return m.d; }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Pack / Unpack] // [Pack / Unpack]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Pack two 8-bit integer and one 16-bit integer into a 32-bit integer as it //! Pack two 8-bit integer and one 16-bit integer into a 32-bit integer as it
//! is an array of `{u0,u1,w2}`. //! is an array of `{u0,u1,w2}`.
static ASMJIT_INLINE uint32_t pack32_2x8_1x16(uint32_t u0, uint32_t u1, uint32_t w2) { static ASMJIT_INLINE uint32_t pack32_2x8_1x16(uint32_t u0, uint32_t u1, uint32_t w2) {
#if defined(ASMJIT_ARCH_LE) return ASMJIT_ARCH_LE ? u0 + (u1 << 8) + (w2 << 16)
return u0 + (u1 << 8) + (w2 << 16); : (u0 << 24) + (u1 << 16) + w2;
#else
return (u0 << 24) + (u1 << 16) + (w2);
#endif
} }
//! Pack four 8-bit integer into a 32-bit integer as it is an array of `{u0,u1,u2,u3}`. //! Pack four 8-bit integer into a 32-bit integer as it is an array of `{u0,u1,u2,u3}`.
static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) { static ASMJIT_INLINE uint32_t pack32_4x8(uint32_t u0, uint32_t u1, uint32_t u2, uint32_t u3) {
#if defined(ASMJIT_ARCH_LE) return ASMJIT_ARCH_LE ? u0 + (u1 << 8) + (u2 << 16) + (u3 << 24)
return u0 + (u1 << 8) + (u2 << 16) + (u3 << 24); : (u0 << 24) + (u1 << 16) + (u2 << 8) + u3;
#else
return (u0 << 24) + (u1 << 16) + (u2 << 8) + u3;
#endif
} }
//! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`. //! Pack two 32-bit integer into a 64-bit integer as it is an array of `{u0,u1}`.
static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) { static ASMJIT_INLINE uint64_t pack64_2x32(uint32_t u0, uint32_t u1) {
#if defined(ASMJIT_ARCH_LE) return ASMJIT_ARCH_LE ? (static_cast<uint64_t>(u1) << 32) + u0
return (static_cast<uint64_t>(u1) << 32) + u0; : (static_cast<uint64_t>(u0) << 32) + u1;
#else
return (static_cast<uint64_t>(u0) << 32) + u1;
#endif
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Min/Max] // [Min/Max]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// NOTE: Because some environments declare min() and max() as macros, it has // NOTE: Because some environments declare min() and max() as macros, it has
@@ -149,83 +156,118 @@ struct IntUtil {
static ASMJIT_INLINE T iMax(const T& a, const T& b) { return a > b ? a : b; } static ASMJIT_INLINE T iMax(const T& a, const T& b) { return a > b ? a : b; }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - MaxUInt] // [InInterval]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get maximum unsigned value of `T`. //! Get whether `x` is greater than or equal to `a` and lesses than or equal to `b`.
template<typename T> template<typename T>
static ASMJIT_INLINE T maxUInt() { return ~T(0); } static ASMJIT_INLINE bool inInterval(T x, T a, T b) {
return x >= a && x <= b;
// --------------------------------------------------------------------------
// [AsmJit - InInterval]
// --------------------------------------------------------------------------
//! Get whether `x` is greater or equal than `start` and less or equal than `end`.
template<typename T>
static ASMJIT_INLINE bool inInterval(const T& x, const T& start, const T& end) {
return x >= start && x <= end;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - IsInt/IsUInt] // [AsInt]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the given integer `x` can be casted to 8-bit signed integer. //! Map an integer `x` of type `T` to an `int` or `int64_t`, depending on the
//! type. Used internally by AsmJit to dispatch an argument that can be an
//! arbitrary integer type into a function that accepts either `int` or
//! `int64_t`.
template<typename T>
static ASMJIT_INLINE typename IntTraits<T>::IntType asInt(T x) {
return static_cast<typename IntTraits<T>::IntType>(x);
}
// --------------------------------------------------------------------------
// [IsInt / IsUInt]
// --------------------------------------------------------------------------
//! Get whether the given integer `x` can be casted to an 8-bit signed integer.
template<typename T> template<typename T>
static ASMJIT_INLINE bool isInt8(T x) { static ASMJIT_INLINE bool isInt8(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned) if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int8_t) ? true : x >= T(-128) && x <= T(127); return sizeof(T) <= 1 || inInterval<SignedType>(SignedType(x), -128, 127);
else else
return x <= T(127); return UnsignedType(x) <= UnsignedType(127U);
} }
//! Get whether the given integer `x` can be casted to 8-bit unsigned integer. //! Get whether the given integer `x` can be casted to a 16-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isUInt8(T x) {
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255));
else
return sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255);
}
//! Get whether the given integer `x` can be casted to 16-bit signed integer.
template<typename T> template<typename T>
static ASMJIT_INLINE bool isInt16(T x) { static ASMJIT_INLINE bool isInt16(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned) if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int16_t) ? true : x >= T(-32768) && x <= T(32767); return sizeof(T) <= 2 || inInterval<SignedType>(SignedType(x), -32768, 32767);
else else
return x >= T(0) && (sizeof(T) <= sizeof(int16_t) ? true : x <= T(32767)); return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(32767U);
} }
//! Get whether the given integer `x` can be casted to 16-bit unsigned integer. //! Get whether the given integer `x` can be casted to a 32-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isUInt16(T x) {
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535));
else
return sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535);
}
//! Get whether the given integer `x` can be casted to 32-bit signed integer.
template<typename T> template<typename T>
static ASMJIT_INLINE bool isInt32(T x) { static ASMJIT_INLINE bool isInt32(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned) if (IntTraits<T>::kIsSigned)
return sizeof(T) <= sizeof(int32_t) ? true : x >= T(-2147483647) - 1 && x <= T(2147483647); return sizeof(T) <= 4 || inInterval<SignedType>(SignedType(x), -2147483647 - 1, 2147483647);
else else
return x >= T(0) && (sizeof(T) <= sizeof(int32_t) ? true : x <= T(2147483647)); return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(2147483647U);
} }
//! Get whether the given integer `x` can be casted to 32-bit unsigned integer. //! Get whether the given integer `x` can be casted to an 8-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt8(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(255));
else
return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(255U);
}
//! Get whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific).
template<typename T>
static ASMJIT_INLINE bool isUInt12(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= 1 ? true : x <= T(4095));
else
return sizeof(T) <= 1 || UnsignedType(x) <= UnsignedType(4095U);
}
//! Get whether the given integer `x` can be casted to a 16-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt16(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= 2 ? true : x <= T(65535));
else
return sizeof(T) <= 2 || UnsignedType(x) <= UnsignedType(65535U);
}
//! Get whether the given integer `x` can be casted to a 32-bit unsigned integer.
template<typename T> template<typename T>
static ASMJIT_INLINE bool isUInt32(T x) { static ASMJIT_INLINE bool isUInt32(T x) {
typedef typename IntTraits<T>::SignedType SignedType;
typedef typename IntTraits<T>::UnsignedType UnsignedType;
if (IntTraits<T>::kIsSigned) if (IntTraits<T>::kIsSigned)
return x >= T(0) && (sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U)); return x >= T(0) && (sizeof(T) <= 4 ? true : x <= T(4294967295U));
else else
return sizeof(T) <= sizeof(uint32_t) ? true : x <= T(4294967295U); return sizeof(T) <= 4 || UnsignedType(x) <= UnsignedType(4294967295U);
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - IsPowerOf2] // [IsPowerOf2]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether the `n` value is a power of two (only one bit is set). //! Get whether the `n` value is a power of two (only one bit is set).
@@ -235,13 +277,13 @@ struct IntUtil {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Mask] // [Mask]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` bit set. //! Generate a bit-mask that has `x` bit set.
static ASMJIT_INLINE uint32_t mask(uint32_t x) { static ASMJIT_INLINE uint32_t mask(uint32_t x) {
ASMJIT_ASSERT(x < 32); ASMJIT_ASSERT(x < 32);
return (1U << x); return static_cast<uint32_t>(1) << x;
} }
//! Generate a bit-mask that has `x0` and `x1` bits set. //! Generate a bit-mask that has `x0` and `x1` bits set.
@@ -261,44 +303,36 @@ struct IntUtil {
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3` and `x4` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) ;
mask(x4) ;
} }
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4` and `x5` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) | mask(x5) ;
mask(x4) | mask(x5) ;
} }
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5` and `x6` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) | mask(x5) | mask(x6) ;
mask(x4) | mask(x5) | mask(x6) ;
} }
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6` and `x7` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) | mask(x5) | mask(x6) | mask(x7) ;
mask(x4) | mask(x5) | mask(x6) | mask(x7) ;
} }
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7` and `x8` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) | mask(x5) | mask(x6) | mask(x7) | mask(x8) ;
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
mask(x8) ;
} }
//! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set. //! Generate a bit-mask that has `x0`, `x1`, `x2`, `x3`, `x4`, `x5`, `x6`, `x7`, `x8` and `x9` bits set.
static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) { static ASMJIT_INLINE uint32_t mask(uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7, uint32_t x8, uint32_t x9) {
return mask(x0) | mask(x1) | mask(x2) | mask(x3) | return mask(x0) | mask(x1) | mask(x2) | mask(x3) | mask(x4) | mask(x5) | mask(x6) | mask(x7) | mask(x8) | mask(x9) ;
mask(x4) | mask(x5) | mask(x6) | mask(x7) |
mask(x8) | mask(x9) ;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Bits] // [Bits]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Generate a bit-mask that has `x` most significant bits set. //! Generate a bit-mask that has `x` most significant bits set.
@@ -316,16 +350,16 @@ struct IntUtil {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - HasBit] // [HasBit]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get whether `x` has bit `n` set. //! Get whether `x` has bit `n` set.
static ASMJIT_INLINE bool hasBit(uint32_t x, uint32_t n) { static ASMJIT_INLINE bool hasBit(uint32_t x, uint32_t n) {
return static_cast<bool>((x >> n) & 0x1); return (x & (static_cast<uint32_t>(1) << n)) != 0;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - BitCount] // [BitCount]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get count of bits in `x`. //! Get count of bits in `x`.
@@ -338,14 +372,14 @@ struct IntUtil {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - FindFirstBit] // [FindFirstBit]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! \internal //! \internal
static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) { static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) {
// This is a reference (slow) implementation of findFirstBit(), used when // This is a reference (slow) implementation of `findFirstBit()`, used when
// we don't have compiler support for this task. The implementation speed // we don't have a C++ compiler support. The implementation speed has been
// has been improved to check for 2 bits per iteration. // improved to check for 2 bits per iteration.
uint32_t i = 1; uint32_t i = 1;
while (mask != 0) { while (mask != 0) {
@@ -375,7 +409,7 @@ struct IntUtil {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Misc] // [Misc]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) { static ASMJIT_INLINE uint32_t keepNOnesFromRight(uint32_t mask, uint32_t nBits) {
@@ -414,7 +448,7 @@ struct IntUtil {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [AsmJit - Alignment] // [Alignment]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
template<typename T> template<typename T>
@@ -457,9 +491,28 @@ struct IntUtil {
//! Get delta required to align `base` to `alignment`. //! Get delta required to align `base` to `alignment`.
template<typename T> template<typename T>
static ASMJIT_INLINE T deltaTo(T base, T alignment) { static ASMJIT_INLINE T alignDiff(T base, T alignment) {
return alignTo(base, alignment) - base; return alignTo(base, alignment) - base;
} }
// --------------------------------------------------------------------------
// [String]
// --------------------------------------------------------------------------
static ASMJIT_INLINE size_t strLen(const char* s, size_t maxlen) {
size_t i;
for (i = 0; i < maxlen; i++)
if (!s[i])
break;
return i;
}
// --------------------------------------------------------------------------
// [CpuTicks]
// --------------------------------------------------------------------------
//! Get the current CPU tick count, used for benchmarking (1ms resolution).
static ASMJIT_API uint32_t getTickCount();
}; };
// ============================================================================ // ============================================================================
@@ -523,7 +576,7 @@ union UInt64 {
ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) { ASMJIT_INLINE UInt64& setPacked_2x32(uint32_t u0, uint32_t u1) {
if (kArchHost64Bit) { if (kArchHost64Bit) {
u64 = IntUtil::pack64_2x32(u0, u1); u64 = Utils::pack64_2x32(u0, u1);
} }
else { else {
u32[0] = u0; u32[0] = u0;
@@ -713,6 +766,7 @@ union UInt64 {
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! 64-bit unsigned value.
uint64_t u64; uint64_t u64;
uint32_t u32[2]; uint32_t u32[2];
@@ -720,7 +774,7 @@ union UInt64 {
uint8_t u8[8]; uint8_t u8[8];
struct { struct {
#if defined(ASMJIT_ARCH_LE) #if ASMJIT_ARCH_LE
uint32_t lo, hi; uint32_t lo, hi;
#else #else
uint32_t hi, lo; uint32_t hi, lo;
@@ -728,6 +782,87 @@ union UInt64 {
}; };
}; };
// ============================================================================
// [asmjit::Lock]
// ============================================================================
//! \internal
//!
//! Lock.
struct Lock {
ASMJIT_NO_COPY(Lock)
// --------------------------------------------------------------------------
// [Windows]
// --------------------------------------------------------------------------
#if ASMJIT_OS_WINDOWS
typedef CRITICAL_SECTION Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { InitializeCriticalSection(&_handle); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { DeleteCriticalSection(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { EnterCriticalSection(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { LeaveCriticalSection(&_handle); }
#endif // ASMJIT_OS_WINDOWS
// --------------------------------------------------------------------------
// [Posix]
// --------------------------------------------------------------------------
#if ASMJIT_OS_POSIX
typedef pthread_mutex_t Handle;
//! Create a new `Lock` instance.
ASMJIT_INLINE Lock() { pthread_mutex_init(&_handle, NULL); }
//! Destroy the `Lock` instance.
ASMJIT_INLINE ~Lock() { pthread_mutex_destroy(&_handle); }
//! Lock.
ASMJIT_INLINE void lock() { pthread_mutex_lock(&_handle); }
//! Unlock.
ASMJIT_INLINE void unlock() { pthread_mutex_unlock(&_handle); }
#endif // ASMJIT_OS_POSIX
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Native handle.
Handle _handle;
};
// ============================================================================
// [asmjit::AutoLock]
// ============================================================================
//! \internal
//!
//! Scoped lock.
struct AutoLock {
ASMJIT_NO_COPY(AutoLock)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Lock `target`, scoped.
ASMJIT_INLINE AutoLock(Lock& target) : _target(target) { _target.lock(); }
//! Unlock `target`.
ASMJIT_INLINE ~AutoLock() { _target.unlock(); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Reference to the `Lock`.
Lock& _target;
};
//! \} //! \}
} // asmjit namespace } // asmjit namespace
@@ -736,4 +871,4 @@ union UInt64 {
#include "../apiend.h" #include "../apiend.h"
// [Guard] // [Guard]
#endif // _ASMJIT_BASE_INTUTIL_H #endif // _ASMJIT_BASE_UTILS_H

View File

@@ -16,7 +16,7 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================

View File

@@ -8,14 +8,11 @@
#define ASMJIT_EXPORTS #define ASMJIT_EXPORTS
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h"
#include "../base/globals.h" #include "../base/globals.h"
#include "../base/intutil.h"
#include "../base/lock.h"
#include "../base/vmem.h" #include "../base/vmem.h"
// [Dependencies - Posix] // [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX) #if ASMJIT_OS_POSIX
# include <sys/types.h> # include <sys/types.h>
# include <sys/mman.h> # include <sys/mman.h>
# include <unistd.h> # include <unistd.h>
@@ -70,7 +67,7 @@ namespace asmjit {
// ============================================================================ // ============================================================================
// Windows specific implementation using `VirtualAllocEx` and `VirtualFree`. // Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
struct VMemLocal { struct VMemLocal {
// AsmJit allows to pass a `NULL` handle to `VMemUtil`. This function is just // AsmJit allows to pass a `NULL` handle to `VMemUtil`. This function is just
// a convenient way to convert such handle to the current process one. // a convenient way to convert such handle to the current process one.
@@ -91,7 +88,7 @@ static const VMemLocal& vMemGet() {
SYSTEM_INFO info; SYSTEM_INFO info;
::GetSystemInfo(&info); ::GetSystemInfo(&info);
vMem.pageSize = IntUtil::alignToPowerOf2<uint32_t>(info.dwPageSize); vMem.pageSize = Utils::alignToPowerOf2<uint32_t>(info.dwPageSize);
vMem.pageGranularity = info.dwAllocationGranularity; vMem.pageGranularity = info.dwAllocationGranularity;
vMem.hProcess = ::GetCurrentProcess(); vMem.hProcess = ::GetCurrentProcess();
@@ -122,7 +119,7 @@ void* VMemUtil::allocProcessMemory(HANDLE hProcess, size_t length, size_t* alloc
hProcess = vMem.getSafeProcessHandle(hProcess); hProcess = vMem.getSafeProcessHandle(hProcess);
// VirtualAlloc rounds allocated size to a page size automatically. // VirtualAlloc rounds allocated size to a page size automatically.
size_t mSize = IntUtil::alignTo(length, vMem.pageSize); size_t mSize = Utils::alignTo(length, vMem.pageSize);
// Windows XP SP2 / Vista allow Data Excution Prevention (DEP). // Windows XP SP2 / Vista allow Data Excution Prevention (DEP).
DWORD protectFlags = 0; DWORD protectFlags = 0;
@@ -136,7 +133,7 @@ void* VMemUtil::allocProcessMemory(HANDLE hProcess, size_t length, size_t* alloc
if (mBase == NULL) if (mBase == NULL)
return NULL; return NULL;
ASMJIT_ASSERT(IntUtil::isAligned<size_t>( ASMJIT_ASSERT(Utils::isAligned<size_t>(
reinterpret_cast<size_t>(mBase), vMem.pageSize)); reinterpret_cast<size_t>(mBase), vMem.pageSize));
if (allocated != NULL) if (allocated != NULL)
@@ -161,7 +158,7 @@ Error VMemUtil::releaseProcessMemory(HANDLE hProcess, void* addr, size_t /* leng
// ============================================================================ // ============================================================================
// Posix specific implementation using `mmap` and `munmap`. // Posix specific implementation using `mmap` and `munmap`.
#if defined(ASMJIT_OS_POSIX) #if ASMJIT_OS_POSIX
// MacOS uses MAP_ANON instead of MAP_ANONYMOUS. // MacOS uses MAP_ANON instead of MAP_ANONYMOUS.
#if !defined(MAP_ANONYMOUS) #if !defined(MAP_ANONYMOUS)
@@ -180,7 +177,7 @@ static const VMemLocal& vMemGet() {
if (!vMem.pageSize) { if (!vMem.pageSize) {
size_t pageSize = ::getpagesize(); size_t pageSize = ::getpagesize();
vMem.pageSize = pageSize; vMem.pageSize = pageSize;
vMem.pageGranularity = IntUtil::iMax<size_t>(pageSize, 65536); vMem.pageGranularity = Utils::iMax<size_t>(pageSize, 65536);
} }
return vMem; return vMem;
@@ -198,7 +195,7 @@ size_t VMemUtil::getPageGranularity() {
void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) { void* VMemUtil::alloc(size_t length, size_t* allocated, uint32_t flags) {
const VMemLocal& vMem = vMemGet(); const VMemLocal& vMem = vMemGet();
size_t msize = IntUtil::alignTo<size_t>(length, vMem.pageSize); size_t msize = Utils::alignTo<size_t>(length, vMem.pageSize);
int protection = PROT_READ; int protection = PROT_READ;
if (flags & kVMemFlagWritable ) protection |= PROT_WRITE; if (flags & kVMemFlagWritable ) protection |= PROT_WRITE;
@@ -430,7 +427,7 @@ struct VMemMgr::PermanentNode {
//! Helper to avoid `#ifdef`s in the code. //! Helper to avoid `#ifdef`s in the code.
ASMJIT_INLINE uint8_t* vMemMgrAllocVMem(VMemMgr* self, size_t size, size_t* vSize) { ASMJIT_INLINE uint8_t* vMemMgrAllocVMem(VMemMgr* self, size_t size, size_t* vSize) {
uint32_t flags = kVMemFlagWritable | kVMemFlagExecutable; uint32_t flags = kVMemFlagWritable | kVMemFlagExecutable;
#if !defined(ASMJIT_OS_WINDOWS) #if !ASMJIT_OS_WINDOWS
return static_cast<uint8_t*>(VMemUtil::alloc(size, vSize, flags)); return static_cast<uint8_t*>(VMemUtil::alloc(size, vSize, flags));
#else #else
return static_cast<uint8_t*>(VMemUtil::allocProcessMemory(self->_hProcess, size, vSize, flags)); return static_cast<uint8_t*>(VMemUtil::allocProcessMemory(self->_hProcess, size, vSize, flags));
@@ -441,7 +438,7 @@ ASMJIT_INLINE uint8_t* vMemMgrAllocVMem(VMemMgr* self, size_t size, size_t* vSiz
//! //!
//! Helper to avoid `#ifdef`s in the code. //! Helper to avoid `#ifdef`s in the code.
ASMJIT_INLINE Error vMemMgrReleaseVMem(VMemMgr* self, void* p, size_t vSize) { ASMJIT_INLINE Error vMemMgrReleaseVMem(VMemMgr* self, void* p, size_t vSize) {
#if !defined(ASMJIT_OS_WINDOWS) #if !ASMJIT_OS_WINDOWS
return VMemUtil::release(p, vSize); return VMemUtil::release(p, vSize);
#else #else
return VMemUtil::releaseProcessMemory(self->_hProcess, p, vSize); return VMemUtil::releaseProcessMemory(self->_hProcess, p, vSize);
@@ -717,7 +714,7 @@ static void* vMemMgrAllocPermanent(VMemMgr* self, size_t vSize) {
static const size_t permanentAlignment = 32; static const size_t permanentAlignment = 32;
static const size_t permanentNodeSize = 32768; static const size_t permanentNodeSize = 32768;
vSize = IntUtil::alignTo<size_t>(vSize, permanentAlignment); vSize = Utils::alignTo<size_t>(vSize, permanentAlignment);
AutoLock locked(self->_lock); AutoLock locked(self->_lock);
PermanentNode* node = self->_permanent; PermanentNode* node = self->_permanent;
@@ -772,7 +769,7 @@ static void* vMemMgrAllocFreeable(VMemMgr* self, size_t vSize) {
size_t minVSize; size_t minVSize;
// Align to 32 bytes by default. // Align to 32 bytes by default.
vSize = IntUtil::alignTo<size_t>(vSize, 32); vSize = Utils::alignTo<size_t>(vSize, 32);
if (vSize == 0) if (vSize == 0)
return NULL; return NULL;
@@ -923,7 +920,7 @@ static void vMemMgrReset(VMemMgr* self, bool keepVirtualMemory) {
// [asmjit::VMemMgr - Construction / Destruction] // [asmjit::VMemMgr - Construction / Destruction]
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_OS_WINDOWS) #if !ASMJIT_OS_WINDOWS
VMemMgr::VMemMgr() VMemMgr::VMemMgr()
#else #else
VMemMgr::VMemMgr(HANDLE hProcess) : VMemMgr::VMemMgr(HANDLE hProcess) :

View File

@@ -9,15 +9,14 @@
#define _ASMJIT_BASE_VMEM_H #define _ASMJIT_BASE_VMEM_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h" #include "../base/utils.h"
#include "../base/lock.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -72,21 +71,14 @@ struct VMemUtil {
//! executable unless 'canExecute' is true. Returns the address of //! executable unless 'canExecute' is true. Returns the address of
//! allocated memory, or NULL on failure. //! allocated memory, or NULL on failure.
static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags); static ASMJIT_API void* alloc(size_t length, size_t* allocated, uint32_t flags);
#if defined(ASMJIT_OS_WINDOWS)
//! Allocate virtual memory of `hProcess`.
//!
//! \note This function is Windows specific.
static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags);
#endif // ASMJIT_OS_WINDOWS
//! Free memory allocated by `alloc()`. //! Free memory allocated by `alloc()`.
static ASMJIT_API Error release(void* addr, size_t length); static ASMJIT_API Error release(void* addr, size_t length);
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
//! Release virtual memory of `hProcess`. //! Allocate virtual memory of `hProcess` (Windows only).
//! static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags);
//! \note This function is Windows specific.
//! Release virtual memory of `hProcess` (Windows only).
static ASMJIT_API Error releaseProcessMemory(HANDLE hProcess, void* addr, size_t length); static ASMJIT_API Error releaseProcessMemory(HANDLE hProcess, void* addr, size_t length);
#endif // ASMJIT_OS_WINDOWS #endif // ASMJIT_OS_WINDOWS
}; };
@@ -102,7 +94,7 @@ struct VMemMgr {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if !defined(ASMJIT_OS_WINDOWS) #if !ASMJIT_OS_WINDOWS
//! Create a `VMemMgr` instance. //! Create a `VMemMgr` instance.
ASMJIT_API VMemMgr(); ASMJIT_API VMemMgr();
#else #else
@@ -128,7 +120,7 @@ struct VMemMgr {
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
//! Get the handle of the process memory manager is bound to. //! Get the handle of the process memory manager is bound to.
ASMJIT_INLINE HANDLE getProcessHandle() const { ASMJIT_INLINE HANDLE getProcessHandle() const {
return _hProcess; return _hProcess;
@@ -189,7 +181,7 @@ struct VMemMgr {
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS) #if ASMJIT_OS_WINDOWS
//! Process passed to `VirtualAllocEx` and `VirtualFree`. //! Process passed to `VirtualAllocEx` and `VirtualFree`.
HANDLE _hProcess; HANDLE _hProcess;
#endif // ASMJIT_OS_WINDOWS #endif // ASMJIT_OS_WINDOWS

View File

@@ -8,7 +8,7 @@
#define ASMJIT_EXPORTS #define ASMJIT_EXPORTS
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/intutil.h" #include "../base/utils.h"
#include "../base/zone.h" #include "../base/zone.h"
// [Dependencies - C] // [Dependencies - C]
@@ -82,7 +82,7 @@ void Zone::reset(bool releaseMemory) {
void* Zone::_alloc(size_t size) { void* Zone::_alloc(size_t size) {
Block* curBlock = _block; Block* curBlock = _block;
size_t blockSize = IntUtil::iMax<size_t>(_blockSize, size); size_t blockSize = Utils::iMax<size_t>(_blockSize, size);
// The `_alloc()` method can only be called if there is not enough space // The `_alloc()` method can only be called if there is not enough space
// in the current block, see `alloc()` implementation for more details. // in the current block, see `alloc()` implementation for more details.

View File

@@ -16,7 +16,7 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_util //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -75,6 +75,15 @@ struct Zone {
uint8_t data[sizeof(void*)]; uint8_t data[sizeof(void*)];
}; };
// --------------------------------------------------------------------------
// [Enums]
// --------------------------------------------------------------------------
enum {
//! Zone allocator overhead.
kZoneOverhead = static_cast<int>(sizeof(Block) - sizeof(void*)) + kMemAllocOverhead
};
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -205,11 +214,6 @@ struct Zone {
size_t _blockSize; size_t _blockSize;
}; };
enum {
//! Zone allocator overhead.
kZoneOverhead = static_cast<int>(sizeof(Zone::Block) - sizeof(void*)) + kMemAllocOverhead
};
//! \} //! \}
} // asmjit namespace } // asmjit namespace

File diff suppressed because it is too large Load Diff

View File

@@ -1,53 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_CONFIG_H
#define _ASMJIT_CONFIG_H
// This file can be used to modify built-in features of AsmJit. AsmJit is by
// default compiled only for host processor to enable JIT compilation. Both
// Assembler and Compiler code generators are compiled by default.
//
// ASMJIT_BUILD_... flags can be defined to build additional backends that can
// be used for remote code generation.
//
// ASMJIT_DISABLE_... flags can be defined to disable standard features. These
// are handy especially when building asmjit statically and some features are
// not needed or unwanted (like Compiler).
// ============================================================================
// [AsmJit - Build-Type]
// ============================================================================
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build.
// ============================================================================
// [AsmJit - Build-Mode]
// ============================================================================
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// #define ASMJIT_TRACE // Define to enable tracing.
// ============================================================================
// [AsmJit - Features]
// ============================================================================
// If none of these is defined AsmJit will select host architecture by default.
// #define ASMJIT_BUILD_X86 // Define to enable x86 instruction set (32-bit).
// #define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit).
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// AsmJit features are enabled by default.
// #define ASMJIT_DISABLE_COMPILER // Disable Compiler (completely).
// #define ASMJIT_DISABLE_LOGGER // Disable Logger (completely).
// #define ASMJIT_DISABLE_NAMES // Disable everything that uses strings
// (instruction names, error names, ...).
// [Guard]
#endif // _ASMJIT_CONFIG_H

View File

@@ -15,7 +15,7 @@
// [asmjit::host - X86 / X64] // [asmjit::host - X86 / X64]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
#include "./x86.h" #include "./x86.h"
namespace asmjit { namespace asmjit {

View File

@@ -13,6 +13,7 @@
#include "./x86/x86assembler.h" #include "./x86/x86assembler.h"
#include "./x86/x86compiler.h" #include "./x86/x86compiler.h"
#include "./x86/x86compilerfunc.h"
#include "./x86/x86cpuinfo.h" #include "./x86/x86cpuinfo.h"
#include "./x86/x86inst.h" #include "./x86/x86inst.h"
#include "./x86/x86operand.h" #include "./x86/x86operand.h"

View File

@@ -12,10 +12,10 @@
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/intutil.h" #include "../base/containers.h"
#include "../base/logger.h" #include "../base/logger.h"
#include "../base/runtime.h" #include "../base/runtime.h"
#include "../base/string.h" #include "../base/utils.h"
#include "../base/vmem.h" #include "../base/vmem.h"
#include "../x86/x86assembler.h" #include "../x86/x86assembler.h"
#include "../x86/x86cpuinfo.h" #include "../x86/x86cpuinfo.h"
@@ -155,7 +155,7 @@ static ASMJIT_INLINE bool x86RexIsInvalid(uint32_t rex) {
//! Encode ModR/M. //! Encode ModR/M.
static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) { static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) {
ASMJIT_ASSERT(m <= 7); ASMJIT_ASSERT(m <= 3);
ASMJIT_ASSERT(o <= 7); ASMJIT_ASSERT(o <= 7);
ASMJIT_ASSERT(rm <= 7); ASMJIT_ASSERT(rm <= 7);
return (m << 6) + (o << 3) + rm; return (m << 6) + (o << 3) + rm;
@@ -163,7 +163,7 @@ static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm)
//! Encode SIB. //! Encode SIB.
static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) { static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) {
ASMJIT_ASSERT(s <= 7); ASMJIT_ASSERT(s <= 3);
ASMJIT_ASSERT(i <= 7); ASMJIT_ASSERT(i <= 7);
ASMJIT_ASSERT(b <= 7); ASMJIT_ASSERT(b <= 7);
return (s << 6) + (i << 3) + b; return (s << 6) + (i << 3) + b;
@@ -173,7 +173,7 @@ static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) {
//! displacement, which fits into a signed 32-bit integer. //! displacement, which fits into a signed 32-bit integer.
static ASMJIT_INLINE bool x64IsRelative(Ptr a, Ptr b) { static ASMJIT_INLINE bool x64IsRelative(Ptr a, Ptr b) {
SignedPtr diff = static_cast<SignedPtr>(a) - static_cast<SignedPtr>(b); SignedPtr diff = static_cast<SignedPtr>(a) - static_cast<SignedPtr>(b);
return IntUtil::isInt32(diff); return Utils::isInt32(diff);
} }
//! Cast `reg` to `X86Reg` and get the register index. //! Cast `reg` to `X86Reg` and get the register index.
@@ -299,8 +299,8 @@ static ASMJIT_INLINE bool x86IsYmm(const X86Reg* reg) { return reg->isYmm(); }
// [asmjit::X86Assembler - Construction / Destruction] // [asmjit::X86Assembler - Construction / Destruction]
// ============================================================================ // ============================================================================
X86Assembler::X86Assembler(Runtime* runtime, uint32_t arch) : X86Assembler::X86Assembler(Runtime* runtime, uint32_t arch)
Assembler(runtime), : Assembler(runtime),
zax(NoInit), zax(NoInit),
zcx(NoInit), zcx(NoInit),
zdx(NoInit), zdx(NoInit),
@@ -309,8 +309,8 @@ X86Assembler::X86Assembler(Runtime* runtime, uint32_t arch) :
zbp(NoInit), zbp(NoInit),
zsi(NoInit), zsi(NoInit),
zdi(NoInit) { zdi(NoInit) {
ASMJIT_ASSERT(arch == kArchX86 || arch == kArchX64);
setArch(arch); _setArch(arch);
} }
X86Assembler::~X86Assembler() {} X86Assembler::~X86Assembler() {}
@@ -319,10 +319,10 @@ X86Assembler::~X86Assembler() {}
// [asmjit::X86Assembler - Arch] // [asmjit::X86Assembler - Arch]
// ============================================================================ // ============================================================================
Error X86Assembler::setArch(uint32_t arch) { Error X86Assembler::_setArch(uint32_t arch) {
#if defined(ASMJIT_BUILD_X86) #if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86) { if (arch == kArchX86) {
_arch = kArchX86; _arch = arch;
_regSize = 4; _regSize = 4;
_regCount.reset(); _regCount.reset();
@@ -338,7 +338,7 @@ Error X86Assembler::setArch(uint32_t arch) {
#if defined(ASMJIT_BUILD_X64) #if defined(ASMJIT_BUILD_X64)
if (arch == kArchX64) { if (arch == kArchX64) {
_arch = kArchX64; _arch = arch;
_regSize = 8; _regSize = 8;
_regCount.reset(); _regCount.reset();
@@ -399,7 +399,7 @@ Error X86Assembler::embedLabel(const Label& op) {
} }
if (_relocList.append(rd) != kErrorOk) if (_relocList.append(rd) != kErrorOk)
return setError(kErrorNoHeapMemory); return setLastError(kErrorNoHeapMemory);
// Emit dummy intptr_t (4 or 8 bytes; depends on the address size). // Emit dummy intptr_t (4 or 8 bytes; depends on the address size).
if (regSize == 4) if (regSize == 4)
@@ -422,10 +422,10 @@ Error X86Assembler::align(uint32_t alignMode, uint32_t offset) {
"%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(offset)); "%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(offset));
#endif // !ASMJIT_DISABLE_LOGGER #endif // !ASMJIT_DISABLE_LOGGER
if (offset <= 1 || !IntUtil::isPowerOf2(offset) || offset > 64) if (alignMode > kAlignZero || offset <= 1 || !Utils::isPowerOf2(offset) || offset > 64)
return setError(kErrorInvalidArgument); return setLastError(kErrorInvalidArgument);
uint32_t i = static_cast<uint32_t>(IntUtil::deltaTo<size_t>(getOffset(), offset)); uint32_t i = static_cast<uint32_t>(Utils::alignDiff<size_t>(getOffset(), offset));
if (i == 0) if (i == 0)
return kErrorOk; return kErrorOk;
@@ -433,57 +433,29 @@ Error X86Assembler::align(uint32_t alignMode, uint32_t offset) {
ASMJIT_PROPAGATE_ERROR(_grow(i)); ASMJIT_PROPAGATE_ERROR(_grow(i));
uint8_t* cursor = getCursor(); uint8_t* cursor = getCursor();
uint8_t alignPattern = 0xCC; uint8_t pattern = 0x00;
if (alignMode == kAlignCode) { switch (alignMode) {
alignPattern = 0x90; case kAlignCode: {
if (hasFeature(kAssemblerFeatureOptimizedAlign)) {
// Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP).
enum { kMaxNopSize = 9 };
if (hasFeature(kCodeGenOptimizedAlign)) { static const uint8_t nopData[kMaxNopSize][kMaxNopSize] = {
const X86CpuInfo* cpuInfo = static_cast<const X86CpuInfo*>(getRuntime()->getCpuInfo()); { 0x90 },
{ 0x66, 0x90 },
{ 0x0F, 0x1F, 0x00 },
{ 0x0F, 0x1F, 0x40, 0x00 },
{ 0x0F, 0x1F, 0x44, 0x00, 0x00 },
{ 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 },
{ 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 },
{ 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
{ 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
};
// NOPs optimized for Intel:
// Intel 64 and IA-32 Architectures Software Developer's Manual
// - Volume 2B
// - Instruction Set Reference N-Z
// - NOP
// NOPs optimized for AMD:
// Software Optimization Guide for AMD Family 10h Processors (Quad-Core)
// - 4.13 - Code Padding with Operand-Size Override and Multibyte NOP
// Intel and AMD.
static const uint8_t nop1[] = { 0x90 };
static const uint8_t nop2[] = { 0x66, 0x90 };
static const uint8_t nop3[] = { 0x0F, 0x1F, 0x00 };
static const uint8_t nop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
static const uint8_t nop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
// AMD.
static const uint8_t nop10[] = { 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop11[] = { 0x66, 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t* p;
uint32_t n;
if (cpuInfo->getVendorId() == kCpuVendorIntel && (
(cpuInfo->getFamily() & 0x0F) == 0x06 ||
(cpuInfo->getFamily() & 0x0F) == 0x0F)) {
do { do {
switch (i) { uint32_t n = Utils::iMin<uint32_t>(i, kMaxNopSize);
case 1: p = nop1; n = 1; break; const uint8_t* p = nopData[(n - 1) * kMaxNopSize];
case 2: p = nop2; n = 2; break;
case 3: p = nop3; n = 3; break;
case 4: p = nop4; n = 4; break;
case 5: p = nop5; n = 5; break;
case 6: p = nop6; n = 6; break;
case 7: p = nop7; n = 7; break;
case 8: p = nop8; n = 8; break;
default: p = nop9; n = 9; break;
}
i -= n; i -= n;
do { do {
@@ -491,33 +463,24 @@ Error X86Assembler::align(uint32_t alignMode, uint32_t offset) {
} while (--n); } while (--n);
} while (i); } while (i);
} }
else if (cpuInfo->getVendorId() == kCpuVendorAmd && cpuInfo->getFamily() >= 0x0F) {
do { pattern = 0x90;
switch (i) { break;
case 1: p = nop1 ; n = 1; break;
case 2: p = nop2 ; n = 2; break;
case 3: p = nop3 ; n = 3; break;
case 4: p = nop4 ; n = 4; break;
case 5: p = nop5 ; n = 5; break;
case 6: p = nop6 ; n = 6; break;
case 7: p = nop7 ; n = 7; break;
case 8: p = nop8 ; n = 8; break;
case 9: p = nop9 ; n = 9; break;
case 10: p = nop10; n = 10; break;
default: p = nop11; n = 11; break;
} }
i -= n; case kAlignData: {
do { pattern = 0xCC;
EMIT_BYTE(*p++); break;
} while (--n);
} while (i);
} }
case kAlignZero: {
// Already set to zero.
break;
} }
} }
while (i) { while (i) {
EMIT_BYTE(alignPattern); EMIT_BYTE(pattern);
i--; i--;
} }
@@ -578,7 +541,7 @@ size_t X86Assembler::_relocCode(void* _dst, Ptr baseAddress) const {
case kRelocTrampoline: case kRelocTrampoline:
ptr -= baseAddress + rd.from + 4; ptr -= baseAddress + rd.from + 4;
if (!IntUtil::isInt32(static_cast<SignedPtr>(ptr))) { if (!Utils::isInt32(static_cast<SignedPtr>(ptr))) {
ptr = (Ptr)tramp - (baseAddress + rd.from + 4); ptr = (Ptr)tramp - (baseAddress + rd.from + 4);
useTrampoline = true; useTrampoline = true;
} }
@@ -740,6 +703,10 @@ _EmitNE:
sb._appendString(&reg16[index * 4]); sb._appendString(&reg16[index * 4]);
return; return;
case kX86RegTypeK:
sb._appendString("k", 1);
goto _EmitID;
case kX86RegTypeFp: case kX86RegTypeFp:
sb._appendString("fp", 2); sb._appendString("fp", 2);
goto _EmitID; goto _EmitID;
@@ -756,6 +723,10 @@ _EmitNE:
sb._appendString("ymm", 3); sb._appendString("ymm", 3);
goto _EmitID; goto _EmitID;
case kX86RegTypeZmm:
sb._appendString("zmm", 3);
goto _EmitID;
case kX86RegTypeSeg: case kX86RegTypeSeg:
if (index >= kX86SegCount) if (index >= kX86SegCount)
goto _EmitNE; goto _EmitNE;
@@ -952,19 +923,33 @@ static const Operand::VRegOp x86PatchedHiRegs[4] = {
#undef HI_REG #undef HI_REG
template<int Arch> template<int Arch>
static Error ASMJIT_CDECL X86Assembler_emit(Assembler* self_, uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) { static ASMJIT_INLINE Error X86Assembler_emit(Assembler* self_, uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) {
X86Assembler* self = static_cast<X86Assembler*>(self_); X86Assembler* self = static_cast<X86Assembler*>(self_);
uint8_t* cursor = self->getCursor();
uint32_t encoded = o0->getOp() + (o1->getOp() << 3) + (o2->getOp() << 6);
uint32_t options = self->getInstOptionsAndReset(); uint32_t options = self->getInstOptionsAndReset();
// Invalid instruction. // Invalid instruction.
if (code >= _kX86InstIdCount) { if (code >= _kX86InstIdCount) {
self->_comment = NULL; self->_comment = NULL;
return self->setError(kErrorUnknownInst); return self->setLastError(kErrorUnknownInst);
} }
// --------------------------------------------------------------------------
// [Grow]
// --------------------------------------------------------------------------
// Grow request happens rarely.
uint8_t* cursor = self->getCursor();
if (ASMJIT_UNLIKELY((size_t)(self->_end - cursor) < 16)) {
ASMJIT_PROPAGATE_ERROR(self->_grow(16));
cursor = self->getCursor();
}
// --------------------------------------------------------------------------
// [Prepare]
// --------------------------------------------------------------------------
uint32_t encoded = o0->getOp() + (o1->getOp() << 3) + (o2->getOp() << 6);
// Instruction opcode. // Instruction opcode.
uint32_t opCode; uint32_t opCode;
// ModR/M opcode or register code. // ModR/M opcode or register code.
@@ -1005,16 +990,6 @@ static Error ASMJIT_CDECL X86Assembler_emit(Assembler* self_, uint32_t code, con
const X86InstInfo& info = _x86InstInfo[code]; const X86InstInfo& info = _x86InstInfo[code];
const X86InstExtendedInfo& extendedInfo = info.getExtendedInfo(); const X86InstExtendedInfo& extendedInfo = info.getExtendedInfo();
// Grow request happens rarely. C++ compiler generates better code if it is
// handled at the end of the function.
if ((size_t)(self->_end - cursor) < 16)
goto _GrowBuffer;
// --------------------------------------------------------------------------
// [Prepare]
// --------------------------------------------------------------------------
_Prepare:
opCode = info.getPrimaryOpCode(); opCode = info.getPrimaryOpCode();
opReg = x86ExtractO(opCode); opReg = x86ExtractO(opCode);
@@ -1196,7 +1171,7 @@ _Prepare:
if (encoded == ENC_OPS(Reg, Imm, None)) { if (encoded == ENC_OPS(Reg, Imm, None)) {
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = IntUtil::isInt8(imVal) ? static_cast<uint32_t>(1) : IntUtil::iMin<uint32_t>(o0->getSize(), 4); imLen = Utils::isInt8(imVal) ? static_cast<uint32_t>(1) : Utils::iMin<uint32_t>(o0->getSize(), 4);
rmReg = x86OpReg(o0); rmReg = x86OpReg(o0);
ADD_66H_P_BY_SIZE(o0->getSize()); ADD_66H_P_BY_SIZE(o0->getSize());
@@ -1206,7 +1181,7 @@ _Prepare:
if (rmReg == 0 && (o0->getSize() == 1 || imLen != 1)) { if (rmReg == 0 && (o0->getSize() == 1 || imLen != 1)) {
opCode &= kX86InstOpCode_PP_66 | kX86InstOpCode_W; opCode &= kX86InstOpCode_PP_66 | kX86InstOpCode_W;
opCode |= ((opReg << 3) | (0x04 + (o0->getSize() != 1))); opCode |= ((opReg << 3) | (0x04 + (o0->getSize() != 1)));
imLen = IntUtil::iMin<uint32_t>(o0->getSize(), 4); imLen = Utils::iMin<uint32_t>(o0->getSize(), 4);
goto _EmitX86Op; goto _EmitX86Op;
} }
@@ -1221,7 +1196,7 @@ _Prepare:
goto _IllegalInst; goto _IllegalInst;
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = IntUtil::isInt8(imVal) ? static_cast<uint32_t>(1) : IntUtil::iMin<uint32_t>(memSize, 4); imLen = Utils::isInt8(imVal) ? static_cast<uint32_t>(1) : Utils::iMin<uint32_t>(memSize, 4);
opCode += memSize != 1 ? (imLen != 1 ? 1 : 3) : 0; opCode += memSize != 1 ? (imLen != 1 ? 1 : 3) : 0;
ADD_66H_P_BY_SIZE(memSize); ADD_66H_P_BY_SIZE(memSize);
@@ -1388,7 +1363,7 @@ _Prepare:
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = 1; imLen = 1;
if (!IntUtil::isInt8(imVal)) { if (!Utils::isInt8(imVal)) {
opCode -= 2; opCode -= 2;
imLen = o0->getSize() == 2 ? 2 : 4; imLen = o0->getSize() == 2 ? 2 : 4;
} }
@@ -1404,7 +1379,7 @@ _Prepare:
imVal = static_cast<const Imm*>(o2)->getInt64(); imVal = static_cast<const Imm*>(o2)->getInt64();
imLen = 1; imLen = 1;
if (!IntUtil::isInt8(imVal)) { if (!Utils::isInt8(imVal)) {
opCode -= 2; opCode -= 2;
imLen = o0->getSize() == 2 ? 2 : 4; imLen = o0->getSize() == 2 ? 2 : 4;
} }
@@ -1420,7 +1395,7 @@ _Prepare:
imVal = static_cast<const Imm*>(o2)->getInt64(); imVal = static_cast<const Imm*>(o2)->getInt64();
imLen = 1; imLen = 1;
if (!IntUtil::isInt8(imVal)) { if (!Utils::isInt8(imVal)) {
opCode -= 2; opCode -= 2;
imLen = o0->getSize() == 2 ? 2 : 4; imLen = o0->getSize() == 2 ? 2 : 4;
} }
@@ -1477,7 +1452,7 @@ _Prepare:
if (encoded == ENC_OPS(Label, None, None)) { if (encoded == ENC_OPS(Label, None, None)) {
label = self->getLabelData(static_cast<const Label*>(o0)->getId()); label = self->getLabelData(static_cast<const Label*>(o0)->getId());
if (self->hasFeature(kCodeGenPredictedJumps)) { if (self->hasFeature(kAssemblerFeaturePredictedJumps)) {
if (options & kInstOptionTaken) if (options & kInstOptionTaken)
EMIT_BYTE(0x3E); EMIT_BYTE(0x3E);
if (options & kInstOptionNotTaken) if (options & kInstOptionNotTaken)
@@ -1492,7 +1467,7 @@ _Prepare:
intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer); intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer);
ASMJIT_ASSERT(offs <= 0); ASMJIT_ASSERT(offs <= 0);
if ((options & kInstOptionLongForm) == 0 && IntUtil::isInt8(offs - kRel8Size)) { if ((options & kInstOptionLongForm) == 0 && Utils::isInt8(offs - kRel8Size)) {
EMIT_OP(opCode); EMIT_OP(opCode);
EMIT_BYTE(offs - kRel8Size); EMIT_BYTE(offs - kRel8Size);
@@ -1544,7 +1519,7 @@ _Prepare:
if (label->offset != -1) { if (label->offset != -1) {
// Bound label. // Bound label.
intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer) - 1; intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer) - 1;
if (!IntUtil::isInt8(offs)) if (!Utils::isInt8(offs))
goto _IllegalInst; goto _IllegalInst;
EMIT_BYTE(offs); EMIT_BYTE(offs);
@@ -1588,7 +1563,7 @@ _Prepare:
intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer); intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer);
if ((options & kInstOptionLongForm) == 0 && IntUtil::isInt8(offs - kRel8Size)) { if ((options & kInstOptionLongForm) == 0 && Utils::isInt8(offs - kRel8Size)) {
options |= kInstOptionShortForm; options |= kInstOptionShortForm;
EMIT_BYTE(0xEB); EMIT_BYTE(0xEB);
@@ -1746,7 +1721,7 @@ _Prepare:
rmReg = x86OpReg(o0); rmReg = x86OpReg(o0);
// Optimize instruction size by using 32-bit immediate if possible. // Optimize instruction size by using 32-bit immediate if possible.
if (Arch == kArchX64 && imLen == 8 && IntUtil::isInt32(imVal)) { if (Arch == kArchX64 && imLen == 8 && Utils::isInt32(imVal)) {
opCode = 0xC7; opCode = 0xC7;
ADD_REX_W(1); ADD_REX_W(1);
imLen = 4; imLen = 4;
@@ -1769,7 +1744,7 @@ _Prepare:
goto _IllegalInst; goto _IllegalInst;
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = IntUtil::iMin<uint32_t>(memSize, 4); imLen = Utils::iMin<uint32_t>(memSize, 4);
opCode = 0xC6 + (memSize != 1); opCode = 0xC6 + (memSize != 1);
opReg = 0; opReg = 0;
@@ -1869,7 +1844,7 @@ _Prepare:
if (encoded == ENC_OPS(Imm, None, None)) { if (encoded == ENC_OPS(Imm, None, None)) {
imVal = static_cast<const Imm*>(o0)->getInt64(); imVal = static_cast<const Imm*>(o0)->getInt64();
imLen = IntUtil::isInt8(imVal) ? 1 : 4; imLen = Utils::isInt8(imVal) ? 1 : 4;
EMIT_BYTE(imLen == 1 ? 0x6A : 0x68); EMIT_BYTE(imLen == 1 ? 0x6A : 0x68);
goto _EmitImm; goto _EmitImm;
@@ -2074,7 +2049,7 @@ _GroupPop_Gp:
if (encoded == ENC_OPS(Reg, Imm, None)) { if (encoded == ENC_OPS(Reg, Imm, None)) {
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = IntUtil::iMin<uint32_t>(o0->getSize(), 4); imLen = Utils::iMin<uint32_t>(o0->getSize(), 4);
ADD_66H_P_BY_SIZE(o0->getSize()); ADD_66H_P_BY_SIZE(o0->getSize());
ADD_REX_W_BY_SIZE(o0->getSize()); ADD_REX_W_BY_SIZE(o0->getSize());
@@ -2095,7 +2070,7 @@ _GroupPop_Gp:
goto _IllegalInst; goto _IllegalInst;
imVal = static_cast<const Imm*>(o1)->getInt64(); imVal = static_cast<const Imm*>(o1)->getInt64();
imLen = IntUtil::iMin<uint32_t>(o0->getSize(), 4); imLen = Utils::iMin<uint32_t>(o0->getSize(), 4);
ADD_66H_P_BY_SIZE(o0->getSize()); ADD_66H_P_BY_SIZE(o0->getSize());
ADD_REX_W_BY_SIZE(o0->getSize()); ADD_REX_W_BY_SIZE(o0->getSize());
@@ -2115,7 +2090,7 @@ _GroupPop_Gp:
rmMem = x86OpMem(o1); rmMem = x86OpMem(o1);
goto _EmitX86M; goto _EmitX86M;
} }
// ... fall through ... // ... Fall through ...
case kX86InstEncodingIdX86Xadd: case kX86InstEncodingIdX86Xadd:
if (encoded == ENC_OPS(Reg, Reg, None)) { if (encoded == ENC_OPS(Reg, Reg, None)) {
@@ -3478,21 +3453,21 @@ _AvxRmMr_AfterRegRegCheck:
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
_IllegalInst: _IllegalInst:
self->setError(kErrorIllegalInst); self->setLastError(kErrorIllegalInst);
#if defined(ASMJIT_DEBUG) #if defined(ASMJIT_DEBUG)
assertIllegal = true; assertIllegal = true;
#endif // ASMJIT_DEBUG #endif // ASMJIT_DEBUG
goto _EmitDone; goto _EmitDone;
_IllegalAddr: _IllegalAddr:
self->setError(kErrorIllegalAddresing); self->setLastError(kErrorIllegalAddresing);
#if defined(ASMJIT_DEBUG) #if defined(ASMJIT_DEBUG)
assertIllegal = true; assertIllegal = true;
#endif // ASMJIT_DEBUG #endif // ASMJIT_DEBUG
goto _EmitDone; goto _EmitDone;
_IllegalDisp: _IllegalDisp:
self->setError(kErrorIllegalDisplacement); self->setLastError(kErrorIllegalDisplacement);
#if defined(ASMJIT_DEBUG) #if defined(ASMJIT_DEBUG)
assertIllegal = true; assertIllegal = true;
#endif // ASMJIT_DEBUG #endif // ASMJIT_DEBUG
@@ -3658,7 +3633,7 @@ _EmitSib:
EMIT_BYTE(x86EncodeMod(0, opReg, 4)); EMIT_BYTE(x86EncodeMod(0, opReg, 4));
EMIT_BYTE(x86EncodeSib(0, 4, 4)); EMIT_BYTE(x86EncodeSib(0, 4, 4));
} }
else if (IntUtil::isInt8(dispOffset)) { else if (Utils::isInt8(dispOffset)) {
// [Esp/Rsp/R12 + Disp8]. // [Esp/Rsp/R12 + Disp8].
EMIT_BYTE(x86EncodeMod(1, opReg, 4)); EMIT_BYTE(x86EncodeMod(1, opReg, 4));
EMIT_BYTE(x86EncodeSib(0, 4, 4)); EMIT_BYTE(x86EncodeSib(0, 4, 4));
@@ -3675,7 +3650,7 @@ _EmitSib:
// [Base]. // [Base].
EMIT_BYTE(x86EncodeMod(0, opReg, mBase)); EMIT_BYTE(x86EncodeMod(0, opReg, mBase));
} }
else if (IntUtil::isInt8(dispOffset)) { else if (Utils::isInt8(dispOffset)) {
// [Base + Disp8]. // [Base + Disp8].
EMIT_BYTE(x86EncodeMod(1, opReg, mBase)); EMIT_BYTE(x86EncodeMod(1, opReg, mBase));
EMIT_BYTE(static_cast<int8_t>(dispOffset)); EMIT_BYTE(static_cast<int8_t>(dispOffset));
@@ -3698,7 +3673,7 @@ _EmitSib:
EMIT_BYTE(x86EncodeMod(0, opReg, 4)); EMIT_BYTE(x86EncodeMod(0, opReg, 4));
EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase)); EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase));
} }
else if (IntUtil::isInt8(dispOffset)) { else if (Utils::isInt8(dispOffset)) {
// [Base + Index * Scale + Disp8]. // [Base + Index * Scale + Disp8].
EMIT_BYTE(x86EncodeMod(1, opReg, 4)); EMIT_BYTE(x86EncodeMod(1, opReg, 4));
EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase)); EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase));
@@ -3742,7 +3717,7 @@ _EmitSib:
rd.data = static_cast<SignedPtr>(dispOffset); rd.data = static_cast<SignedPtr>(dispOffset);
if (self->_relocList.append(rd) != kErrorOk) if (self->_relocList.append(rd) != kErrorOk)
return self->setError(kErrorNoHeapMemory); return self->setLastError(kErrorNoHeapMemory);
if (label->offset != -1) { if (label->offset != -1) {
// Bound label. // Bound label.
@@ -3767,7 +3742,7 @@ _EmitSib:
rd.data = rd.from + static_cast<SignedPtr>(dispOffset); rd.data = rd.from + static_cast<SignedPtr>(dispOffset);
if (self->_relocList.append(rd) != kErrorOk) if (self->_relocList.append(rd) != kErrorOk)
return self->setError(kErrorNoHeapMemory); return self->setLastError(kErrorNoHeapMemory);
EMIT_DWORD(0); EMIT_DWORD(0);
} }
@@ -3997,7 +3972,7 @@ _EmitAvxV:
EMIT_BYTE(x86EncodeMod(0, opReg, 4)); EMIT_BYTE(x86EncodeMod(0, opReg, 4));
EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase)); EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase));
} }
else if (IntUtil::isInt8(dispOffset)) { else if (Utils::isInt8(dispOffset)) {
// [Base + Index * Scale + Disp8]. // [Base + Index * Scale + Disp8].
EMIT_BYTE(x86EncodeMod(1, opReg, 4)); EMIT_BYTE(x86EncodeMod(1, opReg, 4));
EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase)); EMIT_BYTE(x86EncodeSib(shift, mIndex, mBase));
@@ -4033,7 +4008,7 @@ _EmitAvxV:
rd.data = static_cast<SignedPtr>(dispOffset); rd.data = static_cast<SignedPtr>(dispOffset);
if (self->_relocList.append(rd) != kErrorOk) if (self->_relocList.append(rd) != kErrorOk)
return self->setError(kErrorNoHeapMemory); return self->setLastError(kErrorNoHeapMemory);
} }
if (label->offset != -1) { if (label->offset != -1) {
@@ -4147,7 +4122,6 @@ _EmitXopM:
// trampoline, it's better to use 6-byte `jmp/call` (prefixing it with REX // trampoline, it's better to use 6-byte `jmp/call` (prefixing it with REX
// prefix) and to patch the `jmp/call` instruction to read the address from // prefix) and to patch the `jmp/call` instruction to read the address from
// a memory in case the trampoline is needed. // a memory in case the trampoline is needed.
//
_EmitJmpOrCallAbs: _EmitJmpOrCallAbs:
{ {
RelocData rd; RelocData rd;
@@ -4159,7 +4133,7 @@ _EmitJmpOrCallAbs:
uint32_t trampolineSize = 0; uint32_t trampolineSize = 0;
if (Arch == kArchX64) { if (Arch == kArchX64) {
Ptr baseAddress = self->getBaseAddress(); Ptr baseAddress = self->getRuntime()->getBaseAddress();
// If the base address of the output is known, it's possible to determine // If the base address of the output is known, it's possible to determine
// the need for a trampoline here. This saves possible REX prefix in // the need for a trampoline here. This saves possible REX prefix in
@@ -4182,10 +4156,10 @@ _EmitJmpOrCallAbs:
EMIT_DWORD(0); EMIT_DWORD(0);
if (self->_relocList.append(rd) != kErrorOk) if (self->_relocList.append(rd) != kErrorOk)
return self->setError(kErrorNoHeapMemory); return self->setLastError(kErrorNoHeapMemory);
// Reserve space for a possible trampoline. // Reserve space for a possible trampoline.
self->_trampolineSize += trampolineSize; self->_trampolinesSize += trampolineSize;
} }
goto _EmitDone; goto _EmitDone;
@@ -4227,7 +4201,7 @@ _EmitDone:
# else # else
if (self->_logger) { if (self->_logger) {
# endif // ASMJIT_DEBUG # endif // ASMJIT_DEBUG
StringBuilderT<512> sb; StringBuilderTmp<512> sb;
uint32_t loggerOptions = 0; uint32_t loggerOptions = 0;
if (self->_logger) { if (self->_logger) {
@@ -4248,9 +4222,9 @@ _EmitDone:
self->_logger->logString(kLoggerStyleDefault, sb.getData(), sb.getLength()); self->_logger->logString(kLoggerStyleDefault, sb.getData(), sb.getLength());
# if defined(ASMJIT_DEBUG) # if defined(ASMJIT_DEBUG)
// Raise an assertion failure, because this situation shouldn't happen. // This shouldn't happen.
if (assertIllegal) if (assertIllegal)
assertionFailed(sb.getData(), __FILE__, __LINE__); DebugUtils::assertionFailed(__FILE__, __LINE__, sb.getData());
# endif // ASMJIT_DEBUG # endif // ASMJIT_DEBUG
} }
#else #else
@@ -4263,12 +4237,6 @@ _EmitDone:
self->setCursor(cursor); self->setCursor(cursor);
return kErrorOk; return kErrorOk;
_GrowBuffer:
ASMJIT_PROPAGATE_ERROR(self->_grow(16));
cursor = self->getCursor();
goto _Prepare;
} }
Error X86Assembler::_emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) { Error X86Assembler::_emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {

View File

@@ -379,13 +379,13 @@ namespace asmjit {
//! functions available that return a new register operand. //! functions available that return a new register operand.
//! //!
//! \sa X86Compiler. //! \sa X86Compiler.
struct ASMJIT_VCLASS X86Assembler : public Assembler { struct ASMJIT_VIRTAPI X86Assembler : public Assembler {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API X86Assembler(Runtime* runtime, uint32_t arch ASMJIT_API X86Assembler(Runtime* runtime, uint32_t arch
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
= kArchHost = kArchHost
#endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64 #endif // ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
); );
@@ -395,17 +395,18 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
// [Arch] // [Arch]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! \internal
//!
//! Set the assembler architecture to `kArchX86` or `kArchX64`.
ASMJIT_API Error _setArch(uint32_t arch);
//! Get count of registers of the current architecture and mode. //! Get count of registers of the current architecture and mode.
ASMJIT_INLINE const X86RegCount& getRegCount() const { ASMJIT_INLINE const X86RegCount& getRegCount() const { return _regCount; }
return _regCount;
}
//! Get Gpd or Gpq register depending on the current architecture. //! Get DWORD or QWORD register depending on the current architecture.
ASMJIT_INLINE X86GpReg gpz(uint32_t index) const { ASMJIT_INLINE X86GpReg gpz(uint32_t index) const { return X86GpReg(zax, index); }
return X86GpReg(zax, index);
}
//! Create an architecture dependent intptr_t memory operand. //! Create an `intptr_t` memory operand depending on the current architecture.
ASMJIT_INLINE X86Mem intptr_ptr(const X86GpReg& base, int32_t disp = 0) const { ASMJIT_INLINE X86Mem intptr_ptr(const X86GpReg& base, int32_t disp = 0) const {
return x86::ptr(base, disp, _regSize); return x86::ptr(base, disp, _regSize);
} }
@@ -434,8 +435,6 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
return x86::ptr_abs(pAbs, index, shift, disp, _regSize); return x86::ptr_abs(pAbs, index, shift, disp, _regSize);
} }
ASMJIT_API Error setArch(uint32_t arch);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Embed] // [Embed]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -492,7 +491,7 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
// [Align] // [Align]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API virtual Error align(uint32_t mode, uint32_t offset); ASMJIT_API virtual Error align(uint32_t alignMode, uint32_t offset);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reloc] // [Reloc]
@@ -559,13 +558,13 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
#define INST_1i(_Inst_, _Code_, _Op0_) \ #define INST_1i(_Inst_, _Code_, _Op0_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0) { return emit(_Code_, o0); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0) { return emit(_Code_, o0); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(int o0) { return emit(_Code_, asInt(o0)); } \ ASMJIT_INLINE Error _Inst_(int o0) { return emit(_Code_, Utils::asInt(o0)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(unsigned int o0) { return emit(_Code_, asInt(o0)); } \ ASMJIT_INLINE Error _Inst_(unsigned int o0) { return emit(_Code_, Utils::asInt(o0)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(int64_t o0) { return emit(_Code_, asInt(o0)); } \ ASMJIT_INLINE Error _Inst_(int64_t o0) { return emit(_Code_, Utils::asInt(o0)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(uint64_t o0) { return emit(_Code_, asInt(o0)); } ASMJIT_INLINE Error _Inst_(uint64_t o0) { return emit(_Code_, Utils::asInt(o0)); }
#define INST_1cc(_Inst_, _Code_, _Translate_, _Op0_) \ #define INST_1cc(_Inst_, _Code_, _Translate_, _Op0_) \
ASMJIT_INLINE Error _Inst_(uint32_t cc, const _Op0_& o0) { \ ASMJIT_INLINE Error _Inst_(uint32_t cc, const _Op0_& o0) { \
@@ -617,13 +616,13 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
#define INST_2i(_Inst_, _Code_, _Op0_, _Op1_) \ #define INST_2i(_Inst_, _Code_, _Op0_, _Op1_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1) { return emit(_Code_, o0, o1); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1) { return emit(_Code_, o0, o1); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int o1) { return emit(_Code_, o0, asInt(o1)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int o1) { return emit(_Code_, o0, Utils::asInt(o1)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, unsigned int o1) { return emit(_Code_, o0, asInt(o1)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, unsigned int o1) { return emit(_Code_, o0, Utils::asInt(o1)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int64_t o1) { return emit(_Code_, o0, asInt(o1)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int64_t o1) { return emit(_Code_, o0, Utils::asInt(o1)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, uint64_t o1) { return emit(_Code_, o0, asInt(o1)); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, uint64_t o1) { return emit(_Code_, o0, Utils::asInt(o1)); }
#define INST_2cc(_Inst_, _Code_, _Translate_, _Op0_, _Op1_) \ #define INST_2cc(_Inst_, _Code_, _Translate_, _Op0_, _Op1_) \
ASMJIT_INLINE Error _Inst_(uint32_t cc, const _Op0_& o0, const _Op1_& o1) { \ ASMJIT_INLINE Error _Inst_(uint32_t cc, const _Op0_& o0, const _Op1_& o1) { \
@@ -667,24 +666,24 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
#define INST_3i(_Inst_, _Code_, _Op0_, _Op1_, _Op2_) \ #define INST_3i(_Inst_, _Code_, _Op0_, _Op1_, _Op2_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2) { return emit(_Code_, o0, o1, o2); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2) { return emit(_Code_, o0, o1, o2); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int o2) { return emit(_Code_, o0, o1, asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int o2) { return emit(_Code_, o0, o1, Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, unsigned int o2) { return emit(_Code_, o0, o1, asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, unsigned int o2) { return emit(_Code_, o0, o1, Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int64_t o2) { return emit(_Code_, o0, o1, asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int64_t o2) { return emit(_Code_, o0, o1, Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, uint64_t o2) { return emit(_Code_, o0, o1, asInt(o2)); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, uint64_t o2) { return emit(_Code_, o0, o1, Utils::asInt(o2)); }
#define INST_3ii(_Inst_, _Code_, _Op0_, _Op1_, _Op2_) \ #define INST_3ii(_Inst_, _Code_, _Op0_, _Op1_, _Op2_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2) { return emit(_Code_, o0, o1, o2); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2) { return emit(_Code_, o0, o1, o2); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int o1, int o2) { return emit(_Code_, o0, Imm(o1), asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int o1, int o2) { return emit(_Code_, o0, Imm(o1), Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, unsigned int o1, unsigned int o2) { return emit(_Code_, o0, Imm(o1), asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, unsigned int o1, unsigned int o2) { return emit(_Code_, o0, Imm(o1), Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int64_t o1, int64_t o2) { return emit(_Code_, o0, Imm(o1), asInt(o2)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, int64_t o1, int64_t o2) { return emit(_Code_, o0, Imm(o1), Utils::asInt(o2)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, uint64_t o1, uint64_t o2) { return emit(_Code_, o0, Imm(o1), asInt(o2)); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, uint64_t o1, uint64_t o2) { return emit(_Code_, o0, Imm(o1), Utils::asInt(o2)); }
#define INST_4x(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \ #define INST_4x(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); }
@@ -692,24 +691,24 @@ struct ASMJIT_VCLASS X86Assembler : public Assembler {
#define INST_4i(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \ #define INST_4i(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, int o3) { return emit(_Code_, o0, o1, o2, asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, int o3) { return emit(_Code_, o0, o1, o2, Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, unsigned int o3) { return emit(_Code_, o0, o1, o2, asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, unsigned int o3) { return emit(_Code_, o0, o1, o2, Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, int64_t o3) { return emit(_Code_, o0, o1, o2, asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, int64_t o3) { return emit(_Code_, o0, o1, o2, Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, uint64_t o3) { return emit(_Code_, o0, o1, o2, asInt(o3)); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, uint64_t o3) { return emit(_Code_, o0, o1, o2, Utils::asInt(o3)); }
#define INST_4ii(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \ #define INST_4ii(_Inst_, _Code_, _Op0_, _Op1_, _Op2_, _Op3_) \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, const _Op2_& o2, const _Op3_& o3) { return emit(_Code_, o0, o1, o2, o3); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int o2, int o3) { return emit(_Code_, o0, o1, Imm(o2), asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int o2, int o3) { return emit(_Code_, o0, o1, Imm(o2), Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, unsigned int o2, unsigned int o3) { return emit(_Code_, o0, o1, Imm(o2), asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, unsigned int o2, unsigned int o3) { return emit(_Code_, o0, o1, Imm(o2), Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int64_t o2, int64_t o3) { return emit(_Code_, o0, o1, Imm(o2), asInt(o3)); } \ ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, int64_t o2, int64_t o3) { return emit(_Code_, o0, o1, Imm(o2), Utils::asInt(o3)); } \
/*! \overload */ \ /*! \overload */ \
ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, uint64_t o2, uint64_t o3) { return emit(_Code_, o0, o1, Imm(o2), asInt(o3)); } ASMJIT_INLINE Error _Inst_(const _Op0_& o0, const _Op1_& o1, uint64_t o2, uint64_t o3) { return emit(_Code_, o0, o1, Imm(o2), Utils::asInt(o3)); }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [X86/X64] // [X86/X64]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -5,16 +5,16 @@
// Zlib - See LICENSE.md file in the package. // Zlib - See LICENSE.md file in the package.
// [Guard] // [Guard]
#ifndef _ASMJIT_X86_X86CONTEXT_P_H #ifndef _ASMJIT_X86_X86COMPILERCONTEXT_P_H
#define _ASMJIT_X86_X86CONTEXT_P_H #define _ASMJIT_X86_X86COMPILERCONTEXT_P_H
#include "../build.h" #include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER) #if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/compiler.h" #include "../base/compiler.h"
#include "../base/context_p.h" #include "../base/compilercontext_p.h"
#include "../base/intutil.h" #include "../base/utils.h"
#include "../x86/x86assembler.h" #include "../x86/x86assembler.h"
#include "../x86/x86compiler.h" #include "../x86/x86compiler.h"
@@ -23,9 +23,228 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_x86_compiler //! \addtogroup asmjit_x86
//! \{ //! \{
// ============================================================================
// [asmjit::X86VarMap]
// ============================================================================
struct X86VarMap : public VarMap {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get variable-attributes list as VarAttr data.
ASMJIT_INLINE VarAttr* getVaList() const {
return const_cast<VarAttr*>(_list);
}
//! Get variable-attributes list as VarAttr data (by class).
ASMJIT_INLINE VarAttr* getVaListByClass(uint32_t rc) const {
return const_cast<VarAttr*>(_list) + _start.get(rc);
}
//! Get position of variables (by class).
ASMJIT_INLINE uint32_t getVaStart(uint32_t rc) const {
return _start.get(rc);
}
//! Get count of variables (by class).
ASMJIT_INLINE uint32_t getVaCountByClass(uint32_t rc) const {
return _count.get(rc);
}
//! Get VarAttr at `index`.
ASMJIT_INLINE VarAttr* getVa(uint32_t index) const {
ASMJIT_ASSERT(index < _vaCount);
return getVaList() + index;
}
//! Get VarAttr of `c` class at `index`.
ASMJIT_INLINE VarAttr* getVaByClass(uint32_t rc, uint32_t index) const {
ASMJIT_ASSERT(index < _count._regs[rc]);
return getVaListByClass(rc) + index;
}
// --------------------------------------------------------------------------
// [Utils]
// --------------------------------------------------------------------------
//! Find VarAttr.
ASMJIT_INLINE VarAttr* findVa(VarData* vd) const {
VarAttr* list = getVaList();
uint32_t count = getVaCount();
for (uint32_t i = 0; i < count; i++)
if (list[i].getVd() == vd)
return &list[i];
return NULL;
}
//! Find VarAttr (by class).
ASMJIT_INLINE VarAttr* findVaByClass(uint32_t rc, VarData* vd) const {
VarAttr* list = getVaListByClass(rc);
uint32_t count = getVaCountByClass(rc);
for (uint32_t i = 0; i < count; i++)
if (list[i].getVd() == vd)
return &list[i];
return NULL;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Special registers on input.
//!
//! Special register(s) restricted to one or more physical register. If there
//! is more than one special register it means that we have to duplicate the
//! variable content to all of them (it means that the same varible was used
//! by two or more operands). We forget about duplicates after the register
//! allocation finishes and marks all duplicates as non-assigned.
X86RegMask _inRegs;
//! Special registers on output.
//!
//! Special register(s) used on output. Each variable can have only one
//! special register on the output, 'X86VarMap' contains all registers from
//! all 'VarAttr's.
X86RegMask _outRegs;
//! Clobbered registers (by a function call).
X86RegMask _clobberedRegs;
//! Start indexes of variables per register class.
X86RegCount _start;
//! Count of variables per register class.
X86RegCount _count;
//! VarAttr list.
VarAttr _list[1];
};
// ============================================================================
// [asmjit::X86StateCell]
// ============================================================================
//! X86/X64 state-cell.
union X86StateCell {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t getState() const {
return _state;
}
ASMJIT_INLINE void setState(uint32_t state) {
_state = static_cast<uint8_t>(state);
}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() { _packed = 0; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint8_t _packed;
struct {
uint8_t _state : 2;
uint8_t _unused : 6;
};
};
// ============================================================================
// [asmjit::X86VarState]
// ============================================================================
//! X86/X64 state.
struct X86VarState : VarState {
enum {
//! Base index of Gp registers.
kGpIndex = 0,
//! Count of Gp registers.
kGpCount = 16,
//! Base index of Mm registers.
kMmIndex = kGpIndex + kGpCount,
//! Count of Mm registers.
kMmCount = 8,
//! Base index of Xmm registers.
kXmmIndex = kMmIndex + kMmCount,
//! Count of Xmm registers.
kXmmCount = 16,
//! Count of all registers in `X86VarState`.
kAllCount = kXmmIndex + kXmmCount
};
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE VarData** getList() {
return _list;
}
ASMJIT_INLINE VarData** getListByClass(uint32_t rc) {
switch (rc) {
case kX86RegClassGp : return _listGp;
case kX86RegClassMm : return _listMm;
case kX86RegClassXyz: return _listXmm;
default:
return NULL;
}
}
// --------------------------------------------------------------------------
// [Clear]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset(size_t numCells) {
::memset(this, 0, kAllCount * sizeof(VarData*) +
2 * sizeof(X86RegMask) +
numCells * sizeof(X86StateCell));
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
//! List of all allocated variables in one array.
VarData* _list[kAllCount];
struct {
//! Allocated Gp registers.
VarData* _listGp[kGpCount];
//! Allocated Mm registers.
VarData* _listMm[kMmCount];
//! Allocated Xmm registers.
VarData* _listXmm[kXmmCount];
};
};
//! Occupied registers (mask).
X86RegMask _occupied;
//! Modified registers (mask).
X86RegMask _modified;
//! Variables data, the length is stored in `X86Context`.
X86StateCell _cells[1];
};
// ============================================================================ // ============================================================================
// [asmjit::X86Context] // [asmjit::X86Context]
// ============================================================================ // ============================================================================
@@ -38,11 +257,13 @@ namespace asmjit {
//! \internal //! \internal
//! //!
//! Compiler context is used by `X86Compiler`. //! Compiler context, used by `X86Compiler`.
//! //!
//! Compiler context is used during compilation and normally developer doesn't //! Compiler context takes care of generating function prolog and epilog, and
//! need access to it. The context is user per function (it's reset after each //! also performs register allocation. It's used during the compilation phase
//! function is generated). //! and considered an implementation detail and asmjit consumers don't have
//! access to it. The context is used once per function and it's reset after
//! the function is processed.
struct X86Context : public Context { struct X86Context : public Context {
ASMJIT_NO_COPY(X86Context) ASMJIT_NO_COPY(X86Context)
@@ -65,28 +286,19 @@ struct X86Context : public Context {
// [Arch] // [Arch]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE bool isX64() const { ASMJIT_INLINE bool isX64() const { return _zsp.getSize() == 16; }
return _zsp.getSize() == 16; ASMJIT_INLINE uint32_t getRegSize() const { return _zsp.getSize(); }
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get compiler as `X86Compiler`. //! Get compiler as `X86Compiler`.
ASMJIT_INLINE X86Compiler* getCompiler() const { ASMJIT_INLINE X86Compiler* getCompiler() const { return static_cast<X86Compiler*>(_compiler); }
return static_cast<X86Compiler*>(_compiler);
}
//! Get function as `X86FuncNode`. //! Get function as `X86FuncNode`.
ASMJIT_INLINE X86FuncNode* getFunc() const { ASMJIT_INLINE X86FuncNode* getFunc() const { return reinterpret_cast<X86FuncNode*>(_func); }
return reinterpret_cast<X86FuncNode*>(_func);
}
//! Get clobbered registers (global). //! Get clobbered registers (global).
ASMJIT_INLINE uint32_t getClobberedRegs(uint32_t c) { ASMJIT_INLINE uint32_t getClobberedRegs(uint32_t rc) { return _clobberedRegs.get(rc); }
return _clobberedRegs.get(c);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Helpers] // [Helpers]
@@ -94,7 +306,7 @@ struct X86Context : public Context {
ASMJIT_INLINE X86VarMap* newVarMap(uint32_t vaCount) { ASMJIT_INLINE X86VarMap* newVarMap(uint32_t vaCount) {
return static_cast<X86VarMap*>( return static_cast<X86VarMap*>(
_baseZone.alloc(sizeof(X86VarMap) + vaCount * sizeof(VarAttr))); _zoneAllocator.alloc(sizeof(X86VarMap) + vaCount * sizeof(VarAttr)));
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -121,10 +333,6 @@ struct X86Context : public Context {
void _checkState(); void _checkState();
ASMJIT_INLINE uint32_t getRegSize() const {
return _zsp.getSize();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Attach / Detach] // [Attach / Detach]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -142,12 +350,12 @@ struct X86Context : public Context {
// Prevent Esp allocation if C==Gp. // Prevent Esp allocation if C==Gp.
ASMJIT_ASSERT(C != kX86RegClassGp || regIndex != kX86RegIndexSp); ASMJIT_ASSERT(C != kX86RegClassGp || regIndex != kX86RegIndexSp);
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = Utils::mask(regIndex);
vd->setState(kVarStateReg); vd->setState(kVarStateReg);
vd->setModified(modified);
vd->setRegIndex(regIndex); vd->setRegIndex(regIndex);
vd->addHomeIndex(regIndex); vd->addHomeIndex(regIndex);
vd->setModified(modified);
_x86State.getListByClass(C)[regIndex] = vd; _x86State.getListByClass(C)[regIndex] = vd;
_x86State._occupied.or_(C, regMask); _x86State._occupied.or_(C, regMask);
@@ -167,7 +375,7 @@ struct X86Context : public Context {
ASMJIT_ASSERT(vd->getRegIndex() == regIndex); ASMJIT_ASSERT(vd->getRegIndex() == regIndex);
ASMJIT_ASSERT(vState != kVarStateReg); ASMJIT_ASSERT(vState != kVarStateReg);
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = Utils::mask(regIndex);
vd->setState(vState); vd->setState(vState);
vd->resetRegIndex(); vd->resetRegIndex();
@@ -188,13 +396,13 @@ struct X86Context : public Context {
//! //!
//! Change the register of the 'VarData' changing also the current 'X86VarState'. //! Change the register of the 'VarData' changing also the current 'X86VarState'.
//! Rebase is nearly identical to 'Detach' and 'Attach' sequence, but doesn't //! Rebase is nearly identical to 'Detach' and 'Attach' sequence, but doesn't
// change the 'VarData' modified flag. //! change the `VarData`s modified flag.
template<int C> template<int C>
ASMJIT_INLINE void rebase(VarData* vd, uint32_t newRegIndex, uint32_t oldRegIndex) { ASMJIT_INLINE void rebase(VarData* vd, uint32_t newRegIndex, uint32_t oldRegIndex) {
ASMJIT_ASSERT(vd->getClass() == C); ASMJIT_ASSERT(vd->getClass() == C);
uint32_t newRegMask = IntUtil::mask(newRegIndex); uint32_t newRegMask = Utils::mask(newRegIndex);
uint32_t oldRegMask = IntUtil::mask(oldRegIndex); uint32_t oldRegMask = Utils::mask(oldRegIndex);
uint32_t bothRegMask = newRegMask ^ oldRegMask; uint32_t bothRegMask = newRegMask ^ oldRegMask;
vd->setRegIndex(newRegIndex); vd->setRegIndex(newRegIndex);
@@ -239,7 +447,7 @@ struct X86Context : public Context {
ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg); ASMJIT_ASSERT(vd->getRegIndex() != kInvalidReg);
uint32_t regIndex = vd->getRegIndex(); uint32_t regIndex = vd->getRegIndex();
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = Utils::mask(regIndex);
emitSave(vd, regIndex, "Save"); emitSave(vd, regIndex, "Save");
@@ -315,7 +523,7 @@ struct X86Context : public Context {
uint32_t oldRegIndex = vd->getRegIndex(); uint32_t oldRegIndex = vd->getRegIndex();
uint32_t oldState = vd->getState(); uint32_t oldState = vd->getState();
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = Utils::mask(regIndex);
ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == NULL || regIndex == oldRegIndex); ASMJIT_ASSERT(_x86State.getListByClass(C)[regIndex] == NULL || regIndex == oldRegIndex);
@@ -328,7 +536,7 @@ struct X86Context : public Context {
emitMove(vd, regIndex, oldRegIndex, "Alloc"); emitMove(vd, regIndex, oldRegIndex, "Alloc");
_x86State.getListByClass(C)[oldRegIndex] = NULL; _x86State.getListByClass(C)[oldRegIndex] = NULL;
regMask ^= IntUtil::mask(oldRegIndex); regMask ^= Utils::mask(oldRegIndex);
} }
else { else {
ASMJIT_X86_CHECK_STATE ASMJIT_X86_CHECK_STATE
@@ -337,6 +545,7 @@ struct X86Context : public Context {
vd->setState(kVarStateReg); vd->setState(kVarStateReg);
vd->setRegIndex(regIndex); vd->setRegIndex(regIndex);
vd->addHomeIndex(regIndex);
_x86State.getListByClass(C)[regIndex] = vd; _x86State.getListByClass(C)[regIndex] = vd;
_x86State._occupied.xor_(C, regMask); _x86State._occupied.xor_(C, regMask);
@@ -378,7 +587,7 @@ struct X86Context : public Context {
ASMJIT_ASSERT(vd->getClass() == C); ASMJIT_ASSERT(vd->getClass() == C);
uint32_t regIndex = vd->getRegIndex(); uint32_t regIndex = vd->getRegIndex();
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = Utils::mask(regIndex);
vd->setModified(true); vd->setModified(true);
_x86State._modified.or_(C, regMask); _x86State._modified.or_(C, regMask);
@@ -463,7 +672,7 @@ struct X86Context : public Context {
// [Serialize] // [Serialize]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
virtual Error serialize(Assembler* assembler, Node* start, Node* stop); virtual Error serialize(Assembler* assembler, HLNode* start, HLNode* stop);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -485,7 +694,7 @@ struct X86Context : public Context {
//! Memory cell where is stored address used to restore manually //! Memory cell where is stored address used to restore manually
//! aligned stack. //! aligned stack.
MemCell* _stackFrameCell; VarCell* _stackFrameCell;
//! Global allocable registers mask. //! Global allocable registers mask.
uint32_t _gaRegs[kX86RegClassCount]; uint32_t _gaRegs[kX86RegClassCount];
@@ -508,7 +717,7 @@ struct X86Context : public Context {
int32_t _varActualDisp; int32_t _varActualDisp;
//! Temporary string builder used for logging. //! Temporary string builder used for logging.
StringBuilderT<256> _stringBuilder; StringBuilderTmp<256> _stringBuilder;
}; };
//! \} //! \}
@@ -520,4 +729,4 @@ struct X86Context : public Context {
// [Guard] // [Guard]
#endif // !ASMJIT_DISABLE_COMPILER #endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_X86_X86CONTEXT_P_H #endif // _ASMJIT_X86_X86COMPILERCONTEXT_P_H

View File

@@ -0,0 +1,551 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Guard]
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER) && (defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64))
// [Dependencies - AsmJit]
#include "../x86/x86compiler.h"
#include "../x86/x86compilerfunc.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::X86FuncDecl - Helpers]
// ============================================================================
static ASMJIT_INLINE bool x86ArgIsInt(uint32_t aType) {
ASMJIT_ASSERT(aType < kX86VarTypeCount);
return Utils::inInterval<uint32_t>(aType, _kVarTypeIntStart, _kVarTypeIntEnd);
}
static ASMJIT_INLINE bool x86ArgIsFp(uint32_t aType) {
ASMJIT_ASSERT(aType < kX86VarTypeCount);
return Utils::inInterval<uint32_t>(aType, _kVarTypeFpStart, _kVarTypeFpEnd);
}
static ASMJIT_INLINE uint32_t x86ArgTypeToXmmType(uint32_t aType) {
if (aType == kVarTypeFp32) return kX86VarTypeXmmSs;
if (aType == kVarTypeFp64) return kX86VarTypeXmmSd;
return aType;
}
//! Get an architecture depending on the calling convention `callConv`.
//!
//! Returns `kArchNone`, `kArchX86`, or `kArchX64`.
static ASMJIT_INLINE uint32_t x86GetArchFromCConv(uint32_t callConv) {
if (Utils::inInterval<uint32_t>(callConv, _kCallConvX86Start, _kCallConvX86End)) return kArchX86;
if (Utils::inInterval<uint32_t>(callConv, _kCallConvX64Start, _kCallConvX64End)) return kArchX64;
return kArchNone;
}
// ============================================================================
// [asmjit::X86FuncDecl - SetPrototype]
// ============================================================================
#define R(_Index_) kX86RegIndex##_Index_
static uint32_t X86FuncDecl_initConv(X86FuncDecl* self, uint32_t arch, uint32_t callConv) {
// Setup defaults.
self->_argStackSize = 0;
self->_redZoneSize = 0;
self->_spillZoneSize = 0;
self->_callConv = static_cast<uint8_t>(callConv);
self->_calleePopsStack = false;
self->_direction = kFuncDirRTL;
self->_passed.reset();
self->_preserved.reset();
::memset(self->_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderGp));
::memset(self->_passedOrderXyz, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderXyz));
switch (arch) {
// ------------------------------------------------------------------------
// [X86 Support]
// ------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X86)
case kArchX86: {
self->_preserved.set(kX86RegClassGp, Utils::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di)));
switch (callConv) {
case kCallConvX86CDecl:
break;
case kCallConvX86StdCall:
self->_calleePopsStack = true;
break;
case kCallConvX86MsThisCall:
self->_calleePopsStack = true;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx)));
self->_passedOrderGp[0] = R(Cx);
break;
case kCallConvX86MsFastCall:
self->_calleePopsStack = true;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Cx)));
self->_passedOrderGp[0] = R(Cx);
self->_passedOrderGp[1] = R(Dx);
break;
case kCallConvX86BorlandFastCall:
self->_calleePopsStack = true;
self->_direction = kFuncDirLTR;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
self->_passedOrderGp[2] = R(Cx);
break;
case kCallConvX86GccFastCall:
self->_calleePopsStack = true;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Dx)));
self->_passedOrderGp[0] = R(Cx);
self->_passedOrderGp[1] = R(Dx);
break;
case kCallConvX86GccRegParm1:
self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax)));
self->_passedOrderGp[0] = R(Ax);
break;
case kCallConvX86GccRegParm2:
self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
break;
case kCallConvX86GccRegParm3:
self->_passed.set(kX86RegClassGp, Utils::mask(R(Ax), R(Dx), R(Cx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
self->_passedOrderGp[2] = R(Cx);
break;
default:
return kErrorInvalidArgument;
}
return kErrorOk;
}
#endif // ASMJIT_BUILD_X86
// ------------------------------------------------------------------------
// [X64 Support]
// ------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X64)
case kArchX64: {
switch (callConv) {
case kCallConvX64Win:
self->_spillZoneSize = 32;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Cx), R(Dx), 8, 9));
self->_passedOrderGp[0] = R(Cx);
self->_passedOrderGp[1] = R(Dx);
self->_passedOrderGp[2] = 8;
self->_passedOrderGp[3] = 9;
self->_passed.set(kX86RegClassXyz, Utils::mask(0, 1, 2, 3));
self->_passedOrderXyz[0] = 0;
self->_passedOrderXyz[1] = 1;
self->_passedOrderXyz[2] = 2;
self->_passedOrderXyz[3] = 3;
self->_preserved.set(kX86RegClassGp , Utils::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di), 12, 13, 14, 15));
self->_preserved.set(kX86RegClassXyz, Utils::mask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
break;
case kCallConvX64Unix:
self->_redZoneSize = 128;
self->_passed.set(kX86RegClassGp, Utils::mask(R(Di), R(Si), R(Dx), R(Cx), 8, 9));
self->_passedOrderGp[0] = R(Di);
self->_passedOrderGp[1] = R(Si);
self->_passedOrderGp[2] = R(Dx);
self->_passedOrderGp[3] = R(Cx);
self->_passedOrderGp[4] = 8;
self->_passedOrderGp[5] = 9;
self->_passed.set(kX86RegClassXyz, Utils::mask(0, 1, 2, 3, 4, 5, 6, 7));
self->_passedOrderXyz[0] = 0;
self->_passedOrderXyz[1] = 1;
self->_passedOrderXyz[2] = 2;
self->_passedOrderXyz[3] = 3;
self->_passedOrderXyz[4] = 4;
self->_passedOrderXyz[5] = 5;
self->_passedOrderXyz[6] = 6;
self->_passedOrderXyz[7] = 7;
self->_preserved.set(kX86RegClassGp, Utils::mask(R(Bx), R(Sp), R(Bp), 12, 13, 14, 15));
break;
default:
return kErrorInvalidArgument;
}
return kErrorOk;
}
#endif // ASMJIT_BUILD_X64
default:
return kErrorInvalidArgument;
}
}
#undef R
static Error X86FuncDecl_initFunc(X86FuncDecl* self, uint32_t arch,
uint32_t ret, const uint32_t* args, uint32_t numArgs) {
ASMJIT_ASSERT(numArgs <= kFuncArgCount);
uint32_t callConv = self->_callConv;
uint32_t regSize = (arch == kArchX86) ? 4 : 8;
int32_t i = 0;
int32_t gpPos = 0;
int32_t xmmPos = 0;
int32_t stackOffset = 0;
const uint8_t* varMapping = NULL;
#if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86)
varMapping = _x86VarMapping;
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_X64)
if (arch == kArchX64)
varMapping = _x64VarMapping;
#endif // ASMJIT_BUILD_X64
ASMJIT_ASSERT(varMapping != NULL);
self->_numArgs = static_cast<uint8_t>(numArgs);
self->_retCount = 0;
for (i = 0; i < static_cast<int32_t>(numArgs); i++) {
FuncInOut& arg = self->getArg(i);
arg._varType = static_cast<uint8_t>(varMapping[args[i]]);
arg._regIndex = kInvalidReg;
arg._stackOffset = kFuncStackInvalid;
}
for (; i < kFuncArgCount; i++) {
self->_args[i].reset();
}
self->_rets[0].reset();
self->_rets[1].reset();
self->_argStackSize = 0;
self->_used.reset();
if (ret != kInvalidVar) {
ret = varMapping[ret];
switch (ret) {
case kVarTypeInt64:
case kVarTypeUInt64:
// 64-bit value is returned in EDX:EAX on x86.
#if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86) {
self->_retCount = 2;
self->_rets[0]._varType = kVarTypeUInt32;
self->_rets[0]._regIndex = kX86RegIndexAx;
self->_rets[1]._varType = static_cast<uint8_t>(ret - 2);
self->_rets[1]._regIndex = kX86RegIndexDx;
}
#endif // ASMJIT_BUILD_X86
// ... Fall through ...
case kVarTypeInt8:
case kVarTypeUInt8:
case kVarTypeInt16:
case kVarTypeUInt16:
case kVarTypeInt32:
case kVarTypeUInt32:
self->_retCount = 1;
self->_rets[0]._varType = static_cast<uint8_t>(ret);
self->_rets[0]._regIndex = kX86RegIndexAx;
break;
case kX86VarTypeMm:
self->_retCount = 1;
self->_rets[0]._varType = static_cast<uint8_t>(ret);
self->_rets[0]._regIndex = 0;
break;
case kVarTypeFp32:
self->_retCount = 1;
if (arch == kArchX86) {
self->_rets[0]._varType = kVarTypeFp32;
self->_rets[0]._regIndex = 0;
}
else {
self->_rets[0]._varType = kX86VarTypeXmmSs;
self->_rets[0]._regIndex = 0;
}
break;
case kVarTypeFp64:
self->_retCount = 1;
if (arch == kArchX86) {
self->_rets[0]._varType = kVarTypeFp64;
self->_rets[0]._regIndex = 0;
}
else {
self->_rets[0]._varType = kX86VarTypeXmmSd;
self->_rets[0]._regIndex = 0;
break;
}
break;
case kX86VarTypeXmm:
case kX86VarTypeXmmSs:
case kX86VarTypeXmmSd:
case kX86VarTypeXmmPs:
case kX86VarTypeXmmPd:
self->_retCount = 1;
self->_rets[0]._varType = static_cast<uint8_t>(ret);
self->_rets[0]._regIndex = 0;
break;
}
}
if (self->_numArgs == 0)
return kErrorOk;
#if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86) {
// Register arguments (Integer), always left-to-right.
for (i = 0; i != static_cast<int32_t>(numArgs); i++) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (!x86ArgIsInt(varType) || gpPos >= ASMJIT_ARRAY_SIZE(self->_passedOrderGp))
continue;
if (self->_passedOrderGp[gpPos] == kInvalidReg)
continue;
arg._regIndex = self->_passedOrderGp[gpPos++];
self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex()));
}
// Stack arguments.
int32_t iStart = static_cast<int32_t>(numArgs - 1);
int32_t iEnd = -1;
int32_t iStep = -1;
if (self->_direction == kFuncDirLTR) {
iStart = 0;
iEnd = static_cast<int32_t>(numArgs);
iStep = 1;
}
for (i = iStart; i != iEnd; i += iStep) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (arg.hasRegIndex())
continue;
if (x86ArgIsInt(varType)) {
stackOffset -= 4;
arg._stackOffset = static_cast<int16_t>(stackOffset);
}
else if (x86ArgIsFp(varType)) {
int32_t size = static_cast<int32_t>(_x86VarInfo[varType].getSize());
stackOffset -= size;
arg._stackOffset = static_cast<int16_t>(stackOffset);
}
}
}
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_X64)
if (arch == kArchX64) {
if (callConv == kCallConvX64Win) {
int32_t argMax = Utils::iMin<int32_t>(numArgs, 4);
// Register arguments (Gp/Xmm), always left-to-right.
for (i = 0; i != argMax; i++) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (x86ArgIsInt(varType) && i < ASMJIT_ARRAY_SIZE(self->_passedOrderGp)) {
arg._regIndex = self->_passedOrderGp[i];
self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex()));
continue;
}
if (x86ArgIsFp(varType) && i < ASMJIT_ARRAY_SIZE(self->_passedOrderXyz)) {
arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType));
arg._regIndex = self->_passedOrderXyz[i];
self->_used.or_(kX86RegClassXyz, Utils::mask(arg.getRegIndex()));
}
}
// Stack arguments (always right-to-left).
for (i = numArgs - 1; i != -1; i--) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (arg.hasRegIndex())
continue;
if (x86ArgIsInt(varType)) {
stackOffset -= 8; // Always 8 bytes.
arg._stackOffset = stackOffset;
}
else if (x86ArgIsFp(varType)) {
stackOffset -= 8; // Always 8 bytes (float/double).
arg._stackOffset = stackOffset;
}
}
// 32 bytes shadow space (X64W calling convention specific).
stackOffset -= 4 * 8;
}
else {
// Register arguments (Gp), always left-to-right.
for (i = 0; i != static_cast<int32_t>(numArgs); i++) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (!x86ArgIsInt(varType) || gpPos >= ASMJIT_ARRAY_SIZE(self->_passedOrderGp))
continue;
if (self->_passedOrderGp[gpPos] == kInvalidReg)
continue;
arg._regIndex = self->_passedOrderGp[gpPos++];
self->_used.or_(kX86RegClassGp, Utils::mask(arg.getRegIndex()));
}
// Register arguments (Xmm), always left-to-right.
for (i = 0; i != static_cast<int32_t>(numArgs); i++) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (x86ArgIsFp(varType)) {
arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType));
arg._regIndex = self->_passedOrderXyz[xmmPos++];
self->_used.or_(kX86RegClassXyz, Utils::mask(arg.getRegIndex()));
}
}
// Stack arguments.
for (i = numArgs - 1; i != -1; i--) {
FuncInOut& arg = self->getArg(i);
uint32_t varType = varMapping[arg.getVarType()];
if (arg.hasRegIndex())
continue;
if (x86ArgIsInt(varType)) {
stackOffset -= 8;
arg._stackOffset = static_cast<int16_t>(stackOffset);
}
else if (x86ArgIsFp(varType)) {
int32_t size = static_cast<int32_t>(_x86VarInfo[varType].getSize());
stackOffset -= size;
arg._stackOffset = static_cast<int16_t>(stackOffset);
}
}
}
}
#endif // ASMJIT_BUILD_X64
// Modify the stack offset, thus in result all parameters would have positive
// non-zero stack offset.
for (i = 0; i < static_cast<int32_t>(numArgs); i++) {
FuncInOut& arg = self->getArg(i);
if (!arg.hasRegIndex()) {
arg._stackOffset += static_cast<uint16_t>(static_cast<int32_t>(regSize) - stackOffset);
}
}
self->_argStackSize = static_cast<uint32_t>(-stackOffset);
return kErrorOk;
}
Error X86FuncDecl::setPrototype(const FuncPrototype& p) {
uint32_t callConv = p.getCallConv();
uint32_t arch = x86GetArchFromCConv(callConv);
if (arch == kArchNone)
return kErrorInvalidArgument;
if (p.getNumArgs() > kFuncArgCount)
return kErrorInvalidArgument;
// Validate that the required convention is supported by the current asmjit
// configuration, if only one target is compiled.
#if defined(ASMJIT_BUILD_X86) && !defined(ASMJIT_BUILD_X64)
if (arch == kArchX64)
return kErrorInvalidState;
#endif // ASMJIT_BUILD_X86 && !ASMJIT_BUILD_X64
#if !defined(ASMJIT_BUILD_X86) && defined(ASMJIT_BUILD_X64)
if (arch == kArchX86)
return kErrorInvalidState;
#endif // !ASMJIT_BUILD_X86 && ASMJIT_BUILD_X64
ASMJIT_PROPAGATE_ERROR(X86FuncDecl_initConv(this, arch, callConv));
ASMJIT_PROPAGATE_ERROR(X86FuncDecl_initFunc(this, arch, p.getRet(), p.getArgs(), p.getNumArgs()));
return kErrorOk;
}
// ============================================================================
// [asmjit::X86FuncDecl - Reset]
// ============================================================================
void X86FuncDecl::reset() {
uint32_t i;
_callConv = kCallConvNone;
_calleePopsStack = false;
_direction = kFuncDirRTL;
_reserved0 = 0;
_numArgs = 0;
_retCount = 0;
_argStackSize = 0;
_redZoneSize = 0;
_spillZoneSize = 0;
for (i = 0; i < ASMJIT_ARRAY_SIZE(_args); i++)
_args[i].reset();
_rets[0].reset();
_rets[1].reset();
_used.reset();
_passed.reset();
_preserved.reset();
::memset(_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderGp));
::memset(_passedOrderXyz, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderXyz));
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)

View File

@@ -0,0 +1,133 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86COMPILERFUNC_P_H
#define _ASMJIT_X86_X86COMPILERFUNC_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/compilerfunc.h"
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_x86
//! \{
// ============================================================================
// [asmjit::TypeId]
// ============================================================================
#if !defined(ASMJIT_DOCGEN)
ASMJIT_TYPE_ID(X86MmReg, kX86VarTypeMm);
ASMJIT_TYPE_ID(X86MmVar, kX86VarTypeMm);
ASMJIT_TYPE_ID(X86XmmReg, kX86VarTypeXmm);
ASMJIT_TYPE_ID(X86XmmVar, kX86VarTypeXmm);
ASMJIT_TYPE_ID(X86YmmReg, kX86VarTypeYmm);
ASMJIT_TYPE_ID(X86YmmVar, kX86VarTypeYmm);
ASMJIT_TYPE_ID(X86ZmmReg, kX86VarTypeZmm);
ASMJIT_TYPE_ID(X86ZmmVar, kX86VarTypeZmm);
#endif // !ASMJIT_DOCGEN
// ============================================================================
// [asmjit::X86FuncDecl]
// ============================================================================
//! X86 function, including calling convention, arguments and their
//! register indices or stack positions.
struct X86FuncDecl : public FuncDecl {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `X86FuncDecl` instance.
ASMJIT_INLINE X86FuncDecl() { reset(); }
// --------------------------------------------------------------------------
// [Accessors - X86]
// --------------------------------------------------------------------------
//! Get used registers mask for the given register class `rc`.
//!
//! \note The result depends on the function calling convention AND the
//! function prototype. Returned mask contains only registers actually used
//! to pass function arguments.
ASMJIT_INLINE uint32_t getUsed(uint32_t rc) const { return _used.get(rc); }
//! Get passed registers mask for the given register class `rc`.
//!
//! \note The result depends on the function calling convention used; the
//! prototype of the function doesn't affect the mask returned.
ASMJIT_INLINE uint32_t getPassed(uint32_t rc) const { return _passed.get(rc); }
//! Get preserved registers mask for the given register class `rc`.
//!
//! \note The result depends on the function calling convention used; the
//! prototype of the function doesn't affect the mask returned.
ASMJIT_INLINE uint32_t getPreserved(uint32_t rc) const { return _preserved.get(rc); }
//! Get ther order of passed registers (Gp).
//!
//! \note The result depends on the function calling convention used; the
//! prototype of the function doesn't affect the mask returned.
ASMJIT_INLINE const uint8_t* getPassedOrderGp() const { return _passedOrderGp; }
//! Get ther order of passed registers (Xmm/Ymm/Zmm).
//!
//! \note The result depends on the function calling convention used; the
//! prototype of the function doesn't affect the mask returned.
ASMJIT_INLINE const uint8_t* getPassedOrderXyz() const { return _passedOrderXyz; }
// --------------------------------------------------------------------------
// [SetPrototype]
// --------------------------------------------------------------------------
//! Set function prototype.
//!
//! This will set function calling convention and setup arguments variables.
//!
//! \note This function will allocate variables, it can be called only once.
ASMJIT_API Error setPrototype(const FuncPrototype& p);
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Used registers.
X86RegMask _used;
//! Passed registers (defined by the calling convention).
X86RegMask _passed;
//! Preserved registers (defined by the calling convention).
X86RegMask _preserved;
//! Order of registers used to pass Gp function arguments.
uint8_t _passedOrderGp[8];
//! Order of registers used to pass Xmm function arguments.
uint8_t _passedOrderXyz[8];
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_X86_X86COMPILERFUNC_P_H

View File

@@ -12,7 +12,7 @@
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/intutil.h" #include "../base/utils.h"
#include "../x86/x86cpuinfo.h" #include "../x86/x86cpuinfo.h"
// 2009-02-05: Thanks to Mike Tajmajer for VC7.1 compiler support. It shouldn't // 2009-02-05: Thanks to Mike Tajmajer for VC7.1 compiler support. It shouldn't
@@ -37,9 +37,9 @@ struct X86CpuVendor {
static const X86CpuVendor x86CpuVendorList[] = { static const X86CpuVendor x86CpuVendorList[] = {
{ kCpuVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } }, { kCpuVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } },
{ kCpuVendorAmd , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } }, { kCpuVendorAMD , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } },
{ kCpuVendorVia , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }, { kCpuVendorVIA , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } },
{ kCpuVendorVia , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } } { kCpuVendorVIA , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } }
}; };
static ASMJIT_INLINE bool x86CpuVendorEq(const X86CpuVendor& info, const char* vendorString) { static ASMJIT_INLINE bool x86CpuVendorEq(const X86CpuVendor& info, const char* vendorString) {
@@ -98,14 +98,14 @@ union X86XCR {
}; };
// callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here. // callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here.
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
void X86CpuUtil::_docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* result) { void X86CpuUtil::_docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* result) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
// __cpuidex was introduced by VS2008-SP1. // __cpuidex was introduced by VS2008-SP1.
# if _MSC_FULL_VER >= 150030729 # if _MSC_FULL_VER >= 150030729
__cpuidex(reinterpret_cast<int*>(result->i), inEax, inEcx); __cpuidex(reinterpret_cast<int*>(result->i), inEax, inEcx);
# elif defined(ASMJIT_ARCH_X64) # elif ASMJIT_ARCH_X64
// VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However, 64-bit // VS2008 or less, 64-bit mode - `__cpuidex` doesn't exist! However, 64-bit
// calling convention specifies parameter to be passed in ECX/RCX, so we may // calling convention specifies parameter to be passed in ECX/RCX, so we may
// be lucky if compiler doesn't move the register, otherwise the result is // be lucky if compiler doesn't move the register, otherwise the result is
@@ -130,7 +130,7 @@ void X86CpuUtil::_docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* result) {
#elif defined(__GNUC__) #elif defined(__GNUC__)
// Note, patched to preserve ebx/rbx register which is used by GCC. // Note, patched to preserve ebx/rbx register which is used by GCC.
# if defined(ASMJIT_ARCH_X86) # if ASMJIT_ARCH_X86
# define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \ # define __myCpuId(inEax, inEcx, outEax, outEbx, outEcx, outEdx) \
__asm__ __volatile__( \ __asm__ __volatile__( \
"mov %%ebx, %%edi\n" \ "mov %%ebx, %%edi\n" \
@@ -150,22 +150,18 @@ void X86CpuUtil::_docpuid(uint32_t inEcx, uint32_t inEax, X86CpuId* result) {
__myCpuId(inEax, inEcx, result->eax, result->ebx, result->ecx, result->edx); __myCpuId(inEax, inEcx, result->eax, result->ebx, result->ecx, result->edx);
#else #else
# error "asmjit::X86CpuUtil::_docpuid() unimplemented!" # error "[asmjit] X86CpuUtil::_docpuid() unimplemented!"
#endif #endif
} }
static void callXGetBV(X86XCR* result, uint32_t inEcx) { static void callXGetBV(X86XCR* result, uint32_t inEcx) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
# if (_MSC_FULL_VER >= 160040219) // 2010SP1+ # if (_MSC_FULL_VER >= 160040219) // 2010SP1+
result->value = _xgetbv(inEcx); result->value = _xgetbv(inEcx);
# else # else
result->value = 0; result->value = 0;
# endif # endif
#elif defined(__GNUC__) #elif defined(__GNUC__)
unsigned int eax, edx; unsigned int eax, edx;
// Removed, because the world is not perfect: // Removed, because the world is not perfect:
@@ -174,21 +170,16 @@ static void callXGetBV(X86XCR* result, uint32_t inEcx) {
result->eax = eax; result->eax = eax;
result->edx = edx; result->edx = edx;
#else #else
result->value = 0; result->value = 0;
#endif // COMPILER #endif // COMPILER
} }
void X86CpuUtil::detect(X86CpuInfo* cpuInfo) { void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
X86CpuId regs;
uint32_t i; uint32_t i;
uint32_t maxBaseId; uint32_t maxBaseId;
bool maybeMPX = false; X86CpuId regs;
X86XCR xcr0; X86XCR xcr0;
xcr0.value = 0; xcr0.value = 0;
@@ -252,8 +243,8 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
if (regs.ecx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMOVBE); if (regs.ecx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMOVBE);
if (regs.ecx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeaturePOPCNT); if (regs.ecx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeaturePOPCNT);
if (regs.ecx & 0x02000000U) cpuInfo->addFeature(kX86CpuFeatureAESNI); if (regs.ecx & 0x02000000U) cpuInfo->addFeature(kX86CpuFeatureAESNI);
if (regs.ecx & 0x04000000U) cpuInfo->addFeature(kX86CpuFeatureXSave); if (regs.ecx & 0x04000000U) cpuInfo->addFeature(kX86CpuFeatureXSAVE);
if (regs.ecx & 0x08000000U) cpuInfo->addFeature(kX86CpuFeatureXSaveOS); if (regs.ecx & 0x08000000U) cpuInfo->addFeature(kX86CpuFeatureXSAVE_OS);
if (regs.ecx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeatureRDRAND); if (regs.ecx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeatureRDRAND);
if (regs.edx & 0x00000010U) cpuInfo->addFeature(kX86CpuFeatureRDTSC); if (regs.edx & 0x00000010U) cpuInfo->addFeature(kX86CpuFeatureRDTSC);
@@ -267,7 +258,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
if (regs.edx & 0x10000000U) cpuInfo->addFeature(kX86CpuFeatureMT); if (regs.edx & 0x10000000U) cpuInfo->addFeature(kX86CpuFeatureMT);
// AMD sets Multithreading to ON if it has two or more cores. // AMD sets Multithreading to ON if it has two or more cores.
if (cpuInfo->_hwThreadsCount == 1 && cpuInfo->_vendorId == kCpuVendorAmd && (regs.edx & 0x10000000U)) { if (cpuInfo->_hwThreadsCount == 1 && cpuInfo->_vendorId == kCpuVendorAMD && (regs.edx & 0x10000000U)) {
cpuInfo->_hwThreadsCount = 2; cpuInfo->_hwThreadsCount = 2;
} }
@@ -296,19 +287,20 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// Detect new features if the processor supports CPUID-07. // Detect new features if the processor supports CPUID-07.
bool maybeMPX = false;
if (maxBaseId >= 0x7) { if (maxBaseId >= 0x7) {
callCpuId(&regs, 0x7); callCpuId(&regs, 0x7);
if (regs.ebx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureFSGSBase); if (regs.ebx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureFSGSBASE);
if (regs.ebx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureBMI); if (regs.ebx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureBMI);
if (regs.ebx & 0x00000010U) cpuInfo->addFeature(kX86CpuFeatureHLE); if (regs.ebx & 0x00000010U) cpuInfo->addFeature(kX86CpuFeatureHLE);
if (regs.ebx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeatureBMI2); if (regs.ebx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeatureBMI2);
if (regs.ebx & 0x00000200U) cpuInfo->addFeature(kX86CpuFeatureMOVSBSTOSBOpt); if (regs.ebx & 0x00000200U) cpuInfo->addFeature(kX86CpuFeatureMOVSBSTOSB_OPT);
if (regs.ebx & 0x00000800U) cpuInfo->addFeature(kX86CpuFeatureRTM); if (regs.ebx & 0x00000800U) cpuInfo->addFeature(kX86CpuFeatureRTM);
if (regs.ebx & 0x00004000U) maybeMPX = true; if (regs.ebx & 0x00004000U) maybeMPX = true;
if (regs.ebx & 0x00040000U) cpuInfo->addFeature(kX86CpuFeatureRDSEED); if (regs.ebx & 0x00040000U) cpuInfo->addFeature(kX86CpuFeatureRDSEED);
if (regs.ebx & 0x00080000U) cpuInfo->addFeature(kX86CpuFeatureADX); if (regs.ebx & 0x00080000U) cpuInfo->addFeature(kX86CpuFeatureADX);
if (regs.ebx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeatureCLFLUSHOpt); if (regs.ebx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeatureCLFLUSH_OPT);
if (regs.ebx & 0x20000000U) cpuInfo->addFeature(kX86CpuFeatureSHA); if (regs.ebx & 0x20000000U) cpuInfo->addFeature(kX86CpuFeatureSHA);
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeaturePREFETCHWT1); if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeaturePREFETCHWT1);
@@ -358,7 +350,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
// extended IDs. // extended IDs.
callCpuId(&regs, 0x80000000); callCpuId(&regs, 0x80000000);
uint32_t maxExtId = IntUtil::iMin<uint32_t>(regs.eax, 0x80000004); uint32_t maxExtId = Utils::iMin<uint32_t>(regs.eax, 0x80000004);
uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString); uint32_t* brand = reinterpret_cast<uint32_t*>(cpuInfo->_brandString);
for (i = 0x80000001; i <= maxExtId; i++) { for (i = 0x80000001; i <= maxExtId; i++) {
@@ -373,7 +365,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
if (regs.ecx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeaturePREFETCH); if (regs.ecx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeaturePREFETCH);
if (regs.edx & 0x00100000U) cpuInfo->addFeature(kX86CpuFeatureNX); if (regs.edx & 0x00100000U) cpuInfo->addFeature(kX86CpuFeatureNX);
if (regs.edx & 0x00200000U) cpuInfo->addFeature(kX86CpuFeatureFXSROpt); if (regs.edx & 0x00200000U) cpuInfo->addFeature(kX86CpuFeatureFXSR_OPT);
if (regs.edx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMMX2); if (regs.edx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMMX2);
if (regs.edx & 0x08000000U) cpuInfo->addFeature(kX86CpuFeatureRDTSCP); if (regs.edx & 0x08000000U) cpuInfo->addFeature(kX86CpuFeatureRDTSCP);
if (regs.edx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeature3DNOW2).addFeature(kX86CpuFeatureMMX2); if (regs.edx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeature3DNOW2).addFeature(kX86CpuFeatureMMX2);
@@ -395,7 +387,7 @@ void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
} }
} }
// Simplify the brand string (remove unnecessary spaces to make printing nicer). // Simplify the brand string (remove unnecessary spaces to make printing prettier).
x86SimplifyBrandString(cpuInfo->_brandString); x86SimplifyBrandString(cpuInfo->_brandString);
} }
#endif #endif

View File

@@ -22,7 +22,7 @@ namespace asmjit {
struct X86CpuInfo; struct X86CpuInfo;
//! \addtogroup asmjit_x86_general //! \addtogroup asmjit_x86
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -48,7 +48,7 @@ ASMJIT_ENUM(X86CpuFeature) {
//! Cpu has CLFUSH. //! Cpu has CLFUSH.
kX86CpuFeatureCLFLUSH, kX86CpuFeatureCLFLUSH,
//! Cpu has CLFUSH (Optimized). //! Cpu has CLFUSH (Optimized).
kX86CpuFeatureCLFLUSHOpt, kX86CpuFeatureCLFLUSH_OPT,
//! Cpu has PREFETCH. //! Cpu has PREFETCH.
kX86CpuFeaturePREFETCH, kX86CpuFeaturePREFETCH,
//! Cpu has PREFETCHWT1. //! Cpu has PREFETCHWT1.
@@ -58,7 +58,7 @@ ASMJIT_ENUM(X86CpuFeature) {
//! Cpu has FXSAVE/FXRSTOR. //! Cpu has FXSAVE/FXRSTOR.
kX86CpuFeatureFXSR, kX86CpuFeatureFXSR,
//! Cpu has FXSAVE/FXRSTOR (Optimized). //! Cpu has FXSAVE/FXRSTOR (Optimized).
kX86CpuFeatureFXSROpt, kX86CpuFeatureFXSR_OPT,
//! Cpu has MMX. //! Cpu has MMX.
kX86CpuFeatureMMX, kX86CpuFeatureMMX,
//! Cpu has extended MMX. //! Cpu has extended MMX.
@@ -102,9 +102,9 @@ ASMJIT_ENUM(X86CpuFeature) {
//! Cpu has SHA-1 and SHA-256. //! Cpu has SHA-1 and SHA-256.
kX86CpuFeatureSHA, kX86CpuFeatureSHA,
//! Cpu has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR0. //! Cpu has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR0.
kX86CpuFeatureXSave, kX86CpuFeatureXSAVE,
//! OS has enabled XSAVE, you can call XGETBV to get value of XCR0. //! OS has enabled XSAVE, you can call XGETBV to get value of XCR0.
kX86CpuFeatureXSaveOS, kX86CpuFeatureXSAVE_OS,
//! Cpu has AVX. //! Cpu has AVX.
kX86CpuFeatureAVX, kX86CpuFeatureAVX,
//! Cpu has AVX2. //! Cpu has AVX2.
@@ -130,9 +130,9 @@ ASMJIT_ENUM(X86CpuFeature) {
//! Cpu has MPX (Memory Protection Extensions). //! Cpu has MPX (Memory Protection Extensions).
kX86CpuFeatureMPX, kX86CpuFeatureMPX,
//! Cpu has FSGSBASE. //! Cpu has FSGSBASE.
kX86CpuFeatureFSGSBase, kX86CpuFeatureFSGSBASE,
//! Cpu has optimized REP MOVSB/STOSB. //! Cpu has optimized REP MOVSB/STOSB.
kX86CpuFeatureMOVSBSTOSBOpt, kX86CpuFeatureMOVSBSTOSB_OPT,
//! Cpu has AVX-512F (Foundation). //! Cpu has AVX-512F (Foundation).
kX86CpuFeatureAVX512F, kX86CpuFeatureAVX512F,
@@ -178,7 +178,7 @@ union X86CpuId {
// [asmjit::X86CpuUtil] // [asmjit::X86CpuUtil]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
//! CPU utilities available only if the host processor is X86/X64. //! CPU utilities available only if the host processor is X86/X64.
struct X86CpuUtil { struct X86CpuUtil {
//! \internal //! \internal
@@ -238,7 +238,7 @@ struct X86CpuInfo : public CpuInfo {
// [Statics] // [Statics]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
//! Get global instance of `X86CpuInfo`. //! Get global instance of `X86CpuInfo`.
static ASMJIT_INLINE const X86CpuInfo* getHost() { static ASMJIT_INLINE const X86CpuInfo* getHost() {
return static_cast<const X86CpuInfo*>(CpuInfo::getHost()); return static_cast<const X86CpuInfo*>(CpuInfo::getHost());

View File

@@ -25,21 +25,22 @@ namespace asmjit {
//! \internal //! \internal
enum { enum {
kX86InstTable_L__ = (0) << kX86InstOpCode_L_Shift, // REX/VEX.
kX86InstTable_L_I = (0) << kX86InstOpCode_L_Shift, kX86InstTable_L__ = (0) << kX86InstOpCode_L_Shift, // L is operand-based or unspecified.
kX86InstTable_L_0 = (0) << kX86InstOpCode_L_Shift, kX86InstTable_L_I = (0) << kX86InstOpCode_L_Shift, // L is ignored (LIG).
kX86InstTable_L_L = (1) << kX86InstOpCode_L_Shift, kX86InstTable_L_0 = (0) << kX86InstOpCode_L_Shift, // L has to be zero.
kX86InstTable_L_L = (1) << kX86InstOpCode_L_Shift, // L has to be set.
kX86InstTable_W__ = (0) << kX86InstOpCode_W_Shift, kX86InstTable_W__ = (0) << kX86InstOpCode_W_Shift, // W is operand-based or unspecified.
kX86InstTable_W_I = (0) << kX86InstOpCode_W_Shift, kX86InstTable_W_I = (0) << kX86InstOpCode_W_Shift, // W is ignored (WIG).
kX86InstTable_W_0 = (0) << kX86InstOpCode_W_Shift, kX86InstTable_W_0 = (0) << kX86InstOpCode_W_Shift, // W has to be zero.
kX86InstTable_W_1 = (1) << kX86InstOpCode_W_Shift, kX86InstTable_W_W = (1) << kX86InstOpCode_W_Shift, // W has to be set.
kX86InstTable_W_W = (1) << kX86InstOpCode_W_Shift,
kX86InstTable_E__ = (0) << kX86InstOpCode_EW_Shift, // EVEX.
kX86InstTable_E_I = (0) << kX86InstOpCode_EW_Shift, kX86InstTable_E__ = (0) << kX86InstOpCode_EW_Shift, // EVEX.W is operand-based or unspecified.
kX86InstTable_E_0 = (0) << kX86InstOpCode_EW_Shift, kX86InstTable_E_I = (0) << kX86InstOpCode_EW_Shift, // EVEX.W is ignored (WIG).
kX86InstTable_E_1 = (1) << kX86InstOpCode_EW_Shift kX86InstTable_E_0 = (0) << kX86InstOpCode_EW_Shift, // EVEX.W has to be zero.
kX86InstTable_E_1 = (1) << kX86InstOpCode_EW_Shift // EVEX.W has to be set.
}; };
//! \internal //! \internal
@@ -47,8 +48,9 @@ enum {
//! Combined flags. //! Combined flags.
enum X86InstOpInternal { enum X86InstOpInternal {
kX86InstOpI = kX86InstOpImm, kX86InstOpI = kX86InstOpImm,
kX86InstOpL = kX86InstOpLabel, kX86InstOpL = kX86InstOpLabel,
kX86InstOpLbImm = kX86InstOpLabel | kX86InstOpImm, kX86InstOpLImm = kX86InstOpLabel | kX86InstOpImm,
kX86InstOpGwb = kX86InstOpGw | kX86InstOpGb, kX86InstOpGwb = kX86InstOpGw | kX86InstOpGb,
kX86InstOpGqd = kX86InstOpGq | kX86InstOpGd, kX86InstOpGqd = kX86InstOpGq | kX86InstOpGd,
@@ -2044,7 +2046,7 @@ const X86InstExtendedInfo _x86InstExtendedInfo[] = {
{ Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,7,_,_,_) }, { Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,7,_,_,_) },
{ Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,6,_,_,_) }, { Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,6,_,_,_) },
{ Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,5,_,_,_) }, { Enc(X86BTest) , 0 , 0 , 0x00, 0x3B, 0, { O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U }, F(Lock) , O_000F00(BA,5,_,_,_) },
{ Enc(X86Call) , 0 , 0 , 0x00, 0x00, 0, { O(GqdMem)|O(LbImm), U , U , U , U }, F(Flow) , O_000000(E8,U,_,_,_) }, { Enc(X86Call) , 0 , 0 , 0x00, 0x00, 0, { O(GqdMem)|O(LImm) , U , U , U , U }, F(Flow) , O_000000(E8,U,_,_,_) },
{ Enc(X86Op) , 0 , 0 , 0x00, 0x00, 0, { U , U , U , U , U }, F(None)|F(Special) , U }, { Enc(X86Op) , 0 , 0 , 0x00, 0x00, 0, { U , U , U , U , U }, F(None)|F(Special) , U },
{ Enc(X86Op) , 0 , 0 , 0x00, 0x20, 0, { U , U , U , U , U }, F(None) , U }, { Enc(X86Op) , 0 , 0 , 0x00, 0x20, 0, { U , U , U , U , U }, F(None) , U },
{ Enc(X86Op) , 0 , 0 , 0x00, 0x40, 0, { U , U , U , U , U }, F(None) , U }, { Enc(X86Op) , 0 , 0 , 0x00, 0x40, 0, { U , U , U , U , U }, F(None) , U },
@@ -3377,12 +3379,12 @@ enum X86InstData_ExtendedIndex {
}; };
// ${X86InstData:End} // ${X86InstData:End}
// Please run tools/src-gendefs.js (by using just node.js, without any dependencies) to regenerate the code above. // Please run tools/src-gendefs.js (by using just node.js, without any dependencies) to regenerate the code enclosed with ${X86InstData...}.
const X86InstInfo _x86InstInfo[] = { const X86InstInfo _x86InstInfo[] = {
// <----------------------------+--------------------+-------------------------------------------+-------------------+------------------------------------+-------------+-------+---------------------------------------------------------------------------------------------------+ // <----------------------------+--------------------+-------------------------------------------+-------------------+------------------------------------+-------------+-------+---------------------------------------------------------------------------------------------------+
// | | Instruction Opcodes | | Instruction Flags | E-FLAGS | Write | Operands (Gp/Fp/Mm/K/Xmm/Ymm/Zmm Regs, Mem, Imm, Label, None/Undefined) | // | | Instruction Opcodes | | Instruction Flags | E-FLAGS | Write | Operands (Gp/Fp/Mm/K/Xmm/Ymm/Zmm Regs, Mem, Imm, Label, None/Undefined) |
// Instruction Id | Instruction Name +---------------------+---------------------+ Instruction Enc. +---------------+--------------------+-------------+---+---+-------------------+-------------------+-------------------+-------------------+-------------------+ // Instruction Id | Instruction Name +---------------------+---------------------+ Instruction Enc. +---------------+--------------------+-------------+---+---+-------------------+-------------------+-------------------+-------------------+-------------------+
// | | 0:PP-MMM OP/O L/W/EW| 1:PP-MMM OP/O L/W/EW| | Global Flags |A512(ID|VL|kz|rnd|b)| EF:OSZAPCDX |Idx| Sz| [0] 1st Operand | [1] 2nd Operand | [2] 3rd Operand | [3] 4th Operand | [4] 5th Operand | // | | O-PP-MMM OP/O L/W/EW| 1:PP-MMM OP/O L/W/EW| | Global Flags |A512(ID|VL|kz|rnd|b)| EF:OSZAPCDX |Idx| Sz| [0] 1st Operand | [1] 2nd Operand | [2] 3rd Operand | [3] 4th Operand | [4] 5th Operand |
// <----------------------------+--------------------+---------------------+---------------------+-------------------+---------------+--------------------+-------------+---+---+-------------------+-------------------+-------------------+-------------------+-------------------+ // <----------------------------+--------------------+---------------------+---------------------+-------------------+---------------+--------------------+-------------+---+---+-------------------+-------------------+-------------------+-------------------+-------------------+
INST(kInstIdNone , "" , U , U , Enc(None) , F(None) , EF(________), 0 , 0 , U , U , U , U , U ), INST(kInstIdNone , "" , U , U , Enc(None) , F(None) , EF(________), 0 , 0 , U , U , U , U , U ),
INST(kX86InstIdAdc , "adc" , O_000000(10,2,_,_,_), U , Enc(X86Arith) , F(Lock) , EF(WWWWWX__), 0 , 0 , O(GqdwbMem) , O(GqdwbMem)|O(Imm), U , U , U ), INST(kX86InstIdAdc , "adc" , O_000000(10,2,_,_,_), U , Enc(X86Arith) , F(Lock) , EF(WWWWWX__), 0 , 0 , O(GqdwbMem) , O(GqdwbMem)|O(Imm), U , U , U ),
@@ -3421,7 +3423,7 @@ const X86InstInfo _x86InstInfo[] = {
INST(kX86InstIdBtr , "btr" , O_000F00(B3,U,_,_,_), O_000F00(BA,6,_,_,_), Enc(X86BTest) , F(Lock) , EF(UU_UUW__), 0 , 0 , O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U ), INST(kX86InstIdBtr , "btr" , O_000F00(B3,U,_,_,_), O_000F00(BA,6,_,_,_), Enc(X86BTest) , F(Lock) , EF(UU_UUW__), 0 , 0 , O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U ),
INST(kX86InstIdBts , "bts" , O_000F00(AB,U,_,_,_), O_000F00(BA,5,_,_,_), Enc(X86BTest) , F(Lock) , EF(UU_UUW__), 0 , 0 , O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U ), INST(kX86InstIdBts , "bts" , O_000F00(AB,U,_,_,_), O_000F00(BA,5,_,_,_), Enc(X86BTest) , F(Lock) , EF(UU_UUW__), 0 , 0 , O(GqdwMem) , O(Gqdw)|O(Imm) , U , U , U ),
INST(kX86InstIdBzhi , "bzhi" , O_000F38(F5,U,_,_,_), U , Enc(AvxRmv) , F(None) , EF(WWWUUW__), 0 , 0 , O(Gqd) , O(GqdMem) , O(Gqd) , U , U ), INST(kX86InstIdBzhi , "bzhi" , O_000F38(F5,U,_,_,_), U , Enc(AvxRmv) , F(None) , EF(WWWUUW__), 0 , 0 , O(Gqd) , O(GqdMem) , O(Gqd) , U , U ),
INST(kX86InstIdCall , "call" , O_000000(FF,2,_,_,_), O_000000(E8,U,_,_,_), Enc(X86Call) , F(Flow) , EF(________), 0 , 0 , O(GqdMem)|O(LbImm), U , U , U , U ), INST(kX86InstIdCall , "call" , O_000000(FF,2,_,_,_), O_000000(E8,U,_,_,_), Enc(X86Call) , F(Flow) , EF(________), 0 , 0 , O(GqdMem)|O(LImm) , U , U , U , U ),
INST(kX86InstIdCbw , "cbw" , O_660000(98,U,_,_,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ), INST(kX86InstIdCbw , "cbw" , O_660000(98,U,_,_,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ),
INST(kX86InstIdCdq , "cdq" , O_000000(99,U,_,_,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ), INST(kX86InstIdCdq , "cdq" , O_000000(99,U,_,_,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ),
INST(kX86InstIdCdqe , "cdqe" , O_000000(98,U,_,W,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ), INST(kX86InstIdCdqe , "cdqe" , O_000000(98,U,_,W,_), U , Enc(X86Op) , F(None)|F(Special) , EF(________), 0 , 0 , U , U , U , U , U ),
@@ -4490,52 +4492,19 @@ const X86InstInfo _x86InstInfo[] = {
// ============================================================================ // ============================================================================
#define CC_TO_INST(_Inst_) { \ #define CC_TO_INST(_Inst_) { \
_Inst_##o, \ _Inst_##o , _Inst_##no , _Inst_##b , _Inst_##ae , \
_Inst_##no, \ _Inst_##e , _Inst_##ne , _Inst_##be , _Inst_##a , \
_Inst_##b, \ _Inst_##s , _Inst_##ns , _Inst_##pe , _Inst_##po , \
_Inst_##ae, \ _Inst_##l , _Inst_##ge , _Inst_##le , _Inst_##g , \
_Inst_##e, \ kInstIdNone, kInstIdNone, kInstIdNone, kInstIdNone \
_Inst_##ne, \
_Inst_##be, \
_Inst_##a, \
_Inst_##s, \
_Inst_##ns, \
_Inst_##pe, \
_Inst_##po, \
_Inst_##l, \
_Inst_##ge, \
_Inst_##le, \
_Inst_##g, \
\
kInstIdNone, \
kInstIdNone, \
kInstIdNone, \
kInstIdNone \
} }
const uint32_t _x86ReverseCond[20] = { const uint32_t _x86ReverseCond[20] = {
/* kX86CondO -> */ kX86CondO, /* O|NO|B|AE -> */ kX86CondO, kX86CondNO, kX86CondA , kX86CondBE,
/* kX86CondNO -> */ kX86CondNO, /* E|NE|BE|A -> */ kX86CondE, kX86CondNE, kX86CondAE, kX86CondB ,
/* kX86CondB -> */ kX86CondA, /* S|NS|PE|PO -> */ kX86CondS, kX86CondNS, kX86CondPE, kX86CondPO,
/* kX86CondAE -> */ kX86CondBE, /* L|GE|LE|G -> */ kX86CondG, kX86CondLE, kX86CondGE, kX86CondL ,
/* kX86CondE -> */ kX86CondE, /* Unord|!Unord -> */ kX86CondFpuUnordered , kX86CondFpuNotUnordered, 0x12, 0x13
/* kX86CondNE -> */ kX86CondNE,
/* kX86CondBE -> */ kX86CondAE,
/* kX86CondA -> */ kX86CondB,
/* kX86CondS -> */ kX86CondS,
/* kX86CondNS -> */ kX86CondNS,
/* kX86CondPE -> */ kX86CondPE,
/* kX86CondPO -> */ kX86CondPO,
/* kX86CondL -> */ kX86CondG,
/* kX86CondGE -> */ kX86CondLE,
/* kX86CondLE -> */ kX86CondGE,
/* kX86CondG -> */ kX86CondL,
/* kX86CondFpuUnordered -> */ kX86CondFpuUnordered,
/* kX86CondFpuNotUnordered -> */ kX86CondFpuNotUnordered,
0x12,
0x13
}; };
const uint32_t _x86CondToCmovcc[20] = CC_TO_INST(kX86InstIdCmov); const uint32_t _x86CondToCmovcc[20] = CC_TO_INST(kX86InstIdCmov);
@@ -4549,10 +4518,12 @@ const uint32_t _x86CondToSetcc [20] = CC_TO_INST(kX86InstIdSet );
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_DISABLE_NAMES) #if !defined(ASMJIT_DISABLE_NAMES)
// Compare two instruction names. //! \internal
// //!
// `a` is null terminated instruction name from `_x86InstName[]` table. //! Compare two instruction names.
// `b` is non-null terminated instruction name passed to `getInstIdByName()`. //!
//! `a` is null terminated instruction name from `_x86InstName[]` table.
//! `b` is non-null terminated instruction name passed to `getInstIdByName()`.
static ASMJIT_INLINE int X86Util_cmpInstName(const char* a, const char* b, size_t len) { static ASMJIT_INLINE int X86Util_cmpInstName(const char* a, const char* b, size_t len) {
for (size_t i = 0; i < len; i++) { for (size_t i = 0; i < len; i++) {
int c = static_cast<int>(static_cast<uint8_t>(a[i])) - int c = static_cast<int>(static_cast<uint8_t>(a[i])) -

View File

@@ -10,10 +10,9 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/assembler.h" #include "../base/assembler.h"
#include "../base/compiler.h"
#include "../base/globals.h" #include "../base/globals.h"
#include "../base/intutil.h"
#include "../base/operand.h" #include "../base/operand.h"
#include "../base/utils.h"
#include "../base/vectypes.h" #include "../base/vectypes.h"
// [Api-Begin] // [Api-Begin]
@@ -28,7 +27,7 @@ namespace asmjit {
struct X86InstInfo; struct X86InstInfo;
struct X86InstExtendedInfo; struct X86InstExtendedInfo;
//! \addtogroup asmjit_x86_inst //! \addtogroup asmjit_x86
//! \{ //! \{
// ============================================================================ // ============================================================================
@@ -39,38 +38,38 @@ struct X86InstExtendedInfo;
//! \internal //! \internal
//! //!
//! X86/X64 instructions' names, accessible through `X86InstInfo`. //! X86/X64 instructions' names, accessible through `X86InstInfo`.
ASMJIT_VAR const char _x86InstName[]; ASMJIT_VARAPI const char _x86InstName[];
#endif // !ASMJIT_DISABLE_NAMES #endif // !ASMJIT_DISABLE_NAMES
//! \internal //! \internal
//! //!
//! X86/X64 instructions' extended information, accessible through `X86InstInfo`. //! X86/X64 instructions' extended information, accessible through `X86InstInfo`.
ASMJIT_VAR const X86InstExtendedInfo _x86InstExtendedInfo[]; ASMJIT_VARAPI const X86InstExtendedInfo _x86InstExtendedInfo[];
//! \internal //! \internal
//! //!
//! X86/X64 instructions' information. //! X86/X64 instructions' information.
ASMJIT_VAR const X86InstInfo _x86InstInfo[]; ASMJIT_VARAPI const X86InstInfo _x86InstInfo[];
//! \internal //! \internal
//! //!
//! X86/X64 condition codes to reversed condition codes map. //! X86/X64 condition codes to reversed condition codes map.
ASMJIT_VAR const uint32_t _x86ReverseCond[20]; ASMJIT_VARAPI const uint32_t _x86ReverseCond[20];
//! \internal //! \internal
//! //!
//! X86/X64 condition codes to "cmovcc" group map. //! X86/X64 condition codes to "cmovcc" group map.
ASMJIT_VAR const uint32_t _x86CondToCmovcc[20]; ASMJIT_VARAPI const uint32_t _x86CondToCmovcc[20];
//! \internal //! \internal
//! //!
//! X86/X64 condition codes to "jcc" group map. //! X86/X64 condition codes to "jcc" group map.
ASMJIT_VAR const uint32_t _x86CondToJcc[20]; ASMJIT_VARAPI const uint32_t _x86CondToJcc[20];
//! \internal //! \internal
//! //!
//! X86/X64 condition codes to "setcc" group map. //! X86/X64 condition codes to "setcc" group map.
ASMJIT_VAR const uint32_t _x86CondToSetcc[20]; ASMJIT_VARAPI const uint32_t _x86CondToSetcc[20];
// ============================================================================ // ============================================================================
// [asmjit::X86InstId] // [asmjit::X86InstId]
@@ -1624,8 +1623,8 @@ ASMJIT_ENUM(X86InstFlags) {
//! Instruction always performs memory access. //! Instruction always performs memory access.
//! //!
//! This flag is always combined with `kX86InstFlagSpecial` and describes //! This flag is always combined with `kX86InstFlagSpecial` and describes
//! that there is an implicit address which is accessed (usually EDI/RDI or //! that there is an implicit address which is accessed (usually EDI/RDI
//! ESI/EDI). //! and/or ESI/RSI).
kX86InstFlagSpecialMem = 0x00000080, kX86InstFlagSpecialMem = 0x00000080,
//! Instruction memory operand can refer to 16-bit address (used by FPU). //! Instruction memory operand can refer to 16-bit address (used by FPU).
@@ -1667,7 +1666,7 @@ ASMJIT_ENUM(X86InstFlags) {
//! Instruction supports zeroing of elements {k0z..k7z}. //! Instruction supports zeroing of elements {k0z..k7z}.
kX86InstFlagAvx512KZero = 0x10000000, kX86InstFlagAvx512KZero = 0x10000000,
//! Instruction supports broadcast {1toN}. //! Instruction supports broadcast {1toN}.
kX86InstFlagAvx512Broadcast = 0x20000000, kX86InstFlagAvx512BCast = 0x20000000,
//! Instruction supports suppressing all exceptions {sae}. //! Instruction supports suppressing all exceptions {sae}.
kX86InstFlagAvx512Sae = 0x40000000, kX86InstFlagAvx512Sae = 0x40000000,
//! Instruction supports static rounding control with SAE {rnd-sae}, //! Instruction supports static rounding control with SAE {rnd-sae},
@@ -1975,6 +1974,27 @@ ASMJIT_ENUM(X86VCmp) {
kX86VCmpTRUE_US = 0x1F //!< True (Signaling, Unordered). kX86VCmpTRUE_US = 0x1F //!< True (Signaling, Unordered).
}; };
// ============================================================================
// [asmjit::X86Round]
// ============================================================================
//! X86/X64 round encoding used by ROUND[PD/PS/SD/SS] family instructions.
ASMJIT_ENUM(X86Round) {
//! Round control - round to nearest (even).
kX86RoundNearest = 0x0,
//! Round control - round to down toward -INF (floor),
kX86RoundDown = 0x1,
//! Round control - round to up toward +INF (ceil).
kX86RoundUp = 0x2,
//! Round control - round toward zero (truncate).
kX86RoundTrunc = 0x3,
//! Rounding select - if set it will use the the current rounding mode
//! according to MXCS and ignore the round control (RC) bits.
kX86RoundCurrent = 0x4,
//! Precision mask - if set it avoids an inexact exception.
kX86RoundInexact = 0x8
};
// ============================================================================ // ============================================================================
// [asmjit::X86Prefetch] // [asmjit::X86Prefetch]
// ============================================================================ // ============================================================================
@@ -2327,8 +2347,7 @@ struct X86Util {
//! `kInstIdNone` (zero) is returned. //! `kInstIdNone` (zero) is returned.
//! //!
//! The given `name` doesn't have to be null-terminated if `len` is provided. //! The given `name` doesn't have to be null-terminated if `len` is provided.
ASMJIT_API static uint32_t getInstIdByName( ASMJIT_API static uint32_t getInstIdByName(const char* name, size_t len = kInvalidIndex);
const char* name, size_t len = kInvalidIndex);
#endif // !ASMJIT_DISABLE_NAMES #endif // !ASMJIT_DISABLE_NAMES
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -2369,35 +2388,39 @@ struct X86Util {
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [MmShuffle] // [Shuffle (SIMD)]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Pack a shuffle constant to be used with multimedia instrutions (2 values). //! Pack a shuffle constant to be used with multimedia instrutions (2 values).
//! //!
//! \param x First component position, number at interval [0, 1] inclusive. //! \param a Position of the first component [0, 1], inclusive.
//! \param y Second component position, number at interval [0, 1] inclusive. //! \param b Position of the second component [0, 1], inclusive.
//! //!
//! Shuffle constants can be used to make immediate value for these intrinsics: //! Shuffle constants can be used to encode an immediate for these instructions:
//! - `X86Assembler::shufpd()` and `X86Compiler::shufpd()` //! - `X86Assembler::shufpd()` and `X86Compiler::shufpd()`
static ASMJIT_INLINE int mmShuffle(uint32_t x, uint32_t y) { static ASMJIT_INLINE int shuffle(uint32_t a, uint32_t b) {
return static_cast<int>((x << 1) | y); uint32_t result = (a << 1) | b;
ASMJIT_ASSERT(result <= 0xFF);
return static_cast<int>(result);
} }
//! Pack a shuffle constant to be used with multimedia instrutions (4 values). //! Pack a shuffle constant to be used with multimedia instrutions (4 values).
//! //!
//! \param z First component position, number at interval [0, 3] inclusive. //! \param a Position of the first component [0, 3], inclusive.
//! \param x Second component position, number at interval [0, 3] inclusive. //! \param b Position of the second component [0, 3], inclusive.
//! \param y Third component position, number at interval [0, 3] inclusive. //! \param c Position of the third component [0, 3], inclusive.
//! \param w Fourth component position, number at interval [0, 3] inclusive. //! \param d Position of the fourth component [0, 3], inclusive.
//! //!
//! Shuffle constants can be used to make immediate value for these intrinsics: //! Shuffle constants can be used to encode an immediate for these instructions:
//! - `X86Assembler::pshufw()` and `X86Compiler::pshufw()` //! - `X86Assembler::pshufw()` and `X86Compiler::pshufw()`.
//! - `X86Assembler::pshufd()` and `X86Compiler::pshufd()` //! - `X86Assembler::pshufd()` and `X86Compiler::pshufd()`.
//! - `X86Assembler::pshufhw()` and `X86Compiler::pshufhw()` //! - `X86Assembler::pshufhw()` and `X86Compiler::pshufhw()`.
//! - `X86Assembler::pshuflw()` and `X86Compiler::pshuflw()` //! - `X86Assembler::pshuflw()` and `X86Compiler::pshuflw()`.
//! - `X86Assembler::shufps()` and `X86Compiler::shufps()` //! - `X86Assembler::shufps()` and `X86Compiler::shufps()`.
static ASMJIT_INLINE int mmShuffle(uint32_t z, uint32_t y, uint32_t x, uint32_t w) { static ASMJIT_INLINE int shuffle(uint32_t a, uint32_t b, uint32_t c, uint32_t d) {
return static_cast<int>((z << 6) | (y << 4) | (x << 2) | w); uint32_t result = (a << 6) | (b << 4) | (c << 2) | d;
ASMJIT_ASSERT(result <= 0xFF);
return static_cast<int>(result);
} }
}; };

File diff suppressed because it is too large Load Diff

View File

@@ -20,9 +20,9 @@
namespace asmjit { namespace asmjit {
#define REG(_Type_, _Index_, _Size_) {{ \ #define REG(_Type_, _Index_, _Size_) {{{ \
kOperandTypeReg, _Size_, { ((_Type_) << 8) + _Index_ }, kInvalidValue, {{ kInvalidVar, 0 }} \ kOperandTypeReg, _Size_, { ((_Type_) << 8) + _Index_ }, kInvalidValue, {{ kInvalidVar, 0 }} \
}} }}}
const X86RegData x86RegData = { const X86RegData x86RegData = {
// RIP. // RIP.

View File

@@ -47,9 +47,9 @@ struct X86ScheduleData {
uint16_t reserved; uint16_t reserved;
//! All instructions that this instruction depends on. //! All instructions that this instruction depends on.
PodList<InstNode*>::Link* dependsOn; PodList<HLInst*>::Link* dependsOn;
//! All instructions that use the result of this instruction. //! All instructions that use the result of this instruction.
PodList<InstNode*>::Link* usedBy; PodList<HLInst*>::Link* usedBy;
}; };
// ============================================================================ // ============================================================================
@@ -65,18 +65,18 @@ X86Scheduler::~X86Scheduler() {}
// [asmjit::X86Scheduler - Run] // [asmjit::X86Scheduler - Run]
// ============================================================================ // ============================================================================
Error X86Scheduler::run(Node* start, Node* stop) { Error X86Scheduler::run(HLNode* start, HLNode* stop) {
/* /*
ASMJIT_TLOG("[Schedule] === Begin ==="); ASMJIT_TLOG("[Schedule] === Begin ===");
Zone zone(8096 - kZoneOverhead); Zone zone(8096 - Zone::kZoneOverhead);
Node* node_ = start; HLNode* node_ = start;
while (node_ != stop) { while (node_ != stop) {
Node* next = node_->getNext(); HLNode* next = node_->getNext();
ASMJIT_ASSERT(node_->getType() == kNodeTypeInst); ASMJIT_ASSERT(node_->getType() == kHLNodeTypeInst);
printf(" %s\n", X86Util::getInstInfo(static_cast<InstNode*>(node_)->getInstId()).getInstName()); printf(" %s\n", X86Util::getInstInfo(static_cast<HLInst*>(node_)->getInstId()).getInstName());
node_ = next; node_ = next;
} }

View File

@@ -13,7 +13,7 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../x86/x86compiler.h" #include "../x86/x86compiler.h"
#include "../x86/x86context_p.h" #include "../x86/x86compilercontext_p.h"
#include "../x86/x86cpuinfo.h" #include "../x86/x86cpuinfo.h"
#include "../x86/x86inst.h" #include "../x86/x86inst.h"
@@ -41,7 +41,7 @@ struct X86Scheduler {
// [Run] // [Run]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
Error run(Node* start, Node* stop); Error run(HLNode* start, HLNode* stop);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]

View File

@@ -22,7 +22,7 @@
struct Performance { struct Performance {
static inline uint32_t now() { static inline uint32_t now() {
return asmjit::CpuTicks::now(); return asmjit::Utils::getTickCount();
} }
inline void reset() { inline void reset() {
@@ -67,7 +67,7 @@ int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
X86Assembler a(&runtime); X86Assembler a(&runtime);
X86Compiler c(&runtime); X86Compiler c;
uint32_t r, i; uint32_t r, i;
@@ -100,12 +100,12 @@ int main(int argc, char* argv[]) {
for (r = 0; r < kNumRepeats; r++) { for (r = 0; r < kNumRepeats; r++) {
perf.start(); perf.start();
for (i = 0; i < kNumIterations; i++) { for (i = 0; i < kNumIterations; i++) {
c.attach(&a);
asmgen::blend(c); asmgen::blend(c);
c.finalize();
void* p = c.make(); void* p = a.make();
runtime.release(p); runtime.release(p);
c.reset();
} }
perf.end(); perf.end();
} }

View File

@@ -6,6 +6,8 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../asmjit/asmjit.h" #include "../asmjit/asmjit.h"
#include "../asmjit/base/compilercontext_p.h"
#include "../asmjit/x86/x86compilercontext_p.h"
// ============================================================================ // ============================================================================
// [DumpCpu] // [DumpCpu]
@@ -38,7 +40,7 @@ static void dumpCpu(void) {
// [X86] // [X86]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_ARCH_X86) || defined(ASMJIT_ARCH_X64) #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
const asmjit::X86CpuInfo* x86Cpu = static_cast<const asmjit::X86CpuInfo*>(cpu); const asmjit::X86CpuInfo* x86Cpu = static_cast<const asmjit::X86CpuInfo*>(cpu);
static const DumpCpuFeature x86FeaturesList[] = { static const DumpCpuFeature x86FeaturesList[] = {
@@ -50,12 +52,12 @@ static void dumpCpu(void) {
{ asmjit::kX86CpuFeatureCMPXCHG8B , "CMPXCHG8B" }, { asmjit::kX86CpuFeatureCMPXCHG8B , "CMPXCHG8B" },
{ asmjit::kX86CpuFeatureCMPXCHG16B , "CMPXCHG16B" }, { asmjit::kX86CpuFeatureCMPXCHG16B , "CMPXCHG16B" },
{ asmjit::kX86CpuFeatureCLFLUSH , "CLFLUSH" }, { asmjit::kX86CpuFeatureCLFLUSH , "CLFLUSH" },
{ asmjit::kX86CpuFeatureCLFLUSHOpt , "CLFLUSH (Opt)" }, { asmjit::kX86CpuFeatureCLFLUSH_OPT , "CLFLUSH (Opt)" },
{ asmjit::kX86CpuFeaturePREFETCH , "PREFETCH" }, { asmjit::kX86CpuFeaturePREFETCH , "PREFETCH" },
{ asmjit::kX86CpuFeaturePREFETCHWT1 , "PREFETCHWT1" }, { asmjit::kX86CpuFeaturePREFETCHWT1 , "PREFETCHWT1" },
{ asmjit::kX86CpuFeatureLahfSahf , "LAHF/SAHF" }, { asmjit::kX86CpuFeatureLahfSahf , "LAHF/SAHF" },
{ asmjit::kX86CpuFeatureFXSR , "FXSR" }, { asmjit::kX86CpuFeatureFXSR , "FXSR" },
{ asmjit::kX86CpuFeatureFXSROpt , "FXSR (Opt)" }, { asmjit::kX86CpuFeatureFXSR_OPT , "FXSR (Opt)" },
{ asmjit::kX86CpuFeatureMMX , "MMX" }, { asmjit::kX86CpuFeatureMMX , "MMX" },
{ asmjit::kX86CpuFeatureMMX2 , "MMX2" }, { asmjit::kX86CpuFeatureMMX2 , "MMX2" },
{ asmjit::kX86CpuFeature3DNOW , "3DNOW" }, { asmjit::kX86CpuFeature3DNOW , "3DNOW" },
@@ -77,8 +79,8 @@ static void dumpCpu(void) {
{ asmjit::kX86CpuFeatureRDRAND , "RDRAND" }, { asmjit::kX86CpuFeatureRDRAND , "RDRAND" },
{ asmjit::kX86CpuFeatureRDSEED , "RDSEED" }, { asmjit::kX86CpuFeatureRDSEED , "RDSEED" },
{ asmjit::kX86CpuFeatureSHA , "SHA" }, { asmjit::kX86CpuFeatureSHA , "SHA" },
{ asmjit::kX86CpuFeatureXSave , "XSAVE" }, { asmjit::kX86CpuFeatureXSAVE , "XSAVE" },
{ asmjit::kX86CpuFeatureXSaveOS , "XSAVE (OS)" }, { asmjit::kX86CpuFeatureXSAVE_OS , "XSAVE (OS)" },
{ asmjit::kX86CpuFeatureAVX , "AVX" }, { asmjit::kX86CpuFeatureAVX , "AVX" },
{ asmjit::kX86CpuFeatureAVX2 , "AVX2" }, { asmjit::kX86CpuFeatureAVX2 , "AVX2" },
{ asmjit::kX86CpuFeatureF16C , "F16C" }, { asmjit::kX86CpuFeatureF16C , "F16C" },
@@ -91,8 +93,8 @@ static void dumpCpu(void) {
{ asmjit::kX86CpuFeatureRTM , "RTM" }, { asmjit::kX86CpuFeatureRTM , "RTM" },
{ asmjit::kX86CpuFeatureADX , "ADX" }, { asmjit::kX86CpuFeatureADX , "ADX" },
{ asmjit::kX86CpuFeatureMPX , "MPX" }, { asmjit::kX86CpuFeatureMPX , "MPX" },
{ asmjit::kX86CpuFeatureFSGSBase , "FS/GS Base" }, { asmjit::kX86CpuFeatureFSGSBASE , "FS/GS Base" },
{ asmjit::kX86CpuFeatureMOVSBSTOSBOpt , "REP MOVSB/STOSB (Opt)" }, { asmjit::kX86CpuFeatureMOVSBSTOSB_OPT, "REP MOVSB/STOSB (Opt)" },
{ asmjit::kX86CpuFeatureAVX512F , "AVX512F" }, { asmjit::kX86CpuFeatureAVX512F , "AVX512F" },
{ asmjit::kX86CpuFeatureAVX512CD , "AVX512CD" }, { asmjit::kX86CpuFeatureAVX512CD , "AVX512CD" },
{ asmjit::kX86CpuFeatureAVX512PF , "AVX512PF" }, { asmjit::kX86CpuFeatureAVX512PF , "AVX512PF" },
@@ -138,7 +140,6 @@ static void dumpSizeOf(void) {
INFO(""); INFO("");
INFO("SizeOf Base:"); INFO("SizeOf Base:");
DUMP_TYPE(asmjit::CodeGen);
DUMP_TYPE(asmjit::ConstPool); DUMP_TYPE(asmjit::ConstPool);
DUMP_TYPE(asmjit::Runtime); DUMP_TYPE(asmjit::Runtime);
DUMP_TYPE(asmjit::Zone); DUMP_TYPE(asmjit::Zone);
@@ -164,23 +165,23 @@ static void dumpSizeOf(void) {
#if !defined(ASMJIT_DISABLE_COMPILER) #if !defined(ASMJIT_DISABLE_COMPILER)
INFO("SizeOf Compiler:"); INFO("SizeOf Compiler:");
DUMP_TYPE(asmjit::Compiler); DUMP_TYPE(asmjit::Compiler);
DUMP_TYPE(asmjit::Node); DUMP_TYPE(asmjit::VarMap);
DUMP_TYPE(asmjit::AlignNode); DUMP_TYPE(asmjit::VarAttr);
DUMP_TYPE(asmjit::CallNode); DUMP_TYPE(asmjit::VarData);
DUMP_TYPE(asmjit::CommentNode); DUMP_TYPE(asmjit::VarState);
DUMP_TYPE(asmjit::EmbedNode); DUMP_TYPE(asmjit::HLNode);
DUMP_TYPE(asmjit::FuncNode); DUMP_TYPE(asmjit::HLInst);
DUMP_TYPE(asmjit::EndNode); DUMP_TYPE(asmjit::HLJump);
DUMP_TYPE(asmjit::InstNode); DUMP_TYPE(asmjit::HLData);
DUMP_TYPE(asmjit::JumpNode); DUMP_TYPE(asmjit::HLAlign);
DUMP_TYPE(asmjit::TargetNode); DUMP_TYPE(asmjit::HLLabel);
DUMP_TYPE(asmjit::HLComment);
DUMP_TYPE(asmjit::HLSentinel);
DUMP_TYPE(asmjit::HLFunc);
DUMP_TYPE(asmjit::HLCall);
DUMP_TYPE(asmjit::FuncDecl); DUMP_TYPE(asmjit::FuncDecl);
DUMP_TYPE(asmjit::FuncInOut); DUMP_TYPE(asmjit::FuncInOut);
DUMP_TYPE(asmjit::FuncPrototype); DUMP_TYPE(asmjit::FuncPrototype);
DUMP_TYPE(asmjit::VarAttr);
DUMP_TYPE(asmjit::VarData);
DUMP_TYPE(asmjit::VarMap);
DUMP_TYPE(asmjit::VarState);
INFO(""); INFO("");
#endif // !ASMJIT_DISABLE_COMPILER #endif // !ASMJIT_DISABLE_COMPILER
@@ -196,12 +197,12 @@ static void dumpSizeOf(void) {
#if !defined(ASMJIT_DISABLE_COMPILER) #if !defined(ASMJIT_DISABLE_COMPILER)
DUMP_TYPE(asmjit::X86Compiler); DUMP_TYPE(asmjit::X86Compiler);
DUMP_TYPE(asmjit::X86CallNode);
DUMP_TYPE(asmjit::X86FuncNode);
DUMP_TYPE(asmjit::X86FuncDecl);
DUMP_TYPE(asmjit::X86VarMap); DUMP_TYPE(asmjit::X86VarMap);
DUMP_TYPE(asmjit::X86VarInfo); DUMP_TYPE(asmjit::X86VarInfo);
DUMP_TYPE(asmjit::X86VarState); DUMP_TYPE(asmjit::X86VarState);
DUMP_TYPE(asmjit::X86CallNode);
DUMP_TYPE(asmjit::X86FuncNode);
DUMP_TYPE(asmjit::X86FuncDecl);
#endif // !ASMJIT_DISABLE_COMPILER #endif // !ASMJIT_DISABLE_COMPILER
INFO(""); INFO("");

File diff suppressed because it is too large Load Diff

View File

@@ -22,22 +22,22 @@ static void blend(asmjit::X86Compiler& c) {
using namespace asmjit; using namespace asmjit;
using namespace asmjit::x86; using namespace asmjit::x86;
X86GpVar dst(c, kVarTypeIntPtr, "dst"); X86GpVar dst = c.newIntPtr("dst");
X86GpVar src(c, kVarTypeIntPtr, "src"); X86GpVar src = c.newIntPtr("src");
X86GpVar i(c, kVarTypeIntPtr, "i"); X86GpVar i = c.newIntPtr("i");
X86GpVar j(c, kVarTypeIntPtr, "j"); X86GpVar j = c.newIntPtr("j");
X86GpVar t(c, kVarTypeIntPtr, "t"); X86GpVar t = c.newIntPtr("t");
X86XmmVar cZero(c, kX86VarTypeXmm, "cZero"); X86XmmVar cZero = c.newXmm("cZero");
X86XmmVar cMul255A(c, kX86VarTypeXmm, "cMul255A"); X86XmmVar cMul255A = c.newXmm("cMul255A");
X86XmmVar cMul255M(c, kX86VarTypeXmm, "cMul255M"); X86XmmVar cMul255M = c.newXmm("cMul255M");
X86XmmVar x0(c, kX86VarTypeXmm, "x0"); X86XmmVar x0 = c.newXmm("x0");
X86XmmVar x1(c, kX86VarTypeXmm, "x1"); X86XmmVar x1 = c.newXmm("x1");
X86XmmVar y0(c, kX86VarTypeXmm, "y0"); X86XmmVar y0 = c.newXmm("y0");
X86XmmVar a0(c, kX86VarTypeXmm, "a0"); X86XmmVar a0 = c.newXmm("a0");
X86XmmVar a1(c, kX86VarTypeXmm, "a1"); X86XmmVar a1 = c.newXmm("a1");
Label L_SmallLoop(c); Label L_SmallLoop(c);
Label L_SmallEnd(c); Label L_SmallEnd(c);
@@ -47,7 +47,7 @@ static void blend(asmjit::X86Compiler& c) {
Label L_Data(c); Label L_Data(c);
c.addFunc(kFuncConvHost, FuncBuilder3<Void, void*, const void*, size_t>()); c.addFunc(FuncBuilder3<Void, void*, const void*, size_t>(kCallConvHost));
c.setArg(0, dst); c.setArg(0, dst);
c.setArg(1, src); c.setArg(1, src);
@@ -90,7 +90,7 @@ static void blend(asmjit::X86Compiler& c) {
c.psrlw(a0, 8); c.psrlw(a0, 8);
c.punpcklbw(x0, cZero); c.punpcklbw(x0, cZero);
c.pshuflw(a0, a0, X86Util::mmShuffle(1, 1, 1, 1)); c.pshuflw(a0, a0, X86Util::shuffle(1, 1, 1, 1));
c.punpcklbw(y0, cZero); c.punpcklbw(y0, cZero);
c.pmullw(x0, a0); c.pmullw(x0, a0);
@@ -138,8 +138,8 @@ static void blend(asmjit::X86Compiler& c) {
c.punpckhbw(x1, cZero); c.punpckhbw(x1, cZero);
c.punpckhwd(a1, a1); c.punpckhwd(a1, a1);
c.pshufd(a0, a0, X86Util::mmShuffle(3, 3, 1, 1)); c.pshufd(a0, a0, X86Util::shuffle(3, 3, 1, 1));
c.pshufd(a1, a1, X86Util::mmShuffle(3, 3, 1, 1)); c.pshufd(a1, a1, X86Util::shuffle(3, 3, 1, 1));
c.pmullw(x0, a0); c.pmullw(x0, a0);
c.pmullw(x1, a1); c.pmullw(x1, a1);

View File

@@ -1,424 +0,0 @@
#!/usr/bin/env python
import os
AUTOEXP_FILES = [
# Visual Studio 8.0 (2005).
"C:\\Program Files\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 8\\Common7\\Packages\\Debugger\\autoexp.dat",
# Visual Studio 9.0 (2008).
"C:\\Program Files\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 9.0\\Common7\\Packages\\Debugger\\autoexp.dat",
# Visual Studio 10.0 (2010).
"C:\\Program Files\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat",
"C:\\Program Files (x86)\\Microsoft Visual Studio 10.0\\Common7\\Packages\\Debugger\\autoexp.dat"
]
DIRECTIVE_SYMBOL = '@'
# =============================================================================
# [Log]
# =============================================================================
def log(str):
print(str)
# =============================================================================
# [Is...]
# =============================================================================
def isDirective(c):
return c == DIRECTIVE_SYMBOL
def isAlpha(c):
c = ord(c)
return (c >= ord('a') and c <= ord('z')) or (c >= ord('A') and c <= ord('Z'))
def isAlpha_(c):
return isAlpha(c) or (c == '_')
def isNumber(c):
c = ord(c)
return (c >= ord('0')) and (c <= ord('9'))
def isAlnum(c):
return isAlpha(c) or isNumber(c)
def isAlnum_(c):
return isAlnum(c) or (c == '_')
def isSpace(c):
return (c == ' ') or (c == '\t')
def isNewLine(c):
return c == '\n'
# =============================================================================
# [SyntaxError]
# =============================================================================
class SyntaxError(Exception):
def __init__(self, msg):
self.msg = msg
def __str__(self):
return repr(self.msg)
# =============================================================================
# [Context]
# =============================================================================
class Context(object):
def __init__(self, data):
self.data = data
self.index = 0
self.size = len(data)
def isNewLine(self):
if self.index == 0:
return True
else:
return self.data[self.index - 1] == '\n'
def isEnd(self):
return self.index >= self.size
def getChar(self):
if self.index >= self.size:
return '\0'
return self.data[self.index]
def advance(self):
if self.index < self.size:
self.index += 1
def parseUntilTrue(self, func, advance):
while not self.isEnd():
c = self.data[self.index]
if func(c):
self.index += 1
continue
if advance:
self.index += 1
return True
return False
def parseUntilFalse(self, func, advance):
while not self.isEnd():
c = self.data[self.index]
if not func(c):
self.index += 1
continue
if advance:
self.index += 1
return True
return False
def skipString(self):
def func(c):
return c == '"'
return self.parseUntilFalse(func, True)
def skipSpaces(self):
return self.parseUntilTrue(isSpace, False)
def skipLine(self):
return self.parseUntilFalse(isNewLine, True)
def parseDirective(self, index):
start = index
data = self.data
size = self.size
c = data[index]
assert isAlpha_(c)
while True:
index += 1
if index >= size:
break
c = data[index]
if isAlnum_(c):
continue
break
self.index = index
return data[start:index]
def parseSymbol(self, index):
start = index
data = self.data
size = self.size
c = data[index]
assert isAlpha_(c)
while True:
index += 1
if index >= size:
return data[start:index]
c = data[index]
if isAlnum_(c):
continue
if c == ':' and index + 2 < size and data[index + 1] == ':' and isAlpha_(data[index + 2]):
index += 2
continue
self.index = index
return data[start:index]
def parseMacro(self, index):
start = index
end = None
data = self.data
size = self.size
if index >= size:
return ""
while True:
c = data[index]
index += 1
if c == '\n' or index >= size:
if end == None:
end = index - 1
break
if c == ';':
if end == None:
end = index
while start < end and isSpace(data[end - 1]):
end -= 1
self.index = index
return data[start:end]
def replaceRange(self, start, end, content):
old = self.data
self.data = old[0:start] + content + old[end:]
self.size = len(self.data)
assert(self.index >= end)
self.index -= end - start
self.index += len(content)
# =============================================================================
# [AutoExpDat]
# =============================================================================
class AutoExpDat(object):
def __init__(self, data):
self.library = None
self.symbols = {}
self.data = self.process(data.replace('\r', ''))
def process(self, data):
ctx = Context(data)
while not ctx.isEnd():
c = ctx.getChar()
# Skip comments.
if c == ';':
ctx.skipLine()
continue
# Skip strings.
if c == '"':
ctx.advance()
ctx.skipString()
continue
# Skip numbers.
if isNumber(c):
ctx.parseUntilTrue(isAlnum_, True)
continue
# Parse directives.
if isDirective(c) and ctx.isNewLine():
start = ctx.index
ctx.advance()
c = ctx.getChar()
# Remove lines that have '@' followed by space or newline.
if isNewLine(c) or c == '\0':
ctx.advance()
ctx.replaceRange(start, ctx.index, "")
continue
if isSpace(c):
ctx.skipLine()
ctx.replaceRange(start, ctx.index, "")
continue
directive = ctx.parseDirective(ctx.index)
c = ctx.getChar()
if not isSpace(c):
self.error("Directive Error: @" + directive + ".")
ctx.skipSpaces()
# Directive '@library'.
if directive == "library":
self.library = ctx.parseMacro(ctx.index)
# Directive '@define'.
elif directive == "define":
c = ctx.getChar()
if not isAlpha_(c):
self.error("Define Directive has to start with alpha character or underscore")
symbol = ctx.parseSymbol(ctx.index)
c = ctx.getChar()
# No Macro.
if isNewLine(c):
ctx.advance()
self.addSymbol(symbol, "")
# Has Macro.
else:
ctx.skipSpaces()
macro = ctx.parseMacro(ctx.index)
self.addSymbol(symbol, macro)
# Unknown Directive.
else:
self.error("Unknown Directive: @" + directive + ".")
ctx.replaceRange(start, ctx.index, "")
continue
# Parse/Replace symbol.
if isAlpha_(c) and ctx.index > 0 and ctx.data[ctx.index - 1] != '#':
start = ctx.index
symbol = ctx.parseSymbol(start)
if symbol in self.symbols:
ctx.replaceRange(start, start + len(symbol), self.symbols[symbol])
continue
ctx.advance()
return ctx.data
def addSymbol(self, symbol, macro):
if symbol in self.symbols:
self.error("Symbol '" + symbol + "' redefinition.")
else:
# Recurse.
macro = self.process(macro)
log("-- @define " + symbol + " " + macro)
self.symbols[symbol] = macro
def error(self, msg):
raise SyntaxError(msg)
# =============================================================================
# [LoadFile / SaveFile]
# =============================================================================
def loadFile(file):
h = None
data = None
try:
h = open(file, "rb")
data = h.read()
except:
pass
finally:
if h:
h.close()
return data
def saveFile(file, data):
h = None
result = False
try:
h = open(file, "wb")
h.truncate()
h.write(data)
result = True
except:
pass
finally:
if h:
h.close()
return result
# =============================================================================
# [PatchFile]
# =============================================================================
def patchFile(file, mark, data):
input = loadFile(file)
if not input:
return
beginMark = ";${" + mark + ":Begin}"
endMark = ";${" + mark + ":End}"
if beginMark in input:
# Replace.
if not endMark in input:
log("-- Corrupted File:\n" + " " + file)
return
beginMarkIndex = input.find(beginMark)
endMarkIndex = input.find(endMark)
beginMarkIndex = input.find('\n', beginMarkIndex) + 1
endMarkIndex = input.rfind('\n', 0, endMarkIndex) + 1
if beginMarkIndex == -1 or \
endMarkIndex == -1 or \
beginMarkIndex > endMarkIndex:
log("-- Corrupted File:\n" + " " + file)
return
output = input[:beginMarkIndex] + data + input[endMarkIndex:]
else:
# Add.
output = input
output += "\n"
output += beginMark + "\n"
output += data
output += endMark + "\n"
if input == output:
log("-- Unaffected:\n" + " " + file)
else:
log("-- Patching:\n" + " " + file)
if not saveFile(file, output):
log("!! Can't write:\n" + " " + file)
def main():
src = loadFile("autoexp.dat")
if src == None:
log("!! Can't read autoexp.dat")
return
src = AutoExpDat(src)
if not src.library:
log("!! Library not defined, use @library directive.")
return
for file in AUTOEXP_FILES:
patchFile(file, src.library, src.data)
main()

View File

@@ -1,920 +0,0 @@
@library asmjit
@
@define NULL (0)
@
@define asmjit::kInvalidValue (0xFFFFFFFF)
@
@define asmjit::kOperandTypeNone (0x0)
@define asmjit::kOperandTypeReg (0x1)
@define asmjit::kOperandTypeVar (0x2)
@define asmjit::kOperandTypeMem (0x3)
@define asmjit::kOperandTypeImm (0x4)
@define asmjit::kOperandTypeLabel (0x5)
@
@define asmjit::kMemTypeBaseIndex (0x0)
@define asmjit::kMemTypeStackIndex (0x1)
@define asmjit::kMemTypeLabel (0x2)
@define asmjit::kMemTypeAbsolute (0x3)
@
@define asmjit::kVarAttrInReg (0x00000001)
@define asmjit::kVarAttrOutReg (0x00000002)
@define asmjit::kVarAttrInOutReg (0x00000003)
@define asmjit::kVarAttrInMem (0x00000004)
@define asmjit::kVarAttrOutMem (0x00000008)
@define asmjit::kVarAttrInOutMem (0x0000000C)
@define asmjit::kVarAttrInDecide (0x00000010)
@define asmjit::kVarAttrOutDecide (0x00000020)
@define asmjit::kVarAttrInOutDecide (0x00000030)
@define asmjit::kVarAttrInConv (0x00000040)
@define asmjit::kVarAttrOutConv (0x00000080)
@define asmjit::kVarAttrInOutConv (0x000000C0)
@define asmjit::kVarAttrInCall (0x00000100)
@define asmjit::kVarAttrInArg (0x00000200)
@define asmjit::kVarAttrOutRet (0x00000400)
@define asmjit::kVarAttrUnuse (0x00000800)
@
@define asmjit::kVarTypeInt8 (0x0)
@define asmjit::kVarTypeUInt8 (0x1)
@define asmjit::kVarTypeInt16 (0x2)
@define asmjit::kVarTypeUInt16 (0x3)
@define asmjit::kVarTypeInt32 (0x4)
@define asmjit::kVarTypeUInt32 (0x5)
@define asmjit::kVarTypeInt64 (0x6)
@define asmjit::kVarTypeUInt64 (0x7)
@define asmjit::kVarTypeFp32 (0x8)
@define asmjit::kVarTypeFp64 (0x9)
@define asmjit::kVarTypeFpEx (0xA)
@define asmjit::kVarTypeInvalid (0xFF)
@
@define asmjit::x86::kVarTypeMm (0xB)
@define asmjit::x86::kVarTypeXmm (0xC)
@define asmjit::x86::kVarTypeXmmSs (0xD)
@define asmjit::x86::kVarTypeXmmPs (0xE)
@define asmjit::x86::kVarTypeXmmSd (0xF)
@define asmjit::x86::kVarTypeXmmPd (0x10)
@
@define asmjit::kVarStateUnused (0x0)
@define asmjit::kVarStateReg (0x1)
@define asmjit::kVarStateMem (0x2)
@
@define asmjit::kNodeTypeNone (0x0)
@define asmjit::kNodeTypeAlign (0x1)
@define asmjit::kNodeTypeEmbed (0x2)
@define asmjit::kNodeTypeComment (0x3)
@define asmjit::kNodeTypeHint (0x4)
@define asmjit::kNodeTypeTarget (0x5)
@define asmjit::kNodeTypeInst (0x6)
@define asmjit::kNodeTypeFunc (0x7)
@define asmjit::kNodeTypeEnd (0x8)
@define asmjit::kNodeTypeRet (0x9)
@define asmjit::kNodeTypeCall (0xA)
@define asmjit::kNodeTypeSArg (0xB)
@
@define asmjit::kNodeFlagIsTranslated (0x0001)
@define asmjit::kNodeFlagIsJmp (0x0002)
@define asmjit::kNodeFlagIsJcc (0x0004)
@define asmjit::kNodeFlagIsTaken (0x0008)
@define asmjit::kNodeFlagIsRet (0x0010)
@define asmjit::kNodeFlagIsSpecial (0x0020)
@define asmjit::kNodeFlagIsFp (0x0040)
[Visualizer]
; =============================================================================
; [asmjit::base]
; =============================================================================
asmjit::PodVector<*> {
preview(
#(
"[", $e._length, "]",
"(",
#array(
expr: ((($T1*)($e._d + 1))[$i]),
size: $e._d->length
),
")"
)
)
children(
#(
#([...]: [$c,!]),
#array(
expr: ((($T1*)($e._d + 1))[$i]),
size: $e._d->length
)
)
)
}
; =============================================================================
; [asmjit::x86x64 - Operand]
; =============================================================================
asmjit::Operand {
preview(
#(
#if ($e._base.op == asmjit::kOperandTypeReg) ([(*(asmjit::BaseReg *) &$e)])
#elif ($e._base.op == asmjit::kOperandTypeVar) ([(*(asmjit::BaseVar *) &$e)])
#elif ($e._base.op == asmjit::kOperandTypeMem) ([(*(asmjit::BaseMem *) &$e)])
#elif ($e._base.op == asmjit::kOperandTypeImm) ([(*(asmjit::Imm *) &$e)])
#elif ($e._base.op == asmjit::kOperandTypeLabel) ([(*(asmjit::Label *) &$e)])
#else ("noOperand")
)
)
children(
#(
#([...]: [$c,!]),
#(base: [$e._base]),
#(reg: [(*(asmjit::BaseReg*) &$e)]),
#(var: [(*(asmjit::BaseVar*) &$e)]),
#(mem: [(*(asmjit::BaseMem*) &$e)]),
#(imm: [(*(asmjit::Imm*) &$e)]),
#(label: [(*(asmjit::Label*) &$e)])
)
)
}
asmjit::BaseReg|asmjit::x86x64::X86Reg|asmjit::x86x64::GpReg|asmjit::x86x64::FpReg|asmjit::x86x64::MmReg|asmjit::x86x64::XmmReg|asmjit::x86x64::SegReg {
preview(
#(
#if ($e._reg.code == 0x0100) ("al")
#elif ($e._reg.code == 0x0101) ("cl")
#elif ($e._reg.code == 0x0102) ("dl")
#elif ($e._reg.code == 0x0103) ("bl")
#elif ($e._reg.code == 0x0104) ("spl")
#elif ($e._reg.code == 0x0105) ("bpl")
#elif ($e._reg.code == 0x0106) ("sil")
#elif ($e._reg.code == 0x0107) ("dil")
#elif ($e._reg.code == 0x0108) ("r8b")
#elif ($e._reg.code == 0x0109) ("r9b")
#elif ($e._reg.code == 0x010A) ("r10b")
#elif ($e._reg.code == 0x010B) ("r11b")
#elif ($e._reg.code == 0x010C) ("r12b")
#elif ($e._reg.code == 0x010D) ("r13b")
#elif ($e._reg.code == 0x010E) ("r14b")
#elif ($e._reg.code == 0x010F) ("r15b")
#elif ($e._reg.code == 0x0200) ("ah")
#elif ($e._reg.code == 0x0201) ("ch")
#elif ($e._reg.code == 0x0202) ("dh")
#elif ($e._reg.code == 0x0203) ("bh")
#elif ($e._reg.code == 0x1000) ("ax")
#elif ($e._reg.code == 0x1001) ("cx")
#elif ($e._reg.code == 0x1002) ("dx")
#elif ($e._reg.code == 0x1003) ("bx")
#elif ($e._reg.code == 0x1004) ("sp")
#elif ($e._reg.code == 0x1005) ("bp")
#elif ($e._reg.code == 0x1006) ("si")
#elif ($e._reg.code == 0x1007) ("di")
#elif ($e._reg.code == 0x1008) ("r8w")
#elif ($e._reg.code == 0x1009) ("r9w")
#elif ($e._reg.code == 0x100A) ("r10w")
#elif ($e._reg.code == 0x100B) ("r11w")
#elif ($e._reg.code == 0x100C) ("r12w")
#elif ($e._reg.code == 0x100D) ("r13w")
#elif ($e._reg.code == 0x100E) ("r14w")
#elif ($e._reg.code == 0x100F) ("r15w")
#elif ($e._reg.code == 0x2000) ("eax")
#elif ($e._reg.code == 0x2001) ("ecx")
#elif ($e._reg.code == 0x2002) ("edx")
#elif ($e._reg.code == 0x2003) ("ebx")
#elif ($e._reg.code == 0x2004) ("esp")
#elif ($e._reg.code == 0x2005) ("ebp")
#elif ($e._reg.code == 0x2006) ("esi")
#elif ($e._reg.code == 0x2007) ("edi")
#elif ($e._reg.code == 0x2008) ("r8d")
#elif ($e._reg.code == 0x2009) ("r9d")
#elif ($e._reg.code == 0x200A) ("r10d")
#elif ($e._reg.code == 0x200B) ("r11d")
#elif ($e._reg.code == 0x200C) ("r12d")
#elif ($e._reg.code == 0x200D) ("r13d")
#elif ($e._reg.code == 0x200E) ("r14d")
#elif ($e._reg.code == 0x200F) ("r15d")
#elif ($e._reg.code == 0x3000) ("rax")
#elif ($e._reg.code == 0x3001) ("rcx")
#elif ($e._reg.code == 0x3002) ("rdx")
#elif ($e._reg.code == 0x3003) ("rbx")
#elif ($e._reg.code == 0x3004) ("rsp")
#elif ($e._reg.code == 0x3005) ("rbp")
#elif ($e._reg.code == 0x3006) ("rsi")
#elif ($e._reg.code == 0x3007) ("rdi")
#elif ($e._reg.code == 0x3008) ("r8")
#elif ($e._reg.code == 0x3009) ("r9")
#elif ($e._reg.code == 0x300A) ("r10")
#elif ($e._reg.code == 0x300B) ("r11")
#elif ($e._reg.code == 0x300C) ("r12")
#elif ($e._reg.code == 0x300D) ("r13")
#elif ($e._reg.code == 0x300E) ("r14")
#elif ($e._reg.code == 0x300F) ("r15")
#elif ($e._reg.code == 0x5000) ("fp0")
#elif ($e._reg.code == 0x5001) ("fp1")
#elif ($e._reg.code == 0x5002) ("fp2")
#elif ($e._reg.code == 0x5003) ("fp3")
#elif ($e._reg.code == 0x5004) ("fp4")
#elif ($e._reg.code == 0x5005) ("fp5")
#elif ($e._reg.code == 0x5006) ("fp6")
#elif ($e._reg.code == 0x5007) ("fp7")
#elif ($e._reg.code == 0x6000) ("mm0")
#elif ($e._reg.code == 0x6001) ("mm1")
#elif ($e._reg.code == 0x6002) ("mm2")
#elif ($e._reg.code == 0x6003) ("mm3")
#elif ($e._reg.code == 0x6004) ("mm4")
#elif ($e._reg.code == 0x6005) ("mm5")
#elif ($e._reg.code == 0x6006) ("mm6")
#elif ($e._reg.code == 0x6007) ("mm7")
#elif ($e._reg.code == 0x7000) ("xmm0")
#elif ($e._reg.code == 0x7001) ("xmm1")
#elif ($e._reg.code == 0x7002) ("xmm2")
#elif ($e._reg.code == 0x7003) ("xmm3")
#elif ($e._reg.code == 0x7004) ("xmm4")
#elif ($e._reg.code == 0x7005) ("xmm5")
#elif ($e._reg.code == 0x7006) ("xmm6")
#elif ($e._reg.code == 0x7007) ("xmm7")
#elif ($e._reg.code == 0x7008) ("xmm8")
#elif ($e._reg.code == 0x7009) ("xmm9")
#elif ($e._reg.code == 0x700A) ("xmm10")
#elif ($e._reg.code == 0x700B) ("xmm11")
#elif ($e._reg.code == 0x700C) ("xmm12")
#elif ($e._reg.code == 0x700D) ("xmm13")
#elif ($e._reg.code == 0x700E) ("xmm14")
#elif ($e._reg.code == 0x700F) ("xmm15")
#elif ($e._reg.code == 0x8000) ("ymm0")
#elif ($e._reg.code == 0x8001) ("ymm1")
#elif ($e._reg.code == 0x8002) ("ymm2")
#elif ($e._reg.code == 0x8003) ("ymm3")
#elif ($e._reg.code == 0x8004) ("ymm4")
#elif ($e._reg.code == 0x8005) ("ymm5")
#elif ($e._reg.code == 0x8006) ("ymm6")
#elif ($e._reg.code == 0x8007) ("ymm7")
#elif ($e._reg.code == 0x8008) ("ymm8")
#elif ($e._reg.code == 0x8009) ("ymm9")
#elif ($e._reg.code == 0x800A) ("ymm10")
#elif ($e._reg.code == 0x800B) ("ymm11")
#elif ($e._reg.code == 0x800C) ("ymm12")
#elif ($e._reg.code == 0x800D) ("ymm13")
#elif ($e._reg.code == 0x800E) ("ymm14")
#elif ($e._reg.code == 0x800F) ("ymm15")
#elif ($e._reg.code == 0xD000) ("es")
#elif ($e._reg.code == 0xD001) ("cs")
#elif ($e._reg.code == 0xD002) ("ss")
#elif ($e._reg.code == 0xD003) ("ds")
#elif ($e._reg.code == 0xD004) ("fs")
#elif ($e._reg.code == 0xD005) ("gs")
#else ("noReg")
)
)
children(
#(
#([...]: [$c,!]),
#(op: [$e._reg.op, x]),
#(size: [$e._reg.size, u]),
#(code: [$e._reg.code, x])
)
)
}
asmjit::BaseVar|asmjit::x86x64::X86Var|asmjit::x86x64::GpVar|asmjit::x86x64::FpVar|asmjit::x86x64::MmVar|asmjit::x86x64::XmmVar {
preview(
#(
#if ($e._var.varType == asmjit::kVarTypeInt8) ("gpbLo")
#elif ($e._var.varType == asmjit::kVarTypeUInt8) ("gpbLo")
#elif ($e._var.varType == asmjit::kVarTypeInt16) ("gpw")
#elif ($e._var.varType == asmjit::kVarTypeUInt16) ("gpw")
#elif ($e._var.varType == asmjit::kVarTypeInt32) ("gpd")
#elif ($e._var.varType == asmjit::kVarTypeUInt32) ("gpd")
#elif ($e._var.varType == asmjit::kVarTypeInt64) ("gpq")
#elif ($e._var.varType == asmjit::kVarTypeUInt64) ("gpq")
#elif ($e._var.varType == asmjit::kVarTypeFp32) ("fp32")
#elif ($e._var.varType == asmjit::kVarTypeFp64) ("fp64")
#elif ($e._var.varType == asmjit::kVarTypeFpEx) ("fpEx")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeMm) ("mm")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmm) ("xmm")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmSs) ("xmmSs")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmSd) ("xmmSd")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmPs) ("xmmPs")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeXmmPd) ("xmmPd")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmm) ("ymm")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmmPs) ("ymmPs")
#elif ($e._var.varType == asmjit::x86x64::kVarTypeYmmPd) ("ymmPd")
#else ("noVar"),
"(",
"id=",
#if ($e._var.id != asmjit::kInvalidValue) (
[$e._var.id, x]
)
#else (
"INVALID"
),
")"
)
)
children(
#(
#([...]: [$c,!]),
#(op: [$e._var.op, x]),
#(size: [$e._var.size, u]),
#(id: [$e._var.id, x]),
#(code: [$e._var.code, x]),
#(varType: [$e._var.varType, x])
)
)
}
asmjit::BaseMem|asmjit::x86x64::Mem {
preview(
#(
#if ($e._mem.size == 1) ("byte ptr")
#elif ($e._mem.size == 2) ("word ptr")
#elif ($e._mem.size == 4) ("dword ptr")
#elif ($e._mem.size == 8) ("qword ptr")
#elif ($e._mem.size == 10) ("tword ptr")
#elif ($e._mem.size == 16) ("dqword ptr")
#elif ($e._mem.size == 32) ("qqword ptr")
#else ("ptr"),
#if ($e._mem.segment == 0) (" es:")
#elif ($e._mem.segment == 1) (" cs:")
#elif ($e._mem.segment == 2) (" ss:")
#elif ($e._mem.segment == 3) (" ds:")
#elif ($e._mem.segment == 4) (" fs:")
#elif ($e._mem.segment == 5) (" gs:")
#else (""),
"[",
#if ($e._mem.id == asmjit::kInvalidValue) (
#(
#if ($e._mem.type == asmjit::kMemTypeBaseIndex) (
#if ((sizeof(uintptr_t) == 4) && ($e._mem.sizePrefix == 1)) (
#if (($e._mem.base & 0xFF) == 0x0) ("ax")
#elif (($e._mem.base & 0xFF) == 0x1) ("cx")
#elif (($e._mem.base & 0xFF) == 0x2) ("dx")
#elif (($e._mem.base & 0xFF) == 0x3) ("bx")
#elif (($e._mem.base & 0xFF) == 0x4) ("sp")
#elif (($e._mem.base & 0xFF) == 0x5) ("bp")
#elif (($e._mem.base & 0xFF) == 0x6) ("si")
#elif (($e._mem.base & 0xFF) == 0x7) ("di")
#elif (($e._mem.base & 0xFF) == 0x8) ("r8w")
#elif (($e._mem.base & 0xFF) == 0x9) ("r9w")
#elif (($e._mem.base & 0xFF) == 0xA) ("r10w")
#elif (($e._mem.base & 0xFF) == 0xB) ("r11w")
#elif (($e._mem.base & 0xFF) == 0xC) ("r12w")
#elif (($e._mem.base & 0xFF) == 0xD) ("r13w")
#elif (($e._mem.base & 0xFF) == 0xE) ("r14w")
#elif (($e._mem.base & 0xFF) == 0xF) ("r15w")
#else ("INVALID")
)
#elif ((sizeof(uintptr_t) == 4) || ($e._mem.sizePrefix == 1)) (
#if (($e._mem.base & 0xFF) == 0x0) ("eax")
#elif (($e._mem.base & 0xFF) == 0x1) ("ecx")
#elif (($e._mem.base & 0xFF) == 0x2) ("edx")
#elif (($e._mem.base & 0xFF) == 0x3) ("ebx")
#elif (($e._mem.base & 0xFF) == 0x4) ("esp")
#elif (($e._mem.base & 0xFF) == 0x5) ("ebp")
#elif (($e._mem.base & 0xFF) == 0x6) ("esi")
#elif (($e._mem.base & 0xFF) == 0x7) ("edi")
#elif (($e._mem.base & 0xFF) == 0x8) ("r8d")
#elif (($e._mem.base & 0xFF) == 0x9) ("r9d")
#elif (($e._mem.base & 0xFF) == 0xA) ("r10d")
#elif (($e._mem.base & 0xFF) == 0xB) ("r11d")
#elif (($e._mem.base & 0xFF) == 0xC) ("r12d")
#elif (($e._mem.base & 0xFF) == 0xD) ("r13d")
#elif (($e._mem.base & 0xFF) == 0xE) ("r14d")
#elif (($e._mem.base & 0xFF) == 0xF) ("r15d")
#else ("INVALID")
)
#else (
#if (($e._mem.base & 0xFF) == 0x0) ("rax")
#elif (($e._mem.base & 0xFF) == 0x1) ("rcx")
#elif (($e._mem.base & 0xFF) == 0x2) ("rdx")
#elif (($e._mem.base & 0xFF) == 0x3) ("rbx")
#elif (($e._mem.base & 0xFF) == 0x4) ("rsp")
#elif (($e._mem.base & 0xFF) == 0x5) ("rbp")
#elif (($e._mem.base & 0xFF) == 0x6) ("rsi")
#elif (($e._mem.base & 0xFF) == 0x7) ("rdi")
#elif (($e._mem.base & 0xFF) == 0x8) ("r8")
#elif (($e._mem.base & 0xFF) == 0x9) ("r9")
#elif (($e._mem.base & 0xFF) == 0xA) ("r10")
#elif (($e._mem.base & 0xFF) == 0xB) ("r11")
#elif (($e._mem.base & 0xFF) == 0xC) ("r12")
#elif (($e._mem.base & 0xFF) == 0xD) ("r13")
#elif (($e._mem.base & 0xFF) == 0xE) ("r14")
#elif (($e._mem.base & 0xFF) == 0xF) ("r15")
#else ("INVALID")
)
)
#elif ($e._mem.type == asmjit::kMemTypeLabel) (
#(
"L.",
#if ($e._mem.base != asmjit::kInvalidValue) (
[$e._mem.base & 0x3FFFFFFF, x]
)
#else (
"INVALID"
)
)
)
#else (
[$e._mem.target]
)
)
)
#else (
#("{id=", [$e._mem.id, x], "}")
),
#if ($e._mem.index != asmjit::kInvalidValue) (
#(
" + ",
#if ((sizeof(uintptr_t) == 4) && ($e._mem.sizePrefix == 1)) (
#if (($e._mem.index & 0xFF) == 0x0) ("ax")
#elif (($e._mem.index & 0xFF) == 0x1) ("cx")
#elif (($e._mem.index & 0xFF) == 0x2) ("dx")
#elif (($e._mem.index & 0xFF) == 0x3) ("bx")
#elif (($e._mem.index & 0xFF) == 0x4) ("sp")
#elif (($e._mem.index & 0xFF) == 0x5) ("bp")
#elif (($e._mem.index & 0xFF) == 0x6) ("si")
#elif (($e._mem.index & 0xFF) == 0x7) ("di")
#elif (($e._mem.index & 0xFF) == 0x8) ("r8w")
#elif (($e._mem.index & 0xFF) == 0x9) ("r9w")
#elif (($e._mem.index & 0xFF) == 0xA) ("r10w")
#elif (($e._mem.index & 0xFF) == 0xB) ("r11w")
#elif (($e._mem.index & 0xFF) == 0xC) ("r12w")
#elif (($e._mem.index & 0xFF) == 0xD) ("r13w")
#elif (($e._mem.index & 0xFF) == 0xE) ("r14w")
#elif (($e._mem.index & 0xFF) == 0xF) ("r15w")
#else ("INVALID")
)
#elif ((sizeof(uintptr_t) == 4) || ($e._mem.sizePrefix == 1)) (
#if (($e._mem.index & 0xFF) == 0x0) ("eax")
#elif (($e._mem.index & 0xFF) == 0x1) ("ecx")
#elif (($e._mem.index & 0xFF) == 0x2) ("edx")
#elif (($e._mem.index & 0xFF) == 0x3) ("ebx")
#elif (($e._mem.index & 0xFF) == 0x4) ("esp")
#elif (($e._mem.index & 0xFF) == 0x5) ("ebp")
#elif (($e._mem.index & 0xFF) == 0x6) ("esi")
#elif (($e._mem.index & 0xFF) == 0x7) ("edi")
#elif (($e._mem.index & 0xFF) == 0x8) ("r8d")
#elif (($e._mem.index & 0xFF) == 0x9) ("r9d")
#elif (($e._mem.index & 0xFF) == 0xA) ("r10d")
#elif (($e._mem.index & 0xFF) == 0xB) ("r11d")
#elif (($e._mem.index & 0xFF) == 0xC) ("r12d")
#elif (($e._mem.index & 0xFF) == 0xD) ("r13d")
#elif (($e._mem.index & 0xFF) == 0xE) ("r14d")
#elif (($e._mem.index & 0xFF) == 0xF) ("r15d")
#else ("INVALID")
)
#else (
#if (($e._mem.index & 0xFF) == 0x0) ("rax")
#elif (($e._mem.index & 0xFF) == 0x1) ("rcx")
#elif (($e._mem.index & 0xFF) == 0x2) ("rdx")
#elif (($e._mem.index & 0xFF) == 0x3) ("rbx")
#elif (($e._mem.index & 0xFF) == 0x4) ("rsp")
#elif (($e._mem.index & 0xFF) == 0x5) ("rbp")
#elif (($e._mem.index & 0xFF) == 0x6) ("rsi")
#elif (($e._mem.index & 0xFF) == 0x7) ("rdi")
#elif (($e._mem.index & 0xFF) == 0x8) ("r8")
#elif (($e._mem.index & 0xFF) == 0x9) ("r9")
#elif (($e._mem.index & 0xFF) == 0xA) ("r10")
#elif (($e._mem.index & 0xFF) == 0xB) ("r11")
#elif (($e._mem.index & 0xFF) == 0xC) ("r12")
#elif (($e._mem.index & 0xFF) == 0xD) ("r13")
#elif (($e._mem.index & 0xFF) == 0xE) ("r14")
#elif (($e._mem.index & 0xFF) == 0xF) ("r15")
#else ("INVALID")
),
#if ($e._mem.shift == 1) (" * 2")
#elif ($e._mem.shift == 2) (" * 4")
#elif ($e._mem.shift == 3) (" * 8")
#else ("")
)
),
#if (($e._mem.type != asmjit::kMemTypeAbsolute) && ($e._mem.displacement != 0)) (
#if ($e._mem.displacement < 0) (
#(" - ", [-$e._mem.displacement, i])
)
#else (
#(" + ", [$e._mem.displacement, i])
)
),
"]"
)
)
children(
#(
#([...]: [$c,!]),
#(op: [$e._mem.op, x]),
#(size: [$e._mem.size, u]),
#(type: [$e._mem.type, u]),
#(segment: [$e._mem.segment, u]),
#(sizePrefix: [$e._mem.sizePrefix, u]),
#(shift: [$e._mem.shift, u]),
#(id: [$e._mem.id, x]),
#(base: [$e._mem.base, u]),
#(index: [$e._mem.index, u]),
#(target: [$e._mem.target]),
#(displacement: [$e._mem.displacement, i])
)
)
}
asmjit::Imm {
preview(
#(
"i=", [(int64_t)$e._imm.value, i],
" ",
"u=", [(uint64_t)$e._imm.value, u],
" ",
"x=", [(uint64_t)$e._imm.value, x]
)
)
children(
#(
#([...]: [$c,!]),
#(op: [$e._imm.op, x]),
#(size: [$e._imm.size, u]),
#(value_s: [(int64_t)$e._imm.value, i]),
#(value_u: [(uint64_t)$e._imm.value, u]),
#(value_x: [(uint64_t)$e._imm.value, x])
)
)
}
asmjit::Label {
preview(
#(
"L_",
#if ($e._label.id != asmjit::kInvalidValue) (
[$e._label.id, x]
)
#else (
"INVALID"
),
""
)
)
children(
#(
#([...]: [$c,!]),
#(op: [$e._label.op, x]),
#(size: [$e._label.size, u]),
#(id: [$e._label.id, x])
)
)
}
; =============================================================================
; [asmjit::x86x64 - RegMask]
; =============================================================================
asmjit::x86x64::RegMask {
preview(
#(
#if (($e._gp | $e._fp | $e._mm | $e._xy) != 0) (
#(
#if ($e._gp != 0) (
#(
"gp=", [$e._gp, x],
#if ($e._gp & 0x0001) ("|rax"),
#if ($e._gp & 0x0002) ("|rcx"),
#if ($e._gp & 0x0004) ("|rdx"),
#if ($e._gp & 0x0008) ("|rbx"),
#if ($e._gp & 0x0010) ("|rsp"),
#if ($e._gp & 0x0020) ("|rbp"),
#if ($e._gp & 0x0040) ("|rsi"),
#if ($e._gp & 0x0080) ("|rdi"),
#if ($e._gp & 0x0100) ("|r8"),
#if ($e._gp & 0x0200) ("|r9"),
#if ($e._gp & 0x0400) ("|r10"),
#if ($e._gp & 0x0800) ("|r11"),
#if ($e._gp & 0x1000) ("|r12"),
#if ($e._gp & 0x2000) ("|r13"),
#if ($e._gp & 0x4000) ("|r14"),
#if ($e._gp & 0x8000) ("|r15"),
#if (($e._fp | $e._mm | $e._xy) != 0) (" ")
)
),
#if ($e._fp != 0) (
#(
"fp=", [$e._fp, x],
#if ($e._fp & 0x0001) ("|fp0"),
#if ($e._fp & 0x0002) ("|fp1"),
#if ($e._fp & 0x0004) ("|fp2"),
#if ($e._fp & 0x0008) ("|fp3"),
#if ($e._fp & 0x0010) ("|fp4"),
#if ($e._fp & 0x0020) ("|fp5"),
#if ($e._fp & 0x0040) ("|fp6"),
#if ($e._fp & 0x0080) ("|fp7"),
#if (($e._mm | $e._xy) != 0) (" ")
)
),
#if ($e._mm != 0) (
#(
"mm=", [$e._mm, x],
#if ($e._mm & 0x0001) ("|mm0"),
#if ($e._mm & 0x0002) ("|mm1"),
#if ($e._mm & 0x0004) ("|mm2"),
#if ($e._mm & 0x0008) ("|mm3"),
#if ($e._mm & 0x0010) ("|mm4"),
#if ($e._mm & 0x0020) ("|mm5"),
#if ($e._mm & 0x0040) ("|mm6"),
#if ($e._mm & 0x0080) ("|mm7"),
#if ($e._xy != 0) (" ")
)
),
#if ($e._xy != 0) (
#(
"xy=", [$e._xy, x],
#if ($e._xy & 0x0001) ("|xy0"),
#if ($e._xy & 0x0002) ("|xy1"),
#if ($e._xy & 0x0004) ("|xy2"),
#if ($e._xy & 0x0008) ("|xy3"),
#if ($e._xy & 0x0010) ("|xy4"),
#if ($e._xy & 0x0020) ("|xy5"),
#if ($e._xy & 0x0040) ("|xy6"),
#if ($e._xy & 0x0080) ("|xy7"),
#if ($e._xy & 0x0100) ("|xy8"),
#if ($e._xy & 0x0200) ("|xy9"),
#if ($e._xy & 0x0400) ("|xy10"),
#if ($e._xy & 0x0800) ("|xy11"),
#if ($e._xy & 0x1000) ("|xy12"),
#if ($e._xy & 0x2000) ("|xy13"),
#if ($e._xy & 0x4000) ("|xy14"),
#if ($e._xy & 0x8000) ("|xy15")
)
)
)
)
#else (
"empty"
)
)
)
children(
#(
#([...]: [$c,!]),
#(gp: [$e._gp, x]),
#(fp: [$e._fp, x]),
#(mm: [$e._mm, x]),
#(xy: [$e._xy, x])
)
)
}
; =============================================================================
; [asmjit::x86x64 - Var]
; =============================================================================
asmjit::BaseVarAttr|asmjit::x86x64::VarAttr {
preview(
#(
"VarAttr(",
#if ($e._vd != NULL) (
#(
"id=",
[$e._vd->_id, x],
" ",
#if (($e._vd->_contextId) != asmjit::kInvalidValue) (
#("cid=", [($e._vd->_contextId), u], " ")
),
#if (($e._vd->_name) != NULL) (
#("name=", [($e._vd->_name), s], " ")
),
"state=",
#if ($e._vd->_state == asmjit::kVarStateUnused) ("unused")
#elif ($e._vd->_state == asmjit::kVarStateReg) (#("reg|", [$e._vd->_regIndex, u]))
#elif ($e._vd->_state == asmjit::kVarStateMem) ("mem")
#else ("INVALID"),
" ",
#if (($e._flags & (asmjit::kVarAttrInReg | asmjit::kVarAttrInMem | asmjit::kVarAttrInDecide | asmjit::kVarAttrInConv | asmjit::kVarAttrInCall | asmjit::kVarAttrInArg)) != 0) (
#(
"in[",
#if (($e._flags & asmjit::kVarAttrInReg) != 0) ("reg "),
#if (($e._flags & asmjit::kVarAttrInMem) != 0) ("mem "),
#if (($e._flags & asmjit::kVarAttrInDecide) != 0) ("decide "),
#if (($e._flags & asmjit::kVarAttrInConv) != 0) ("conv "),
#if (($e._flags & asmjit::kVarAttrInCall) != 0) ("call "),
#if (($e._flags & asmjit::kVarAttrInArg) != 0) ("arg "),
"] "
)
),
#if (($e._flags & (asmjit::kVarAttrOutReg | asmjit::kVarAttrOutMem | asmjit::kVarAttrOutDecide | asmjit::kVarAttrOutConv | asmjit::kVarAttrOutRet)) != 0) (
#(
"out[",
#if (($e._flags & asmjit::kVarAttrOutReg) != 0) ("reg "),
#if (($e._flags & asmjit::kVarAttrOutMem) != 0) ("mem "),
#if (($e._flags & asmjit::kVarAttrOutDecide) != 0) ("decide "),
#if (($e._flags & asmjit::kVarAttrOutConv) != 0) ("conv "),
#if (($e._flags & asmjit::kVarAttrOutRet) != 0) ("ret "),
"] "
)
),
#if (($e._flags & asmjit::kVarAttrUnuse) == asmjit::kVarAttrUnuse) ("unuse ")
)
)
#else (
"INVALID "
),
")"
)
)
children(
#(
#([...]: [$c,!]),
#(vd: [(asmjit::x86x64::VarData*)$e._vd]),
#(flags: [$e._flags, x]),
#(varCount: [$e._varCount, u]),
#(argCount: [$e._argCount, u]),
#(inRegIndex: [$e._inRegIndex, u]),
#(outRegIndex: [$e._outRegIndex, u]),
#(inRegs: [$e._inRegs, x]),
#(allocableRegs: [$e._allocableRegs, x])
)
)
}
asmjit::BaseVarInst|asmjit::x86x64::VarInst {
children(
#(
#([...]: [$c,!]),
#(inRegs: [$e._inRegs]),
#(outRegs: [$e._outRegs]),
#(clobberedRegs: [$e._clobberedRegs]),
#(start: [$e._start]),
#(count: [$e._count]),
#(vaCount: [$e._vaCount, u]),
#array(
expr: $e._list[$i],
size: $e._vaCount
)
)
)
}
; =============================================================================
; [asmjit::X86 - Compiler - BaseNode]
; =============================================================================
asmjit::BaseNode|asmjit::AlignNode|asmjit::EmbedNode|asmjit::CommentNode|asmjit::HintNode|asmjit::TargetNode|asmjit::InstNode|asmjit::JumpNode::asmjit::FuncNode|asmjit::EndNode|asmjit::RetNode|asmjit::x86x64::X86X64FuncNode|asmjit::x86x64::X86X64CallNode|asmjit::SArgNode {
preview(
#(
#if ($e._type == asmjit::kNodeTypeAlign) ("AlignNode")
#elif ($e._type == asmjit::kNodeTypeEmbed) ("EmbedNode")
#elif ($e._type == asmjit::kNodeTypeComment) ("CommentNode")
#elif ($e._type == asmjit::kNodeTypeHint) ("HintNode")
#elif ($e._type == asmjit::kNodeTypeTarget) ("TargetNode")
#elif ($e._type == asmjit::kNodeTypeInst) ("InstNode")
#elif ($e._type == asmjit::kNodeTypeFunc) ("FuncNode")
#elif ($e._type == asmjit::kNodeTypeEnd) ("EndNode")
#elif ($e._type == asmjit::kNodeTypeRet) ("RetNode")
#elif ($e._type == asmjit::kNodeTypeCall) ("CallNode")
#elif ($e._type == asmjit::kNodeTypeSArg) ("SArgNode")
#else ("BaseNode"),
"(",
#if (($e._liveness) != NULL) ("analyzed "),
#if (($e._flags & asmjit::kNodeFlagIsTranslated) != 0) ("translated "),
#if (($e._flags & asmjit::kNodeFlagIsJmp) != 0) ("jmp "),
#if (($e._flags & asmjit::kNodeFlagIsJcc) != 0) ("jcc "),
#if (($e._flags & asmjit::kNodeFlagIsTaken) != 0) ("taken "),
#if (($e._flags & asmjit::kNodeFlagIsRet) != 0) ("ret "),
")"
)
)
children(
#(
#([...]: [$c,!]),
#(prev: [$e._prev]),
#(next: [$e._next]),
#(type: [$e._type]),
#(flags: [$e._flags]),
#(flowId: [$e._flowId]),
#(comment: [$e._comment]),
#(varInst: [( (asmjit::x86x64::VarInst*)($e._varInst) )]),
#(liveness: [( (asmjit::VarBits*)($e._liveness) )]),
#(state: [( (asmjit::x86x64::VarState*)($e._state) )]),
#if ($e._type == asmjit::kNodeTypeAlign) (
#(
#(size : [( ((asmjit::AlignNode*)&$e)->_size )])
)
)
#elif (($e._type == asmjit::kNodeTypeEmbed) && (($e._packedData.embed.size) <= (sizeof(uintptr_t)))) (
#(
#(size : [( ((asmjit::EmbedNode*)&$e)->_size )]),
#(data : [( ((asmjit::EmbedNode*)&$e)->_data.buf )])
)
)
#elif (($e._type == asmjit::kNodeTypeEmbed) && (($e._packedData.embed.size) > (sizeof(uintptr_t)))) (
#(
#(size : [( ((asmjit::EmbedNode*)&$e)->_size )]),
#(data : [( ((asmjit::EmbedNode*)&$e)->_data.ptr )])
)
)
#elif ($e._type == asmjit::kNodeTypeHint) (
#(
#(var : [( (asmjit::x86x64::VarData*) (((asmjit::HintNode*)&$e)->_var) )]),
#(hint : [( ((asmjit::HintNode*)&$e)->_hint )]),
#(value : [( ((asmjit::HintNode*)&$e)->_value )])
)
)
#elif ($e._type == asmjit::kNodeTypeTarget) (
#(
#(label : [( ((asmjit::TargetNode*)&$e)->_label )]),
#(from : [( ((asmjit::TargetNode*)&$e)->_from )]),
#(numRefs: [( ((asmjit::TargetNode*)&$e)->_numRefs )])
)
)
#elif ($e._type == asmjit::kNodeTypeInst) (
#(
#(opCount: [( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opCount )]),
#array(
expr: ( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opList[$i] ),
size: ( ((asmjit::x86x64::X86X64InstNode*)&$e)->_opCount )
)
)
)
#elif ($e._type == asmjit::kNodeTypeFunc) (
#(
#(entryTarget : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_entryTarget )]),
#(exitTarget : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_exitTarget )]),
#(decl : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_x86Decl )]),
#(end : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_end )]),
#(argList : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_argList )]),
#(funcHints : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_funcHints )]),
#(funcFlags : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_funcFlags )]),
#(expectedStackAlignment: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_expectedStackAlignment )]),
#(requiredStackAlignment: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_requiredStackAlignment )]),
#(redZoneSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_redZoneSize )]),
#(spillZoneSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_spillZoneSize )]),
#(argStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_argStackSize )]),
#(memStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_memStackSize )]),
#(callStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_callStackSize )]),
; X86.
#(saveRestoreRegs : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_saveRestoreRegs )]),
#(alignStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_alignStackSize )]),
#(alignedMemStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_alignedMemStackSize )]),
#(pushPopStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_pushPopStackSize )]),
#(moveStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_moveStackSize )]),
#(extraStackSize : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_extraStackSize )]),
#(stackFrameRegIndex : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_stackFrameRegIndex )]),
#(stackFrameRegPreserved: [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_isStackFrameRegPreserved )]),
#(stackFrameCopyGpIndex : [( ((asmjit::x86x64::X86X64FuncNode*)&$e)->_stackFrameCopyGpIndex )])
)
)
)
)
}

View File

@@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_xcode"
mkdir ../${ASMJIT_BUILD_DIR} mkdir ../${ASMJIT_BUILD_DIR}
cd ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR}
cmake .. -G"Xcode" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Xcode" -DASMJIT_BUILD_TEST=1
cd ${ASMJIT_CURRENT_DIR} cd ${ASMJIT_CURRENT_DIR}

View File

@@ -5,5 +5,5 @@ ASMJIT_BUILD_DIR="build_makefiles_rel"
mkdir ../${ASMJIT_BUILD_DIR} mkdir ../${ASMJIT_BUILD_DIR}
cd ../${ASMJIT_BUILD_DIR} cd ../${ASMJIT_BUILD_DIR}
cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1
cd ${ASMJIT_CURRENT_DIR} cd ${ASMJIT_CURRENT_DIR}

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_dbg"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_mingw_rel"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -1,9 +0,0 @@
@echo off
set ASMJIT_CURRENT_DIR=%CD%
set ASMJIT_BUILD_DIR="build_vs2005_x64"
mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 8 2005 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR%

View File

@@ -1,9 +0,0 @@
@echo off
set ASMJIT_CURRENT_DIR=%CD%
set ASMJIT_BUILD_DIR="build_vs2005_x86"
mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 8 2005" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR%

View File

@@ -1,9 +0,0 @@
@echo off
set ASMJIT_CURRENT_DIR=%CD%
set ASMJIT_BUILD_DIR="build_vs2008_x64"
mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 9 2008 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR%

View File

@@ -1,9 +0,0 @@
@echo off
set ASMJIT_CURRENT_DIR=%CD%
set ASMJIT_BUILD_DIR="build_vs2008_x86"
mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 9 2008" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 10 Win64" -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2010_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 10" -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x64"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 12 Win64" -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -5,5 +5,5 @@ set ASMJIT_BUILD_DIR="build_vs2013_x86"
mkdir ..\%ASMJIT_BUILD_DIR% mkdir ..\%ASMJIT_BUILD_DIR%
cd ..\%ASMJIT_BUILD_DIR% cd ..\%ASMJIT_BUILD_DIR%
cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 cmake .. -G"Visual Studio 12" -DASMJIT_BUILD_TEST=1
cd %ASMJIT_CURRENT_DIR% cd %ASMJIT_CURRENT_DIR%

View File

@@ -16,8 +16,7 @@ var hasOwn = Object.prototype.hasOwnProperty;
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
function upFirst(s) { function upFirst(s) {
if (!s) if (!s) return "";
return s;
return s[0].toUpperCase() + s.substr(1); return s[0].toUpperCase() + s.substr(1);
} }
@@ -167,7 +166,7 @@ IndexedString.prototype.index = function() {
IndexedString.prototype.format = function(indent) { IndexedString.prototype.format = function(indent) {
if (this.size === -1) if (this.size === -1)
throw new Error("IndexedString not indexed yet, call index()"); throw new Error("IndexedString - not indexed yet, call index()");
var s = ""; var s = "";
var array = this.array; var array = this.array;
@@ -183,16 +182,16 @@ IndexedString.prototype.format = function(indent) {
IndexedString.prototype.getSize = function() { IndexedString.prototype.getSize = function() {
if (this.size === -1) if (this.size === -1)
throw new Error("IndexedString not indexed yet, call index()"); throw new Error("IndexedString - not indexed yet, call index()");
return this.size; return this.size;
}; };
IndexedString.prototype.getIndex = function(k) { IndexedString.prototype.getIndex = function(k) {
if (this.size === -1) if (this.size === -1)
throw new Error("IndexedString not indexed yet, call index()"); throw new Error("IndexedString - not indexed yet, call index()");
if (!hasOwn.call(this.map, k)) if (!hasOwn.call(this.map, k))
throw new Error("Key '" + k + "' not found in IndexedString."); throw new Error("IndexedString - key '" + k + "' not found.");
return this.map[k]; return this.map[k];
}; };

View File

@@ -1,293 +0,0 @@
var assert = require("assert");
var fs = require("fs");
var path = require("path");
/**
* List all files that can be processed by sanitizer in the given directory.
*/
var filesToSanitize = (function() {
var listPrivate = function(array, dir, displayDir, accept) {
var files = fs.readdirSync(dir);
var subarray = [];
for (var i = 0; i < files.length; i++) {
var baseName = files[i];
var fullName = path.normalize(path.join(dir, baseName));
var stat = fs.lstatSync(fullName);
if (stat.isSymbolicLink()) {
continue;
}
if (stat.isDirectory()) {
subarray = listPrivate(subarray,
path.join(dir, baseName), displayDir ? displayDir + "/" + baseName : baseName, accept);
continue;
}
if (stat.isFile()) {
if (accept(baseName))
array.push({ name: fullName, display: displayDir ? displayDir + "/" + baseName : baseName });
continue;
}
}
return array.concat(subarray);
};
return function(dir, accept) {
return listPrivate([], dir, "", accept);
};
})();
/**
* Inject data into string.
*/
var inject = function(s, start, end, what) {
assert(start <= s.length);
assert(end <= s.length);
return s.substr(0, start) + what + s.substr(end);
};
/**
* Is the extension c++ header file?
*/
var isCppHeaderExt = function(ext) {
return ext === ".h" ||
ext === ".hh" ||
ext === ".hpp" ||
ext === ".hxx" ;
};
/**
* Is the extension c++ source file?
*/
var isCppSourceExt = function(ext) {
return ext === ".c" ||
ext === ".cc" ||
ext === ".cpp" ||
ext === ".cxx" ;
};
/**
* Filter that returns true if the given file name should be processed.
*/
var filesToAccept = function(name) {
var ext = path.extname(name).toLowerCase();
return isCppHeaderExt(ext) ||
isCppSourceExt(ext) ||
ext === ".cmake" ||
ext === ".m" ||
ext === ".md" ||
ext === ".mm" ;
};
/**
* Sanity spaces.
*/
var sanitySpaces = function(data, name) {
// Remove carriage return.
data = data.replace(/\r\n/g, "\n");
// Remove spaces before the end of the line.
data = data.replace(/[ \t]+\n/g, "\n");
// Convert tabs to spaces.
data = data.replace(/\t/g, " ");
return data;
};
/**
* Sanity header guards.
*/
var sanityHeaderGuards = (function() {
var parseGuardName = function(data, i) {
var m = data.substr(i).match(/[\w][\d\w]*/);
return m ? m[0] : null;
};
var makeGuardName = function(name) {
// Remove leading '/' or '\'.
if (/^[\\\/]/.test(name))
name = name.substr(1);
return "_" + name.toUpperCase().replace(/[\/\\\.-]/g, "_");
};
var directiveMarks = [
"#ifndef ",
"#endif // ",
"#define "
];
var directiveNames = [
"#ifndef ",
"#endif ",
"#define "
];
return function(data, name) {
var i = 0;
var nl = true;
var guard = "// " + "[Guard]" + "\n";
var nFound = 0;
while (i < data.length) {
if (nl && data.substr(i, guard.length) === guard) {
i += guard.length;
nFound++;
if (i >= data.length)
break;
for (var j = 0; j < directiveMarks.length; ) {
var m = directiveMarks[j];
if (data.substr(i, m.length) === m && data.charAt(i + m.length) === '_') {
i += directiveMarks[j].length;
var oldGuardName = parseGuardName(data, i);
var newGuardName;
if (oldGuardName) {
var startPosition = i;
var endPosition = i + oldGuardName.length;
newGuardName = makeGuardName(name);
if (oldGuardName !== newGuardName) {
console.log(name + ": " + directiveNames[j] + newGuardName);
data = inject(data, startPosition, endPosition, newGuardName);
i += newGuardName.length;
i = data.indexOf('\n', i);
if (i === -1) {
// Terminates the loop.
i = data.length;
j = 9999;
nl = false;
break;
}
else {
i++;
}
}
}
j += 2;
}
// Don't process '#define' directive if previous '#ifndef' wasn't matched.
else {
if (++j == 2)
break;
}
}
}
else {
nl = data.charAt(i) === '\n';
i++;
}
}
if (nFound & 1) {
console.log(name + ": Odd number of guards found: " + nFound);
}
return data;
};
})();
/**
* Sanity #include order.
*/
var sanityIncludeOrder = function(data, name, directive) {
var i = 0;
var nl = true;
var startPosition = -1;
var endPosition = -1;
var list = null;
var replacement;
while (i < data.length) {
if (nl && data.substr(i, directive.length) === directive) {
var iLocal = i
if (startPosition === -1) {
startPosition = i;
list = [];
}
for (;;) {
if (++i >= data.length) {
list.push(data.substring(iLocal, i));
break;
}
if (data.charAt(i) === '\n') {
list.push(data.substring(iLocal, i));
i++;
break;
}
}
}
else if (startPosition !== -1) {
assert(nl === true);
endPosition = i;
if (list.length > 1) {
list.sort();
replacement = list.join("\n") + "\n";
assert(replacement.length == endPosition - startPosition);
data = inject(data, startPosition, endPosition, replacement);
}
startPosition = -1;
endPosition = -1;
list = null;
nl = false;
i++;
}
else {
nl = data.charAt(i) === '\n';
i++;
}
}
return data;
};
/**
* Sanity the given data of file.
*/
var sanity = function(data, name) {
var ext = path.extname(name).toLowerCase();
// Sanity spaces.
data = sanitySpaces(data, name);
// Fix C/C++ header guards and sort '#include' files.
if (isCppHeaderExt(ext)) {
data = sanityHeaderGuards(data, name);
data = sanityIncludeOrder(data, name, "#include");
}
return data;
};
/**
* Entry.
*/
var main = function(dir) {
filesToSanitize(dir, filesToAccept).forEach(function(file) {
var oldData = fs.readFileSync(file.name, "utf8");
var newData = sanity(oldData, file.display);
if (oldData !== newData) {
console.log(file.display + ": Writing...");
fs.writeFileSync(file.name, newData, "utf8");
}
});
};
main(path.join(__dirname, "../src"));