Changed asmjit namespaces, each architecture has now only one namespace for registers / memory operands.

Changed instruction table schema to minimize its size and added use of EFLAGS register (for scheduler).
Changed the rest of intrinsics accepting `void*` to accept `Ptr` instead.
Changed clear()/reset() concept - only `reset()` now exists and accepts a `releaseMemory` argument.
Changed unit tests to use bundled `Broken` framework.
Moved podvector and podlist to base/containers.
Added CMPS, LODS, MOVS, SCAS, STOS instructions.
Added Label::isInitialized() and Var::isInitialized().
Added X86Scheduler stub - preparing for instruction reordering.
Added support for tracing (see ASMJIT_TRACE) to allow consumers to find bugs in AsmJit quicker.
Fixed possible Zone memory leak.
Fixed and improved alloc/spill (added support for home register which asmjit honors from now).
Fixed Assembler `LEA REG, [LABEL]` bug.
Fixed [Mem, Imm] instructions with zero-sized operand to return error instead of emitting garbage.
Fixed minor bug in VMemMgr - always point to a correct hProcess so it can be used properly (#41).
This commit is contained in:
kobalicek
2014-07-12 17:50:35 +02:00
parent a66efd5460
commit fa955663e3
74 changed files with 21072 additions and 18503 deletions

View File

@@ -6,14 +6,33 @@ compiler:
before_install: before_install:
- sudo add-apt-repository ppa:kubuntu-ppa/backports -y - sudo add-apt-repository ppa:kubuntu-ppa/backports -y
- sudo apt-get update -qq - sudo apt-get -qq update
- sudo apt-get install -qq cmake - sudo apt-get -qq install cmake valgrind
before_script: before_script:
- mkdir build - mkdir build_dbg
- cd build - mkdir build_rel
- cd build_dbg
- cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1 - cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
- cd ..
- cd build_rel
- cmake .. -G"Unix Makefiles" -DCMAKE_BUILD_TYPE=Release -DASMJIT_BUILD_TEST=1 -DASMJIT_BUILD_SAMPLES=1
- cd ..
script: script:
- cd build_dbg
- make - make
- ./asmjit_test - cd ..
- cd build_rel
- make
- cd ..
- ./build_dbg/asmjit_test
- ./build_rel/asmjit_test
after_success:
- valgrind --leak-check=full --show-reachable=yes ./build_dbg/asmjit_test
- valgrind --leak-check=full --show-reachable=yes ./build_rel/asmjit_test

View File

@@ -82,7 +82,7 @@ Set(ASMJIT_CFLAGS_REL)
Set(ASMJIT_DEFINE "-D") Set(ASMJIT_DEFINE "-D")
# MSVC. # MSVC.
If(MSVC) If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
Message("-- Using MSVC") Message("-- Using MSVC")
Set(ASMJIT_DEFINE "/D") Set(ASMJIT_DEFINE "/D")
@@ -91,35 +91,46 @@ If(MSVC)
Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-) Set(ASMJIT_CFLAGS_DBG /DASMJIT_DEBUG /GS /GR-)
Set(ASMJIT_CFLAGS_REL /DASMJIT_RELEASE /Oi /Oy /GS- /GR-) Set(ASMJIT_CFLAGS_REL /DASMJIT_RELEASE /Oi /Oy /GS- /GR-)
# Use Unicode by default on Windows target.
If(WIN32)
List(APPEND ASMJIT_CFLAGS /D_UNICODE)
EndIf()
# Enable multi-process compilation. # Enable multi-process compilation.
If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71) If(NOT MSVC60 AND NOT MSVC70 AND NOT MSVC71)
List(APPEND ASMJIT_CFLAGS /MP) List(APPEND ASMJIT_CFLAGS /MP)
EndIf() EndIf()
EndIf() EndIf()
# GCC. # GCC
If(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
Message("-- Using GCC") Message("-- Using GCC")
Set(ASMJIT_CFLAGS Set(ASMJIT_CFLAGS
-fno-exceptions) -fno-exceptions)
Set(ASMJIT_CFLAGS_DBG -DASMJIT_DEBUG -O0 Set(ASMJIT_CFLAGS_DBG
-fno-inline-functions) -DASMJIT_DEBUG -O0)
Set(ASMJIT_CFLAGS_REL -DASMJIT_RELEASE -O2 Set(ASMJIT_CFLAGS_REL
-DASMJIT_RELEASE -O2
-finline-functions -finline-functions
-fomit-frame-pointer -fomit-frame-pointer
-fmerge-all-constants -fmerge-all-constants
-fno-keep-static-consts) -fno-keep-static-consts)
EndIf()
# Clang.
If("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
Message("-- Using Clang")
Set(ASMJIT_CFLAGS
-fno-exceptions)
Set(ASMJIT_CFLAGS_DBG
-DASMJIT_DEBUG -O0)
Set(ASMJIT_CFLAGS_REL
-DASMJIT_RELEASE -O2
-finline-functions
-fomit-frame-pointer
-fmerge-all-constants)
EndIf()
# Use Unicode by default on Windows target. # Use Unicode by default on Windows target.
If(WIN32) If(WIN32)
List(APPEND ASMJIT_CFLAGS -D_UNICODE) List(APPEND ASMJIT_CFLAGS "${ASMJIT_DEFINE}_UNICODE")
EndIf()
EndIf() EndIf()
# Static library. # Static library.
@@ -228,6 +239,8 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
compiler.h compiler.h
constpool.cpp constpool.cpp
constpool.h constpool.h
containers.cpp
containers.h
context.cpp context.cpp
context_p.h context_p.h
cpuinfo.cpp cpuinfo.cpp
@@ -236,8 +249,6 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
cputicks.h cputicks.h
error.cpp error.cpp
error.h error.h
func.cpp
func.h
globals.cpp globals.cpp
globals.h globals.h
intutil.cpp intutil.cpp
@@ -247,9 +258,6 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
logger.h logger.h
operand.cpp operand.cpp
operand.h operand.h
podlist.h
podvector.cpp
podvector.h
runtime.cpp runtime.cpp
runtime.h runtime.h
string.cpp string.cpp
@@ -270,16 +278,13 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/x86
x86context_p.h x86context_p.h
x86cpuinfo.cpp x86cpuinfo.cpp
x86cpuinfo.h x86cpuinfo.h
x86func.cpp
x86func.h
x86inst.cpp x86inst.cpp
x86inst.h x86inst.h
x86operand.cpp x86operand.cpp
x86operand_regs.cpp
x86operand.h x86operand.h
x86regs.cpp x86scheduler.cpp
x86regs.h x86scheduler_p.h
x86util.cpp
x86util.h
) )
If(ASMJIT_BUILD_CONTRIB) If(ASMJIT_BUILD_CONTRIB)
@@ -327,10 +332,7 @@ EndIf()
# AsmJit library is always embedded into the tests executable. This way it's # AsmJit library is always embedded into the tests executable. This way it's
# much easier to test private functions compared to just linking to AsmJit. # much easier to test private functions compared to just linking to AsmJit.
If(ASMJIT_BUILD_TEST) If(ASMJIT_BUILD_TEST)
AsmJit_AddSource(ASMJIT_TEST_SRC asmjit/test AsmJit_AddSource(ASMJIT_TEST_SRC asmjit/test broken.cpp broken.h main.cpp)
main.cpp
test.cpp
test.h)
Set(ASMJIT_TEST_CFLAGS Set(ASMJIT_TEST_CFLAGS
${ASMJIT_CFLAGS} ${ASMJIT_CFLAGS}

204
README.md
View File

@@ -1,25 +1,22 @@
AsmJit AsmJit
====== ------
Complete x86/x64 JIT and Remote Assembler for C++. Complete x86/x64 JIT and Remote Assembler for C++.
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=QDRM6SRNG7378&lc=EN;&item_name=asmjit&currency_code=EUR)
Official Repository Official Repository
------------------- -------------------
https://github.com/kobalicek/asmjit https://github.com/kobalicek/asmjit
Support the Project
-------------------
[![Donate](https://www.paypalobjects.com/en_US/i/btn/btn_donate_LG.gif)](
https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=QDRM6SRNG7378&lc=EN;&item_name=asmjit&currency_code=EUR)
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 a semantic checks at compile-time even before the assembled code is generated or run.
AsmJit is not a virtual machine nor tries to be. It's a general purpose tool that can be used to encode assembly 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 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.
Features Features
-------- --------
@@ -45,9 +42,11 @@ Supported Environments
### C++ Compilers ### C++ Compilers
* BorlandC++ * BorlandC++
* GNU (3.4.X+, 4.0+, MinGW) * Clang (Travis-CI)
* MSVC (VS2005+) * Gcc (Travis-CI)
* Other compilers require testing * MinGW
* MSVC
* Other compilers require testing and support in `asmjit/build.h` header
### Backends ### Backends
@@ -57,77 +56,85 @@ Supported Environments
Project Organization 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 the AsmJit and all backends
- contrib - Contributions that extends base functionality * `contrib` - Contributions that extends base functionality
- x86 - X86/X64 specific files, used only by X86/X64 backend * `test` - Unit testing support (don't include in your project)
- tools - Tools used for configuring, documenting and generating files * `x86` - X86/X64 specific files, used only by X86/X64 backend
* `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 relocation. 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.
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 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.
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 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 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.
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. 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 perfored, pure Assembler code generator is the preffered way.
Configuring & Building Configuring & Building
---------------------- ----------------------
AsmJit is designed to be easy embeddable in any project. However, it has some compile-time flags that can be used to build a specific version of AsmJit including or omitting certain features: AsmJit is designed to be easy embeddable in any kind project. However, it has some compile-time flags that can be used to build a specific version of AsmJit including or omitting certain features. A typical way to build AsmJit is to use [cmake](http://www.cmake.org), but it's also possible to just include AsmJit source code in our project and build it with it optionally editing its `asmjit/config.h` file to turn on/off some specific features. The most easies way to include AsmJit in your project is to just copy AsmJit source somewhere into it and to define globally `ASMJIT_STATIC` macro. This way AsmJit can be just updated from time to time without any changes to it. Please do not include / compile AsmJit test files (`asmjit/test` directory) when embedding.
### Library Type ### Build Type
* *ASMJIT_EMBED* - Parameter that can be set to cmake to turn off building library, useful if you want to include asmjit in your project without building the library. * `ASMJIT_EMBED` - Parameter that can be set to cmake to turn off building library, useful if you want to include asmjit in your project without building the library. `ASMJIT_EMBED` behaves identically as `ASMJIT_STATIC`.
* *ASMJIT_STATIC* - Define when building AsmJit as a static library. No symbols will be exported by AsmJit by default. * `ASMJIT_STATIC` - Define when building AsmJit as a static library. No symbols will be exported by AsmJit by default.
* *ASMJIT_API* - This is AsmJit API decorator that is used in all functions that has to be exported. It can be redefined, however it's not a recommended way.
* By default AsmJit build is configured as a shared library and *ASMJIT_API* contains compiler specific attributes to import/export AsmJit symbols.
### Backends * By default AsmJit build is configured as a shared library so none of `ASMJIT_EMBED` and `ASMJIT_STATIC` have to be defined explicitly.
* *ASMJIT_BUILD_X86* - Always build x86 backend regardless of host architecture.
* *ASMJIT_BUILD_X64* - Always build x64 backend regardless of host architecture.
* *ASMJIT_BUILD_HOST* - Always build host backand, if only *ASMJIT_BUILD_HOST* is used only the host architecture detected at compile-time will be included.
* By default only *ASMJIT_BUILD_HOST* is defined.
### Build Mode ### Build Mode
* *ASMJIT_DEBUG* - Define to always turn debugging on (regardless of build-mode). * `ASMJIT_DEBUG` - Define to always turn debugging on (regardless of build-mode).
* *ASMJIT_RELEASE* - Define to always turn debugging off (regardless of build-mode). * `ASMJIT_RELEASE` - Define to always turn debugging off (regardless of build-mode).
* `ASMJIT_TRACE` - Define to enable AsmJit tracing. Tracing is used to catch bugs in AsmJit and it has to be enabled explicitly. When AsmJit is compiled with `ASMJIT_TRACE` it uses `stdout` to log information related to AsmJit execution. This log can be helpful when examining liveness analysis, register allocation or any other part of AsmJit.
* By default none of these is defined, AsmJit detects mode based on compile-time macros (useful when using IDE that has switches for Debug/Release/etc...). * By default none of these is defined, AsmJit detects mode based on compile-time macros (useful when using IDE that has switches for Debug/Release/etc...).
To build AsmJit please use cmake <http://www.cmake.org> that will generate project files for your favorite IDE and platform. If you don't use cmake and you still want to include AsmJit in your project it's perfectly fine by just including it there, probably defining *ASMJIT_STATIC* to prevent AsmJit trying to export the API. ### Architectures
* `ASMJIT_BUILD_X86` - Always build x86 backend regardless of host architecture.
* `ASMJIT_BUILD_X64` - Always build x64 backend regardless of host architecture.
* `ASMJIT_BUILD_HOST` - Always build host backand, if only `ASMJIT_BUILD_HOST` is used only the host architecture detected at compile-time will be included.
* By default only `ASMJIT_BUILD_HOST` is defined.
### Features
* `ASMJIT_DISABLE_COMPILER` - Disable `Compiler` completely. Use this flag if you don't use Compiler and want 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 are not available.
* `ASMJIT_DISABLE_NAMES` = Disable everything that uses strings and that causes that certain strings are 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 test suite contains up-to-date tests that can be used as a starting point. Base concepts are discussed below. Most of the constructs will work in pure Assembler if variables are replaced by registers and functions prologs/epilogs hand coded. The Compiler is used just to make things simple and most of users prefer it anyway. To use AsmJit basic skills to setup your environment are required and not discussed here. 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 nested, for example x86 support is in `asmjit::x86`, x64 support is in `asmjit::x64` and shared x86/x64 in `asmjit::x86x64`. To make things simple AsmJit provides `asmjit::host` namespace which imports namespace of the detected host architecture automatically. Nested namespaces were introduced to enable support of multiple architectures in the future and to make JIT code generation a special case, not a mandatory requirement. To use AsmJit include only the main `asmjit.h` header usually in form `<asmjit/asmjit.h>`, don't include headers found in subdirectories.
### Runtime & Code-Generators ### Runtime & Code-Generators
AsmJit contains two classes that are required to generate machine code. Runtime specifies where the code is generated and acts as a storage, while Code-Generator specifies how the code is generated and acts as a machine code stream. All the examples here use `asmjit::host::Compiler` class to generate the code and 'asmjit::JitRuntime` to store and run it. AsmJit contains two classes that are required to generate a machine code. `Runtime` specifies where the code is generated and acts as a storage, while `CodeGen` specifies how the code is generated and acts as a machine code stream. All the examples here use `Compiler` code-generator to generate the code and `JitRuntime` to store and run it.
### Instruction Operands ### Instruction Operands
Operand is a part of CPU instruction which specifices the data the instruction will operate on. There are five types of operands in AsmJit: Operand is a part of CPU instruction which specifices the data the instruction will operate on. There are five types of operands in AsmJit:
* *Register* - Physical register (used only by Assember) * `Reg` - Physical register, used only by `Assember`
* *Variable* - Virtual register (used only by Compiler) * `Var` - Virtual register, used only by `Compiler`
* *Memory* - Location in memory * `Mem` - Used to reference memory location
* *Label* - Location in code * `Label` - Used to reference a location in code
* *Immediate* - Constant that is encoded with the instruction itself * `Imm` - Immediate value that is encoded with the instruction itself
Base class for all operands is `asmjit::Operand`, but it contains only interface that can be used by all of them. Operand is a statically allocated structure that acts lika a value, not a pointer - just copy if you need multiple instances of the same operand. Since the most of the operands are architecture dependent,AsmJit always contain a base-operand structure - for example `asmjit::BaseReg` or `asmjit::BaseMem` and their architecture specific counterparts `asmjit::x86x64::GpReg` or `asmjit::x86x64::Mem`. Base class for all operands is `Operand`. It contains interface that can be used by all types of operands only and it is typically pased by value, not as a pointer. The classes `Reg`, `Var`, `BaseMem`, `Label` and `Imm` all inherit `Operand` and provide an operand specific functionality. Architecture specific operands are prefixed by the architecture like `X86Reg` or `X86Mem`. Most of the architectures provide several types of registers, for example x86/x64 architecture has `X86GpReg`, `X86MmReg`, `X86FpReg`, `X86XmmReg` and `X86YmmReg` registers plus some extras including segment registers and `rip` (relative instruction pointer).
When using a code-generator some operands have to be created explicitly, for example use `newLabel()` to create a label and `newGpVar()` to create a virtual general purpose register. When using a code-generator some operands have to be created explicitly by using its interface. For example labels are created by using `newLabel()` method of the code-generator and variables are used by using architecture specific methods like `newGpVar()`, `newMmVar()` or `newXmmVar()`.
### Function Prototypes ### Function Prototypes
@@ -146,7 +153,7 @@ using namespace asmjit::host;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
// Create JitRuntime and host specific Compiler. // Create JitRuntime and host specific Compiler.
JitRuntime runtime; JitRuntime runtime;
Compiler c(&runtime); X86Compiler c(&runtime);
// 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. kFuncConvHost
@@ -156,8 +163,8 @@ int main(int argc, char* argv[]) {
// 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 names is purely optional and only greatly helps while
// debugging. // debugging.
GpVar a(c, kVarTypeInt32, "a"); X86GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b"); X86GpVar b(c, kVarTypeInt32, "b");
// 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, a);
@@ -215,7 +222,7 @@ The function starts with `c.addFunc()` and ends with `c.endFunc()`. It's not all
### Using Labels ### Using Labels
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()` member function 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>
@@ -225,15 +232,15 @@ using namespace asmjit::host;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
Compiler c(&runtime); X86Compiler c(&runtime);
// This function uses 3 arguments. // This function uses 3 arguments.
c.addFunc(kFuncConvHost, FuncBuilder3<int, int, int, int>()); c.addFunc(kFuncConvHost, FuncBuilder3<int, int, int, int>());
// New variable 'op' added. // New variable 'op' added.
GpVar op(c, kVarTypeInt32, "op"); X86GpVar op(c, kVarTypeInt32, "op");
GpVar a(c, kVarTypeInt32, "a"); X86GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b"); X86GpVar b(c, kVarTypeInt32, "b");
c.setArg(0, op); c.setArg(0, op);
c.setArg(1, a); c.setArg(1, a);
@@ -297,21 +304,21 @@ using namespace asmjit::host;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
Compiler c(&runtime); X86Compiler c(&runtime);
// 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(kFuncConvHost, FuncBuilder3<int, const int*, intptr_t, intptr_t>());
GpVar p(c, kVarTypeIntPtr, "p"); X86GpVar p(c, kVarTypeIntPtr, "p");
GpVar aIndex(c, kVarTypeIntPtr, "aIndex"); X86GpVar aIndex(c, kVarTypeIntPtr, "aIndex");
GpVar bIndex(c, kVarTypeIntPtr, "bIndex"); X86GpVar bIndex(c, kVarTypeIntPtr, "bIndex");
c.setArg(0, p); c.setArg(0, p);
c.setArg(1, aIndex); c.setArg(1, aIndex);
c.setArg(2, bIndex); c.setArg(2, bIndex);
GpVar a(c, kVarTypeInt32, "a"); X86GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b"); X86GpVar b(c, kVarTypeInt32, "b");
// Read 'a' by using a memory operand having base register, index register // Read 'a' 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 a, dword ptr [p + aIndex << 2]'.
@@ -354,7 +361,7 @@ int main(int argc, char* argv[]) {
### Using Stack ### Using Stack
AsmJit uses stack automatically to spill variables if there is not enough registers to keep them all allocated. Stack is allocated automatically by Compiler and it's not allowed to manipulate it directly. However, Compiler provides an interface to allocate chunks of memory of user specified size and alignment on the stack. AsmJit uses stack automatically to spill variables if there is not enough registers to keep them all allocated. The stack frame is managed by `Compiler` that provides also an interface to allocate chunks of memory of user specified size and alignment.
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.
@@ -366,16 +373,16 @@ using namespace asmjit::host;
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
JitRuntime runtime; JitRuntime runtime;
Compiler c(&runtime); X86Compiler c(&runtime);
// Function returning 'int' without any arguments. // Function returning 'int' without any arguments.
c.addFunc(kFuncConvHost, FuncBuilder0<int>()); c.addFunc(kFuncConvHost, FuncBuilder0<int>());
// Allocate a function stack of size 256 aligned to 4 bytes. // Allocate a function stack of size 256 aligned to 4 bytes.
Mem stack = c.newStack(256, 4); X86Mem stack = c.newStack(256, 4);
GpVar p(c, kVarTypeIntPtr, "p"); X86GpVar p(c, kVarTypeIntPtr, "p");
GpVar i(c, kVarTypeIntPtr, "i"); X86GpVar i(c, kVarTypeIntPtr, "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)
@@ -404,8 +411,8 @@ int main(int argc, char* argv[]) {
c.jb(L1); c.jb(L1);
// Second loop, sum all bytes stored in 'stack'. // Second loop, sum all bytes stored in 'stack'.
GpVar a(c, kVarTypeInt32, "a"); X86GpVar a(c, kVarTypeInt32, "a");
GpVar t(c, kVarTypeInt32, "t"); X86GpVar t(c, kVarTypeInt32, "t");
c.xor_(i, i); c.xor_(i, i);
c.xor_(a, a); c.xor_(a, a);
@@ -448,30 +455,71 @@ AsmJit offers much more, but not everything can fit into the introduction. The f
### Logging and Error Handling ### Logging and Error Handling
Failures are common when working at machine level. AsmJit does already a good job by using overloaded functions per instruction to prevent from emitting semantically incorrect code. However, AsmJit can't prevent you from emitting code that is semantically correct, but doesn't do what it it supposed to do. Logging has always been an important part of AsmJit's infrastructure and the output can be very valuable after something went wrong. Failures are common when working at machine level. AsmJit does already a good job with function overloading to prevent from emitting semantically incorrect instructions; however, AsmJit can't prevent from emitting code that is semantically correct, but contains bug(s). Logging has always been an important part of AsmJit's infrastructure and the output can be very valuable after something went wrong.
To be documented. AsmJit contains extensible logging interface defined by `Logger` class and implemented by `FileLogger` and `StringLogger`. `FileLogger` can log into a standard C-based `FILE*` stream while `StringLogger` logs to an internal buffer that can be used after the code generation is done.
Loggers can be assigned to any code generator and there is no restriction of assigning a single logger to multiple code generators, but this is not practical when running these in multiple threads. `FileLogger` is thread-safe since it uses plain C `FILE*` stream, but `StringLogger` is not!
The following snippet describes how to log into `FILE*`:
```C++
// Create logger logging to `stdout`. Logger life-time should always be
// greater than lifetime of the code generator.
FileLogger logger(stdout);
// Create a code generator and assign our logger into it.
X86Compiler c(...);
c.setLogger(&logger);
// ... Generate the code ...
```
The following snippet describes how to log into a string:
```C++
StringLogger logger;
// Create a code generator and assign our logger into it.
X86Compiler c(...);
c.setLogger(&logger);
// ... Generate the code ...
printf("Logger Content:\n%s", logger.getString());
// You can also use `logger.clearString()` if the logger
// instance will be reused.
```
Logger can be configured to show more information by using `logger.setOption()` method. The following options are available:
* `kLoggerOptionBinaryForm` - Log also binary sequence for each instruction generated.
* `kLoggerOptionHexImmediate` - Format immediate values to base16 (hex) form.
* `kLoggerOptionHexDisplacement` - Format memory displacements to base16 (hex) form.
TODO: Liveness analysis and instruction scheduling options.
### Code Injection ### Code Injection
Code injection was one of key concepts of Compiler from the beginning. Compiler records all emitted instructions in a double-linked list which can be manipulated before `make()` is called. Any call to Compiler that adds instruction, function or anything else in fact manipulates this list by inserting nodes into it. Code injection was one of key concepts of Compiler from the beginning. Compiler records all emitted instructions in a double-linked list which can be manipulated before `make()` is called. Any call to Compiler that adds instruction, function or anything else in fact manipulates this list by inserting nodes into it.
To manipulate the current cursor use Compiler's `getCursor()` and `setCursor()` member functions. 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++
Compiler c(...); X86Compiler c(...);
GpVar a(c, kVarTypeInt32, "a"); X86GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b"); X86GpVar b(c, kVarTypeInt32, "b");
BaseNode* here = c.getCursor(); Node* here = c.getCursor();
c.mov(b, 2); c.mov(b, 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 b, 2'. To inject
// anything it's good to remember the current cursor so it can be set back // anything it's good to remember the current cursor so it can be set back
// after the injecting is done. When setCursor() is called it returns the old // after the injecting is done. When setCursor() is called it returns the old
// cursor. // cursor.
BaseNode* oldCursor = c.setCursor(here); Node* oldCursor = c.setCursor(here);
c.mov(a, 1); c.mov(a, 1);
c.setCursor(oldCursor); c.setCursor(oldCursor);
``` ```

View File

@@ -53,17 +53,21 @@ struct Performance {
// [Main] // [Main]
// ============================================================================ // ============================================================================
static uint32_t instPerMs(uint32_t time, uint32_t numIterations, uint32_t instPerIteration) {
return static_cast<uint32_t>(
static_cast<uint64_t>(numIterations) * instPerIteration * 1000 / time);
}
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {
using namespace asmjit; using namespace asmjit;
using namespace asmjit::host;
Performance perf; Performance perf;
uint32_t kNumRepeats = 10; uint32_t kNumRepeats = 10;
uint32_t kNumIterations = 100000; uint32_t kNumIterations = 10000;
JitRuntime runtime; JitRuntime runtime;
Assembler a(&runtime); X86Assembler a(&runtime);
Compiler c(&runtime); X86Compiler c(&runtime);
uint32_t r, i; uint32_t r, i;
@@ -80,11 +84,13 @@ int main(int argc, char* argv[]) {
void *p = a.make(); void *p = a.make();
runtime.release(p); runtime.release(p);
a.clear(); a.reset();
} }
perf.end(); perf.end();
} }
printf("Opcode | Time: %u [ms]\n", perf.best);
printf("Opcode | Time: %-6u [ms] | Speed: %-9u [inst/s]\n",
perf.best, instPerMs(perf.best, kNumIterations, asmgen::kGenOpCodeInstCount));
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Bench - Blend] // [Bench - Blend]
@@ -99,11 +105,13 @@ int main(int argc, char* argv[]) {
void* p = c.make(); void* p = c.make();
runtime.release(p); runtime.release(p);
c.clear(); c.reset();
} }
perf.end(); perf.end();
} }
printf("Blend | Time: %u [ms]\n", perf.best);
printf("Blend | Time: %-6u [ms] | Speed: %-9u [inst/s]\n",
perf.best, instPerMs(perf.best, kNumIterations, asmgen::kGenBlendInstCount));
return 0; return 0;
} }

View File

@@ -13,29 +13,31 @@
namespace asmgen { namespace asmgen {
enum { kGenBlendInstCount = 65 };
// Generate a typical alpha blend function using SSE2 instruction set. Used // Generate a typical alpha blend function using SSE2 instruction set. Used
// for benchmarking and also in test86. The generated code should be stable // for benchmarking and also in test86. The generated code should be stable
// and fully functional. // and fully functional.
static void blend(asmjit::host::Compiler& c) { static void blend(asmjit::X86Compiler& c) {
using namespace asmjit; using namespace asmjit;
using namespace asmjit::host; using namespace asmjit::x86;
GpVar dst(c, kVarTypeIntPtr, "dst"); X86GpVar dst(c, kVarTypeIntPtr, "dst");
GpVar src(c, kVarTypeIntPtr, "src"); X86GpVar src(c, kVarTypeIntPtr, "src");
GpVar i(c, kVarTypeIntPtr, "i"); X86GpVar i(c, kVarTypeIntPtr, "i");
GpVar j(c, kVarTypeIntPtr, "j"); X86GpVar j(c, kVarTypeIntPtr, "j");
GpVar t(c, kVarTypeIntPtr, "t"); X86GpVar t(c, kVarTypeIntPtr, "t");
XmmVar cZero(c, kVarTypeXmm, "cZero"); X86XmmVar cZero(c, kX86VarTypeXmm, "cZero");
XmmVar cMul255A(c, kVarTypeXmm, "cMul255A"); X86XmmVar cMul255A(c, kX86VarTypeXmm, "cMul255A");
XmmVar cMul255M(c, kVarTypeXmm, "cMul255M"); X86XmmVar cMul255M(c, kX86VarTypeXmm, "cMul255M");
XmmVar x0(c, kVarTypeXmm, "x0"); X86XmmVar x0(c, kX86VarTypeXmm, "x0");
XmmVar x1(c, kVarTypeXmm, "x1"); X86XmmVar x1(c, kX86VarTypeXmm, "x1");
XmmVar y0(c, kVarTypeXmm, "y0"); X86XmmVar y0(c, kX86VarTypeXmm, "y0");
XmmVar a0(c, kVarTypeXmm, "a0"); X86XmmVar a0(c, kX86VarTypeXmm, "a0");
XmmVar a1(c, kVarTypeXmm, "a1"); X86XmmVar a1(c, kX86VarTypeXmm, "a1");
Label L_SmallLoop(c); Label L_SmallLoop(c);
Label L_SmallEnd(c); Label L_SmallEnd(c);
@@ -45,7 +47,7 @@ static void blend(asmjit::host::Compiler& c) {
Label L_Data(c); Label L_Data(c);
c.addFunc(kFuncConvHost, FuncBuilder3<FnVoid, void*, const void*, size_t>()); c.addFunc(kFuncConvHost, FuncBuilder3<Void, void*, const void*, size_t>());
c.setArg(0, dst); c.setArg(0, dst);
c.setArg(1, src); c.setArg(1, src);
@@ -168,8 +170,8 @@ static void blend(asmjit::host::Compiler& c) {
// Data. // Data.
c.align(kAlignData, 16); c.align(kAlignData, 16);
c.bind(L_Data); c.bind(L_Data);
c.dxmm(XmmData::fromSw(0x0080)); c.dxmm(Vec128::fromSw(0x0080));
c.dxmm(XmmData::fromSw(0x0101)); c.dxmm(Vec128::fromSw(0x0101));
} }
} // asmgen namespace } // asmgen namespace

View File

@@ -13,10 +13,21 @@
namespace asmgen { namespace asmgen {
enum { kGenOpCodeInstCount = 2640 };
// Generate all instructions asmjit can emit. // Generate all instructions asmjit can emit.
static void opcode(asmjit::host::Assembler& a) { static void opcode(asmjit::X86Assembler& a) {
using namespace asmjit; using namespace asmjit;
using namespace asmjit::host; using namespace asmjit::x86;
const X86GpReg& zax = a.zax;
const X86GpReg& zdx = a.zdx;
const X86GpReg& zcx = a.zcx;
const X86GpReg& zbx = a.zbx;
const X86GpReg& zsp = a.zsp;
const X86GpReg& zbp = a.zbp;
const X86GpReg& zsi = a.zsi;
const X86GpReg& zdi = a.zdi;
// Prevent crashing when the generated function is called (for debugging to // Prevent crashing when the generated function is called (for debugging to
// see disassembly). // see disassembly).
@@ -24,18 +35,18 @@ static void opcode(asmjit::host::Assembler& a) {
// When any problem is found this section can be used to customize the index // When any problem is found this section can be used to customize the index
// of the registers used. // of the registers used.
GpReg gp0 = zax; X86GpReg gp0 = zax;
GpReg gp1 = zsi; X86GpReg gp1 = zsi;
FpReg fpx = fp6; X86FpReg fpx = fp6;
Mem ptr_gp0 = ptr(gp0); X86Mem ptr_gp0 = ptr(gp0);
Mem ptr_gp1 = ptr(gp1); X86Mem ptr_gp1 = ptr(gp1);
Mem vm32x = ptr(gp0, xmm1); X86Mem vm32x = ptr(gp0, xmm1);
Mem vm32y = ptr(gp0, ymm1); X86Mem vm32y = ptr(gp0, ymm1);
Mem intptr_gp0 = intptr_ptr(gp0); X86Mem intptr_gp0 = a.intptr_ptr(gp0);
Mem intptr_gp1 = intptr_ptr(gp1); X86Mem intptr_gp1 = a.intptr_ptr(gp1);
// Base. // Base.
a.adc(al, 1); a.adc(al, 1);
@@ -268,6 +279,49 @@ static void opcode(asmjit::host::Assembler& a) {
a.xor_(intptr_gp0, gp1); a.xor_(intptr_gp0, gp1);
a.xor_(intptr_gp0, 0); a.xor_(intptr_gp0, 0);
a.nop();
a.lodsb();
a.lodsd();
a.lodsw();
a.rep_lodsb();
a.rep_lodsd();
a.rep_lodsw();
a.movsb();
a.movsd();
a.movsw();
a.rep_movsb();
a.rep_movsd();
a.rep_movsw();
a.stosb();
a.stosd();
a.stosw();
a.rep_stosb();
a.rep_stosd();
a.rep_stosw();
a.cmpsb();
a.cmpsd();
a.cmpsw();
a.repe_cmpsb();
a.repe_cmpsd();
a.repe_cmpsw();
a.repne_cmpsb();
a.repne_cmpsd();
a.repne_cmpsw();
a.scasb();
a.scasd();
a.scasw();
a.repe_scasb();
a.repe_scasd();
a.repe_scasw();
a.repne_scasb();
a.repne_scasd();
a.repne_scasw();
// Label...Jcc/Jecxz/Jmp. // Label...Jcc/Jecxz/Jmp.
{ {
a.nop(); a.nop();

View File

@@ -29,7 +29,7 @@ int main(int argc, char* argv[]) {
logger.setOption(kLoggerOptionBinaryForm, true); logger.setOption(kLoggerOptionBinaryForm, true);
JitRuntime runtime; JitRuntime runtime;
Assembler a(&runtime); X86Assembler a(&runtime);
a.setLogger(&logger); a.setLogger(&logger);
asmgen::opcode(a); asmgen::opcode(a);

File diff suppressed because it is too large Load Diff

View File

@@ -13,7 +13,6 @@
// ============================================================================ // ============================================================================
#if defined(_MSC_VER) #if defined(_MSC_VER)
// Disable some warnings we know about // Disable some warnings we know about
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
@@ -33,27 +32,18 @@
# define ASMJIT_DEFINED_VSNPRINTF # define ASMJIT_DEFINED_VSNPRINTF
# define vsnprintf _vsnprintf # define vsnprintf _vsnprintf
# endif // !vsnprintf # endif // !vsnprintf
# if !defined(snprintf) # if !defined(snprintf)
# define ASMJIT_DEFINED_SNPRINTF # define ASMJIT_DEFINED_SNPRINTF
# define snprintf _snprintf # define snprintf _snprintf
# endif // !snprintf # endif // !snprintf
#endif // _MSC_VER #endif // _MSC_VER
// ============================================================================ // ============================================================================
// [GNUC] // [GNUC]
// ============================================================================ // ============================================================================
#if defined(__GNUC__) #if defined(__GNUC__) && !defined(__clang__)
// GCC warnings fix: I can't understand why GCC has no interface to push/pop # if __GNUC__ >= 4 && !defined(__MINGW32__)
// specific warnings.
// # if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) >= 402001
// # pragma GCC diagnostic ignored "-w"
// # endif
#if __GNUC__ >= 4
# pragma GCC visibility push(hidden) # pragma GCC visibility push(hidden)
# endif // __GNUC__ >= 4 # endif // __GNUC__ >= 4
#endif // __GNUC__ #endif // __GNUC__

View File

@@ -9,31 +9,25 @@
// ============================================================================ // ============================================================================
#if defined(_MSC_VER) #if defined(_MSC_VER)
// Pop disabled warnings by ApiBegin.h // Pop disabled warnings by ApiBegin.h
# pragma warning(pop) # pragma warning(pop)
// Rename symbols back. // Rename symbols back.
# if defined(ASMJIT_DEFINED_VSNPRINTF) # if defined(ASMJIT_DEFINED_VSNPRINTF)
# undef ASMJIT_DEFINED_VSNPRINTF # undef ASMJIT_DEFINED_VSNPRINTF
# undef vsnprintf # undef vsnprintf
# endif // ASMJIT_DEFINED_VSNPRINTF # endif // ASMJIT_DEFINED_VSNPRINTF
# if defined(ASMJIT_DEFINED_SNPRINTF) # if defined(ASMJIT_DEFINED_SNPRINTF)
# undef ASMJIT_DEFINED_SNPRINTF # undef ASMJIT_DEFINED_SNPRINTF
# undef snprintf # undef snprintf
# endif // ASMJIT_DEFINED_SNPRINTF # endif // ASMJIT_DEFINED_SNPRINTF
#endif // _MSC_VER #endif // _MSC_VER
// ============================================================================ // ============================================================================
// [GNUC] // [GNUC]
// ============================================================================ // ============================================================================
#if defined(__GNUC__) #if defined(__GNUC__) && !defined(__clang__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
#if __GNUC__ >= 4
# pragma GCC visibility pop # pragma GCC visibility pop
# endif // __GNUC__ >= 4 # endif // __GNUC__ >= 4
#endif // __GNUC__ #endif // __GNUC__

View File

@@ -64,7 +64,7 @@
//! //!
//! @section AsmJit_Main_HomePage AsmJit Homepage //! @section AsmJit_Main_HomePage AsmJit Homepage
//! //!
//! - https://github.com/kobalicekp/asmjit //! - https://github.com/kobalicek/asmjit
// ============================================================================ // ============================================================================
// [asmjit_base] // [asmjit_base]
@@ -85,10 +85,10 @@
//! //!
//! Contains all `asmjit` classes and helper functions that are architecture //! Contains all `asmjit` classes and helper functions that are architecture
//! independent or abstract. Abstract classes are implemented by the backend, //! independent or abstract. Abstract classes are implemented by the backend,
//! for example `BaseAssembler` is implemented by `x86x64::X86X64Assembler`. //! for example `Assembler` is implemented by `X86Assembler`.
//! //!
//! - See `BaseAssembler` for low level code generation documentation. //! - See `Assembler` for low level code generation documentation.
//! - See `BaseCompiler` for high level code generation documentation. //! - See `Compiler` for high level code generation documentation.
//! - See `Operand` for operand's overview. //! - See `Operand` for operand's overview.
//! //!
//! Logging and Error Handling //! Logging and Error Handling
@@ -117,10 +117,10 @@
//! \sa \ref Logger, \ref FileLogger, \ref StringLogger. //! \sa \ref Logger, \ref FileLogger, \ref StringLogger.
// ============================================================================ // ============================================================================
// [asmjit_base_tree] // [asmjit_base_compiler]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_base_tree AsmJit Code-Tree //! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base //! \ingroup asmjit_base
//! //!
//! \brief AsmJit code-tree used by Compiler. //! \brief AsmJit code-tree used by Compiler.
@@ -128,7 +128,7 @@
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes //! AsmJit intermediate code-tree is a double-linked list that is made of nodes
//! that represent assembler instructions, directives, labels and high-level //! that represent assembler instructions, directives, labels and high-level
//! constructs compiler is using to represent functions and function calls. The //! constructs compiler is using to represent functions and function calls. The
//! node list can only be used together with \ref BaseCompiler. //! node list can only be used together with \ref Compiler.
//! //!
//! TODO //! TODO
@@ -181,8 +181,8 @@
//! ---------------- //! ----------------
//! //!
//! 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 `Vec64Data`, //! or a block of functions generated. AsmJit contains classes `Vec64`,
//! `Vec128Data` and `Vec256Data` that can be used to prepare data useful when //! `Vec128` and `Vec256` that can be used to prepare data useful when
//! generating SIMD code. //! generating SIMD code.
//! //!
//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm` //! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm`
@@ -193,19 +193,19 @@
//! embedding constants manually after the function body. //! embedding constants manually after the function body.
// ============================================================================ // ============================================================================
// [asmjit_x86x64] // [asmjit_x86]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86x64 X86/X64 //! \defgroup asmjit_x86 X86/X64
//! //!
//! \brief X86/X64 module //! \brief X86/X64 module
// ============================================================================ // ============================================================================
// [asmjit_x86x64_general] // [asmjit_x86_general]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86x64_general X86/X64 General API //! \defgroup asmjit_x86_general X86/X64 General API
//! \ingroup asmjit_x86x64 //! \ingroup asmjit_x86
//! //!
//! \brief X86/X64 general API. //! \brief X86/X64 general API.
//! //!
@@ -243,15 +243,14 @@
//! - `asmjit::tword_ptr()` //! - `asmjit::tword_ptr()`
//! - `asmjit::oword_ptr()` //! - `asmjit::oword_ptr()`
//! - `asmjit::yword_ptr()` //! - `asmjit::yword_ptr()`
//! - `asmjit::intptr_ptr()` //! - `asmjit::zword_ptr()`
//! //!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates //! Most useful function to make pointer should be `asmjit::ptr()`. It creates
//! pointer to the target with unspecified size. Unspecified size works in all //! pointer to the target with unspecified size. Unspecified size works in all
//! intrinsics where are used registers (this means that size is specified by //! intrinsics where are used registers (this means that size is specified by
//! register operand or by instruction itself). For example `asmjit::ptr()` //! register operand or by instruction itself). For example `asmjit::ptr()`
//! can't be used with @c asmjit::Assembler::inc() instruction. In this case //! can't be used with `Assembler::inc()` instruction. In this case size must
//! size must be specified and it's also reason to make difference between //! be specified and it's also reason to make difference between pointer sizes.
//! pointer sizes.
//! //!
//! Supported are simple address forms `[base + displacement]` and complex //! Supported are simple address forms `[base + displacement]` and complex
//! address forms `[base + index * scale + displacement]`. //! address forms `[base + index * scale + displacement]`.
@@ -260,8 +259,8 @@
//! ------------------ //! ------------------
//! //!
//! Immediate values are constants thats passed directly after instruction //! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use @c asmjit::imm() or @c asmjit::imm_u() //! opcode. To create such value use `imm()` or `imm_u()` methods to create
//! methods to create signed or unsigned immediate value. //! signed or unsigned immediate value.
//! //!
//! X86/X64 CPU Information //! X86/X64 CPU Information
//! ----------------------- //! -----------------------
@@ -270,22 +269,22 @@
//! the host X86/X64 processor. AsmJit contains utilities that can get the most //! the host X86/X64 processor. AsmJit contains utilities that can get the most
//! important information related to the features supported by the CPU and the //! important information related to the features supported by the CPU and the
//! host operating system, in addition to host processor name and number of //! host operating system, in addition to host processor name and number of
//! cores. Class `CpuInfo` extends `BaseCpuInfo` and provides functionality //! cores. Class `X86CpuInfo` extends `CpuInfo` and provides functionality
//! specific to X86 and X64. //! specific to X86 and X64.
//! //!
//! By default AsmJit queries the CPU information after the library is loaded //! By default AsmJit queries the CPU information after the library is loaded
//! and the queried information is reused by all instances of `JitRuntime`. //! and the queried information is reused by all instances of `JitRuntime`.
//! The global instance of `CpuInfo` can't be changed, because it will affect //! The global instance of `X86CpuInfo` can't be changed, because it will affect
//! the code generation of all `Runtime`s. If there is a need to have a //! the code generation of all `Runtime`s. If there is a need to have a
//! specific CPU information which contains modified features or processor //! specific CPU information which contains modified features or processor
//! vendor it's possible by creating a new instance of `CpuInfo` and setting //! vendor it's possible by creating a new instance of `X86CpuInfo` and setting
//! up its members. `CpuUtil::detect` can be used to detect CPU features into //! up its members. `X86CpuUtil::detect` can be used to detect CPU features into
//! an existing `CpuInfo` instance - it may become handly if only one property //! an existing `X86CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off. //! has to be turned on/off.
//! //!
//! If the high-level interface `CpuInfo` offers is not enough there is also //! If the high-level interface `X86CpuInfo` offers is not enough there is also
//! `CpuUtil::callCpuId` helper that can be used to call CPUID instruction with //! `X86CpuUtil::callCpuId` helper that can be used to call CPUID instruction
//! a given parameters and to consume the output. //! with a given parameters and to consume the output.
//! //!
//! Cpu detection is important when generating a JIT code that may or may not //! Cpu detection is important when generating a JIT code that may or may not
//! 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
@@ -295,15 +294,14 @@
//! //!
//! ~~~ //! ~~~
//! using namespace asmjit; //! using namespace asmjit;
//! using namespace asmjit::host;
//! //!
//! // Get `CpuInfo` global instance. //! // Get `X86CpuInfo` global instance.
//! const CpuInfo* cpuInfo = CpuInfo::getHost(); //! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
//! //!
//! if (cpuInfo->hasFeature(kCpuFeatureSse2)) { //! if (cpuInfo->hasFeature(kX86CpuFeatureSse2)) {
//! // Processor has SSE2. //! // Processor has SSE2.
//! } //! }
//! else if (cpuInfo->hasFeature(kCpuFeatureMmx)) { //! else if (cpuInfo->hasFeature(kX86CpuFeatureMmx)) {
//! // Processor doesn't have SSE2, but has MMX. //! // Processor doesn't have SSE2, but has MMX.
//! } //! }
//! else { //! else {
@@ -317,8 +315,8 @@
//! 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.
//! CpuId out; //! X86CpuId out;
//! CpuUtil::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];
@@ -332,29 +330,29 @@
//! ~~~ //! ~~~
// ============================================================================ // ============================================================================
// [asmjit_x86x64_tree] // [asmjit_x86_compiler]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86x64_tree X86/X64 Code-Tree //! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
//! \ingroup asmjit_x86x64 //! \ingroup asmjit_x86
//! //!
//! \brief X86/X64 code-tree and helpers. //! \brief X86/X64 code-tree and helpers.
// ============================================================================ // ============================================================================
// [asmjit_x86x64_inst] // [asmjit_x86_inst]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86x64_inst X86/X64 Instructions //! \defgroup asmjit_x86_inst X86/X64 Instructions
//! \ingroup asmjit_x86x64 //! \ingroup asmjit_x86
//! //!
//! \brief X86/X64 low-level instruction definitions. //! \brief X86/X64 low-level instruction definitions.
// ============================================================================ // ============================================================================
// [asmjit_x86x64_util] // [asmjit_x86_util]
// ============================================================================ // ============================================================================
//! \defgroup asmjit_x86x64_util X86/X64 Utilities //! \defgroup asmjit_x86_util X86/X64 Utilities
//! \ingroup asmjit_x86x64 //! \ingroup asmjit_x86
//! //!
//! \brief X86/X64 utility classes. //! \brief X86/X64 utility classes.

View File

@@ -15,17 +15,15 @@
#include "base/codegen.h" #include "base/codegen.h"
#include "base/compiler.h" #include "base/compiler.h"
#include "base/constpool.h" #include "base/constpool.h"
#include "base/containers.h"
#include "base/cpuinfo.h" #include "base/cpuinfo.h"
#include "base/cputicks.h" #include "base/cputicks.h"
#include "base/error.h" #include "base/error.h"
#include "base/func.h"
#include "base/globals.h" #include "base/globals.h"
#include "base/intutil.h" #include "base/intutil.h"
#include "base/lock.h" #include "base/lock.h"
#include "base/logger.h" #include "base/logger.h"
#include "base/operand.h" #include "base/operand.h"
#include "base/podlist.h"
#include "base/podvector.h"
#include "base/runtime.h" #include "base/runtime.h"
#include "base/string.h" #include "base/string.h"
#include "base/vectypes.h" #include "base/vectypes.h"

View File

@@ -21,10 +21,10 @@
namespace asmjit { namespace asmjit {
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Construction / Destruction] // [asmjit::Assembler - Construction / Destruction]
// ============================================================================ // ============================================================================
BaseAssembler::BaseAssembler(Runtime* runtime) : Assembler::Assembler(Runtime* runtime) :
CodeGen(runtime), CodeGen(runtime),
_buffer(NULL), _buffer(NULL),
_end(NULL), _end(NULL),
@@ -33,56 +33,42 @@ BaseAssembler::BaseAssembler(Runtime* runtime) :
_comment(NULL), _comment(NULL),
_unusedLinks(NULL) {} _unusedLinks(NULL) {}
BaseAssembler::~BaseAssembler() { Assembler::~Assembler() {
if (_buffer != NULL) reset(true);
ASMJIT_FREE(_buffer);
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Clear / Reset] // [asmjit::Assembler - Clear / Reset]
// ============================================================================ // ============================================================================
void BaseAssembler::clear() { void Assembler::reset(bool releaseMemory) {
_purge(); // CodeGen members.
} _error = kErrorOk;
_options = 0;
_baseZone.reset(releaseMemory);
void BaseAssembler::reset() { // Assembler members.
_purge(); if (releaseMemory && _buffer != NULL) {
_baseZone.reset();
if (_buffer != NULL) {
ASMJIT_FREE(_buffer); ASMJIT_FREE(_buffer);
_buffer = NULL; _buffer = NULL;
_end = NULL; _end = NULL;
_cursor = NULL;
} }
_labels.reset();
_relocData.reset();
}
void BaseAssembler::_purge() {
_baseZone.clear();
_cursor = _buffer; _cursor = _buffer;
_options = 0;
_trampolineSize = 0; _trampolineSize = 0;
_comment = NULL; _comment = NULL;
_unusedLinks = NULL; _unusedLinks = NULL;
_labels.clear(); _labels.reset(releaseMemory);
_relocData.clear(); _relocData.reset(releaseMemory);
clearError();
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Buffer] // [asmjit::Assembler - Buffer]
// ============================================================================ // ============================================================================
Error BaseAssembler::_grow(size_t n) { Error Assembler::_grow(size_t n) {
size_t capacity = getCapacity(); size_t capacity = getCapacity();
size_t after = getOffset() + n; size_t after = getOffset() + n;
@@ -117,7 +103,7 @@ Error BaseAssembler::_grow(size_t n) {
return _reserve(capacity); return _reserve(capacity);
} }
Error BaseAssembler::_reserve(size_t n) { Error Assembler::_reserve(size_t n) {
size_t capacity = getCapacity(); size_t capacity = getCapacity();
if (n <= capacity) if (n <= capacity)
return kErrorOk; return kErrorOk;
@@ -141,10 +127,10 @@ Error BaseAssembler::_reserve(size_t n) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Label] // [asmjit::Assembler - Label]
// ============================================================================ // ============================================================================
Error BaseAssembler::_registerIndexedLabels(size_t index) { Error Assembler::_registerIndexedLabels(size_t index) {
size_t i = _labels.getLength(); size_t i = _labels.getLength();
if (index < i) if (index < i)
return kErrorOk; return kErrorOk;
@@ -163,7 +149,7 @@ Error BaseAssembler::_registerIndexedLabels(size_t index) {
return kErrorOk; return kErrorOk;
} }
Error BaseAssembler::_newLabel(Label* dst) { Error Assembler::_newLabel(Label* dst) {
dst->_label.op = kOperandTypeLabel; dst->_label.op = kOperandTypeLabel;
dst->_label.size = 0; dst->_label.size = 0;
dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labels.getLength())); dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labels.getLength()));
@@ -181,7 +167,7 @@ _NoMemory:
return setError(kErrorNoHeapMemory); return setError(kErrorNoHeapMemory);
} }
LabelLink* BaseAssembler::_newLabelLink() { LabelLink* Assembler::_newLabelLink() {
LabelLink* link = _unusedLinks; LabelLink* link = _unusedLinks;
if (link) { if (link) {
@@ -202,10 +188,10 @@ LabelLink* BaseAssembler::_newLabelLink() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Embed] // [asmjit::Assembler - Embed]
// ============================================================================ // ============================================================================
Error BaseAssembler::embed(const void* data, uint32_t size) { 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)
@@ -225,10 +211,10 @@ Error BaseAssembler::embed(const void* data, uint32_t size) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Make] // [asmjit::Assembler - Make]
// ============================================================================ // ============================================================================
void* BaseAssembler::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 (_error != kErrorOk || getCodeSize() == 0)
return NULL; return NULL;
@@ -243,57 +229,65 @@ void* BaseAssembler::make() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler - Emit (Helpers)] // [asmjit::Assembler - Emit (Helpers)]
// ============================================================================ // ============================================================================
#define no noOperand #define no noOperand
Error BaseAssembler::emit(uint32_t code) { Error Assembler::emit(uint32_t code) {
return _emit(code, no, no, no, no); return _emit(code, no, no, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0) { Error Assembler::emit(uint32_t code, const Operand& o0) {
return _emit(code, o0, no, no, no); return _emit(code, o0, no, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1) {
return _emit(code, o0, o1, no, no); return _emit(code, o0, o1, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) {
return _emit(code, o0, o1, o2, no); return _emit(code, o0, o1, o2, no);
} }
Error BaseAssembler::emit(uint32_t code, int o0_) { Error Assembler::emit(uint32_t code, int o0) {
return _emit(code, Imm(o0_), no, no, no); Imm imm(o0);
return _emit(code, imm, no, no, no);
} }
Error BaseAssembler::emit(uint32_t code, uint64_t o0_) { Error Assembler::emit(uint32_t code, uint64_t o0) {
return _emit(code, Imm(o0_), no, no, no); Imm imm(o0);
return _emit(code, imm, no, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, int o1_) { Error Assembler::emit(uint32_t code, const Operand& o0, int o1) {
return _emit(code, o0, Imm(o1_), no, no); Imm imm(o1);
return _emit(code, o0, imm, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, uint64_t o1_) { Error Assembler::emit(uint32_t code, const Operand& o0, uint64_t o1) {
return _emit(code, o0, Imm(o1_), no, no); Imm imm(o1);
return _emit(code, o0, imm, no, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2_) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2) {
return _emit(code, o0, o1, Imm(o2_), no); Imm imm(o2);
return _emit(code, o0, o1, imm, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2_) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, uint64_t o2) {
return _emit(code, o0, o1, Imm(o2_), no); Imm imm(o2);
return _emit(code, o0, o1, imm, no);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3_) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3) {
return _emit(code, o0, o1, o2, Imm(o3_)); Imm imm(o3);
return _emit(code, o0, o1, o2, imm);
} }
Error BaseAssembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3_) { Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, uint64_t o3) {
return _emit(code, o0, o1, o2, Imm(o3_)); Imm imm(o3);
return _emit(code, o0, o1, o2, imm);
} }
#undef no #undef no

View File

@@ -10,11 +10,10 @@
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/codegen.h" #include "../base/codegen.h"
#include "../base/containers.h"
#include "../base/error.h" #include "../base/error.h"
#include "../base/logger.h" #include "../base/logger.h"
#include "../base/operand.h" #include "../base/operand.h"
#include "../base/podlist.h"
#include "../base/podvector.h"
#include "../base/runtime.h" #include "../base/runtime.h"
#include "../base/zone.h" #include "../base/zone.h"
@@ -27,13 +26,13 @@ namespace asmjit {
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::kInstCode] // [asmjit::kInstId]
// ============================================================================ // ============================================================================
//! Instruction codes (stub). //! Instruction codes (stub).
ASMJIT_ENUM(kInstCode) { ASMJIT_ENUM(kInstId) {
//! No instruction. //! No instruction.
kInstNone = 0 kInstIdNone = 0
}; };
// ============================================================================ // ============================================================================
@@ -132,7 +131,7 @@ struct RelocData {
}; };
// ============================================================================ // ============================================================================
// [asmjit::BaseAssembler] // [asmjit::Assembler]
// ============================================================================ // ============================================================================
//! Base assembler. //! Base assembler.
@@ -140,30 +139,27 @@ struct RelocData {
//! This class implements the base interface to an assembler. The architecture //! This class implements the base interface to an assembler. The architecture
//! specific API is implemented by backends. //! specific API is implemented by backends.
//! //!
//! @sa BaseCompiler. //! \sa Compiler.
struct BaseAssembler : public CodeGen { struct ASMJIT_VCLASS Assembler : public CodeGen {
ASMJIT_NO_COPY(BaseAssembler) ASMJIT_NO_COPY(Assembler)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a new `BaseAssembler` instance. //! Create a new `Assembler` instance.
ASMJIT_API BaseAssembler(Runtime* runtime); ASMJIT_API Assembler(Runtime* runtime);
//! Destroy the `BaseAssembler` instance. //! Destroy the `Assembler` instance.
ASMJIT_API virtual ~BaseAssembler(); ASMJIT_API virtual ~Assembler();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Clear / Reset] // [Reset]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Clear everything, but not deallocate buffers. //! Reset the assembler.
ASMJIT_API void clear(); //!
//! Reset everything (means also to free all buffers). //! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void reset(); ASMJIT_API void reset(bool releaseMemory = false);
//! Called by clear() and reset() to clear all data related to derived class
//! implementation.
ASMJIT_API virtual void _purge();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Buffer] // [Buffer]
@@ -526,7 +522,7 @@ struct BaseAssembler : public CodeGen {
// [Defined-Later] // [Defined-Later]
// ============================================================================ // ============================================================================
ASMJIT_INLINE Label::Label(BaseAssembler& a) : Operand(NoInit) { ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
a._newLabel(this); a._newLabel(this);
} }

View File

@@ -57,12 +57,20 @@ Error CodeGen::setError(Error error, const char* message) {
return kErrorOk; return kErrorOk;
} }
if (message == NULL) if (message == NULL) {
#if !defined(ASMJIT_DISABLE_NAMES)
message = ErrorUtil::asString(error); 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 // Error handler is called before logger so logging can be skipped if error
// has been handled. // has been handled.
ErrorHandler* handler = _errorHandler; ErrorHandler* handler = _errorHandler;
ASMJIT_TLOG("[ERROR] %s %s\n", message, !handler ? "(Possibly unhandled?)" : "");
if (handler != NULL && handler->handleError(error, message)) if (handler != NULL && handler->handleError(error, message))
return error; return error;

View File

@@ -28,7 +28,9 @@ namespace asmjit {
//! Features of \ref CodeGen. //! Features of \ref CodeGen.
ASMJIT_ENUM(kCodeGen) { ASMJIT_ENUM(kCodeGen) {
//! Emit optimized code-alignment sequences (true by default). //! Emit optimized code-alignment sequences (`Assembler` and `Compiler`).
//!
//! Default `true`.
//! //!
//! X86/X64 //! X86/X64
//! ------- //! -------
@@ -37,12 +39,14 @@ ASMJIT_ENUM(kCodeGen) {
//! opcode that is mostly shown by disassemblers as nop. However there are //! opcode that is mostly shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster. //! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled asmjit will generate specialized sequences //! If this feature is enabled asmjit will generate specialized sequences
//! for alignment between 1 to 11 bytes. Also when `x86x64::Compiler` is //! for alignment between 1 to 11 bytes. Also when `X86Compiler` is used,
//! used, it may add rex prefixes into the code to make some instructions //! it can add REX prefixes into the code to make some instructions greater
//! greater so no alignment sequences are needed. //! so no alignment sequence is needed.
kCodeGenOptimizedAlign = 0, kCodeGenOptimizedAlign = 0,
//! Emit jump-prediction hints (false by default). //! Emit jump-prediction hints (`Assembler` and `Compiler`).
//!
//! Default `false`.
//! //!
//! X86/X64 //! X86/X64
//! ------- //! -------
@@ -55,9 +59,24 @@ ASMJIT_ENUM(kCodeGen) {
//! If this option is enabled these hints will be emitted. //! If this option is enabled these hints will be emitted.
//! //!
//! This feature is disabled by default, because the only processor that //! This feature is disabled by default, because the only processor that
//! used to take into consideration prediction hints was P4 that is not used //! used to take into consideration prediction hints was P4. Newer processors
//! anymore. //! implement heuristics for branch prediction that ignores any static hints.
kCodeGenPredictedJumps = 1 kCodeGenPredictedJumps = 1,
//! Schedule instructions so they can be executed faster (`Compiler` only).
//!
//! Default `false`, has to be explicitly enabled because it 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
}; };
// ============================================================================ // ============================================================================
@@ -66,7 +85,9 @@ ASMJIT_ENUM(kCodeGen) {
//! Code aligning mode. //! Code aligning mode.
ASMJIT_ENUM(kAlignMode) { ASMJIT_ENUM(kAlignMode) {
//! Align by emitting a sequence that can be executed (code).
kAlignCode = 0, kAlignCode = 0,
//! Align by emitting sequence that shouldn't be executed (data).
kAlignData = 1 kAlignData = 1
}; };
@@ -86,8 +107,8 @@ ASMJIT_ENUM(kRelocMode) {
// [asmjit::CodeGen] // [asmjit::CodeGen]
// ============================================================================ // ============================================================================
//! Abstract class defining basics of \ref Assembler and \ref BaseCompiler. //! Abstract class defining basics of \ref Assembler and \ref Compiler.
struct CodeGen { struct ASMJIT_VCLASS CodeGen {
ASMJIT_NO_COPY(CodeGen) ASMJIT_NO_COPY(CodeGen)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -154,7 +175,7 @@ struct CodeGen {
ASMJIT_API Error setError(Error error, const char* message = NULL); ASMJIT_API Error setError(Error error, const char* message = NULL);
//! Clear the last error code. //! Clear the last error code.
ASMJIT_INLINE void clearError() { ASMJIT_INLINE void resetError() {
_error = kErrorOk; _error = kErrorOk;
} }
@@ -167,7 +188,7 @@ struct CodeGen {
ASMJIT_API Error setErrorHandler(ErrorHandler* handler); ASMJIT_API Error setErrorHandler(ErrorHandler* handler);
//! Clear error handler. //! Clear error handler.
ASMJIT_INLINE Error clearErrorHandler() { ASMJIT_INLINE Error resetErrorHandler() {
return setErrorHandler(NULL); return setErrorHandler(NULL);
} }
@@ -194,21 +215,13 @@ struct CodeGen {
_options = options; _options = options;
} }
//! Get options of the next instruction and clear them. //! Get options of the next instruction and reset them.
ASMJIT_INLINE uint32_t getOptionsAndClear() { ASMJIT_INLINE uint32_t getOptionsAndReset() {
uint32_t options = _options; uint32_t options = _options;
_options = 0; _options = 0;
return options; return options;
}; };
// --------------------------------------------------------------------------
// [Purge]
// --------------------------------------------------------------------------
//! Called by \ref clear() and \ref reset() to clear all data used by the
//! code generator.
virtual void _purge() = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Make] // [Make]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@@ -35,10 +35,10 @@ static const char noName[1] = { '\0' };
enum { kBaseCompilerDefaultLookAhead = 64 }; enum { kBaseCompilerDefaultLookAhead = 64 };
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Construction / Destruction] // [asmjit::Compiler - Construction / Destruction]
// ============================================================================ // ============================================================================
BaseCompiler::BaseCompiler(Runtime* runtime) : Compiler::Compiler(Runtime* runtime) :
CodeGen(runtime), CodeGen(runtime),
_nodeFlowId(0), _nodeFlowId(0),
_nodeFlags(0), _nodeFlags(0),
@@ -54,40 +54,23 @@ BaseCompiler::BaseCompiler(Runtime* runtime) :
_localConstPool(&_localConstZone), _localConstPool(&_localConstZone),
_globalConstPool(&_baseZone) {} _globalConstPool(&_baseZone) {}
BaseCompiler::~BaseCompiler() { Compiler::~Compiler() {
reset(); reset();
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Clear / Reset] // [asmjit::Compiler - Clear / Reset]
// ============================================================================ // ============================================================================
void BaseCompiler::clear() { void Compiler::reset(bool releaseMemory) {
_purge(); // CodeGen members.
} _error = kErrorOk;
void BaseCompiler::reset() {
_purge();
_localConstPool.reset();
_globalConstPool.reset();
_targets.reset();
_vars.reset();
_baseZone.reset();
_varZone.reset();
_stringZone.reset();
_localConstZone.reset();
}
void BaseCompiler::_purge() {
_baseZone.clear();
_varZone.clear();
_stringZone.clear();
_options = 0; _options = 0;
_baseZone.reset(releaseMemory);
// Compiler members.
_nodeFlowId = 0;
_nodeFlags = 0;
_firstNode = NULL; _firstNode = NULL;
_lastNode = NULL; _lastNode = NULL;
@@ -95,23 +78,31 @@ void BaseCompiler::_purge() {
_cursor = NULL; _cursor = NULL;
_func = NULL; _func = NULL;
_targets.clear(); _localConstPool.reset();
_vars.clear(); _globalConstPool.reset();
clearError(); _localConstPoolLabel.reset();
_globalConstPoolLabel.reset();
_varZone.reset(releaseMemory);
_stringZone.reset(releaseMemory);
_localConstZone.reset(releaseMemory);
_targets.reset(releaseMemory);
_vars.reset(releaseMemory);
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Node Management] // [asmjit::Compiler - Node Management]
// ============================================================================ // ============================================================================
Node* BaseCompiler::setCursor(Node* node) { Node* Compiler::setCursor(Node* node) {
Node* old = _cursor; Node* old = _cursor;
_cursor = node; _cursor = node;
return old; return old;
} }
Node* BaseCompiler::addNode(Node* node) { Node* Compiler::addNode(Node* 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);
@@ -145,7 +136,7 @@ Node* BaseCompiler::addNode(Node* node) {
return node; return node;
} }
Node* BaseCompiler::addNodeBefore(Node* node, Node* ref) { Node* Compiler::addNodeBefore(Node* node, Node* 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);
@@ -166,7 +157,7 @@ Node* BaseCompiler::addNodeBefore(Node* node, Node* ref) {
return node; return node;
} }
Node* BaseCompiler::addNodeAfter(Node* node, Node* ref) { Node* Compiler::addNodeAfter(Node* node, Node* 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);
@@ -187,7 +178,7 @@ Node* BaseCompiler::addNodeAfter(Node* node, Node* ref) {
return node; return node;
} }
static ASMJIT_INLINE void BaseCompiler_nodeRemoved(BaseCompiler* self, Node* node_) { static ASMJIT_INLINE void BaseCompiler_nodeRemoved(Compiler* self, Node* node_) {
if (node_->isJmpOrJcc()) { if (node_->isJmpOrJcc()) {
JumpNode* node = static_cast<JumpNode*>(node_); JumpNode* node = static_cast<JumpNode*>(node_);
TargetNode* target = node->getTarget(); TargetNode* target = node->getTarget();
@@ -213,7 +204,7 @@ static ASMJIT_INLINE void BaseCompiler_nodeRemoved(BaseCompiler* self, Node* nod
} }
} }
Node* BaseCompiler::removeNode(Node* node) { Node* Compiler::removeNode(Node* node) {
Node* prev = node->_prev; Node* prev = node->_prev;
Node* next = node->_next; Node* next = node->_next;
@@ -237,7 +228,7 @@ Node* BaseCompiler::removeNode(Node* node) {
return node; return node;
} }
void BaseCompiler::removeNodes(Node* first, Node* last) { void Compiler::removeNodes(Node* first, Node* last) {
if (first == last) { if (first == last) {
removeNode(first); removeNode(first);
return; return;
@@ -275,10 +266,10 @@ void BaseCompiler::removeNodes(Node* first, Node* last) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Align] // [asmjit::Compiler - Align]
// ============================================================================ // ============================================================================
AlignNode* BaseCompiler::newAlign(uint32_t mode, uint32_t offset) { AlignNode* Compiler::newAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newNode<AlignNode>(mode, offset); AlignNode* node = newNode<AlignNode>(mode, offset);
if (node == NULL) if (node == NULL)
goto _NoMemory; goto _NoMemory;
@@ -289,7 +280,7 @@ _NoMemory:
return NULL; return NULL;
} }
AlignNode* BaseCompiler::addAlign(uint32_t mode, uint32_t offset) { AlignNode* Compiler::addAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newAlign(mode, offset); AlignNode* node = newAlign(mode, offset);
if (node == NULL) if (node == NULL)
return NULL; return NULL;
@@ -297,10 +288,10 @@ AlignNode* BaseCompiler::addAlign(uint32_t mode, uint32_t offset) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Target] // [asmjit::Compiler - Target]
// ============================================================================ // ============================================================================
TargetNode* BaseCompiler::newTarget() { TargetNode* Compiler::newTarget() {
TargetNode* node = newNode<TargetNode>( TargetNode* node = newNode<TargetNode>(
OperandUtil::makeLabelId(static_cast<uint32_t>(_targets.getLength()))); OperandUtil::makeLabelId(static_cast<uint32_t>(_targets.getLength())));
@@ -313,7 +304,7 @@ _NoMemory:
return NULL; return NULL;
} }
TargetNode* BaseCompiler::addTarget() { TargetNode* Compiler::addTarget() {
TargetNode* node = newTarget(); TargetNode* node = newTarget();
if (node == NULL) if (node == NULL)
return NULL; return NULL;
@@ -321,10 +312,10 @@ TargetNode* BaseCompiler::addTarget() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Label] // [asmjit::Compiler - Label]
// ============================================================================ // ============================================================================
Error BaseCompiler::_newLabel(Label* dst) { Error Compiler::_newLabel(Label* dst) {
dst->_init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue); dst->_init_packed_op_sz_b0_b1_id(kOperandTypeLabel, 0, 0, 0, kInvalidValue);
dst->_init_packed_d2_d3(0, 0); dst->_init_packed_d2_d3(0, 0);
@@ -339,7 +330,7 @@ _NoMemory:
return setError(kErrorNoHeapMemory); return setError(kErrorNoHeapMemory);
} }
void BaseCompiler::bind(const Label& label) { void Compiler::bind(const Label& label) {
uint32_t index = label.getId(); uint32_t index = label.getId();
ASMJIT_ASSERT(index < _targets.getLength()); ASMJIT_ASSERT(index < _targets.getLength());
@@ -347,10 +338,10 @@ void BaseCompiler::bind(const Label& label) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Embed] // [asmjit::Compiler - Embed]
// ============================================================================ // ============================================================================
EmbedNode* BaseCompiler::newEmbed(const void* data, uint32_t size) { EmbedNode* Compiler::newEmbed(const void* data, uint32_t size) {
EmbedNode* node; EmbedNode* node;
if (size > EmbedNode::kInlineBufferSize) { if (size > EmbedNode::kInlineBufferSize) {
@@ -373,7 +364,7 @@ _NoMemory:
return NULL; return NULL;
} }
EmbedNode* BaseCompiler::addEmbed(const void* data, uint32_t size) { EmbedNode* Compiler::addEmbed(const void* data, uint32_t size) {
EmbedNode* node = newEmbed(data, size); EmbedNode* node = newEmbed(data, size);
if (node == NULL) if (node == NULL)
return node; return node;
@@ -381,10 +372,10 @@ EmbedNode* BaseCompiler::addEmbed(const void* data, uint32_t size) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Comment] // [asmjit::Compiler - Comment]
// ============================================================================ // ============================================================================
CommentNode* BaseCompiler::newComment(const char* str) { CommentNode* Compiler::newComment(const char* str) {
CommentNode* node; CommentNode* node;
if (str != NULL && str[0]) { if (str != NULL && str[0]) {
@@ -403,14 +394,14 @@ _NoMemory:
return NULL; return NULL;
} }
CommentNode* BaseCompiler::addComment(const char* str) { CommentNode* Compiler::addComment(const char* str) {
CommentNode* node = newComment(str); CommentNode* node = newComment(str);
if (node == NULL) if (node == NULL)
return NULL; return NULL;
return static_cast<CommentNode*>(addNode(node)); return static_cast<CommentNode*>(addNode(node));
} }
CommentNode* BaseCompiler::comment(const char* fmt, ...) { CommentNode* Compiler::comment(const char* fmt, ...) {
char buf[256]; char buf[256];
char* p = buf; char* p = buf;
@@ -431,10 +422,10 @@ CommentNode* BaseCompiler::comment(const char* fmt, ...) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Hint] // [asmjit::Compiler - Hint]
// ============================================================================ // ============================================================================
HintNode* BaseCompiler::newHint(BaseVar& var, uint32_t hint, uint32_t value) { HintNode* Compiler::newHint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return NULL; return NULL;
VarData* vd = getVd(var); VarData* vd = getVd(var);
@@ -449,7 +440,7 @@ _NoMemory:
return NULL; return NULL;
} }
HintNode* BaseCompiler::addHint(BaseVar& var, uint32_t hint, uint32_t value) { HintNode* Compiler::addHint(Var& var, uint32_t hint, uint32_t value) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return NULL; return NULL;
@@ -460,10 +451,10 @@ HintNode* BaseCompiler::addHint(BaseVar& var, uint32_t hint, uint32_t value) {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCompiler - Vars] // [asmjit::Compiler - Vars]
// ============================================================================ // ============================================================================
VarData* BaseCompiler:: _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*>(_varZone.alloc(sizeof(VarData)));
if (vd == NULL) if (vd == NULL)
goto _NoMemory; goto _NoMemory;
@@ -492,6 +483,7 @@ VarData* BaseCompiler:: _newVd(uint32_t type, uint32_t size, uint32_t c, const c
vd->_alignment = static_cast<uint8_t>(IntUtil::iMin<uint32_t>(size, 64)); vd->_alignment = static_cast<uint8_t>(IntUtil::iMin<uint32_t>(size, 64));
vd->_size = size; vd->_size = size;
vd->_homeMask = 0;
vd->_memOffset = 0; vd->_memOffset = 0;
vd->_memCell = NULL; vd->_memCell = NULL;
@@ -512,31 +504,31 @@ _NoMemory:
return NULL; return NULL;
} }
void BaseCompiler::alloc(BaseVar& var) { void Compiler::alloc(Var& var) {
addHint(var, kVarHintAlloc, kInvalidValue); addHint(var, kVarHintAlloc, kInvalidValue);
} }
void BaseCompiler::alloc(BaseVar& var, uint32_t regIndex) { void Compiler::alloc(Var& var, uint32_t regIndex) {
addHint(var, kVarHintAlloc, regIndex); addHint(var, kVarHintAlloc, regIndex);
} }
void BaseCompiler::alloc(BaseVar& var, const BaseReg& reg) { void Compiler::alloc(Var& var, const Reg& reg) {
addHint(var, kVarHintAlloc, reg.getRegIndex()); addHint(var, kVarHintAlloc, reg.getRegIndex());
} }
void BaseCompiler::save(BaseVar& var) { void Compiler::save(Var& var) {
addHint(var, kVarHintSave, kInvalidValue); addHint(var, kVarHintSave, kInvalidValue);
} }
void BaseCompiler::spill(BaseVar& var) { void Compiler::spill(Var& var) {
addHint(var, kVarHintSpill, kInvalidValue); addHint(var, kVarHintSpill, kInvalidValue);
} }
void BaseCompiler::unuse(BaseVar& var) { void Compiler::unuse(Var& var) {
addHint(var, kVarHintUnuse, kInvalidValue); addHint(var, kVarHintUnuse, kInvalidValue);
} }
uint32_t BaseCompiler::getPriority(BaseVar& var) const { uint32_t Compiler::getPriority(Var& var) const {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return kInvalidValue; return kInvalidValue;
@@ -544,7 +536,7 @@ uint32_t BaseCompiler::getPriority(BaseVar& var) const {
return vd->getPriority(); return vd->getPriority();
} }
void BaseCompiler::setPriority(BaseVar& var, uint32_t priority) { void Compiler::setPriority(Var& var, uint32_t priority) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return;
@@ -555,7 +547,7 @@ void BaseCompiler::setPriority(BaseVar& var, uint32_t priority) {
vd->_priority = static_cast<uint8_t>(priority); vd->_priority = static_cast<uint8_t>(priority);
} }
bool BaseCompiler::getSaveOnUnuse(BaseVar& var) const { bool Compiler::getSaveOnUnuse(Var& var) const {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return false; return false;
@@ -563,7 +555,7 @@ bool BaseCompiler::getSaveOnUnuse(BaseVar& var) const {
return static_cast<bool>(vd->_saveOnUnuse); return static_cast<bool>(vd->_saveOnUnuse);
} }
void BaseCompiler::setSaveOnUnuse(BaseVar& var, bool value) { void Compiler::setSaveOnUnuse(Var& var, bool value) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return;
@@ -571,7 +563,7 @@ void BaseCompiler::setSaveOnUnuse(BaseVar& var, bool value) {
vd->_saveOnUnuse = value; vd->_saveOnUnuse = value;
} }
void BaseCompiler::rename(BaseVar& var, const char* name) { void Compiler::rename(Var& var, const char* name) {
if (var.getId() == kInvalidValue) if (var.getId() == kInvalidValue)
return; return;

File diff suppressed because it is too large Load Diff

View File

@@ -372,7 +372,7 @@ void ConstPool::fill(void* dst) {
#if defined(ASMJIT_TEST) #if defined(ASMJIT_TEST)
UNIT(base_constpool) { UNIT(base_constpool) {
Zone zone(16192); Zone zone(32384 - kZoneOverhead);
ConstPool pool(&zone); ConstPool pool(&zone);
uint32_t i; uint32_t i;
@@ -455,7 +455,7 @@ UNIT(base_constpool) {
"pool.add() - Didn't return aligned offset."); "pool.add() - Didn't return aligned offset.");
} }
INFO("Adding 2 byte constant verify the gap is filled."); INFO("Adding 2 byte constant to verify the gap is filled.");
{ {
uint16_t c = 0xFFFE; uint16_t c = 0xFFFE;
size_t offset; size_t offset;

View File

@@ -8,8 +8,8 @@
#define ASMJIT_EXPORTS #define ASMJIT_EXPORTS
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/containers.h"
#include "../base/intutil.h" #include "../base/intutil.h"
#include "../base/podvector.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -22,6 +22,26 @@ namespace asmjit {
const PodVectorData PodVectorBase::_nullData = { 0, 0 }; const PodVectorData PodVectorBase::_nullData = { 0, 0 };
// ============================================================================
// [asmjit::PodVectorBase - Reset]
// ============================================================================
//! Clear vector data and free internal buffer.
void PodVectorBase::reset(bool releaseMemory) {
PodVectorData* d = _d;
if (d == &_nullData)
return;
if (releaseMemory) {
ASMJIT_FREE(d);
_d = const_cast<PodVectorData*>(&_nullData);
return;
}
d->length = 0;
}
// ============================================================================ // ============================================================================
// [asmjit::PodVectorBase - Helpers] // [asmjit::PodVectorBase - Helpers]
// ============================================================================ // ============================================================================

View File

@@ -5,11 +5,12 @@
// Zlib - See LICENSE.md file in the package. // Zlib - See LICENSE.md file in the package.
// [Guard] // [Guard]
#ifndef _ASMJIT_BASE_PODVECTOR_H #ifndef _ASMJIT_BASE_CONTAINERS_H
#define _ASMJIT_BASE_PODVECTOR_H #define _ASMJIT_BASE_CONTAINERS_H
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/error.h" #include "../base/error.h"
#include "../base/globals.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -25,11 +26,19 @@ namespace asmjit {
//! \internal //! \internal
struct PodVectorData { struct PodVectorData {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get data. //! Get data.
ASMJIT_INLINE void* getData() const { ASMJIT_INLINE void* getData() const {
return (void*)(this + 1); return (void*)(this + 1);
} }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Capacity of the vector. //! Capacity of the vector.
size_t capacity; size_t capacity;
//! Length of the vector. //! Length of the vector.
@@ -54,10 +63,19 @@ struct PodVectorBase {
//! Destroy the `PodVectorBase` and data. //! Destroy the `PodVectorBase` and data.
ASMJIT_INLINE ~PodVectorBase() { ASMJIT_INLINE ~PodVectorBase() {
if (_d != &_nullData) reset(true);
ASMJIT_FREE(_d);
} }
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the vector data and set its `length` to zero.
//!
//! If `releaseMemory` is true the vector buffer will be released to the
//! system.
ASMJIT_API void reset(bool releaseMemory = false);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Grow / Reserve] // [Grow / Reserve]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -127,24 +145,6 @@ struct PodVector : PodVectorBase {
return static_cast<const T*>(_d->getData()); return static_cast<const T*>(_d->getData());
} }
// --------------------------------------------------------------------------
// [Clear / Reset]
// --------------------------------------------------------------------------
//! Clear vector data, but don't free an internal buffer.
ASMJIT_INLINE void clear() {
if (_d != &_nullData)
_d->length = 0;
}
//! Clear vector data and free internal buffer.
ASMJIT_INLINE void reset() {
if (_d != &_nullData) {
ASMJIT_FREE(_d);
_d = const_cast<PodVectorData*>(&_nullData);
}
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Grow / Reserve] // [Grow / Reserve]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -254,19 +254,89 @@ struct PodVector : PodVectorBase {
ASMJIT_ASSERT(i < getLength()); ASMJIT_ASSERT(i < getLength());
return getData()[i]; return getData()[i];
} }
};
//! Allocate and append a new item and return its address. // ============================================================================
T* newElement() { // [asmjit::PodList<T>]
PodVectorData* d = _d; // ============================================================================
if (d->length == d->capacity) { //! \internal
if (!_grow(1)) template <typename T>
return NULL; struct PodList {
d = _d; ASMJIT_NO_COPY(PodList<T>)
// --------------------------------------------------------------------------
// [Link]
// --------------------------------------------------------------------------
struct Link {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get next node.
ASMJIT_INLINE Link* getNext() const { return _next; }
//! Get value.
ASMJIT_INLINE T getValue() const { return _value; }
//! Set value to `value`.
ASMJIT_INLINE void setValue(const T& value) { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _next;
T _value;
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE PodList() : _first(NULL), _last(NULL) {}
ASMJIT_INLINE ~PodList() {}
// --------------------------------------------------------------------------
// [Data]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const { return _first != NULL; }
ASMJIT_INLINE Link* getFirst() const { return _first; }
ASMJIT_INLINE Link* getLast() const { return _last; }
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_first = NULL;
_last = NULL;
} }
return static_cast<T*>(d->getData()) + (d->length++); ASMJIT_INLINE void prepend(Link* link) {
link->_next = _first;
if (_first == NULL)
_last = link;
_first = link;
} }
ASMJIT_INLINE void append(Link* link) {
link->_next = NULL;
if (_first == NULL)
_first = link;
else
_last->_next = link;
_last = link;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _first;
Link* _last;
}; };
//! \} //! \}
@@ -277,4 +347,4 @@ struct PodVector : PodVectorBase {
#include "../apiend.h" #include "../apiend.h"
// [Guard] // [Guard]
#endif // _ASMJIT_BASE_PODVECTOR_H #endif // _ASMJIT_BASE_CONTAINERS_H

View File

@@ -21,24 +21,25 @@
namespace asmjit { namespace asmjit {
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - Construction / Destruction] // [asmjit::Context - Construction / Destruction]
// ============================================================================ // ============================================================================
BaseContext::BaseContext(BaseCompiler* compiler) : Context::Context(Compiler* compiler) :
_compiler(compiler), _compiler(compiler),
_varMapToVaListOffset(0),
_baseZone(8192 - kZoneOverhead) { _baseZone(8192 - kZoneOverhead) {
BaseContext::reset(); Context::reset();
} }
BaseContext::~BaseContext() {} Context::~Context() {}
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - Reset] // [asmjit::Context - Reset]
// ============================================================================ // ============================================================================
void BaseContext::reset() { void Context::reset(bool releaseMemory) {
_baseZone.clear(); _baseZone.reset(releaseMemory);
_func = NULL; _func = NULL;
_start = NULL; _start = NULL;
@@ -48,7 +49,7 @@ void BaseContext::reset() {
_unreachableList.reset(); _unreachableList.reset();
_jccList.reset(); _jccList.reset();
_contextVd.clear(); _contextVd.reset(releaseMemory);
_memVarCells = NULL; _memVarCells = NULL;
_memStackCells = NULL; _memStackCells = NULL;
@@ -72,7 +73,7 @@ void BaseContext::reset() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - Mem] // [asmjit::Context - Mem]
// ============================================================================ // ============================================================================
static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) { static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) {
@@ -92,7 +93,7 @@ static ASMJIT_INLINE uint32_t BaseContext_getDefaultAlignment(uint32_t size) {
return 1; return 1;
} }
MemCell* BaseContext::_newVarCell(VarData* vd) { MemCell* Context::_newVarCell(VarData* vd) {
ASMJIT_ASSERT(vd->_memCell == NULL); ASMJIT_ASSERT(vd->_memCell == NULL);
MemCell* cell; MemCell* cell;
@@ -139,7 +140,7 @@ _NoMemory:
return NULL; return NULL;
} }
MemCell* BaseContext::_newStackCell(uint32_t size, uint32_t alignment) { MemCell* Context::_newStackCell(uint32_t size, uint32_t alignment) {
MemCell* cell = static_cast<MemCell*>(_baseZone.alloc(sizeof(MemCell))); MemCell* cell = static_cast<MemCell*>(_baseZone.alloc(sizeof(MemCell)));
if (cell == NULL) if (cell == NULL)
goto _NoMemory; goto _NoMemory;
@@ -185,7 +186,7 @@ _NoMemory:
return NULL; return NULL;
} }
Error BaseContext::resolveCellOffsets() { Error Context::resolveCellOffsets() {
MemCell* varCell = _memVarCells; MemCell* varCell = _memVarCells;
MemCell* stackCell = _memStackCells; MemCell* stackCell = _memStackCells;
@@ -265,10 +266,10 @@ Error BaseContext::resolveCellOffsets() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - RemoveUnreachableCode] // [asmjit::Context - RemoveUnreachableCode]
// ============================================================================ // ============================================================================
Error BaseContext::removeUnreachableCode() { Error Context::removeUnreachableCode() {
PodList<Node*>::Link* link = _unreachableList.getFirst(); PodList<Node*>::Link* link = _unreachableList.getFirst();
Node* stop = getStop(); Node* stop = getStop();
@@ -297,13 +298,211 @@ Error BaseContext::removeUnreachableCode() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - Cleanup] // [asmjit::Context - Liveness Analysis]
// ============================================================================ // ============================================================================
//! \internal //! \internal
//! struct LivenessTarget {
//! Translate the given function `func`. //! Previous target.
void BaseContext::cleanup() { LivenessTarget* prev;
//! Target node.
TargetNode* node;
//! Jumped from.
JumpNode* from;
};
Error Context::livenessAnalysis() {
FuncNode* func = getFunc();
JumpNode* from = NULL;
Node* node = func->getEnd();
uint32_t bLen = static_cast<uint32_t>(
((_contextVd.getLength() + VarBits::kEntityBits - 1) / VarBits::kEntityBits));
LivenessTarget* ltCur = NULL;
LivenessTarget* ltUnused = NULL;
size_t varMapToVaListOffset = _varMapToVaListOffset;
// No variables.
if (bLen == 0)
return kErrorOk;
VarBits* bCur = newBits(bLen);
if (bCur == NULL)
goto _NoMemory;
// Allocate bits for code visited first time.
_OnVisit:
for (;;) {
if (node->hasLiveness()) {
if (bCur->_addBitsDelSource(node->getLiveness(), bCur, bLen))
goto _OnPatch;
else
goto _OnDone;
}
VarBits* bTmp = copyBits(bCur, bLen);
if (bTmp == NULL)
goto _NoMemory;
node->setLiveness(bTmp);
VarMap* map = node->getMap();
if (map != NULL) {
uint32_t vaCount = map->getVaCount();
VarAttr* vaList = reinterpret_cast<VarAttr*>(((uint8_t*)map) + varMapToVaListOffset);
for (uint32_t i = 0; i < vaCount; i++) {
VarAttr* va = &vaList[i];
VarData* vd = va->getVd();
uint32_t flags = va->getFlags();
uint32_t ctxId = vd->getContextId();
if ((flags & kVarAttrOutAll) && !(flags & kVarAttrInAll)) {
// Write-Only.
bTmp->setBit(ctxId);
bCur->delBit(ctxId);
}
else {
// Read-Only or Read/Write.
bTmp->setBit(ctxId);
bCur->setBit(ctxId);
}
}
}
if (node->getType() == kNodeTypeTarget)
goto _OnTarget;
if (node == func)
goto _OnDone;
ASMJIT_ASSERT(node->getPrev());
node = node->getPrev();
}
// Patch already generated liveness bits.
_OnPatch:
for (;;) {
ASMJIT_ASSERT(node->hasLiveness());
VarBits* bNode = node->getLiveness();
if (!bNode->_addBitsDelSource(bCur, bLen))
goto _OnDone;
if (node->getType() == kNodeTypeTarget)
goto _OnTarget;
if (node == func)
goto _OnDone;
node = node->getPrev();
}
_OnTarget:
if (static_cast<TargetNode*>(node)->getNumRefs() != 0) {
// Push a new LivenessTarget onto the stack if needed.
if (ltCur == NULL || ltCur->node != node) {
// Allocate a new LivenessTarget object (from pool or zone).
LivenessTarget* ltTmp = ltUnused;
if (ltTmp != NULL) {
ltUnused = ltUnused->prev;
}
else {
ltTmp = _baseZone.allocT<LivenessTarget>(
sizeof(LivenessTarget) - sizeof(VarBits) + bLen * sizeof(uintptr_t));
if (ltTmp == NULL)
goto _NoMemory;
}
// Initialize and make current - ltTmp->from will be set later on.
ltTmp->prev = ltCur;
ltTmp->node = static_cast<TargetNode*>(node);
ltCur = ltTmp;
from = static_cast<TargetNode*>(node)->getFrom();
ASMJIT_ASSERT(from != NULL);
}
else {
from = ltCur->from;
goto _OnJumpNext;
}
// Visit/Patch.
do {
ltCur->from = from;
bCur->copyBits(node->getLiveness(), bLen);
if (!from->hasLiveness()) {
node = from;
goto _OnVisit;
}
// Issue #25: Moved '_OnJumpNext' here since it's important to patch
// code again if there are more live variables than before.
_OnJumpNext:
if (bCur->delBits(from->getLiveness(), bLen)) {
node = from;
goto _OnPatch;
}
from = from->getJumpNext();
} while (from != NULL);
// Pop the current LivenessTarget from the stack.
{
LivenessTarget* ltTmp = ltCur;
ltCur = ltCur->prev;
ltTmp->prev = ltUnused;
ltUnused = ltTmp;
}
}
bCur->copyBits(node->getLiveness(), bLen);
node = node->getPrev();
if (node->isJmp() || !node->isFetched())
goto _OnDone;
if (!node->hasLiveness())
goto _OnVisit;
if (bCur->delBits(node->getLiveness(), bLen))
goto _OnPatch;
_OnDone:
if (ltCur != NULL) {
node = ltCur->node;
from = ltCur->from;
goto _OnJumpNext;
}
return kErrorOk;
_NoMemory:
return setError(kErrorNoHeapMemory);
}
// ============================================================================
// [asmjit::Context - Schedule]
// ============================================================================
Error Context::schedule() {
// By default there is no instruction scheduler implemented.
return kErrorOk;
}
// ============================================================================
// [asmjit::Context - Cleanup]
// ============================================================================
void Context::cleanup() {
VarData** array = _contextVd.getData(); VarData** array = _contextVd.getData();
size_t length = _contextVd.getLength(); size_t length = _contextVd.getLength();
@@ -313,15 +512,15 @@ void BaseContext::cleanup() {
vd->resetRegIndex(); vd->resetRegIndex();
} }
_contextVd.clear(); _contextVd.reset(false);
_extraBlock = NULL; _extraBlock = NULL;
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseContext - CompileFunc] // [asmjit::Context - CompileFunc]
// ============================================================================ // ============================================================================
Error BaseContext::compile(FuncNode* func) { Error Context::compile(FuncNode* func) {
Node* end = func->getEnd(); Node* end = func->getEnd();
Node* stop = end->getNext(); Node* stop = end->getNext();
@@ -331,19 +530,24 @@ Error BaseContext::compile(FuncNode* func) {
ASMJIT_PROPAGATE_ERROR(fetch()); ASMJIT_PROPAGATE_ERROR(fetch());
ASMJIT_PROPAGATE_ERROR(removeUnreachableCode()); ASMJIT_PROPAGATE_ERROR(removeUnreachableCode());
ASMJIT_PROPAGATE_ERROR(analyze()); ASMJIT_PROPAGATE_ERROR(livenessAnalysis());
Compiler* compiler = getCompiler();
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGER)
if (_compiler->hasLogger()) if (compiler->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))
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
// it after compilation - some nodes may disappear and it's forbidden to add // it after compilation - some nodes may disappear and it's forbidden to add
// new code after the compilation is done. // new code after the compilation is done.
_compiler->_setCursor(NULL); compiler->_setCursor(NULL);
return kErrorOk; return kErrorOk;
} }

View File

@@ -20,40 +20,40 @@
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_tree //! \addtogroup asmjit_base_compiler
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::BaseContext] // [asmjit::Context]
// ============================================================================ // ============================================================================
//! \internal //! \internal
//! //!
//! Code generation context is the logic behind `BaseCompiler`. The context is //! Code generation context is the logic behind `Compiler`. The context is
//! used to compile the code stored in `BaseCompiler`. //! used to compile the code stored in `Compiler`.
struct BaseContext { struct Context {
ASMJIT_NO_COPY(BaseContext) ASMJIT_NO_COPY(Context)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
BaseContext(BaseCompiler* compiler); Context(Compiler* compiler);
virtual ~BaseContext(); virtual ~Context();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Reset]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Reset the whole context. //! Reset the whole context.
virtual void reset(); virtual void reset(bool releaseMemory = false);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get compiler. //! Get compiler.
ASMJIT_INLINE BaseCompiler* getCompiler() const { return _compiler; } ASMJIT_INLINE Compiler* getCompiler() const { return _compiler; }
//! Get function. //! Get function.
ASMJIT_INLINE FuncNode* getFunc() const { return _func; } ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
@@ -89,23 +89,24 @@ struct BaseContext {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get current state. //! Get current state.
ASMJIT_INLINE BaseVarState* getState() const { ASMJIT_INLINE VarState* getState() const {
return _state; return _state;
} }
//! Load current state from `target` state. //! Load current state from `target` state.
virtual void loadState(BaseVarState* src) = 0; virtual void loadState(VarState* src) = 0;
//! Save current state, returning new `BaseVarState` instance.
virtual BaseVarState* saveState() = 0; //! Save current state, returning new `VarState` instance.
virtual VarState* saveState() = 0;
//! Change the current state to `target` state. //! Change the current state to `target` state.
virtual void switchState(BaseVarState* src) = 0; virtual void switchState(VarState* src) = 0;
//! Change the current state to the intersection of two states `a` and `b`. //! Change the current state to the intersection of two states `a` and `b`.
virtual void intersectStates(BaseVarState* a, BaseVarState* b) = 0; virtual void intersectStates(VarState* a, VarState* b) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Mem] // [Context]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE Error _registerContextVar(VarData* vd) { ASMJIT_INLINE Error _registerContextVar(VarData* vd) {
@@ -169,7 +170,7 @@ struct BaseContext {
// [Analyze] // [Analyze]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Preform variable liveness analysis. //! Perform variable liveness analysis.
//! //!
//! Analysis phase iterates over nodes in reverse order and generates a bit //! Analysis phase iterates over nodes in reverse order and generates a bit
//! array describing variables that are alive at every node in the function. //! array describing variables that are alive at every node in the function.
@@ -179,7 +180,7 @@ struct BaseContext {
//! //!
//! When a label is found all jumps to that label are followed and analysis //! When a label is found all jumps to that label are followed and analysis
//! repeats until all variables are resolved. //! repeats until all variables are resolved.
virtual Error analyze() = 0; virtual Error livenessAnalysis();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Annotate] // [Annotate]
@@ -194,6 +195,12 @@ struct BaseContext {
//! Translate code by allocating registers and handling state changes. //! Translate code by allocating registers and handling state changes.
virtual Error translate() = 0; virtual Error translate() = 0;
// --------------------------------------------------------------------------
// [Schedule]
// --------------------------------------------------------------------------
virtual Error schedule();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Cleanup] // [Cleanup]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -210,20 +217,28 @@ struct BaseContext {
// [Serialize] // [Serialize]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
virtual Error serialize(BaseAssembler* assembler, Node* start, Node* stop) = 0; virtual Error serialize(Assembler* assembler, Node* start, Node* stop) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Compiler. //! Compiler.
BaseCompiler* _compiler; Compiler* _compiler;
//! Function. //! Function.
FuncNode* _func; FuncNode* _func;
//! Zone allocator. //! Zone allocator.
Zone _baseZone; 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. //! Start of the current active scope.
Node* _start; Node* _start;
//! End of the current active scope. //! End of the current active scope.
@@ -277,7 +292,7 @@ struct BaseContext {
uint32_t _annotationLength; uint32_t _annotationLength;
//! Current state (used by register allocator). //! Current state (used by register allocator).
BaseVarState* _state; VarState* _state;
}; };
//! \} //! \}

View File

@@ -30,10 +30,10 @@
namespace asmjit { namespace asmjit {
// ============================================================================ // ============================================================================
// [asmjit::BaseCpuInfo - DetectNumberOfCores] // [asmjit::CpuInfo - DetectNumberOfCores]
// ============================================================================ // ============================================================================
uint32_t BaseCpuInfo::detectNumberOfCores() { uint32_t CpuInfo::detectHwThreadsCount() {
#if defined(ASMJIT_OS_WINDOWS) #if defined(ASMJIT_OS_WINDOWS)
SYSTEM_INFO info; SYSTEM_INFO info;
::GetSystemInfo(&info); ::GetSystemInfo(&info);
@@ -51,22 +51,22 @@ uint32_t BaseCpuInfo::detectNumberOfCores() {
} }
// ============================================================================ // ============================================================================
// [asmjit::BaseCpuInfo - GetHost] // [asmjit::CpuInfo - GetHost]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64) #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
struct HostCpuInfo : public x86x64::CpuInfo { struct AutoX86CpuInfo : public X86CpuInfo {
ASMJIT_INLINE HostCpuInfo() : CpuInfo() { ASMJIT_INLINE AutoX86CpuInfo() : X86CpuInfo() {
x86x64::CpuUtil::detect(this); X86CpuUtil::detect(this);
} }
}; };
#else #else
#error "AsmJit - Unsupported CPU." #error "AsmJit - Unsupported CPU."
#endif // ASMJIT_HOST || ASMJIT_HOST_X64 #endif // ASMJIT_HOST || ASMJIT_HOST_X64
const BaseCpuInfo* BaseCpuInfo::getHost() { const CpuInfo* CpuInfo::getHost() {
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64) #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
static HostCpuInfo cpuInfo; static AutoX86CpuInfo cpuInfo;
#else #else
#error "AsmJit - Unsupported CPU." #error "AsmJit - Unsupported CPU."
#endif // ASMJIT_HOST || ASMJIT_HOST_X64 #endif // ASMJIT_HOST || ASMJIT_HOST_X64

View File

@@ -43,12 +43,12 @@ ASMJIT_ENUM(kCpuVendor) {
}; };
// ============================================================================ // ============================================================================
// [asmjit::BaseCpuInfo] // [asmjit::CpuInfo]
// ============================================================================ // ============================================================================
//! Base cpu information. //! Base cpu information.
struct BaseCpuInfo { struct CpuInfo {
ASMJIT_NO_COPY(BaseCpuInfo) ASMJIT_NO_COPY(CpuInfo)
//! \internal //! \internal
enum { enum {
@@ -59,7 +59,7 @@ struct BaseCpuInfo {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE BaseCpuInfo(uint32_t size = sizeof(BaseCpuInfo)) : _size(size) {} ASMJIT_INLINE CpuInfo(uint32_t size = sizeof(CpuInfo)) : _size(size) {}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
@@ -78,8 +78,9 @@ struct BaseCpuInfo {
ASMJIT_INLINE uint32_t getModel() const { return _model; } ASMJIT_INLINE uint32_t getModel() const { return _model; }
//! Get CPU stepping. //! Get CPU stepping.
ASMJIT_INLINE uint32_t getStepping() const { return _stepping; } ASMJIT_INLINE uint32_t getStepping() const { return _stepping; }
//! Get CPU cores count (or sum of all cores of all procesors).
ASMJIT_INLINE uint32_t getCoresCount() const { return _coresCount; } //! Get number of hardware threads available.
ASMJIT_INLINE uint32_t getHwThreadsCount() const { return _hwThreadsCount; }
//! Get whether CPU has a `feature`. //! Get whether CPU has a `feature`.
ASMJIT_INLINE bool hasFeature(uint32_t feature) const { ASMJIT_INLINE bool hasFeature(uint32_t feature) const {
@@ -90,7 +91,7 @@ struct BaseCpuInfo {
} }
//! Add a CPU `feature`. //! Add a CPU `feature`.
ASMJIT_INLINE BaseCpuInfo& addFeature(uint32_t feature) { ASMJIT_INLINE CpuInfo& addFeature(uint32_t feature) {
ASMJIT_ASSERT(feature < sizeof(_features) * 8); ASMJIT_ASSERT(feature < sizeof(_features) * 8);
_features[feature / kFeaturesPerUInt32] |= (1U << (feature % kFeaturesPerUInt32)); _features[feature / kFeaturesPerUInt32] |= (1U << (feature % kFeaturesPerUInt32));
@@ -102,10 +103,10 @@ struct BaseCpuInfo {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Detect number of cores (or sum of all cores of all processors). //! Detect number of cores (or sum of all cores of all processors).
static ASMJIT_API uint32_t detectNumberOfCores(); static ASMJIT_API uint32_t detectHwThreadsCount();
//! Get host cpu. //! Get host cpu.
static ASMJIT_API const BaseCpuInfo* getHost(); static ASMJIT_API const CpuInfo* getHost();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -127,8 +128,9 @@ struct BaseCpuInfo {
uint32_t _model; uint32_t _model;
//! Cpu stepping. //! Cpu stepping.
uint32_t _stepping; uint32_t _stepping;
//! Cpu cores count (or sum of all CPU cores of all processors).
uint32_t _coresCount; //! Number of hardware threads.
uint32_t _hwThreadsCount;
//! Cpu features bitfield. //! Cpu features bitfield.
uint32_t _features[4]; uint32_t _features[4];

View File

@@ -37,29 +37,42 @@ void ErrorHandler::release() {}
// [asmjit::ErrorUtil - AsString] // [asmjit::ErrorUtil - AsString]
// ============================================================================ // ============================================================================
static const char* errorMessages[] = { #if !defined(ASMJIT_DISABLE_NAMES)
"Ok", static const char errorMessages[] = {
"Ok\0"
"No heap memory", "No heap memory\0"
"No virtual memory", "No virtual memory\0"
"Invalid argument\0"
"Invalid argument", "Invalid state\0"
"Invalid state", "Unknown instruction\0"
"Illegal instruction\0"
"Unknown instruction", "Illegal addressing\0"
"Illegal instruction", "Illegal displacement\0"
"Illegal addressing", "Invalid function\0"
"Illegal displacement", "Overlapped arguments\0"
"Unknown error\0"
"Invalid function",
"Overlapped arguments",
"Unknown error"
}; };
const char* ErrorUtil::asString(Error e) { static const char* findPackedString(const char* p, uint32_t id, uint32_t maxId) {
return errorMessages[IntUtil::iMin<Error>(e, kErrorCount)]; uint32_t i = 0;
if (id > maxId)
id = maxId;
while (i < id) {
while (p[0])
p++;
p++;
} }
return p;
}
const char* ErrorUtil::asString(Error e) {
return findPackedString(errorMessages, e, kErrorCount);
}
#endif // ASMJIT_DISABLE_NAMES
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -109,7 +109,7 @@ typedef uint32_t Error;
//! Please note that `addRef` and `release` functions are used, but there is //! Please note that `addRef` and `release` functions are used, but there is
//! no reference counting implemented by default, reimplement to change the //! no reference counting implemented by default, reimplement to change the
//! default behavior. //! default behavior.
struct ErrorHandler { struct ASMJIT_VCLASS ErrorHandler {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -141,8 +141,8 @@ struct ErrorHandler {
//! Error handler (pure). //! Error handler (pure).
//! //!
//! Error handler is called when an error happened. An error can happen in //! Error handler is called when an error happened. An error can happen in
//! many places, but error handler is mostly used by `BaseAssembler` and //! many places, but error handler is mostly used by `Assembler` and
//! `BaseCompiler` classes to report anything that may cause incorrect code //! `Compiler` classes to report anything that may cause incorrect code
//! generation. There are multiple ways how the error handler can be used //! generation. There are multiple ways how the error handler can be used
//! and each has it's pros/cons. //! and each has it's pros/cons.
//! //!
@@ -151,23 +151,23 @@ struct ErrorHandler {
//! exceptions it is exception-safe and handleError() can report an incoming //! exceptions it is exception-safe and handleError() can report an incoming
//! error by throwing an exception of any type. It's guaranteed that the //! 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 //! exception won't be catched by AsmJit and will be propagated to the code
//! calling AsmJit `BaseAssembler` or `BaseCompiler` methods. Alternative to //! calling AsmJit `Assembler` or `Compiler` methods. Alternative to
//! throwing an exception is using `setjmp()` and `longjmp()` pair available //! throwing an exception is using `setjmp()` and `longjmp()` pair available
//! in the standard C library. //! in the standard C library.
//! //!
//! If the exception or setjmp() / longjmp() mechanism is used, the state of //! If the exception or setjmp() / longjmp() mechanism is used, the state of
//! the `BaseAssember` or `BaseCompiler` is unchanged and if it's possible the //! the `BaseAssember` or `Compiler` is unchanged and if it's possible the
//! execution (instruction serialization) can continue. However if the error //! execution (instruction serialization) can continue. However if the error
//! happened during any phase that translates or modifies the stored code //! happened during any phase that translates or modifies the stored code
//! (for example relocation done by `BaseAssembler` or analysis/translation //! (for example relocation done by `Assembler` or analysis/translation
//! done by `BaseCompiler`) the execution can't continue and the error will //! done by `Compiler`) the execution can't continue and the error will
//! be also stored in `BaseAssembler` or `BaseCompiler`. //! be also stored in `Assembler` or `Compiler`.
//! //!
//! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used, //! Finally, if no exceptions nor setjmp() / longjmp() mechanisms were used,
//! you can still implement a compatible handling by returning from your //! you can still implement a compatible handling by returning from your
//! error handler. Returning `true` means that error was reported and AsmJit //! error handler. Returning `true` means that error was reported and AsmJit
//! should continue execution, but `false` sets the rror immediately to the //! should continue execution, but `false` sets the rror immediately to the
//! `BaseAssembler` or `BaseCompiler` and execution shouldn't continue (this //! `Assembler` or `Compiler` and execution shouldn't continue (this
//! is the default behavior in case no error handler is used). //! is the default behavior in case no error handler is used).
virtual bool handleError(Error code, const char* message) = 0; virtual bool handleError(Error code, const char* message) = 0;
}; };
@@ -178,8 +178,10 @@ struct ErrorHandler {
//! Error utilities. //! Error utilities.
struct ErrorUtil { struct ErrorUtil {
#if !defined(ASMJIT_DISABLE_NAMES)
//! Get printable version of AsmJit `kError` code. //! Get printable version of AsmJit `kError` code.
static ASMJIT_API const char* asString(Error code); static ASMJIT_API const char* asString(Error code);
#endif // ASMJIT_DISABLE_NAMES
}; };
//! \} //! \}

View File

@@ -1,20 +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/func.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
} // asmjit namespace
// [Api-End]
#include "../apiend.h"

View File

@@ -1,651 +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_FUNC_H
#define _ASMJIT_BASE_FUNC_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_tree
//! \{
// ============================================================================
// [asmjit::kFuncConv]
// ============================================================================
//! Function calling convention.
//!
//! For a platform specific calling conventions, see:
//! - `x86x64::kFuncConv` - X86/X64 calling conventions.
ASMJIT_ENUM(kFuncConv) {
//! Calling convention is invalid (can't be used).
kFuncConvNone = 0
};
// ============================================================================
// [asmjit::kFuncHint]
// ============================================================================
//! Function hints.
//!
//! For a platform specific calling conventions, see:
//! - `x86x64::kFuncHint` - X86/X64 function hints.
ASMJIT_ENUM(kFuncHint) {
//! Make a naked function (default true).
//!
//! Naked function is function without using standard prolog/epilog sequence).
//!
//! X86/X64 Specific
//! ----------------
//!
//! Standard prolog sequence is:
//!
//! ~~~
//! push zbp
//! mov zsp, zbp
//! sub zsp, StackAdjustment
//! ~~~
//!
//! which is an equivalent to:
//!
//! ~~~
//! enter StackAdjustment, 0
//! ~~~
//!
//! Standard epilog sequence is:
//!
//! ~~~
//! mov zsp, zbp
//! pop zbp
//! ~~~
//!
//! which is an equavalent to:
//!
//! ~~~
//! leave
//! ~~~
//!
//! Naked functions can omit the prolog/epilog sequence. The advantage of
//! doing such modification is that EBP/RBP register can be used by the
//! register allocator which can result in less spills/allocs.
kFuncHintNaked = 0,
//! Generate compact function prolog/epilog if possible.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Use shorter, but possible slower prolog/epilog sequence to save/restore
//! registers.
kFuncHintCompact = 1
};
// ============================================================================
// [asmjit::kFuncFlags]
// ============================================================================
//! Function flags.
//!
//! For a platform specific calling conventions, see:
//! - `x86x64::kFuncFlags` - X86/X64 function flags.
ASMJIT_ENUM(kFuncFlags) {
//! Whether the function is using naked (minimal) prolog / epilog.
kFuncFlagIsNaked = 0x00000001,
//! Whether an another function is called from this function.
kFuncFlagIsCaller = 0x00000002,
//! Whether the stack is not aligned to the required stack alignment,
//! thus it has to be aligned manually.
kFuncFlagIsStackMisaligned = 0x00000004,
//! Whether the stack pointer is adjusted by the stack size needed
//! to save registers and function variables.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Stack pointer (ESP/RSP) is adjusted by 'sub' instruction in prolog and by
//! 'add' instruction in epilog (only if function is not naked). If function
//! needs to perform manual stack alignment more instructions are used to
//! adjust the stack (like "and zsp, -Alignment").
kFuncFlagIsStackAdjusted = 0x00000008,
//! Whether the function is finished using `BaseCompiler::endFunc()`.
kFuncFlagIsFinished = 0x80000000
};
// ============================================================================
// [asmjit::kFuncDir]
// ============================================================================
//! Function arguments direction.
ASMJIT_ENUM(kFuncDir) {
//! Arguments are passed left to right.
//!
//! This arguments direction is unusual in C, however it's used in Pascal.
kFuncDirLtr = 0,
//! Arguments are passed right ro left
//!
//! This is the default argument direction in C.
kFuncDirRtl = 1
};
// ============================================================================
// [asmjit::kFuncArg]
// ============================================================================
//! Function argument (lo/hi) specification.
ASMJIT_ENUM(kFuncArg) {
//! Maxumum number of function arguments supported by AsmJit.
kFuncArgCount = 16,
//! Extended maximum number of arguments (used internally).
kFuncArgCountLoHi = kFuncArgCount * 2,
//! Index to the LO part of function argument (default).
//!
//! This value is typically omitted and added only if there is HI argument
//! accessed.
kFuncArgLo = 0,
//! Index to the HI part of function argument.
//!
//! HI part of function argument depends on target architecture. On x86 it's
//! typically used to transfer 64-bit integers (they form a pair of 32-bit
//! integers).
kFuncArgHi = kFuncArgCount
};
// ============================================================================
// [asmjit::kFuncRet]
// ============================================================================
//! Function return value (lo/hi) specification.
ASMJIT_ENUM(kFuncRet) {
//! Index to the LO part of function return value.
kFuncRetLo = 0,
//! Index to the HI part of function return value.
kFuncRetHi = 1
};
// ============================================================================
// [asmjit::kFuncStackInvalid]
// ============================================================================
enum kFuncMisc {
//! Invalid stack offset in function or function parameter.
kFuncStackInvalid = -1
};
// ============================================================================
// [asmjit::FnTypeId]
// ============================================================================
//! Function builder 'void' type.
struct FnVoid {};
//! Function builder 'int8_t' type.
struct FnInt8 {};
//! Function builder 'uint8_t' type.
struct FnUInt8 {};
//! Function builder 'int16_t' type.
struct FnInt16 {};
//! Function builder 'uint16_t' type.
struct FnUInt16 {};
//! Function builder 'int32_t' type.
struct FnInt32 {};
//! Function builder 'uint32_t' type.
struct FnUInt32 {};
//! Function builder 'int64_t' type.
struct FnInt64 {};
//! Function builder 'uint64_t' type.
struct FnUInt64 {};
//! Function builder 'intptr_t' type.
struct FnIntPtr {};
//! Function builder 'uintptr_t' type.
struct FnUIntPtr {};
//! Function builder 'float' type.
struct FnFloat {};
//! Function builder 'double' type.
struct FnDouble {};
#if !defined(ASMJIT_DOCGEN)
template<typename T>
struct FnTypeId;
#define ASMJIT_DECLARE_TYPE_CORE(_PtrId_) \
template<typename T> \
struct TypeId { enum { kId = static_cast<int>(::asmjit::kVarTypeInvalid) }; }; \
\
template<typename T> \
struct TypeId<T*> { enum { kId = _PtrId_ }; }
#define ASMJIT_DECLARE_TYPE_ID(_T_, _Id_) \
template<> \
struct TypeId<_T_> { enum { kId = _Id_ }; }
ASMJIT_DECLARE_TYPE_CORE(kVarTypeIntPtr);
ASMJIT_DECLARE_TYPE_ID(void, kVarTypeInvalid);
ASMJIT_DECLARE_TYPE_ID(FnVoid, kVarTypeInvalid);
ASMJIT_DECLARE_TYPE_ID(int8_t, kVarTypeInt8);
ASMJIT_DECLARE_TYPE_ID(FnInt8, kVarTypeInt8);
ASMJIT_DECLARE_TYPE_ID(uint8_t, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(FnUInt8, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(int16_t, kVarTypeInt16);
ASMJIT_DECLARE_TYPE_ID(FnInt16, kVarTypeInt16);
ASMJIT_DECLARE_TYPE_ID(uint16_t, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(FnUInt16, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(int32_t, kVarTypeInt32);
ASMJIT_DECLARE_TYPE_ID(FnInt32, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(uint32_t, kVarTypeUInt32);
ASMJIT_DECLARE_TYPE_ID(FnUInt32, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(int64_t, kVarTypeInt64);
ASMJIT_DECLARE_TYPE_ID(FnInt64, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(uint64_t, kVarTypeUInt64);
ASMJIT_DECLARE_TYPE_ID(FnUInt64, kVarTypeUInt8);
ASMJIT_DECLARE_TYPE_ID(float, kVarTypeFp32);
ASMJIT_DECLARE_TYPE_ID(FnFloat, kVarTypeFp32);
ASMJIT_DECLARE_TYPE_ID(double, kVarTypeFp64);
ASMJIT_DECLARE_TYPE_ID(FnDouble, kVarTypeFp64);
#endif // !ASMJIT_DOCGEN
// ============================================================================
// [asmjit::FuncInOut]
// ============================================================================
//! Function in/out - argument or return value translated from `FuncPrototype`.
struct FuncInOut {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t getVarType() const { return _varType; }
ASMJIT_INLINE bool hasRegIndex() const { return _regIndex != kInvalidReg; }
ASMJIT_INLINE uint32_t getRegIndex() const { return _regIndex; }
ASMJIT_INLINE bool hasStackOffset() const { return _stackOffset != kFuncStackInvalid; }
ASMJIT_INLINE int32_t getStackOffset() const { return static_cast<int32_t>(_stackOffset); }
//! Get whether the argument / return value is assigned.
ASMJIT_INLINE bool isSet() const {
return (_regIndex != kInvalidReg) | (_stackOffset != kFuncStackInvalid);
}
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
//! Reset the function argument to "unassigned state".
ASMJIT_INLINE void reset() { _packed = 0xFFFFFFFF; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
//! Variable type, see `kVarType`.
uint8_t _varType;
//! Register index if argument / return value is a register.
uint8_t _regIndex;
//! Stack offset if argument / return value is on the stack.
int16_t _stackOffset;
};
//! All members packed into single 32-bit integer.
uint32_t _packed;
};
};
// ============================================================================
// [asmjit::FuncPrototype]
// ============================================================================
//! Function prototype.
//!
//! Function prototype contains information about function return type, count
//! of arguments and their types. Function prototype is a low level structure
//! which doesn't contain platform specific or calling convention specific
//! information. Function prototype is used to create a `FuncDecl`.
struct FuncPrototype {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function return value.
ASMJIT_INLINE uint32_t getRet() const { return _ret; }
//! Get function arguments' IDs.
ASMJIT_INLINE const uint32_t* getArgList() const { return _argList; }
//! Get count of function arguments.
ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
//! Get argument at index `id`.
ASMJIT_INLINE uint32_t getArg(uint32_t id) const {
ASMJIT_ASSERT(id < _argCount);
return _argList[id];
}
//! Set function definition - return type and arguments.
ASMJIT_INLINE void _setPrototype(uint32_t ret, const uint32_t* argList, uint32_t argCount) {
_ret = ret;
_argList = argList;
_argCount = argCount;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _ret;
uint32_t _argCount;
const uint32_t* _argList;
};
// ============================================================================
// [asmjit::FuncDecl]
// ============================================================================
//! Function declaration.
struct FuncDecl {
// --------------------------------------------------------------------------
// [Accessors - Calling Convention]
// --------------------------------------------------------------------------
//! Get function calling convention, see `kFuncConv`.
ASMJIT_INLINE uint32_t getConvention() const { return _convention; }
//! Get whether the callee pops the stack.
ASMJIT_INLINE uint32_t getCalleePopsStack() const { return _calleePopsStack; }
//! Get direction of arguments passed on the stack.
//!
//! Direction should be always `kFuncDirRtl`.
//!
//! \note This is related to used calling convention, it's not affected by
//! number of function arguments or their types.
ASMJIT_INLINE uint32_t getDirection() const { return _direction; }
//! Get stack size needed for function arguments passed on the stack.
ASMJIT_INLINE uint32_t getArgStackSize() const { return _argStackSize; }
//! Get size of "Red Zone".
ASMJIT_INLINE uint32_t getRedZoneSize() const { return _redZoneSize; }
//! Get size of "Spill Zone".
ASMJIT_INLINE uint32_t getSpillZoneSize() const { return _spillZoneSize; }
// --------------------------------------------------------------------------
// [Accessors - Arguments and Return]
// --------------------------------------------------------------------------
//! Get whether the function has a return value.
ASMJIT_INLINE bool hasRet() const { return _retCount != 0; }
//! Get count of function return values.
ASMJIT_INLINE uint32_t getRetCount() const { return _retCount; }
//! Get function return value.
ASMJIT_INLINE FuncInOut& getRet(uint32_t index = kFuncRetLo) { return _retList[index]; }
//! Get function return value.
ASMJIT_INLINE const FuncInOut& getRet(uint32_t index = kFuncRetLo) const { return _retList[index]; }
//! Get count of function arguments.
ASMJIT_INLINE uint32_t getArgCount() const { return _argCount; }
//! Get function arguments array.
ASMJIT_INLINE FuncInOut* getArgList() { return _argList; }
//! Get function arguments array (const).
ASMJIT_INLINE const FuncInOut* getArgList() const { return _argList; }
//! Get function argument at index `index`.
ASMJIT_INLINE FuncInOut& getArg(size_t index) {
ASMJIT_ASSERT(index < kFuncArgCountLoHi);
return _argList[index];
}
//! Get function argument at index `index`.
ASMJIT_INLINE const FuncInOut& getArg(size_t index) const {
ASMJIT_ASSERT(index < kFuncArgCountLoHi);
return _argList[index];
}
ASMJIT_INLINE void resetArg(size_t index) {
ASMJIT_ASSERT(index < kFuncArgCountLoHi);
_argList[index].reset();
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Calling convention.
uint8_t _convention;
//! Whether a callee pops stack.
uint8_t _calleePopsStack : 1;
//! Direction for arguments passed on the stack, see `kFuncDir`.
uint8_t _direction : 1;
//! Reserved #0 (alignment).
uint8_t _reserved0 : 6;
//! Count of arguments in `_argList`.
uint8_t _argCount;
//! Count of return value(s).
uint8_t _retCount;
//! Count of bytes consumed by arguments on the stack (aligned).
uint32_t _argStackSize;
//! Size of "Red Zone".
//!
//! \note Used by AMD64-ABI (128 bytes).
uint16_t _redZoneSize;
//! Size of "Spill Zone".
//!
//! \note Used by WIN64-ABI (32 bytes).
uint16_t _spillZoneSize;
//! Function arguments (including HI arguments) mapped to physical
//! registers and stack offset.
FuncInOut _argList[kFuncArgCountLoHi];
//! Function return value(s).
FuncInOut _retList[2];
};
// ============================================================================
// [asmjit::FuncBuilderX]
// ============================================================================
//! Custom function builder for up to 32 function arguments.
struct FuncBuilderX : public FuncPrototype {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE FuncBuilderX() {
_setPrototype(kVarTypeInvalid, _builderArgList, 0);
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Set return type to `retType`.
ASMJIT_INLINE void setRet(uint32_t retType) {
_ret = retType;
}
ASMJIT_INLINE void setArg(uint32_t id, uint32_t type) {
ASMJIT_ASSERT(id < _argCount);
_builderArgList[id] = type;
}
ASMJIT_INLINE void addArg(uint32_t type) {
ASMJIT_ASSERT(_argCount < kFuncArgCount);
_builderArgList[_argCount++] = type;
}
template<typename T>
ASMJIT_INLINE void setRetT() {
setRet(TypeId<T>::kId);
}
template<typename T>
ASMJIT_INLINE void setArgT(uint32_t id) {
setArg(id, TypeId<T>::kId);
}
template<typename T>
ASMJIT_INLINE void addArgT() {
addArg(TypeId<T>::kId);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _builderArgList[kFuncArgCount];
};
//! \internal
#define _TID(_T_) TypeId<_T_>::kId
//! Function builder (no args).
template<typename RET>
struct FuncBuilder0 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder0() {
_setPrototype(_TID(RET), NULL, 0);
}
};
//! Function builder (1 argument).
template<typename RET, typename P0>
struct FuncBuilder1 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder1() {
static const uint32_t args[] = { _TID(P0) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (2 arguments).
template<typename RET, typename P0, typename P1>
struct FuncBuilder2 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder2() {
static const uint32_t args[] = { _TID(P0), _TID(P1) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (3 arguments).
template<typename RET, typename P0, typename P1, typename P2>
struct FuncBuilder3 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder3() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (4 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3>
struct FuncBuilder4 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder4() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (5 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4>
struct FuncBuilder5 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder5() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (6 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5>
struct FuncBuilder6 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder6() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (7 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6>
struct FuncBuilder7 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder7() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (8 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7>
struct FuncBuilder8 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder8() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2),_TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (9 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8>
struct FuncBuilder9 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder9() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7), _TID(P8) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
//! Function builder (10 arguments).
template<typename RET, typename P0, typename P1, typename P2, typename P3, typename P4, typename P5, typename P6, typename P7, typename P8, typename P9>
struct FuncBuilder10 : public FuncPrototype {
ASMJIT_INLINE FuncBuilder10() {
static const uint32_t args[] = { _TID(P0), _TID(P1), _TID(P2), _TID(P3), _TID(P4), _TID(P5), _TID(P6), _TID(P7), _TID(P8), _TID(P9) };
_setPrototype(_TID(RET), args, ASMJIT_ARRAY_SIZE(args));
}
};
#undef _TID
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_FUNC_H

View File

@@ -37,6 +37,8 @@ ASMJIT_ENUM(kGlobals) {
//! Invalid register index. //! Invalid register index.
kInvalidReg = 0xFF, kInvalidReg = 0xFF,
//! Invalid variable type.
kInvalidVar = 0xFF,
//! Host memory allocator overhead. //! Host memory allocator overhead.
//! //!

View File

@@ -74,9 +74,13 @@ struct Lock {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get handle. //! Get handle.
ASMJIT_INLINE Handle& getHandle() { return _handle; } ASMJIT_INLINE Handle& getHandle() {
return _handle;
}
//! \overload //! \overload
ASMJIT_INLINE const Handle& getHandle() const { return _handle; } ASMJIT_INLINE const Handle& getHandle() const {
return _handle;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]

View File

@@ -70,7 +70,7 @@ ASMJIT_ENUM(kLoggerStyle) {
//! //!
//! 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 Logger { struct ASMJIT_VCLASS Logger {
ASMJIT_NO_COPY(Logger) ASMJIT_NO_COPY(Logger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -117,11 +117,17 @@ struct Logger {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get indentation. //! Get indentation.
ASMJIT_INLINE const char* getIndentation() const { return _indentation; } ASMJIT_INLINE const char* getIndentation() const {
return _indentation;
}
//! Set indentation. //! Set indentation.
ASMJIT_API void setIndentation(const char* indentation); ASMJIT_API void setIndentation(const char* indentation);
//! Reset indentation. //! Reset indentation.
ASMJIT_INLINE void resetIndentation() { setIndentation(NULL); } ASMJIT_INLINE void resetIndentation() {
setIndentation(NULL);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -139,7 +145,7 @@ struct Logger {
// ============================================================================ // ============================================================================
//! Logger that can log to standard C `FILE*` stream. //! Logger that can log to standard C `FILE*` stream.
struct FileLogger : public Logger { struct ASMJIT_VCLASS FileLogger : public Logger {
ASMJIT_NO_COPY(FileLogger) ASMJIT_NO_COPY(FileLogger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -184,7 +190,7 @@ struct FileLogger : public Logger {
// ============================================================================ // ============================================================================
//! String logger. //! String logger.
struct StringLogger : public Logger { struct ASMJIT_VCLASS StringLogger : public Logger {
ASMJIT_NO_COPY(StringLogger) ASMJIT_NO_COPY(StringLogger)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -205,10 +211,14 @@ struct StringLogger : public Logger {
//! string. //! string.
//! //!
//! The pointer is owned by `StringLogger`, it can't be modified or freed. //! The pointer is owned by `StringLogger`, it can't be modified or freed.
ASMJIT_INLINE const char* getString() const { return _stringBuilder.getData(); } ASMJIT_INLINE const char* getString() const {
return _stringBuilder.getData();
}
//! Clear the resulting string. //! Clear the resulting string.
ASMJIT_INLINE void clearString() { _stringBuilder.clear(); } ASMJIT_INLINE void clearString() {
_stringBuilder.clear();
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Logging] // [Logging]

View File

@@ -8,7 +8,7 @@
#define ASMJIT_EXPORTS #define ASMJIT_EXPORTS
// [Dependencies - AsmJit] // [Dependencies - AsmJit]
#include "../base/operand.h" #include "../base/globals.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -19,7 +19,19 @@ namespace asmjit {
// [asmjit::Operand] // [asmjit::Operand]
// ============================================================================ // ============================================================================
const Operand noOperand; // Prevent static initialization.
struct Operand {
uint8_t op;
uint8_t size;
uint8_t reserved_2_1;
uint8_t reserved_3_1;
uint32_t id;
uint32_t reserved_8_4;
uint32_t reserved_12_4;
};
ASMJIT_VAR const Operand noOperand;
const Operand noOperand = { 0, 0, 0, 0, kInvalidValue, 0, 0 };
} // asmjit namespace } // asmjit namespace

View File

@@ -20,8 +20,8 @@ namespace asmjit {
// [Forward Declarations] // [Forward Declarations]
// ============================================================================ // ============================================================================
struct BaseAssembler; struct Assembler;
struct BaseCompiler; struct Compiler;
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base_general
//! \{ //! \{
@@ -52,7 +52,7 @@ ASMJIT_ENUM(kOperandType) {
//! Operand id masks used to determine the operand type. //! Operand id masks used to determine the operand type.
ASMJIT_ENUM(kOperandId) { ASMJIT_ENUM(kOperandId) {
//! Operand id refers to `BaseVar`. //! Operand id refers to `Var`.
kOperandIdVar = 0x80000000U, kOperandIdVar = 0x80000000U,
//! Operand id to real index mask. //! Operand id to real index mask.
kOperandIdNum = 0x7FFFFFFFU kOperandIdNum = 0x7FFFFFFFU
@@ -64,11 +64,8 @@ ASMJIT_ENUM(kOperandId) {
//! Register class. //! Register class.
ASMJIT_ENUM(kRegClass) { ASMJIT_ENUM(kRegClass) {
//! Gp register class (any architecture). //! Gp register class, compatible with all architectures.
kRegClassGp = 0, kRegClassGp = 0
//! Invalid register class.
kRegClassInvalid = 0xFF
}; };
// ============================================================================ // ============================================================================
@@ -102,7 +99,7 @@ ASMJIT_ENUM(kMemType) {
//! Memory operand is a combination of base register and optional index register //! Memory operand is a combination of base register and optional index register
//! and displacement. //! and displacement.
//! //!
//! The `BaseAssembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex` //! The `Assembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex`
//! types the same way, but `Compiler` interprets `kMemTypeBaseIndex` as //! types the same way, but `Compiler` interprets `kMemTypeBaseIndex` as
//! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`. //! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
kMemTypeBaseIndex = 0, kMemTypeBaseIndex = 0,
@@ -110,8 +107,8 @@ ASMJIT_ENUM(kMemType) {
//! Memory operand is a combination of variable's memory location, //! Memory operand is a combination of variable's memory location,
//! optional index register and displacement. //! optional index register and displacement.
//! //!
//! The `BaseAssembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex` //! The `Assembler` interprets `kMemTypeBaseIndex` and `kMemTypeStackIndex`
//! types in the same way, but `BaseCompiler` interprets `kMemTypeBaseIndex` as //! types in the same way, but `Compiler` interprets `kMemTypeBaseIndex` as
//! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`. //! `[base + index]` and `kMemTypeStackIndex` as `[stack(base) + index]`.
kMemTypeStackIndex = 1, kMemTypeStackIndex = 1,
@@ -124,52 +121,6 @@ ASMJIT_ENUM(kMemType) {
kMemTypeAbsolute = 3 kMemTypeAbsolute = 3
}; };
// ============================================================================
// [asmjit::kVarType]
// ============================================================================
ASMJIT_ENUM(kVarType) {
//! 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`, not compatible with host `intptr_t`.
kVarTypeIntPtr = 8,
//! Variable is target `uintptr_t`, not compatible with host `uintptr_t`.
kVarTypeUIntPtr = 9,
//! Variable is 32-bit floating point (single precision).
kVarTypeFp32 = 10,
//! Variable is 64-bit floating point (double precision).
kVarTypeFp64 = 11,
//! Invalid variable type.
kVarTypeInvalid = 0xFF,
//! \internal
_kVarTypeIntStart = kVarTypeInt8,
//! \internal
_kVarTypeIntEnd = kVarTypeUIntPtr,
//! \internal
_kVarTypeFpStart = kVarTypeFp32,
//! \internal
_kVarTypeFpEnd = kVarTypeFp64
};
// ============================================================================ // ============================================================================
// [asmjit::Operand] // [asmjit::Operand]
// ============================================================================ // ============================================================================
@@ -180,19 +131,6 @@ struct Operand {
// [Structs] // [Structs]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// \internal
//
// Register operand structure, allows to do register initialization at
// compile time instead of doing it "non-deterministically" at runtime.
struct InitRegOp {
uint8_t op;
uint8_t size;
uint16_t code;
uint32_t id;
uint32_t vType;
uint32_t vUnused;
};
//! \internal //! \internal
//! //!
//! Base operand data. //! Base operand data.
@@ -201,15 +139,20 @@ struct Operand {
uint8_t op; uint8_t op;
//! Size of operand (register, address, immediate, or variable). //! Size of operand (register, address, immediate, or variable).
uint8_t size; uint8_t size;
//! Flags, each operand uses this byte for something else. //! \internal
uint8_t reserved0; uint8_t reserved_2_1;
//! Reserved (not used). //! \internal
uint8_t reserved1; uint8_t reserved_3_1;
//! Operand id, identifier used by `BaseAssembler` and `BaseCompiler`. //! Operand id, identifier used by `Assembler` and `Compiler`.
//! //!
//! \note Uninitialized operand has always set id to `kInvalidValue`. //! \note Uninitialized operand has always set id to `kInvalidValue`.
uint32_t id; uint32_t id;
//! \internal
uint32_t reserved_8_4;
//! \internal
uint32_t reserved_12_4;
}; };
//! \internal //! \internal
@@ -241,15 +184,24 @@ struct Operand {
}; };
}; };
//! Variable id, used by `BaseCompiler` to identify variables. //! Variable id, used by `Compiler` to identify variables.
uint32_t id; uint32_t id;
union {
struct {
//! Variable type. //! Variable type.
uint32_t vType; uint32_t vType;
//! \internal
uint32_t reserved_12_4;
};
//! \internal //! \internal
//! //!
//! Unused. //! This is not needed or used, it's just to force compiler to always
uint32_t vUnused; //! align this struct to 8-bytes (so the struct is compatible to others
//! when it comes to alignment). It should fix VS linker warning as well.
uint64_t reserved8_8;
};
}; };
//! \internal //! \internal
@@ -263,7 +215,7 @@ struct Operand {
//! Type of the memory operand, see `kMemType`. //! Type of the memory operand, see `kMemType`.
uint8_t type; uint8_t type;
//! X86/X64 layout: //! X86/X64 layout:
//! - segment [3 bits], see `x86x64::kSeg`. //! - segment [3 bits], see `kX86Seg`.
//! - shift [2 bits], index register shift (0 to 3). //! - shift [2 bits], index register shift (0 to 3).
uint8_t flags; uint8_t flags;
@@ -283,12 +235,12 @@ struct Operand {
uint8_t op; uint8_t op;
//! Size of immediate (or 0 to autodetect). //! Size of immediate (or 0 to autodetect).
uint8_t size; uint8_t size;
//! Reserved (not used). //! \internal
uint8_t reserved0; uint8_t reserved_2_1;
//! Reserved (not used). //! \internal
uint8_t reserved1; uint8_t reserved_3_1;
//! Operand id, always set to `kInvalidValue`. //! Operand id, always set to `kInvalidValue` (immediates don't have IDs).
uint32_t id; uint32_t id;
union { union {
@@ -325,15 +277,21 @@ struct Operand {
struct LabelOp { struct LabelOp {
//! Type of operand, `kOperandTypeLabel`. //! Type of operand, `kOperandTypeLabel`.
uint8_t op; uint8_t op;
//! Reserved (not used). //! Always zero, labels don't have size.
uint8_t size; uint8_t size;
//! Reserved (not used). //! \internal
uint8_t reserved0; uint8_t reserved_2_1;
//! Reserved (not used). //! \internal
uint8_t reserved1; uint8_t reserved_3_1;
//! Operand id. //! Operand id (`kInvalidValue` if the label is not initialized by code
//! generator).
uint32_t id; uint32_t id;
//! \internal
uint32_t reserved_8_4;
//! \internal
uint32_t reserved_12_4;
}; };
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -407,10 +365,14 @@ struct Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
template<typename T> template<typename T>
ASMJIT_INLINE T& getData() { return reinterpret_cast<T&>(_base); } ASMJIT_INLINE T& getData() {
return reinterpret_cast<T&>(_base);
}
template<typename T> template<typename T>
ASMJIT_INLINE const T& getData() const { return reinterpret_cast<const T&>(_base); } ASMJIT_INLINE const T& getData() const {
return reinterpret_cast<const T&>(_base);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Type] // [Type]
@@ -436,6 +398,16 @@ struct Operand {
// [Type - Combined] // [Type - Combined]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get register type.
ASMJIT_INLINE uint32_t getRegType() const {
return _vreg.type;
}
//! Get register index.
ASMJIT_INLINE uint32_t getRegIndex() const {
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] & IntUtil::pack32_2x8_1x16(0xFF, 0, 0xFF00)) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 0, (type << 8));
@@ -465,7 +437,9 @@ struct Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get size of the operand in bytes. //! Get size of the operand in bytes.
ASMJIT_INLINE uint32_t getSize() const { return _base.size; } ASMJIT_INLINE uint32_t getSize() const {
return _base.size;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Id] // [Id]
@@ -473,11 +447,13 @@ struct Operand {
//! Get operand id. //! Get operand id.
//! //!
//! Operand id's are used internally by `BaseAssembler` and `BaseCompiler`. //! Operand id's are used internally by `Assembler` and `Compiler`.
//! //!
//! 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 { return _base.id; } ASMJIT_INLINE uint32_t getId() const {
return _base.id;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -521,7 +497,7 @@ struct OperandUtil {
return id & 0x7FFFFFFFU; return id & 0x7FFFFFFFU;
} }
//! Get whether the id refers to `BaseVar`. //! Get whether the id refers to `Var`.
//! //!
//! \note The function will never return `true` if the id is `kInvalidValue`. //! \note The function will never return `true` if the id is `kInvalidValue`.
//! The trick is to compare a given id to -1 (kInvalidValue) so we check both //! The trick is to compare a given id to -1 (kInvalidValue) so we check both
@@ -539,39 +515,44 @@ struct OperandUtil {
}; };
// ============================================================================ // ============================================================================
// [asmjit::BaseReg] // [asmjit::Reg]
// ============================================================================ // ============================================================================
//! Base class for all register operands. //! Base class for all register operands.
struct BaseReg : public Operand { struct Reg : public Operand {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a dummy base register. //! Create a dummy base register.
ASMJIT_INLINE BaseReg() : Operand(NoInit) { ASMJIT_INLINE Reg() : Operand(NoInit) {
_init_packed_op_sz_w0_id(kOperandTypeReg, 0, (kInvalidReg << 8) + kInvalidReg, kInvalidValue); _init_packed_op_sz_w0_id(kOperandTypeReg, 0, (kInvalidReg << 8) + kInvalidReg, kInvalidValue);
_init_packed_d2_d3(kVarTypeInvalid, 0); _init_packed_d2_d3(kInvalidVar, 0);
} }
//! Create a new base register. //! Create a new base register.
ASMJIT_INLINE BaseReg(uint32_t type, uint32_t index, uint32_t size) : Operand(NoInit) { ASMJIT_INLINE Reg(uint32_t type, uint32_t index, uint32_t size) : Operand(NoInit) {
_init_packed_op_sz_w0_id(kOperandTypeReg, size, (type << 8) + index, kInvalidValue); _init_packed_op_sz_w0_id(kOperandTypeReg, size, (type << 8) + index, kInvalidValue);
_init_packed_d2_d3(kVarTypeInvalid, 0); _init_packed_d2_d3(kInvalidVar, 0);
} }
//! Create a new reference to `other`. //! Create a new reference to `other`.
ASMJIT_INLINE BaseReg(const BaseReg& other) : Operand(other) {} ASMJIT_INLINE Reg(const Reg& other) : Operand(other) {}
explicit ASMJIT_INLINE BaseReg(const _NoInit&) : Operand(NoInit) {} //! Create a new reference to `other` and change the index to `index`.
ASMJIT_INLINE Reg(const Reg& other, uint32_t index) : Operand(other) {
_vreg.index = static_cast<uint8_t>(index);
}
explicit ASMJIT_INLINE Reg(const _NoInit&) : Operand(NoInit) {}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [BaseReg Specific] // [Reg Specific]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Clone `BaseReg` operand. //! Clone `Reg` operand.
ASMJIT_INLINE BaseReg clone() const { ASMJIT_INLINE Reg clone() const {
return BaseReg(*this); return Reg(*this);
} }
//! Get whether register code is equal to `type`. //! Get whether register code is equal to `type`.
@@ -679,15 +660,25 @@ struct BaseMem : public Operand {
} }
//! Get the type of the memory operand, see `kMemType`. //! Get the type of the memory operand, see `kMemType`.
ASMJIT_INLINE uint32_t getMemType() const { return _vmem.type; } ASMJIT_INLINE uint32_t getMemType() const {
return _vmem.type;
}
//! Get whether the type of the memory operand is either `kMemTypeBaseIndex` //! Get whether the type of the memory operand is either `kMemTypeBaseIndex`
//! or `kMemTypeStackIndex`. //! or `kMemTypeStackIndex`.
ASMJIT_INLINE bool isBaseIndexType() const { return _vmem.type <= kMemTypeStackIndex; } ASMJIT_INLINE bool isBaseIndexType() const {
return _vmem.type <= kMemTypeStackIndex;
}
//! Get whether the memory operand has base register. //! Get whether the memory operand has base register.
ASMJIT_INLINE bool hasBase() const { return _vmem.base != kInvalidValue; } ASMJIT_INLINE bool hasBase() const {
return _vmem.base != kInvalidValue;
}
//! Get memory operand base id, or `kInvalidValue`. //! Get memory operand base id, or `kInvalidValue`.
ASMJIT_INLINE uint32_t getBase() const { return _vmem.base; } ASMJIT_INLINE uint32_t getBase() const {
return _vmem.base;
}
//! Set memory operand size. //! Set memory operand size.
ASMJIT_INLINE BaseMem& setSize(uint32_t size) { ASMJIT_INLINE BaseMem& setSize(uint32_t size) {
@@ -719,53 +710,11 @@ struct BaseMem : public Operand {
return (_packed[0] == other._packed[0]) & (_packed[1] == other._packed[1]); return (_packed[0] == other._packed[0]) & (_packed[1] == other._packed[1]);
} }
ASMJIT_INLINE bool operator!=(const BaseMem& other) const { return !(*this == other); } ASMJIT_INLINE bool operator!=(const BaseMem& other) const {
return !(*this == other);
}
}; };
// ============================================================================
// [asmjit::BaseVar]
// ============================================================================
#if !defined(ASMJIT_DISABLE_COMPILER)
//! Base class for all variables.
struct BaseVar : public Operand {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE BaseVar() : Operand(NoInit) {
_init_packed_op_sz_b0_b1_id(kOperandTypeVar, 0, 0, 0, kInvalidValue);
_init_packed_d2_d3(kInvalidValue, kInvalidValue);
}
ASMJIT_INLINE BaseVar(const BaseVar& other) : Operand(other) {}
explicit ASMJIT_INLINE BaseVar(const _NoInit&) : Operand(NoInit) {}
// --------------------------------------------------------------------------
// [BaseVar Specific]
// --------------------------------------------------------------------------
//! Clone `BaseVar` operand.
ASMJIT_INLINE BaseVar clone() const {
return BaseVar(*this);
}
ASMJIT_INLINE uint32_t getVarType() const {
return _vreg.vType;
}
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE BaseVar& operator=(const BaseVar& other) { _copy(other); return *this; }
ASMJIT_INLINE bool operator==(const BaseVar& other) const { return _packed[0] == other._packed[0]; }
ASMJIT_INLINE bool operator!=(const BaseVar& other) const { return !operator==(other); }
};
#endif // !ASMJIT_DISABLE_COMPILER
// ============================================================================ // ============================================================================
// [asmjit::Imm] // [asmjit::Imm]
// ============================================================================ // ============================================================================
@@ -1033,7 +982,7 @@ struct Imm : public Operand {
//! Label represents a location in code typically used as jump targets, but may //! Label represents a location in code typically used as jump targets, but may
//! be also reference data or static variables. Label has to be explicitly //! be also reference data or static variables. Label has to be explicitly
//! created by a code-generator by calling `CodeGen::newLabel()` where `CodeGen` //! created by a code-generator by calling `CodeGen::newLabel()` where `CodeGen`
//! is your code generator, which derives from `BaseAssembler` or `BaseCompiler`. //! is your code generator, which derives from `Assembler` or `Compiler`.
//! //!
//! Example of using labels: //! Example of using labels:
//! //!
@@ -1070,9 +1019,9 @@ struct Label : public Operand {
} }
//! Create new initialized label. //! Create new initialized label.
explicit ASMJIT_INLINE Label(BaseAssembler& a); explicit ASMJIT_INLINE Label(Assembler& a);
//! Create new initialized label. //! Create new initialized label.
explicit ASMJIT_INLINE Label(BaseCompiler& c); explicit ASMJIT_INLINE Label(Compiler& c);
//! Create reference to another label. //! Create reference to another label.
ASMJIT_INLINE Label(const Label& other) : Operand(other) {} ASMJIT_INLINE Label(const Label& other) : Operand(other) {}
@@ -1088,6 +1037,15 @@ struct Label : public Operand {
_init_packed_d2_d3(0, 0); _init_packed_d2_d3(0, 0);
} }
// --------------------------------------------------------------------------
// [Label Specific]
// --------------------------------------------------------------------------
//! Get whether the label has been initialized by `Assembler` or `Compiler`.
ASMJIT_INLINE bool isInitialized() const {
return _label.id != kInvalidValue;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Operator Overload] // [Operator Overload]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View File

@@ -1,117 +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_PODLIST_H
#define _ASMJIT_BASE_PODLIST_H
// [Dependencies - AsmJit]
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::PodList<T>]
// ============================================================================
//! \internal
template <typename T>
struct PodList {
ASMJIT_NO_COPY(PodList<T>)
// --------------------------------------------------------------------------
// [Link]
// --------------------------------------------------------------------------
struct Link {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get next node.
ASMJIT_INLINE Link* getNext() const { return _next; }
//! Get value.
ASMJIT_INLINE T getValue() const { return _value; }
//! Set value to `value`.
ASMJIT_INLINE void setValue(const T& value) { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _next;
T _value;
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE PodList() : _first(NULL), _last(NULL) {}
ASMJIT_INLINE ~PodList() {}
// --------------------------------------------------------------------------
// [Data]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const { return _first != NULL; }
ASMJIT_INLINE Link* getFirst() const { return _first; }
ASMJIT_INLINE Link* getLast() const { return _last; }
// --------------------------------------------------------------------------
// [Ops]
// --------------------------------------------------------------------------
ASMJIT_INLINE void clear() {
reset();
}
ASMJIT_INLINE void reset() {
_first = NULL;
_last = NULL;
}
ASMJIT_INLINE void prepend(Link* link) {
link->_next = _first;
if (_first == NULL)
_last = link;
_first = link;
}
ASMJIT_INLINE void append(Link* link) {
link->_next = NULL;
if (_first == NULL)
_first = link;
else
_last->_next = link;
_last = link;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Link* _first;
Link* _last;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_PODLIST_H

View File

@@ -62,15 +62,15 @@ uint32_t JitRuntime::getStackAlignment() {
return alignment; return alignment;
} }
const BaseCpuInfo* JitRuntime::getCpuInfo() { const CpuInfo* JitRuntime::getCpuInfo() {
return BaseCpuInfo::getHost(); return CpuInfo::getHost();
} }
// ============================================================================ // ============================================================================
// [asmjit::JitRuntime - Add] // [asmjit::JitRuntime - Add]
// ============================================================================ // ============================================================================
Error JitRuntime::add(void** dst, BaseAssembler* assembler) { Error JitRuntime::add(void** dst, Assembler* assembler) {
// Disallow empty code generation. // Disallow empty code generation.
size_t codeSize = assembler->getCodeSize(); size_t codeSize = assembler->getCodeSize();

View File

@@ -21,8 +21,8 @@ namespace asmjit {
// [Forward Declarations] // [Forward Declarations]
// ============================================================================ // ============================================================================
struct BaseAssembler; struct Assembler;
struct BaseCpuInfo; struct CpuInfo;
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base_general
//! \{ //! \{
@@ -32,7 +32,7 @@ struct BaseCpuInfo;
// ============================================================================ // ============================================================================
//! Base runtime. //! Base runtime.
struct Runtime { struct ASMJIT_VCLASS Runtime {
ASMJIT_NO_COPY(Runtime) ASMJIT_NO_COPY(Runtime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -52,7 +52,7 @@ struct Runtime {
virtual uint32_t getStackAlignment() = 0; virtual uint32_t getStackAlignment() = 0;
//! Get CPU information. //! Get CPU information.
virtual const BaseCpuInfo* getCpuInfo() = 0; virtual const CpuInfo* getCpuInfo() = 0;
//! Allocate a memory needed for a code generated by `assembler` and //! Allocate a memory needed for a code generated by `assembler` and
//! relocate it to the target location. //! relocate it to the target location.
@@ -60,7 +60,7 @@ struct Runtime {
//! The beginning of the memory allocated for the function is returned in //! The beginning of the memory allocated for the function is returned in
//! `dst`. Returns Status code as \ref kError, on failure `dst` is set to //! `dst`. Returns Status code as \ref kError, on failure `dst` is set to
//! `NULL`. //! `NULL`.
virtual Error add(void** dst, BaseAssembler* assembler) = 0; virtual Error add(void** dst, Assembler* assembler) = 0;
//! Release memory allocated by `add`. //! Release memory allocated by `add`.
virtual Error release(void* p) = 0; virtual Error release(void* p) = 0;
@@ -71,7 +71,7 @@ struct Runtime {
// ============================================================================ // ============================================================================
//! JIT runtime. //! JIT runtime.
struct JitRuntime : public Runtime { struct ASMJIT_VCLASS JitRuntime : public Runtime {
ASMJIT_NO_COPY(JitRuntime) ASMJIT_NO_COPY(JitRuntime)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -112,9 +112,9 @@ struct JitRuntime : public Runtime {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API virtual uint32_t getStackAlignment(); ASMJIT_API virtual uint32_t getStackAlignment();
ASMJIT_API virtual const BaseCpuInfo* getCpuInfo(); ASMJIT_API virtual const CpuInfo* getCpuInfo();
ASMJIT_API virtual Error add(void** dst, BaseAssembler* assembler); ASMJIT_API virtual Error add(void** dst, Assembler* assembler);
ASMJIT_API virtual Error release(void* p); ASMJIT_API virtual Error release(void* p);
//! Flush instruction cache. //! Flush instruction cache.

View File

@@ -20,164 +20,164 @@ namespace asmjit {
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::Vec64Data] // [asmjit::Vec64]
// ============================================================================ // ============================================================================
//! 64-bit vector register data. //! 64-bit vector register data.
union Vec64Data { union Vec64 {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Set all eight 8-bit signed integers. //! Set all eight 8-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSb( static ASMJIT_INLINE Vec64 fromSb(
int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7) int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7)
{ {
Vec64Data self; Vec64 self;
self.setSb(x0, x1, x2, x3, x4, x5, x6, x7); self.setSb(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 8-bit signed integers. //! Set all eight 8-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSb( static ASMJIT_INLINE Vec64 fromSb(
int8_t x0) int8_t x0)
{ {
Vec64Data self; Vec64 self;
self.setSb(x0); self.setSb(x0);
return self; return self;
} }
//! Set all eight 8-bit unsigned integers. //! Set all eight 8-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUb( static ASMJIT_INLINE Vec64 fromUb(
uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7) uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7)
{ {
Vec64Data self; Vec64 self;
self.setUb(x0, x1, x2, x3, x4, x5, x6, x7); self.setUb(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 8-bit unsigned integers. //! Set all eight 8-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUb( static ASMJIT_INLINE Vec64 fromUb(
uint8_t x0) uint8_t x0)
{ {
Vec64Data self; Vec64 self;
self.setUb(x0); self.setUb(x0);
return self; return self;
} }
//! Set all four 16-bit signed integers. //! Set all four 16-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSw( static ASMJIT_INLINE Vec64 fromSw(
int16_t x0, int16_t x1, int16_t x2, int16_t x3) int16_t x0, int16_t x1, int16_t x2, int16_t x3)
{ {
Vec64Data self; Vec64 self;
self.setSw(x0, x1, x2, x3); self.setSw(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 16-bit signed integers. //! Set all four 16-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSw( static ASMJIT_INLINE Vec64 fromSw(
int16_t x0) int16_t x0)
{ {
Vec64Data self; Vec64 self;
self.setSw(x0); self.setSw(x0);
return self; return self;
} }
//! Set all four 16-bit unsigned integers. //! Set all four 16-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUw( static ASMJIT_INLINE Vec64 fromUw(
uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3) uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3)
{ {
Vec64Data self; Vec64 self;
self.setUw(x0, x1, x2, x3); self.setUw(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 16-bit unsigned integers. //! Set all four 16-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUw( static ASMJIT_INLINE Vec64 fromUw(
uint16_t x0) uint16_t x0)
{ {
Vec64Data self; Vec64 self;
self.setUw(x0); self.setUw(x0);
return self; return self;
} }
//! Set all two 32-bit signed integers. //! Set all two 32-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSd( static ASMJIT_INLINE Vec64 fromSd(
int32_t x0, int32_t x1) int32_t x0, int32_t x1)
{ {
Vec64Data self; Vec64 self;
self.setSd(x0, x1); self.setSd(x0, x1);
return self; return self;
} }
//! Set all two 32-bit signed integers. //! Set all two 32-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSd( static ASMJIT_INLINE Vec64 fromSd(
int32_t x0) int32_t x0)
{ {
Vec64Data self; Vec64 self;
self.setSd(x0); self.setSd(x0);
return self; return self;
} }
//! Set all two 32-bit unsigned integers. //! Set all two 32-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUd( static ASMJIT_INLINE Vec64 fromUd(
uint32_t x0, uint32_t x1) uint32_t x0, uint32_t x1)
{ {
Vec64Data self; Vec64 self;
self.setUd(x0, x1); self.setUd(x0, x1);
return self; return self;
} }
//! Set all two 32-bit unsigned integers. //! Set all two 32-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUd( static ASMJIT_INLINE Vec64 fromUd(
uint32_t x0) uint32_t x0)
{ {
Vec64Data self; Vec64 self;
self.setUd(x0); self.setUd(x0);
return self; return self;
} }
//! Set 64-bit signed integer. //! Set 64-bit signed integer.
static ASMJIT_INLINE Vec64Data fromSq( static ASMJIT_INLINE Vec64 fromSq(
int64_t x0) int64_t x0)
{ {
Vec64Data self; Vec64 self;
self.setSq(x0); self.setSq(x0);
return self; return self;
} }
//! Set 64-bit unsigned integer. //! Set 64-bit unsigned integer.
static ASMJIT_INLINE Vec64Data fromUq( static ASMJIT_INLINE Vec64 fromUq(
uint64_t x0) uint64_t x0)
{ {
Vec64Data self; Vec64 self;
self.setUq(x0); self.setUq(x0);
return self; return self;
} }
//! Set all two SP-FP values. //! Set all two SP-FP values.
static ASMJIT_INLINE Vec64Data fromSf( static ASMJIT_INLINE Vec64 fromSf(
float x0, float x1) float x0, float x1)
{ {
Vec64Data self; Vec64 self;
self.setSf(x0, x1); self.setSf(x0, x1);
return self; return self;
} }
//! Set all two SP-FP values. //! Set all two SP-FP values.
static ASMJIT_INLINE Vec64Data fromSf( static ASMJIT_INLINE Vec64 fromSf(
float x0) float x0)
{ {
Vec64Data self; Vec64 self;
self.setSf(x0); self.setSf(x0);
return self; return self;
} }
//! Set all two SP-FP values. //! Set all two SP-FP values.
static ASMJIT_INLINE Vec64Data fromDf( static ASMJIT_INLINE Vec64 fromDf(
double x0) double x0)
{ {
Vec64Data self; Vec64 self;
self.setDf(x0); self.setDf(x0);
return self; return self;
} }
@@ -351,197 +351,197 @@ union Vec64Data {
}; };
// ============================================================================ // ============================================================================
// [asmjit::Vec128Data] // [asmjit::Vec128]
// ============================================================================ // ============================================================================
//! 128-bit vector register data. //! 128-bit vector register data.
union Vec128Data { union Vec128 {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Set all sixteen 8-bit signed integers. //! Set all sixteen 8-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSb( static ASMJIT_INLINE Vec128 fromSb(
int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
int8_t x12, int8_t x13, int8_t x14, int8_t x15) int8_t x12, int8_t x13, int8_t x14, int8_t x15)
{ {
Vec128Data self; Vec128 self;
self.setSb(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); self.setSb(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
return self; return self;
} }
//! Set all sixteen 8-bit signed integers. //! Set all sixteen 8-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSb( static ASMJIT_INLINE Vec128 fromSb(
int8_t x0) int8_t x0)
{ {
Vec128Data self; Vec128 self;
self.setSb(x0); self.setSb(x0);
return self; return self;
} }
//! Set all sixteen 8-bit unsigned integers. //! Set all sixteen 8-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUb( static ASMJIT_INLINE Vec128 fromUb(
uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15) uint8_t x12, uint8_t x13, uint8_t x14, uint8_t x15)
{ {
Vec128Data self; Vec128 self;
self.setUb(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); self.setUb(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
return self; return self;
} }
//! Set all sixteen 8-bit unsigned integers. //! Set all sixteen 8-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUb( static ASMJIT_INLINE Vec128 fromUb(
uint8_t x0) uint8_t x0)
{ {
Vec128Data self; Vec128 self;
self.setUb(x0); self.setUb(x0);
return self; return self;
} }
//! Set all eight 16-bit signed integers. //! Set all eight 16-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSw( static ASMJIT_INLINE Vec128 fromSw(
int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7) int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7)
{ {
Vec128Data self; Vec128 self;
self.setSw(x0, x1, x2, x3, x4, x5, x6, x7); self.setSw(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 16-bit signed integers. //! Set all eight 16-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSw( static ASMJIT_INLINE Vec128 fromSw(
int16_t x0) int16_t x0)
{ {
Vec128Data self; Vec128 self;
self.setSw(x0); self.setSw(x0);
return self; return self;
} }
//! Set all eight 16-bit unsigned integers. //! Set all eight 16-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUw( static ASMJIT_INLINE Vec128 fromUw(
uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7) uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7)
{ {
Vec128Data self; Vec128 self;
self.setUw(x0, x1, x2, x3, x4, x5, x6, x7); self.setUw(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 16-bit unsigned integers. //! Set all eight 16-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUw( static ASMJIT_INLINE Vec128 fromUw(
uint16_t x0) uint16_t x0)
{ {
Vec128Data self; Vec128 self;
self.setUw(x0); self.setUw(x0);
return self; return self;
} }
//! Set all four 32-bit signed integers. //! Set all four 32-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSd( static ASMJIT_INLINE Vec128 fromSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3) int32_t x0, int32_t x1, int32_t x2, int32_t x3)
{ {
Vec128Data self; Vec128 self;
self.setSd(x0, x1, x2, x3); self.setSd(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 32-bit signed integers. //! Set all four 32-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSd( static ASMJIT_INLINE Vec128 fromSd(
int32_t x0) int32_t x0)
{ {
Vec128Data self; Vec128 self;
self.setSd(x0); self.setSd(x0);
return self; return self;
} }
//! Set all four 32-bit unsigned integers. //! Set all four 32-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUd( static ASMJIT_INLINE Vec128 fromUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3) uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
{ {
Vec128Data self; Vec128 self;
self.setUd(x0, x1, x2, x3); self.setUd(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 32-bit unsigned integers. //! Set all four 32-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUd( static ASMJIT_INLINE Vec128 fromUd(
uint32_t x0) uint32_t x0)
{ {
Vec128Data self; Vec128 self;
self.setUd(x0); self.setUd(x0);
return self; return self;
} }
//! Set all two 64-bit signed integers. //! Set all two 64-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSq( static ASMJIT_INLINE Vec128 fromSq(
int64_t x0, int64_t x1) int64_t x0, int64_t x1)
{ {
Vec128Data self; Vec128 self;
self.setSq(x0, x1); self.setSq(x0, x1);
return self; return self;
} }
//! Set all two 64-bit signed integers. //! Set all two 64-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSq( static ASMJIT_INLINE Vec128 fromSq(
int64_t x0) int64_t x0)
{ {
Vec128Data self; Vec128 self;
self.setSq(x0); self.setSq(x0);
return self; return self;
} }
//! Set all two 64-bit unsigned integers. //! Set all two 64-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUq( static ASMJIT_INLINE Vec128 fromUq(
uint64_t x0, uint64_t x1) uint64_t x0, uint64_t x1)
{ {
Vec128Data self; Vec128 self;
self.setUq(x0, x1); self.setUq(x0, x1);
return self; return self;
} }
//! Set all two 64-bit unsigned integers. //! Set all two 64-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUq( static ASMJIT_INLINE Vec128 fromUq(
uint64_t x0) uint64_t x0)
{ {
Vec128Data self; Vec128 self;
self.setUq(x0); self.setUq(x0);
return self; return self;
} }
//! Set all four SP-FP floats. //! Set all four SP-FP floats.
static ASMJIT_INLINE Vec128Data fromSf( static ASMJIT_INLINE Vec128 fromSf(
float x0, float x1, float x2, float x3) float x0, float x1, float x2, float x3)
{ {
Vec128Data self; Vec128 self;
self.setSf(x0, x1, x2, x3); self.setSf(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four SP-FP floats. //! Set all four SP-FP floats.
static ASMJIT_INLINE Vec128Data fromSf( static ASMJIT_INLINE Vec128 fromSf(
float x0) float x0)
{ {
Vec128Data self; Vec128 self;
self.setSf(x0); self.setSf(x0);
return self; return self;
} }
//! Set all two DP-FP floats. //! Set all two DP-FP floats.
static ASMJIT_INLINE Vec128Data fromDf( static ASMJIT_INLINE Vec128 fromDf(
double x0, double x1) double x0, double x1)
{ {
Vec128Data self; Vec128 self;
self.setDf(x0, x1); self.setDf(x0, x1);
return self; return self;
} }
//! Set all two DP-FP floats. //! Set all two DP-FP floats.
static ASMJIT_INLINE Vec128Data fromDf( static ASMJIT_INLINE Vec128 fromDf(
double x0) double x0)
{ {
Vec128Data self; Vec128 self;
self.setDf(x0); self.setDf(x0);
return self; return self;
} }
@@ -764,17 +764,17 @@ union Vec128Data {
}; };
// ============================================================================ // ============================================================================
// [asmjit::Vec256Data] // [asmjit::Vec256]
// ============================================================================ // ============================================================================
//! 256-bit vector register data. //! 256-bit vector register data.
union Vec256Data { union Vec256 {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Set all thirty two 8-bit signed integers. //! Set all thirty two 8-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSb( static ASMJIT_INLINE Vec256 fromSb(
int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 , int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 , int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
int8_t x8 , int8_t x9 , int8_t x10, int8_t x11, int8_t x8 , int8_t x9 , int8_t x10, int8_t x11,
@@ -784,7 +784,7 @@ union Vec256Data {
int8_t x24, int8_t x25, int8_t x26, int8_t x27, int8_t x24, int8_t x25, int8_t x26, int8_t x27,
int8_t x28, int8_t x29, int8_t x30, int8_t x31) int8_t x28, int8_t x29, int8_t x30, int8_t x31)
{ {
Vec256Data self; Vec256 self;
self.setSb( self.setSb(
x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15,
x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31);
@@ -792,16 +792,16 @@ union Vec256Data {
} }
//! Set all thirty two 8-bit signed integers. //! Set all thirty two 8-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSb( static ASMJIT_INLINE Vec256 fromSb(
int8_t x0) int8_t x0)
{ {
Vec256Data self; Vec256 self;
self.setSb(x0); self.setSb(x0);
return self; return self;
} }
//! Set all thirty two 8-bit unsigned integers. //! Set all thirty two 8-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUb( static ASMJIT_INLINE Vec256 fromUb(
uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 , uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 , uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11, uint8_t x8 , uint8_t x9 , uint8_t x10, uint8_t x11,
@@ -811,7 +811,7 @@ union Vec256Data {
uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27, uint8_t x24, uint8_t x25, uint8_t x26, uint8_t x27,
uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31) uint8_t x28, uint8_t x29, uint8_t x30, uint8_t x31)
{ {
Vec256Data self; Vec256 self;
self.setUb( self.setUb(
x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15, x0, x1 , x2 , x3 , x4 , x5 , x6 , x7 , x8 , x9 , x10, x11, x12, x13, x14, x15,
x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31); x16, x17, x18, x19, x20, x21, x22, x23, x24, x25, x26, x27, x28, x29, x30, x31);
@@ -819,159 +819,159 @@ union Vec256Data {
} }
//! Set all thirty two 8-bit unsigned integers. //! Set all thirty two 8-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUb( static ASMJIT_INLINE Vec256 fromUb(
uint8_t x0) uint8_t x0)
{ {
Vec256Data self; Vec256 self;
self.setUb(x0); self.setUb(x0);
return self; return self;
} }
//! Set all sixteen 16-bit signed integers. //! Set all sixteen 16-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSw( static ASMJIT_INLINE Vec256 fromSw(
int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7 , int16_t x0, int16_t x1, int16_t x2 , int16_t x3 , int16_t x4 , int16_t x5 , int16_t x6 , int16_t x7 ,
int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15) int16_t x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15)
{ {
Vec256Data self; Vec256 self;
self.setSw(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); self.setSw(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
return self; return self;
} }
//! Set all sixteen 16-bit signed integers. //! Set all sixteen 16-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSw( static ASMJIT_INLINE Vec256 fromSw(
int16_t x0) int16_t x0)
{ {
Vec256Data self; Vec256 self;
self.setSw(x0); self.setSw(x0);
return self; return self;
} }
//! Set all sixteen 16-bit unsigned integers. //! Set all sixteen 16-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUw( static ASMJIT_INLINE Vec256 fromUw(
uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7 , uint16_t x0, uint16_t x1, uint16_t x2 , uint16_t x3 , uint16_t x4 , uint16_t x5 , uint16_t x6 , uint16_t x7 ,
uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15) uint16_t x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15)
{ {
Vec256Data self; Vec256 self;
self.setUw(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15); self.setUw(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15);
return self; return self;
} }
//! Set all sixteen 16-bit unsigned integers. //! Set all sixteen 16-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUw( static ASMJIT_INLINE Vec256 fromUw(
uint16_t x0) uint16_t x0)
{ {
Vec256Data self; Vec256 self;
self.setUw(x0); self.setUw(x0);
return self; return self;
} }
//! Set all eight 32-bit signed integers. //! Set all eight 32-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSd( static ASMJIT_INLINE Vec256 fromSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3, int32_t x0, int32_t x1, int32_t x2, int32_t x3,
int32_t x4, int32_t x5, int32_t x6, int32_t x7) int32_t x4, int32_t x5, int32_t x6, int32_t x7)
{ {
Vec256Data self; Vec256 self;
self.setSd(x0, x1, x2, x3, x4, x5, x6, x7); self.setSd(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 32-bit signed integers. //! Set all eight 32-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSd( static ASMJIT_INLINE Vec256 fromSd(
int32_t x0) int32_t x0)
{ {
Vec256Data self; Vec256 self;
self.setSd(x0); self.setSd(x0);
return self; return self;
} }
//! Set all eight 32-bit unsigned integers. //! Set all eight 32-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUd( static ASMJIT_INLINE Vec256 fromUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3, 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 x4, uint32_t x5, uint32_t x6, uint32_t x7)
{ {
Vec256Data self; Vec256 self;
self.setUd(x0, x1, x2, x3, x4, x5, x6, x7); self.setUd(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight 32-bit unsigned integers. //! Set all eight 32-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUd( static ASMJIT_INLINE Vec256 fromUd(
uint32_t x0) uint32_t x0)
{ {
Vec256Data self; Vec256 self;
self.setUd(x0); self.setUd(x0);
return self; return self;
} }
//! Set all four 64-bit signed integers. //! Set all four 64-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSq( static ASMJIT_INLINE Vec256 fromSq(
int64_t x0, int64_t x1, int64_t x2, int64_t x3) int64_t x0, int64_t x1, int64_t x2, int64_t x3)
{ {
Vec256Data self; Vec256 self;
self.setSq(x0, x1, x2, x3); self.setSq(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 64-bit signed integers. //! Set all four 64-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSq( static ASMJIT_INLINE Vec256 fromSq(
int64_t x0) int64_t x0)
{ {
Vec256Data self; Vec256 self;
self.setSq(x0); self.setSq(x0);
return self; return self;
} }
//! Set all four 64-bit unsigned integers. //! Set all four 64-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUq( static ASMJIT_INLINE Vec256 fromUq(
uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3) uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3)
{ {
Vec256Data self; Vec256 self;
self.setUq(x0, x1, x2, x3); self.setUq(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four 64-bit unsigned integers. //! Set all four 64-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUq( static ASMJIT_INLINE Vec256 fromUq(
uint64_t x0) uint64_t x0)
{ {
Vec256Data self; Vec256 self;
self.setUq(x0); self.setUq(x0);
return self; return self;
} }
//! Set all eight SP-FP floats. //! Set all eight SP-FP floats.
static ASMJIT_INLINE Vec256Data fromSf( static ASMJIT_INLINE Vec256 fromSf(
float x0, float x1, float x2, float x3, float x0, float x1, float x2, float x3,
float x4, float x5, float x6, float x7) float x4, float x5, float x6, float x7)
{ {
Vec256Data self; Vec256 self;
self.setSf(x0, x1, x2, x3, x4, x5, x6, x7); self.setSf(x0, x1, x2, x3, x4, x5, x6, x7);
return self; return self;
} }
//! Set all eight SP-FP floats. //! Set all eight SP-FP floats.
static ASMJIT_INLINE Vec256Data fromSf( static ASMJIT_INLINE Vec256 fromSf(
float x0) float x0)
{ {
Vec256Data self; Vec256 self;
self.setSf(x0); self.setSf(x0);
return self; return self;
} }
//! Set all four DP-FP floats. //! Set all four DP-FP floats.
static ASMJIT_INLINE Vec256Data fromDf( static ASMJIT_INLINE Vec256 fromDf(
double x0, double x1, double x2, double x3) double x0, double x1, double x2, double x3)
{ {
Vec256Data self; Vec256 self;
self.setDf(x0, x1, x2, x3); self.setDf(x0, x1, x2, x3);
return self; return self;
} }
//! Set all four DP-FP floats. //! Set all four DP-FP floats.
static ASMJIT_INLINE Vec256Data fromDf( static ASMJIT_INLINE Vec256 fromDf(
double x0) double x0)
{ {
Vec256Data self; Vec256 self;
self.setDf(x0); self.setDf(x0);
return self; return self;
} }

File diff suppressed because it is too large Load Diff

View File

@@ -10,6 +10,7 @@
// [Dependencies] // [Dependencies]
#include "../base/error.h" #include "../base/error.h"
#include "../base/lock.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../apibegin.h"
@@ -59,12 +60,12 @@ ASMJIT_ENUM(kVMemFlags) {
//! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed //! on POSIX. `VirtualAlloc()` and `mmap()` documentation provide a detailed
//! overview on how to use a platform specific APIs. //! overview on how to use a platform specific APIs.
struct VMemUtil { struct VMemUtil {
//! Get the alignment guaranteed by alloc(). //! Get a size/alignment of a single virtual memory page.
static ASMJIT_API size_t getAlignment();
//! Get size of the single page.
static ASMJIT_API size_t getPageSize(); static ASMJIT_API size_t getPageSize();
//! Get a recommended granularity for a single `alloc` call.
static ASMJIT_API size_t getPageGranularity();
//! Allocate virtual memory. //! Allocate virtual memory.
//! //!
//! Pages are readable/writeable, but they are not guaranteed to be //! Pages are readable/writeable, but they are not guaranteed to be
@@ -72,19 +73,21 @@ struct VMemUtil {
//! 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);
//! Free memory allocated by `alloc()`.
static ASMJIT_API void release(void* addr, size_t length);
#if defined(ASMJIT_OS_WINDOWS) #if defined(ASMJIT_OS_WINDOWS)
//! Allocate virtual memory of `hProcess`. //! Allocate virtual memory of `hProcess`.
//! //!
//! \note This function is Windows specific. //! \note This function is Windows specific.
static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags); static ASMJIT_API void* allocProcessMemory(HANDLE hProcess, size_t length, size_t* allocated, uint32_t flags);
#endif // ASMJIT_OS_WINDOWS
//! Free virtual memory of `hProcess`. //! Free memory allocated by `alloc()`.
static ASMJIT_API Error release(void* addr, size_t length);
#if defined(ASMJIT_OS_WINDOWS)
//! Release virtual memory of `hProcess`.
//! //!
//! \note This function is Windows specific. //! \note This function is Windows specific.
static ASMJIT_API void 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
}; };
@@ -99,15 +102,16 @@ struct VMemMgr {
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if !defined(ASMJIT_OS_WINDOWS)
//! Create a `VMemMgr` instance. //! Create a `VMemMgr` instance.
ASMJIT_API VMemMgr(); ASMJIT_API VMemMgr();
#else
#if defined(ASMJIT_OS_WINDOWS) //! Create a `VMemMgr` instance.
//! Create a `VMemMgr` instance for `hProcess`.
//! //!
//! This is a specialized version of constructor available only for windows //! \note When running on Windows it's possible to specify a `hProcess` to
//! and usable to alloc/free memory of a different process. //! be used for memory allocation. This allows to allocate memory of remote
explicit ASMJIT_API VMemMgr(HANDLE hProcess); //! process.
ASMJIT_API VMemMgr(HANDLE hProcess = static_cast<HANDLE>(0));
#endif // ASMJIT_OS_WINDOWS #endif // ASMJIT_OS_WINDOWS
//! Destroy the `VMemMgr` instance and free all blocks. //! Destroy the `VMemMgr` instance and free all blocks.
@@ -126,18 +130,27 @@ struct VMemMgr {
#if defined(ASMJIT_OS_WINDOWS) #if defined(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_API HANDLE getProcessHandle() const; ASMJIT_INLINE HANDLE getProcessHandle() const {
return _hProcess;
}
#endif // ASMJIT_OS_WINDOWS #endif // ASMJIT_OS_WINDOWS
//! Get how many bytes are currently used.
ASMJIT_API size_t getUsedBytes() const;
//! Get how many bytes are currently allocated. //! Get how many bytes are currently allocated.
ASMJIT_API size_t getAllocatedBytes() const; ASMJIT_INLINE size_t getAllocatedBytes() const {
return _allocatedBytes;
}
//! Get how many bytes are currently used.
ASMJIT_INLINE size_t getUsedBytes() const {
return _usedBytes;
}
//! Get whether to keep allocated memory after the `VMemMgr` is destroyed. //! Get whether to keep allocated memory after the `VMemMgr` is destroyed.
//! //!
//! \sa \ref setKeepVirtualMemory. //! \sa \ref setKeepVirtualMemory.
ASMJIT_API bool getKeepVirtualMemory() const; ASMJIT_INLINE bool getKeepVirtualMemory() const {
return _keepVirtualMemory;
}
//! Set whether to keep allocated memory after memory manager is //! Set whether to keep allocated memory after memory manager is
//! destroyed. //! destroyed.
@@ -151,7 +164,9 @@ struct VMemMgr {
//! \note Memory allocated with kVMemAllocPermanent is always kept. //! \note Memory allocated with kVMemAllocPermanent is always kept.
//! //!
//! \sa \ref getKeepVirtualMemory. //! \sa \ref getKeepVirtualMemory.
ASMJIT_API void setKeepVirtualMemory(bool keepVirtualMemory); ASMJIT_INLINE void setKeepVirtualMemory(bool keepVirtualMemory) {
_keepVirtualMemory = keepVirtualMemory;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Alloc / Release] // [Alloc / Release]
@@ -165,19 +180,53 @@ struct VMemMgr {
ASMJIT_API void* alloc(size_t size, uint32_t type = kVMemAllocFreeable); ASMJIT_API void* alloc(size_t size, uint32_t type = kVMemAllocFreeable);
//! Free previously allocated memory at a given `address`. //! Free previously allocated memory at a given `address`.
ASMJIT_API Error release(void* address); ASMJIT_API Error release(void* p);
//! Free some tail memory. //! Free extra memory allocated with `p`.
ASMJIT_API Error shrink(void* address, size_t used); ASMJIT_API Error shrink(void* p, size_t used);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_OS_WINDOWS)
//! Process passed to `VirtualAllocEx` and `VirtualFree`.
HANDLE _hProcess;
#endif // ASMJIT_OS_WINDOWS
//! Lock to enable thread-safe functionality.
Lock _lock;
//! Default block size.
size_t _blockSize;
//! Default block density.
size_t _blockDensity;
// Whether to keep virtual memory after destroy.
bool _keepVirtualMemory;
//! How many bytes are currently allocated.
size_t _allocatedBytes;
//! How many bytes are currently used.
size_t _usedBytes;
//! \internal //! \internal
//! //! \{
//! Pointer to a private data hidden from the public API.
void* _d; struct RbNode;
struct MemNode;
struct PermanentNode;
// Memory nodes root.
MemNode* _root;
// Memory nodes list.
MemNode* _first;
MemNode* _last;
MemNode* _optimal;
// Permanent memory.
PermanentNode* _permanent;
//! \}
}; };
//! \} //! \}

View File

@@ -34,42 +34,47 @@ Zone::Zone(size_t blockSize) {
} }
Zone::~Zone() { Zone::~Zone() {
reset(); reset(true);
} }
// ============================================================================ // ============================================================================
// [asmjit::Zone - Clear / Reset] // [asmjit::Zone - Reset]
// ============================================================================ // ============================================================================
void Zone::clear() { void Zone::reset(bool releaseMemory) {
Block* cur = _block;
// Can't be altered.
if (cur == &Zone_zeroBlock)
return;
while (cur->prev != NULL)
cur = cur->prev;
cur->pos = cur->data;
_block = cur;
}
void Zone::reset() {
Block* cur = _block; Block* cur = _block;
// Can't be altered. // Can't be altered.
if (cur == &Zone_zeroBlock) if (cur == &Zone_zeroBlock)
return; return;
if (releaseMemory) {
// Since cur can be in the middle of the double-linked list, we have to
// traverse to both directions `prev` and `next` separately.
Block* next = cur->next;
do { do {
Block* prev = cur->prev; Block* prev = cur->prev;
ASMJIT_FREE(cur); ASMJIT_FREE(cur);
cur = prev; cur = prev;
} while (cur != NULL); } while (cur != NULL);
cur = next;
while (cur != NULL) {
next = cur->next;
ASMJIT_FREE(cur);
cur = next;
}
_block = const_cast<Zone::Block*>(&Zone_zeroBlock); _block = const_cast<Zone::Block*>(&Zone_zeroBlock);
} }
else {
while (cur->prev != NULL)
cur = cur->prev;
cur->pos = cur->data;
_block = cur;
}
}
// ============================================================================ // ============================================================================
// [asmjit::Zone - Alloc] // [asmjit::Zone - Alloc]
@@ -83,7 +88,7 @@ void* Zone::_alloc(size_t size) {
// in the current block, see `alloc()` implementation for more details. // in the current block, see `alloc()` implementation for more details.
ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || curBlock->getRemainingSize() < size); ASMJIT_ASSERT(curBlock == &Zone_zeroBlock || curBlock->getRemainingSize() < size);
// If the `Zone` has been cleared the current block doesn't have to be the // If the `Zone` has been reset the current block doesn't have to be the
// last one. Check if there is a block that can be used instead of allocating // last one. Check if there is a block that can be used instead of allocating
// a new one. If there is a `next` block it's completely unused, we don't have // a new one. If there is a `next` block it's completely unused, we don't have
// to check for remaining bytes. // to check for remaining bytes.

View File

@@ -33,7 +33,7 @@ namespace asmjit {
//! Zone memory allocators are designed to allocate data of short lifetime. The //! Zone memory allocators are designed to allocate data of short lifetime. The
//! data used by `Assembler` and `Compiler` has a very short lifetime, thus, is //! data used by `Assembler` and `Compiler` has a very short lifetime, thus, is
//! allocated by `Zone`. The advantage is that `Zone` can free all of the data //! allocated by `Zone`. The advantage is that `Zone` can free all of the data
//! allocated at once by calling `clear()` or `reset()`. //! allocated at once by calling `reset()` or by `Zone` destructor.
struct Zone { struct Zone {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Block] // [Block]
@@ -94,23 +94,17 @@ struct Zone {
//! Destroy the `Zone` instance. //! Destroy the `Zone` instance.
//! //!
//! This will destroy the `Zone` instance and release all blocks of memory //! This will destroy the `Zone` instance and release all blocks of memory
//! allocated by it. It performs implicit `reset()`. //! allocated by it. It performs implicit `reset(true)`.
ASMJIT_API ~Zone(); ASMJIT_API ~Zone();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Clear / Reset] // [Reset]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Clear the `Zone`, but keep all blocks allocated so they can be reused. //! Reset the `Zone` invalidating all blocks allocated.
//! //!
//! This is the preferred way of invalidating objects allocated by `Zone`. //! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void clear(); ASMJIT_API void reset(bool releaseMemory = false);
//! Reset the `Zone` releasing all blocks allocated.
//!
//! Calling `reset()` does complete cleanup, it releases all blocks allocated
//! by `Zone`.
ASMJIT_API void reset();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
@@ -128,8 +122,8 @@ struct Zone {
//! Allocate `size` bytes of memory. //! Allocate `size` bytes of memory.
//! //!
//! Pointer returned is valid until the `Zone` instance is destroyed or reset //! Pointer returned is valid until the `Zone` instance is destroyed or reset
//! by calling `clear()` or `reset()`. If you plan to make an instance of C++ //! by calling `reset()`. If you plan to make an instance of C++ from the
//! from the given pointer use placement `new` and `delete` operators: //! given pointer use placement `new` and `delete` operators:
//! //!
//! ~~~ //! ~~~
//! using namespace asmjit; //! using namespace asmjit;

View File

@@ -9,9 +9,11 @@
#define _ASMJIT_BUILD_H #define _ASMJIT_BUILD_H
// [Include] // [Include]
#if !defined(ASMJIT_CONFIG_FILE) #if defined(ASMJIT_CONFIG_FILE)
# include ASMJIT_CONFIG_FILE
#else
# include "./config.h" # include "./config.h"
#endif // !ASMJIT_CONFIG_FILE #endif // ASMJIT_CONFIG_FILE
// Turn off deprecation warnings when compiling AsmJit. // Turn off deprecation warnings when compiling AsmJit.
#if defined(ASMJIT_EXPORTS) && defined(_MSC_VER) #if defined(ASMJIT_EXPORTS) && defined(_MSC_VER)
@@ -35,9 +37,9 @@
// [asmjit::build - Sanity] // [asmjit::build - Sanity]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_DISABLE_INST_NAMES) && !defined(ASMJIT_DISABLE_LOGGER) #if defined(ASMJIT_DISABLE_NAMES) && !defined(ASMJIT_DISABLE_LOGGER)
# error "ASMJIT_DISABLE_INST_NAMES requires ASMJIT_DISABLE_LOGGER to be defined." # error "ASMJIT_DISABLE_NAMES requires ASMJIT_DISABLE_LOGGER to be defined."
#endif // ASMJIT_DISABLE_INST_NAMES && !ASMJIT_DISABLE_LOGGER #endif // ASMJIT_DISABLE_NAMES && !ASMJIT_DISABLE_LOGGER
// ============================================================================ // ============================================================================
// [asmjit::build - OS] // [asmjit::build - OS]
@@ -127,35 +129,56 @@
# define ASMJIT_STATIC # define ASMJIT_STATIC
#endif // ASMJIT_EMBED && !ASMJIT_STATIC #endif // ASMJIT_EMBED && !ASMJIT_STATIC
#if !defined(ASMJIT_API)
#if defined(ASMJIT_STATIC) #if defined(ASMJIT_STATIC)
# define ASMJIT_API # define ASMJIT_API
#elif defined(ASMJIT_OS_WINDOWS) #elif defined(ASMJIT_OS_WINDOWS)
# if defined(__GNUC__) || defined(__clang__) # if (defined(__GNUC__) || defined(__clang__)) && !defined(__MINGW32__)
# if defined(ASMJIT_EXPORTS) # if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __attribute__((dllexport)) # define ASMJIT_API __attribute__((dllexport))
# else # else
# define ASMJIT_API __attribute__((dllimport)) # define ASMJIT_API __attribute__((dllimport))
# endif # endif // ASMJIT_EXPORTS
# elif defined(ASMJIT_EXPORTS) # else
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __declspec(dllexport) # define ASMJIT_API __declspec(dllexport)
# else # else
# define ASMJIT_API __declspec(dllimport) # define ASMJIT_API __declspec(dllimport)
# endif # endif
# else # endif
# if defined(__GNUC__) #elif defined(__GNUC__) && (__GNUC__ >= 4)
# if __GNUC__ >= 4
# define ASMJIT_API __attribute__((visibility("default"))) # define ASMJIT_API __attribute__((visibility("default")))
# define ASMJIT_VAR extern ASMJIT_API
# endif
# endif
#endif #endif
#if !defined(ASMJIT_API)
# define ASMJIT_API
#endif // ASMJIT_API #endif // ASMJIT_API
// This is basically a workaround. When using MSVC and marking class as DLL
// export everything is exported, which is unwanted since there are many
// inlines which mimic instructions. MSVC automatically exports typeinfo and
// vtable if at least one symbol of that class is exported. However, GCC has
// some strange behavior that even if one or more symbol is exported it doesn't
// export `typeinfo` unless the class itself is marked as "visibility(default)".
#if !defined(ASMJIT_OS_WINDOWS) && (defined(__GNUC__) || defined (__clang__))
# define ASMJIT_VCLASS ASMJIT_API
#else
# define ASMJIT_VCLASS
#endif
#if !defined(ASMJIT_VAR) #if !defined(ASMJIT_VAR)
# define ASMJIT_VAR extern ASMJIT_API # define ASMJIT_VAR extern ASMJIT_API
#endif // !ASMJIT_VAR #endif // !ASMJIT_VAR
#if defined(_MSC_VER)
# define ASMJIT_INLINE __forceinline
#elif defined(__clang__)
# define ASMJIT_INLINE inline __attribute__((always_inline)) __attribute__((visibility("hidden")))
#elif defined(__GNUC__)
# define ASMJIT_INLINE inline __attribute__((always_inline))
#else
# define ASMJIT_INLINE inline
#endif
#if defined(ASMJIT_HOST_X86) #if defined(ASMJIT_HOST_X86)
# if defined(__GNUC__) || defined(__clang__) # if defined(__GNUC__) || defined(__clang__)
# define ASMJIT_REGPARM_1 __attribute__((regparm(1))) # define ASMJIT_REGPARM_1 __attribute__((regparm(1)))
@@ -175,14 +198,6 @@
# define ASMJIT_CDECL # define ASMJIT_CDECL
#endif // ASMJIT_HOST_X86 #endif // ASMJIT_HOST_X86
#if defined(_MSC_VER)
# define ASMJIT_INLINE __forceinline
#elif (defined(__GNUC__) || defined(__clang__)) && !defined(__MINGW32__)
# define ASMJIT_INLINE inline __attribute__((always_inline))
#else
# define ASMJIT_INLINE inline
#endif
// ============================================================================ // ============================================================================
// [asmjit::build - Enum] // [asmjit::build - Enum]
// ============================================================================ // ============================================================================
@@ -217,14 +232,23 @@
# define _ASMJIT_HOST_INDEX(_Total_, _Index_) ((_Total_) - 1 - (_Index_)) # define _ASMJIT_HOST_INDEX(_Total_, _Index_) ((_Total_) - 1 - (_Index_))
#endif #endif
// ============================================================================
// [asmjit::build - BLEND_OFFSET_OF]
// ============================================================================
//! Cross-platform solution to get offset of `_Field_` in `_Struct_`.
#define ASMJIT_OFFSET_OF(_Struct_, _Field_) \
((size_t) ((const uint8_t*) &((const _Struct_*)0x1)->_Field_) - 1)
// ============================================================================ // ============================================================================
// [asmjit::build - ASMJIT_ARRAY_SIZE] // [asmjit::build - ASMJIT_ARRAY_SIZE]
// ============================================================================ // ============================================================================
#define ASMJIT_ARRAY_SIZE(_Array_) (sizeof(_Array_) / sizeof(*_Array_)) #define ASMJIT_ARRAY_SIZE(_Array_) \
(sizeof(_Array_) / sizeof(*_Array_))
// ============================================================================ // ============================================================================
// [asmjit::build - ASMJIT_DEBUG] // [asmjit::build - ASMJIT_DEBUG / ASMJIT_TRACE]
// ============================================================================ // ============================================================================
// If ASMJIT_DEBUG and ASMJIT_RELEASE is not defined ASMJIT_DEBUG will be // If ASMJIT_DEBUG and ASMJIT_RELEASE is not defined ASMJIT_DEBUG will be
@@ -236,6 +260,18 @@
# endif // _DEBUG # endif // _DEBUG
#endif // !ASMJIT_DEBUG && !ASMJIT_RELEASE #endif // !ASMJIT_DEBUG && !ASMJIT_RELEASE
// ASMJIT_TRACE is only used by sources and private headers. It's safe to make
// it unavailable outside of AsmJit.
#if defined(ASMJIT_EXPORTS)
# if defined(ASMJIT_TRACE)
# define ASMJIT_TSEC(_Section_) _Section_
# define ASMJIT_TLOG(...) ::printf(__VA_ARGS__)
# else
# define ASMJIT_TSEC(_Section_) do {} while(0)
# define ASMJIT_TLOG(...) do {} while(0)
# endif // ASMJIT_TRACE
#endif // ASMJIT_EXPORTS
// ============================================================================ // ============================================================================
// [asmjit::build - ASMJIT_UNUSED] // [asmjit::build - ASMJIT_UNUSED]
// ============================================================================ // ============================================================================
@@ -266,9 +302,9 @@ public:
// [asmjit::build - StdInt] // [asmjit::build - StdInt]
// ============================================================================ // ============================================================================
#if defined(__MINGW32__) || defined(__MINGW64__) #if defined(__MINGW32__)
# include <sys/types.h> # include <sys/types.h>
#endif // __MINGW32__ || __MINGW64__ #endif // __MINGW32__
#if defined(_MSC_VER) && (_MSC_VER < 1600) #if defined(_MSC_VER) && (_MSC_VER < 1600)
# if !defined(ASMJIT_SUPRESS_STD_TYPES) # if !defined(ASMJIT_SUPRESS_STD_TYPES)
@@ -329,9 +365,9 @@ typedef unsigned __int64 uint64_t;
// [asmjit::build - Test] // [asmjit::build - Test]
// ============================================================================ // ============================================================================
// Include test if building for unit testing. // Include a unit testing package if this is a `asmjit_test` build.
#if defined(ASMJIT_TEST) #if defined(ASMJIT_TEST)
#include "./test/test.h" #include "./test/broken.h"
#endif // ASMJIT_TEST #endif // ASMJIT_TEST
// [Guard] // [Guard]

View File

@@ -10,37 +10,44 @@
// This file can be used to modify built-in features of AsmJit. AsmJit is by // 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 // default compiled only for host processor to enable JIT compilation. Both
// Assembler and Compiler code generators are compiled by default. However, any // Assembler and Compiler code generators are compiled by default.
// ASMJIT_BUILD_... flag can be defined to enable building of additional //
// backends that can be used for remote code generation. // 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 - Debugging] // [AsmJit - Build-Type]
// ============================================================================
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// ============================================================================
// [AsmJit - Library]
// ============================================================================ // ============================================================================
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC). // #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build. // #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] // [AsmJit - Features]
// ============================================================================ // ============================================================================
// If none of these is defined AsmJit will select host architecture by default. // 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_X86 // Define to enable x86 instruction set (32-bit).
// #define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit). // #define ASMJIT_BUILD_X64 // Define to enable x64 instruction set (64-bit).
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set. // #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// #define ASMJIT_DISABLE_COMPILER // Disable Compiler. // AsmJit features are enabled by default.
// #define ASMJIT_DISABLE_COMPILER // Disable Compiler (completely).
// #define ASMJIT_DISABLE_LOGGER // Disable Logger (completely). // #define ASMJIT_DISABLE_LOGGER // Disable Logger (completely).
// #define ASMJIT_DISABLE_INST_NAMES // Disable Instruction names (and API). // #define ASMJIT_DISABLE_NAMES // Disable everything that uses strings
// (instruction names, error names, ...).
// [Guard] // [Guard]
#endif // _ASMJIT_CONFIG_H #endif // _ASMJIT_CONFIG_H

View File

@@ -37,7 +37,6 @@ WinRemoteRuntime::~WinRemoteRuntime() {}
uint32_t WinRemoteRuntime::add(void** dest, BaseAssembler* assembler) { uint32_t WinRemoteRuntime::add(void** dest, BaseAssembler* assembler) {
// Disallow generation of no code. // Disallow generation of no code.
size_t codeSize = assembler->getCodeSize(); size_t codeSize = assembler->getCodeSize();
if (codeSize == 0) { if (codeSize == 0) {
*dest = NULL; *dest = NULL;
return kErrorInvalidState; return kErrorInvalidState;
@@ -45,15 +44,13 @@ uint32_t WinRemoteRuntime::add(void** dest, BaseAssembler* assembler) {
// Allocate temporary memory where the code will be stored and relocated. // Allocate temporary memory where the code will be stored and relocated.
void* codeData = ASMJIT_ALLOC(codeSize); void* codeData = ASMJIT_ALLOC(codeSize);
if (codeData == NULL) { if (codeData == NULL) {
*dest = NULL; *dest = NULL;
return kErrorNoHeapMemory; return kErrorNoHeapMemory;
} }
// Allocate a pernament remote process memory. // Allocate a permanent remote process memory.
void* processMemPtr = _memMgr.alloc(codeSize, kVMemAllocPermanent); void* processMemPtr = _memMgr.alloc(codeSize, kVMemAllocPermanent);
if (processMemPtr == NULL) { if (processMemPtr == NULL) {
ASMJIT_FREE(codeData); ASMJIT_FREE(codeData);
*dest = NULL; *dest = NULL;

View File

@@ -11,28 +11,49 @@
// [Dependencies - Core] // [Dependencies - Core]
#include "base.h" #include "base.h"
// [Host - Helpers] // ============================================================================
#define ASMJIT_USE_HOST(_Arch_) \ // [asmjit::host - X86 / X64]
namespace asmjit { \ // ============================================================================
namespace host { \
using namespace ::asmjit::_Arch_; \
} \
}
// [Host - X86] #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
#if defined(ASMJIT_HOST_X86)
#include "x86.h" #include "x86.h"
ASMJIT_USE_HOST(x86)
#endif // ASMJIT_HOST_X86
// [Host - X64] namespace asmjit {
#if defined(ASMJIT_HOST_X64)
#include "x86.h"
ASMJIT_USE_HOST(x64)
#endif // ASMJIT_HOST_X64
// [Host - Cleanup] // Define `asmjit::host` namespace wrapping `asmjit::x86`.
#undef ASMJIT_USE_HOST namespace host { using namespace ::asmjit::x86; }
// Define host assembler.
typedef X86Assembler HostAssembler;
// Define host operands.
typedef X86GpReg GpReg;
typedef X86FpReg FpReg;
typedef X86MmReg MmReg;
typedef X86XmmReg XmmReg;
typedef X86YmmReg YmmReg;
typedef X86SegReg SegReg;
typedef X86Mem Mem;
// Define host utilities.
typedef X86CpuInfo HostCpuInfo;
// Define host compiler and related.
#if !defined(ASMJIT_DISABLE_COMPILER)
typedef X86Compiler HostCompiler;
typedef X86CallNode HostCallNode;
typedef X86FuncDecl HostFuncDecl;
typedef X86FuncNode HostFuncNode;
typedef X86GpVar GpVar;
typedef X86MmVar MmVar;
typedef X86XmmVar XmmVar;
typedef X86YmmVar YmmVar;
#endif // !ASMJIT_DISABLE_COMPILER
} // asmjit namespace
#endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64
// [Guard] // [Guard]
#endif // _ASMJIT_HOST_H #endif // _ASMJIT_HOST_H

279
src/asmjit/test/broken.cpp Normal file
View File

@@ -0,0 +1,279 @@
// [Broken]
// Lightweight Unit Testing for C++.
//
// [License]
// Public Domain (Unlicense)
#include "./broken.h"
// ============================================================================
// [Broken - Global]
// ============================================================================
// Zero initialized globals.
struct BrokenGlobal {
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
bool hasArg(const char* a) const {
int argc = _argc;
const char** argv = _argv;
for (int i = 1; i < argc; i++) {
if (::strcmp(argv[i], a) == 0)
return true;
}
return false;
}
FILE* getFile() const {
return _file ? _file : stdout;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
// Application arguments.
int _argc;
const char** _argv;
// Output file.
FILE* _file;
// Current context.
const char* _currentFile;
int _currentLine;
// Unit tests.
BrokenAPI::Unit* _unitList;
BrokenAPI::Unit* _unitRunning;
};
static BrokenGlobal _brokenGlobal;
// ============================================================================
// [Broken - API]
// ============================================================================
// Get whether the string `a` starts with string `b`.
static bool BrokenAPI_startsWith(const char* a, const char* b) {
for (size_t i = 0; ; i++) {
if (b[i] == '\0') return true;
if (a[i] != b[i]) return false;
}
}
// Get whether the strings `a` and `b` are equal, ignoring case and treating
// `-` as `_`.
static bool BrokenAPI_matchesFilter(const char* a, const char* b) {
for (size_t i = 0; ; i++) {
unsigned char ca = static_cast<unsigned char>(a[i]);
unsigned char cb = static_cast<unsigned char>(b[i]);
// If filter is defined as wildcard the rest automatically matches.
if (cb == '*')
return true;
if (ca == '-') ca = '_';
if (cb == '-') cb = '_';
if (ca >= 'A' && ca <= 'Z') ca += 'a' - 'A';
if (cb >= 'A' && cb <= 'Z') cb += 'a' - 'A';
if (ca != cb)
return false;
if (ca == '\0')
return true;
}
}
static bool BrokenAPI_canRun(BrokenAPI::Unit* unit) {
BrokenGlobal& global = _brokenGlobal;
int i, argc = global._argc;
const char** argv = global._argv;
const char* unitName = unit->name;
bool hasFilter = false;
for (i = 1; i < argc; i++) {
const char* arg = argv[i];
if (BrokenAPI_startsWith(arg, "--run-") && ::strcmp(arg, "--run-all") != 0) {
hasFilter = true;
if (BrokenAPI_matchesFilter(unitName, arg + 6))
return true;
}
}
// If no filter has been specified the default is to run.
return !hasFilter;
}
static void BrokenAPI_runUnit(BrokenAPI::Unit* unit) {
BrokenAPI::info("Running %s", unit->name);
_brokenGlobal._unitRunning = unit;
unit->entry();
_brokenGlobal._unitRunning = NULL;
}
static void BrokenAPI_runAll() {
BrokenAPI::Unit* unit = _brokenGlobal._unitList;
if (unit != NULL) {
size_t count = 0;
do {
if (BrokenAPI_canRun(unit)) {
BrokenAPI_runUnit(unit);
count++;
}
unit = unit->next;
} while (unit != NULL);
if (count) {
INFO("\nSuccess:");
INFO(" All tests passed!");
}
else {
INFO("\nWarning:");
INFO(" No units matched the filter!");
}
}
else {
INFO("\nWarning:");
INFO(" No units defined!");
}
}
static void BrokenAPI_listAll() {
BrokenAPI::Unit* unit = _brokenGlobal._unitList;
if (unit != NULL) {
INFO("Units:");
do {
INFO(" %s", unit->name);
unit = unit->next;
} while (unit != NULL);
}
else {
INFO("Warning:");
INFO(" No units defined!");
}
}
void BrokenAPI::add(Unit* unit) {
Unit** pPrev = &_brokenGlobal._unitList;
Unit* current = *pPrev;
// C++ static initialization doesn't guarantee anything. We sort all units by
// name so the execution will always happen in deterministic order.
while (current != NULL) {
if (::strcmp(current->name, unit->name) >= 0)
break;
pPrev = &current->next;
current = *pPrev;
}
*pPrev = unit;
unit->next = current;
}
void BrokenAPI::setOutputFile(FILE* file) {
BrokenGlobal& global = _brokenGlobal;
global._file = file;
}
void BrokenAPI::setContext(const char* file, int line) {
BrokenGlobal& global = _brokenGlobal;
global._currentFile = file;
global._currentLine = line;
}
int BrokenAPI::run(int argc, const char* argv[],
Entry onBeforeRun,
Entry onAfterRun) {
BrokenGlobal& global = _brokenGlobal;
global._argc = argc;
global._argv = argv;
if (global.hasArg("--help")) {
INFO("Options:");
INFO(" --help - print this usage");
INFO(" --list - list all tests");
INFO(" --run-... - run a test(s), trailing wildcards supported");
INFO(" --run-all - run all tests");
return 0;
}
if (global.hasArg("--list")) {
BrokenAPI_listAll();
return 0;
}
if (onBeforeRun)
onBeforeRun();
// We don't care about filters here, it's implemented by `runAll`.
BrokenAPI_runAll();
if (onAfterRun)
onAfterRun();
return 0;
}
void BrokenAPI::info(const char* fmt, ...) {
BrokenGlobal& global = _brokenGlobal;
FILE* dst = global.getFile();
const char* prefix = global._unitRunning ? " " : "";
size_t len = ::strlen(fmt);
if (len != 0) {
va_list ap;
va_start(ap, fmt);
::fputs(prefix, dst);
::vfprintf(dst, fmt, ap);
va_end(ap);
}
if (len == 0 || fmt[len - 1] != '\n')
::fputs("\n", dst);
::fflush(dst);
}
void BrokenAPI::fail(const char* fmt, va_list ap) {
BrokenGlobal& global = _brokenGlobal;
FILE* dst = global.getFile();
::fputs(" Failed!", dst);
if (fmt == NULL)
fmt = "";
size_t len = ::strlen(fmt);
if (len != 0) {
::fputs(" ", dst);
::vfprintf(dst, fmt, ap);
}
if (len > 0 && fmt[len - 1] != '\n')
::fputs("\n", dst);
::fprintf(dst, " File: %s (Line: %d)\n", global._currentFile, global._currentLine);
::fflush(dst);
::exit(1);
}

115
src/asmjit/test/broken.h Normal file
View File

@@ -0,0 +1,115 @@
// [Broken]
// Lightweight Unit Testing for C++.
//
// [License]
// Public Domain (Unlicense)
// [Guard]
#ifndef BROKEN_INTERNAL_H
#define BROKEN_INTERNAL_H
// [Dependencies - C]
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// If using Doxygen to document a source-code hide everything. Ideally this
// can be also done by a macro, but there is no global and widely used one.
//! \internal
//! \{
// ============================================================================
// [Broken - API]
// ============================================================================
struct BrokenAPI {
//! Test entry point.
typedef void (*Entry)(void);
//! Test unit.
struct Unit {
const char* name;
Entry entry;
size_t finished;
Unit* next;
};
//! Automatic unit registration by using static initialization.
struct AutoUnit : Unit {
inline AutoUnit(const char* _name, Entry _entry) {
name = _name;
entry = _entry;
finished = false;
next = NULL;
BrokenAPI::add(this);
}
};
//! Register a new test (called automatically by `AutoUnit` and `UNIT`).
static void add(Unit* unit);
//! Set output file to `file`.
static void setOutputFile(FILE* file);
//! Set the current context.
static void setContext(const char* file, int line);
//! Initialize `Broken` framework.
//!
//! Returns `true` if `run()` should be called.
static int run(int argc, const char* argv[],
Entry onBeforeRun = (Entry)NULL,
Entry onAfterRun = (Entry)NULL);
//!
template<typename T>
static void expect(const T& exp, const char* fmt = NULL, ...) {
if (exp)
return;
va_list ap;
va_start(ap, fmt);
fail(fmt, ap);
va_end(ap);
}
//! Log message, adds automatically new line if not present.
static void info(const char* fmt, ...);
//! Called on `EXPECT()` failure.
static void fail(const char* fmt, va_list ap);
};
// ============================================================================
// [Broken - Macros]
// ============================================================================
//! Define a unit.
//!
//! `_Name_` can only contain ASCII characters, numbers and underscore. It has
//! the same rules as identifiers in C and C++.
#define UNIT(_Name_) \
static void unit_##_Name_##_entry(void); \
\
static ::BrokenAPI::AutoUnit unit_##_Name_##_autoinit( \
#_Name_, unit_##_Name_##_entry); \
\
static void unit_##_Name_##_entry(void)
//! Informative message printed to stdout.
#define INFO(...) \
::BrokenAPI::info(__VA_ARGS__)
//! Expect `_Exp_` to be truthy, fail otherwise.
#define EXPECT(...) \
do { \
::BrokenAPI::setContext(__FILE__, __LINE__); \
::BrokenAPI::expect(__VA_ARGS__); \
} while(0)
//! \}
// [Guard]
#endif // BROKEN_INTERNAL_H

View File

@@ -4,8 +4,7 @@
// [License] // [License]
// Zlib - See LICENSE.md file in the package. // Zlib - See LICENSE.md file in the package.
// [Dependencies - MiniUnit] // [Dependencies - AsmJit]
#include "./test.h"
#include "../asmjit.h" #include "../asmjit.h"
using namespace asmjit; using namespace asmjit;
@@ -19,22 +18,22 @@ struct DumpCpuFeature {
const char* name; const char* name;
}; };
static void dumpCpuFeatures(const BaseCpuInfo* cpuInfo, const DumpCpuFeature* data, size_t count) { static void dumpCpuFeatures(const CpuInfo* cpuInfo, const DumpCpuFeature* data, size_t count) {
for (size_t i = 0; i < count; i++) for (size_t i = 0; i < count; i++)
if (cpuInfo->hasFeature(data[i].feature)) if (cpuInfo->hasFeature(data[i].feature))
INFO(" %s", data[i].name); INFO(" %s", data[i].name);
} }
static void dumpCpu() { static void dumpCpu(void) {
const BaseCpuInfo* cpuInfo_ = BaseCpuInfo::getHost(); const CpuInfo* cpu = CpuInfo::getHost();
INFO("Host CPU Info:"); INFO("Host CPU Info:");
INFO(" Vendor string : %s", cpuInfo_->getVendorString()); INFO(" Vendor string : %s", cpu->getVendorString());
INFO(" Brand string : %s", cpuInfo_->getBrandString()); INFO(" Brand string : %s", cpu->getBrandString());
INFO(" Family : %u", cpuInfo_->getFamily()); INFO(" Family : %u", cpu->getFamily());
INFO(" Model : %u", cpuInfo_->getModel()); INFO(" Model : %u", cpu->getModel());
INFO(" Stepping : %u", cpuInfo_->getStepping()); INFO(" Stepping : %u", cpu->getStepping());
INFO(" Cores Count : %u", cpuInfo_->getCoresCount()); INFO(" HW-Threads Count : %u", cpu->getHwThreadsCount());
INFO(""); INFO("");
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -42,63 +41,63 @@ static void dumpCpu() {
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64) #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
const x86x64::CpuInfo* cpuInfo = static_cast<const x86x64::CpuInfo*>(cpuInfo_); const X86CpuInfo* x86Cpu = static_cast<const X86CpuInfo*>(cpu);
static const DumpCpuFeature featuresList[] = { static const DumpCpuFeature x86FeaturesList[] = {
{ x86x64::kCpuFeatureMultithreading , "Multithreading" }, { kX86CpuFeatureMultithreading , "Multithreading" },
{ x86x64::kCpuFeatureExecuteDisableBit , "Execute-Disable Bit" }, { kX86CpuFeatureExecuteDisableBit , "Execute-Disable Bit" },
{ x86x64::kCpuFeatureRdtsc , "Rdtsc" }, { kX86CpuFeatureRdtsc , "Rdtsc" },
{ x86x64::kCpuFeatureRdtscp , "Rdtscp" }, { kX86CpuFeatureRdtscp , "Rdtscp" },
{ x86x64::kCpuFeatureCmov , "Cmov" }, { kX86CpuFeatureCmov , "Cmov" },
{ x86x64::kCpuFeatureCmpXchg8B , "Cmpxchg8b" }, { kX86CpuFeatureCmpXchg8B , "Cmpxchg8b" },
{ x86x64::kCpuFeatureCmpXchg16B , "Cmpxchg16b" }, { kX86CpuFeatureCmpXchg16B , "Cmpxchg16b" },
{ x86x64::kCpuFeatureClflush , "Clflush" }, { kX86CpuFeatureClflush , "Clflush" },
{ x86x64::kCpuFeaturePrefetch , "Prefetch" }, { kX86CpuFeaturePrefetch , "Prefetch" },
{ x86x64::kCpuFeatureLahfSahf , "Lahf/Sahf" }, { kX86CpuFeatureLahfSahf , "Lahf/Sahf" },
{ x86x64::kCpuFeatureFxsr , "Fxsave/Fxrstor" }, { kX86CpuFeatureFxsr , "Fxsave/Fxrstor" },
{ x86x64::kCpuFeatureFfxsr , "Fxsave/Fxrstor Opt." }, { kX86CpuFeatureFfxsr , "Fxsave/Fxrstor Opt." },
{ x86x64::kCpuFeatureMmx , "Mmx" }, { kX86CpuFeatureMmx , "Mmx" },
{ x86x64::kCpuFeatureMmxExt , "MmxExt" }, { kX86CpuFeatureMmxExt , "MmxExt" },
{ x86x64::kCpuFeature3dNow , "3dnow" }, { kX86CpuFeature3dNow , "3dnow" },
{ x86x64::kCpuFeature3dNowExt , "3dnowExt" }, { kX86CpuFeature3dNowExt , "3dnowExt" },
{ x86x64::kCpuFeatureSse , "Sse" }, { kX86CpuFeatureSse , "Sse" },
{ x86x64::kCpuFeatureSse2 , "Sse2" }, { kX86CpuFeatureSse2 , "Sse2" },
{ x86x64::kCpuFeatureSse3 , "Sse3" }, { kX86CpuFeatureSse3 , "Sse3" },
{ x86x64::kCpuFeatureSsse3 , "Ssse3" }, { kX86CpuFeatureSsse3 , "Ssse3" },
{ x86x64::kCpuFeatureSse4A , "Sse4a" }, { kX86CpuFeatureSse4A , "Sse4a" },
{ x86x64::kCpuFeatureSse41 , "Sse4.1" }, { kX86CpuFeatureSse41 , "Sse4.1" },
{ x86x64::kCpuFeatureSse42 , "Sse4.2" }, { kX86CpuFeatureSse42 , "Sse4.2" },
{ x86x64::kCpuFeatureMsse , "Misaligned SSE" }, { kX86CpuFeatureMsse , "Misaligned SSE" },
{ x86x64::kCpuFeatureMonitorMWait , "Monitor/MWait" }, { kX86CpuFeatureMonitorMWait , "Monitor/MWait" },
{ x86x64::kCpuFeatureMovbe , "Movbe" }, { kX86CpuFeatureMovbe , "Movbe" },
{ x86x64::kCpuFeaturePopcnt , "Popcnt" }, { kX86CpuFeaturePopcnt , "Popcnt" },
{ x86x64::kCpuFeatureLzcnt , "Lzcnt" }, { kX86CpuFeatureLzcnt , "Lzcnt" },
{ x86x64::kCpuFeatureAesni , "AesNI" }, { kX86CpuFeatureAesni , "AesNI" },
{ x86x64::kCpuFeaturePclmulqdq , "Pclmulqdq" }, { kX86CpuFeaturePclmulqdq , "Pclmulqdq" },
{ x86x64::kCpuFeatureRdrand , "Rdrand" }, { kX86CpuFeatureRdrand , "Rdrand" },
{ x86x64::kCpuFeatureAvx , "Avx" }, { kX86CpuFeatureAvx , "Avx" },
{ x86x64::kCpuFeatureAvx2 , "Avx2" }, { kX86CpuFeatureAvx2 , "Avx2" },
{ x86x64::kCpuFeatureF16C , "F16C" }, { kX86CpuFeatureF16C , "F16C" },
{ x86x64::kCpuFeatureFma3 , "Fma3" }, { kX86CpuFeatureFma3 , "Fma3" },
{ x86x64::kCpuFeatureFma4 , "Fma4" }, { kX86CpuFeatureFma4 , "Fma4" },
{ x86x64::kCpuFeatureXop , "Xop" }, { kX86CpuFeatureXop , "Xop" },
{ x86x64::kCpuFeatureBmi , "Bmi" }, { kX86CpuFeatureBmi , "Bmi" },
{ x86x64::kCpuFeatureBmi2 , "Bmi2" }, { kX86CpuFeatureBmi2 , "Bmi2" },
{ x86x64::kCpuFeatureHle , "Hle" }, { kX86CpuFeatureHle , "Hle" },
{ x86x64::kCpuFeatureRtm , "Rtm" }, { kX86CpuFeatureRtm , "Rtm" },
{ x86x64::kCpuFeatureFsGsBase , "FsGsBase" }, { kX86CpuFeatureFsGsBase , "FsGsBase" },
{ x86x64::kCpuFeatureRepMovsbStosbExt , "RepMovsbStosbExt" } { kX86CpuFeatureRepMovsbStosbExt , "RepMovsbStosbExt" }
}; };
INFO("Host CPU Info (X86/X64):"); INFO("Host CPU Info (X86/X64):");
INFO(" Processor Type : %u", cpuInfo->getProcessorType()); INFO(" Processor Type : %u", x86Cpu->getProcessorType());
INFO(" Brand Index : %u", cpuInfo->getBrandIndex()); INFO(" Brand Index : %u", x86Cpu->getBrandIndex());
INFO(" CL Flush Cache Line : %u", cpuInfo->getFlushCacheLineSize()); INFO(" CL Flush Cache Line : %u", x86Cpu->getFlushCacheLineSize());
INFO(" Max logical Processors: %u", cpuInfo->getMaxLogicalProcessors()); INFO(" Max logical Processors: %u", x86Cpu->getMaxLogicalProcessors());
INFO(""); INFO("");
INFO("Host CPU Features (X86/X64):"); INFO("Host CPU Features (X86/X64):");
dumpCpuFeatures(cpuInfo, featuresList, ASMJIT_ARRAY_SIZE(featuresList)); dumpCpuFeatures(x86Cpu, x86FeaturesList, ASMJIT_ARRAY_SIZE(x86FeaturesList));
INFO(""); INFO("");
#endif // ASMJIT_HOST || ASMJIT_HOST_X64 #endif // ASMJIT_HOST || ASMJIT_HOST_X64
} }
@@ -107,68 +106,68 @@ static void dumpCpu() {
// [DumpSizeOf] // [DumpSizeOf]
// ============================================================================ // ============================================================================
#define DUMP_SIZE(_Type_) \ #define DUMP_TYPE(_Type_) \
INFO(" %-31s: %u", #_Type_, static_cast<uint32_t>(sizeof(_Type_))) INFO(" %-31s: %u", #_Type_, static_cast<uint32_t>(sizeof(_Type_)))
static void dumpSizeOf() { static void dumpSizeOf(void) {
INFO("SizeOf Types:"); INFO("SizeOf Types:");
DUMP_SIZE(int8_t); DUMP_TYPE(int8_t);
DUMP_SIZE(int16_t); DUMP_TYPE(int16_t);
DUMP_SIZE(int32_t); DUMP_TYPE(int32_t);
DUMP_SIZE(int64_t); DUMP_TYPE(int64_t);
DUMP_SIZE(int); DUMP_TYPE(int);
DUMP_SIZE(long); DUMP_TYPE(long);
DUMP_SIZE(size_t); DUMP_TYPE(size_t);
DUMP_SIZE(intptr_t); DUMP_TYPE(intptr_t);
DUMP_SIZE(float); DUMP_TYPE(float);
DUMP_SIZE(double); DUMP_TYPE(double);
DUMP_SIZE(void*); DUMP_TYPE(void*);
DUMP_SIZE(asmjit::Ptr);
DUMP_SIZE(asmjit::SignedPtr);
INFO(""); INFO("");
INFO("SizeOf Base:"); INFO("SizeOf Base:");
DUMP_SIZE(asmjit::CodeGen); DUMP_TYPE(asmjit::CodeGen);
DUMP_SIZE(asmjit::ConstPool); DUMP_TYPE(asmjit::ConstPool);
DUMP_SIZE(asmjit::Runtime); DUMP_TYPE(asmjit::Runtime);
DUMP_SIZE(asmjit::Zone); DUMP_TYPE(asmjit::Zone);
DUMP_TYPE(asmjit::Ptr);
DUMP_TYPE(asmjit::SignedPtr);
INFO(""); INFO("");
INFO("SizeOf Operand:"); INFO("SizeOf Operand:");
DUMP_SIZE(asmjit::Operand); DUMP_TYPE(asmjit::Operand);
DUMP_SIZE(asmjit::BaseReg); DUMP_TYPE(asmjit::Reg);
DUMP_SIZE(asmjit::BaseVar); DUMP_TYPE(asmjit::Var);
DUMP_SIZE(asmjit::BaseMem); DUMP_TYPE(asmjit::BaseMem);
DUMP_SIZE(asmjit::Imm); DUMP_TYPE(asmjit::Imm);
DUMP_SIZE(asmjit::Label); DUMP_TYPE(asmjit::Label);
INFO(""); INFO("");
INFO("SizeOf Assembler:"); INFO("SizeOf Assembler:");
DUMP_SIZE(asmjit::BaseAssembler); DUMP_TYPE(asmjit::Assembler);
DUMP_SIZE(asmjit::LabelData); DUMP_TYPE(asmjit::LabelData);
DUMP_SIZE(asmjit::RelocData); DUMP_TYPE(asmjit::RelocData);
INFO(""); INFO("");
#if !defined(ASMJIT_DISABLE_COMPILER) #if !defined(ASMJIT_DISABLE_COMPILER)
INFO("SizeOf Compiler:"); INFO("SizeOf Compiler:");
DUMP_SIZE(asmjit::BaseCompiler); DUMP_TYPE(asmjit::Compiler);
DUMP_SIZE(asmjit::Node); DUMP_TYPE(asmjit::Node);
DUMP_SIZE(asmjit::AlignNode); DUMP_TYPE(asmjit::AlignNode);
DUMP_SIZE(asmjit::CallNode); DUMP_TYPE(asmjit::CallNode);
DUMP_SIZE(asmjit::CommentNode); DUMP_TYPE(asmjit::CommentNode);
DUMP_SIZE(asmjit::EmbedNode); DUMP_TYPE(asmjit::EmbedNode);
DUMP_SIZE(asmjit::FuncNode); DUMP_TYPE(asmjit::FuncNode);
DUMP_SIZE(asmjit::EndNode); DUMP_TYPE(asmjit::EndNode);
DUMP_SIZE(asmjit::InstNode); DUMP_TYPE(asmjit::InstNode);
DUMP_SIZE(asmjit::JumpNode); DUMP_TYPE(asmjit::JumpNode);
DUMP_SIZE(asmjit::TargetNode); DUMP_TYPE(asmjit::TargetNode);
DUMP_SIZE(asmjit::FuncDecl); DUMP_TYPE(asmjit::FuncDecl);
DUMP_SIZE(asmjit::FuncInOut); DUMP_TYPE(asmjit::FuncInOut);
DUMP_SIZE(asmjit::FuncPrototype); DUMP_TYPE(asmjit::FuncPrototype);
DUMP_SIZE(asmjit::VarAttr); DUMP_TYPE(asmjit::VarAttr);
DUMP_SIZE(asmjit::VarData); DUMP_TYPE(asmjit::VarData);
DUMP_SIZE(asmjit::BaseVarInst); DUMP_TYPE(asmjit::VarMap);
DUMP_SIZE(asmjit::BaseVarState); DUMP_TYPE(asmjit::VarState);
INFO(""); INFO("");
#endif // !ASMJIT_DISABLE_COMPILER #endif // !ASMJIT_DISABLE_COMPILER
@@ -178,30 +177,33 @@ static void dumpSizeOf() {
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) #if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
INFO("SizeOf X86/X64:"); INFO("SizeOf X86/X64:");
DUMP_SIZE(asmjit::x86x64::X86X64Assembler); DUMP_TYPE(asmjit::X86Assembler);
DUMP_SIZE(asmjit::x86x64::X86X64Compiler); #if !defined(ASMJIT_DISABLE_COMPILER)
DUMP_SIZE(asmjit::x86x64::X86X64CallNode); DUMP_TYPE(asmjit::X86Compiler);
DUMP_SIZE(asmjit::x86x64::X86X64FuncNode); DUMP_TYPE(asmjit::X86CallNode);
DUMP_SIZE(asmjit::x86x64::X86X64FuncDecl); DUMP_TYPE(asmjit::X86FuncNode);
DUMP_SIZE(asmjit::x86x64::VarInst); DUMP_TYPE(asmjit::X86FuncDecl);
DUMP_SIZE(asmjit::x86x64::VarState); DUMP_TYPE(asmjit::X86InstInfo);
DUMP_SIZE(asmjit::x86x64::InstInfo); DUMP_TYPE(asmjit::X86VarMap);
DUMP_SIZE(asmjit::x86x64::VarInfo); DUMP_TYPE(asmjit::X86VarInfo);
DUMP_TYPE(asmjit::X86VarState);
#endif // !ASMJIT_DISABLE_COMPILER
INFO(""); INFO("");
#endif // ASMJIT_BUILD_X86 #endif // ASMJIT_BUILD_X86
} }
#undef DUMP_TYPE
// ============================================================================ // ============================================================================
// [Main] // [Main]
// ============================================================================ // ============================================================================
int main(int argc, const char* argv[]) { static void onBeforeRun(void) {
if (MiniUnit::init(argc, argv)) {
dumpCpu(); dumpCpu();
dumpSizeOf(); dumpSizeOf();
MiniUnit::run();
} }
return 0; int main(int argc, const char* argv[]) {
INFO("AsmJit Unit-Test\n\n");
return BrokenAPI::run(argc, argv, onBeforeRun);
} }

View File

@@ -1,112 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - MiniUnit]
#include "./test.h"
// ============================================================================
// [MiniUnit - Statics]
// ============================================================================
int MiniUnit::argc;
const char** MiniUnit::argv;
FILE* MiniUnit::outFile;
MiniUnit::Unit* MiniUnit::unitList;
MiniUnit::Unit* MiniUnit::unitRunning;
// ============================================================================
// [MiniUnit - Init]
// ============================================================================
bool MiniUnit::init(int argc, const char* argv[]) {
MiniUnit::argc = argc;
MiniUnit::argv = argv;
MiniUnit::outFile = stdout;
return unitList != NULL;
}
// ============================================================================
// [MiniUnit - Add]
// ============================================================================
void MiniUnit::addUnit(Unit* unit) {
Unit** pPrev = &unitList;
Unit* current = *pPrev;
while (current != NULL) {
if (::strcmp(current->name, unit->name) >= 0)
break;
pPrev = &current->next;
current = *pPrev;
}
*pPrev = unit;
unit->next = current;
}
// ============================================================================
// [MiniUnit - Run]
// ============================================================================
void MiniUnit::run() {
MiniUnit::Unit* unit = unitList;
while (unit != NULL) {
runUnit(unit);
unit = unit->next;
}
}
void MiniUnit::runUnit(Unit* unit) {
info("[Unit] %s", unit->name);
unitRunning = unit;
unit->entry();
unitRunning = NULL;
}
// ============================================================================
// [MiniUnit - Info]
// ============================================================================
void MiniUnit::info(const char* fmt, ...) {
const char* prefix = unitRunning ? " " : "";
size_t len = ::strlen(fmt);
if (len != 0) {
va_list ap;
va_start(ap, fmt);
::fputs(prefix, outFile);
::vfprintf(outFile, fmt, ap);
va_end(ap);
}
if (len == 0 || fmt[len - 1] != '\n')
::fputs("\n", outFile);
::fflush(outFile);
}
void MiniUnit::fail(const char* file, int line, const char* fmt, ...) {
size_t len = ::strlen(fmt);
if (len != 0) {
va_list ap;
va_start(ap, fmt);
::fputs("[Fail] ", outFile);
::vfprintf(outFile, fmt, ap);
va_end(ap);
}
if (len > 0 && fmt[len - 1] != '\n')
::fputs("\n", outFile);
::fprintf(outFile, "[File] %s (Line: %d)\n", file, line);
::fflush(outFile);
::exit(1);
}

View File

@@ -1,99 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef MINIUNIT_H
#define MINIUNIT_H
// [Dependencies - C]
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
//! \internal
//! \{
// ============================================================================
// [MiniUnit]
// ============================================================================
//! Define a unit.
//!
//! `_Name_` can only contain ASCII characters, numbers and underscore.
#define UNIT(_Name_) \
static void unit_##_Name_##_entry(void); \
static ::MiniUnit::AutoUnit unit_##_Name_##_autoinit(#_Name_, unit_##_Name_##_entry); \
static void unit_##_Name_##_entry(void)
//! Informative message printed to stdout.
#define INFO(...) \
::MiniUnit::info(__VA_ARGS__)
//! Expect `_Exp_` to be truthy, fail otherwise.
#define EXPECT(_Exp_, ...) \
do { \
if (!(_Exp_)) ::MiniUnit::fail(__FILE__, __LINE__, __VA_ARGS__); \
} while(0)
struct MiniUnit {
//! Test entry point.
typedef void (*Entry)(void);
//! Test unit.
struct Unit {
const char* name;
Entry entry;
size_t finished;
Unit* next;
};
//! Automatic unit registration by using static initialization.
struct AutoUnit : Unit {
inline AutoUnit(const char* _name, Entry _entry) {
name = _name;
entry = _entry;
finished = false;
next = NULL;
MiniUnit::addUnit(this);
}
};
//! Test arguments count.
static int argc;
//! Test arguments list.
static const char** argv;
//! File where to log.
static FILE* outFile;
//! Test unit list.
static Unit* unitList;
//! Running test reference.
static Unit* unitRunning;
//! Initialize MiniUnit framework.
//!
//! Returns `true` if `run()` should be called.
static bool init(int argc, const char* argv[]);
//! Register a new test.
static void addUnit(Unit* unit);
//! Run all units.
static void run();
//! Run a single unit.
static void runUnit(Unit* unit);
//! Log message, adds automatically new line if not present.
static void info(const char* fmt, ...);
//! Called on `EXPECT()` failure.
static void fail(const char* file, int line, const char* fmt, ...);
};
//! \}
// [Guard]
#endif // MINIUNIT_H

View File

@@ -14,11 +14,8 @@
#include "x86/x86assembler.h" #include "x86/x86assembler.h"
#include "x86/x86compiler.h" #include "x86/x86compiler.h"
#include "x86/x86cpuinfo.h" #include "x86/x86cpuinfo.h"
#include "x86/x86func.h"
#include "x86/x86inst.h" #include "x86/x86inst.h"
#include "x86/x86operand.h" #include "x86/x86operand.h"
#include "x86/x86regs.h"
#include "x86/x86util.h"
// [Guard] // [Guard]
#endif // _ASMJIT_X86_H #endif // _ASMJIT_X86_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -22,10 +22,12 @@
#include "../apibegin.h" #include "../apibegin.h"
namespace asmjit { namespace asmjit {
namespace x86x64 {
//! \addtogroup asmjit_x86_compiler
//! \{
// ============================================================================ // ============================================================================
// [asmjit::Context] // [asmjit::X86Context]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_DEBUG) #if defined(ASMJIT_DEBUG)
@@ -34,27 +36,24 @@ namespace x86x64 {
# define ASMJIT_X86_CHECK_STATE # define ASMJIT_X86_CHECK_STATE
#endif // ASMJIT_DEBUG #endif // ASMJIT_DEBUG
//! \addtogroup asmjit_x86x64_tree
//! \{
//! \internal //! \internal
//! //!
//! Compiler context is used by `X86X64Compiler`. //! Compiler context is used by `X86Compiler`.
//! //!
//! Compiler context is used during compilation and normally developer doesn't //! Compiler context is used during compilation and normally developer doesn't
//! need access to it. The context is user per function (it's reset after each //! need access to it. The context is user per function (it's reset after each
//! function is generated). //! function is generated).
struct X86X64Context : public BaseContext { struct X86Context : public Context {
ASMJIT_NO_COPY(X86X64Context) ASMJIT_NO_COPY(X86Context)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a new `X86X64Context` instance. //! Create a new `X86Context` instance.
X86X64Context(X86X64Compiler* compiler); X86Context(X86Compiler* compiler);
//! Destroy the `X86X64Context` instance. //! Destroy the `X86Context` instance.
virtual ~X86X64Context(); virtual ~X86Context();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Reset]
@@ -62,22 +61,26 @@ struct X86X64Context : public BaseContext {
virtual void reset(); virtual void reset();
// --------------------------------------------------------------------------
// [Arch]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isX64() const {
return _zsp.getSize() == 16;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get compiler as `X86X64Compiler`. //! Get compiler as `X86Compiler`.
ASMJIT_INLINE X86X64Compiler* getCompiler() const { ASMJIT_INLINE X86Compiler* getCompiler() const {
return static_cast<X86X64Compiler*>(_compiler); return static_cast<X86Compiler*>(_compiler);
} }
//! Get function as `X86X64FuncNode`. //! Get function as `X86FuncNode`.
ASMJIT_INLINE X86X64FuncNode* getFunc() const { ASMJIT_INLINE X86FuncNode* getFunc() const {
return reinterpret_cast<X86X64FuncNode*>(_func); return reinterpret_cast<X86FuncNode*>(_func);
}
ASMJIT_INLINE bool isX64() const {
return _baseRegsCount == 16;
} }
//! Get clobbered registers (global). //! Get clobbered registers (global).
@@ -89,9 +92,9 @@ struct X86X64Context : public BaseContext {
// [Helpers] // [Helpers]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE VarInst* newVarInst(uint32_t vaCount) { ASMJIT_INLINE X86VarMap* newVarMap(uint32_t vaCount) {
return static_cast<VarInst*>( return static_cast<X86VarMap*>(
_baseZone.alloc(sizeof(VarInst) + vaCount * sizeof(VarAttr))); _baseZone.alloc(sizeof(X86VarMap) + vaCount * sizeof(VarAttr)));
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -107,8 +110,8 @@ struct X86X64Context : public BaseContext {
void emitPopSequence(uint32_t regs); void emitPopSequence(uint32_t regs);
void emitConvertVarToVar(uint32_t dstType, uint32_t dstIndex, uint32_t srcType, uint32_t srcIndex); void emitConvertVarToVar(uint32_t dstType, uint32_t dstIndex, uint32_t srcType, uint32_t srcIndex);
void emitMoveVarOnStack(uint32_t dstType, const Mem* dst, uint32_t srcType, uint32_t srcIndex); void emitMoveVarOnStack(uint32_t dstType, const X86Mem* dst, uint32_t srcType, uint32_t srcIndex);
void emitMoveImmOnStack(uint32_t dstType, const Mem* dst, const Imm* src); void emitMoveImmOnStack(uint32_t dstType, const X86Mem* dst, const Imm* src);
void emitMoveImmToReg(uint32_t dstType, uint32_t dstIndex, const Imm* src); void emitMoveImmToReg(uint32_t dstType, uint32_t dstIndex, const Imm* src);
@@ -118,13 +121,6 @@ struct X86X64Context : public BaseContext {
void _checkState(); void _checkState();
ASMJIT_INLINE uint32_t getRegsCount(uint32_t c) const {
if (c == kRegClassGp || c == kRegClassXyz)
return _baseRegsCount;
else
return 8;
}
ASMJIT_INLINE uint32_t getRegSize() const { ASMJIT_INLINE uint32_t getRegSize() const {
return _zsp.getSize(); return _zsp.getSize();
} }
@@ -137,19 +133,20 @@ struct X86X64Context : public BaseContext {
//! //!
//! Attach a register to the 'VarData', changing 'VarData' members to show //! Attach a register to the 'VarData', changing 'VarData' members to show
//! that the variable is currently alive and linking variable with the //! that the variable is currently alive and linking variable with the
//! current 'VarState'. //! current 'X86VarState'.
template<int C> template<int C>
ASMJIT_INLINE void attach(VarData* vd, uint32_t regIndex, bool modified) { ASMJIT_INLINE void attach(VarData* vd, uint32_t regIndex, bool modified) {
ASMJIT_ASSERT(vd->getClass() == C); ASMJIT_ASSERT(vd->getClass() == C);
ASMJIT_ASSERT(regIndex != kInvalidReg); ASMJIT_ASSERT(regIndex != kInvalidReg);
// Prevent Esp allocation if C==Gp. // Prevent Esp allocation if C==Gp.
ASMJIT_ASSERT(C != kRegClassGp || regIndex != kRegIndexSp); ASMJIT_ASSERT(C != kX86RegClassGp || regIndex != kX86RegIndexSp);
uint32_t regMask = IntUtil::mask(regIndex); uint32_t regMask = IntUtil::mask(regIndex);
vd->setState(kVarStateReg); vd->setState(kVarStateReg);
vd->setRegIndex(regIndex); vd->setRegIndex(regIndex);
vd->addHomeIndex(regIndex);
vd->setModified(modified); vd->setModified(modified);
_x86State.getListByClass(C)[regIndex] = vd; _x86State.getListByClass(C)[regIndex] = vd;
@@ -163,7 +160,7 @@ struct X86X64Context : public BaseContext {
//! //!
//! The opposite of 'Attach'. Detach resets the members in 'VarData' //! The opposite of 'Attach'. Detach resets the members in 'VarData'
//! (regIndex, state and changed flags) and unlinks the variable with the //! (regIndex, state and changed flags) and unlinks the variable with the
//! current 'VarState'. //! current 'X86VarState'.
template<int C> template<int C>
ASMJIT_INLINE void detach(VarData* vd, uint32_t regIndex, uint32_t vState) { ASMJIT_INLINE void detach(VarData* vd, uint32_t regIndex, uint32_t vState) {
ASMJIT_ASSERT(vd->getClass() == C); ASMJIT_ASSERT(vd->getClass() == C);
@@ -189,7 +186,7 @@ struct X86X64Context : public BaseContext {
//! Rebase. //! Rebase.
//! //!
//! Change the register of the 'VarData' changing also the current 'VarState'. //! 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' modified flag.
template<int C> template<int C>
@@ -281,11 +278,11 @@ struct X86X64Context : public BaseContext {
ASMJIT_INLINE void swapGp(VarData* aVd, VarData* bVd) { ASMJIT_INLINE void swapGp(VarData* aVd, VarData* bVd) {
ASMJIT_ASSERT(aVd != bVd); ASMJIT_ASSERT(aVd != bVd);
ASMJIT_ASSERT(aVd->getClass() == kRegClassGp); ASMJIT_ASSERT(aVd->getClass() == kX86RegClassGp);
ASMJIT_ASSERT(aVd->getState() == kVarStateReg); ASMJIT_ASSERT(aVd->getState() == kVarStateReg);
ASMJIT_ASSERT(aVd->getRegIndex() != kInvalidReg); ASMJIT_ASSERT(aVd->getRegIndex() != kInvalidReg);
ASMJIT_ASSERT(bVd->getClass() == kRegClassGp); ASMJIT_ASSERT(bVd->getClass() == kX86RegClassGp);
ASMJIT_ASSERT(bVd->getState() == kVarStateReg); ASMJIT_ASSERT(bVd->getState() == kVarStateReg);
ASMJIT_ASSERT(bVd->getRegIndex() != kInvalidReg); ASMJIT_ASSERT(bVd->getRegIndex() != kInvalidReg);
@@ -297,11 +294,11 @@ struct X86X64Context : public BaseContext {
aVd->setRegIndex(bIndex); aVd->setRegIndex(bIndex);
bVd->setRegIndex(aIndex); bVd->setRegIndex(aIndex);
_x86State.getListByClass(kRegClassGp)[aIndex] = bVd; _x86State.getListByClass(kX86RegClassGp)[aIndex] = bVd;
_x86State.getListByClass(kRegClassGp)[bIndex] = aVd; _x86State.getListByClass(kX86RegClassGp)[bIndex] = aVd;
uint32_t m = aVd->isModified() ^ bVd->isModified(); uint32_t m = aVd->isModified() ^ bVd->isModified();
_x86State._modified.xor_(kRegClassGp, (m << aIndex) | (m << bIndex)); _x86State._modified.xor_(kX86RegClassGp, (m << aIndex) | (m << bIndex));
ASMJIT_X86_CHECK_STATE ASMJIT_X86_CHECK_STATE
} }
@@ -310,7 +307,7 @@ struct X86X64Context : public BaseContext {
// [Alloc / Spill] // [Alloc / Spill]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Alloc //! Alloc.
template<int C> template<int C>
ASMJIT_INLINE void alloc(VarData* vd, uint32_t regIndex) { ASMJIT_INLINE void alloc(VarData* vd, uint32_t regIndex) {
ASMJIT_ASSERT(vd->getClass() == C); ASMJIT_ASSERT(vd->getClass() == C);
@@ -415,35 +412,34 @@ struct X86X64Context : public BaseContext {
// [State] // [State]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get state as `VarState`. //! Get state as `X86VarState`.
ASMJIT_INLINE VarState* getState() const { ASMJIT_INLINE X86VarState* getState() const {
return const_cast<VarState*>(&_x86State); return const_cast<X86VarState*>(&_x86State);
} }
virtual void loadState(BaseVarState* src); virtual void loadState(VarState* src);
virtual BaseVarState* saveState(); virtual VarState* saveState();
virtual void switchState(BaseVarState* src); virtual void switchState(VarState* src);
virtual void intersectStates(BaseVarState* a, BaseVarState* b); virtual void intersectStates(VarState* a, VarState* b);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Memory] // [Memory]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE Mem getVarMem(VarData* vd) { ASMJIT_INLINE X86Mem getVarMem(VarData* vd) {
(void)getVarCell(vd); (void)getVarCell(vd);
Mem mem(_memSlot); X86Mem mem(_memSlot);
mem.setBase(vd->getId()); mem.setBase(vd->getId());
return mem; return mem;
} }
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Prepare] // [Fetch]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
virtual Error fetch(); virtual Error fetch();
virtual Error analyze();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Annotate] // [Annotate]
@@ -457,37 +453,43 @@ struct X86X64Context : public BaseContext {
virtual Error translate(); virtual Error translate();
// --------------------------------------------------------------------------
// [Schedule]
// --------------------------------------------------------------------------
virtual Error schedule();
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Serialize] // [Serialize]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
virtual Error serialize(BaseAssembler* assembler, Node* start, Node* stop); virtual Error serialize(Assembler* assembler, Node* start, Node* stop);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Count of X86/X64 registers.
X86RegCount _regCount;
//! X86/X64 stack-pointer (esp or rsp). //! X86/X64 stack-pointer (esp or rsp).
GpReg _zsp; X86GpReg _zsp;
//! X86/X64 frame-pointer (ebp or rbp). //! X86/X64 frame-pointer (ebp or rbp).
GpReg _zbp; X86GpReg _zbp;
//! Temporary memory operand. //! Temporary memory operand.
Mem _memSlot; X86Mem _memSlot;
//! X86/X64 specific compiler state, linked to `_state`. //! X86/X64 specific compiler state, linked to `_state`.
VarState _x86State; X86VarState _x86State;
//! Clobbered registers (for the whole function). //! Clobbered registers (for the whole function).
RegMask _clobberedRegs; X86RegMask _clobberedRegs;
//! 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; MemCell* _stackFrameCell;
//! Global allocable registers mask. //! Global allocable registers mask.
uint32_t _gaRegs[kRegClassCount]; uint32_t _gaRegs[kX86RegClassCount];
//! X86/X64 number of Gp/Xmm registers.
uint8_t _baseRegsCount;
//! Function arguments base pointer (register). //! Function arguments base pointer (register).
uint8_t _argBaseReg; uint8_t _argBaseReg;
//! Function variables base pointer (register). //! Function variables base pointer (register).
@@ -511,7 +513,6 @@ struct X86X64Context : public BaseContext {
//! \} //! \}
} // x86x64 namespace
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -25,33 +25,31 @@
#include "../apibegin.h" #include "../apibegin.h"
namespace asmjit { namespace asmjit {
namespace x86x64 {
// ============================================================================ // ============================================================================
// [asmjit::x86x64::CpuVendor] // [asmjit::X86CpuVendor]
// ============================================================================ // ============================================================================
struct CpuVendor { struct X86CpuVendor {
uint32_t id; uint32_t id;
char text[12]; char text[12];
}; };
static const CpuVendor cpuVendorTable[] = { 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' } },
{ kCpuVendorAmd , { 'A', 'M', 'D', 'i', 's', 'b', 'e', 't', 't', 'e', 'r', '!' } },
{ 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 cpuVendorEq(const CpuVendor& info, const char* vendorString) { static ASMJIT_INLINE bool x86CpuVendorEq(const X86CpuVendor& info, const char* vendorString) {
const uint32_t* a = reinterpret_cast<const uint32_t*>(info.text); const uint32_t* a = reinterpret_cast<const uint32_t*>(info.text);
const uint32_t* b = reinterpret_cast<const uint32_t*>(vendorString); const uint32_t* b = reinterpret_cast<const uint32_t*>(vendorString);
return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]); return (a[0] == b[0]) & (a[1] == b[1]) & (a[2] == b[2]);
} }
static ASMJIT_INLINE void simplifyBrandString(char* s) { static ASMJIT_INLINE void x86SimplifyBrandString(char* s) {
// Always clear the current character in the buffer. It ensures that there // Always clear the current character in the buffer. It ensures that there
// is no garbage after the string NULL terminator. // is no garbage after the string NULL terminator.
char* d = s; char* d = s;
@@ -82,7 +80,7 @@ _Skip:
} }
// ============================================================================ // ============================================================================
// [asmjit::x86x64::CpuUtil] // [asmjit::X86CpuUtil]
// ============================================================================ // ============================================================================
// This is messy, I know. Cpuid is implemented as intrinsic in VS2005, but // This is messy, I know. Cpuid is implemented as intrinsic in VS2005, but
@@ -92,7 +90,7 @@ _Skip:
// callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here. // callCpuId() and detectCpuInfo() for x86 and x64 platforms begins here.
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64) #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
void CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, CpuId* outResult) { void X86CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* outResult) {
#if defined(_MSC_VER) #if defined(_MSC_VER)
// 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler. // 2009-02-05: Thanks to Mike Tajmajer for supporting VC7.1 compiler.
@@ -136,35 +134,43 @@ void CpuUtil::callCpuId(uint32_t inEax, uint32_t inEcx, CpuId* outResult) {
#endif // COMPILER #endif // COMPILER
} }
void CpuUtil::detect(CpuInfo* cpuInfo) { void X86CpuUtil::detect(X86CpuInfo* cpuInfo) {
CpuId regs; X86CpuId regs;
uint32_t i; uint32_t i;
uint32_t maxId; uint32_t maxId;
// Clear everything except the '_size' member. // Clear everything except the '_size' member.
::memset(reinterpret_cast<uint8_t*>(cpuInfo) + sizeof(uint32_t), ::memset(reinterpret_cast<uint8_t*>(cpuInfo) + sizeof(uint32_t),
0, sizeof(BaseCpuInfo) - sizeof(uint32_t)); 0, sizeof(CpuInfo) - sizeof(uint32_t));
// Fill safe defaults. // Fill safe defaults.
::memcpy(cpuInfo->_vendorString, "Unknown", 8); cpuInfo->_hwThreadsCount = CpuInfo::detectHwThreadsCount();
cpuInfo->_coresCount = BaseCpuInfo::detectNumberOfCores();
// --------------------------------------------------------------------------
// [CPUID EAX=0x00000000]
// --------------------------------------------------------------------------
// Get vendor string/id. // Get vendor string/id.
callCpuId(0, 0, &regs); callCpuId(0, 0, &regs);
maxId = regs.eax; maxId = regs.eax;
::memcpy(cpuInfo->_vendorString, &regs.ebx, 4); ::memcpy(cpuInfo->_vendorString, &regs.ebx, 4);
::memcpy(cpuInfo->_vendorString + 4, &regs.edx, 4); ::memcpy(cpuInfo->_vendorString + 4, &regs.edx, 4);
::memcpy(cpuInfo->_vendorString + 8, &regs.ecx, 4); ::memcpy(cpuInfo->_vendorString + 8, &regs.ecx, 4);
for (i = 0; i < ASMJIT_ARRAY_SIZE(cpuVendorTable); i++) { for (i = 0; i < ASMJIT_ARRAY_SIZE(x86CpuVendorList); i++) {
if (cpuVendorEq(cpuVendorTable[i], cpuInfo->_vendorString)) { if (x86CpuVendorEq(x86CpuVendorList[i], cpuInfo->_vendorString)) {
cpuInfo->_vendorId = cpuVendorTable[i].id; cpuInfo->_vendorId = x86CpuVendorList[i].id;
break; break;
} }
} }
// --------------------------------------------------------------------------
// [CPUID EAX=0x00000001]
// --------------------------------------------------------------------------
// Get feature flags in ecx/edx and family/model in eax. // Get feature flags in ecx/edx and family/model in eax.
callCpuId(1, 0, &regs); callCpuId(1, 0, &regs);
@@ -184,60 +190,64 @@ void CpuUtil::detect(CpuInfo* cpuInfo) {
cpuInfo->_flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8; cpuInfo->_flushCacheLineSize = ((regs.ebx >> 8) & 0xFF) * 8;
cpuInfo->_maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF); cpuInfo->_maxLogicalProcessors = ((regs.ebx >> 16) & 0xFF);
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kCpuFeatureSse3); if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureSse3);
if (regs.ecx & 0x00000002U) cpuInfo->addFeature(kCpuFeaturePclmulqdq); if (regs.ecx & 0x00000002U) cpuInfo->addFeature(kX86CpuFeaturePclmulqdq);
if (regs.ecx & 0x00000008U) cpuInfo->addFeature(kCpuFeatureMonitorMWait); if (regs.ecx & 0x00000008U) cpuInfo->addFeature(kX86CpuFeatureMonitorMWait);
if (regs.ecx & 0x00000200U) cpuInfo->addFeature(kCpuFeatureSsse3); if (regs.ecx & 0x00000200U) cpuInfo->addFeature(kX86CpuFeatureSsse3);
if (regs.ecx & 0x00002000U) cpuInfo->addFeature(kCpuFeatureCmpXchg16B); if (regs.ecx & 0x00002000U) cpuInfo->addFeature(kX86CpuFeatureCmpXchg16B);
if (regs.ecx & 0x00080000U) cpuInfo->addFeature(kCpuFeatureSse41); if (regs.ecx & 0x00080000U) cpuInfo->addFeature(kX86CpuFeatureSse41);
if (regs.ecx & 0x00100000U) cpuInfo->addFeature(kCpuFeatureSse42); if (regs.ecx & 0x00100000U) cpuInfo->addFeature(kX86CpuFeatureSse42);
if (regs.ecx & 0x00400000U) cpuInfo->addFeature(kCpuFeatureMovbe); if (regs.ecx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMovbe);
if (regs.ecx & 0x00800000U) cpuInfo->addFeature(kCpuFeaturePopcnt); if (regs.ecx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeaturePopcnt);
if (regs.ecx & 0x02000000U) cpuInfo->addFeature(kCpuFeatureAesni); if (regs.ecx & 0x02000000U) cpuInfo->addFeature(kX86CpuFeatureAesni);
if (regs.ecx & 0x40000000U) cpuInfo->addFeature(kCpuFeatureRdrand); if (regs.ecx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeatureRdrand);
if (regs.edx & 0x00000010U) cpuInfo->addFeature(kCpuFeatureRdtsc); if (regs.edx & 0x00000010U) cpuInfo->addFeature(kX86CpuFeatureRdtsc);
if (regs.edx & 0x00000100U) cpuInfo->addFeature(kCpuFeatureCmpXchg8B); if (regs.edx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeatureCmpXchg8B);
if (regs.edx & 0x00008000U) cpuInfo->addFeature(kCpuFeatureCmov); if (regs.edx & 0x00008000U) cpuInfo->addFeature(kX86CpuFeatureCmov);
if (regs.edx & 0x00800000U) cpuInfo->addFeature(kCpuFeatureMmx); if (regs.edx & 0x00800000U) cpuInfo->addFeature(kX86CpuFeatureMmx);
if (regs.edx & 0x01000000U) cpuInfo->addFeature(kCpuFeatureFxsr); if (regs.edx & 0x01000000U) cpuInfo->addFeature(kX86CpuFeatureFxsr);
if (regs.edx & 0x02000000U) cpuInfo->addFeature(kCpuFeatureSse).addFeature(kCpuFeatureMmxExt); if (regs.edx & 0x02000000U) cpuInfo->addFeature(kX86CpuFeatureSse).addFeature(kX86CpuFeatureMmxExt);
if (regs.edx & 0x04000000U) cpuInfo->addFeature(kCpuFeatureSse).addFeature(kCpuFeatureSse2); if (regs.edx & 0x04000000U) cpuInfo->addFeature(kX86CpuFeatureSse).addFeature(kX86CpuFeatureSse2);
if (regs.edx & 0x10000000U) cpuInfo->addFeature(kCpuFeatureMultithreading); if (regs.edx & 0x10000000U) cpuInfo->addFeature(kX86CpuFeatureMultithreading);
if (cpuInfo->_vendorId == kCpuVendorAmd && (regs.edx & 0x10000000U)) { if (cpuInfo->_vendorId == kCpuVendorAmd && (regs.edx & 0x10000000U)) {
// AMD sets Multithreading to ON if it has more cores. // AMD sets Multithreading to ON if it has more cores.
if (cpuInfo->_coresCount == 1) if (cpuInfo->_hwThreadsCount == 1)
cpuInfo->_coresCount = 2; cpuInfo->_hwThreadsCount = 2;
} }
// Detect AVX. // Detect AVX.
if (regs.ecx & 0x10000000U) { if (regs.ecx & 0x10000000U) {
cpuInfo->addFeature(kCpuFeatureAvx); cpuInfo->addFeature(kX86CpuFeatureAvx);
if (regs.ecx & 0x00000800U) cpuInfo->addFeature(kCpuFeatureXop); if (regs.ecx & 0x00000800U) cpuInfo->addFeature(kX86CpuFeatureXop);
if (regs.ecx & 0x00004000U) cpuInfo->addFeature(kCpuFeatureFma3); if (regs.ecx & 0x00004000U) cpuInfo->addFeature(kX86CpuFeatureFma3);
if (regs.ecx & 0x00010000U) cpuInfo->addFeature(kCpuFeatureFma4); if (regs.ecx & 0x00010000U) cpuInfo->addFeature(kX86CpuFeatureFma4);
if (regs.ecx & 0x20000000U) cpuInfo->addFeature(kCpuFeatureF16C); if (regs.ecx & 0x20000000U) cpuInfo->addFeature(kX86CpuFeatureF16C);
} }
// Detect new features if the processor supports CPUID-07. // Detect new features if the processor supports CPUID-07.
if (maxId >= 7) { if (maxId >= 7) {
callCpuId(7, 0, &regs); callCpuId(7, 0, &regs);
if (regs.ebx & 0x00000001) cpuInfo->addFeature(kCpuFeatureFsGsBase); if (regs.ebx & 0x00000001) cpuInfo->addFeature(kX86CpuFeatureFsGsBase);
if (regs.ebx & 0x00000008) cpuInfo->addFeature(kCpuFeatureBmi); if (regs.ebx & 0x00000008) cpuInfo->addFeature(kX86CpuFeatureBmi);
if (regs.ebx & 0x00000010) cpuInfo->addFeature(kCpuFeatureHle); if (regs.ebx & 0x00000010) cpuInfo->addFeature(kX86CpuFeatureHle);
if (regs.ebx & 0x00000100) cpuInfo->addFeature(kCpuFeatureBmi2); if (regs.ebx & 0x00000100) cpuInfo->addFeature(kX86CpuFeatureBmi2);
if (regs.ebx & 0x00000200) cpuInfo->addFeature(kCpuFeatureRepMovsbStosbExt); if (regs.ebx & 0x00000200) cpuInfo->addFeature(kX86CpuFeatureRepMovsbStosbExt);
if (regs.ebx & 0x00000800) cpuInfo->addFeature(kCpuFeatureRtm); if (regs.ebx & 0x00000800) cpuInfo->addFeature(kX86CpuFeatureRtm);
// AVX2 depends on AVX. // AVX2 depends on AVX.
if (cpuInfo->hasFeature(kCpuFeatureAvx)) { if (cpuInfo->hasFeature(kX86CpuFeatureAvx)) {
if (regs.ebx & 0x00000020) cpuInfo->addFeature(kCpuFeatureAvx2); if (regs.ebx & 0x00000020) cpuInfo->addFeature(kX86CpuFeatureAvx2);
} }
} }
// --------------------------------------------------------------------------
// [CPUID EAX=0x80000000]
// --------------------------------------------------------------------------
// Calling cpuid with 0x80000000 as the in argument gets the number of valid // Calling cpuid with 0x80000000 as the in argument gets the number of valid
// extended IDs. // extended IDs.
callCpuId(0x80000000, 0, &regs); callCpuId(0x80000000, 0, &regs);
@@ -250,18 +260,18 @@ void CpuUtil::detect(CpuInfo* cpuInfo) {
switch (i) { switch (i) {
case 0x80000001: case 0x80000001:
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kCpuFeatureLahfSahf); if (regs.ecx & 0x00000001U) cpuInfo->addFeature(kX86CpuFeatureLahfSahf);
if (regs.ecx & 0x00000020U) cpuInfo->addFeature(kCpuFeatureLzcnt); if (regs.ecx & 0x00000020U) cpuInfo->addFeature(kX86CpuFeatureLzcnt);
if (regs.ecx & 0x00000040U) cpuInfo->addFeature(kCpuFeatureSse4A); if (regs.ecx & 0x00000040U) cpuInfo->addFeature(kX86CpuFeatureSse4A);
if (regs.ecx & 0x00000080U) cpuInfo->addFeature(kCpuFeatureMsse); if (regs.ecx & 0x00000080U) cpuInfo->addFeature(kX86CpuFeatureMsse);
if (regs.ecx & 0x00000100U) cpuInfo->addFeature(kCpuFeaturePrefetch); if (regs.ecx & 0x00000100U) cpuInfo->addFeature(kX86CpuFeaturePrefetch);
if (regs.edx & 0x00100000U) cpuInfo->addFeature(kCpuFeatureExecuteDisableBit); if (regs.edx & 0x00100000U) cpuInfo->addFeature(kX86CpuFeatureExecuteDisableBit);
if (regs.edx & 0x00200000U) cpuInfo->addFeature(kCpuFeatureFfxsr); if (regs.edx & 0x00200000U) cpuInfo->addFeature(kX86CpuFeatureFfxsr);
if (regs.edx & 0x00400000U) cpuInfo->addFeature(kCpuFeatureMmxExt); if (regs.edx & 0x00400000U) cpuInfo->addFeature(kX86CpuFeatureMmxExt);
if (regs.edx & 0x08000000U) cpuInfo->addFeature(kCpuFeatureRdtscp); if (regs.edx & 0x08000000U) cpuInfo->addFeature(kX86CpuFeatureRdtscp);
if (regs.edx & 0x40000000U) cpuInfo->addFeature(kCpuFeature3dNowExt).addFeature(kCpuFeatureMmxExt); if (regs.edx & 0x40000000U) cpuInfo->addFeature(kX86CpuFeature3dNowExt).addFeature(kX86CpuFeatureMmxExt);
if (regs.edx & 0x80000000U) cpuInfo->addFeature(kCpuFeature3dNow); if (regs.edx & 0x80000000U) cpuInfo->addFeature(kX86CpuFeature3dNow);
break; break;
case 0x80000002: case 0x80000002:
@@ -280,11 +290,10 @@ void CpuUtil::detect(CpuInfo* cpuInfo) {
} }
// Simplify the brand string (remove unnecessary spaces to make printing nicer). // Simplify the brand string (remove unnecessary spaces to make printing nicer).
simplifyBrandString(cpuInfo->_brandString); x86SimplifyBrandString(cpuInfo->_brandString);
} }
#endif #endif
} // x86x64 namespace
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -15,120 +15,119 @@
#include "../apibegin.h" #include "../apibegin.h"
namespace asmjit { namespace asmjit {
namespace x86x64 {
// ============================================================================ // ============================================================================
// [Forward Declarations] // [Forward Declarations]
// ============================================================================ // ============================================================================
struct CpuInfo; struct X86CpuInfo;
//! \addtogroup asmjit_x86x64_general //! \addtogroup asmjit_x86_general
//! \{ //! \{
// ============================================================================ // ============================================================================
// [asmjit::x86x64::kCpuFeature] // [asmjit::kX86CpuFeature]
// ============================================================================ // ============================================================================
//! X86 CPU features. //! X86 CPU features.
ASMJIT_ENUM(kCpuFeature) { ASMJIT_ENUM(kX86CpuFeature) {
//! Cpu has multithreading. //! Cpu has multithreading.
kCpuFeatureMultithreading = 1, kX86CpuFeatureMultithreading = 1,
//! Cpu has execute disable bit. //! Cpu has execute disable bit.
kCpuFeatureExecuteDisableBit, kX86CpuFeatureExecuteDisableBit,
//! Cpu has RDTSC. //! Cpu has RDTSC.
kCpuFeatureRdtsc, kX86CpuFeatureRdtsc,
//! Cpu has RDTSCP. //! Cpu has RDTSCP.
kCpuFeatureRdtscp, kX86CpuFeatureRdtscp,
//! Cpu has CMOV. //! Cpu has CMOV.
kCpuFeatureCmov, kX86CpuFeatureCmov,
//! Cpu has CMPXCHG8B. //! Cpu has CMPXCHG8B.
kCpuFeatureCmpXchg8B, kX86CpuFeatureCmpXchg8B,
//! Cpu has CMPXCHG16B (x64). //! Cpu has CMPXCHG16B (x64).
kCpuFeatureCmpXchg16B, kX86CpuFeatureCmpXchg16B,
//! Cpu has CLFUSH. //! Cpu has CLFUSH.
kCpuFeatureClflush, kX86CpuFeatureClflush,
//! Cpu has PREFETCH. //! Cpu has PREFETCH.
kCpuFeaturePrefetch, kX86CpuFeaturePrefetch,
//! Cpu has LAHF/SAHF. //! Cpu has LAHF/SAHF.
kCpuFeatureLahfSahf, kX86CpuFeatureLahfSahf,
//! Cpu has FXSAVE/FXRSTOR. //! Cpu has FXSAVE/FXRSTOR.
kCpuFeatureFxsr, kX86CpuFeatureFxsr,
//! Cpu has FXSAVE/FXRSTOR optimizations. //! Cpu has FXSAVE/FXRSTOR optimizations.
kCpuFeatureFfxsr, kX86CpuFeatureFfxsr,
//! Cpu has MMX. //! Cpu has MMX.
kCpuFeatureMmx, kX86CpuFeatureMmx,
//! Cpu has extended MMX. //! Cpu has extended MMX.
kCpuFeatureMmxExt, kX86CpuFeatureMmxExt,
//! Cpu has 3dNow! //! Cpu has 3dNow!
kCpuFeature3dNow, kX86CpuFeature3dNow,
//! Cpu has enchanced 3dNow! //! Cpu has enchanced 3dNow!
kCpuFeature3dNowExt, kX86CpuFeature3dNowExt,
//! Cpu has SSE. //! Cpu has SSE.
kCpuFeatureSse, kX86CpuFeatureSse,
//! Cpu has SSE2. //! Cpu has SSE2.
kCpuFeatureSse2, kX86CpuFeatureSse2,
//! Cpu has SSE3. //! Cpu has SSE3.
kCpuFeatureSse3, kX86CpuFeatureSse3,
//! Cpu has Supplemental SSE3 (SSSE3). //! Cpu has Supplemental SSE3 (SSSE3).
kCpuFeatureSsse3, kX86CpuFeatureSsse3,
//! Cpu has SSE4.A. //! Cpu has SSE4.A.
kCpuFeatureSse4A, kX86CpuFeatureSse4A,
//! Cpu has SSE4.1. //! Cpu has SSE4.1.
kCpuFeatureSse41, kX86CpuFeatureSse41,
//! Cpu has SSE4.2. //! Cpu has SSE4.2.
kCpuFeatureSse42, kX86CpuFeatureSse42,
//! Cpu has Misaligned SSE (MSSE). //! Cpu has Misaligned SSE (MSSE).
kCpuFeatureMsse, kX86CpuFeatureMsse,
//! Cpu has MONITOR and MWAIT. //! Cpu has MONITOR and MWAIT.
kCpuFeatureMonitorMWait, kX86CpuFeatureMonitorMWait,
//! Cpu has MOVBE. //! Cpu has MOVBE.
kCpuFeatureMovbe, kX86CpuFeatureMovbe,
//! Cpu has POPCNT. //! Cpu has POPCNT.
kCpuFeaturePopcnt, kX86CpuFeaturePopcnt,
//! Cpu has LZCNT. //! Cpu has LZCNT.
kCpuFeatureLzcnt, kX86CpuFeatureLzcnt,
//! Cpu has AESNI. //! Cpu has AESNI.
kCpuFeatureAesni, kX86CpuFeatureAesni,
//! Cpu has PCLMULQDQ. //! Cpu has PCLMULQDQ.
kCpuFeaturePclmulqdq, kX86CpuFeaturePclmulqdq,
//! Cpu has RDRAND. //! Cpu has RDRAND.
kCpuFeatureRdrand, kX86CpuFeatureRdrand,
//! Cpu has AVX. //! Cpu has AVX.
kCpuFeatureAvx, kX86CpuFeatureAvx,
//! Cpu has AVX2. //! Cpu has AVX2.
kCpuFeatureAvx2, kX86CpuFeatureAvx2,
//! Cpu has F16C. //! Cpu has F16C.
kCpuFeatureF16C, kX86CpuFeatureF16C,
//! Cpu has FMA3. //! Cpu has FMA3.
kCpuFeatureFma3, kX86CpuFeatureFma3,
//! Cpu has FMA4. //! Cpu has FMA4.
kCpuFeatureFma4, kX86CpuFeatureFma4,
//! Cpu has XOP. //! Cpu has XOP.
kCpuFeatureXop, kX86CpuFeatureXop,
//! Cpu has BMI. //! Cpu has BMI.
kCpuFeatureBmi, kX86CpuFeatureBmi,
//! Cpu has BMI2. //! Cpu has BMI2.
kCpuFeatureBmi2, kX86CpuFeatureBmi2,
//! Cpu has HLE. //! Cpu has HLE.
kCpuFeatureHle, kX86CpuFeatureHle,
//! Cpu has RTM. //! Cpu has RTM.
kCpuFeatureRtm, kX86CpuFeatureRtm,
//! Cpu has FSGSBASE. //! Cpu has FSGSBASE.
kCpuFeatureFsGsBase, kX86CpuFeatureFsGsBase,
//! Cpu has enhanced REP MOVSB/STOSB. //! Cpu has enhanced REP MOVSB/STOSB.
kCpuFeatureRepMovsbStosbExt, kX86CpuFeatureRepMovsbStosbExt,
//! Count of X86/X64 Cpu features. //! Count of X86/X64 Cpu features.
kCpuFeatureCount kX86CpuFeatureCount
}; };
// ============================================================================ // ============================================================================
// [asmjit::x86x64::CpuId] // [asmjit::X86CpuId]
// ============================================================================ // ============================================================================
//! X86/X64 CPUID output. //! X86/X64 CPUID output.
union CpuId { union X86CpuId {
//! EAX/EBX/ECX/EDX output. //! EAX/EBX/ECX/EDX output.
uint32_t i[4]; uint32_t i[4];
@@ -145,33 +144,33 @@ union CpuId {
}; };
// ============================================================================ // ============================================================================
// [asmjit::x86x64::CpuUtil] // [asmjit::X86CpuUtil]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64) #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
//! CPU utilities available only if the host processor is X86/X64. //! CPU utilities available only if the host processor is X86/X64.
struct CpuUtil { struct X86CpuUtil {
//! Get the result of calling CPUID instruction to `out`. //! Get the result of calling CPUID instruction to `out`.
ASMJIT_API static void callCpuId(uint32_t inEax, uint32_t inEcx, CpuId* out); ASMJIT_API static void callCpuId(uint32_t inEax, uint32_t inEcx, X86CpuId* out);
//! Detect the Host CPU. //! Detect the Host CPU.
ASMJIT_API static void detect(CpuInfo* cpuInfo); ASMJIT_API static void detect(X86CpuInfo* cpuInfo);
}; };
#endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64 #endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64
// ============================================================================ // ============================================================================
// [asmjit::x86x64::CpuInfo] // [asmjit::X86CpuInfo]
// ============================================================================ // ============================================================================
struct CpuInfo : public BaseCpuInfo { struct X86CpuInfo : public CpuInfo {
ASMJIT_NO_COPY(CpuInfo) ASMJIT_NO_COPY(X86CpuInfo)
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_INLINE CpuInfo(uint32_t size = sizeof(CpuInfo)) : ASMJIT_INLINE X86CpuInfo(uint32_t size = sizeof(X86CpuInfo)) :
BaseCpuInfo(size) {} CpuInfo(size) {}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Accessors] // [Accessors]
@@ -201,10 +200,12 @@ struct CpuInfo : public BaseCpuInfo {
// [Statics] // [Statics]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get global instance of `x86x64::CpuInfo`. #if defined(ASMJIT_HOST_X86) || defined(ASMJIT_HOST_X64)
static ASMJIT_INLINE const CpuInfo* getHost() { //! Get global instance of `X86CpuInfo`.
return static_cast<const CpuInfo*>(BaseCpuInfo::getHost()); static ASMJIT_INLINE const X86CpuInfo* getHost() {
return static_cast<const X86CpuInfo*>(CpuInfo::getHost());
} }
#endif // ASMJIT_HOST_X86 || ASMJIT_HOST_X64
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -222,7 +223,6 @@ struct CpuInfo : public BaseCpuInfo {
//! \} //! \}
} // x86x64 namespace
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]

View File

@@ -1,547 +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
// [Guard]
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER) && (defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64))
// [Dependencies - AsmJit]
#include "../base/globals.h"
#include "../base/intutil.h"
#include "../base/string.h"
#include "../x86/x86func.h"
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
// ============================================================================
// [asmjit::X86X64FuncDecl - Helpers]
// ============================================================================
static ASMJIT_INLINE bool x86ArgIsInt(uint32_t aType) {
ASMJIT_ASSERT(aType < kVarTypeCount);
return IntUtil::inInterval<uint32_t>(aType, _kVarTypeIntStart, _kVarTypeIntEnd);
}
static ASMJIT_INLINE bool x86ArgIsFp(uint32_t aType) {
ASMJIT_ASSERT(aType < kVarTypeCount);
return IntUtil::inInterval<uint32_t>(aType, _kVarTypeFpStart, _kVarTypeFpEnd);
}
static ASMJIT_INLINE uint32_t x86ArgTypeToXmmType(uint32_t aType) {
if (aType == kVarTypeFp32)
return kVarTypeXmmSs;
if (aType == kVarTypeFp64)
return kVarTypeXmmSd;
return aType;
}
//! Get an architecture from calling convention.
//!
//! Returns `kArchX86` or `kArchX64` depending on `conv`.
static ASMJIT_INLINE uint32_t x86GetArchFromCConv(uint32_t conv) {
return IntUtil::inInterval<uint32_t>(conv, kFuncConvX64W, kFuncConvX64U) ? kArchX64 : kArchX86;
}
// ============================================================================
// [asmjit::X86X64FuncDecl - SetPrototype]
// ============================================================================
#define R(_Index_) kRegIndex##_Index_
static uint32_t X86X64FuncDecl_initConv(X86X64FuncDecl* self, uint32_t arch, uint32_t conv) {
// Setup defaults.
self->_argStackSize = 0;
self->_redZoneSize = 0;
self->_spillZoneSize = 0;
self->_convention = static_cast<uint8_t>(conv);
self->_calleePopsStack = false;
self->_direction = kFuncDirRtl;
self->_passed.reset();
self->_preserved.reset();
::memset(self->_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderGp));
::memset(self->_passedOrderXmm, kInvalidReg, ASMJIT_ARRAY_SIZE(self->_passedOrderXmm));
// --------------------------------------------------------------------------
// [X86 Support]
// --------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86) {
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di)));
switch (conv) {
case kFuncConvCDecl:
break;
case kFuncConvStdCall:
self->_calleePopsStack = true;
break;
case kFuncConvMsThisCall:
self->_calleePopsStack = true;
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx)));
self->_passedOrderGp[0] = R(Cx);
break;
case kFuncConvMsFastCall:
self->_calleePopsStack = true;
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Cx)));
self->_passedOrderGp[0] = R(Cx);
self->_passedOrderGp[1] = R(Dx);
break;
case kFuncConvBorlandFastCall:
self->_calleePopsStack = true;
self->_direction = kFuncDirLtr;
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx), R(Cx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
self->_passedOrderGp[2] = R(Cx);
break;
case kFuncConvGccFastCall:
self->_calleePopsStack = true;
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Dx)));
self->_passedOrderGp[0] = R(Cx);
self->_passedOrderGp[1] = R(Dx);
break;
case kFuncConvGccRegParm1:
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax)));
self->_passedOrderGp[0] = R(Ax);
break;
case kFuncConvGccRegParm2:
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
break;
case kFuncConvGccRegParm3:
self->_passed.set(kRegClassGp, IntUtil::mask(R(Ax), R(Dx), R(Cx)));
self->_passedOrderGp[0] = R(Ax);
self->_passedOrderGp[1] = R(Dx);
self->_passedOrderGp[2] = R(Cx);
break;
default:
ASMJIT_ASSERT(!"Reached");
}
return kErrorOk;
}
#endif // ASMJIT_BUILD_X86
// --------------------------------------------------------------------------
// [X64 Support]
// --------------------------------------------------------------------------
#if defined(ASMJIT_BUILD_X64)
switch (conv) {
case kFuncConvX64W:
self->_spillZoneSize = 32;
self->_passed.set(kRegClassGp, IntUtil::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(kRegClassXyz, IntUtil::mask(0, 1, 2, 3));
self->_passedOrderXmm[0] = 0;
self->_passedOrderXmm[1] = 1;
self->_passedOrderXmm[2] = 2;
self->_passedOrderXmm[3] = 3;
self->_preserved.set(kRegClassGp , IntUtil::mask(R(Bx), R(Sp), R(Bp), R(Si), R(Di), 12, 13, 14, 15));
self->_preserved.set(kRegClassXyz, IntUtil::mask(6, 7, 8, 9, 10, 11, 12, 13, 14, 15));
break;
case kFuncConvX64U:
self->_redZoneSize = 128;
self->_passed.set(kRegClassGp, IntUtil::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(kRegClassXyz, IntUtil::mask(0, 1, 2, 3, 4, 5, 6, 7));
self->_passedOrderXmm[0] = 0;
self->_passedOrderXmm[1] = 1;
self->_passedOrderXmm[2] = 2;
self->_passedOrderXmm[3] = 3;
self->_passedOrderXmm[4] = 4;
self->_passedOrderXmm[5] = 5;
self->_passedOrderXmm[6] = 6;
self->_passedOrderXmm[7] = 7;
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), 12, 13, 14, 15));
break;
default:
ASMJIT_ASSERT(!"Reached");
}
#endif // ASMJIT_BUILD_X64
return kErrorOk;
}
#undef R
static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
uint32_t ret, const uint32_t* argList, uint32_t argCount) {
ASMJIT_ASSERT(argCount <= kFuncArgCount);
uint32_t conv = self->_convention;
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;
#if defined(ASMJIT_BUILD_X86)
if (arch == kArchX86)
varMapping = x86::_varMapping;
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_X64)
if (arch == kArchX64)
varMapping = x64::_varMapping;
#endif // ASMJIT_BUILD_X64
self->_argCount = static_cast<uint8_t>(argCount);
self->_retCount = 0;
for (i = 0; i < static_cast<int32_t>(argCount); i++) {
FuncInOut& arg = self->getArg(i);
arg._varType = static_cast<uint8_t>(argList[i]);
arg._regIndex = kInvalidReg;
arg._stackOffset = kFuncStackInvalid;
}
for (; i < kFuncArgCount; i++) {
self->_argList[i].reset();
}
self->_retList[0].reset();
self->_retList[1].reset();
self->_argStackSize = 0;
self->_used.reset();
if (ret != kVarTypeInvalid) {
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->_retList[0]._varType = kVarTypeUInt32;
self->_retList[0]._regIndex = kRegIndexAx;
self->_retList[1]._varType = static_cast<uint8_t>(ret - 2);
self->_retList[1]._regIndex = kRegIndexDx;
}
#endif // ASMJIT_BUILD_X86
// ... Fall through ...
case kVarTypeInt8:
case kVarTypeUInt8:
case kVarTypeInt16:
case kVarTypeUInt16:
case kVarTypeInt32:
case kVarTypeUInt32:
self->_retCount = 1;
self->_retList[0]._varType = static_cast<uint8_t>(ret);
self->_retList[0]._regIndex = kRegIndexAx;
break;
case kVarTypeMm:
self->_retCount = 1;
self->_retList[0]._varType = static_cast<uint8_t>(ret);
self->_retList[0]._regIndex = 0;
break;
case kVarTypeFp32:
self->_retCount = 1;
if (arch == kArchX86) {
self->_retList[0]._varType = kVarTypeFp32;
self->_retList[0]._regIndex = 0;
}
else {
self->_retList[0]._varType = kVarTypeXmmSs;
self->_retList[0]._regIndex = 0;
}
break;
case kVarTypeFp64:
self->_retCount = 1;
if (arch == kArchX86) {
self->_retList[0]._varType = kVarTypeFp64;
self->_retList[0]._regIndex = 0;
}
else {
self->_retList[0]._varType = kVarTypeXmmSd;
self->_retList[0]._regIndex = 0;
break;
}
break;
case kVarTypeXmm:
case kVarTypeXmmSs:
case kVarTypeXmmSd:
case kVarTypeXmmPs:
case kVarTypeXmmPd:
self->_retCount = 1;
self->_retList[0]._varType = static_cast<uint8_t>(ret);
self->_retList[0]._regIndex = 0;
break;
}
}
if (self->_argCount == 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>(argCount); 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.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
}
// Stack arguments.
int32_t iStart = static_cast<int32_t>(argCount - 1);
int32_t iEnd = -1;
int32_t iStep = -1;
if (self->_direction == kFuncDirLtr) {
iStart = 0;
iEnd = static_cast<int32_t>(argCount);
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>(_varInfo[varType].getSize());
stackOffset -= size;
arg._stackOffset = static_cast<int16_t>(stackOffset);
}
}
}
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_X64)
if (arch == kArchX64) {
if (conv == kFuncConvX64W) {
int32_t argMax = IntUtil::iMin<int32_t>(argCount, 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.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
continue;
}
if (x86ArgIsFp(varType) && i < ASMJIT_ARRAY_SIZE(self->_passedOrderXmm)) {
arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType));
arg._regIndex = self->_passedOrderXmm[i];
self->_used.add(kRegClassXyz, IntUtil::mask(arg.getRegIndex()));
}
}
// Stack arguments (always right-to-left).
for (i = argCount - 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>(argCount); 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.add(kRegClassGp, IntUtil::mask(arg.getRegIndex()));
}
// Register arguments (Xmm), always left-to-right.
for (i = 0; i != static_cast<int32_t>(argCount); 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->_passedOrderXmm[xmmPos++];
self->_used.add(kRegClassXyz, IntUtil::mask(arg.getRegIndex()));
}
}
// Stack arguments.
for (i = argCount - 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>(_varInfo[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>(argCount); 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 X86X64FuncDecl::setPrototype(uint32_t conv, const FuncPrototype& p) {
if (conv == kFuncConvNone || conv >= _kFuncConvCount)
return kErrorInvalidArgument;
if (p.getArgCount() > kFuncArgCount)
return kErrorInvalidArgument;
// Validate that the required convention is supported by the current asmjit
// configuration, if only one target is compiled.
uint32_t arch = x86GetArchFromCConv(conv);
#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(X86X64FuncDecl_initConv(this, arch, conv));
ASMJIT_PROPAGATE_ERROR(X86X64FuncDecl_initFunc(this, arch, p.getRet(), p.getArgList(), p.getArgCount()));
return kErrorOk;
}
// ============================================================================
// [asmjit::X86X64FuncDecl - Reset]
// ============================================================================
void X86X64FuncDecl::reset() {
uint32_t i;
_convention = kFuncConvNone;
_calleePopsStack = false;
_direction = kFuncDirRtl;
_reserved0 = 0;
_argCount = 0;
_retCount = 0;
_argStackSize = 0;
_redZoneSize = 0;
_spillZoneSize = 0;
for (i = 0; i < ASMJIT_ARRAY_SIZE(_argList); i++) {
_argList[i].reset();
}
_retList[0].reset();
_retList[1].reset();
_used.reset();
_passed.reset();
_preserved.reset();
::memset(_passedOrderGp, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderGp));
::memset(_passedOrderXmm, kInvalidReg, ASMJIT_ARRAY_SIZE(_passedOrderXmm));
}
} // x86x64 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)

View File

@@ -1,492 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86FUNC_H
#define _ASMJIT_X86_X86FUNC_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../base/func.h"
#include "../x86/x86util.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
//! \addtogroup asmjit_x86x64_tree
//! \{
// ============================================================================
// [asmjit::x86x64::kFuncConv]
// ============================================================================
//! X86 function calling conventions.
//!
//! Calling convention is scheme how function arguments are passed into
//! function and how functions returns values. In assembler programming
//! it's needed to always comply with function calling conventions, because
//! even small inconsistency can cause undefined behavior or crash.
//!
//! List of calling conventions for 32-bit x86 mode:
//! - `kFuncConvCDecl` - Calling convention for C runtime.
//! - `kFuncConvStdCall` - Calling convention for WinAPI functions.
//! - `kFuncConvMsThisCall` - Calling convention for C++ members under
//! Windows (produced by MSVC and all MSVC compatible compilers).
//! - `kFuncConvMsFastCall` - Fastest calling convention that can be used
//! by MSVC compiler.
//! - `kFuncConvBorlandFastCall` - Borland fastcall convention.
//! - `kFuncConvGccFastCall` - GCC fastcall convention (2 register arguments).
//! - `kFuncConvGccRegParm1` - GCC regparm(1) convention.
//! - `kFuncConvGccRegParm2` - GCC regparm(2) convention.
//! - `kFuncConvGccRegParm3` - GCC regparm(3) convention.
//!
//! List of calling conventions for 64-bit x86 mode (x64):
//! - `kFuncConvX64W` - Windows 64-bit calling convention (WIN64 ABI).
//! - `kFuncConvX64U` - Unix 64-bit calling convention (AMD64 ABI).
//!
//! There is also `kFuncConvHost` that is defined to fit the host calling
//! convention.
//!
//! These types are used together with `BaseCompiler::addFunc()` method.
ASMJIT_ENUM(kFuncConv) {
// --------------------------------------------------------------------------
// [X64]
// --------------------------------------------------------------------------
//! X64 calling convention for Windows platform (WIN64 ABI).
//!
//! For first four arguments are used these registers:
//! - 1. 32/64-bit integer or floating point argument - rcx/xmm0
//! - 2. 32/64-bit integer or floating point argument - rdx/xmm1
//! - 3. 32/64-bit integer or floating point argument - r8/xmm2
//! - 4. 32/64-bit integer or floating point argument - r9/xmm3
//!
//! Note first four arguments here means arguments at positions from 1 to 4
//! (included). For example if second argument is not passed in register then
//! rdx/xmm1 register is unused.
//!
//! All other arguments are pushed on the stack in right-to-left direction.
//! Stack is aligned by 16 bytes. There is 32-byte shadow space on the stack
//! that can be used to save up to four 64-bit registers (probably designed to
//! be used to save first four arguments passed in registers).
//!
//! Arguments direction:
//! - Right to Left (except for first 4 parameters that's in registers)
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - Rax register.
//! - Floating points - Xmm0 register.
//!
//! Stack is always aligned by 16 bytes.
//!
//! More information about this calling convention can be found on MSDN:
//! http://msdn.microsoft.com/en-us/library/9b372w95.aspx .
kFuncConvX64W = 1,
//! X64 calling convention for Unix platforms (AMD64 ABI).
//!
//! First six 32 or 64-bit integer arguments are passed in rdi, rsi, rdx,
//! rcx, r8, r9 registers. First eight floating point or Xmm arguments
//! are passed in xmm0, xmm1, xmm2, xmm3, xmm4, xmm5, xmm6, xmm7 registers.
//! This means that in registers can be transferred up to 14 arguments total.
//!
//! There is also RED ZONE below the stack pointer that can be used for
//! temporary storage. The red zone is the space from [rsp-128] to [rsp-8].
//!
//! Arguments direction:
//! - Right to Left (Except for arguments passed in registers).
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - Rax register.
//! - Floating points - Xmm0 register.
//!
//! Stack is always aligned by 16 bytes.
kFuncConvX64U = 2,
// --------------------------------------------------------------------------
// [X86]
// --------------------------------------------------------------------------
//! Cdecl calling convention (used by C runtime).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to Left
//!
//! Stack is cleaned by:
//! - Caller.
kFuncConvCDecl = 3,
//! Stdcall calling convention (used by WinAPI).
//!
//! Compatible across MSVC and GCC.
//!
//! Arguments direction:
//! - Right to Left
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
kFuncConvStdCall = 4,
//! MSVC specific calling convention used by MSVC/Intel compilers
//! for struct/class methods.
//!
//! This is MSVC (and Intel) only calling convention used in Windows
//! world for C++ class methods. Implicit 'this' pointer is stored in
//! ECX register instead of storing it on the stack.
//!
//! Arguments direction:
//! - Right to Left (except this pointer in ECX)
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! C++ class methods that have variable count of arguments uses different
//! calling convention called cdecl.
//!
//! \note This calling convention is always used by MSVC for class methods,
//! it's implicit and there is no way how to override it.
kFuncConvMsThisCall = 5,
//! MSVC specific fastcall.
//!
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
//! registers, all others on the stack in right-to-left order.
//!
//! Arguments direction:
//! - Right to Left (except to first two integer arguments in ECX:EDX)
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! \note This calling convention differs to GCC one in stack cleaning
//! mechanism.
kFuncConvMsFastCall = 6,
//! Borland specific fastcall with 2 parameters in registers.
//!
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
//! registers, all others on the stack in left-to-right order.
//!
//! Arguments direction:
//! - Left to Right (except to first two integer arguments in ECX:EDX)
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! \note Arguments on the stack are in left-to-right order that differs
//! to other fastcall conventions used in different compilers.
kFuncConvBorlandFastCall = 7,
//! GCC specific fastcall convention.
//!
//! Two first parameters (evaluated from left-to-right) are in ECX:EDX
//! registers, all others on the stack in right-to-left order.
//!
//! Arguments direction:
//! - Right to Left (except to first two integer arguments in ECX:EDX)
//!
//! Stack is cleaned by:
//! - Callee.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! \note This calling convention should be compatible with `kFuncConvMsFastCall`.
kFuncConvGccFastCall = 8,
//! GCC specific regparm(1) convention.
//!
//! The first parameter (evaluated from left-to-right) is in EAX register,
//! all others on the stack in right-to-left order.
//!
//! Arguments direction:
//! - Right to Left (except to first one integer argument in EAX)
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
kFuncConvGccRegParm1 = 9,
//! GCC specific regparm(2) convention.
//!
//! Two first parameters (evaluated from left-to-right) are in EAX:EDX
//! registers, all others on the stack in right-to-left order.
//!
//! Arguments direction:
//! - Right to Left (except to first two integer arguments in EAX:EDX)
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
kFuncConvGccRegParm2 = 10,
//! GCC specific fastcall with 3 parameters in registers.
//!
//! Three first parameters (evaluated from left-to-right) are in
//! EAX:EDX:ECX registers, all others on the stack in right-to-left order.
//!
//! Arguments direction:
//! - Right to Left (except to first three integer arguments in EAX:EDX:ECX)
//!
//! Stack is cleaned by:
//! - Caller.
//!
//! Return value:
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
kFuncConvGccRegParm3 = 11,
//! \internal
//!
//! Count of function calling conventions.
_kFuncConvCount = 12,
// --------------------------------------------------------------------------
// [Host]
// --------------------------------------------------------------------------
#if defined(ASMJIT_DOCGEN)
//! Default calling convention for current platform / operating system.
kFuncConvHost = DependsOnHost,
//! Default C calling convention based on current compiler's settings.
kFuncConvHostCDecl = DependsOnHost,
//! Compatibility for `__stdcall` calling convention.
//!
//! \note This enumeration is always set to a value which is compatible with
//! current compilers __stdcall calling convention. In 64-bit mode the value
//! is compatible with `kFuncConvX64W` or `kFuncConvX64U`.
kFuncConvHostStdCall = DependsOnHost,
//! Compatibility for `__fastcall` calling convention.
//!
//! \note This enumeration is always set to a value which is compatible with
//! current compilers `__fastcall` calling convention. In 64-bit mode the value
//! is compatible with `kFuncConvX64W` or `kFuncConvX64U`.
kFuncConvHostFastCall = DependsOnHost
#elif defined(ASMJIT_HOST_X86)
// X86.
kFuncConvHost = kFuncConvCDecl,
kFuncConvHostCDecl = kFuncConvCDecl,
kFuncConvHostStdCall = kFuncConvStdCall,
#if defined(_MSC_VER)
kFuncConvHostFastCall = kFuncConvMsFastCall
#elif defined(__GNUC__)
kFuncConvHostFastCall = kFuncConvGccFastCall
#elif defined(__BORLANDC__)
kFuncConvHostFastCall = kFuncConvBorlandFastCall
#else
#error "kFuncConvHostFastCall not determined."
#endif
#else
// X64.
#if defined(ASMJIT_OS_WINDOWS)
kFuncConvHost = kFuncConvX64W,
#else
kFuncConvHost = kFuncConvX64U,
#endif
kFuncConvHostCDecl = kFuncConvHost,
kFuncConvHostStdCall = kFuncConvHost,
kFuncConvHostFastCall = kFuncConvHost
#endif
};
// ============================================================================
// [asmjit::x86x64::kFuncHint]
// ============================================================================
//! X86 function hints.
ASMJIT_ENUM(kFuncHint) {
//! Use push/pop sequences instead of mov sequences in function prolog
//! and epilog.
kFuncHintPushPop = 16,
//! Add emms instruction to the function epilog.
kFuncHintEmms = 17,
//! Add sfence instruction to the function epilog.
kFuncHintSFence = 18,
//! Add lfence instruction to the function epilog.
kFuncHintLFence = 19
};
// ============================================================================
// [asmjit::x86x64::kFuncFlags]
// ============================================================================
//! X86 function flags.
ASMJIT_ENUM(kFuncFlags) {
//! Whether to emit register load/save sequence using push/pop pairs.
kFuncFlagPushPop = 0x00010000,
//! Whether to emit `enter` instead of three instructions in case
//! that the function is not naked or misaligned.
kFuncFlagEnter = 0x00020000,
//! Whether to emit `leave` instead of two instructions in case
//! that the function is not naked or misaligned.
kFuncFlagLeave = 0x00040000,
//! Whether it's required to move arguments to a new stack location,
//! because of manual aligning.
kFuncFlagMoveArgs = 0x00080000,
//! Whether to emit `emms` instruction in epilog (auto-detected).
kFuncFlagEmms = 0x01000000,
//! Whether to emit `sfence` instruction in epilog (auto-detected).
//!
//! `kFuncFlagSFence` with `kFuncFlagLFence` results in emitting `mfence`.
kFuncFlagSFence = 0x02000000,
//! Whether to emit `lfence` instruction in epilog (auto-detected).
//!
//! `kFuncFlagSFence` with `kFuncFlagLFence` results in emitting `mfence`.
kFuncFlagLFence = 0x04000000
};
// ============================================================================
// [asmjit::x86x64::X86X64FuncDecl]
// ============================================================================
//! X86 function, including calling convention, arguments and their
//! register indices or stack positions.
struct X86X64FuncDecl : public FuncDecl {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `X86X64FuncDecl` instance.
ASMJIT_INLINE X86X64FuncDecl() {
reset();
}
// --------------------------------------------------------------------------
// [Accessors - X86]
// --------------------------------------------------------------------------
//! Get used registers (mask).
//!
//! \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 c) const {
return _used.get(c);
}
//! Get passed registers (mask).
//!
//! \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 c) const {
return _passed.get(c);
}
//! Get preserved registers (mask).
//!
//! \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 c) const {
return _preserved.get(c);
}
//! 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).
//!
//! \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* getPassedOrderXmm() const {
return _passedOrderXmm;
}
// --------------------------------------------------------------------------
// [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(uint32_t conv, const FuncPrototype& p);
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Used registers.
RegMask _used;
//! Passed registers (defined by the calling convention).
RegMask _passed;
//! Preserved registers (defined by the calling convention).
RegMask _preserved;
//! Order of registers defined to pass function arguments (Gp).
uint8_t _passedOrderGp[8];
//! Order of registers defined to pass function arguments (Xmm).
uint8_t _passedOrderXmm[8];
};
//! \}
} // x86x64 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_X86_X86FUNC_H

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -18,48 +18,14 @@
#include "../apibegin.h" #include "../apibegin.h"
namespace asmjit { namespace asmjit {
namespace x86x64 { namespace x86 {
// ============================================================================ // ============================================================================
// [asmjit::x86x64::Variables] // [asmjit::X86Mem - abs[]]
// ============================================================================ // ============================================================================
#define C(_Class_) kRegClass##_Class_ X86Mem ptr_abs(Ptr pAbs, int32_t disp, uint32_t size) {
#define D(_Desc_) kVarDesc##_Desc_ X86Mem m(NoInit);
const VarInfo _varInfo[] = {
/* 00: kVarTypeInt8 */ { kRegTypeGpbLo, 1 , C(Gp) , 0 , "gpb" },
/* 01: kVarTypeUInt8 */ { kRegTypeGpbLo, 1 , C(Gp) , 0 , "gpb" },
/* 02: kVarTypeInt16 */ { kRegTypeGpw , 2 , C(Gp) , 0 , "gpw" },
/* 03: kVarTypeUInt16 */ { kRegTypeGpw , 2 , C(Gp) , 0 , "gpw" },
/* 04: kVarTypeInt32 */ { kRegTypeGpd , 4 , C(Gp) , 0 , "gpd" },
/* 05: kVarTypeUInt32 */ { kRegTypeGpd , 4 , C(Gp) , 0 , "gpd" },
/* 06: kVarTypeInt64 */ { kRegTypeGpq , 8 , C(Gp) , 0 , "gpq" },
/* 07: kVarTypeUInt64 */ { kRegTypeGpq , 8 , C(Gp) , 0 , "gpq" },
/* 08: kVarTypeIntPtr */ { 0 , 0 , C(Gp) , 0 , "" }, // Remapped.
/* 09: kVarTypeUIntPtr */ { 0 , 0 , C(Gp) , 0 , "" }, // Remapped.
/* 10: kVarTypeFp32 */ { kRegTypeFp , 4 , C(Fp) , D(Sp) , "fp" },
/* 11: kVarTypeFp64 */ { kRegTypeFp , 8 , C(Fp) , D(Dp) , "fp" },
/* 12: kVarTypeMm */ { kRegTypeMm , 8 , C(Mm) , 0 , "mm" },
/* 13: kVarTypeXmm */ { kRegTypeXmm , 16, C(Xyz), 0 , "xmm" },
/* 14: kVarTypeXmmSs */ { kRegTypeXmm , 4 , C(Xyz), D(Sp) , "xmm" },
/* 15: kVarTypeXmmPs */ { kRegTypeXmm , 16, C(Xyz), D(Sp) | D(Packed), "xmm" },
/* 16: kVarTypeXmmSd */ { kRegTypeXmm , 8 , C(Xyz), D(Dp) , "xmm" },
/* 17: kVarTypeXmmPd */ { kRegTypeXmm , 16, C(Xyz), D(Dp) | D(Packed), "xmm" },
/* 18: kVarTypeYmm */ { kRegTypeYmm , 32, C(Xyz), 0 , "ymm" },
/* 19: kVarTypeYmmPs */ { kRegTypeYmm , 32, C(Xyz), D(Sp) | D(Packed), "ymm" },
/* 20: kVarTypeYmmPd */ { kRegTypeYmm , 32, C(Xyz), D(Dp) | D(Packed), "ymm" }
};
#undef D
#undef C
// ============================================================================
// [asmjit::Mem - abs[]]
// ============================================================================
Mem ptr_abs(Ptr pAbs, int32_t disp, uint32_t size) {
Mem m(NoInit);
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, 0, kInvalidValue); m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, 0, kInvalidValue);
m._vmem.index = kInvalidValue; m._vmem.index = kInvalidValue;
@@ -68,13 +34,16 @@ Mem ptr_abs(Ptr pAbs, int32_t disp, uint32_t size) {
return m; return m;
} }
Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift, int32_t disp, uint32_t size) { X86Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift, int32_t disp, uint32_t size) {
Mem m(NoInit); X86Mem m(NoInit);
uint32_t flags = shift << kMemShiftIndex; uint32_t flags = shift << kX86MemShiftIndex;
if (index.isGp()) flags |= Mem::_getGpdFlags(reinterpret_cast<const BaseVar&>(index)); if (index.isGp())
if (index.isXmm()) flags |= kMemVSibXmm << kMemVSibIndex; flags |= X86Mem::_getGpdFlags(index);
if (index.isYmm()) flags |= kMemVSibYmm << kMemVSibIndex; else if (index.isXmm())
flags |= kX86MemVSibXmm << kX86MemVSibIndex;
else if (index.isYmm())
flags |= kX86MemVSibYmm << kX86MemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue); m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index.getRegIndex(); m._vmem.index = index.getRegIndex();
@@ -83,99 +52,33 @@ Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift, int32_t disp, uint32_
return m; return m;
} }
Mem ptr_abs(Ptr pAbs, const X86Var& index, uint32_t shift, int32_t disp, uint32_t size) { #if !defined(ASMJIT_DISABLE_COMPILER)
Mem m(NoInit); X86Mem ptr_abs(Ptr pAbs, const X86Var& index, uint32_t shift, int32_t disp, uint32_t size) {
uint32_t flags = shift << kMemShiftIndex; X86Mem m(NoInit);
uint32_t flags = shift << kX86MemShiftIndex;
if (index.isGp()) flags |= Mem::_getGpdFlags(reinterpret_cast<const BaseVar&>(index)); const Var& index_ = reinterpret_cast<const Var&>(index);
if (index.isXmm()) flags |= kMemVSibXmm << kMemVSibIndex; uint32_t indexRegType = index_.getRegType();
if (index.isYmm()) flags |= kMemVSibYmm << kMemVSibIndex;
if (indexRegType <= kX86RegTypeGpq)
flags |= X86Mem::_getGpdFlags(reinterpret_cast<const Var&>(index));
else if (indexRegType == kX86RegTypeXmm)
flags |= kX86MemVSibXmm << kX86MemVSibIndex;
else if (indexRegType == kX86RegTypeYmm)
flags |= kX86MemVSibYmm << kX86MemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue); m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index.getId(); m._vmem.index = index_.getId();
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp)); m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m; return m;
} }
#endif // !ASMJIT_DISABLE_COMPILER
} // x86x64 namespace
} // asmjit namespace
// ============================================================================
// [asmjit::x86]
// ============================================================================
#if defined(ASMJIT_BUILD_X86)
namespace asmjit {
namespace x86 {
const uint8_t _varMapping[kVarTypeCount] = {
/* 00: kVarTypeInt8 */ kVarTypeInt8,
/* 01: kVarTypeUInt8 */ kVarTypeUInt8,
/* 02: kVarTypeInt16 */ kVarTypeInt16,
/* 03: kVarTypeUInt16 */ kVarTypeUInt16,
/* 04: kVarTypeInt32 */ kVarTypeInt32,
/* 05: kVarTypeUInt32 */ kVarTypeUInt32,
/* 06: kVarTypeInt64 */ kVarTypeInvalid, // Invalid in 32-bit mode.
/* 07: kVarTypeUInt64 */ kVarTypeInvalid, // Invalid in 32-bit mode.
/* 08: kVarTypeIntPtr */ kVarTypeInt32, // Remapped.
/* 09: kVarTypeUIntPtr */ kVarTypeUInt32, // Remapped.
/* 10: kVarTypeFp32 */ kVarTypeFp32,
/* 11: kVarTypeFp64 */ kVarTypeFp64,
/* 12: kVarTypeMm */ kVarTypeMm,
/* 13: kVarTypeXmm */ kVarTypeXmm,
/* 14: kVarTypeXmmSs */ kVarTypeXmmSs,
/* 15: kVarTypeXmmPs */ kVarTypeXmmPs,
/* 16: kVarTypeXmmSd */ kVarTypeXmmSd,
/* 17: kVarTypeXmmPd */ kVarTypeXmmPd,
/* 18: kVarTypeYmm */ kVarTypeYmm,
/* 19: kVarTypeYmmPs */ kVarTypeYmmPs,
/* 20: kVarTypeYmmPd */ kVarTypeYmmPd
};
} // x86 namespace } // x86 namespace
} // asmjit namespace } // asmjit namespace
#endif // ASMJIT_BUILD_X86 // [Api-End]
// ============================================================================
// [asmjit::x64]
// ============================================================================
#if defined(ASMJIT_BUILD_X64)
namespace asmjit {
namespace x64 {
const uint8_t _varMapping[kVarTypeCount] = {
/* 00: kVarTypeInt8 */ kVarTypeInt8,
/* 01: kVarTypeUInt8 */ kVarTypeUInt8,
/* 02: kVarTypeInt16 */ kVarTypeInt16,
/* 03: kVarTypeUInt16 */ kVarTypeUInt16,
/* 04: kVarTypeInt32 */ kVarTypeInt32,
/* 05: kVarTypeUInt32 */ kVarTypeUInt32,
/* 06: kVarTypeInt64 */ kVarTypeInt64,
/* 07: kVarTypeUInt64 */ kVarTypeUInt64,
/* 08: kVarTypeIntPtr */ kVarTypeInt64, // Remapped.
/* 09: kVarTypeUIntPtr */ kVarTypeUInt64, // Remapped.
/* 10: kVarTypeFp32 */ kVarTypeFp32,
/* 11: kVarTypeFp64 */ kVarTypeFp64,
/* 12: kVarTypeMm */ kVarTypeMm,
/* 13: kVarTypeXmm */ kVarTypeXmm,
/* 14: kVarTypeXmmSs */ kVarTypeXmmSs,
/* 15: kVarTypeXmmPs */ kVarTypeXmmPs,
/* 16: kVarTypeXmmSd */ kVarTypeXmmSd,
/* 17: kVarTypeXmmPd */ kVarTypeXmmPd,
/* 18: kVarTypeYmm */ kVarTypeYmm,
/* 19: kVarTypeYmmPs */ kVarTypeYmmPs,
/* 20: kVarTypeYmmPd */ kVarTypeYmmPd
};
} // x64 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X64
#include "../apiend.h" #include "../apiend.h"
// [Guard] // [Guard]

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,188 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
#define ASMJIT_EXPORTS_X86OPERAND_REGS
// [Guard]
#include "../build.h"
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit]
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// Prevent static initialization.
//
// Remap all classes to POD structs so they can be statically initialized
// without calling a constructor. Compiler will store these in data section.
struct X86GpReg { Operand::VRegOp data; };
struct X86FpReg { Operand::VRegOp data; };
struct X86MmReg { Operand::VRegOp data; };
struct X86XmmReg { Operand::VRegOp data; };
struct X86YmmReg { Operand::VRegOp data; };
struct X86SegReg { Operand::VRegOp data; };
namespace x86 {
// ============================================================================
// [asmjit::x86::Registers]
// ============================================================================
#define REG(_Class_, _Name_, _Type_, _Index_, _Size_) \
const _Class_ _Name_ = {{ \
kOperandTypeReg, _Size_, { ((_Type_) << 8) + _Index_ }, kInvalidValue, {{ kInvalidVar, 0 }} \
}}
REG(X86GpReg, noGpReg, kInvalidReg, kInvalidReg, 0);
REG(X86GpReg, al, kX86RegTypeGpbLo, kX86RegIndexAx, 1);
REG(X86GpReg, cl, kX86RegTypeGpbLo, kX86RegIndexCx, 1);
REG(X86GpReg, dl, kX86RegTypeGpbLo, kX86RegIndexDx, 1);
REG(X86GpReg, bl, kX86RegTypeGpbLo, kX86RegIndexBx, 1);
REG(X86GpReg, spl, kX86RegTypeGpbLo, kX86RegIndexSp, 1);
REG(X86GpReg, bpl, kX86RegTypeGpbLo, kX86RegIndexBp, 1);
REG(X86GpReg, sil, kX86RegTypeGpbLo, kX86RegIndexSi, 1);
REG(X86GpReg, dil, kX86RegTypeGpbLo, kX86RegIndexDi, 1);
REG(X86GpReg, r8b, kX86RegTypeGpbLo, 8, 1);
REG(X86GpReg, r9b, kX86RegTypeGpbLo, 9, 1);
REG(X86GpReg, r10b, kX86RegTypeGpbLo, 10, 1);
REG(X86GpReg, r11b, kX86RegTypeGpbLo, 11, 1);
REG(X86GpReg, r12b, kX86RegTypeGpbLo, 12, 1);
REG(X86GpReg, r13b, kX86RegTypeGpbLo, 13, 1);
REG(X86GpReg, r14b, kX86RegTypeGpbLo, 14, 1);
REG(X86GpReg, r15b, kX86RegTypeGpbLo, 15, 1);
REG(X86GpReg, ah, kX86RegTypeGpbHi, kX86RegIndexAx, 1);
REG(X86GpReg, ch, kX86RegTypeGpbHi, kX86RegIndexCx, 1);
REG(X86GpReg, dh, kX86RegTypeGpbHi, kX86RegIndexDx, 1);
REG(X86GpReg, bh, kX86RegTypeGpbHi, kX86RegIndexBx, 1);
REG(X86GpReg, ax, kX86RegTypeGpw, kX86RegIndexAx, 2);
REG(X86GpReg, cx, kX86RegTypeGpw, kX86RegIndexCx, 2);
REG(X86GpReg, dx, kX86RegTypeGpw, kX86RegIndexDx, 2);
REG(X86GpReg, bx, kX86RegTypeGpw, kX86RegIndexBx, 2);
REG(X86GpReg, sp, kX86RegTypeGpw, kX86RegIndexSp, 2);
REG(X86GpReg, bp, kX86RegTypeGpw, kX86RegIndexBp, 2);
REG(X86GpReg, si, kX86RegTypeGpw, kX86RegIndexSi, 2);
REG(X86GpReg, di, kX86RegTypeGpw, kX86RegIndexDi, 2);
REG(X86GpReg, r8w, kX86RegTypeGpw, 8, 2);
REG(X86GpReg, r9w, kX86RegTypeGpw, 9, 2);
REG(X86GpReg, r10w, kX86RegTypeGpw, 10, 2);
REG(X86GpReg, r11w, kX86RegTypeGpw, 11, 2);
REG(X86GpReg, r12w, kX86RegTypeGpw, 12, 2);
REG(X86GpReg, r13w, kX86RegTypeGpw, 13, 2);
REG(X86GpReg, r14w, kX86RegTypeGpw, 14, 2);
REG(X86GpReg, r15w, kX86RegTypeGpw, 15, 2);
REG(X86GpReg, eax, kX86RegTypeGpd, kX86RegIndexAx, 4);
REG(X86GpReg, ecx, kX86RegTypeGpd, kX86RegIndexCx, 4);
REG(X86GpReg, edx, kX86RegTypeGpd, kX86RegIndexDx, 4);
REG(X86GpReg, ebx, kX86RegTypeGpd, kX86RegIndexBx, 4);
REG(X86GpReg, esp, kX86RegTypeGpd, kX86RegIndexSp, 4);
REG(X86GpReg, ebp, kX86RegTypeGpd, kX86RegIndexBp, 4);
REG(X86GpReg, esi, kX86RegTypeGpd, kX86RegIndexSi, 4);
REG(X86GpReg, edi, kX86RegTypeGpd, kX86RegIndexDi, 4);
REG(X86GpReg, r8d, kX86RegTypeGpd, 8, 4);
REG(X86GpReg, r9d, kX86RegTypeGpd, 9, 4);
REG(X86GpReg, r10d, kX86RegTypeGpd, 10, 4);
REG(X86GpReg, r11d, kX86RegTypeGpd, 11, 4);
REG(X86GpReg, r12d, kX86RegTypeGpd, 12, 4);
REG(X86GpReg, r13d, kX86RegTypeGpd, 13, 4);
REG(X86GpReg, r14d, kX86RegTypeGpd, 14, 4);
REG(X86GpReg, r15d, kX86RegTypeGpd, 15, 4);
REG(X86GpReg, rax, kX86RegTypeGpq, kX86RegIndexAx, 8);
REG(X86GpReg, rcx, kX86RegTypeGpq, kX86RegIndexCx, 8);
REG(X86GpReg, rdx, kX86RegTypeGpq, kX86RegIndexDx, 8);
REG(X86GpReg, rbx, kX86RegTypeGpq, kX86RegIndexBx, 8);
REG(X86GpReg, rsp, kX86RegTypeGpq, kX86RegIndexSp, 8);
REG(X86GpReg, rbp, kX86RegTypeGpq, kX86RegIndexBp, 8);
REG(X86GpReg, rsi, kX86RegTypeGpq, kX86RegIndexSi, 8);
REG(X86GpReg, rdi, kX86RegTypeGpq, kX86RegIndexDi, 8);
REG(X86GpReg, r8, kX86RegTypeGpq, 8, 8);
REG(X86GpReg, r9, kX86RegTypeGpq, 9, 8);
REG(X86GpReg, r10, kX86RegTypeGpq, 10, 8);
REG(X86GpReg, r11, kX86RegTypeGpq, 11, 8);
REG(X86GpReg, r12, kX86RegTypeGpq, 12, 8);
REG(X86GpReg, r13, kX86RegTypeGpq, 13, 8);
REG(X86GpReg, r14, kX86RegTypeGpq, 14, 8);
REG(X86GpReg, r15, kX86RegTypeGpq, 15, 8);
REG(X86FpReg, fp0, kX86RegTypeFp, 0, 10);
REG(X86FpReg, fp1, kX86RegTypeFp, 1, 10);
REG(X86FpReg, fp2, kX86RegTypeFp, 2, 10);
REG(X86FpReg, fp3, kX86RegTypeFp, 3, 10);
REG(X86FpReg, fp4, kX86RegTypeFp, 4, 10);
REG(X86FpReg, fp5, kX86RegTypeFp, 5, 10);
REG(X86FpReg, fp6, kX86RegTypeFp, 6, 10);
REG(X86FpReg, fp7, kX86RegTypeFp, 7, 10);
REG(X86MmReg, mm0, kX86RegTypeMm, 0, 8);
REG(X86MmReg, mm1, kX86RegTypeMm, 1, 8);
REG(X86MmReg, mm2, kX86RegTypeMm, 2, 8);
REG(X86MmReg, mm3, kX86RegTypeMm, 3, 8);
REG(X86MmReg, mm4, kX86RegTypeMm, 4, 8);
REG(X86MmReg, mm5, kX86RegTypeMm, 5, 8);
REG(X86MmReg, mm6, kX86RegTypeMm, 6, 8);
REG(X86MmReg, mm7, kX86RegTypeMm, 7, 8);
REG(X86XmmReg, xmm0, kX86RegTypeXmm, 0, 16);
REG(X86XmmReg, xmm1, kX86RegTypeXmm, 1, 16);
REG(X86XmmReg, xmm2, kX86RegTypeXmm, 2, 16);
REG(X86XmmReg, xmm3, kX86RegTypeXmm, 3, 16);
REG(X86XmmReg, xmm4, kX86RegTypeXmm, 4, 16);
REG(X86XmmReg, xmm5, kX86RegTypeXmm, 5, 16);
REG(X86XmmReg, xmm6, kX86RegTypeXmm, 6, 16);
REG(X86XmmReg, xmm7, kX86RegTypeXmm, 7, 16);
REG(X86XmmReg, xmm8, kX86RegTypeXmm, 8, 16);
REG(X86XmmReg, xmm9, kX86RegTypeXmm, 9, 16);
REG(X86XmmReg, xmm10, kX86RegTypeXmm, 10, 16);
REG(X86XmmReg, xmm11, kX86RegTypeXmm, 11, 16);
REG(X86XmmReg, xmm12, kX86RegTypeXmm, 12, 16);
REG(X86XmmReg, xmm13, kX86RegTypeXmm, 13, 16);
REG(X86XmmReg, xmm14, kX86RegTypeXmm, 14, 16);
REG(X86XmmReg, xmm15, kX86RegTypeXmm, 15, 16);
REG(X86YmmReg, ymm0, kX86RegTypeYmm, 0, 32);
REG(X86YmmReg, ymm1, kX86RegTypeYmm, 1, 32);
REG(X86YmmReg, ymm2, kX86RegTypeYmm, 2, 32);
REG(X86YmmReg, ymm3, kX86RegTypeYmm, 3, 32);
REG(X86YmmReg, ymm4, kX86RegTypeYmm, 4, 32);
REG(X86YmmReg, ymm5, kX86RegTypeYmm, 5, 32);
REG(X86YmmReg, ymm6, kX86RegTypeYmm, 6, 32);
REG(X86YmmReg, ymm7, kX86RegTypeYmm, 7, 32);
REG(X86YmmReg, ymm8, kX86RegTypeYmm, 8, 32);
REG(X86YmmReg, ymm9, kX86RegTypeYmm, 9, 32);
REG(X86YmmReg, ymm10, kX86RegTypeYmm, 10, 32);
REG(X86YmmReg, ymm11, kX86RegTypeYmm, 11, 32);
REG(X86YmmReg, ymm12, kX86RegTypeYmm, 12, 32);
REG(X86YmmReg, ymm13, kX86RegTypeYmm, 13, 32);
REG(X86YmmReg, ymm14, kX86RegTypeYmm, 14, 32);
REG(X86YmmReg, ymm15, kX86RegTypeYmm, 15, 32);
REG(X86SegReg, cs, kX86RegTypeSeg, kX86SegCs, 2);
REG(X86SegReg, ss, kX86RegTypeSeg, kX86SegSs, 2);
REG(X86SegReg, ds, kX86RegTypeSeg, kX86SegDs, 2);
REG(X86SegReg, es, kX86RegTypeSeg, kX86SegEs, 2);
REG(X86SegReg, fs, kX86RegTypeSeg, kX86SegFs, 2);
REG(X86SegReg, gs, kX86RegTypeSeg, kX86SegGs, 2);
#undef REG
} // x86 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64

View File

@@ -1,216 +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
#define ASMJIT_REGS_INIT
// [Guard]
#include "../build.h"
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit]
#include "../x86/x86regs.h"
// [Api-Begin]
#include "../apibegin.h"
#define DEFINE_REG(_Class_, _Name_, _Type_, _Index_, _Size_) \
const _Class_ _Name_ = { { kOperandTypeReg, _Size_, ((_Type_) << 8) + _Index_, kInvalidValue, kVarTypeInvalid, 0 } }
namespace asmjit {
namespace x86x64 {
// ============================================================================
// [asmjit::x86x64::Registers]
// ============================================================================
DEFINE_REG(GpReg, noGpReg, kInvalidReg, kInvalidReg, 0);
DEFINE_REG(GpReg, al, kRegTypeGpbLo, kRegIndexAx, 1);
DEFINE_REG(GpReg, cl, kRegTypeGpbLo, kRegIndexCx, 1);
DEFINE_REG(GpReg, dl, kRegTypeGpbLo, kRegIndexDx, 1);
DEFINE_REG(GpReg, bl, kRegTypeGpbLo, kRegIndexBx, 1);
DEFINE_REG(GpReg, spl, kRegTypeGpbLo, kRegIndexSp, 1);
DEFINE_REG(GpReg, bpl, kRegTypeGpbLo, kRegIndexBp, 1);
DEFINE_REG(GpReg, sil, kRegTypeGpbLo, kRegIndexSi, 1);
DEFINE_REG(GpReg, dil, kRegTypeGpbLo, kRegIndexDi, 1);
DEFINE_REG(GpReg, r8b, kRegTypeGpbLo, 8, 1);
DEFINE_REG(GpReg, r9b, kRegTypeGpbLo, 9, 1);
DEFINE_REG(GpReg, r10b, kRegTypeGpbLo, 10, 1);
DEFINE_REG(GpReg, r11b, kRegTypeGpbLo, 11, 1);
DEFINE_REG(GpReg, r12b, kRegTypeGpbLo, 12, 1);
DEFINE_REG(GpReg, r13b, kRegTypeGpbLo, 13, 1);
DEFINE_REG(GpReg, r14b, kRegTypeGpbLo, 14, 1);
DEFINE_REG(GpReg, r15b, kRegTypeGpbLo, 15, 1);
DEFINE_REG(GpReg, ah, kRegTypeGpbHi, kRegIndexAx, 1);
DEFINE_REG(GpReg, ch, kRegTypeGpbHi, kRegIndexCx, 1);
DEFINE_REG(GpReg, dh, kRegTypeGpbHi, kRegIndexDx, 1);
DEFINE_REG(GpReg, bh, kRegTypeGpbHi, kRegIndexBx, 1);
DEFINE_REG(GpReg, ax, kRegTypeGpw, kRegIndexAx, 2);
DEFINE_REG(GpReg, cx, kRegTypeGpw, kRegIndexCx, 2);
DEFINE_REG(GpReg, dx, kRegTypeGpw, kRegIndexDx, 2);
DEFINE_REG(GpReg, bx, kRegTypeGpw, kRegIndexBx, 2);
DEFINE_REG(GpReg, sp, kRegTypeGpw, kRegIndexSp, 2);
DEFINE_REG(GpReg, bp, kRegTypeGpw, kRegIndexBp, 2);
DEFINE_REG(GpReg, si, kRegTypeGpw, kRegIndexSi, 2);
DEFINE_REG(GpReg, di, kRegTypeGpw, kRegIndexDi, 2);
DEFINE_REG(GpReg, r8w, kRegTypeGpw, 8, 2);
DEFINE_REG(GpReg, r9w, kRegTypeGpw, 9, 2);
DEFINE_REG(GpReg, r10w, kRegTypeGpw, 10, 2);
DEFINE_REG(GpReg, r11w, kRegTypeGpw, 11, 2);
DEFINE_REG(GpReg, r12w, kRegTypeGpw, 12, 2);
DEFINE_REG(GpReg, r13w, kRegTypeGpw, 13, 2);
DEFINE_REG(GpReg, r14w, kRegTypeGpw, 14, 2);
DEFINE_REG(GpReg, r15w, kRegTypeGpw, 15, 2);
DEFINE_REG(GpReg, eax, kRegTypeGpd, kRegIndexAx, 4);
DEFINE_REG(GpReg, ecx, kRegTypeGpd, kRegIndexCx, 4);
DEFINE_REG(GpReg, edx, kRegTypeGpd, kRegIndexDx, 4);
DEFINE_REG(GpReg, ebx, kRegTypeGpd, kRegIndexBx, 4);
DEFINE_REG(GpReg, esp, kRegTypeGpd, kRegIndexSp, 4);
DEFINE_REG(GpReg, ebp, kRegTypeGpd, kRegIndexBp, 4);
DEFINE_REG(GpReg, esi, kRegTypeGpd, kRegIndexSi, 4);
DEFINE_REG(GpReg, edi, kRegTypeGpd, kRegIndexDi, 4);
DEFINE_REG(GpReg, r8d, kRegTypeGpd, 8, 4);
DEFINE_REG(GpReg, r9d, kRegTypeGpd, 9, 4);
DEFINE_REG(GpReg, r10d, kRegTypeGpd, 10, 4);
DEFINE_REG(GpReg, r11d, kRegTypeGpd, 11, 4);
DEFINE_REG(GpReg, r12d, kRegTypeGpd, 12, 4);
DEFINE_REG(GpReg, r13d, kRegTypeGpd, 13, 4);
DEFINE_REG(GpReg, r14d, kRegTypeGpd, 14, 4);
DEFINE_REG(GpReg, r15d, kRegTypeGpd, 15, 4);
DEFINE_REG(GpReg, rax, kRegTypeGpq, kRegIndexAx, 8);
DEFINE_REG(GpReg, rcx, kRegTypeGpq, kRegIndexCx, 8);
DEFINE_REG(GpReg, rdx, kRegTypeGpq, kRegIndexDx, 8);
DEFINE_REG(GpReg, rbx, kRegTypeGpq, kRegIndexBx, 8);
DEFINE_REG(GpReg, rsp, kRegTypeGpq, kRegIndexSp, 8);
DEFINE_REG(GpReg, rbp, kRegTypeGpq, kRegIndexBp, 8);
DEFINE_REG(GpReg, rsi, kRegTypeGpq, kRegIndexSi, 8);
DEFINE_REG(GpReg, rdi, kRegTypeGpq, kRegIndexDi, 8);
DEFINE_REG(GpReg, r8, kRegTypeGpq, 8, 8);
DEFINE_REG(GpReg, r9, kRegTypeGpq, 9, 8);
DEFINE_REG(GpReg, r10, kRegTypeGpq, 10, 8);
DEFINE_REG(GpReg, r11, kRegTypeGpq, 11, 8);
DEFINE_REG(GpReg, r12, kRegTypeGpq, 12, 8);
DEFINE_REG(GpReg, r13, kRegTypeGpq, 13, 8);
DEFINE_REG(GpReg, r14, kRegTypeGpq, 14, 8);
DEFINE_REG(GpReg, r15, kRegTypeGpq, 15, 8);
DEFINE_REG(FpReg, fp0, kRegTypeFp, 0, 10);
DEFINE_REG(FpReg, fp1, kRegTypeFp, 1, 10);
DEFINE_REG(FpReg, fp2, kRegTypeFp, 2, 10);
DEFINE_REG(FpReg, fp3, kRegTypeFp, 3, 10);
DEFINE_REG(FpReg, fp4, kRegTypeFp, 4, 10);
DEFINE_REG(FpReg, fp5, kRegTypeFp, 5, 10);
DEFINE_REG(FpReg, fp6, kRegTypeFp, 6, 10);
DEFINE_REG(FpReg, fp7, kRegTypeFp, 7, 10);
DEFINE_REG(MmReg, mm0, kRegTypeMm, 0, 8);
DEFINE_REG(MmReg, mm1, kRegTypeMm, 1, 8);
DEFINE_REG(MmReg, mm2, kRegTypeMm, 2, 8);
DEFINE_REG(MmReg, mm3, kRegTypeMm, 3, 8);
DEFINE_REG(MmReg, mm4, kRegTypeMm, 4, 8);
DEFINE_REG(MmReg, mm5, kRegTypeMm, 5, 8);
DEFINE_REG(MmReg, mm6, kRegTypeMm, 6, 8);
DEFINE_REG(MmReg, mm7, kRegTypeMm, 7, 8);
DEFINE_REG(XmmReg, xmm0, kRegTypeXmm, 0, 16);
DEFINE_REG(XmmReg, xmm1, kRegTypeXmm, 1, 16);
DEFINE_REG(XmmReg, xmm2, kRegTypeXmm, 2, 16);
DEFINE_REG(XmmReg, xmm3, kRegTypeXmm, 3, 16);
DEFINE_REG(XmmReg, xmm4, kRegTypeXmm, 4, 16);
DEFINE_REG(XmmReg, xmm5, kRegTypeXmm, 5, 16);
DEFINE_REG(XmmReg, xmm6, kRegTypeXmm, 6, 16);
DEFINE_REG(XmmReg, xmm7, kRegTypeXmm, 7, 16);
DEFINE_REG(XmmReg, xmm8, kRegTypeXmm, 8, 16);
DEFINE_REG(XmmReg, xmm9, kRegTypeXmm, 9, 16);
DEFINE_REG(XmmReg, xmm10, kRegTypeXmm, 10, 16);
DEFINE_REG(XmmReg, xmm11, kRegTypeXmm, 11, 16);
DEFINE_REG(XmmReg, xmm12, kRegTypeXmm, 12, 16);
DEFINE_REG(XmmReg, xmm13, kRegTypeXmm, 13, 16);
DEFINE_REG(XmmReg, xmm14, kRegTypeXmm, 14, 16);
DEFINE_REG(XmmReg, xmm15, kRegTypeXmm, 15, 16);
DEFINE_REG(YmmReg, ymm0, kRegTypeYmm, 0, 32);
DEFINE_REG(YmmReg, ymm1, kRegTypeYmm, 1, 32);
DEFINE_REG(YmmReg, ymm2, kRegTypeYmm, 2, 32);
DEFINE_REG(YmmReg, ymm3, kRegTypeYmm, 3, 32);
DEFINE_REG(YmmReg, ymm4, kRegTypeYmm, 4, 32);
DEFINE_REG(YmmReg, ymm5, kRegTypeYmm, 5, 32);
DEFINE_REG(YmmReg, ymm6, kRegTypeYmm, 6, 32);
DEFINE_REG(YmmReg, ymm7, kRegTypeYmm, 7, 32);
DEFINE_REG(YmmReg, ymm8, kRegTypeYmm, 8, 32);
DEFINE_REG(YmmReg, ymm9, kRegTypeYmm, 9, 32);
DEFINE_REG(YmmReg, ymm10, kRegTypeYmm, 10, 32);
DEFINE_REG(YmmReg, ymm11, kRegTypeYmm, 11, 32);
DEFINE_REG(YmmReg, ymm12, kRegTypeYmm, 12, 32);
DEFINE_REG(YmmReg, ymm13, kRegTypeYmm, 13, 32);
DEFINE_REG(YmmReg, ymm14, kRegTypeYmm, 14, 32);
DEFINE_REG(YmmReg, ymm15, kRegTypeYmm, 15, 32);
DEFINE_REG(SegReg, cs, kRegTypeSeg, kSegCs, 2);
DEFINE_REG(SegReg, ss, kRegTypeSeg, kSegSs, 2);
DEFINE_REG(SegReg, ds, kRegTypeSeg, kSegDs, 2);
DEFINE_REG(SegReg, es, kRegTypeSeg, kSegEs, 2);
DEFINE_REG(SegReg, fs, kRegTypeSeg, kSegFs, 2);
DEFINE_REG(SegReg, gs, kRegTypeSeg, kSegGs, 2);
} // x86x64 namespace
} // asmjit namespace
// ============================================================================
// [asmjit::x86]
// ============================================================================
#if defined(ASMJIT_BUILD_X86)
namespace asmjit {
namespace x86 {
DEFINE_REG(GpReg, zax, kRegTypeGpd, kRegIndexAx, 4);
DEFINE_REG(GpReg, zcx, kRegTypeGpd, kRegIndexCx, 4);
DEFINE_REG(GpReg, zdx, kRegTypeGpd, kRegIndexDx, 4);
DEFINE_REG(GpReg, zbx, kRegTypeGpd, kRegIndexBx, 4);
DEFINE_REG(GpReg, zsp, kRegTypeGpd, kRegIndexSp, 4);
DEFINE_REG(GpReg, zbp, kRegTypeGpd, kRegIndexBp, 4);
DEFINE_REG(GpReg, zsi, kRegTypeGpd, kRegIndexSi, 4);
DEFINE_REG(GpReg, zdi, kRegTypeGpd, kRegIndexDi, 4);
} // x86 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X86
// ============================================================================
// [asmjit::x64]
// ============================================================================
#if defined(ASMJIT_BUILD_X64)
namespace asmjit {
namespace x64 {
DEFINE_REG(GpReg, zax, kRegTypeGpq, kRegIndexAx, 8);
DEFINE_REG(GpReg, zcx, kRegTypeGpq, kRegIndexCx, 8);
DEFINE_REG(GpReg, zdx, kRegTypeGpq, kRegIndexDx, 8);
DEFINE_REG(GpReg, zbx, kRegTypeGpq, kRegIndexBx, 8);
DEFINE_REG(GpReg, zsp, kRegTypeGpq, kRegIndexSp, 8);
DEFINE_REG(GpReg, zbp, kRegTypeGpq, kRegIndexBp, 8);
DEFINE_REG(GpReg, zsi, kRegTypeGpq, kRegIndexSi, 8);
DEFINE_REG(GpReg, zdi, kRegTypeGpq, kRegIndexDi, 8);
} // x64 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X64
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64

View File

@@ -1,412 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86REGS_H
#define _ASMJIT_X86_X86REGS_H
// [Dependencies - AsmJit]
#include "../base/operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
struct GpReg;
struct FpReg;
struct MmReg;
struct XmmReg;
struct YmmReg;
struct SegReg;
#if defined(ASMJIT_REGS_INIT)
// Remap all classes to POD structs that can be statically initialized.
struct GpReg { Operand::InitRegOp data; };
struct FpReg { Operand::InitRegOp data; };
struct MmReg { Operand::InitRegOp data; };
struct XmmReg { Operand::InitRegOp data; };
struct YmmReg { Operand::InitRegOp data; };
struct SegReg { Operand::InitRegOp data; };
#endif // ASMJIT_REGS_INIT
//! \addtogroup asmjit_x86x64_general
//! \{
// ============================================================================
// [asmjit::x86x64::kRegClass]
// ============================================================================
//! X86/X64 variable class.
ASMJIT_ENUM(kRegClass) {
// kRegClassGp defined earlier.
//! X86/X64 Fp register class.
kRegClassFp = 1,
//! X86/X64 Mm register class.
kRegClassMm = 2,
//! X86/X64 Xmm/Ymm/Zmm register class.
kRegClassXyz = 3,
//! Count of X86/X64 register classes.
kRegClassCount = 4
};
// ============================================================================
// [asmjit::x86x64::kRegCount]
// ============================================================================
//! X86/X64 registers count.
ASMJIT_ENUM(kRegCount) {
//! Count of Fp registers (8).
kRegCountFp = 8,
//! Count of Mm registers (8).
kRegCountMm = 8,
//! Count of segment registers (6).
kRegCountSeg = 6
};
// ============================================================================
// [asmjit::x86x64::kRegType]
// ============================================================================
//! X86/X64 register type.
ASMJIT_ENUM(kRegType) {
//! Gpb-lo register (AL, BL, CL, DL, ...).
kRegTypeGpbLo = 0x01,
//! Gpb-hi register (AH, BH, CH, DH only).
kRegTypeGpbHi = 0x02,
//! \internal
//!
//! Gpb-hi register patched to native index (4-7).
kRegTypePatchedGpbHi = kRegTypeGpbLo | kRegTypeGpbHi,
//! Gpw register.
kRegTypeGpw = 0x10,
//! Gpd register.
kRegTypeGpd = 0x20,
//! Gpq register.
kRegTypeGpq = 0x30,
//! Fp register.
kRegTypeFp = 0x50,
//! Mm register.
kRegTypeMm = 0x60,
//! Xmm register.
kRegTypeXmm = 0x70,
//! Ymm register.
kRegTypeYmm = 0x80,
//! Zmm register.
kRegTypeZmm = 0x90,
//! Segment register.
kRegTypeSeg = 0xF0
};
// ============================================================================
// [asmjit::x86x64::kRegIndex]
// ============================================================================
//! X86/X64 register indexes.
//!
//! \note Register indexes have been reduced to only support general purpose
//! registers. There is no need to have enumerations with number suffix that
//! expands to the exactly same value as the suffix value itself.
ASMJIT_ENUM(kRegIndex) {
//! Index of Al/Ah/Ax/Eax/Rax registers.
kRegIndexAx = 0,
//! Index of Cl/Ch/Cx/Ecx/Rcx registers.
kRegIndexCx = 1,
//! Index of Dl/Dh/Dx/Edx/Rdx registers.
kRegIndexDx = 2,
//! Index of Bl/Bh/Bx/Ebx/Rbx registers.
kRegIndexBx = 3,
//! Index of Spl/Sp/Esp/Rsp registers.
kRegIndexSp = 4,
//! Index of Bpl/Bp/Ebp/Rbp registers.
kRegIndexBp = 5,
//! Index of Sil/Si/Esi/Rsi registers.
kRegIndexSi = 6,
//! Index of Dil/Di/Edi/Rdi registers.
kRegIndexDi = 7,
//! Index of R8b/R8w/R8d/R8 registers (64-bit only).
kRegIndexR8 = 8,
//! Index of R9B/R9w/R9d/R9 registers (64-bit only).
kRegIndexR9 = 9,
//! Index of R10B/R10w/R10D/R10 registers (64-bit only).
kRegIndexR10 = 10,
//! Index of R11B/R11w/R11d/R11 registers (64-bit only).
kRegIndexR11 = 11,
//! Index of R12B/R12w/R12d/R12 registers (64-bit only).
kRegIndexR12 = 12,
//! Index of R13B/R13w/R13d/R13 registers (64-bit only).
kRegIndexR13 = 13,
//! Index of R14B/R14w/R14d/R14 registers (64-bit only).
kRegIndexR14 = 14,
//! Index of R15B/R15w/R15d/R15 registers (64-bit only).
kRegIndexR15 = 15
};
// ============================================================================
// [asmjit::x86x64::kSeg]
// ============================================================================
//! X86/X64 segment codes.
ASMJIT_ENUM(kSeg) {
//! No/Default segment.
kSegDefault = 0,
//! Es segment.
kSegEs = 1,
//! Cs segment.
kSegCs = 2,
//! Ss segment.
kSegSs = 3,
//! Ds segment.
kSegDs = 4,
//! Fs segment.
kSegFs = 5,
//! Gs segment.
kSegGs = 6
};
// ============================================================================
// [asmjit::x86x64::Registers]
// ============================================================================
//! No Gp register, can be used only within `Mem` operand.
ASMJIT_VAR const GpReg noGpReg;
ASMJIT_VAR const GpReg al; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const GpReg cl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const GpReg dl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const GpReg bl; //!< 8-bit Gpb-lo register.
ASMJIT_VAR const GpReg spl; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg bpl; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg sil; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg dil; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r8b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r9b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r10b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r11b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r12b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r13b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r14b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg r15b; //!< 8-bit Gpb-lo register (X64).
ASMJIT_VAR const GpReg ah; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const GpReg ch; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const GpReg dh; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const GpReg bh; //!< 8-bit Gpb-hi register.
ASMJIT_VAR const GpReg ax; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg cx; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg dx; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg bx; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg sp; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg bp; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg si; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg di; //!< 16-bit Gpw register.
ASMJIT_VAR const GpReg r8w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r9w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r10w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r11w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r12w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r13w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r14w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg r15w; //!< 16-bit Gpw register (X64).
ASMJIT_VAR const GpReg eax; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg ecx; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg edx; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg ebx; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg esp; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg ebp; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg esi; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg edi; //!< 32-bit Gpd register.
ASMJIT_VAR const GpReg r8d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r9d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r10d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r11d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r12d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r13d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r14d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg r15d; //!< 32-bit Gpd register (X64).
ASMJIT_VAR const GpReg rax; //!< 64-bit Gpq register (X64).
ASMJIT_VAR const GpReg rcx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rdx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rbx; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rsp; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rbp; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rsi; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg rdi; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r8; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r9; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r10; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r11; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r12; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r13; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r14; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const GpReg r15; //!< 64-bit Gpq register (X64)
ASMJIT_VAR const FpReg fp0; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp1; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp2; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp3; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp4; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp5; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp6; //!< 80-bit Fp register.
ASMJIT_VAR const FpReg fp7; //!< 80-bit Fp register.
ASMJIT_VAR const MmReg mm0; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm1; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm2; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm3; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm4; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm5; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm6; //!< 64-bit Mm register.
ASMJIT_VAR const MmReg mm7; //!< 64-bit Mm register.
ASMJIT_VAR const XmmReg xmm0; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm1; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm2; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm3; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm4; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm5; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm6; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm7; //!< 128-bit Xmm register.
ASMJIT_VAR const XmmReg xmm8; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm9; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm10; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm11; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm12; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm13; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm14; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const XmmReg xmm15; //!< 128-bit Xmm register (X64).
ASMJIT_VAR const YmmReg ymm0; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm1; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm2; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm3; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm4; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm5; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm6; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm7; //!< 256-bit Ymm register.
ASMJIT_VAR const YmmReg ymm8; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm9; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm10; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm11; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm12; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm13; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm14; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const YmmReg ymm15; //!< 256-bit Ymm register (X64).
ASMJIT_VAR const SegReg cs; //!< Cs segment register.
ASMJIT_VAR const SegReg ss; //!< Ss segment register.
ASMJIT_VAR const SegReg ds; //!< Ds segment register.
ASMJIT_VAR const SegReg es; //!< Es segment register.
ASMJIT_VAR const SegReg fs; //!< Fs segment register.
ASMJIT_VAR const SegReg gs; //!< Gs segment register.
//! \}
} // x86x64 namespace
} // asmjit namespace
// ============================================================================
// [asmjit::x86]
// ============================================================================
#if defined(ASMJIT_BUILD_X86)
namespace asmjit {
namespace x86 {
// This is the only place where the x86x64 namespace is included into x86.
using namespace ::asmjit::x86x64;
//! \addtogroup asmjit_x86x64_general
//! \{
// ============================================================================
// [asmjit::x86::Registers]
// ============================================================================
//! Gpd register.
ASMJIT_VAR const GpReg zax;
//! Gpd register.
ASMJIT_VAR const GpReg zcx;
//! Gpd register.
ASMJIT_VAR const GpReg zdx;
//! Gpd register.
ASMJIT_VAR const GpReg zbx;
//! Gpd register.
ASMJIT_VAR const GpReg zsp;
//! Gpd register.
ASMJIT_VAR const GpReg zbp;
//! Gpd register.
ASMJIT_VAR const GpReg zsi;
//! Gpd register.
ASMJIT_VAR const GpReg zdi;
//! \}
} // x86 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X86
// ============================================================================
// [asmjit::x64]
// ============================================================================
#if defined(ASMJIT_BUILD_X64)
namespace asmjit {
namespace x64 {
// This is the only place where the x86x64 namespace is included into x64.
using namespace ::asmjit::x86x64;
//! \addtogroup asmjit_x86x64_general
//! \{
// ============================================================================
// [asmjit::x64::Registers]
// ============================================================================
//! Gpq register.
ASMJIT_VAR const GpReg zax;
//! Gpq register.
ASMJIT_VAR const GpReg zcx;
//! Gpq register.
ASMJIT_VAR const GpReg zdx;
//! Gpq register.
ASMJIT_VAR const GpReg zbx;
//! Gpq register.
ASMJIT_VAR const GpReg zsp;
//! Gpq register.
ASMJIT_VAR const GpReg zbp;
//! Gpq register.
ASMJIT_VAR const GpReg zsi;
//! Gpq register.
ASMJIT_VAR const GpReg zdi;
//! \}
} // x64 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X64
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_X86_X86REGS_H

View File

@@ -0,0 +1,94 @@
// [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 "../base/containers.h"
#include "../x86/x86scheduler_p.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [Internals]
// ============================================================================
//! \internal
struct X86ScheduleData {
//! Registers read by the instruction.
X86RegMask regsIn;
//! Registers written by the instruction.
X86RegMask regsOut;
//! Flags read by the instruction.
uint8_t flagsIn;
//! Flags written by the instruction.
uint8_t flagsOut;
//! How many `uops` or `cycles` the instruction takes.
uint8_t ops;
//! Instruction latency.
uint8_t latency;
//! Which ports the instruction can run at.
uint16_t ports;
//! \internal
uint16_t reserved;
//! All instructions that this instruction depends on.
PodList<InstNode*>::Link* dependsOn;
//! All instructions that use the result of this instruction.
PodList<InstNode*>::Link* usedBy;
};
// ============================================================================
// [asmjit::X86Scheduler - Construction / Destruction]
// ============================================================================
X86Scheduler::X86Scheduler(X86Compiler* compiler, const X86CpuInfo* cpuInfo) :
_compiler(compiler),
_cpuInfo(cpuInfo) {}
X86Scheduler::~X86Scheduler() {}
// ============================================================================
// [asmjit::X86Scheduler - Run]
// ============================================================================
Error X86Scheduler::run(Node* start, Node* stop) {
/*
ASMJIT_TLOG("[Schedule] === Begin ===");
Zone zone(8096 - kZoneOverhead);
Node* node_ = start;
while (node_ != stop) {
Node* next = node_->getNext();
ASMJIT_ASSERT(node_->getType() == kNodeTypeInst);
printf(" %s\n", X86Util::getInstInfo(static_cast<InstNode*>(node_)->getCode()).getInstName());
node_ = next;
}
ASMJIT_TLOG("[Schedule] === End ===");
*/
return kErrorOk;
}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER && (ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64)

View File

@@ -0,0 +1,63 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86SCHEDULER_P_H
#define _ASMJIT_X86_X86SCHEDULER_P_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies - AsmJit]
#include "../x86/x86compiler.h"
#include "../x86/x86context_p.h"
#include "../x86/x86cpuinfo.h"
#include "../x86/x86inst.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::X86Scheduler]
// ============================================================================
//! \internal
//!
//! X86 scheduler.
struct X86Scheduler {
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
X86Scheduler(X86Compiler* compiler, const X86CpuInfo* cpuInfo);
~X86Scheduler();
// --------------------------------------------------------------------------
// [Run]
// --------------------------------------------------------------------------
Error run(Node* start, Node* stop);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Attached compiler.
X86Compiler* _compiler;
//! CPU information used for scheduling.
const X86CpuInfo* _cpuInfo;
};
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_X86_X86SCHEDULER_P_H

View File

@@ -1,90 +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
// [Guard]
#include "../build.h"
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
// [Dependencies - AsmJit]
#include "../x86/x86util.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
// ============================================================================
// [asmjit::x86x64::Condition Codes]
// ============================================================================
#define CC_TO_INST(_Inst_) { \
_Inst_##o, \
_Inst_##no, \
_Inst_##b, \
_Inst_##ae, \
_Inst_##e, \
_Inst_##ne, \
_Inst_##be, \
_Inst_##a, \
_Inst_##s, \
_Inst_##ns, \
_Inst_##pe, \
_Inst_##po, \
_Inst_##l, \
_Inst_##ge, \
_Inst_##le, \
_Inst_##g, \
\
kInstNone, \
kInstNone, \
kInstNone, \
kInstNone \
}
const uint32_t _reverseCond[20] = {
/* kCondO -> */ kCondO,
/* kCondNO -> */ kCondNO,
/* kCondB -> */ kCondA,
/* kCondAE -> */ kCondBE,
/* kCondE -> */ kCondE,
/* kCondNE -> */ kCondNE,
/* kCondBE -> */ kCondAE,
/* kCondA -> */ kCondB,
/* kCondS -> */ kCondS,
/* kCondNS -> */ kCondNS,
/* kCondPE -> */ kCondPE,
/* kCondPO -> */ kCondPO,
/* kCondL -> */ kCondG,
/* kCondGE -> */ kCondLE,
/* kCondLE -> */ kCondGE,
/* kCondG -> */ kCondL,
/* kCondFpuUnordered -> */ kCondFpuUnordered,
/* kCondFpuNotUnordered -> */ kCondFpuNotUnordered,
0x12,
0x13
};
const uint32_t _condToCmovcc[20] = CC_TO_INST(kInstCmov);
const uint32_t _condToJcc [20] = CC_TO_INST(kInstJ );
const uint32_t _condToSetcc [20] = CC_TO_INST(kInstSet );
#undef CC_TO_INST
} // x86x64 namespace
} // asmjit namespace
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64

View File

@@ -1,394 +0,0 @@
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_X86_X86UTIL_H
#define _ASMJIT_X86_X86UTIL_H
// [Dependencies - AsmJit]
#include "../base/func.h"
#include "../x86/x86inst.h"
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
//! \addtogroup asmjit_x86x64_util
//! \{
// ============================================================================
// [asmjit::x86x64::Internal]
// ============================================================================
//! \internal
//!
//! X86/X64 condition codes to reversed condition codes map.
ASMJIT_VAR const uint32_t _reverseCond[20];
//! \internal
//!
//! X86X64 condition codes to "cmovcc" group map.
ASMJIT_VAR const uint32_t _condToCmovcc[20];
//! \internal
//!
//! X86X64 condition codes to "jcc" group map.
ASMJIT_VAR const uint32_t _condToJcc[20];
//! \internal
//!
//! X86X64 condition codes to "setcc" group map.
ASMJIT_VAR const uint32_t _condToSetcc[20];
// ============================================================================
// [asmjit::x86x64::RegCount]
// ============================================================================
//! \internal
//!
//! X86/X64 registers count (Gp, Fp, Mm, Xmm).
struct RegCount {
// --------------------------------------------------------------------------
// [Zero]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_packed = 0;
}
// --------------------------------------------------------------------------
// [Get]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t get(uint32_t c) const {
ASMJIT_ASSERT(c < kRegClassCount);
return _regs[c];
}
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
ASMJIT_INLINE void set(uint32_t c, uint32_t n) {
ASMJIT_ASSERT(c < kRegClassCount);
ASMJIT_ASSERT(n < 0x100);
_regs[c] = static_cast<uint8_t>(n);
}
// --------------------------------------------------------------------------
// [Add]
// --------------------------------------------------------------------------
ASMJIT_INLINE void add(uint32_t c, uint32_t n = 1) {
ASMJIT_ASSERT(c < kRegClassCount);
ASMJIT_ASSERT(n < 0x100);
_regs[c] += static_cast<uint8_t>(n);
}
// --------------------------------------------------------------------------
// [Misc]
// --------------------------------------------------------------------------
ASMJIT_INLINE void makeIndex(const RegCount& count) {
uint8_t a = count._regs[0];
uint8_t b = count._regs[1];
uint8_t c = count._regs[2];
_regs[0] = 0;
_regs[1] = a;
_regs[2] = a + b;
_regs[3] = a + b + c;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _gp;
uint8_t _fp;
uint8_t _mm;
uint8_t _xy;
};
uint8_t _regs[4];
uint32_t _packed;
};
};
// ============================================================================
// [asmjit::x86x64::RegMask]
// ============================================================================
//! \internal
//!
//! X86/X64 registers mask (Gp, Fp, Mm, Xmm/Ymm/Zmm).
struct RegMask {
// --------------------------------------------------------------------------
// [Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE void reset() {
_packed.reset();
}
// --------------------------------------------------------------------------
// [IsEmpty / Has]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isEmpty() const {
return _packed.isZero();
}
ASMJIT_INLINE bool has(uint32_t c, uint32_t mask = 0xFFFFFFFF) const {
switch (c) {
case kRegClassGp : return (static_cast<uint32_t>(_gp ) & mask) != 0;
case kRegClassFp : return (static_cast<uint32_t>(_fp ) & mask) != 0;
case kRegClassMm : return (static_cast<uint32_t>(_mm ) & mask) != 0;
case kRegClassXyz: return (static_cast<uint32_t>(_xyz) & mask) != 0;
}
ASMJIT_ASSERT(!"Reached");
return false;
}
// --------------------------------------------------------------------------
// [Zero]
// --------------------------------------------------------------------------
ASMJIT_INLINE void zero(uint32_t c) {
switch (c) {
case kRegClassGp : _gp = 0; break;
case kRegClassFp : _fp = 0; break;
case kRegClassMm : _mm = 0; break;
case kRegClassXyz: _xyz = 0; break;
}
}
// --------------------------------------------------------------------------
// [Get]
// --------------------------------------------------------------------------
ASMJIT_INLINE uint32_t get(uint32_t c) const {
switch (c) {
case kRegClassGp : return _gp;
case kRegClassFp : return _fp;
case kRegClassMm : return _mm;
case kRegClassXyz: return _xyz;
}
ASMJIT_ASSERT(!"Reached");
return 0;
}
// --------------------------------------------------------------------------
// [Set]
// --------------------------------------------------------------------------
ASMJIT_INLINE void set(uint32_t c, uint32_t mask) {
switch (c) {
case kRegClassGp : _gp = static_cast<uint16_t>(mask); break;
case kRegClassFp : _fp = static_cast<uint8_t >(mask); break;
case kRegClassMm : _mm = static_cast<uint8_t >(mask); break;
case kRegClassXyz: _xyz = static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void set(const RegMask& other) {
_packed.setUInt64(other._packed);
}
// --------------------------------------------------------------------------
// [Add]
// --------------------------------------------------------------------------
ASMJIT_INLINE void add(uint32_t c, uint32_t mask) {
switch (c) {
case kRegClassGp : _gp |= static_cast<uint16_t>(mask); break;
case kRegClassFp : _fp |= static_cast<uint8_t >(mask); break;
case kRegClassMm : _mm |= static_cast<uint8_t >(mask); break;
case kRegClassXyz: _xyz |= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void add(const RegMask& other) {
_packed.or_(other._packed);
}
// --------------------------------------------------------------------------
// [Del]
// --------------------------------------------------------------------------
ASMJIT_INLINE void del(uint32_t c, uint32_t mask) {
switch (c) {
case kRegClassGp : _gp &= ~static_cast<uint16_t>(mask); break;
case kRegClassFp : _fp &= ~static_cast<uint8_t >(mask); break;
case kRegClassMm : _mm &= ~static_cast<uint8_t >(mask); break;
case kRegClassXyz: _xyz &= ~static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void del(const RegMask& other) {
_packed.del(other._packed);
}
// --------------------------------------------------------------------------
// [And]
// --------------------------------------------------------------------------
ASMJIT_INLINE void and_(uint32_t c, uint32_t mask) {
switch (c) {
case kRegClassGp : _gp &= static_cast<uint16_t>(mask); break;
case kRegClassFp : _fp &= static_cast<uint8_t >(mask); break;
case kRegClassMm : _mm &= static_cast<uint8_t >(mask); break;
case kRegClassXyz: _xyz &= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void and_(const RegMask& other) {
_packed.and_(other._packed);
}
// --------------------------------------------------------------------------
// [Xor]
// --------------------------------------------------------------------------
ASMJIT_INLINE void xor_(uint32_t c, uint32_t mask) {
switch (c) {
case kRegClassGp : _gp ^= static_cast<uint16_t>(mask); break;
case kRegClassFp : _fp ^= static_cast<uint8_t >(mask); break;
case kRegClassMm : _mm ^= static_cast<uint8_t >(mask); break;
case kRegClassXyz: _xyz ^= static_cast<uint32_t>(mask); break;
}
}
ASMJIT_INLINE void xor_(const RegMask& other) {
_packed.xor_(other._packed);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
//! Gp mask (16-bit).
uint16_t _gp;
//! Fp mask (8-bit).
uint8_t _fp;
//! Mm mask (8-bit).
uint8_t _mm;
//! Xmm/Ymm/Zmm mask (32-bit).
uint32_t _xyz;
};
//! All masks as 64-bit integer.
UInt64 _packed;
};
};
// ============================================================================
// [asmjit::x86x64::X86Util]
// ============================================================================
//! X86/X64 utilities.
struct X86Util {
// --------------------------------------------------------------------------
// [Condition Codes]
// --------------------------------------------------------------------------
//! Corresponds to transposing the operands of a comparison.
static ASMJIT_INLINE uint32_t reverseCond(uint32_t cond) {
ASMJIT_ASSERT(cond < ASMJIT_ARRAY_SIZE(_reverseCond));
return _reverseCond[cond];
}
//! Get the equivalent of negated condition code.
static ASMJIT_INLINE uint32_t negateCond(uint32_t cond) {
ASMJIT_ASSERT(cond < ASMJIT_ARRAY_SIZE(_reverseCond));
return static_cast<kCond>(cond ^ static_cast<uint32_t>(cond < kCondNone));
}
//! Translate condition code `cc` to `cmovcc` instruction code.
//! \sa \ref kInstCode, \ref _kInstCmovcc.
static ASMJIT_INLINE uint32_t condToCmovcc(uint32_t cond) {
ASMJIT_ASSERT(static_cast<uint32_t>(cond) < ASMJIT_ARRAY_SIZE(_condToCmovcc));
return _condToCmovcc[cond];
}
//! Translate condition code `cc` to `jcc` instruction code.
//! \sa \ref kInstCode, \ref _kInstJcc.
static ASMJIT_INLINE uint32_t condToJcc(uint32_t cond) {
ASMJIT_ASSERT(static_cast<uint32_t>(cond) < ASMJIT_ARRAY_SIZE(_condToJcc));
return _condToJcc[cond];
}
//! Translate condition code `cc` to `setcc` instruction code.
//! \sa \ref kInstCode, \ref _kInstSetcc.
static ASMJIT_INLINE uint32_t condToSetcc(uint32_t cond) {
ASMJIT_ASSERT(static_cast<uint32_t>(cond) < ASMJIT_ARRAY_SIZE(_condToSetcc));
return _condToSetcc[cond];
}
// --------------------------------------------------------------------------
// [Registers]
// --------------------------------------------------------------------------
//! Get whether the `op` operand is Gpb-Lo or Gpb-Hi register.
static ASMJIT_INLINE bool isGpbRegOp(const Operand& op) {
const uint32_t mask = IntUtil::pack32_2x8_1x16(0xFF, 0xFF, ~(kRegTypePatchedGpbHi << 8) & 0xFF00);
return (op._packed[0].u32[0] & mask) == IntUtil::pack32_2x8_1x16(kOperandTypeReg, 1, 0x0000);
}
// --------------------------------------------------------------------------
// [Immediates]
// --------------------------------------------------------------------------
//! Pack a shuffle constant to be used with multimedia instrutions (2 values).
//!
//! \param x First component position, number at interval [0, 1] inclusive.
//! \param y Second component position, number at interval [0, 1] inclusive.
//!
//! Shuffle constants can be used to make immediate value for these intrinsics:
//! - `X86X64Assembler::shufpd()` and `X86X64Compiler::shufpd()`
static ASMJIT_INLINE int mmShuffle(uint32_t x, uint32_t y) {
return static_cast<int>((x << 1) | y);
}
//! Pack a shuffle constant to be used with multimedia instrutions (4 values).
//!
//! \param z First component position, number at interval [0, 3] inclusive.
//! \param x Second component position, number at interval [0, 3] inclusive.
//! \param y Third component position, number at interval [0, 3] inclusive.
//! \param w Fourth component position, number at interval [0, 3] inclusive.
//!
//! Shuffle constants can be used to make immediate value for these intrinsics:
//! - `X86X64Assembler::pshufw()` and `X86X64Compiler::pshufw()`
//! - `X86X64Assembler::pshufd()` and `X86X64Compiler::pshufd()`
//! - `X86X64Assembler::pshufhw()` and `X86X64Compiler::pshufhw()`
//! - `X86X64Assembler::pshuflw()` and `X86X64Compiler::pshuflw()`
//! - `X86X64Assembler::shufps()` and `X86X64Compiler::shufps()`
static ASMJIT_INLINE int mmShuffle(uint32_t z, uint32_t y, uint32_t x, uint32_t w) {
return static_cast<int>((z << 6) | (y << 4) | (x << 2) | w);
}
};
//! \}
} // x86x64 namespace
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_X86_X86UTIL_H

View File

@@ -1,29 +1,27 @@
// [GenDefs] // [GenDefs]
// //
// The purpose of this script is to fetch all instructions' names into a single // The purpose of this script is to fetch all instructions' names into a single
// string. It prevents relocation that has to be done by linked to make all // string and to optimize common patterns that appear in instruction data. It
// pointers the binary application/library uses valid. This approach decreases // prevents relocation of small strings (instruction names) that has to be done
// the final size of AsmJit binary. // by a linker to make all pointers the binary application/library uses valid.
// This approach decreases the final size of AsmJit binary and relocation data.
var fs = require("fs"); var fs = require("fs");
// ----------------------------------------------------------------------------
// [Configuration]
// ----------------------------------------------------------------------------
var injectStartMarker = "// ${kInstData:Begin}\n";
var injectEndMarker = "// ${kInstData:End}\n";
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// [Utilities] // [Utilities]
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
var uppercaseFirst = function(s) { var upFirst = function(s) {
if (!s) if (!s)
return s; return s;
return s[0].toUpperCase() + s.substr(1); return s[0].toUpperCase() + s.substr(1);
}; };
var trimLeft = function(s) {
return s.replace(/^\s+/, "");
}
var inject = function(s, start, end, code) { var inject = function(s, start, end, code) {
var iStart = s.indexOf(start); var iStart = s.indexOf(start);
var iEnd = s.indexOf(end); var iEnd = s.indexOf(end);
@@ -41,9 +39,8 @@ var inject = function(s, start, end, code) {
// [Database] // [Database]
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// FullIndex - Index of the name of the instruction in one big string.
var Database = (function() { var Database = (function() {
// `IndexedString` class.
var IndexedString = function() { var IndexedString = function() {
this.array = []; this.array = [];
this.index = 0; this.index = 0;
@@ -52,6 +49,7 @@ var Database = (function() {
IndexedString.prototype.add = function(s) { IndexedString.prototype.add = function(s) {
var index = this.map[s]; var index = this.map[s];
if (typeof index === "number") if (typeof index === "number")
return index; return index;
@@ -84,38 +82,58 @@ var Database = (function() {
return this.index; return this.index;
}; };
// `Database` class.
var Database = function() { var Database = function() {
this.map = {}; this.instMap = {};
this.alphabetical = new Array(26); this.instNames = new IndexedString();
this.fullString = new IndexedString(); this.instAlpha = new Array(26);
this.extendedData = [];
this.extendedMap = {};
}; };
Database.prototype.add = function(name, id) { Database.prototype.add = function(name, id, extendedData) {
this.map[name] = { this.instMap[name] = {
id: id, id : id, // Instruction ID.
fullIndex: 0, nameIndex : 0, // Instruction name-index, used directly by AsmJit.
hasV: 0 vPrefix : 0, // Instruction starts with 'v', not used at this point.
extendedData : extendedData,
extendedIndex : ""
}; };
}; };
Database.prototype.index = function() { Database.prototype.index = function() {
var map = this.map; var instMap = this.instMap;
var alphabetical = this.alphabetical; var instNames = this.instNames;
var instAlpha = this.instAlpha;
for (var name in map) { var extendedData = this.extendedData;
var inst = map[name]; var extendedMap = this.extendedMap;
inst.fullIndex = this.fullString.add(name);
for (var name in instMap) {
var inst = instMap[name];
var nameIndex = instNames.add(name);
var extendedIndex = extendedMap[inst.extendedData];
if (typeof extendedIndex !== "number") {
extendedIndex = extendedData.length;
extendedMap[inst.extendedData] = extendedIndex;
extendedData.push(inst.extendedData);
}
inst.nameIndex = nameIndex;
inst.extendedIndex = extendedIndex;
var aIndex = name.charCodeAt(0) - 'a'.charCodeAt(0); var aIndex = name.charCodeAt(0) - 'a'.charCodeAt(0);
if (aIndex < 0 || aIndex >= 26) if (aIndex < 0 || aIndex >= 26)
throw new Error("Alphabetical index error"); throw new Error("Alphabetical index error");
if (alphabetical[aIndex] === undefined) if (instAlpha[aIndex] === undefined)
alphabetical[aIndex] = inst.id; instAlpha[aIndex] = inst.id;
if (name.indexOf("v") === 0) { if (name.indexOf("v") === 0) {
inst.hasV = 1; inst.vPrefix = 1;
name = name.substr(1);
} }
} }
}; };
@@ -127,64 +145,154 @@ var Database = (function() {
// [Generate] // [Generate]
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
var decToHex = function(n, nPad) {
var hex = Number(n < 0 ? 0x100000000 + n : n).toString(16);
while (nPad > hex.length)
hex = "0" + hex;
return "0x" + hex.toUpperCase();
};
var getEFlagsMask = function(eflags, passing) {
var msk = 0x0;
var bit = 0x1;
for (var i = 0; i < 8; i++, bit <<= 1) {
if (passing.indexOf(eflags[i]) !== -1)
msk |= bit;
}
return msk;
};
var generate = function(fileName, arch) { var generate = function(fileName, arch) {
var Arch = upFirst(arch);
var oldData = fs.readFileSync(fileName, "utf8").replace(/\r\n/g, "\n"); var oldData = fs.readFileSync(fileName, "utf8").replace(/\r\n/g, "\n");
var data = oldData; var data = oldData;
var code = ""; var code = "";
var disclaimer = "// Automatically generated, do not edit.\n";
var Arch = uppercaseFirst(arch);
// Create database. // Create database.
var db = new Database(); var db = new Database();
var re = new RegExp("INST\\(([A-Za-z0-9_]+)\\s*,\\s*\\\"([A-Za-z0-9_ ]*)\\\"", "g"); var re = new RegExp(
"INST\\(([A-Za-z0-9_]+)\\s*," + // [01] Inst-Code.
"\\s*\\\"([A-Za-z0-9_ ]*)\\\"\\s*," + // [02] Inst-Name.
"([^,]+)," + // [03] Inst-Group.
"([^,]+)," + // [04] Inst-Flags.
"([^,]+)," + // [05] Move-Size.
"([^,]+)," + // [06] Operand-Flags[0].
"([^,]+)," + // [07] Operand-Flags[1].
"([^,]+)," + // [08] Operand-Flags[2].
"([^,]+)," + // [09] Operand-Flags[3].
"\\s*E\\(([A-Z_]+)\\)\\s*," + // [10] EFLAGS.
"(.{17}[^,]*)," + // [11] OpCode[0].
"(.{17}[^\\)]*)\\)", // [12] OpCode[1].
"g");
while (m = re.exec(data)) { while (m = re.exec(data)) {
// Extract instruction ID and Name.
var id = m[1]; var id = m[1];
var name = m[2]; var name = m[2];
db.add(name, id); // Extract data that goes to the secondary table (ExtendedInfo).
var instGroup = trimLeft(m[3]);
var instFlags = trimLeft(m[4]);
var moveSize = trimLeft(m[5]);
var opFlags0 = trimLeft(m[6]);
var opFlags1 = trimLeft(m[7]);
var opFlags2 = trimLeft(m[8]);
var opFlags3 = trimLeft(m[9]);
var eflags = m[10];
var opCode1 = trimLeft(m[12]);
// Generate EFlags-In and EFlags-Out.
var eflagsIn = decToHex(getEFlagsMask(eflags, "RX"), 2);
var eflagsOut = decToHex(getEFlagsMask(eflags, "WXU"), 2);
var extData = "" +
instGroup + ", " +
moveSize + ", " +
eflagsIn + ", " +
eflagsOut + ", " +
instFlags + ", " +
"{ " + opFlags0 + ", " + opFlags1 + ", " + opFlags2 + ", " + opFlags3 + ", U }, " +
opCode1;
db.add(name, id, extData);
} }
db.index(); db.index();
console.log("Full size: " + db.fullString.getSize()); console.log("Number of instructions: " + db.instNames.array.length);
console.log("Instruction names size: " + db.instNames.getSize());
console.log("Extended-info length : " + db.extendedData.length);
// Generate InstName[] string. // Generate InstName[] string.
code += "const char _instName[] =\n"; code += disclaimer;
for (var k in db.map) { code += "#if !defined(ASMJIT_DISABLE_INST_NAMES)\n";
var inst = db.map[k]; code += "const char _" + arch + "InstName[] =\n";
for (var k in db.instMap) {
var inst = db.instMap[k];
code += " \"" + k + "\\0\"\n"; code += " \"" + k + "\\0\"\n";
} }
code = code.substr(code, code.length - 1) + ";\n\n"; code = code.substr(code, code.length - 1) + ";\n\n";
// Generate AlphaIndex. // Generate AlphaIndex.
code += "enum kInstAlphaIndex {\n"; code += disclaimer;
code += " kInstAlphaIndexFirst = 'a',\n"; code += "enum k" + Arch + "InstAlphaIndex {\n";
code += " kInstAlphaIndexLast = 'z',\n"; code += " k" + Arch + "InstAlphaIndexFirst = 'a',\n";
code += " kInstAlphaIndexInvalid = 0xFFFF\n"; code += " k" + Arch + "InstAlphaIndexLast = 'z',\n";
code += " k" + Arch + "InstAlphaIndexInvalid = 0xFFFF\n";
code += "};\n"; code += "};\n";
code += "\n"; code += "\n";
// Generate NameIndex. code += disclaimer;
code += "static const uint16_t _instAlphaIndex[26] = {\n"; code += "static const uint16_t _" + arch + "InstAlphaIndex[26] = {\n";
for (var i = 0; i < db.alphabetical.length; i++) { for (var i = 0; i < db.instAlpha.length; i++) {
var id = db.alphabetical[i]; var id = db.instAlpha[i];
code += " " + (id === undefined ? "0xFFFF" : id); code += " " + (id === undefined ? "0xFFFF" : id);
if (i !== db.alphabetical.length - 1) if (i !== db.instAlpha.length - 1)
code += ","; code += ",";
code += "\n"; code += "\n";
} }
code += "};\n\n"; code += "};\n\n";
code += "enum kInstData_NameIndex {\n"; // Generate NameIndex.
for (var k in db.map) { code += disclaimer;
var inst = db.map[k]; code += "enum k" + Arch + "InstData_NameIndex {\n";
code += " " + inst.id + "_NameIndex = " + inst.fullIndex + ",\n"; for (var k in db.instMap) {
var inst = db.instMap[k];
code += " " + inst.id + "_NameIndex = " + inst.nameIndex + ",\n";
} }
code = code.substr(code, code.length - 2) + "\n};\n"; code = code.substr(0, code.length - 2) + "\n};\n";
code += "#endif // !ASMJIT_DISABLE_INST_NAMES\n"
code += "\n";
// Generate ExtendedInfo.
code += disclaimer;
code += "const " + Arch + "InstExtendedInfo _" + arch + "InstExtendedInfo[] = {\n";
for (var i = 0; i < db.extendedData.length; i++) {
code += " { " + db.extendedData[i] + " }";
if (i !== db.extendedData.length - 1)
code += ",";
code += "\n";
}
code += "};\n";
code += "\n";
code += disclaimer;
code += "enum k" + Arch + "InstData_ExtendedIndex {\n";
for (var k in db.instMap) {
var inst = db.instMap[k];
code += " " + inst.id + "_ExtendedIndex = " + inst.extendedIndex + ",\n";
}
code = code.substr(0, code.length - 2) + "\n};\n";
// Inject. // Inject.
data = inject(data, injectStartMarker, injectEndMarker, code); data = inject(data,
"// ${" + Arch + "InstData:Begin}\n",
"// ${" + Arch + "InstData:End}\n",
code);
// Save only if modified. // Save only if modified.
if (data !== oldData) if (data !== oldData)