- Minor reorganization of source code (split defs to operand and instruction info).

- Added JECXZ instruction.
- Doxyfile is now in project root.
- Documentation updates.
This commit is contained in:
kobalicek
2014-05-10 21:19:50 +02:00
parent bd1a5facb8
commit 1a73e65534
69 changed files with 9451 additions and 5174 deletions

View File

@@ -222,8 +222,6 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
cpuinfo.h
cputicks.cpp
cputicks.h
defs.cpp
defs.h
error.cpp
error.h
func.cpp
@@ -234,6 +232,8 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/base
lock.h
logger.cpp
logger.h
operand.cpp
operand.h
podlist.h
podvector.cpp
podvector.h
@@ -257,10 +257,14 @@ AsmJit_AddSource(ASMJIT_SRC asmjit/x86
x86context_p.h
x86cpuinfo.cpp
x86cpuinfo.h
x86defs.cpp
x86defs.h
x86func.cpp
x86func.h
x86inst.cpp
x86inst.h
x86operand.cpp
x86operand.h
x86util.cpp
x86util.h
)
AsmJit_AddSource(ASMJIT_SRC asmjit/contrib

236
Doxyfile Normal file
View File

@@ -0,0 +1,236 @@
# Doxyfile 1.8.7
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "AsmJit"
PROJECT_NUMBER = "1.1"
PROJECT_BRIEF = "Complete Remote and JIT Assembler for x86/x64"
OUTPUT_DIRECTORY = .
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
FULL_PATH_NAMES = YES
STRIP_FROM_PATH =
STRIP_FROM_INC_PATH =
SHORT_NAMES = NO
BRIEF_MEMBER_DESC = YES
REPEAT_BRIEF = YES
QT_AUTOBRIEF = NO
JAVADOC_AUTOBRIEF = YES
MULTILINE_CPP_IS_BRIEF = YES
ALWAYS_DETAILED_SEC = NO
INLINE_INHERITED_MEMB = NO
INHERIT_DOCS = YES
TAB_SIZE = 2
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = NO
IDL_PROPERTY_SUPPORT = NO
SEPARATE_MEMBER_PAGES = NO
DISTRIBUTE_GROUP_DOC = NO
SUBGROUPING = YES
INLINE_GROUPED_CLASSES = NO
INLINE_SIMPLE_STRUCTS = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
HIDE_UNDOC_CLASSES = YES
HIDE_UNDOC_MEMBERS = NO
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = NO
SHOW_GROUPED_MEMB_INC = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = YES
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
MAX_INITIALIZER_LINES = 0
SHOW_USED_FILES = NO
SHOW_FILES = NO
SHOW_NAMESPACES = NO
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = src/asmjit
INPUT_ENCODING = UTF-8
RECURSIVE = YES
EXCLUDE =
USE_MDFILE_AS_MAINPAGE = README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
SOURCE_TOOLTIPS = YES
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
#---------------------------------------------------------------------------
# Configuration options related to outputs
#---------------------------------------------------------------------------
GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_MAN = NO
GENERATE_XML = YES
XML_OUTPUT = build_xml
XML_PROGRAMLISTING = NO
HTML_OUTPUT = build_doc
HTML_FILE_EXTENSION = .html
LAYOUT_FILE = tools/doc-layout.xml
HTML_HEADER = tools/doc-header.html
HTML_FOOTER = tools/doc-footer.html
HTML_STYLESHEET = tools/doc-style.css
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 0
SEARCHENGINE = NO
#---------------------------------------------------------------------------
# Configuration options related to the CHM output
#---------------------------------------------------------------------------
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
# files are now used as the Windows 98 help format, and will replace the old
# Windows help format (.hlp) on all Windows platforms in the future. Compressed
# HTML files also contain an index, a table of contents, and you can search for
# words in the documentation. The HTML workshop also contains a viewer for
# compressed HTML files.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
# The CHM_FILE tag can be used to specify the file name of the resulting .chm
# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler ( hhc.exe). If non-empty
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members to
# the table of contents of the HTML help documentation and to the tree view.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
DISABLE_INDEX = NO
GENERATE_TREEVIEW = NO
ENUM_VALUES_PER_LINE = 0
TREEVIEW_WIDTH = 250
EXT_LINKS_IN_WINDOW = NO
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
PREDEFINED = ASMJIT_DOCGEN \
ASMJIT_BUILD_X86 \
ASMJIT_BUILD_X64 \
ASMJIT_API
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
CLASS_GRAPH = NO

View File

@@ -1,4 +1,4 @@
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
Copyright (c) 2008-2014, Petr Kobalicek <kobalicek.petr@gmail.com>
This software is provided 'as-is', without any express or implied

992
README.md
View File

@@ -1,496 +1,496 @@
AsmJit
======
Complete x86/x64 JIT and Remote Assembler for C++.
Official Repository
-------------------
https://github.com/kobalicekp/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
------------
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.
Features
--------
* Complete x86/x64 instruction set - MMX, SSE, AVX, BMI, XOP, FMA...,
* Low-level and high-level code generation,
* Built-in CPU detection,
* Virtual Memory management,
* Pretty logging and error handling,
* Small and embeddable, around 150kB compiled,
* Zero dependencies, not even STL or RTTI.
Supported Environments
----------------------
### Operating Systems
* BSDs
* Linux
* Mac
* Windows
### C++ Compilers
* BorlandC++
* GNU (3.4.X+, 4.0+, MinGW)
* MSVC (VS2005, VS2008, VS2010)
* Other compilers require testing
### Backends
* X86
* X64
Project Organization
--------------------
- project root /
- src - Source code
- asmjit - Public header files (always include from here)
- base - Base files, used by the AsmJit and all backends
- contrib - Contributions that extends base functionality
- x86 - X86/X64 specific files, used only by X86/X64 backend
- tools - Tools used for configuring, documenting and generating files
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.
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.
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.
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:
### Library 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_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
* *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
* *ASMJIT_DEBUG* - Define to always turn debugging on (regardless of build-mode).
* *ASMJIT_RELEASE* - Define to always turn debugging off (regardless of build-mode).
* 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.
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 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
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.
### 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:
* *Register* - Physical register (used only by Assember)
* *Variable* - Virtual register (used only by Compiler)
* *Memory* - Location in memory
* *Label* - Location in code
* *Immediate* - Constant 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`.
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.
### Function Prototypes
AsmJit needs to know the prototype of the function it will generate or call. AsmJit contains a mapping between a type and the register that will be used to represent it. To make life easier there is a function builder that does the mapping on the fly. Function builder is a template class that helps with creating a function prototype by using native C/C++ types that describe function arguments and return value. It translates C/C++ native types into AsmJit specific IDs and makes these IDs accessible to Compiler.
### Putting It All Together
Let's put all together and generate a first function that sums its two arguments and returns the result. At the end the generated function is called from a C++ code.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
// Create JitRuntime and host specific Compiler.
JitRuntime runtime;
Compiler c(&runtime);
// Build function having two arguments and a return value of type 'int'.
// First type in function builder describes the return value. kFuncConvHost
// tells compiler to use a host calling convention.
c.addFunc(kFuncConvHost, FuncBuilder2<int, int, int>());
// Create 32-bit variables (virtual registers) and assign some names to
// them. Using names is purely optional and only greatly helps while
// debugging.
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
// Tell asmjit to use these variables as function arguments.
c.setArg(0, a);
c.setArg(1, b);
// a = a + b;
c.add(a, b);
// Tell asmjit to return 'a'.
c.ret(a);
// Finalize the current function.
c.endFunc();
// Now the Compiler contains the whole function, but the code is not yet
// generated. To tell compiler to generate the function make() has to be
// called.
// Make uses the JitRuntime passed to Compiler constructor to allocate a
// buffer for the function and make it executable.
void* funcPtr = c.make();
// In order to run 'funcPtr' it has to be casted to the desired type.
// Typedef is a recommended and safe way to create a function-type.
typedef int (*FuncType)(int, int);
// Using asmjit_cast is purely optional, it's basically a C-style cast
// that tries to make it visible that a function-type is returned.
FuncType func = asmjit_cast<FuncType>(funcPtr);
// Finally, run it and do something with the result...
int x = func(1, 2);
printf("x=%d\n", x); // Outputs "x=3".
// The function will remain in memory after Compiler is destroyed, but
// will be destroyed together with Runtime. This is just simple example
// where we can just destroy both at the end of the scope and that's it.
// However, it's a good practice to clean-up resources after they are
// not needed and using runtime.release() is the preferred way to free
// a function added to JitRuntime.
runtime.release((void*)func);
// Runtime and Compiler will be destroyed at the end of the scope.
return 0;
}
```
The code should be self explanatory, however there are some details to be clarified.
The code above generates and calls a function of `kFuncConvHost` calling convention. 32-bit architecture contains a wide range of function calling conventions that can be all used by a single program, so it's important to know which calling convention is used by your C/C++ compiler so you can call the function. However, most compilers should generate CDecl by default. In 64-bit mode there are only two calling conventions, one is specific for Windows (Win64 calling convention) and the other for Unix (AMD64 calling convention). The `kFuncConvHost` is defined to be one of CDecl, Win64 or AMD64 depending on your architecture and operating system.
Default integer size is platform specific, virtual types `kVarTypeIntPtr` and `kVarTypeUIntPtr` can be used to make the code more portable and they should be always used when a pointer type is needed. When no type is specified AsmJit always defaults to `kVarTypeIntPtr`. The code above works with integers where the default behavior has been overidden to 32-bits. Note it's always a good practice to specify the type of the variable used. Alternative form of creating a variable is `c.newGpVar(...)`, `c.newMmVar(...)`, `c.newXmmVar` and so on...
The function starts with `c.addFunc()` and ends with `c.endFunc()`. It's not allowed to put code outside of the function; however, embedding data outside of the function body is allowed.
### 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`.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// This function uses 3 arguments.
c.addFunc(kFuncConvHost, FuncBuilder3<int, int, int, int>());
// New variable 'op' added.
GpVar op(c, kVarTypeInt32, "op");
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
c.setArg(0, op);
c.setArg(1, a);
c.setArg(2, b);
// Create labels.
Label L_Subtract(c);
Label L_Skip(c);
// If (op != 0)
// goto L_Subtract;
c.test(op, op);
c.jne(L_Subtract);
// a = a + b;
// goto L_Skip;
c.add(a, b);
c.jmp(L_Skip);
// L_Subtract:
// a = a - b;
c.bind(L_Subtract);
c.sub(a, b);
// L_Skip:
c.bind(L_Skip);
c.ret(a);
c.endFunc();
// The prototype of the generated function changed also here.
typedef int (*FuncType)(int, int, int);
FuncType func = asmjit_cast<FuncType>(c.make());
int x = func(0, 1, 2);
int y = func(1, 1, 2);
printf("x=%d\n", x); // Outputs "x=3".
printf("y=%d\n", y); // Outputs "y=-1".
runtime.release((void*)func);
return 0;
}
```
In this example conditional and uncondition jumps were used with labels together. Labels are created explicitly by the Compiler by passing a Compiler instance to a `Label` constructor or by using a `Label l = c.newLabel()` form. Each label as an unique ID that identifies it, however it's not a string and there is no way to query for a Label instance that already exists. Label is like any other operand moved by value so the copy of the label will still reference the same label and changing a copied will not change the original label.
Each label has to be bound to the location in the code by using `c.bind()`; however, it can be only bound once! Trying to bind the same label multiple times has undefined behavior - it will trigger an assertion failure in the best case.
### Memory Addressing
X86/X64 architectures have several memory addressing modes which can be used to combine base register, index register and a displacement. In addition, index register can be shifted by a constant from 1 to 3 that can help with addressing elements up to 8-byte long in an array. AsmJit supports all forms of memory addressing. Memory operand can be created by using `asmjit::host::Mem` or by using related non-member functions like `asmjit::host::ptr` or `asmjit::host::ptr_abs`. Use `ptr` to create a memory operand having a base register with optional index register and a displacement and `ptr_abs` to create a memory operand refering to an absolute address in memory and optionally having an index register.
In the following example various memory addressing modes are used to demonstrate how to construct and use memory operands. It creates a function that accepts an array and two indexes which specify which elements to sum and return.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// Function returning 'int' accepting pointer and two indexes.
c.addFunc(kFuncConvHost, FuncBuilder3<int, const int*, intptr_t, intptr_t>());
GpVar p(c, kVarTypeIntPtr, "p");
GpVar aIndex(c, kVarTypeIntPtr, "aIndex");
GpVar bIndex(c, kVarTypeIntPtr, "bIndex");
c.setArg(0, p);
c.setArg(1, aIndex);
c.setArg(2, bIndex);
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
// Read 'a' by using a memory operand having base register, index register
// and scale. Translates to 'mov a, dword ptr [p + aIndex << 2]'.
c.mov(a, ptr(p, aIndex, 2));
// Read 'b' by using a memory operand having base register only. Variables
// 'p' and 'bIndex' are both modified.
// Shift bIndex by 2 (exactly the same as multiplying by 4).
// And add scaled 'bIndex' to 'p' resulting in 'p = p + bIndex * 4'.
c.shl(bIndex, 2);
c.add(p, bIndex);
// Read 'b'.
c.mov(b, ptr(p));
// a = a + b;
c.add(a, b);
c.ret(a);
c.endFunc();
// The prototype of the generated function changed also here.
typedef int (*FuncType)(const int*, intptr_t, intptr_t);
FuncType func = asmjit_cast<FuncType>(c.make());
// Array passed to 'func'
const int array[] = { 1, 2, 3, 5, 8, 13 };
int x = func(array, 1, 2);
int y = func(array, 3, 5);
printf("x=%d\n", x); // Outputs "x=5".
printf("y=%d\n", y); // Outputs "y=18".
runtime.release((void*)func);
return 0;
}
```
### 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.
In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// Function returning 'int' without any arguments.
c.addFunc(kFuncConvHost, FuncBuilder0<int>());
// Allocate a function stack of size 256 aligned to 4 bytes.
Mem stack = c.newStack(256, 4);
GpVar p(c, kVarTypeIntPtr, "p");
GpVar i(c, kVarTypeIntPtr, "i");
// 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)
// to a general purpose register.
c.lea(p, stack);
// Clear 'i'. Notice that xor_() is used instead of xor(), because xor is
// unfortunately a keyword in C++.
c.xor_(i, i);
// First loop, fill the stack allocated by a sequence of bytes from 0 to 255.
Label L1(c);
c.bind(L1);
// Mov [p + i], i.
//
// Any operand can be cloned and modified. By cloning 'stack' and calling
// 'setIndex' we created a new memory operand based on stack having an
// index register set.
c.mov(stack.clone().setIndex(i), i.r8());
// if (++i < 256)
// goto L1;
c.inc(i);
c.cmp(i, 256);
c.jb(L1);
// Second loop, sum all bytes stored in 'stack'.
GpVar a(c, kVarTypeInt32, "a");
GpVar t(c, kVarTypeInt32, "t");
c.xor_(i, i);
c.xor_(a, a);
Label L2(c);
c.bind(L2);
// Movzx t, byte ptr [stack + i]
c.movzx(t, stack.clone().setIndex(i).setSize(1));
// a += t;
c.add(a, t);
// if (++i < 256)
// goto L2;
c.inc(i);
c.cmp(i, 256);
c.jb(L2);
c.ret(a);
c.endFunc();
typedef int (*FuncType)(void);
FuncType func = asmjit_cast<FuncType>(c.make());
printf("a=%d\n", func()); // Outputs "a=32640".
runtime.release((void*)func);
return 0;
}
```
### Using Constant Pool
To be documented.
Advanced Features
-----------------
AsmJit offers much more, but not everything can fit into the introduction. The following sections don't have complete examples, but contain hints that can be useful and can change a bit the way AsmJit is used.
### 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.
To be documented.
### 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.
To manipulate the current cursor use Compiler's `getCursor()` and `setCursor()` member functions. The following snippet demonstrates the proper way of code injection.
```C++
Compiler c(...);
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
BaseNode* here = c.getCursor();
c.mov(b, 2);
// 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
// after the injecting is done. When setCursor() is called it returns the old
// cursor.
BaseNode* oldCursor = c.setCursor(here);
c.mov(a, 1);
c.setCursor(oldCursor);
```
The resulting code would look like:
```
c.mov(a, 1);
c.mov(b, 2);
```
License
-------
AsmJit can be distributed under zlib license:
* <http://www.opensource.org/licenses/zlib-license.php>
Contact Authors & Maintainers
-----------------------------
* Petr Kobalicek <kobalicek.petr@gmail.com>
AsmJit
======
Complete x86/x64 JIT and Remote Assembler for C++.
Official Repository
-------------------
https://github.com/kobalicekp/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
------------
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.
Features
--------
* Complete x86/x64 instruction set - MMX, SSE, AVX, BMI, XOP, FMA...,
* Low-level and high-level code generation,
* Built-in CPU detection,
* Virtual Memory management,
* Pretty logging and error handling,
* Small and embeddable, around 150-200kB compiled,
* Zero dependencies, not even STL or RTTI.
Supported Environments
----------------------
### Operating Systems
* BSDs
* Linux
* Mac
* Windows
### C++ Compilers
* BorlandC++
* GNU (3.4.X+, 4.0+, MinGW)
* MSVC (VS2005+)
* Other compilers require testing
### Backends
* X86
* X64
Project Organization
--------------------
- project root /
- src - Source code
- asmjit - Public header files (always include from here)
- base - Base files, used by the AsmJit and all backends
- contrib - Contributions that extends base functionality
- x86 - X86/X64 specific files, used only by X86/X64 backend
- tools - Tools used for configuring, documenting and generating files
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.
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.
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.
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:
### Library 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_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
* *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
* *ASMJIT_DEBUG* - Define to always turn debugging on (regardless of build-mode).
* *ASMJIT_RELEASE* - Define to always turn debugging off (regardless of build-mode).
* 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.
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 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
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.
### 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:
* *Register* - Physical register (used only by Assember)
* *Variable* - Virtual register (used only by Compiler)
* *Memory* - Location in memory
* *Label* - Location in code
* *Immediate* - Constant 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`.
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.
### Function Prototypes
AsmJit needs to know the prototype of the function it will generate or call. AsmJit contains a mapping between a type and the register that will be used to represent it. To make life easier there is a function builder that does the mapping on the fly. Function builder is a template class that helps with creating a function prototype by using native C/C++ types that describe function arguments and return value. It translates C/C++ native types into AsmJit specific IDs and makes these IDs accessible to Compiler.
### Putting It All Together
Let's put all together and generate a first function that sums its two arguments and returns the result. At the end the generated function is called from a C++ code.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
// Create JitRuntime and host specific Compiler.
JitRuntime runtime;
Compiler c(&runtime);
// Build function having two arguments and a return value of type 'int'.
// First type in function builder describes the return value. kFuncConvHost
// tells compiler to use a host calling convention.
c.addFunc(kFuncConvHost, FuncBuilder2<int, int, int>());
// Create 32-bit variables (virtual registers) and assign some names to
// them. Using names is purely optional and only greatly helps while
// debugging.
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
// Tell asmjit to use these variables as function arguments.
c.setArg(0, a);
c.setArg(1, b);
// a = a + b;
c.add(a, b);
// Tell asmjit to return 'a'.
c.ret(a);
// Finalize the current function.
c.endFunc();
// Now the Compiler contains the whole function, but the code is not yet
// generated. To tell compiler to generate the function make() has to be
// called.
// Make uses the JitRuntime passed to Compiler constructor to allocate a
// buffer for the function and make it executable.
void* funcPtr = c.make();
// In order to run 'funcPtr' it has to be casted to the desired type.
// Typedef is a recommended and safe way to create a function-type.
typedef int (*FuncType)(int, int);
// Using asmjit_cast is purely optional, it's basically a C-style cast
// that tries to make it visible that a function-type is returned.
FuncType func = asmjit_cast<FuncType>(funcPtr);
// Finally, run it and do something with the result...
int x = func(1, 2);
printf("x=%d\n", x); // Outputs "x=3".
// The function will remain in memory after Compiler is destroyed, but
// will be destroyed together with Runtime. This is just simple example
// where we can just destroy both at the end of the scope and that's it.
// However, it's a good practice to clean-up resources after they are
// not needed and using runtime.release() is the preferred way to free
// a function added to JitRuntime.
runtime.release((void*)func);
// Runtime and Compiler will be destroyed at the end of the scope.
return 0;
}
```
The code should be self explanatory, however there are some details to be clarified.
The code above generates and calls a function of `kFuncConvHost` calling convention. 32-bit architecture contains a wide range of function calling conventions that can be all used by a single program, so it's important to know which calling convention is used by your C/C++ compiler so you can call the function. However, most compilers should generate CDecl by default. In 64-bit mode there are only two calling conventions, one is specific for Windows (Win64 calling convention) and the other for Unix (AMD64 calling convention). The `kFuncConvHost` is defined to be one of CDecl, Win64 or AMD64 depending on your architecture and operating system.
Default integer size is platform specific, virtual types `kVarTypeIntPtr` and `kVarTypeUIntPtr` can be used to make the code more portable and they should be always used when a pointer type is needed. When no type is specified AsmJit always defaults to `kVarTypeIntPtr`. The code above works with integers where the default behavior has been overidden to 32-bits. Note it's always a good practice to specify the type of the variable used. Alternative form of creating a variable is `c.newGpVar(...)`, `c.newMmVar(...)`, `c.newXmmVar` and so on...
The function starts with `c.addFunc()` and ends with `c.endFunc()`. It's not allowed to put code outside of the function; however, embedding data outside of the function body is allowed.
### 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`.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// This function uses 3 arguments.
c.addFunc(kFuncConvHost, FuncBuilder3<int, int, int, int>());
// New variable 'op' added.
GpVar op(c, kVarTypeInt32, "op");
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
c.setArg(0, op);
c.setArg(1, a);
c.setArg(2, b);
// Create labels.
Label L_Subtract(c);
Label L_Skip(c);
// If (op != 0)
// goto L_Subtract;
c.test(op, op);
c.jne(L_Subtract);
// a = a + b;
// goto L_Skip;
c.add(a, b);
c.jmp(L_Skip);
// L_Subtract:
// a = a - b;
c.bind(L_Subtract);
c.sub(a, b);
// L_Skip:
c.bind(L_Skip);
c.ret(a);
c.endFunc();
// The prototype of the generated function changed also here.
typedef int (*FuncType)(int, int, int);
FuncType func = asmjit_cast<FuncType>(c.make());
int x = func(0, 1, 2);
int y = func(1, 1, 2);
printf("x=%d\n", x); // Outputs "x=3".
printf("y=%d\n", y); // Outputs "y=-1".
runtime.release((void*)func);
return 0;
}
```
In this example conditional and uncondition jumps were used with labels together. Labels are created explicitly by the Compiler by passing a Compiler instance to a `Label` constructor or by using a `Label l = c.newLabel()` form. Each label as an unique ID that identifies it, however it's not a string and there is no way to query for a Label instance that already exists. Label is like any other operand moved by value so the copy of the label will still reference the same label and changing a copied will not change the original label.
Each label has to be bound to the location in the code by using `c.bind()`; however, it can be only bound once! Trying to bind the same label multiple times has undefined behavior - it will trigger an assertion failure in the best case.
### Memory Addressing
X86/X64 architectures have several memory addressing modes which can be used to combine base register, index register and a displacement. In addition, index register can be shifted by a constant from 1 to 3 that can help with addressing elements up to 8-byte long in an array. AsmJit supports all forms of memory addressing. Memory operand can be created by using `asmjit::host::Mem` or by using related non-member functions like `asmjit::host::ptr` or `asmjit::host::ptr_abs`. Use `ptr` to create a memory operand having a base register with optional index register and a displacement and `ptr_abs` to create a memory operand refering to an absolute address in memory and optionally having an index register.
In the following example various memory addressing modes are used to demonstrate how to construct and use memory operands. It creates a function that accepts an array and two indexes which specify which elements to sum and return.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// Function returning 'int' accepting pointer and two indexes.
c.addFunc(kFuncConvHost, FuncBuilder3<int, const int*, intptr_t, intptr_t>());
GpVar p(c, kVarTypeIntPtr, "p");
GpVar aIndex(c, kVarTypeIntPtr, "aIndex");
GpVar bIndex(c, kVarTypeIntPtr, "bIndex");
c.setArg(0, p);
c.setArg(1, aIndex);
c.setArg(2, bIndex);
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
// Read 'a' by using a memory operand having base register, index register
// and scale. Translates to 'mov a, dword ptr [p + aIndex << 2]'.
c.mov(a, ptr(p, aIndex, 2));
// Read 'b' by using a memory operand having base register only. Variables
// 'p' and 'bIndex' are both modified.
// Shift bIndex by 2 (exactly the same as multiplying by 4).
// And add scaled 'bIndex' to 'p' resulting in 'p = p + bIndex * 4'.
c.shl(bIndex, 2);
c.add(p, bIndex);
// Read 'b'.
c.mov(b, ptr(p));
// a = a + b;
c.add(a, b);
c.ret(a);
c.endFunc();
// The prototype of the generated function changed also here.
typedef int (*FuncType)(const int*, intptr_t, intptr_t);
FuncType func = asmjit_cast<FuncType>(c.make());
// Array passed to 'func'
const int array[] = { 1, 2, 3, 5, 8, 13 };
int x = func(array, 1, 2);
int y = func(array, 3, 5);
printf("x=%d\n", x); // Outputs "x=5".
printf("y=%d\n", y); // Outputs "y=18".
runtime.release((void*)func);
return 0;
}
```
### 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.
In the following example a stack of 256 bytes size is allocated, filled by bytes starting from 0 to 255 and then iterated again to sum all the values.
```C++
#include <asmjit/asmjit.h>
using namespace asmjit;
using namespace asmjit::host;
int main(int argc, char* argv[]) {
JitRuntime runtime;
Compiler c(&runtime);
// Function returning 'int' without any arguments.
c.addFunc(kFuncConvHost, FuncBuilder0<int>());
// Allocate a function stack of size 256 aligned to 4 bytes.
Mem stack = c.newStack(256, 4);
GpVar p(c, kVarTypeIntPtr, "p");
GpVar i(c, kVarTypeIntPtr, "i");
// 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)
// to a general purpose register.
c.lea(p, stack);
// Clear 'i'. Notice that xor_() is used instead of xor(), because xor is
// unfortunately a keyword in C++.
c.xor_(i, i);
// First loop, fill the stack allocated by a sequence of bytes from 0 to 255.
Label L1(c);
c.bind(L1);
// Mov [p + i], i.
//
// Any operand can be cloned and modified. By cloning 'stack' and calling
// 'setIndex' we created a new memory operand based on stack having an
// index register set.
c.mov(stack.clone().setIndex(i), i.r8());
// if (++i < 256)
// goto L1;
c.inc(i);
c.cmp(i, 256);
c.jb(L1);
// Second loop, sum all bytes stored in 'stack'.
GpVar a(c, kVarTypeInt32, "a");
GpVar t(c, kVarTypeInt32, "t");
c.xor_(i, i);
c.xor_(a, a);
Label L2(c);
c.bind(L2);
// Movzx t, byte ptr [stack + i]
c.movzx(t, stack.clone().setIndex(i).setSize(1));
// a += t;
c.add(a, t);
// if (++i < 256)
// goto L2;
c.inc(i);
c.cmp(i, 256);
c.jb(L2);
c.ret(a);
c.endFunc();
typedef int (*FuncType)(void);
FuncType func = asmjit_cast<FuncType>(c.make());
printf("a=%d\n", func()); // Outputs "a=32640".
runtime.release((void*)func);
return 0;
}
```
### Using Constant Pool
To be documented.
Advanced Features
-----------------
AsmJit offers much more, but not everything can fit into the introduction. The following sections don't have complete examples, but contain hints that can be useful and can change a bit the way AsmJit is used.
### 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.
To be documented.
### 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.
To manipulate the current cursor use Compiler's `getCursor()` and `setCursor()` member functions. The following snippet demonstrates the proper way of code injection.
```C++
Compiler c(...);
GpVar a(c, kVarTypeInt32, "a");
GpVar b(c, kVarTypeInt32, "b");
BaseNode* here = c.getCursor();
c.mov(b, 2);
// 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
// after the injecting is done. When setCursor() is called it returns the old
// cursor.
BaseNode* oldCursor = c.setCursor(here);
c.mov(a, 1);
c.setCursor(oldCursor);
```
The resulting code would look like:
```
c.mov(a, 1);
c.mov(b, 2);
```
License
-------
AsmJit can be distributed under zlib license:
* <http://www.opensource.org/licenses/zlib-license.php>
Contact Authors & Maintainers
-----------------------------
* Petr Kobalicek <kobalicek.petr@gmail.com>

View File

@@ -88,7 +88,7 @@ static void blend(asmjit::host::Compiler& c) {
c.psrlw(a0, 8);
c.punpcklbw(x0, cZero);
c.pshuflw(a0, a0, mm_shuffle(1, 1, 1, 1));
c.pshuflw(a0, a0, X86Util::mmShuffle(1, 1, 1, 1));
c.punpcklbw(y0, cZero);
c.pmullw(x0, a0);
@@ -136,8 +136,8 @@ static void blend(asmjit::host::Compiler& c) {
c.punpckhbw(x1, cZero);
c.punpckhwd(a1, a1);
c.pshufd(a0, a0, mm_shuffle(3, 3, 1, 1));
c.pshufd(a1, a1, mm_shuffle(3, 3, 1, 1));
c.pshufd(a0, a0, X86Util::mmShuffle(3, 3, 1, 1));
c.pshufd(a1, a1, X86Util::mmShuffle(3, 3, 1, 1));
c.pmullw(x0, a0);
c.pmullw(x1, a1);
@@ -166,7 +166,7 @@ static void blend(asmjit::host::Compiler& c) {
c.endFunc();
// Data.
c.align(16);
c.align(kAlignData, 16);
c.bind(L_Data);
c.dxmm(XmmData::fromSw(0x0080));
c.dxmm(XmmData::fromSw(0x0101));

View File

@@ -268,6 +268,87 @@ static void opcode(asmjit::host::Assembler& a) {
a.xor_(intptr_gp0, gp1);
a.xor_(intptr_gp0, 0);
// Label...Jcc/Jecxz/Jmp.
{
a.nop();
Label L(a);
a.bind(L);
a.ja(L);
a.jae(L);
a.jb(L);
a.jbe(L);
a.jc(L);
a.je(L);
a.jg(L);
a.jge(L);
a.jl(L);
a.jle(L);
a.jna(L);
a.jnae(L);
a.jnb(L);
a.jnbe(L);
a.jnc(L);
a.jne(L);
a.jng(L);
a.jnge(L);
a.jnl(L);
a.jnle(L);
a.jno(L);
a.jnp(L);
a.jns(L);
a.jnz(L);
a.jo(L);
a.jp(L);
a.jpe(L);
a.jpo(L);
a.js(L);
a.jz(L);
a.jecxz(ecx, L);
a.jmp(L);
}
// Jcc/Jecxz/Jmp...Label.
{
a.nop();
Label L(a);
a.ja(L);
a.jae(L);
a.jb(L);
a.jbe(L);
a.jc(L);
a.je(L);
a.jg(L);
a.jge(L);
a.jl(L);
a.jle(L);
a.jna(L);
a.jnae(L);
a.jnb(L);
a.jnbe(L);
a.jnc(L);
a.jne(L);
a.jng(L);
a.jnge(L);
a.jnl(L);
a.jnle(L);
a.jno(L);
a.jnp(L);
a.jns(L);
a.jnz(L);
a.jo(L);
a.jp(L);
a.jpe(L);
a.jpo(L);
a.js(L);
a.jz(L);
a.jecxz(ecx, L);
a.jmp(L);
a.bind(L);
}
// Fpu.
a.nop();

View File

@@ -59,7 +59,7 @@ int main(int argc, char* argv[]) {
printf(" asmjit::LabelData : %u\n", static_cast<uint32_t>(sizeof(LabelData)));
printf(" asmjit::RelocData : %u\n", static_cast<uint32_t>(sizeof(RelocData)));
printf("\n");
printf(" asmjit::BaseNode : %u\n", static_cast<uint32_t>(sizeof(BaseNode)));
printf(" asmjit::Node : %u\n", static_cast<uint32_t>(sizeof(Node)));
printf(" asmjit::AlignNode : %u\n", static_cast<uint32_t>(sizeof(AlignNode)));
printf(" asmjit::CallNode : %u\n", static_cast<uint32_t>(sizeof(CallNode)));
printf(" asmjit::CommentNode : %u\n", static_cast<uint32_t>(sizeof(CommentNode)));

View File

@@ -56,19 +56,315 @@
//!
//! @section AsmJit_Main_CodeGeneration Code Generation
//!
//! - @ref asmjit_base "Assembler core" - Operands, intrinsics and low-level assembler.
//! - @ref asmjit_base_general "Assembler core" - Operands, intrinsics and low-level assembler.
//! - @ref asmjit_compiler "Compiler" - High level code generation.
//! - @ref asmjit_cpuinfo "Cpu Information" - Get information about host processor.
//! - @ref asmjit_logging "Logging" - Logging and error handling.
//! - @ref AsmJit_MemoryManagement "Memory Management" - Virtual memory management.
//!
//! @section AsmJit_Main_Configuration Configuration, Definitions and Utilities
//!
//! - @ref asmjit_config "Configuration" - Macros used to configure AsmJit.
//!
//! @section AsmJit_Main_HomePage AsmJit Homepage
//!
//! - http://code.google.com/p/asmjit/
//! - https://github.com/kobalicekp/asmjit
// ============================================================================
// [asmjit_base]
// ============================================================================
//! \defgroup asmjit_base AsmJit
//!
//! \brief AsmJit.
// ============================================================================
// [asmjit_base_general]
// ============================================================================
//! \defgroup asmjit_base_general AsmJit General API
//! \ingroup asmjit_base
//!
//! \brief AsmJit general API.
//!
//! Contains all `asmjit` classes and helper functions that are architecture
//! independent or abstract. Abstract classes are implemented by the backend,
//! for example `BaseAssembler` is implemented by `x86x64::X86X64Assembler`.
//!
//! - See `BaseAssembler` for low level code generation documentation.
//! - See `BaseCompiler` for high level code generation documentation.
//! - See `Operand` for operand's overview.
//!
//! Logging and Error Handling
//! --------------------------
//!
//! AsmJit contains robust interface that can be used to log the generated code
//! and to handle possible errors. Base logging interface is defined in `Logger`
//! class that is abstract and can be overridden. AsmJit contains two loggers
//! that can be used out of the box - `FileLogger` that logs into a pure C
//! `FILE*` stream and `StringLogger` that just concatenates all log messages
//! by using a `StringBuilder` class.
//!
//! The following snippet shows how to setup a logger that logs to `stderr`:
//!
//! ~~~
//! // `FileLogger` instance.
//! FileLogger logger(stderr);
//!
//! // `Compiler` or any other `CodeGen` interface.
//! host::Compiler c;
//!
//! // use `setLogger` to replace the `CodeGen` logger.
//! c.setLogger(&logger);
//! ~~~
//!
//! \sa \ref Logger, \ref FileLogger, \ref StringLogger.
// ============================================================================
// [asmjit_base_tree]
// ============================================================================
//! \defgroup asmjit_base_tree AsmJit Code-Tree
//! \ingroup asmjit_base
//!
//! \brief AsmJit code-tree used by Compiler.
//!
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes
//! that represent assembler instructions, directives, labels and high-level
//! constructs compiler is using to represent functions and function calls. The
//! node list can only be used together with \ref BaseCompiler.
//!
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \defgroup asmjit_base_util AsmJit Utilities
//! \ingroup asmjit_base
//!
//! \brief AsmJit utility classes.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//!
//! POD Containers
//! --------------
//!
//! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref PodVector - Simple growing array-like container for POD data.
//! - \ref StringBuilder - Simple string builder that can append string
//! and integers.
//!
//! Zone Memory Allocator
//! ---------------------
//!
//! Zone memory allocator is an incremental memory allocator that can be used
//! to allocate data of short life-time. It has much better performance
//! characteristics than all other allocators, because the only thing it can do
//! is to increment a pointer and return its previous address. See \ref Zone
//! for more details.
//!
//! CPU Ticks
//! ---------
//!
//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See
//! \ref CpuTicks class for more details.
//!
//! Integer Utilities
//! -----------------
//!
//! Integer utilities are all implemented by a static class \ref IntUtil.
//! There are utilities for bit manipulation and bit counting, utilities to get
//! an integer minimum / maximum and various other helpers required to perform
//! alignment checks and binary casting from float to integer and vica versa.
//!
//! Vector Utilities
//! ----------------
//!
//! SIMD code generation often requires to embed constants after each function
//! or a block of functions generated. AsmJit contains classes `Vec64Data`,
//! `Vec128Data` and `Vec256Data` that can be used to prepare data useful when
//! generating SIMD code.
//!
//! X86/X64 code generator contains member functions `dmm`, `dxmm` and `dymm`
//! which can be used to embed 64-bit, 128-bit and 256-bit data structures into
//! machine code (both assembler and compiler are supported).
//!
//! \note Compiler contains a constant pool, which should be used instead of
//! embedding constants manually after the function body.
// ============================================================================
// [asmjit_x86x64]
// ============================================================================
//! \defgroup asmjit_x86x64 X86/X64
//!
//! \brief X86/X64 module
// ============================================================================
// [asmjit_x86x64_general]
// ============================================================================
//! \defgroup asmjit_x86x64_general X86/X64 General API
//! \ingroup asmjit_x86x64
//!
//! \brief X86/X64 general API.
//!
//! X86/X64 Registers
//! -----------------
//!
//! There are static objects that represents X86 and X64 registers. They can
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
//! these functions:
//!
//! - `asmjit::gpb_lo()` - Get Gpb-lo register.
//! - `asmjit::gpb_hi()` - Get Gpb-hi register.
//! - `asmjit::gpw()` - Get Gpw register.
//! - `asmjit::gpd()` - Get Gpd register.
//! - `asmjit::gpq()` - Get Gpq Gp register.
//! - `asmjit::gpz()` - Get Gpd/Gpq register.
//! - `asmjit::fp()` - Get Fp register.
//! - `asmjit::mm()` - Get Mm register.
//! - `asmjit::xmm()` - Get Xmm register.
//! - `asmjit::ymm()` - Get Ymm register.
//!
//! X86/X64 Addressing
//! ------------------
//!
//! X86 and x64 architectures contains several addressing modes and most ones
//! are possible with AsmJit library. Memory represents are represented by
//! `BaseMem` class. These functions are used to make operands that represents
//! memory addresses:
//!
//! - `asmjit::ptr()`
//! - `asmjit::byte_ptr()`
//! - `asmjit::word_ptr()`
//! - `asmjit::dword_ptr()`
//! - `asmjit::qword_ptr()`
//! - `asmjit::tword_ptr()`
//! - `asmjit::oword_ptr()`
//! - `asmjit::yword_ptr()`
//! - `asmjit::intptr_ptr()`
//!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates
//! pointer to the target with unspecified size. Unspecified size works in all
//! intrinsics where are used registers (this means that size is specified by
//! register operand or by instruction itself). For example `asmjit::ptr()`
//! can't be used with @c asmjit::Assembler::inc() instruction. In this case
//! size must be specified and it's also reason to make difference between
//! pointer sizes.
//!
//! Supported are simple address forms `[base + displacement]` and complex
//! address forms `[base + index * scale + displacement]`.
//!
//! X86/X64 Immediates
//! ------------------
//!
//! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use @c asmjit::imm() or @c asmjit::imm_u()
//! methods to create signed or unsigned immediate value.
//!
//! X86/X64 CPU Information
//! -----------------------
//!
//! The CPUID instruction can be used to get an exhaustive information about
//! 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
//! host operating system, in addition to host processor name and number of
//! cores. Class `CpuInfo` extends `BaseCpuInfo` and provides functionality
//! specific to X86 and X64.
//!
//! By default AsmJit queries the CPU information after the library is loaded
//! 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 code generation of all `Runtime`s. If there is a need to have a
//! specific CPU information which contains modified features or processor
//! vendor it's possible by creating a new instance of `CpuInfo` and setting
//! up its members. `CpuUtil::detect` can be used to detect CPU features into
//! an existing `CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off.
//!
//! If the high-level interface `CpuInfo` offers is not enough there is also
//! `CpuUtil::callCpuId` helper that can be used to call CPUID instruction with
//! a given parameters and to consume the output.
//!
//! 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
//! in the past and today there is often AVX/AVX2 detection.
//!
//! The example below shows how to detect SSE2:
//!
//! ~~~
//! using namespace asmjit;
//! using namespace asmjit::host;
//!
//! // Get `CpuInfo` global instance.
//! const CpuInfo* cpuInfo = CpuInfo::getHost();
//!
//! if (cpuInfo->hasFeature(kCpuFeatureSse2)) {
//! // Processor has SSE2.
//! }
//! else if (cpuInfo->hasFeature(kCpuFeatureMmx)) {
//! // Processor doesn't have SSE2, but has MMX.
//! }
//! else {
//! // Processor is archaic; it's a wonder AsmJit works here!
//! }
//! ~~~
//!
//! The next example shows how to call `CPUID` directly:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // Call cpuid, first two arguments are passed in Eax/Ecx.
//! CpuId out;
//! CpuUtil::callCpuId(0, 0, &out);
//!
//! // If Eax argument is 0, Ebx, Ecx and Edx registers are filled with a cpu vendor.
//! char cpuVendor[13];
//! ::memcpy(cpuVendor, &out.ebx, 4);
//! ::memcpy(cpuVendor + 4, &out.edx, 4);
//! ::memcpy(cpuVendor + 8, &out.ecx, 4);
//! vendor[12] = '\0';
//!
//! // Print a CPU vendor retrieved from CPUID.
//! ::printf("%s", cpuVendor);
//! ~~~
// ============================================================================
// [asmjit_x86x64_tree]
// ============================================================================
//! \defgroup asmjit_x86x64_tree X86/X64 Code-Tree
//! \ingroup asmjit_x86x64
//!
//! \brief X86/X64 code-tree and helpers.
// ============================================================================
// [asmjit_x86x64_inst]
// ============================================================================
//! \defgroup asmjit_x86x64_inst X86/X64 Instructions
//! \ingroup asmjit_x86x64
//!
//! \brief X86/X64 low-level instruction definitions.
// ============================================================================
// [asmjit_x86x64_util]
// ============================================================================
//! \defgroup asmjit_x86x64_util X86/X64 Utilities
//! \ingroup asmjit_x86x64
//!
//! \brief X86/X64 utility classes.
// ============================================================================
// [asmjit_contrib]
// ============================================================================
//! \defgroup asmjit_contrib Contributions
//!
//! \brief Contributions.
// [Dependencies - Base]
#include "base.h"

View File

@@ -8,193 +8,7 @@
#ifndef _ASMJIT_BASE_H
#define _ASMJIT_BASE_H
// ============================================================================
// [asmjit_base]
// ============================================================================
//! @defgroup asmjit_base Base
//!
//! @brief AsmJit Base API.
//!
//! Contains all `asmjit` classes and helper functions that are architecture
//! independent or abstract. Abstract classes are implemented by the backend,
//! for example `BaseAssembler` is implemented by `x86x64::X86X64Assembler`.
//!
//! - See `BaseAssembler` for low level code generation documentation.
//! - See `BaseCompiler` for high level code generation documentation.
//! - See `Operand` for operand's overview.
//!
//! @section AsmJit_Core_Registers Registers
//!
//! There are static objects that represents X86 and X64 registers. They can
//! be used directly (like `eax`, `mm`, `xmm`, ...) or created through
//! these functions:
//!
//! - `asmjit::gpb_lo()` - Get Gpb-lo register.
//! - `asmjit::gpb_hi()` - Get Gpb-hi register.
//! - `asmjit::gpw()` - Get Gpw register.
//! - `asmjit::gpd()` - Get Gpd register.
//! - `asmjit::gpq()` - Get Gpq Gp register.
//! - `asmjit::gpz()` - Get Gpd/Gpq register.
//! - `asmjit::fp()` - Get Fp register.
//! - `asmjit::mm()` - Get Mm register.
//! - `asmjit::xmm()` - Get Xmm register.
//! - `asmjit::ymm()` - Get Ymm register.
//!
//! @section AsmJit_Core_Addressing Addressing
//!
//! X86 and x64 architectures contains several addressing modes and most ones
//! are possible with AsmJit library. Memory represents are represented by
//! `BaseMem` class. These functions are used to make operands that represents
//! memory addresses:
//!
//! - `asmjit::ptr()`
//! - `asmjit::byte_ptr()`
//! - `asmjit::word_ptr()`
//! - `asmjit::dword_ptr()`
//! - `asmjit::qword_ptr()`
//! - `asmjit::tword_ptr()`
//! - `asmjit::oword_ptr()`
//! - `asmjit::yword_ptr()`
//! - `asmjit::intptr_ptr()`
//!
//! Most useful function to make pointer should be `asmjit::ptr()`. It creates
//! pointer to the target with unspecified size. Unspecified size works in all
//! intrinsics where are used registers (this means that size is specified by
//! register operand or by instruction itself). For example `asmjit::ptr()`
//! can't be used with @c asmjit::Assembler::inc() instruction. In this case
//! size must be specified and it's also reason to make difference between
//! pointer sizes.
//!
//! Supported are simple address forms (register + displacement) and complex
//! address forms (register + (register << shift) + displacement).
//!
//! @section AsmJit_Core_Immediates Immediates
//!
//! Immediate values are constants thats passed directly after instruction
//! opcode. To create such value use @c asmjit::imm() or @c asmjit::imm_u()
//! methods to create signed or unsigned immediate value.
//!
//! @sa @c asmjit::BaseCompiler.
// ============================================================================
// [asmjit_base_globals]
// ============================================================================
//! @defgroup asmjit_base_globals Globals
//! @ingroup asmjit_base
//!
//! @brief Global definitions, macros and functions.
// ============================================================================
// [asmjit_base_codegen]
// ============================================================================
//! @defgroup asmjit_base_codegen Code Generation (Base)
//! @ingroup asmjit_base
//!
//! @brief Low-level and high-level code generation.
// ============================================================================
// [asmjit_base_cpu_info]
// ============================================================================
//! @defgroup asmjit_base_cpu_info CPU Information (Base)
//! @ingroup asmjit_base
//!
//! @brief CPU Information Interface, platform neutral.
// ============================================================================
// [asmjit_base_logging_and_errors]
// ============================================================================
//! @defgroup asmjit_base_logging_and_errors Logging and Error Handling
//! @ingroup asmjit_base
//!
//! @brief Logging and error handling.
//!
//! AsmJit contains robust interface that can be used to log the generated code
//! and to handle possible errors. Base logging interface is defined in `Logger`
//! class that is abstract and can be overridden. AsmJit contains two loggers
//! that can be used out-of-the box - `FileLogger` that logs into a `FILE*`
//! and `StringLogger` that just concatenates all log messages without sending
//! them to a stream.
//!
//! The following snippet shows how to setup a logger that logs to `stderr`:
//!
//! ~~~
//! // `FileLogger` instance.
//! FileLogger logger(stderr);
//!
//! // `Compiler` or any other `CodeGen` interface.
//! host::Compiler c;
//!
//! // use `setLogger` to replace the `CodeGen` logger.
//! c.setLogger(&logger);
//! ~~~
//!
//! @sa @ref `Logger`, @ref `FileLogger`, @ref `StringLogger`.
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! @defgroup asmjit_base_util Utilities
//! @ingroup asmjit_base
//!
//! @brief Utilities inside AsmJit made public.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//!
//! POD-Containers
//! --------------
//!
//! TODO: Documentation
//!
//! String Builder
//! --------------
//!
//! TODO: Documentation
//!
//! Integer Utilities
//! -----------------
//!
//! TODO: Documentation
//!
//! Zone Memory Allocator
//! ---------------------
//!
//! TODO: Documentation
//!
//! CPU Ticks
//! ---------
//!
//! TODO: Documentation
// ============================================================================
// [asmjit_base_vectypes]
// ============================================================================
//! @defgroup asmjit_base_vectypes Vector Types
//! @ingroup asmjit_base
//!
//! @brief Vector types can be used to create a data which is stored in the
//! machine code.
// ============================================================================
// [asmjit::]
// ============================================================================
//! @namespace asmjit
//! Main AsmJit library namespace.
//!
//! There are not other namespaces used in AsmJit library.
// ============================================================================
// [Dependencies - AsmJit]
// ============================================================================
#include "build.h"
#include "base/assembler.h"
@@ -203,15 +17,16 @@
#include "base/constpool.h"
#include "base/cpuinfo.h"
#include "base/cputicks.h"
#include "base/defs.h"
#include "base/error.h"
#include "base/func.h"
#include "base/globals.h"
#include "base/intutil.h"
#include "base/lock.h"
#include "base/logger.h"
#include "base/operand.h"
#include "base/podlist.h"
#include "base/podvector.h"
#include "base/runtime.h"
#include "base/string.h"
#include "base/vectypes.h"
#include "base/vmem.h"

View File

@@ -10,9 +10,9 @@
// [Dependencies - AsmJit]
#include "../base/codegen.h"
#include "../base/defs.h"
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/operand.h"
#include "../base/podlist.h"
#include "../base/podvector.h"
#include "../base/runtime.h"
@@ -23,14 +23,59 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kInstCode]
// ============================================================================
//! Instruction codes (stub).
ASMJIT_ENUM(kInstCode) {
//! No instruction.
kInstNone = 0
};
// ============================================================================
// [asmjit::kInstOptions]
// ============================================================================
//! Instruction options (stub).
ASMJIT_ENUM(kInstOptions) {
//! No instruction options.
kInstOptionNone = 0x00,
//! Emit short form of the instruction.
//!
//! X86/X64:
//!
//! Short form is mostly related to jmp and jcc instructions, but can be used
//! by other instructions supporting 8-bit or 32-bit immediates. This option
//! can be dangerous if the short jmp/jcc is required, but not encodable due
//! to large displacement, in such case an error happens and the whole
//! assembler/compiler stream is unusable.
kInstOptionShortForm = 0x01,
//! Emit long form of the instruction.
//!
//! X86/X64:
//!
//! Long form is mosrlt related to jmp and jcc instructions, but like the
//! `kInstOptionShortForm` option it can be used by other instructions
//! supporting both 8-bit and 32-bit immediates.
kInstOptionLongForm = 0x02,
//! Condition is likely to be taken (instruction).
kInstOptionTaken = 0x04,
//! Condition is unlikely to be taken (instruction).
kInstOptionNotTaken = 0x08
};
// ============================================================================
// [asmjit::LabelLink]
// ============================================================================
//! @internal
//! \internal
//!
//! Data structure used to link linked-labels.
struct LabelLink {
@@ -48,7 +93,7 @@ struct LabelLink {
// [asmjit::LabelData]
// ============================================================================
//! @internal
//! \internal
//!
//! Label data.
struct LabelData {
@@ -62,7 +107,7 @@ struct LabelData {
// [asmjit::RelocData]
// ============================================================================
//! @internal
//! \internal
//!
//! Code relocation data (relative vs absolute addresses).
//!
@@ -182,61 +227,61 @@ struct BaseAssembler : public CodeGen {
//! Reserve the internal buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Set byte at position `pos`.
//! Get BYTE at position `pos`.
ASMJIT_INLINE uint8_t getByteAt(size_t pos) const {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint8_t*>(_buffer + pos);
}
//! Set word at position `pos`.
//! Get WORD at position `pos`.
ASMJIT_INLINE uint16_t getWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint16_t*>(_buffer + pos);
}
//! Set dword at position `pos`.
//! Get DWORD at position `pos`.
ASMJIT_INLINE uint32_t getDWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Set qword at position `pos`.
//! Get QWORD at position `pos`.
ASMJIT_INLINE uint64_t getQWordAt(size_t pos) const {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint64_t*>(_buffer + pos);
}
//! Set int32_t at position `pos`.
//! Get int32_t at position `pos`.
ASMJIT_INLINE int32_t getInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const int32_t*>(_buffer + pos);
}
//! Set uint32_t at position `pos`.
//! Get uint32_t at position `pos`.
ASMJIT_INLINE uint32_t getUInt32At(size_t pos) const {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
return *reinterpret_cast<const uint32_t*>(_buffer + pos);
}
//! Set byte at position `pos`.
//! Set BYTE at position `pos`.
ASMJIT_INLINE void setByteAt(size_t pos, uint8_t x) {
ASMJIT_ASSERT(pos + 1 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint8_t*>(_buffer + pos) = x;
}
//! Set word at position `pos`.
//! Set WORD at position `pos`.
ASMJIT_INLINE void setWordAt(size_t pos, uint16_t x) {
ASMJIT_ASSERT(pos + 2 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint16_t*>(_buffer + pos) = x;
}
//! Set dword at position `pos`.
//! Set DWORD at position `pos`.
ASMJIT_INLINE void setDWordAt(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
//! Set qword at position `pos`.
//! Set QWORD at position `pos`.
ASMJIT_INLINE void setQWordAt(size_t pos, uint64_t x) {
ASMJIT_ASSERT(pos + 8 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint64_t*>(_buffer + pos) = x;
@@ -291,14 +336,14 @@ struct BaseAssembler : public CodeGen {
return static_cast<size_t>(label.getId()) < _labels.getLength();
}
//! @internal
//! \internal
//!
//! Get `LabelData` by `label`.
ASMJIT_INLINE LabelData* getLabelData(const Label& label) const {
return getLabelDataById(label.getId());
}
//! @internal
//! \internal
//!
//! Get `LabelData` by `id`.
ASMJIT_INLINE LabelData* getLabelDataById(uint32_t id) const {
@@ -308,17 +353,17 @@ struct BaseAssembler : public CodeGen {
return const_cast<LabelData*>(&_labels[id]);
}
//! @internal
//! \internal
//!
//! Register labels for other code generator, i.e. `Compiler`.
ASMJIT_API Error _registerIndexedLabels(size_t index);
//! @internal
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
//! @internal
//! \internal
//!
//! New LabelLink instance.
ASMJIT_API LabelLink* _newLabelLink();
@@ -335,7 +380,7 @@ struct BaseAssembler : public CodeGen {
//! Bind label to the current offset.
//!
//! @note Label can be bound only once!
//! \note Label can be bound only once!
ASMJIT_INLINE void bind(const Label& label) {
_bind(label);
}
@@ -356,12 +401,14 @@ struct BaseAssembler : public CodeGen {
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
ASMJIT_INLINE Error align(uint32_t m) {
return _align(m);
ASMJIT_INLINE Error align(uint32_t mode, uint32_t offset) {
return _align(mode, offset);
}
//! Align target buffer to `m` bytes (virtual).
virtual Error _align(uint32_t m) = 0;
//! \internal
//!
//! Align target buffer to `m` bytes.
virtual Error _align(uint32_t mode, uint32_t offset) = 0;
// --------------------------------------------------------------------------
// [Reloc]
@@ -369,25 +416,25 @@ struct BaseAssembler : public CodeGen {
//! Simplifed version of `relocCode()` method designed for JIT.
//!
//! @overload
//! \overload
ASMJIT_INLINE size_t relocCode(void* dst) const {
return _relocCode(dst, static_cast<Ptr>((uintptr_t)dst));
}
//! Relocate code to a given address `dst`.
//!
//! @param dst Where the relocated code should me stored. The pointer can be
//! address returned by virtual memory allocator or your own address if you
//! want only to store the code for later reuse (or load, etc...).
//! @param addressBase Base address used for relocation. When using JIT code
//! generation, this will be the same as `dst`, only casted to system
//! integer type. But when generating code for remote process then the value
//! can be different.
//! \param dst Refers the location where the relocated code should be copied.
//! The pointer can be address returned by virtual memory allocator or any
//! custom address.
//!
//! @retval The bytes used. Code-generator can create trampolines which are
//! used when calling other functions inside the JIT code. However, these
//! trampolines can be unused so the relocCode() returns the exact size needed
//! for the function.
//! \param base Base address used for relocation. `JitRuntime` always sets
//! `base` address to be the same as `dst`, but other runtimes do not have
//! to follow this rule.
//!
//! \retval The number bytes used. If the code generator reserved space for
//! possible trampolines, but these weren't generated, the number of bytes
//! used can be actually less than the expected worst case. Virtual memory
//! allocator can in such case return some memory back to the pool.
//!
//! A given buffer will be overwritten, to get number of bytes required use
//! `getCodeSize()`.
@@ -395,7 +442,9 @@ struct BaseAssembler : public CodeGen {
return _relocCode(dst, base);
}
//! Reloc code (virtual).
//! \internal
//!
//! Reloc code.
virtual size_t _relocCode(void* dst, Ptr base) const = 0;
// --------------------------------------------------------------------------
@@ -410,24 +459,24 @@ struct BaseAssembler : public CodeGen {
//! Emit an instruction.
ASMJIT_API Error emit(uint32_t code);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
//! @overload
//! \overload
ASMJIT_INLINE Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) {
return _emit(code, o0, o1, o2, o3);
}
//! Emit an instruction with integer immediate operand.
ASMJIT_API Error emit(uint32_t code, int o0);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int o2);
//! @overload
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3);
//! Emit an instruction (virtual).
@@ -464,7 +513,7 @@ struct BaseAssembler : public CodeGen {
PodVector<RelocData> _relocData;
};
//! @}
//! \}
// ============================================================================
// [Defined-Later]

View File

@@ -26,8 +26,8 @@ CodeGen::CodeGen(Runtime* runtime) :
_errorHandler(NULL),
_arch(kArchNone),
_regSize(0),
_features(static_cast<uint8_t>(IntUtil::mask(kCodeGenOptimizedAlign))),
_error(kErrorOk),
_features(IntUtil::mask(kCodeGenOptimizedAlign)),
_options(0),
_baseZone(16384 - sizeof(Zone::Chunk) - kMemAllocOverhead) {}

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_CODEGEN_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/runtime.h"
@@ -20,16 +19,16 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kCodeGen]
// ============================================================================
//! Features of `CodeGen`.
//! Features of \ref CodeGen.
ASMJIT_ENUM(kCodeGen) {
//! Emit optimized code-alignment sequences.
//! Emit optimized code-alignment sequences (true by default).
//!
//! X86/X64
//! -------
@@ -41,11 +40,9 @@ ASMJIT_ENUM(kCodeGen) {
//! for alignment between 1 to 11 bytes. Also when `x86x64::Compiler` is
//! used, it may add rex prefixes into the code to make some instructions
//! greater so no alignment sequences are needed.
//!
//! Default true.
kCodeGenOptimizedAlign = 0,
//! Emit jump-prediction hints.
//! Emit jump-prediction hints (false by default).
//!
//! X86/X64
//! -------
@@ -57,15 +54,39 @@ ASMJIT_ENUM(kCodeGen) {
//! However this behavior can be overridden by using instruction prefixes.
//! If this option is enabled these hints will be emitted.
//!
//! Default true.
//! This feature is disabled by default, because the only processor that
//! used to take into consideration prediction hints was P4 that is not used
//! anymore.
kCodeGenPredictedJumps = 1
};
// ============================================================================
// [asmjit::kAlignMode]
// ============================================================================
//! Code aligning mode.
ASMJIT_ENUM(kAlignMode) {
kAlignCode = 0,
kAlignData = 1
};
// ============================================================================
// [asmjit::kRelocMode]
// ============================================================================
//! Relocation mode.
ASMJIT_ENUM(kRelocMode) {
kRelocAbsToAbs = 0,
kRelocRelToAbs = 1,
kRelocAbsToRel = 2,
kRelocTrampoline = 3
};
// ============================================================================
// [asmjit::CodeGen]
// ============================================================================
//! Abstract class inherited by `Assembler` and `Compiler`.
//! Abstract class defining basics of \ref Assembler and \ref BaseCompiler.
struct CodeGen {
ASMJIT_NO_COPY(CodeGen)
@@ -137,12 +158,17 @@ struct CodeGen {
// [Options]
// --------------------------------------------------------------------------
//! Get options.
ASMJIT_INLINE uint32_t getOptions() const { return _options; }
//! Set options.
ASMJIT_INLINE void setOptions(uint32_t options) { _options = options; }
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getOptions() const {
return _options;
}
//! Get options and clear them.
//! Set options of the next instruction.
ASMJIT_INLINE void setOptions(uint32_t options) {
_options = options;
}
//! Get options of the next instruction and clear them.
ASMJIT_INLINE uint32_t getOptionsAndClear() {
uint32_t options = _options;
_options = 0;
@@ -153,15 +179,15 @@ struct CodeGen {
// [Purge]
// --------------------------------------------------------------------------
//! Called by `clear()` and `reset()` to clear all data used by the code
//! generator.
//! Called by \ref clear() and \ref reset() to clear all data used by the
//! code generator.
virtual void _purge() = 0;
// --------------------------------------------------------------------------
// [Make]
// --------------------------------------------------------------------------
//! Make is a convenience method to make and relocate the current code and
//! Make is a convenience method to make and relocate the current code and
//! add it to the associated `Runtime`.
//!
//! What is needed is only to cast the returned pointer to your function type
@@ -177,17 +203,18 @@ struct CodeGen {
Runtime* _runtime;
//! Logger.
Logger* _logger;
//! Error handler, called by `setError()`.
//! Error handler, called by \ref setError().
ErrorHandler* _errorHandler;
//! Target architecture.
uint8_t _arch;
//! Get the default register size of the architecture (4 or 8 bytes).
//! Target general-purpose register size (4 or 8 bytes).
uint8_t _regSize;
//! Last error code.
uint8_t _error;
//! Target features.
uint8_t _features;
//! Last error code.
uint8_t _error;
//! Options for the next generated instruction (only 8-bits used).
uint32_t _options;
@@ -195,7 +222,7 @@ struct CodeGen {
Zone _baseZone;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -101,13 +101,13 @@ void BaseCompiler::_purge() {
// [asmjit::BaseCompiler - Node Management]
// ============================================================================
BaseNode* BaseCompiler::setCursor(BaseNode* node) {
BaseNode* old = _cursor;
Node* BaseCompiler::setCursor(Node* node) {
Node* old = _cursor;
_cursor = node;
return old;
}
BaseNode* BaseCompiler::addNode(BaseNode* node) {
Node* BaseCompiler::addNode(Node* node) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
@@ -124,8 +124,8 @@ BaseNode* BaseCompiler::addNode(BaseNode* node) {
}
}
else {
BaseNode* prev = _cursor;
BaseNode* next = _cursor->_next;
Node* prev = _cursor;
Node* next = _cursor->_next;
node->_prev = prev;
node->_next = next;
@@ -141,14 +141,14 @@ BaseNode* BaseCompiler::addNode(BaseNode* node) {
return node;
}
BaseNode* BaseCompiler::addNodeBefore(BaseNode* node, BaseNode* ref) {
Node* BaseCompiler::addNodeBefore(Node* node, Node* ref) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL);
BaseNode* prev = ref->_prev;
BaseNode* next = ref;
Node* prev = ref->_prev;
Node* next = ref;
node->_prev = prev;
node->_next = next;
@@ -162,14 +162,14 @@ BaseNode* BaseCompiler::addNodeBefore(BaseNode* node, BaseNode* ref) {
return node;
}
BaseNode* BaseCompiler::addNodeAfter(BaseNode* node, BaseNode* ref) {
Node* BaseCompiler::addNodeAfter(Node* node, Node* ref) {
ASMJIT_ASSERT(node != NULL);
ASMJIT_ASSERT(node->_prev == NULL);
ASMJIT_ASSERT(node->_next == NULL);
ASMJIT_ASSERT(ref != NULL);
BaseNode* prev = ref;
BaseNode* next = ref->_next;
Node* prev = ref;
Node* next = ref->_next;
node->_prev = prev;
node->_next = next;
@@ -183,7 +183,7 @@ BaseNode* BaseCompiler::addNodeAfter(BaseNode* node, BaseNode* ref) {
return node;
}
static ASMJIT_INLINE void BaseCompiler_nodeRemoved(BaseCompiler* self, BaseNode* node_) {
static ASMJIT_INLINE void BaseCompiler_nodeRemoved(BaseCompiler* self, Node* node_) {
if (node_->isJmpOrJcc()) {
JumpNode* node = static_cast<JumpNode*>(node_);
TargetNode* target = node->getTarget();
@@ -209,9 +209,9 @@ static ASMJIT_INLINE void BaseCompiler_nodeRemoved(BaseCompiler* self, BaseNode*
}
}
BaseNode* BaseCompiler::removeNode(BaseNode* node) {
BaseNode* prev = node->_prev;
BaseNode* next = node->_next;
Node* BaseCompiler::removeNode(Node* node) {
Node* prev = node->_prev;
Node* next = node->_next;
if (_firstNode == node)
_firstNode = next;
@@ -233,14 +233,14 @@ BaseNode* BaseCompiler::removeNode(BaseNode* node) {
return node;
}
void BaseCompiler::removeNodes(BaseNode* first, BaseNode* last) {
void BaseCompiler::removeNodes(Node* first, Node* last) {
if (first == last) {
removeNode(first);
return;
}
BaseNode* prev = first->_prev;
BaseNode* next = last->_next;
Node* prev = first->_prev;
Node* next = last->_next;
if (_firstNode == first)
_firstNode = next;
@@ -252,9 +252,9 @@ void BaseCompiler::removeNodes(BaseNode* first, BaseNode* last) {
else
next->_prev = prev;
BaseNode* node = first;
Node* node = first;
for (;;) {
BaseNode* next = node->getNext();
Node* next = node->getNext();
ASMJIT_ASSERT(next != NULL);
node->_prev = NULL;
@@ -274,8 +274,8 @@ void BaseCompiler::removeNodes(BaseNode* first, BaseNode* last) {
// [asmjit::BaseCompiler - Align]
// ============================================================================
AlignNode* BaseCompiler::newAlign(uint32_t m) {
AlignNode* node = newNode<AlignNode>(m);
AlignNode* BaseCompiler::newAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newNode<AlignNode>(mode, offset);
if (node == NULL)
goto _NoMemory;
return node;
@@ -285,8 +285,8 @@ _NoMemory:
return NULL;
}
AlignNode* BaseCompiler::addAlign(uint32_t m) {
AlignNode* node = newAlign(m);
AlignNode* BaseCompiler::addAlign(uint32_t mode, uint32_t offset) {
AlignNode* node = newAlign(mode, offset);
if (node == NULL)
return NULL;
return static_cast<AlignNode*>(addNode(node));

View File

@@ -12,10 +12,10 @@
#include "../base/assembler.h"
#include "../base/codegen.h"
#include "../base/constpool.h"
#include "../base/defs.h"
#include "../base/error.h"
#include "../base/func.h"
#include "../base/intutil.h"
#include "../base/operand.h"
#include "../base/podlist.h"
#include "../base/podvector.h"
#include "../base/runtime.h"
@@ -26,9 +26,6 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
// ============================================================================
// [Forward Declarations]
// ============================================================================
@@ -40,7 +37,7 @@ struct VarData;
struct BaseVarInst;
struct BaseVarState;
struct BaseNode;
struct Node;
struct EndNode;
struct InstNode;
struct JumpNode;
@@ -49,6 +46,9 @@ struct JumpNode;
// [asmjit::kConstScope]
// ============================================================================
//! \addtogroup asmjit_base_general
//! \{
//! Scope of the constant.
ASMJIT_ENUM(kConstScope) {
//! Local constant, always embedded right after the current function.
@@ -57,10 +57,15 @@ ASMJIT_ENUM(kConstScope) {
kConstScopeGlobal = 1
};
//! \}
// ============================================================================
// [asmjit::kVarAttrFlags]
// ============================================================================
//! \addtogroup asmjit_base_tree
//! \{
//! Variable attribute flags.
ASMJIT_ENUM(kVarAttrFlags) {
//! Variable is accessed through register on input.
@@ -101,6 +106,9 @@ ASMJIT_ENUM(kVarAttrFlags) {
//! Variable should be unused at the end of the instruction/node.
kVarAttrUnuse = 0x00000800,
//! \internal
//!
//! All in-flags.
kVarAttrInAll =
kVarAttrInReg |
kVarAttrInMem |
@@ -108,6 +116,9 @@ ASMJIT_ENUM(kVarAttrFlags) {
kVarAttrInCall |
kVarAttrInArg,
//! \internal
//!
//! All out-flags.
kVarAttrOutAll =
kVarAttrOutReg |
kVarAttrOutMem |
@@ -146,7 +157,7 @@ ASMJIT_ENUM(kVarHint) {
//! State of variable.
//!
//! @note State of variable is used only during make process and it's not
//! \note State of variable is used only during make process and it's not
//! visible to the developer.
ASMJIT_ENUM(kVarState) {
//! Variable is currently not used.
@@ -168,31 +179,31 @@ ASMJIT_ENUM(kVarState) {
// [asmjit::kNodeType]
// ============================================================================
//! Type of node (see `BaseNode)`.
//! Type of node, see \ref Node.
ASMJIT_ENUM(kNodeType) {
//! Invalid node (internal, can't be used).
kNodeTypeNone = 0,
//! Node is an .align directive, see `AlignNode`.
//! Node is an .align directive, see \ref AlignNode.
kNodeTypeAlign,
//! Node is an embedded data, see `EmbedNode`.
//! Node is an embedded data, see \ref EmbedNode.
kNodeTypeEmbed,
//! Node is a comment, see `CommentNode`.
//! Node is a comment, see \ref CommentNode.
kNodeTypeComment,
//! Node is a variable hint (alloc, spill, use, unuse), see `HintNode`.
//! Node is a variable hint (alloc, spill, use, unuse), see \ref HintNode.
kNodeTypeHint,
//! Node is a label, see `TargetNode`.
//! Node is a label, see \ref TargetNode.
kNodeTypeTarget,
//! Node is an instruction, see `InstNode`.
//! Node is an instruction, see \ref InstNode.
kNodeTypeInst,
//! Node is a function declaration, see `FuncNode`.
//! Node is a function declaration, see \ref FuncNode.
kNodeTypeFunc,
//! Node is an end of the function, see `EndNode`.
//! Node is an end of the function, see \ref EndNode.
kNodeTypeEnd,
//! Node is a return, see `RetNode`.
//! Node is a return, see \ref RetNode.
kNodeTypeRet,
//! Node is a function call, see `CallNode`.
//! Node is a function call, see \ref CallNode.
kNodeTypeCall,
//! Node is a function call argument moved on stack, see `SArgNode`.
//! Node is a function call argument moved on stack, see \ref SArgNode.
kNodeTypeSArg
};
@@ -225,10 +236,15 @@ ASMJIT_ENUM(kNodeFlag) {
kNodeFlagIsFp = 0x0040
};
//! \}
// ============================================================================
// [asmjit::MemCell]
// ============================================================================
//! \addtogroup asmjit_base_tree
//! \{
struct MemCell {
ASMJIT_NO_COPY(MemCell)
@@ -507,7 +523,7 @@ struct VarData {
uint8_t _saveOnUnuse : 1;
//! Whether variable was changed (connected with actual `BaseVarState)`.
uint8_t _modified : 1;
//! @internal
//! \internal
uint8_t _reserved0 : 3;
//! Variable natural alignment.
uint8_t _alignment;
@@ -547,7 +563,9 @@ struct VarData {
//! back to zero/null. Initial value is NULL.
VarAttr* _va;
//! @internal
//! \internal
//!
//! Same as `_va` just provided as `uintptr_t`.
uintptr_t _vaUInt;
};
};
@@ -677,11 +695,11 @@ struct VarAttr {
//!
//! Typically `kInvalidReg` if variable is only used on input.
uint8_t _outRegIndex;
//! @internal
//! \internal
uint8_t _reserved;
};
//! @internal
//! \internal
//!
//! Packed data #0.
uint32_t _packed;
@@ -721,36 +739,36 @@ struct BaseVarInst {};
struct BaseVarState {};
// ============================================================================
// [asmjit::BaseNode]
// [asmjit::Node]
// ============================================================================
//! Base node.
//!
//! `Every` node represents an abstract instruction, directive, label, or
//! macro-instruction generated by compiler.
struct BaseNode {
ASMJIT_NO_COPY(BaseNode)
struct Node {
ASMJIT_NO_COPY(Node)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create new `BaseNode`.
//! Create new `Node`.
//!
//! @note Always use compiler to create nodes.
ASMJIT_INLINE BaseNode(BaseCompiler* compiler, uint32_t type); // Defined-Later.
//! \note Always use compiler to create nodes.
ASMJIT_INLINE Node(BaseCompiler* compiler, uint32_t type); // Defined-Later.
//! Destroy `BaseNode`.
ASMJIT_INLINE ~BaseNode() {}
//! Destroy `Node`.
ASMJIT_INLINE ~Node() {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get previous node in the compiler stream.
ASMJIT_INLINE BaseNode* getPrev() const { return _prev; }
ASMJIT_INLINE Node* getPrev() const { return _prev; }
//! Get next node in the compiler stream.
ASMJIT_INLINE BaseNode* getNext() const { return _next; }
ASMJIT_INLINE Node* getNext() const { return _next; }
//! Get comment string.
ASMJIT_INLINE const char* getComment() const { return _comment; }
@@ -827,9 +845,9 @@ struct BaseNode {
// --------------------------------------------------------------------------
//! Previous node.
BaseNode* _prev;
Node* _prev;
//! Next node.
BaseNode* _next;
Node* _next;
//! Node type, see `kNodeType`.
uint8_t _type;
@@ -863,7 +881,7 @@ struct BaseNode {
// ============================================================================
//! Align node.
struct AlignNode : public BaseNode {
struct AlignNode : public Node {
ASMJIT_NO_COPY(AlignNode)
// --------------------------------------------------------------------------
@@ -871,8 +889,11 @@ struct AlignNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `AlignNode` instance.
ASMJIT_INLINE AlignNode(BaseCompiler* compiler, uint32_t size) : BaseNode(compiler, kNodeTypeAlign) {
_size = size;
ASMJIT_INLINE AlignNode(BaseCompiler* compiler, uint32_t mode, uint32_t offset) :
Node(compiler, kNodeTypeAlign) {
_mode = mode;
_offset = offset;
}
//! Destroy the `AlignNode` instance.
@@ -882,17 +903,34 @@ struct AlignNode : public BaseNode {
// [Accessors]
// --------------------------------------------------------------------------
//! Get align size in bytes.
ASMJIT_INLINE uint32_t getSize() const { return _size; }
//! Set align size in bytes to `size`.
ASMJIT_INLINE void setSize(uint32_t size) { _size = size; }
//! Get alignment mode.
ASMJIT_INLINE uint32_t getMode() const {
return _mode;
}
//! Set alignment mode.
ASMJIT_INLINE void setMode(uint32_t mode) {
_mode = mode;
}
//! Get align offset in bytes.
ASMJIT_INLINE uint32_t getOffset() const {
return _offset;
}
//! Set align offset in bytes to `offset`.
ASMJIT_INLINE void setOffset(uint32_t offset) {
_offset = offset;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Size of the alignment.
uint32_t _size;
//! Alignment mode, see \ref kAlignMode.
uint32_t _mode;
//! Alignment offset in bytes.
uint32_t _offset;
};
// ============================================================================
@@ -903,7 +941,7 @@ struct AlignNode : public BaseNode {
//!
//! Embed node is used to embed data into final assembler stream. The data is
//! considered to be RAW; No analysis is performed on RAW data.
struct EmbedNode : public BaseNode {
struct EmbedNode : public Node {
ASMJIT_NO_COPY(EmbedNode)
// --------------------------------------------------------------------------
@@ -917,7 +955,7 @@ struct EmbedNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `EmbedNode` instance.
ASMJIT_INLINE EmbedNode(BaseCompiler* compiler, void* data, uint32_t size) : BaseNode(compiler, kNodeTypeEmbed) {
ASMJIT_INLINE EmbedNode(BaseCompiler* compiler, void* data, uint32_t size) : Node(compiler, kNodeTypeEmbed) {
_size = size;
if (size <= kInlineBufferSize) {
if (data != NULL)
@@ -964,7 +1002,7 @@ struct EmbedNode : public BaseNode {
//! Comments allows to comment your assembler stream for better debugging
//! and visualization. Comments are usually ignored in release builds unless
//! the logger is present.
struct CommentNode : public BaseNode {
struct CommentNode : public Node {
ASMJIT_NO_COPY(CommentNode)
// --------------------------------------------------------------------------
@@ -972,7 +1010,7 @@ struct CommentNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `CommentNode` instance.
ASMJIT_INLINE CommentNode(BaseCompiler* compiler, const char* comment) : BaseNode(compiler, kNodeTypeComment) {
ASMJIT_INLINE CommentNode(BaseCompiler* compiler, const char* comment) : Node(compiler, kNodeTypeComment) {
_comment = comment;
}
@@ -985,7 +1023,7 @@ struct CommentNode : public BaseNode {
// ============================================================================
//! Hint node.
struct HintNode : public BaseNode {
struct HintNode : public Node {
ASMJIT_NO_COPY(HintNode)
// --------------------------------------------------------------------------
@@ -993,7 +1031,7 @@ struct HintNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `HintNode` instance.
ASMJIT_INLINE HintNode(BaseCompiler* compiler, VarData* vd, uint32_t hint, uint32_t value) : BaseNode(compiler, kNodeTypeHint) {
ASMJIT_INLINE HintNode(BaseCompiler* compiler, VarData* vd, uint32_t hint, uint32_t value) : Node(compiler, kNodeTypeHint) {
_vd = vd;
_hint = hint;
_value = value;
@@ -1036,7 +1074,7 @@ struct HintNode : public BaseNode {
// ============================================================================
//! label node.
struct TargetNode : public BaseNode {
struct TargetNode : public Node {
ASMJIT_NO_COPY(TargetNode)
// --------------------------------------------------------------------------
@@ -1044,7 +1082,7 @@ struct TargetNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `TargetNode` instance.
ASMJIT_INLINE TargetNode(BaseCompiler* compiler, uint32_t labelId) : BaseNode(compiler, kNodeTypeTarget) {
ASMJIT_INLINE TargetNode(BaseCompiler* compiler, uint32_t labelId) : Node(compiler, kNodeTypeTarget) {
_id = labelId;
_numRefs = 0;
_from = NULL;
@@ -1100,7 +1138,7 @@ struct TargetNode : public BaseNode {
// ============================================================================
//! Instruction node.
struct InstNode : public BaseNode {
struct InstNode : public Node {
ASMJIT_NO_COPY(InstNode)
// --------------------------------------------------------------------------
@@ -1108,7 +1146,7 @@ struct InstNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `InstNode` instance.
ASMJIT_INLINE InstNode(BaseCompiler* compiler, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) : BaseNode(compiler, kNodeTypeInst) {
ASMJIT_INLINE InstNode(BaseCompiler* compiler, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) : Node(compiler, kNodeTypeInst) {
_code = static_cast<uint16_t>(code);
_options = static_cast<uint8_t>(options);
@@ -1170,7 +1208,7 @@ struct InstNode : public BaseNode {
ASMJIT_INLINE Operand* getOpList() {
return _opList;
}
//! @overload
//! \overload
ASMJIT_INLINE const Operand* getOpList() const {
return _opList;
}
@@ -1203,7 +1241,7 @@ struct InstNode : public BaseNode {
return static_cast<BaseMem*>(&_opList[_memOpIndex]);
}
//! @overload
//! \overload
template<typename T>
ASMJIT_INLINE T* getMemOp() const {
ASMJIT_ASSERT(hasMemOp());
@@ -1236,7 +1274,7 @@ _Update:
uint16_t _code;
//! Instruction options, see `kInstOptions`.
uint8_t _options;
//! @internal
//! \internal
uint8_t _memOpIndex;
//! Operands list.
@@ -1289,7 +1327,7 @@ struct JumpNode : public InstNode {
//! `FuncNode` can be used to generate function prolog and epilog which are
//! compatible with a given function calling convention and to allocate and
//! manage variables that can be allocated/spilled during compilation phase.
struct FuncNode : public BaseNode {
struct FuncNode : public Node {
ASMJIT_NO_COPY(FuncNode)
// --------------------------------------------------------------------------
@@ -1300,7 +1338,7 @@ struct FuncNode : public BaseNode {
//!
//! Always use `BaseCompiler::addFunc()` to create a `FuncNode` instance.
ASMJIT_INLINE FuncNode(BaseCompiler* compiler) :
BaseNode(compiler, kNodeTypeFunc),
Node(compiler, kNodeTypeFunc),
_entryNode(NULL),
_exitNode(NULL),
_decl(NULL),
@@ -1472,7 +1510,7 @@ struct FuncNode : public BaseNode {
//! Expected stack alignment (we depend on this value).
//!
//! @note It can be global alignment given by the OS or described by an
//! \note It can be global alignment given by the OS or described by an
//! target platform ABI.
uint32_t _expectedStackAlignment;
//! Required stack alignment (usually for multimedia instructions).
@@ -1498,7 +1536,7 @@ struct FuncNode : public BaseNode {
// ============================================================================
//! End of function/block node.
struct EndNode : public BaseNode {
struct EndNode : public Node {
ASMJIT_NO_COPY(EndNode)
// --------------------------------------------------------------------------
@@ -1506,7 +1544,7 @@ struct EndNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `EndNode` instance.
ASMJIT_INLINE EndNode(BaseCompiler* compiler) : BaseNode(compiler, kNodeTypeEnd) {
ASMJIT_INLINE EndNode(BaseCompiler* compiler) : Node(compiler, kNodeTypeEnd) {
_flags |= kNodeFlagIsRet;
}
@@ -1519,7 +1557,7 @@ struct EndNode : public BaseNode {
// ============================================================================
//! Function return node.
struct RetNode : public BaseNode {
struct RetNode : public Node {
ASMJIT_NO_COPY(RetNode)
// --------------------------------------------------------------------------
@@ -1527,7 +1565,7 @@ struct RetNode : public BaseNode {
// --------------------------------------------------------------------------
//! Create a new `RetNode` instance.
ASMJIT_INLINE RetNode(BaseCompiler* compiler, const Operand& o0, const Operand& o1) : BaseNode(compiler, kNodeTypeRet) {
ASMJIT_INLINE RetNode(BaseCompiler* compiler, const Operand& o0, const Operand& o1) : Node(compiler, kNodeTypeRet) {
_flags |= kNodeFlagIsRet;
_ret[0] = o0;
_ret[1] = o1;
@@ -1542,12 +1580,12 @@ struct RetNode : public BaseNode {
//! Get the first return operand.
ASMJIT_INLINE Operand& getFirst() { return _ret[0]; }
//! @overload
//! \overload
ASMJIT_INLINE const Operand& getFirst() const { return _ret[0]; }
//! Get the second return operand.
ASMJIT_INLINE Operand& getSecond() { return _ret[1]; }
//! @overload
//! \overload
ASMJIT_INLINE const Operand& getSecond() const { return _ret[1]; }
// --------------------------------------------------------------------------
@@ -1563,7 +1601,7 @@ struct RetNode : public BaseNode {
// ============================================================================
//! Function-call node.
struct CallNode : public BaseNode {
struct CallNode : public Node {
ASMJIT_NO_COPY(CallNode)
// --------------------------------------------------------------------------
@@ -1572,7 +1610,7 @@ struct CallNode : public BaseNode {
//! Create a new `CallNode` instance.
ASMJIT_INLINE CallNode(BaseCompiler* compiler, const Operand& target) :
BaseNode(compiler, kNodeTypeCall),
Node(compiler, kNodeTypeCall),
_decl(NULL),
_target(target),
_args(NULL) {}
@@ -1589,7 +1627,7 @@ struct CallNode : public BaseNode {
//! Get target operand.
ASMJIT_INLINE Operand& getTarget() { return _target; }
//! @overload
//! \overload
ASMJIT_INLINE const Operand& getTarget() const { return _target; }
//! Get return at `i`.
@@ -1597,7 +1635,7 @@ struct CallNode : public BaseNode {
ASMJIT_ASSERT(i < 2);
return _ret[i];
}
//! @overload
//! \overload
ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const {
ASMJIT_ASSERT(i < 2);
return _ret[i];
@@ -1608,7 +1646,7 @@ struct CallNode : public BaseNode {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return _args[i];
}
//! @overload
//! \overload
ASMJIT_INLINE const Operand& getArg(uint32_t i) const {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return _args[i];
@@ -1634,7 +1672,7 @@ struct CallNode : public BaseNode {
// ============================================================================
//! Function-call 'argument on the stack' node.
struct SArgNode : public BaseNode {
struct SArgNode : public Node {
ASMJIT_NO_COPY(SArgNode)
// --------------------------------------------------------------------------
@@ -1643,7 +1681,7 @@ struct SArgNode : public BaseNode {
//! Create a new `SArgNode` instance.
ASMJIT_INLINE SArgNode(BaseCompiler* compiler, CallNode* call, VarData* sVd, VarData* cVd) :
BaseNode(compiler, kNodeTypeSArg),
Node(compiler, kNodeTypeSArg),
_call(call),
_sVd(sVd),
_cVd(cVd),
@@ -1678,10 +1716,15 @@ struct SArgNode : public BaseNode {
uint32_t _args;
};
//! \}
// ============================================================================
// [asmjit::BaseCompiler]
// ============================================================================
//! \addtogroup asmjit_base_general
//! \{
//! Base compiler.
//!
//! @sa BaseAssembler.
@@ -1712,11 +1755,11 @@ struct BaseCompiler : public CodeGen {
//! Clear everything, but keep buffers allocated.
//!
//! @note This method will destroy your code.
//! \note This method will destroy your code.
ASMJIT_API void clear();
//! Clear everything and reset all buffers.
//!
//! @note This method will destroy your code.
//! \note This method will destroy your code.
ASMJIT_API void reset();
//! Called by clear() and reset() to clear all data related to derived
//! class implementation.
@@ -1751,30 +1794,30 @@ struct BaseCompiler : public CodeGen {
}
//! Get first node.
ASMJIT_INLINE BaseNode* getFirstNode() const { return _firstNode; }
ASMJIT_INLINE Node* getFirstNode() const { return _firstNode; }
//! Get last node.
ASMJIT_INLINE BaseNode* getLastNode() const { return _lastNode; }
ASMJIT_INLINE Node* getLastNode() const { return _lastNode; }
//! Get current node.
//!
//! @note If this method returns `NULL` it means that nothing has been emitted
//! \note If this method returns `NULL` it means that nothing has been emitted
//! yet.
ASMJIT_INLINE BaseNode* getCursor() const { return _cursor; }
ASMJIT_INLINE Node* getCursor() const { return _cursor; }
//! Set the current node without returning the previous node (private).
ASMJIT_INLINE void _setCursor(BaseNode* node) { _cursor = node; }
ASMJIT_INLINE void _setCursor(Node* node) { _cursor = node; }
//! Set the current node to `node` and return the previous one.
ASMJIT_API BaseNode* setCursor(BaseNode* node);
ASMJIT_API Node* setCursor(Node* node);
//! Add node `node` after current and set current to `node`.
ASMJIT_API BaseNode* addNode(BaseNode* node);
ASMJIT_API Node* addNode(Node* node);
//! Add node before `ref`.
ASMJIT_API BaseNode* addNodeBefore(BaseNode* node, BaseNode* ref);
ASMJIT_API Node* addNodeBefore(Node* node, Node* ref);
//! Add node after `ref`.
ASMJIT_API BaseNode* addNodeAfter(BaseNode* node, BaseNode* ref);
ASMJIT_API Node* addNodeAfter(Node* node, Node* ref);
//! Remove node `node`.
ASMJIT_API BaseNode* removeNode(BaseNode* node);
ASMJIT_API Node* removeNode(Node* node);
//! Remove multiple nodes.
ASMJIT_API void removeNodes(BaseNode* first, BaseNode* last);
ASMJIT_API void removeNodes(Node* first, Node* last);
// --------------------------------------------------------------------------
// [Func]
@@ -1788,16 +1831,18 @@ struct BaseCompiler : public CodeGen {
// --------------------------------------------------------------------------
//! Create a new `AlignNode`.
ASMJIT_API AlignNode* newAlign(uint32_t m);
ASMJIT_API AlignNode* newAlign(uint32_t mode, uint32_t offset);
//! Add a new `AlignNode`.
ASMJIT_API AlignNode* addAlign(uint32_t m);
ASMJIT_API AlignNode* addAlign(uint32_t mode, uint32_t offset);
//! Align target buffer to `m` bytes.
//!
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
ASMJIT_INLINE AlignNode* align(uint32_t m) { return addAlign(m); }
ASMJIT_INLINE AlignNode* align(uint32_t mode, uint32_t offset) {
return addAlign(mode, offset);
}
// --------------------------------------------------------------------------
// [Target]
@@ -1826,14 +1871,16 @@ struct BaseCompiler : public CodeGen {
// --------------------------------------------------------------------------
//! Get count of created labels.
ASMJIT_INLINE size_t getLabelsCount() const
{ return _targets.getLength(); }
ASMJIT_INLINE size_t getLabelsCount() const {
return _targets.getLength();
}
//! Get whether `label` is created.
ASMJIT_INLINE bool isLabelCreated(const Label& label) const
{ return static_cast<size_t>(label.getId()) < _targets.getLength(); }
ASMJIT_INLINE bool isLabelCreated(const Label& label) const {
return static_cast<size_t>(label.getId()) < _targets.getLength();
}
//! @internal
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
@@ -1847,7 +1894,7 @@ struct BaseCompiler : public CodeGen {
//! Bind label to the current offset.
//!
//! @note Label can be bound only once!
//! \note Label can be bound only once!
ASMJIT_API void bind(const Label& label);
// --------------------------------------------------------------------------
@@ -1860,7 +1907,9 @@ struct BaseCompiler : public CodeGen {
ASMJIT_API EmbedNode* addEmbed(const void* data, uint32_t size);
//! Embed data.
ASMJIT_INLINE EmbedNode* embed(const void* data, uint32_t size) { return addEmbed(data, size); }
ASMJIT_INLINE EmbedNode* embed(const void* data, uint32_t size) {
return addEmbed(data, size);
}
// --------------------------------------------------------------------------
// [Comment]
@@ -1892,14 +1941,14 @@ struct BaseCompiler : public CodeGen {
return static_cast<size_t>(var.getId() & kOperandIdNum) < _vars.getLength();
}
//! @internal
//! \internal
//!
//! Get `VarData` by `var`.
ASMJIT_INLINE VarData* getVd(const BaseVar& var) const {
return getVdById(var.getId());
}
//! @internal
//! \internal
//!
//! Get `VarData` by `id`.
ASMJIT_INLINE VarData* getVdById(uint32_t id) const {
@@ -1909,14 +1958,14 @@ struct BaseCompiler : public CodeGen {
return _vars[id & kOperandIdNum];
}
//! @internal
//! \internal
//!
//! Get an array of 'VarData*'.
ASMJIT_INLINE VarData** _getVdArray() const {
return const_cast<VarData**>(_vars.getData());
}
//! @internal
//! \internal
//!
//! Create a new `VarData`.
ASMJIT_API VarData* _newVd(uint32_t type, uint32_t size, uint32_t c, const char* name);
@@ -1949,14 +1998,14 @@ struct BaseCompiler : public CodeGen {
//! Rename variable `var` to `name`.
//!
//! @note Only new name will appear in the logger.
//! \note Only new name will appear in the logger.
ASMJIT_API void rename(BaseVar& var, const char* name);
// --------------------------------------------------------------------------
// [Stack]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! Create a new memory chunk allocated on the current function's stack.
virtual Error _newStack(BaseMem* mem, uint32_t size, uint32_t alignment, const char* name) = 0;
@@ -1965,7 +2014,7 @@ struct BaseCompiler : public CodeGen {
// [Const]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! Put data to a constant-pool and get a memory reference to it.
virtual Error _newConst(BaseMem* mem, uint32_t scope, const void* data, size_t size) = 0;
@@ -1993,12 +2042,12 @@ struct BaseCompiler : public CodeGen {
const uint8_t* _targetVarMapping;
//! First node.
BaseNode* _firstNode;
Node* _firstNode;
//! Last node.
BaseNode* _lastNode;
Node* _lastNode;
//! Current node.
BaseNode* _cursor;
Node* _cursor;
//! Current function.
FuncNode* _func;
@@ -2025,6 +2074,8 @@ struct BaseCompiler : public CodeGen {
Label _globalConstPoolLabel;
};
//! \}
// ============================================================================
// [Defined-Later]
// ============================================================================
@@ -2033,7 +2084,7 @@ ASMJIT_INLINE Label::Label(BaseCompiler& c) : Operand(NoInit) {
c._newLabel(this);
}
ASMJIT_INLINE BaseNode::BaseNode(BaseCompiler* compiler, uint32_t type) {
ASMJIT_INLINE Node::Node(BaseCompiler* compiler, uint32_t type) {
_prev = NULL;
_next = NULL;
_type = static_cast<uint8_t>(type);
@@ -2046,8 +2097,6 @@ ASMJIT_INLINE BaseNode::BaseNode(BaseCompiler* compiler, uint32_t type) {
_state = NULL;
}
//! @}
} // asmjit namespace
// [Api-End]

View File

@@ -29,7 +29,7 @@ const ConstPoolNode ConstPoolTree::_sentinel = { {
const_cast<ConstPoolNode*>(&ConstPoolTree::_sentinel)
}, 0, 0, 0 };
//! @internal
//! \internal
//!
//! Remove left horizontal links.
static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node) {
@@ -43,7 +43,7 @@ static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_skewNode(ConstPoolNode* node)
return node;
}
//! @internal
//! \internal
//!
//! Remove consecutive horizontal links.
static ASMJIT_INLINE ConstPoolNode* ConstPoolTree_splitNode(ConstPoolNode* node) {

View File

@@ -17,14 +17,14 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::ConstPoolNode]
// ============================================================================
//! @internal
//! \internal
//!
//! Zone-allocated constant-pool node.
struct ConstPoolNode {
@@ -54,7 +54,7 @@ struct ConstPoolNode {
// [asmjit::ConstPoolTree]
// ============================================================================
//! @internal
//! \internal
//!
//! Zone-allocated constant-pool tree.
struct ConstPoolTree {
@@ -184,7 +184,7 @@ struct ConstPoolTree {
// [asmjit::ConstPoolGap]
// ============================================================================
//! @internal
//! \internal
//!
//! Zone-allocated constant-pool gap.
struct ConstPoolGap {
@@ -291,7 +291,7 @@ struct ConstPool {
size_t _alignment;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -265,14 +265,14 @@ Error BaseContext::resolveCellOffsets() {
// ============================================================================
Error BaseContext::removeUnreachableCode() {
PodList<BaseNode*>::Link* link = _unreachableList.getFirst();
BaseNode* stop = getStop();
PodList<Node*>::Link* link = _unreachableList.getFirst();
Node* stop = getStop();
while (link != NULL) {
BaseNode* node = link->getValue();
Node* node = link->getValue();
if (node != NULL && node->getPrev() != NULL) {
// Locate all unreachable nodes.
BaseNode* first = node;
Node* first = node;
do {
if (node->isFetched())
break;
@@ -281,7 +281,7 @@ Error BaseContext::removeUnreachableCode() {
// Remove.
if (node != first) {
BaseNode* last = (node != NULL) ? node->getPrev() : getCompiler()->getLastNode();
Node* last = (node != NULL) ? node->getPrev() : getCompiler()->getLastNode();
getCompiler()->removeNodes(first, last);
}
}
@@ -296,7 +296,7 @@ Error BaseContext::removeUnreachableCode() {
// [asmjit::BaseContext - Cleanup]
// ============================================================================
//! @internal
//! \internal
//!
//! Translate the given function `func`.
void BaseContext::cleanup() {
@@ -318,8 +318,8 @@ void BaseContext::cleanup() {
// ============================================================================
Error BaseContext::compile(FuncNode* func) {
BaseNode* end = func->getEnd();
BaseNode* stop = end->getNext();
Node* end = func->getEnd();
Node* stop = end->getNext();
_func = func;
_stop = stop;

View File

@@ -17,14 +17,14 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
//! \addtogroup asmjit_base_tree
//! \{
// ============================================================================
// [asmjit::BaseContext]
// ============================================================================
//! @internal
//! \internal
//!
//! Code generation context is the logic behind `BaseCompiler`. The context is
//! used to compile the code stored in `BaseCompiler`.
@@ -55,17 +55,17 @@ struct BaseContext {
//! Get function.
ASMJIT_INLINE FuncNode* getFunc() const { return _func; }
//! Get stop node.
ASMJIT_INLINE BaseNode* getStop() const { return _stop; }
ASMJIT_INLINE Node* getStop() const { return _stop; }
//! Get start of the current scope.
ASMJIT_INLINE BaseNode* getStart() const { return _start; }
ASMJIT_INLINE Node* getStart() const { return _start; }
//! Get end of the current scope.
ASMJIT_INLINE BaseNode* getEnd() const { return _end; }
ASMJIT_INLINE Node* getEnd() const { return _end; }
//! Get extra block.
ASMJIT_INLINE BaseNode* getExtraBlock() const { return _extraBlock; }
ASMJIT_INLINE Node* getExtraBlock() const { return _extraBlock; }
//! Set extra block.
ASMJIT_INLINE void setExtraBlock(BaseNode* node) { _extraBlock = node; }
ASMJIT_INLINE void setExtraBlock(Node* node) { _extraBlock = node; }
// --------------------------------------------------------------------------
// [Error]
@@ -207,7 +207,7 @@ struct BaseContext {
// [Serialize]
// --------------------------------------------------------------------------
virtual Error serialize(BaseAssembler* assembler, BaseNode* start, BaseNode* stop) = 0;
virtual Error serialize(BaseAssembler* assembler, Node* start, Node* stop) = 0;
// --------------------------------------------------------------------------
// [Members]
@@ -222,19 +222,19 @@ struct BaseContext {
Zone _baseZone;
//! Start of the current active scope.
BaseNode* _start;
Node* _start;
//! End of the current active scope.
BaseNode* _end;
Node* _end;
//! Node that is used to insert extra code after the function body.
BaseNode* _extraBlock;
Node* _extraBlock;
//! Stop node.
BaseNode* _stop;
Node* _stop;
//! Unreachable nodes.
PodList<BaseNode*> _unreachableList;
PodList<Node*> _unreachableList;
//! Jump nodes.
PodList<BaseNode*> _jccList;
PodList<Node*> _jccList;
//! All variables used by the current function.
PodVector<VarData*> _contextVd;
@@ -277,7 +277,7 @@ struct BaseContext {
BaseVarState* _state;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -16,11 +16,6 @@
// ?
#endif // ASMJIT_HOST || ASMJIT_HOST_X64
// [Dependencies - Windows]
#if defined(ASMJIT_OS_WINDOWS)
# include <windows.h>
#endif // ASMJIT_OS_WINDOWS
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <errno.h>

View File

@@ -16,31 +16,30 @@
namespace asmjit {
//! @addtogroup asmjit_base_cpu_info
//! @{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kCpuVendor]
// ============================================================================
//! Cpu vendor IDs.
//! Cpu vendor ID.
//!
//! Cpu vendor IDs are specific for AsmJit library. Vendor ID is not directly
//! read from cpuid result, instead it's based on CPU vendor string.
//! Vendor IDs are specific to AsmJit library. During the library initialization
//! AsmJit checks host CPU and tries to identify the vendor based on the CPUID
//! calls. Some manufacturers changed their vendor strings and AsmJit is aware
//! of that - it checks multiple combinations and decides which vendor ID should
//! be used.
ASMJIT_ENUM(kCpuVendor) {
//! Unknown CPU vendor.
kCpuVendorUnknown = 0,
//! No/Unknown vendor.
kCpuVendorNone = 0,
//! Intel CPU vendor.
//! Intel vendor.
kCpuVendorIntel = 1,
//! AMD CPU vendor.
//! AMD vendor.
kCpuVendorAmd = 2,
//! National Semiconductor CPU vendor (applies also to Cyrix processors).
kCpuVendorNSM = 3,
//! Transmeta CPU vendor.
kCpuVendorTransmeta = 4,
//! VIA CPU vendor.
kCpuVendorVia = 5
//! VIA vendor.
kCpuVendorVia = 3
};
// ============================================================================
@@ -51,7 +50,7 @@ ASMJIT_ENUM(kCpuVendor) {
struct BaseCpuInfo {
ASMJIT_NO_COPY(BaseCpuInfo)
//! @internal
//! \internal
enum {
kFeaturesPerUInt32 = static_cast<int>(sizeof(uint32_t)) * 8
};
@@ -135,7 +134,7 @@ struct BaseCpuInfo {
uint32_t _features[4];
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -16,8 +16,8 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::CpuTicks]
@@ -29,7 +29,7 @@ struct CpuTicks {
static ASMJIT_API uint32_t now();
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -49,16 +49,10 @@ static const char* errorMessages[] = {
"Unknown instruction",
"Illegal instruction",
"Illegal addressing",
"Illegal short jump",
"Illegal displacement",
"No function defined",
"Incomplete function",
"Invalid function",
"Overlapped arguments",
"No registers",
"Overlapped registers",
"Incompatible argument",
"Incompatible return",
"Unknown error"
};

View File

@@ -11,10 +11,13 @@
// [Api-Begin]
#include "../apibegin.h"
// [Dependencies - AsmJit]
#include "../base/globals.h"
namespace asmjit {
//! @addtogroup asmjit_base_logging_and_errors
//! @{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kError]
@@ -29,73 +32,69 @@ ASMJIT_ENUM(kError) {
//! Heap memory allocation failed.
kErrorNoHeapMemory = 1,
//! Virtual memory allocation failed.
kErrorNoVirtualMemory = 2,
//! Invalid argument.
kErrorInvalidArgument = 3,
//! Invalid state.
kErrorInvalidState = 4,
//! Unknown instruction. This happens only if instruction code is
//! out of bounds. Shouldn't happen.
kErrorAssemblerUnknownInst = 5,
//! Illegal instruction, usually generated by asmjit::Assembler
//! class when emitting instruction opcode. If this error is generated the
//! target buffer is not affected by this invalid instruction.
kErrorUnknownInst = 5,
//! Illegal instruction (Assembler).
//!
//! You can also get this status code if you are under x64 (64-bit x86) and
//! you tried to decode instruction using AH, BH, CH or DH register with REX
//! prefix. These registers can't be accessed if REX prefix is used and AsmJit
//! didn't check for this situation in intrinsics (`BaseCompiler` takes care of
//! this and rearrange registers if needed).
//! This status code can also be returned in X64 mode if AH, BH, CH or DH
//! registers have been used together with a REX prefix. The instruction
//! is not encodable in such case.
//!
//! Example of raising `kErrorAssemblerIllegalInst` error.
//! Example of raising `kErrorIllegalInst` error.
//!
//! ~~~
//! // Invalid address size.
//! a.mov(dword_ptr(eax), al);
//!
//! // Undecodable instruction - AH used with r10 that can be encoded by using
//! // REX prefix only.
//! // Undecodable instruction - AH used with R10, however R10 can only be
//! // encoded by using REX prefix, which conflicts with AH.
//! a.mov(byte_ptr(r10), ah);
//! ~~~
//!
//! @note In debug mode you get assertion failure instead of setting error
//! code.
kErrorAssemblerIllegalInst = 6,
//! Illegal addressing used (unencodable).
kErrorAssemblerIllegalAddr = 7,
//! Short jump instruction used, but displacement is out of bounds.
kErrorAssemblerIllegalShortJump = 8,
//! \note In debug mode assertion is raised instead of returning an error.
kErrorIllegalInst = 6,
//! No function defined.
kErrorCompilerNoFunc = 9,
//! Function generation is not finished by using `BaseCompiler::endFunc()`
//! or something bad happened during generation related to function. This can
//! be missing compiler node, etc...
kErrorCompilerIncompleteFunc = 10,
//! Tried to generate a function with overlapped arguments.
kErrorCompilerOverlappedArgs = 11,
//! Illegal (unencodable) addressing used (Assembler).
kErrorIllegalAddresing = 7,
//! Compiler can't allocate registers.
kErrorCompilerNoRegs = 12,
//! Compiler can't allocate registers, because they overlap.
kErrorCompilerOverlappedRegs = 13,
//! Illegal (unencodable) displacement used (Assembler).
//!
//! X86/X64
//! -------
//!
//! Short form of jump instruction has been used, but the displacement is out
//! of bounds.
kErrorIllegalDisplacement = 8,
//! Tried to call function with an incompatible argument.
kErrorCompilerIncompatibleArg = 14,
//! Incompatible return value.
kErrorCompilerIncompatibleRet = 15,
//! Invalid function (Compiler).
//!
//! Returned if no function is defined, but `make()` has been called.
kErrorInvalidFunction = 9,
//! A variable has been assigned more than once to a function argument (Compiler).
kErrorOverlappedArgs = 10,
//! Count of AsmJit status codes. Can grow in future.
kErrorCount = 16
kErrorCount = 11
};
// ============================================================================
// [asmjit::Error]
// ============================================================================
//! AsmJit error type (unsigned integer).
typedef uint32_t Error;
// ============================================================================
@@ -126,7 +125,7 @@ struct ErrorHandler {
//! Reference this error handler.
//!
//! @note This member function is provided for convenience. The default
//! \note This member function is provided for convenience. The default
//! implementation does nothing. If you are working in environment where
//! multiple `ErrorHandler` instances are used by a different code generators
//! you may provide your own functionality for reference counting. In that
@@ -135,7 +134,7 @@ struct ErrorHandler {
//! Release this error handler.
//!
//! @note This member function is provided for convenience. See `addRef()`
//! \note This member function is provided for convenience. See `addRef()`
//! for more detailed information related to reference counting.
ASMJIT_API virtual void release();
@@ -183,11 +182,13 @@ struct ErrorUtil {
static ASMJIT_API const char* asString(Error code);
};
//! \}
// ============================================================================
// [ASMJIT_PROPAGATE_ERROR]
// ============================================================================
//! @internal
//! \internal
//!
//! Used by AsmJit to return the `_Exp_` result if it's an error.
#define ASMJIT_PROPAGATE_ERROR(_Exp_) \
@@ -197,8 +198,6 @@ struct ErrorUtil {
return errval_; \
} while (0)
//! @}
} // asmjit namespace
// [Api-End]

View File

@@ -9,23 +9,15 @@
#define _ASMJIT_BASE_FUNC_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/globals.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
// ============================================================================
// [Forward Declarations]
// ============================================================================
template<typename T>
struct FnTypeId;
//! \addtogroup asmjit_base_tree
//! \{
// ============================================================================
// [asmjit::kFuncConv]
@@ -141,24 +133,15 @@ ASMJIT_ENUM(kFuncFlags) {
ASMJIT_ENUM(kFuncDir) {
//! Arguments are passed left to right.
//!
//! This arguments direction is unusual to C programming, it's used by pascal
//! compilers and in some calling conventions by Borland compiler).
//! This arguments direction is unusual in C, however it's used in Pascal.
kFuncDirLtr = 0,
//! Arguments are passed right ro left
//!
//! This is default argument direction in C programming.
//! This is the default argument direction in C.
kFuncDirRtl = 1
};
// ============================================================================
// [asmjit::kFuncStackInvalid]
// ============================================================================
enum {
//! Invalid stack offset in function or function parameter.
kFuncStackInvalid = -1
};
// ============================================================================
// [asmjit::kFuncArg]
// ============================================================================
@@ -196,23 +179,17 @@ ASMJIT_ENUM(kFuncRet) {
};
// ============================================================================
// [asmjit::FnTypeId]
// [asmjit::kFuncStackInvalid]
// ============================================================================
//! @internal
#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_ }; }
enum kFuncMisc {
//! Invalid stack offset in function or function parameter.
kFuncStackInvalid = -1
};
//! @internal
//!
//! Declare C/C++ type-id mapped to `kVarType`.
#define ASMJIT_DECLARE_TYPE_ID(_T_, _Id_) \
template<> \
struct TypeId<_T_> { enum { kId = _Id_ }; }
// ============================================================================
// [asmjit::FnTypeId]
// ============================================================================
//! Function builder 'void' type.
struct FnVoid {};
@@ -248,6 +225,20 @@ struct FnFloat {};
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);
@@ -398,7 +389,7 @@ struct FuncDecl {
//!
//! Direction should be always `kFuncDirRtl`.
//!
//! @note This is related to used calling convention, it's not affected by
//! \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; }
@@ -471,12 +462,12 @@ struct FuncDecl {
//! Size of "Red Zone".
//!
//! @note Used by AMD64-ABI (128 bytes).
//! \note Used by AMD64-ABI (128 bytes).
uint16_t _redZoneSize;
//! Size of "Spill Zone".
//!
//! @note Used by WIN64-ABI (32 bytes).
//! \note Used by WIN64-ABI (32 bytes).
uint16_t _spillZoneSize;
//! Function arguments (including HI arguments) mapped to physical
@@ -542,6 +533,7 @@ struct FuncBuilderX : public FuncPrototype {
uint32_t _builderArgList[kFuncArgCount];
};
//! \internal
#define _TID(_T_) TypeId<_T_>::kId
//! Function builder (no args).
@@ -644,7 +636,7 @@ struct FuncBuilder10 : public FuncPrototype {
#undef _TID
//! @}
//! \}
} // asmjit namespace

View File

@@ -16,15 +16,21 @@
namespace asmjit {
//! @addtogroup asmjit_base_globals
//! @{
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kGlobals]
// ============================================================================
//! Invalid index
//!
//! Invalid index is the last possible index that is never used in practice. In
//! AsmJit it is used exclusively with strings to indicate the the length of the
//! string is not known and has to be determined.
static const size_t kInvalidIndex = ~static_cast<size_t>(0);
//! Global constants.
ASMJIT_ENUM(kGlobals) {
//! Invalid value or operand id.
kInvalidValue = 0xFFFFFFFF,
@@ -32,26 +38,20 @@ ASMJIT_ENUM(kGlobals) {
//! Invalid register index.
kInvalidReg = 0xFF,
//! Minimum reserved bytes in `Buffer`.
kBufferGrow = 32U,
//! Minimum size of assembler/compiler code buffer.
kMemAllocMinimum = 4096,
//! Host memory allocator overhead.
//!
//! The overhead is decremented from all zone allocators so the operating
//! system doesn't have allocate extra virtual page to keep tract of the
//! requested memory block.
//!
//! The number is actually a guess.
kMemAllocOverhead = sizeof(intptr_t) * 4,
//! Memory grow threshold.
//!
//! After the grow threshold is reached the capacity won't be doubled
//! anymore.
kMemAllocGrowMax = 8192 * 1024,
//! Host memory allocator overhead.
//!
//! We decrement the overhead from our pools so the host operating system
//! doesn't need allocate an extra virtual page to put the data it needs
//! to manage the requested memory block (for example if a single virtual
//! page is 4096 and we require the same memory size we decrease our
//! requirement by kMemAllocOverhead).
kMemAllocOverhead = sizeof(intptr_t) * 4,
kMemAllocGrowMax = 8192 * 1024
};
// ============================================================================
@@ -87,7 +87,21 @@ ASMJIT_ENUM(kArch) {
kArchHost64Bit = sizeof(intptr_t) >= 8
};
//! @}
// ============================================================================
// [asmjit::Ptr / SignedPtr]
// ============================================================================
//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
//!
//! This is the preferred pointer type to use with AsmJit library. It has a
//! capability to hold any pointer for any architecture making it an ideal
//! candidate for cross-platform code generation.
typedef uint64_t Ptr;
//! 64-bit signed pointer, like \ref Ptr, but made signed.
typedef int64_t SignedPtr;
//! \}
// ============================================================================
// [asmjit::Init / NoInit]
@@ -105,17 +119,18 @@ static const _NoInit NoInit = {};
// [asmjit::Assert]
// ============================================================================
//! @addtogroup asmjit_base_logging_and_errors
//! @{
//! \addtogroup asmjit_base_general
//! \{
//! Called in debug build on assertion failure.
//!
//! @param exp Expression that failed.
//! @param file Source file name where it happened.
//! @param line Line in the source file.
//! \param exp Expression that failed.
//! \param file Source file name where it happened.
//! \param line Line in the source file.
//!
//! If you have problems with assertions put a breakpoint at assertionFailed()
//! function (asmjit/base/assert.cpp) to see what happened.
//! function (asmjit/base/globals.cpp) and check the call stack to locate the
//! failing code.
ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
#if defined(ASMJIT_DEBUG)
@@ -127,7 +142,7 @@ ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
#define ASMJIT_ASSERT(_Exp_) ASMJIT_NOP()
#endif // DEBUG
//! @}
//! \}
} // asmjit namespace
@@ -135,8 +150,8 @@ ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
// [asmjit_cast<>]
// ============================================================================
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
//! Cast used to cast pointer to function. It's like reinterpret_cast<>,
//! but uses internally C style cast to work with MinGW.
@@ -148,7 +163,7 @@ ASMJIT_API void assertionFailed(const char* exp, const char* file, int line);
template<typename T, typename Z>
static ASMJIT_INLINE T asmjit_cast(Z* p) { return (T)p; }
//! @}
//! \}
// [Api-End]
#include "../apiend.h"

View File

@@ -20,14 +20,14 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::IntTraits]
// ============================================================================
//! @internal
//! \internal
template<typename T>
struct IntTraits {
enum {
@@ -53,13 +53,13 @@ struct IntUtil {
// [Float <-> Int]
// --------------------------------------------------------------------------
//! @internal
//! \internal
union Float {
int32_t i;
float f;
};
//! @internal
//! \internal
union Double {
int64_t i;
double d;
@@ -144,7 +144,7 @@ struct IntUtil {
// [AsmJit - IsInt/IsUInt]
// --------------------------------------------------------------------------
//! Get whether the given integer `x` can be casted to a signed 8-bit integer.
//! Get whether the given integer `x` can be casted to 8-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt8(T x) {
if (IntTraits<T>::kIsSigned)
@@ -153,7 +153,7 @@ struct IntUtil {
return x <= T(127);
}
//! Get whether the given integer `x` can be casted to an unsigned 8-bit integer.
//! Get whether the given integer `x` can be casted to 8-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt8(T x) {
if (IntTraits<T>::kIsSigned)
@@ -162,7 +162,7 @@ struct IntUtil {
return sizeof(T) <= sizeof(uint8_t) ? true : x <= T(255);
}
//! Get whether the given integer `x` can be casted to a signed 16-bit integer.
//! Get whether the given integer `x` can be casted to 16-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt16(T x) {
if (IntTraits<T>::kIsSigned)
@@ -171,7 +171,7 @@ struct IntUtil {
return x >= T(0) && (sizeof(T) <= sizeof(int16_t) ? true : x <= T(32767));
}
//! Get whether the given integer `x` can be casted to an unsigned 16-bit integer.
//! Get whether the given integer `x` can be casted to 16-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt16(T x) {
if (IntTraits<T>::kIsSigned)
@@ -180,7 +180,7 @@ struct IntUtil {
return sizeof(T) <= sizeof(uint16_t) ? true : x <= T(65535);
}
//! Get whether the given integer `x` can be casted to a signed 32-bit integer.
//! Get whether the given integer `x` can be casted to 32-bit signed integer.
template<typename T>
static ASMJIT_INLINE bool isInt32(T x) {
if (IntTraits<T>::kIsSigned)
@@ -189,7 +189,7 @@ struct IntUtil {
return x >= T(0) && (sizeof(T) <= sizeof(int32_t) ? true : x <= T(2147483647));
}
//! Get whether the given integer `x` can be casted to an unsigned 32-bit integer.
//! Get whether the given integer `x` can be casted to 32-bit unsigned integer.
template<typename T>
static ASMJIT_INLINE bool isUInt32(T x) {
if (IntTraits<T>::kIsSigned)
@@ -315,7 +315,7 @@ struct IntUtil {
// [AsmJit - FindFirstBit]
// --------------------------------------------------------------------------
//! @internal
//! \internal
static ASMJIT_INLINE uint32_t findFirstBitSlow(uint32_t mask) {
// This is a reference (slow) implementation of findFirstBit(), used when
// we don't have compiler support for this task. The implementation speed
@@ -716,7 +716,7 @@ union UInt64 {
};
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -11,11 +11,6 @@
// [Dependencies - AsmJit]
#include "../build.h"
// [Dependencies - Windows]
#if defined(ASMJIT_OS_WINDOWS)
# include <windows.h>
#endif // ASMJIT_OS_WINDOWS
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <pthread.h>
@@ -26,8 +21,8 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Lock]
@@ -80,7 +75,7 @@ struct Lock {
//! Get handle.
ASMJIT_INLINE Handle& getHandle() { return _handle; }
//! @overload
//! \overload
ASMJIT_INLINE const Handle& getHandle() const { return _handle; }
// --------------------------------------------------------------------------
@@ -95,7 +90,7 @@ struct Lock {
// [asmjit::AutoLock]
// ============================================================================
//! Scope auto locker.
//! Scoped lock.
struct AutoLock {
ASMJIT_NO_COPY(AutoLock)
@@ -121,7 +116,7 @@ struct AutoLock {
Lock& _target;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_LOGGER_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/string.h"
// [Dependencies - C]
@@ -20,8 +19,8 @@
namespace asmjit {
//! @addtogroup asmjit_base_logging_and_errors
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kLoggerOption]
@@ -156,13 +155,11 @@ struct FileLogger : public Logger {
//! Get `FILE*` stream.
//!
//! @note Return value can be `NULL`.
//! \note Return value can be `NULL`.
ASMJIT_INLINE FILE* getStream() const { return _stream; }
//! Set `FILE*` stream.
//!
//! @param stream `FILE` stream where to log output, can be set to `NULL` to
//! disable logging.
//! Set `FILE*` stream, can be set to `NULL` to disable logging, although
//! the `CodeGen` will still call `logString` even if there is no stream.
ASMJIT_API void setStream(FILE* stream);
// --------------------------------------------------------------------------
@@ -224,7 +221,7 @@ struct StringLogger : public Logger {
StringBuilder _stringBuilder;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -8,7 +8,7 @@
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../apibegin.h"

View File

@@ -5,8 +5,8 @@
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_DEFS_H
#define _ASMJIT_BASE_DEFS_H
#ifndef _ASMJIT_BASE_OPERAND_H
#define _ASMJIT_BASE_OPERAND_H
// [Dependencies - AsmJit]
#include "../base/intutil.h"
@@ -16,9 +16,6 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
// ============================================================================
// [Forward Declarations]
// ============================================================================
@@ -26,6 +23,9 @@ namespace asmjit {
struct BaseAssembler;
struct BaseCompiler;
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::kOperandType]
// ============================================================================
@@ -71,51 +71,6 @@ ASMJIT_ENUM(kRegClass) {
kRegClassInvalid = 0xFF
};
// ============================================================================
// [asmjit::kInstCode]
// ============================================================================
//! Instruction codes (stub).
ASMJIT_ENUM(kInstCode) {
//! No instruction.
kInstNone = 0
};
// ============================================================================
// [asmjit::kInstOptions]
// ============================================================================
//! Instruction options (stub).
ASMJIT_ENUM(kInstOptions) {
//! No instruction options.
kInstOptionNone = 0x00,
//! Emit short form of the instruction.
//!
//! X86/X64:
//!
//! Short form is mostly related to jmp and jcc instructions, but can be used
//! by other instructions supporting 8-bit or 32-bit immediates. This option
//! can be dangerous if the short jmp/jcc is required, but not encodable due
//! to large displacement, in such case an error happens and the whole
//! assembler/compiler stream is unusable.
kInstOptionShortForm = 0x01,
//! Emit long form of the instruction.
//!
//! X86/X64:
//!
//! Long form is mosrlt related to jmp and jcc instructions, but like the
//! `kInstOptionShortForm` option it can be used by other instructions
//! supporting both 8-bit and 32-bit immediates.
kInstOptionLongForm = 0x02,
//! Condition is likely to be taken (instruction).
kInstOptionTaken = 0x04,
//! Condition is unlikely to be taken (instruction).
kInstOptionNotTaken = 0x08
};
// ============================================================================
// [asmjit::kSize]
// ============================================================================
@@ -174,21 +129,21 @@ ASMJIT_ENUM(kMemType) {
// ============================================================================
ASMJIT_ENUM(kVarType) {
//! Variable is signed 8-bit integer.
//! Variable is 8-bit signed integer.
kVarTypeInt8 = 0,
//! Variable is unsigned 8-bit integer.
//! Variable is 8-bit unsigned integer.
kVarTypeUInt8 = 1,
//! Variable is signed 16-bit integer.
//! Variable is 16-bit signed integer.
kVarTypeInt16 = 2,
//! Variable is unsigned 16-bit integer.
//! Variable is 16-bit unsigned integer.
kVarTypeUInt16 = 3,
//! Variable is signed 32-bit integer.
//! Variable is 32-bit signed integer.
kVarTypeInt32 = 4,
//! Variable is unsigned 32-bit integer.
//! Variable is 32-bit unsigned integer.
kVarTypeUInt32 = 5,
//! Variable is signed 64-bit integer.
//! Variable is 64-bit signed integer.
kVarTypeInt64 = 6,
//! Variable is unsigned 64-bit integer.
//! Variable is 64-bit unsigned integer.
kVarTypeUInt64 = 7,
//! Variable is target `intptr_t`, not compatible with host `intptr_t`.
@@ -204,38 +159,17 @@ ASMJIT_ENUM(kVarType) {
//! Invalid variable type.
kVarTypeInvalid = 0xFF,
//! @internal
//! \internal
_kVarTypeIntStart = kVarTypeInt8,
//! @internal
//! \internal
_kVarTypeIntEnd = kVarTypeUIntPtr,
//! @internal
//! \internal
_kVarTypeFpStart = kVarTypeFp32,
//! @internal
//! \internal
_kVarTypeFpEnd = kVarTypeFp64
};
// ============================================================================
// [asmjit::kRelocMode]
// ============================================================================
ASMJIT_ENUM(kRelocMode) {
kRelocAbsToAbs = 0,
kRelocRelToAbs = 1,
kRelocAbsToRel = 2,
kRelocTrampoline = 3
};
// ============================================================================
// [asmjit::Ptr]
// ============================================================================
//! 64-bit signed pointer, compatible with JIT and non-JIT generators.
typedef int64_t SignedPtr;
//! 64-bit unsigned pointer, compatible with JIT and non-JIT generators.
typedef uint64_t Ptr;
// ============================================================================
// [asmjit::Operand]
// ============================================================================
@@ -246,7 +180,7 @@ struct Operand {
// [Structs]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! Base operand data.
struct BaseOp {
@@ -261,11 +195,11 @@ struct Operand {
//! Operand id, identifier used by `BaseAssembler` and `BaseCompiler`.
//!
//! @note Uninitialized operand has always set id to `kInvalidValue`.
//! \note Uninitialized operand has always set id to `kInvalidValue`.
uint32_t id;
};
//! @internal
//! \internal
//!
//! Register or Variable operand data.
struct VRegOp {
@@ -299,13 +233,13 @@ struct Operand {
//! Variable type.
uint32_t vType;
//! @internal
//! \internal
//!
//! Unused.
uint32_t vUnused;
};
//! @internal
//! \internal
//!
//! Memory or Variable operand data.
struct VMemOp {
@@ -328,7 +262,7 @@ struct Operand {
int32_t displacement;
};
//! @internal
//! \internal
//!
//! Immediate operand data.
struct ImmOp {
@@ -345,24 +279,24 @@ struct Operand {
uint32_t id;
union {
//! 8x signed 8-bit immediate values.
//! 8x8-bit signed immediate values.
int8_t _i8[8];
//! 8x unsigned 8-bit immediate values.
//! 8x8-bit unsigned immediate values.
uint8_t _u8[8];
//! 4x signed 16-bit immediate values.
//! 4x16-bit signed immediate values.
int16_t _i16[4];
//! 4x unsigned 16-bit immediate values.
//! 4x16-bit unsigned immediate values.
uint16_t _u16[4];
//! 2x signed 32-bit immediate values.
//! 2x32-bit signed immediate values.
int32_t _i32[2];
//! 2x unsigned 32-bit immediate values.
//! 2x32-bit unsigned immediate values.
uint32_t _u32[2];
//! 1x signed 64-bit immediate value.
//! 1x64-bit signed immediate value.
int64_t _i64[1];
//! 1x unsigned 64-bit immediate value.
//! 1x64-bit unsigned immediate value.
uint64_t _u64[1];
//! 2x SP-FP values.
@@ -372,7 +306,7 @@ struct Operand {
} value;
};
//! @internal
//! \internal
//!
//! Label operand data.
struct LabelOp {
@@ -419,7 +353,7 @@ struct Operand {
// [Init & Copy]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! Initialize operand to `other` (used by constructors).
ASMJIT_INLINE void _init(const Operand& other) {
@@ -448,7 +382,7 @@ struct Operand {
_packed[1].setPacked_2x32(u2, u3);
}
//! @internal
//! \internal
//!
//! Initialize operand to `other` (used by assign operators).
ASMJIT_INLINE void _copy(const Operand& other) {
@@ -525,7 +459,7 @@ struct Operand {
// --------------------------------------------------------------------------
//! Get operand id.
//!
//!
//! Operand id's are used internally by `BaseAssembler` and `BaseCompiler`.
//!
//! There is no way to change or remove operand id. Unneeded operands can be
@@ -553,8 +487,6 @@ struct Operand {
};
};
ASMJIT_VAR const Operand noOperand;
// ============================================================================
// [asmjit::OperandUtil]
// ============================================================================
@@ -578,7 +510,7 @@ struct OperandUtil {
//! Get whether the id refers to `BaseVar`.
//!
//! @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
//! using only one comparison.
static ASMJIT_INLINE bool isVarId(uint32_t id) {
@@ -587,7 +519,7 @@ struct OperandUtil {
//! Get whether the id refers to `Label`.
//!
//! @note The function will never return `true` if the id is `kInvalidValue`.
//! \note The function will never return `true` if the id is `kInvalidValue`.
static ASMJIT_INLINE bool isLabelId(uint32_t id) {
return static_cast<int32_t>(id) >= 0;
}
@@ -1075,21 +1007,6 @@ struct Imm : public Operand {
}
};
//! Create signed immediate value operand.
static ASMJIT_INLINE Imm imm(int64_t val) {
return Imm(val);
}
//! Create unsigned immediate value operand.
static ASMJIT_INLINE Imm imm_u(uint64_t val) {
return Imm(static_cast<int64_t>(val));
}
//! Create void* pointer immediate value operand.
static ASMJIT_INLINE Imm imm_ptr(void* p) {
return Imm(static_cast<int64_t>((intptr_t)p));
}
// ============================================================================
// [asmjit::Label]
// ============================================================================
@@ -1164,7 +1081,30 @@ struct Label : public Operand {
ASMJIT_INLINE bool operator!=(const Label& other) const { return _base.id != other._base.id; }
};
//! @}
// ============================================================================
// [asmjit::Operand - Globals]
// ============================================================================
//! No operand, can be used to reset an operand by assignment or to refer to an
//! operand that doesn't exist.
ASMJIT_VAR const Operand noOperand;
//! Create signed immediate value operand.
static ASMJIT_INLINE Imm imm(int64_t val) {
return Imm(val);
}
//! Create unsigned immediate value operand.
static ASMJIT_INLINE Imm imm_u(uint64_t val) {
return Imm(static_cast<int64_t>(val));
}
//! Create void* pointer immediate value operand.
static ASMJIT_INLINE Imm imm_ptr(void* p) {
return Imm(static_cast<int64_t>((intptr_t)p));
}
//! \}
} // asmjit namespace
@@ -1172,4 +1112,4 @@ struct Label : public Operand {
#include "../apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_DEFS_H
#endif // _ASMJIT_BASE_OPERAND_H

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_PODLIST_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/globals.h"
// [Api-Begin]
@@ -17,14 +16,14 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::PodList<T>]
// ============================================================================
//! @internal
//! \internal
template <typename T>
struct PodList {
ASMJIT_NO_COPY(PodList<T>)
@@ -107,7 +106,7 @@ struct PodList {
Link* _last;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -9,23 +9,21 @@
#define _ASMJIT_BASE_PODVECTOR_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/error.h"
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::PodVectorData]
// ============================================================================
//! @internal
//! \internal
struct PodVectorData {
//! Get data.
ASMJIT_INLINE void* getData() const {
@@ -42,7 +40,7 @@ struct PodVectorData {
// [asmjit::PodVectorBase]
// ============================================================================
//! @internal
//! \internal
struct PodVectorBase {
static ASMJIT_API const PodVectorData _nullData;
@@ -124,7 +122,7 @@ struct PodVector : PodVectorBase {
return static_cast<T*>(_d->getData());
}
//! @overload
//! \overload
ASMJIT_INLINE const T* getData() const {
return static_cast<const T*>(_d->getData());
}
@@ -271,7 +269,7 @@ struct PodVector : PodVectorBase {
}
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -10,7 +10,6 @@
// [Dependencies - AsmJit]
#include "../base/assembler.h"
#include "../base/cpuinfo.h"
#include "../base/defs.h"
#include "../base/error.h"
#include "../base/runtime.h"
@@ -77,7 +76,7 @@ Error JitRuntime::add(void** dst, BaseAssembler* assembler) {
if (codeSize == 0) {
*dst = NULL;
return kErrorCompilerNoFunc;
return kErrorInvalidFunction;
}
void* p = _memMgr.alloc(codeSize, getAllocType());
@@ -96,6 +95,8 @@ Error JitRuntime::add(void** dst, BaseAssembler* assembler) {
// Return the code.
*dst = p;
flush(p, relocSize);
return kErrorOk;
}
@@ -103,6 +104,18 @@ Error JitRuntime::release(void* p) {
return _memMgr.release(p);
}
void JitRuntime::flush(void* p, size_t size) {
// Only useful on non-x86 architectures.
#if !defined(ASMJIT_HOST_X86) && !defined(ASMJIT_HOST_X64)
// Windows has built-in support in kernel32.dll.
#if defined(ASMJIT_OS_WINDOWS)
::FlushInstructionCache(_memMgr.getProcessHandle(), p, size);
#endif // ASMJIT_OS_WINDOWS
#endif // !ASMJIT_HOST_X86 && !ASMJIT_HOST_X64
}
} // asmjit namespace
// [Api-End]

View File

@@ -17,9 +17,6 @@
namespace asmjit {
//! @addtogroup asmjit_base_codegen
//! @{
// ============================================================================
// [Forward Declarations]
// ============================================================================
@@ -27,6 +24,9 @@ namespace asmjit {
struct BaseAssembler;
struct BaseCpuInfo;
//! \addtogroup asmjit_base_general
//! \{
// ============================================================================
// [asmjit::Runtime]
// ============================================================================
@@ -54,10 +54,12 @@ struct Runtime {
//! Get CPU information.
virtual const BaseCpuInfo* getCpuInfo() = 0;
//! Allocate a memory needed for a code generated by `BaseAssembler` and
//! Allocate a memory needed for a code generated by `assembler` and
//! relocate it to the target location.
//!
//! Returns Status code as `kError`.
//! 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
//! `NULL`.
virtual Error add(void** dst, BaseAssembler* assembler) = 0;
//! Release memory allocated by `add`.
@@ -115,6 +117,19 @@ struct JitRuntime : public Runtime {
ASMJIT_API virtual Error add(void** dst, BaseAssembler* assembler);
ASMJIT_API virtual Error release(void* p);
//! Flush instruction cache.
//!
//! This member function is called after the code has been copied to the
//! destination buffer. It is only useful for JIT code generation as it
//! causes to flush the processor cache so it will not use the old data.
//!
//! Flushing is basically a NOP under X86/X64, but is needed by architectures
//! not having a transparent cache.
//!
//! This function can also be overridden to improve compatibility with tools
//! like Valgrind, but this is not an official part of AsmJit.
ASMJIT_API virtual void flush(void* p, size_t size);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
@@ -125,7 +140,7 @@ struct JitRuntime : public Runtime {
uint32_t _allocType;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -8,7 +8,6 @@
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/intutil.h"
#include "../base/string.h"

View File

@@ -9,7 +9,6 @@
#define _ASMJIT_BASE_STRING_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/globals.h"
// [Dependencies - C]
@@ -20,14 +19,14 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kStringOp]
// ============================================================================
//! @internal
//! \internal
//!
//! String operation.
ASMJIT_ENUM(kStringOp) {
@@ -41,7 +40,7 @@ ASMJIT_ENUM(kStringOp) {
// [asmjit::kStringFormat]
// ============================================================================
//! @internal
//! \internal
//!
//! String format flags.
ASMJIT_ENUM(kStringFormat) {
@@ -55,8 +54,6 @@ ASMJIT_ENUM(kStringFormat) {
// [asmjit::StringUtil]
// ============================================================================
//! @internal
//!
//! String utilities.
struct StringUtil {
static ASMJIT_INLINE size_t nlen(const char* s, size_t maxlen) {
@@ -72,8 +69,6 @@ struct StringUtil {
// [asmjit::StringBuilder]
// ============================================================================
//! @internal
//!
//! String builder.
//!
//! String builder was designed to be able to build a string using append like
@@ -339,7 +334,7 @@ struct StringBuilder {
// [asmjit::StringBuilderT]
// ============================================================================
//! @internal
//! \internal
template<size_t N>
struct StringBuilderT : public StringBuilder {
ASMJIT_NO_COPY(StringBuilderT<N>)
@@ -366,7 +361,7 @@ struct StringBuilderT : public StringBuilder {
N + 1 + sizeof(intptr_t)) & ~static_cast<size_t>(sizeof(intptr_t) - 1)];
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -9,15 +9,15 @@
#define _ASMJIT_BASE_VECTYPES_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/globals.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! @addtogroup asmjit_base_vectypes
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Vec64Data]
@@ -29,7 +29,7 @@ union Vec64Data {
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all eight signed 8-bit integers.
//! Set all eight 8-bit signed integers.
static ASMJIT_INLINE Vec64Data 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)
{
@@ -38,7 +38,7 @@ union Vec64Data {
return self;
}
//! Set all eight signed 8-bit integers.
//! Set all eight 8-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSb(
int8_t x0)
{
@@ -47,7 +47,7 @@ union Vec64Data {
return self;
}
//! Set all eight unsigned 8-bit integers.
//! Set all eight 8-bit unsigned integers.
static ASMJIT_INLINE Vec64Data 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)
{
@@ -56,7 +56,7 @@ union Vec64Data {
return self;
}
//! Set all eight unsigned 8-bit integers.
//! Set all eight 8-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUb(
uint8_t x0)
{
@@ -65,7 +65,7 @@ union Vec64Data {
return self;
}
//! Set all four signed 16-bit integers.
//! Set all four 16-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSw(
int16_t x0, int16_t x1, int16_t x2, int16_t x3)
{
@@ -74,7 +74,7 @@ union Vec64Data {
return self;
}
//! Set all four signed 16-bit integers.
//! Set all four 16-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSw(
int16_t x0)
{
@@ -83,7 +83,7 @@ union Vec64Data {
return self;
}
//! Set all four unsigned 16-bit integers.
//! Set all four 16-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUw(
uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3)
{
@@ -92,7 +92,7 @@ union Vec64Data {
return self;
}
//! Set all four unsigned 16-bit integers.
//! Set all four 16-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUw(
uint16_t x0)
{
@@ -101,7 +101,7 @@ union Vec64Data {
return self;
}
//! Set all two signed 32-bit integers.
//! Set all two 32-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSd(
int32_t x0, int32_t x1)
{
@@ -110,7 +110,7 @@ union Vec64Data {
return self;
}
//! Set all two signed 32-bit integers.
//! Set all two 32-bit signed integers.
static ASMJIT_INLINE Vec64Data fromSd(
int32_t x0)
{
@@ -119,7 +119,7 @@ union Vec64Data {
return self;
}
//! Set all two unsigned 32-bit integers.
//! Set all two 32-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUd(
uint32_t x0, uint32_t x1)
{
@@ -128,7 +128,7 @@ union Vec64Data {
return self;
}
//! Set all two unsigned 32-bit integers.
//! Set all two 32-bit unsigned integers.
static ASMJIT_INLINE Vec64Data fromUd(
uint32_t x0)
{
@@ -137,7 +137,7 @@ union Vec64Data {
return self;
}
//! Set signed 64-bit integer.
//! Set 64-bit signed integer.
static ASMJIT_INLINE Vec64Data fromSq(
int64_t x0)
{
@@ -146,7 +146,7 @@ union Vec64Data {
return self;
}
//! Set unsigned 64-bit integer.
//! Set 64-bit unsigned integer.
static ASMJIT_INLINE Vec64Data fromUq(
uint64_t x0)
{
@@ -186,7 +186,7 @@ union Vec64Data {
// [Accessors]
// --------------------------------------------------------------------------
//! Set all eight signed 8-bit integers.
//! Set all eight 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0, int8_t x1, int8_t x2, int8_t x3, int8_t x4, int8_t x5, int8_t x6, int8_t x7)
{
@@ -194,14 +194,14 @@ union Vec64Data {
sb[4] = x4; sb[5] = x5; sb[6] = x6; sb[7] = x7;
}
//! Set all eight signed 8-bit integers.
//! Set all eight 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0)
{
setUb(static_cast<uint8_t>(x0));
}
//! Set all eight unsigned 8-bit integers.
//! Set all eight 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0, uint8_t x1, uint8_t x2, uint8_t x3, uint8_t x4, uint8_t x5, uint8_t x6, uint8_t x7)
{
@@ -209,7 +209,7 @@ union Vec64Data {
ub[4] = x4; ub[5] = x5; ub[6] = x6; ub[7] = x7;
}
//! Set all eight unsigned 8-bit integers.
//! Set all eight 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0)
{
@@ -224,28 +224,28 @@ union Vec64Data {
}
}
//! Set all four signed 16-bit integers.
//! Set all four 16-bit signed integers.
ASMJIT_INLINE void setSw(
int16_t x0, int16_t x1, int16_t x2, int16_t x3)
{
sw[0] = x0; sw[1] = x1; sw[2] = x2; sw[3] = x3;
}
//! Set all four signed 16-bit integers.
//! Set all four 16-bit signed integers.
ASMJIT_INLINE void setSw(
int16_t x0)
{
setUw(static_cast<uint16_t>(x0));
}
//! Set all four unsigned 16-bit integers.
//! Set all four 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3)
{
uw[0] = x0; uw[1] = x1; uw[2] = x2; uw[3] = x3;
}
//! Set all four unsigned 16-bit integers.
//! Set all four 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
uint16_t x0)
{
@@ -260,42 +260,42 @@ union Vec64Data {
}
}
//! Set all two signed 32-bit integers.
//! Set all two 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0, int32_t x1)
{
sd[0] = x0; sd[1] = x1;
}
//! Set all two signed 32-bit integers.
//! Set all two 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0)
{
sd[0] = x0; sd[1] = x0;
}
//! Set all two unsigned 32-bit integers.
//! Set all two 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0, uint32_t x1)
{
ud[0] = x0; ud[1] = x1;
}
//! Set all two unsigned 32-bit integers.
//! Set all two 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0)
{
ud[0] = x0; ud[1] = x0;
}
//! Set signed 64-bit integer.
//! Set 64-bit signed integer.
ASMJIT_INLINE void setSq(
int64_t x0)
{
sq[0] = x0;
}
//! Set unsigned 64-bit integer.
//! Set 64-bit unsigned integer.
ASMJIT_INLINE void setUq(
uint64_t x0)
{
@@ -327,21 +327,21 @@ union Vec64Data {
// [Members]
// --------------------------------------------------------------------------
//! Array of eight signed 8-bit integers.
//! Array of eight 8-bit signed integers.
int8_t sb[8];
//! Array of eight unsigned 8-bit integers.
//! Array of eight 8-bit unsigned integers.
uint8_t ub[8];
//! Array of four signed 16-bit integers.
//! Array of four 16-bit signed integers.
int16_t sw[4];
//! Array of four unsigned 16-bit integers.
//! Array of four 16-bit unsigned integers.
uint16_t uw[4];
//! Array of two signed 32-bit integers.
//! Array of two 32-bit signed integers.
int32_t sd[2];
//! Array of two unsigned 32-bit integers.
//! Array of two 32-bit unsigned integers.
uint32_t ud[2];
//! Array of one signed 64-bit integer.
//! Array of one 64-bit signed integer.
int64_t sq[1];
//! Array of one unsigned 64-bit integer.
//! Array of one 64-bit unsigned integer.
uint64_t uq[1];
//! Array of two SP-FP values.
@@ -360,7 +360,7 @@ union Vec128Data {
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all sixteen signed 8-bit integers.
//! Set all sixteen 8-bit signed integers.
static ASMJIT_INLINE Vec128Data 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 ,
@@ -372,7 +372,7 @@ union Vec128Data {
return self;
}
//! Set all sixteen signed 8-bit integers.
//! Set all sixteen 8-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSb(
int8_t x0)
{
@@ -381,7 +381,7 @@ union Vec128Data {
return self;
}
//! Set all sixteen unsigned 8-bit integers.
//! Set all sixteen 8-bit unsigned integers.
static ASMJIT_INLINE Vec128Data 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 ,
@@ -393,7 +393,7 @@ union Vec128Data {
return self;
}
//! Set all sixteen unsigned 8-bit integers.
//! Set all sixteen 8-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUb(
uint8_t x0)
{
@@ -402,7 +402,7 @@ union Vec128Data {
return self;
}
//! Set all eight signed 16-bit integers.
//! Set all eight 16-bit signed integers.
static ASMJIT_INLINE Vec128Data 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)
{
@@ -411,7 +411,7 @@ union Vec128Data {
return self;
}
//! Set all eight signed 16-bit integers.
//! Set all eight 16-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSw(
int16_t x0)
{
@@ -420,7 +420,7 @@ union Vec128Data {
return self;
}
//! Set all eight unsigned 16-bit integers.
//! Set all eight 16-bit unsigned integers.
static ASMJIT_INLINE Vec128Data 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)
{
@@ -429,7 +429,7 @@ union Vec128Data {
return self;
}
//! Set all eight unsigned 16-bit integers.
//! Set all eight 16-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUw(
uint16_t x0)
{
@@ -438,7 +438,7 @@ union Vec128Data {
return self;
}
//! Set all four signed 32-bit integers.
//! Set all four 32-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3)
{
@@ -447,7 +447,7 @@ union Vec128Data {
return self;
}
//! Set all four signed 32-bit integers.
//! Set all four 32-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSd(
int32_t x0)
{
@@ -456,7 +456,7 @@ union Vec128Data {
return self;
}
//! Set all four unsigned 32-bit integers.
//! Set all four 32-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
{
@@ -465,7 +465,7 @@ union Vec128Data {
return self;
}
//! Set all four unsigned 32-bit integers.
//! Set all four 32-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUd(
uint32_t x0)
{
@@ -474,7 +474,7 @@ union Vec128Data {
return self;
}
//! Set all two signed 64-bit integers.
//! Set all two 64-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSq(
int64_t x0, int64_t x1)
{
@@ -483,7 +483,7 @@ union Vec128Data {
return self;
}
//! Set all two signed 64-bit integers.
//! Set all two 64-bit signed integers.
static ASMJIT_INLINE Vec128Data fromSq(
int64_t x0)
{
@@ -492,7 +492,7 @@ union Vec128Data {
return self;
}
//! Set all two unsigned 64-bit integers.
//! Set all two 64-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUq(
uint64_t x0, uint64_t x1)
{
@@ -501,7 +501,7 @@ union Vec128Data {
return self;
}
//! Set all two unsigned 64-bit integers.
//! Set all two 64-bit unsigned integers.
static ASMJIT_INLINE Vec128Data fromUq(
uint64_t x0)
{
@@ -550,7 +550,7 @@ union Vec128Data {
// [Accessors]
// --------------------------------------------------------------------------
//! Set all sixteen signed 8-bit integers.
//! Set all sixteen 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
@@ -563,14 +563,14 @@ union Vec128Data {
sb[12] = x12; sb[13] = x13; sb[14] = x14; sb[15] = x15;
}
//! Set all sixteen signed 8-bit integers.
//! Set all sixteen 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0)
{
setUb(static_cast<uint8_t>(x0));
}
//! Set all sixteen unsigned 8-bit integers.
//! Set all sixteen 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
@@ -583,7 +583,7 @@ union Vec128Data {
ub[12] = x12; ub[13] = x13; ub[14] = x14; ub[15] = x15;
}
//! Set all sixteen unsigned 8-bit integers.
//! Set all sixteen 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0)
{
@@ -601,7 +601,7 @@ union Vec128Data {
}
}
//! Set all eight signed 16-bit integers.
//! Set all eight 16-bit signed integers.
ASMJIT_INLINE void setSw(
int16_t x0, int16_t x1, int16_t x2, int16_t x3, int16_t x4, int16_t x5, int16_t x6, int16_t x7)
{
@@ -609,14 +609,14 @@ union Vec128Data {
sw[4] = x4; sw[5] = x5; sw[6] = x6; sw[7] = x7;
}
//! Set all eight signed 16-bit integers.
//! Set all eight 16-bit signed integers.
ASMJIT_INLINE void setSw(
int16_t x0)
{
setUw(static_cast<uint16_t>(x0));
}
//! Set all eight unsigned 16-bit integers.
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
uint16_t x0, uint16_t x1, uint16_t x2, uint16_t x3, uint16_t x4, uint16_t x5, uint16_t x6, uint16_t x7)
{
@@ -624,7 +624,7 @@ union Vec128Data {
uw[4] = x4; uw[5] = x5; uw[6] = x6; uw[7] = x7;
}
//! Set all eight unsigned 16-bit integers.
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
uint16_t x0)
{
@@ -642,28 +642,28 @@ union Vec128Data {
}
}
//! Set all four signed 32-bit integers.
//! Set all four 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3)
{
sd[0] = x0; sd[1] = x1; sd[2] = x2; sd[3] = x3;
}
//! Set all four signed 32-bit integers.
//! Set all four 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0)
{
setUd(static_cast<uint32_t>(x0));
}
//! Set all four unsigned 32-bit integers.
//! Set all four 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3)
{
ud[0] = x0; ud[1] = x1; ud[2] = x2; ud[3] = x3;
}
//! Set all four unsigned 32-bit integers.
//! Set all four 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0)
{
@@ -680,28 +680,28 @@ union Vec128Data {
}
}
//! Set all two signed 64-bit integers.
//! Set all two 64-bit signed integers.
ASMJIT_INLINE void setSq(
int64_t x0, int64_t x1)
{
sq[0] = x0; sq[1] = x1;
}
//! Set all two signed 64-bit integers.
//! Set all two 64-bit signed integers.
ASMJIT_INLINE void setSq(
int64_t x0)
{
sq[0] = x0; sq[1] = x0;
}
//! Set all two unsigned 64-bit integers.
//! Set all two 64-bit unsigned integers.
ASMJIT_INLINE void setUq(
uint64_t x0, uint64_t x1)
{
uq[0] = x0; uq[1] = x1;
}
//! Set all two unsigned 64-bit integers.
//! Set all two 64-bit unsigned integers.
ASMJIT_INLINE void setUq(
uint64_t x0)
{
@@ -740,21 +740,21 @@ union Vec128Data {
// [Members]
// --------------------------------------------------------------------------
//! Array of sixteen signed 8-bit integers.
//! Array of sixteen 8-bit signed integers.
int8_t sb[16];
//! Array of sixteen unsigned 8-bit integers.
//! Array of sixteen 8-bit unsigned integers.
uint8_t ub[16];
//! Array of eight signed 16-bit integers.
//! Array of eight 16-bit signed integers.
int16_t sw[8];
//! Array of eight unsigned 16-bit integers.
//! Array of eight 16-bit unsigned integers.
uint16_t uw[8];
//! Array of four signed 32-bit integers.
//! Array of four 32-bit signed integers.
int32_t sd[4];
//! Array of four unsigned 32-bit integers.
//! Array of four 32-bit unsigned integers.
uint32_t ud[4];
//! Array of two signed 64-bit integers.
//! Array of two 64-bit signed integers.
int64_t sq[2];
//! Array of two unsigned 64-bit integers.
//! Array of two 64-bit unsigned integers.
uint64_t uq[2];
//! Array of four 32-bit single precision floating points.
@@ -773,7 +773,7 @@ union Vec256Data {
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Set all thirty two signed 8-bit integers.
//! Set all thirty two 8-bit signed integers.
static ASMJIT_INLINE Vec256Data 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 ,
@@ -791,7 +791,7 @@ union Vec256Data {
return self;
}
//! Set all thirty two signed 8-bit integers.
//! Set all thirty two 8-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSb(
int8_t x0)
{
@@ -800,7 +800,7 @@ union Vec256Data {
return self;
}
//! Set all thirty two unsigned 8-bit integers.
//! Set all thirty two 8-bit unsigned integers.
static ASMJIT_INLINE Vec256Data 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 ,
@@ -818,7 +818,7 @@ union Vec256Data {
return self;
}
//! Set all thirty two unsigned 8-bit integers.
//! Set all thirty two 8-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUb(
uint8_t x0)
{
@@ -827,7 +827,7 @@ union Vec256Data {
return self;
}
//! Set all sixteen signed 16-bit integers.
//! Set all sixteen 16-bit signed integers.
static ASMJIT_INLINE Vec256Data 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 x8, int16_t x9, int16_t x10, int16_t x11, int16_t x12, int16_t x13, int16_t x14, int16_t x15)
@@ -837,7 +837,7 @@ union Vec256Data {
return self;
}
//! Set all sixteen signed 16-bit integers.
//! Set all sixteen 16-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSw(
int16_t x0)
{
@@ -846,7 +846,7 @@ union Vec256Data {
return self;
}
//! Set all sixteen unsigned 16-bit integers.
//! Set all sixteen 16-bit unsigned integers.
static ASMJIT_INLINE Vec256Data 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 x8, uint16_t x9, uint16_t x10, uint16_t x11, uint16_t x12, uint16_t x13, uint16_t x14, uint16_t x15)
@@ -856,7 +856,7 @@ union Vec256Data {
return self;
}
//! Set all sixteen unsigned 16-bit integers.
//! Set all sixteen 16-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUw(
uint16_t x0)
{
@@ -865,7 +865,7 @@ union Vec256Data {
return self;
}
//! Set all eight signed 32-bit integers.
//! Set all eight 32-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3,
int32_t x4, int32_t x5, int32_t x6, int32_t x7)
@@ -875,7 +875,7 @@ union Vec256Data {
return self;
}
//! Set all eight signed 32-bit integers.
//! Set all eight 32-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSd(
int32_t x0)
{
@@ -884,7 +884,7 @@ union Vec256Data {
return self;
}
//! Set all eight unsigned 32-bit integers.
//! Set all eight 32-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3,
uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7)
@@ -894,7 +894,7 @@ union Vec256Data {
return self;
}
//! Set all eight unsigned 32-bit integers.
//! Set all eight 32-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUd(
uint32_t x0)
{
@@ -903,7 +903,7 @@ union Vec256Data {
return self;
}
//! Set all four signed 64-bit integers.
//! Set all four 64-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSq(
int64_t x0, int64_t x1, int64_t x2, int64_t x3)
{
@@ -912,7 +912,7 @@ union Vec256Data {
return self;
}
//! Set all four signed 64-bit integers.
//! Set all four 64-bit signed integers.
static ASMJIT_INLINE Vec256Data fromSq(
int64_t x0)
{
@@ -921,7 +921,7 @@ union Vec256Data {
return self;
}
//! Set all four unsigned 64-bit integers.
//! Set all four 64-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUq(
uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3)
{
@@ -930,7 +930,7 @@ union Vec256Data {
return self;
}
//! Set all four unsigned 64-bit integers.
//! Set all four 64-bit unsigned integers.
static ASMJIT_INLINE Vec256Data fromUq(
uint64_t x0)
{
@@ -980,7 +980,7 @@ union Vec256Data {
// [Accessors]
// --------------------------------------------------------------------------
//! Set all thirty two signed 8-bit integers.
//! Set all thirty two 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0 , int8_t x1 , int8_t x2 , int8_t x3 ,
int8_t x4 , int8_t x5 , int8_t x6 , int8_t x7 ,
@@ -1001,14 +1001,14 @@ union Vec256Data {
sb[28] = x28; sb[29] = x29; sb[30] = x30; sb[31] = x31;
}
//! Set all thirty two signed 8-bit integers.
//! Set all thirty two 8-bit signed integers.
ASMJIT_INLINE void setSb(
int8_t x0)
{
setUb(static_cast<uint8_t>(x0));
}
//! Set all thirty two unsigned 8-bit integers.
//! Set all thirty two 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0 , uint8_t x1 , uint8_t x2 , uint8_t x3 ,
uint8_t x4 , uint8_t x5 , uint8_t x6 , uint8_t x7 ,
@@ -1029,7 +1029,7 @@ union Vec256Data {
ub[28] = x28; ub[29] = x29; ub[30] = x30; ub[31] = x31;
}
//! Set all thirty two unsigned 8-bit integers.
//! Set all thirty two 8-bit unsigned integers.
ASMJIT_INLINE void setUb(
uint8_t x0)
{
@@ -1053,7 +1053,7 @@ union Vec256Data {
}
}
//! Set all sixteen signed 16-bit integers.
//! Set all sixteen 16-bit signed integers.
ASMJIT_INLINE void setSw(
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)
@@ -1064,14 +1064,14 @@ union Vec256Data {
sw[12] = x12; sw[13] = x13; sw[14] = x14; sw[15] = x15;
}
//! Set all sixteen signed 16-bit integers.
//! Set all sixteen 16-bit signed integers.
ASMJIT_INLINE void setSw(
int16_t x0)
{
setUw(static_cast<uint16_t>(x0));
}
//! Set all sixteen unsigned 16-bit integers.
//! Set all sixteen 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
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)
@@ -1082,7 +1082,7 @@ union Vec256Data {
uw[12] = x12; uw[13] = x13; uw[14] = x14; uw[15] = x15;
}
//! Set all eight unsigned 16-bit integers.
//! Set all eight 16-bit unsigned integers.
ASMJIT_INLINE void setUw(
uint16_t x0)
{
@@ -1106,7 +1106,7 @@ union Vec256Data {
}
}
//! Set all eight signed 32-bit integers.
//! Set all eight 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0, int32_t x1, int32_t x2, int32_t x3,
int32_t x4, int32_t x5, int32_t x6, int32_t x7)
@@ -1115,14 +1115,14 @@ union Vec256Data {
sd[4] = x4; sd[5] = x5; sd[6] = x6; sd[7] = x7;
}
//! Set all eight signed 32-bit integers.
//! Set all eight 32-bit signed integers.
ASMJIT_INLINE void setSd(
int32_t x0)
{
setUd(static_cast<uint32_t>(x0));
}
//! Set all eight unsigned 32-bit integers.
//! Set all eight 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0, uint32_t x1, uint32_t x2, uint32_t x3,
uint32_t x4, uint32_t x5, uint32_t x6, uint32_t x7)
@@ -1131,7 +1131,7 @@ union Vec256Data {
ud[4] = x4; ud[5] = x5; ud[6] = x6; ud[7] = x7;
}
//! Set all eight unsigned 32-bit integers.
//! Set all eight 32-bit unsigned integers.
ASMJIT_INLINE void setUd(
uint32_t x0)
{
@@ -1154,28 +1154,28 @@ union Vec256Data {
}
}
//! Set all four signed 64-bit integers.
//! Set all four 64-bit signed integers.
ASMJIT_INLINE void setSq(
int64_t x0, int64_t x1, int64_t x2, int64_t x3)
{
sq[0] = x0; sq[1] = x1; sq[2] = x2; sq[3] = x3;
}
//! Set all four signed 64-bit integers.
//! Set all four 64-bit signed integers.
ASMJIT_INLINE void setSq(
int64_t x0)
{
sq[0] = x0; sq[1] = x0; sq[2] = x0; sq[3] = x0;
}
//! Set all four unsigned 64-bit integers.
//! Set all four 64-bit unsigned integers.
ASMJIT_INLINE void setUq(
uint64_t x0, uint64_t x1, uint64_t x2, uint64_t x3)
{
uq[0] = x0; uq[1] = x1; uq[2] = x2; uq[3] = x3;
}
//! Set all four unsigned 64-bit integers.
//! Set all four 64-bit unsigned integers.
ASMJIT_INLINE void setUq(
uint64_t x0)
{
@@ -1217,21 +1217,21 @@ union Vec256Data {
// [Members]
// --------------------------------------------------------------------------
//! Array of thirty two signed 8-bit integers.
//! Array of thirty two 8-bit signed integers.
int8_t sb[32];
//! Array of thirty two unsigned 8-bit integers.
//! Array of thirty two 8-bit unsigned integers.
uint8_t ub[32];
//! Array of sixteen signed 16-bit integers.
//! Array of sixteen 16-bit signed integers.
int16_t sw[16];
//! Array of sixteen unsigned 16-bit integers.
//! Array of sixteen 16-bit unsigned integers.
uint16_t uw[16];
//! Array of eight signed 32-bit integers.
//! Array of eight 32-bit signed integers.
int32_t sd[8];
//! Array of eight unsigned 32-bit integers.
//! Array of eight 32-bit unsigned integers.
uint32_t ud[8];
//! Array of four signed 64-bit integers.
//! Array of four 64-bit signed integers.
int64_t sq[4];
//! Array of four unsigned 64-bit integers.
//! Array of four 64-bit unsigned integers.
uint64_t uq[4];
//! Array of eight 32-bit single precision floating points.
@@ -1240,7 +1240,7 @@ union Vec256Data {
double df[4];
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -14,11 +14,6 @@
#include "../base/lock.h"
#include "../base/vmem.h"
// [Dependencies - Windows]
#if defined(ASMJIT_OS_WINDOWS)
# include <windows.h>
#endif // ASMJIT_OS_WINDOWS
// [Dependencies - Posix]
#if defined(ASMJIT_OS_POSIX)
# include <sys/types.h>
@@ -190,12 +185,12 @@ void VMemUtil::release(void* addr, size_t length) {
// [VMem - Ops]
// ============================================================================
//! @internal
//! \internal
enum {
kBitsPerEntity = (sizeof(size_t) * 8)
};
//! @internal
//! \internal
//!
//! Set `len` bits in `buf` starting at `index` bit index.
static void _SetBits(size_t* buf, size_t index, size_t len) {
@@ -231,7 +226,7 @@ static void _SetBits(size_t* buf, size_t index, size_t len) {
#define M_DIV(x, y) ((x) / (y))
#define M_MOD(x, y) ((x) % (y))
//! @internal
//! \internal
//!
//! Base red-black tree node.
struct RbNode {
@@ -255,7 +250,7 @@ struct RbNode {
uint8_t* mem;
};
//! @internal
//! \internal
//!
//! Get whether the node is red (NULL or node with red flag).
static ASMJIT_INLINE bool rbIsRed(RbNode* node) {
@@ -303,7 +298,7 @@ struct MemNode : public RbNode {
// [asmjit::PermanentNode]
// ============================================================================
//! @internal
//! \internal
//!
//! Permanent node.
struct PermanentNode {
@@ -330,7 +325,7 @@ struct PermanentNode {
// [asmjit::VMemPrivate]
// ============================================================================
//! @internal
//! \internal
struct VMemPrivate {
// --------------------------------------------------------------------------
// [Construction / Destruction]

View File

@@ -9,21 +9,15 @@
#define _ASMJIT_BASE_VMEM_H
// [Dependencies]
#include "../base/defs.h"
#include "../base/error.h"
// [Dependencies - Windows]
#if defined(ASMJIT_OS_WINDOWS)
# include <windows.h>
#endif // ASMJIT_OS_WINDOWS
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::kVMemAlloc]
@@ -72,12 +66,12 @@ struct VMemUtil {
#if defined(ASMJIT_OS_WINDOWS)
//! 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, bool canExecute);
//! Free 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);
#endif // ASMJIT_OS_WINDOWS
};
@@ -130,7 +124,7 @@ struct VMemMgr {
//! Get whether to keep allocated memory after the `VMemMgr` is destroyed.
//!
//! @sa `setKeepVirtualMemory()`.
//! \sa \ref setKeepVirtualMemory.
ASMJIT_API bool getKeepVirtualMemory() const;
//! Set whether to keep allocated memory after memory manager is
@@ -142,9 +136,9 @@ struct VMemMgr {
//! VMemMgr destructor. After destruction all internal
//! structures are freed, only the process virtual memory remains.
//!
//! @note Memory allocated with kVMemAllocPermanent is always kept.
//! \note Memory allocated with kVMemAllocPermanent is always kept.
//!
//! @sa `getKeepVirtualMemory()`.
//! \sa \ref getKeepVirtualMemory.
ASMJIT_API void setKeepVirtualMemory(bool keepVirtualMemory);
// --------------------------------------------------------------------------
@@ -168,13 +162,13 @@ struct VMemMgr {
// [Members]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! Pointer to private data hidden out of the public API.
void* _d;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -8,7 +8,6 @@
#define ASMJIT_EXPORTS
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/intutil.h"
#include "../base/zone.h"

View File

@@ -16,8 +16,8 @@
namespace asmjit {
//! @addtogroup asmjit_base_util
//! @{
//! \addtogroup asmjit_base_util
//! \{
// ============================================================================
// [asmjit::Zone]
@@ -32,7 +32,7 @@ struct Zone {
// [Chunk]
// --------------------------------------------------------------------------
//! @internal
//! \internal
//!
//! One allocated chunk of memory.
struct Chunk {
@@ -56,33 +56,37 @@ struct Zone {
//! Create a new instance of `Zone` allocator.
//!
//! @param chunkSize Default size of the first chunk.
//! The `chunkSize` parameter describes the size of the chunk. If `alloc()`
//! requires more memory than `chunkSize` then a bigger chunk will be
//! allocated, however `chunkSize` will not be changed.
ASMJIT_API Zone(size_t chunkSize);
//! Destroy `Zone` instance.
//!
//! Destructor released all chunks allocated by `Zone`. The `reset()` member
//! function does the same without actually destroying `Zone` object itself.
ASMJIT_API ~Zone();
// --------------------------------------------------------------------------
// [Clear / Reset]
// --------------------------------------------------------------------------
//! Free all allocated memory except first block that remains for reuse.
//! Reset the `Zone` releasing all chunks allocated.
//!
//! Note that this method will invalidate all instances using this memory
//! allocated by this zone instance.
//! Calling `clear()` will release all chunks allocated by `Zone` except the
//! first one that will be reused if needed.
ASMJIT_API void clear();
//! Free all allocated memory at once.
//! Reset the `Zone` releasing all chunks allocated.
//!
//! Note that this method will invalidate all instances using this memory
//! allocated by this zone instance.
//! Calling `reset()` will release all chunks allocated by `Zone`.
ASMJIT_API void reset();
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get (default) chunk size.
//! Get chunk size.
ASMJIT_INLINE size_t getChunkSize() const { return _chunkSize; }
// --------------------------------------------------------------------------
@@ -140,7 +144,7 @@ struct Zone {
return static_cast<T*>(alloc(size));
}
//! @internal
//! \internal
ASMJIT_API void* _alloc(size_t size);
//! Allocate `size` bytes of zeroed memory.
@@ -158,7 +162,7 @@ struct Zone {
return (void*)p;
}
//! @internal
//! \internal
ASMJIT_API void* _calloc(size_t size);
//! Helper to duplicate data.
@@ -180,7 +184,7 @@ struct Zone {
size_t _chunkSize;
};
//! @}
//! \}
} // asmjit namespace

View File

@@ -31,16 +31,6 @@
// [Dependencies - C++]
#include <new>
// ============================================================================
// [asmjit::build - Documentation]
// ============================================================================
#if defined(ASMJIT_DOCGEN)
# define ASMJIT_BUILD_X86
# define ASMJIT_BUILD_X64
# define ASMJIT_API
#endif // ASMJIT_DOCGEN
// ============================================================================
// [asmjit::build - OS]
// ============================================================================

View File

@@ -70,6 +70,11 @@ uint32_t WinRemoteRuntime::add(void** dest, BaseAssembler* assembler) {
return kErrorOk;
}
// NOP.
Error WinRemoteRuntime::release(void* p) {
return kErrorOk;
}
} // contrib namespace
} // asmjit namespace

View File

@@ -17,6 +17,9 @@
namespace asmjit {
namespace contrib {
//! \addtogroup asmjit_contrib
//! \{
// ============================================================================
// [asmjit::contrib::WinRemoteRuntime]
// ============================================================================
@@ -54,6 +57,7 @@ struct WinRemoteRuntime : public Runtime {
// --------------------------------------------------------------------------
ASMJIT_API virtual uint32_t add(void** dest, BaseAssembler* assembler);
ASMJIT_API virtual Error release(void* p);
// --------------------------------------------------------------------------
// [Members]
@@ -63,6 +67,8 @@ struct WinRemoteRuntime : public Runtime {
VMemMgr _memMgr;
};
//! \}
} // contrib namespace
} // asmjit namespace

View File

@@ -8,121 +8,16 @@
#ifndef _ASMJIT_X86_H
#define _ASMJIT_X86_H
// ============================================================================
// [asmjit_x86x64]
// ============================================================================
//! @defgroup asmjit_x86x64 X86/X64
//!
//! @brief X86/X64 API
// ============================================================================
// [asmjit_x86x64_codegen]
// ============================================================================
//! @defgroup asmjit_x86x64_codegen Code Generation (X86/X64)
//! @ingroup asmjit_x86x64
//!
//! @brief Low-level and high-level code generation.
// ============================================================================
// [asmjit_x86x64_cpu_info]
// ============================================================================
//! @defgroup asmjit_x86x64_cpu_info CPU Information (X86/X64)
//! @ingroup asmjit_x86x64
//!
//! @brief CPU information specific to X86/X64 architecture.
//!
//! The CPUID instruction can be used to get an exhaustive information related
//! to 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 host operating system, in addition to host processor name and number
//! of cores. Class `CpuInfo` extends `BaseCpuInfo` and provides functionality
//! specific to X86 and X64.
//!
//! By default AsmJit queries the CPU information after the library is loaded
//! 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 code generation of all `Runtime`s. If there is a need to have a
//! specific CPU information which contains modified features or processor
//! vendor it's possible by creating a new instance of `CpuInfo` and setting
//! up its members. `CpuUtil::detect` can be used to detect CPU features into
//! an existing `CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off.
//!
//! If the high-level interface `CpuInfo` offers is not enough there is also
//! `CpuUtil::callCpuId` helper that can be used to call CPUID instruction with
//! a given parameters and to consume the output.
//!
//! 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
//! in the past and today there is often AVX/AVX2 detection.
//!
//! The example below shows how to detect SSE2:
//!
//! ~~~
//! using namespace asmjit;
//! using namespace asmjit::host;
//!
//! // Get `CpuInfo` global instance.
//! const CpuInfo* cpuInfo = CpuInfo::getHost();
//!
//! if (cpuInfo->hasFeature(kCpuFeatureSse2)) {
//! // Processor has SSE2.
//! }
//! else if (cpuInfo->hasFeature(kCpuFeatureMmx)) {
//! // Processor doesn't have SSE2, but has MMX.
//! }
//! else {
//! // An archaic processor, it's a wonder AsmJit works here!
//! }
//! ~~~
//!
//! The next example shows how to call CPUID directly:
//!
//! ~~~
//! using namespace asmjit;
//!
//! // The result of CPUID call.
//! CpuId out;
//!
//! // Call CPUID, first two arguments are passed in EAX/ECX.
//! CpuUtil::callCpuId(0, 0, &out);
//!
//! // If EAX argument is 0, EBX, ECX and EDX registers are filled with a cpu vendor.
//! char cpuVendor[13];
//! memcpy(cpuVendor, &out.ebx, 4);
//! memcpy(cpuVendor + 4, &out.edx, 4);
//! memcpy(cpuVendor + 8, &out.ecx, 4);
//! vendor[12] = '\0';
//!
//! // Print a CPU vendor retrieved from CPUID.
//! ::printf("%s", cpuVendor);
//! ~~~
//!
//! @sa @ref asmjit_base_cpu_info
// ============================================================================
// [asmjit_x86x64_constants]
// ============================================================================
//! @defgroup asmjit_x86x64_constants Constants (X86/X64)
//! @ingroup asmjit_x86x64
//!
//! @brief Constants and definitions specific to X86/X64 architecture.
// ============================================================================
// [Dependencies - AsmJit]
// ============================================================================
#include "base.h"
#include "x86/x86assembler.h"
#include "x86/x86compiler.h"
#include "x86/x86cpuinfo.h"
#include "x86/x86defs.h"
#include "x86/x86func.h"
#include "x86/x86inst.h"
#include "x86/x86operand.h"
#include "x86/x86util.h"
// [Guard]
#endif // _ASMJIT_X86_H

View File

@@ -19,7 +19,6 @@
#include "../base/vmem.h"
#include "../x86/x86assembler.h"
#include "../x86/x86cpuinfo.h"
#include "../x86/x86defs.h"
// [Api-Begin]
#include "../apibegin.h"
@@ -58,7 +57,7 @@ enum kVexVVVV {
kVexVVVVMask = 0xF << kVexVVVVShift
};
//! @internal
//! \internal
//!
//! Instruction 2-byte/3-byte opcode prefix definition.
struct OpCodeMM {
@@ -66,7 +65,7 @@ struct OpCodeMM {
uint8_t data[3];
};
//! @internal
//! \internal
//!
//! Mandatory prefixes encoded in 'asmjit' opcode [66, F3, F2] and asmjit
//! extensions
@@ -81,7 +80,7 @@ static const uint8_t x86OpCodePP[8] = {
0x9B
};
//! @internal
//! \internal
//!
//! Instruction 2-byte/3-byte opcode prefix data.
static const OpCodeMM x86OpCodeMM[] = {
@@ -111,7 +110,7 @@ static const uint8_t x86OpCodePopSeg[8] = { 0x00, 0x07, 0x00, 0x17, 0x1F, 0xA1,
// [asmjit::X64TrampolineWriter]
// ============================================================================
//! @internal
//! \internal
//!
//! Trampoline writer.
struct X64TrampolineWriter {
@@ -271,7 +270,7 @@ void X86X64Assembler::_bind(const Label& label) {
if (IntUtil::isInt8(patchedValue))
setByteAt(offset, static_cast<uint8_t>(patchedValue & 0xFF));
else
setError(kErrorAssemblerIllegalShortJump);
setError(kErrorIllegalDisplacement);
}
}
@@ -352,113 +351,108 @@ Error X86X64Assembler::embedLabel(const Label& op) {
// [asmjit::x86x64::Assembler - Align]
// ============================================================================
Error X86X64Assembler::_align(uint32_t m) {
Error X86X64Assembler::_align(uint32_t mode, uint32_t offset) {
if (_logger) {
_logger->logFormat(kLoggerStyleDirective,
"%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(m));
"%s.align %u\n", _logger->getIndentation(), static_cast<unsigned int>(offset));
}
if (m <= 1 || !IntUtil::isPowerOf2(m) || m > 64)
if (offset <= 1 || !IntUtil::isPowerOf2(offset) || offset > 64)
return setError(kErrorInvalidArgument);
uint32_t i = static_cast<uint32_t>(IntUtil::deltaTo<size_t>(getOffset(), m));
uint32_t i = static_cast<uint32_t>(IntUtil::deltaTo<size_t>(getOffset(), offset));
if (i == 0)
return kErrorOk;
if (getRemainingSpace() < i)
ASMJIT_PROPAGATE_ERROR(_grow(i));
uint8_t* cursor = getCursor();
uint8_t alignPattern = 0xCC;
if (IntUtil::hasBit(_features, kCodeGenOptimizedAlign)) {
const CpuInfo* cpuInfo = static_cast<const CpuInfo*>(getRuntime()->getCpuInfo());
if (mode == kAlignCode) {
alignPattern = 0x90;
// NOPs optimized for Intel:
// Intel 64 and IA-32 Architectures Software Developer's Manual
// - Volume 2B
// - Instruction Set Reference N-Z
// - NOP
if (IntUtil::hasBit(_features, kCodeGenOptimizedAlign)) {
const CpuInfo* cpuInfo = static_cast<const CpuInfo*>(getRuntime()->getCpuInfo());
// NOPs optimized for AMD:
// Software Optimization Guide for AMD Family 10h Processors (Quad-Core)
// - 4.13 - Code Padding with Operand-Size Override and Multibyte NOP
// NOPs optimized for Intel:
// Intel 64 and IA-32 Architectures Software Developer's Manual
// - Volume 2B
// - Instruction Set Reference N-Z
// - NOP
// Intel and AMD.
static const uint8_t nop1[] = { 0x90 };
static const uint8_t nop2[] = { 0x66, 0x90 };
static const uint8_t nop3[] = { 0x0F, 0x1F, 0x00 };
static const uint8_t nop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
static const uint8_t nop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
// NOPs optimized for AMD:
// Software Optimization Guide for AMD Family 10h Processors (Quad-Core)
// - 4.13 - Code Padding with Operand-Size Override and Multibyte NOP
// AMD.
static const uint8_t nop10[] = { 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop11[] = { 0x66, 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
// Intel and AMD.
static const uint8_t nop1[] = { 0x90 };
static const uint8_t nop2[] = { 0x66, 0x90 };
static const uint8_t nop3[] = { 0x0F, 0x1F, 0x00 };
static const uint8_t nop4[] = { 0x0F, 0x1F, 0x40, 0x00 };
static const uint8_t nop5[] = { 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop6[] = { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 };
static const uint8_t nop7[] = { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop8[] = { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop9[] = { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
const uint8_t* p;
uint32_t n;
// AMD.
static const uint8_t nop10[] = { 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
static const uint8_t nop11[] = { 0x66, 0x66, 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 };
if (cpuInfo->getVendorId() == kCpuVendorIntel && ((cpuInfo->getFamily() & 0x0F) == 0x06 || (cpuInfo->getFamily() & 0x0F) == 0x0F)) {
do {
switch (i) {
case 1: p = nop1; n = 1; break;
case 2: p = nop2; n = 2; break;
case 3: p = nop3; n = 3; break;
case 4: p = nop4; n = 4; break;
case 5: p = nop5; n = 5; break;
case 6: p = nop6; n = 6; break;
case 7: p = nop7; n = 7; break;
case 8: p = nop8; n = 8; break;
default: p = nop9; n = 9; break;
}
const uint8_t* p;
uint32_t n;
i -= n;
if (cpuInfo->getVendorId() == kCpuVendorIntel && (
(cpuInfo->getFamily() & 0x0F) == 0x06 ||
(cpuInfo->getFamily() & 0x0F) == 0x0F)) {
do {
EMIT_BYTE(*p++);
} while (--n);
} while (i);
}
else if (cpuInfo->getVendorId() == kCpuVendorAmd && cpuInfo->getFamily() >= 0x0F) {
do {
switch (i) {
case 1: p = nop1 ; n = 1; break;
case 2: p = nop2 ; n = 2; break;
case 3: p = nop3 ; n = 3; break;
case 4: p = nop4 ; n = 4; break;
case 5: p = nop5 ; n = 5; break;
case 6: p = nop6 ; n = 6; break;
case 7: p = nop7 ; n = 7; break;
case 8: p = nop8 ; n = 8; break;
case 9: p = nop9 ; n = 9; break;
case 10: p = nop10; n = 10; break;
default: p = nop11; n = 11; break;
}
switch (i) {
case 1: p = nop1; n = 1; break;
case 2: p = nop2; n = 2; break;
case 3: p = nop3; n = 3; break;
case 4: p = nop4; n = 4; break;
case 5: p = nop5; n = 5; break;
case 6: p = nop6; n = 6; break;
case 7: p = nop7; n = 7; break;
case 8: p = nop8; n = 8; break;
default: p = nop9; n = 9; break;
}
i -= n;
i -= n;
do {
EMIT_BYTE(*p++);
} while (--n);
} while (i);
}
else if (cpuInfo->getVendorId() == kCpuVendorAmd && cpuInfo->getFamily() >= 0x0F) {
do {
EMIT_BYTE(*p++);
} while (--n);
} while (i);
}
switch (i) {
case 1: p = nop1 ; n = 1; break;
case 2: p = nop2 ; n = 2; break;
case 3: p = nop3 ; n = 3; break;
case 4: p = nop4 ; n = 4; break;
case 5: p = nop5 ; n = 5; break;
case 6: p = nop6 ; n = 6; break;
case 7: p = nop7 ; n = 7; break;
case 8: p = nop8 ; n = 8; break;
case 9: p = nop9 ; n = 9; break;
case 10: p = nop10; n = 10; break;
default: p = nop11; n = 11; break;
}
// Legacy NOPs, 0x90 with 0x66 prefix.
if (getArch() == kArchX86) {
while (i) {
switch (i) {
default: EMIT_BYTE(0x66); i--;
case 3: EMIT_BYTE(0x66); i--;
case 2: EMIT_BYTE(0x66); i--;
case 1: EMIT_BYTE(0x90); i--;
}
i -= n;
do {
EMIT_BYTE(*p++);
} while (--n);
} while (i);
}
}
}
// Legacy NOPs, only 0x90.
while (i) {
EMIT_BYTE(0x90);
EMIT_BYTE(alignPattern);
i--;
}
@@ -898,7 +892,7 @@ static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) {
return (s << 6) + (i << 3) + b;
}
//! @internal
//! \internal
static const Operand::VRegOp x86PatchedHiRegs[4] = {
// --------------+---+--------------------------------+--------------+------+
// Operand | S | Register Code | OperandId |Unused|
@@ -1006,7 +1000,7 @@ _Prepare:
// Check if one or more register operand is one of BPL, SPL, SIL, DIL and
// force a REX prefix in such case.
if (x86IsGpbRegOp(o0)) {
if (X86Util::isGpbRegOp(*o0)) {
uint32_t index = static_cast<const X86Reg*>(o0)->getRegIndex();
if (static_cast<const X86Reg*>(o0)->isGpbLo()) {
opX |= (index >= 4) << kRexShift;
@@ -1017,7 +1011,7 @@ _Prepare:
}
}
if (x86IsGpbRegOp(o1)) {
if (X86Util::isGpbRegOp(*o1)) {
uint32_t index = static_cast<const X86Reg*>(o1)->getRegIndex();
if (static_cast<const X86Reg*>(o1)->isGpbLo()) {
opX |= (index >= 4) << kRexShift;
@@ -1509,6 +1503,37 @@ _Prepare:
}
break;
case kInstGroupX86Jecxz:
if (encoded == ENC_OPS(Reg, Label, None)) {
ASMJIT_ASSERT(static_cast<const X86Reg*>(o0)->getRegIndex() == kRegIndexCx);
if ((Arch == kArchX86 && o0->getSize() == 2) ||
Arch == kArchX64 && o0->getSize() == 4) {
EMIT_BYTE(0x67);
}
EMIT_BYTE(0xE3);
label = self->getLabelDataById(static_cast<const Label*>(o1)->getId());
if (label->offset != -1) {
// Bound label.
intptr_t offs = label->offset - (intptr_t)(cursor - self->_buffer) - 1;
if (!IntUtil::isInt8(offs))
goto _IllegalInst;
EMIT_BYTE(offs);
goto _EmitDone;
}
else {
// Non-bound label.
dispOffset = -1;
dispSize = 1;
relocId = -1;
goto _EmitDisplacement;
}
}
break;
case kInstGroupX86Jmp:
if (encoded == ENC_OPS(Reg, None, None)) {
rmReg = static_cast<const GpReg*>(o0)->getRegIndex();
@@ -3371,19 +3396,25 @@ _EmitAvxRvm:
// --------------------------------------------------------------------------
_IllegalInst:
self->setError(kErrorAssemblerIllegalInst);
self->setError(kErrorIllegalInst);
#if defined(ASMJIT_DEBUG)
assertIllegal = true;
#endif // ASMJIT_DEBUG
goto _EmitDone;
_IllegalAddr:
self->setError(kErrorAssemblerIllegalAddr);
self->setError(kErrorIllegalAddresing);
#if defined(ASMJIT_DEBUG)
assertIllegal = true;
#endif // ASMJIT_DEBUG
goto _EmitDone;
_IllegalDisp:
self->setError(kErrorIllegalDisplacement);
#if defined(ASMJIT_DEBUG)
assertIllegal = true;
#endif // ASMJIT_DEBUG
goto _EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86]
@@ -3623,7 +3654,7 @@ _EmitSib:
// Indexing is invalid.
if (mIndex < kInvalidReg)
goto _IllegalAddr;
goto _IllegalDisp;
EMIT_BYTE(x86EncodeMod(0, opReg, 5));
dispOffset -= (4 + imLen);
@@ -4067,7 +4098,7 @@ _EmitDone:
_UnknownInst:
self->_comment = NULL;
return self->setError(kErrorAssemblerUnknownInst);
return self->setError(kErrorUnknownInst);
_GrowBuffer:
ASMJIT_PROPAGATE_ERROR(self->_grow(16));

File diff suppressed because it is too large Load Diff

View File

@@ -78,7 +78,7 @@ static Error X86X64Compiler_emitConstPool(X86X64Compiler* self,
if (label.getId() == kInvalidValue)
return kErrorOk;
self->align(static_cast<uint32_t>(pool.getAlignment()));
self->align(kAlignData, static_cast<uint32_t>(pool.getAlignment()));
self->bind(label);
EmbedNode* embedNode = self->embed(NULL, static_cast<uint32_t>(pool.getSize()));
@@ -656,8 +656,8 @@ Error X86X64Compiler::serialize(BaseAssembler& assembler) {
X86X64Context context(this);
Error error = kErrorOk;
BaseNode* node = _firstNode;
BaseNode* start;
Node* node = _firstNode;
Node* start;
// Find function and use the context to translate/emit.
do {

File diff suppressed because it is too large Load Diff

View File

@@ -78,10 +78,10 @@ void X86X64Context::reset() {
_clobberedRegs.reset();
_stackFrameCell = NULL;
_gaRegs[kRegClassGp] = IntUtil::bits(_baseRegsCount) & ~IntUtil::mask(kRegIndexSp);
_gaRegs[kRegClassFp] = IntUtil::bits(kRegCountFp);
_gaRegs[kRegClassMm] = IntUtil::bits(kRegCountMm);
_gaRegs[kRegClassXy] = IntUtil::bits(_baseRegsCount);
_gaRegs[kRegClassGp ] = IntUtil::bits(_baseRegsCount) & ~IntUtil::mask(kRegIndexSp);
_gaRegs[kRegClassFp ] = IntUtil::bits(kRegCountFp);
_gaRegs[kRegClassMm ] = IntUtil::bits(kRegCountMm);
_gaRegs[kRegClassXyz] = IntUtil::bits(_baseRegsCount);
_argBaseReg = kInvalidReg; // Used by patcher.
_varBaseReg = kInvalidReg; // Used by patcher.
@@ -142,6 +142,10 @@ static const X86X64SpecialInst x86SpecialInstDiv[] = {
{ kInvalidReg, kInvalidReg, kVarAttrInReg }
};
static const X86X64SpecialInst x86SpecialInstJecxz[] = {
{ kRegIndexCx, kInvalidReg, kVarAttrInReg }
};
static const X86X64SpecialInst x86SpecialInstMul[] = {
{ kInvalidReg, kRegIndexDx, kVarAttrOutReg },
{ kRegIndexAx, kRegIndexAx, kVarAttrInOutReg },
@@ -240,6 +244,9 @@ static ASMJIT_INLINE const X86X64SpecialInst* X86X64SpecialInst_get(uint32_t cod
case kInstDas:
return x86SpecialInstDaaDas;
case kInstJecxz:
return x86SpecialInstJecxz;
case kInstIdiv:
case kInstDiv:
return x86SpecialInstDiv;
@@ -384,7 +391,7 @@ void X86X64Context::emitLoad(VarData* vd, uint32_t regIndex, const char* reason)
X86X64Compiler* compiler = getCompiler();
Mem m = getVarMem(vd);
BaseNode* node = NULL;
Node* node = NULL;
bool comment = _emitComments;
switch (vd->getType()) {
@@ -465,7 +472,7 @@ void X86X64Context::emitSave(VarData* vd, uint32_t regIndex, const char* reason)
X86X64Compiler* compiler = getCompiler();
Mem m = getVarMem(vd);
BaseNode* node = NULL;
Node* node = NULL;
bool comment = _emitComments;
switch (vd->getType()) {
@@ -546,7 +553,7 @@ void X86X64Context::emitMove(VarData* vd, uint32_t toRegIndex, uint32_t fromRegI
X86X64Compiler* compiler = getCompiler();
BaseNode* node = NULL;
Node* node = NULL;
bool comment = _emitComments;
switch (vd->getType()) {
@@ -615,7 +622,7 @@ void X86X64Context::emitSwapGp(VarData* aVd, VarData* bVd, uint32_t aIndex, uint
X86X64Compiler* compiler = getCompiler();
BaseNode* node = NULL;
Node* node = NULL;
bool comment = _emitComments;
#if defined(ASMJIT_BUILD_X64)
@@ -1161,8 +1168,8 @@ _Move32:
case kVarTypeInt64:
case kVarTypeUInt64:
// Move to GPD register will clear the HI-DWORD of GPQ register in 64-bit
// mode.
// Move to Gpd register will clear also high DWORD of Gpq register in
// 64-bit mode.
if (imm.isUInt32())
goto _Move32Truncate;
@@ -1226,9 +1233,9 @@ static ASMJIT_INLINE void X86X64Context_checkStateVars(X86X64Context* self) {
}
void X86X64Context::_checkState() {
X86X64Context_checkStateVars<kRegClassGp>(this);
X86X64Context_checkStateVars<kRegClassMm>(this);
X86X64Context_checkStateVars<kRegClassXy>(this);
X86X64Context_checkStateVars<kRegClassGp >(this);
X86X64Context_checkStateVars<kRegClassMm >(this);
X86X64Context_checkStateVars<kRegClassXyz>(this);
}
#else
void X86X64Context::_checkState() {}
@@ -1270,9 +1277,9 @@ void X86X64Context::loadState(BaseVarState* src_) {
uint32_t vdCount = static_cast<uint32_t>(_contextVd.getLength());
// Load allocated variables.
X86X64Context_loadStateVars<kRegClassGp>(this, src);
X86X64Context_loadStateVars<kRegClassMm>(this, src);
X86X64Context_loadStateVars<kRegClassXy>(this, src);
X86X64Context_loadStateVars<kRegClassGp >(this, src);
X86X64Context_loadStateVars<kRegClassMm >(this, src);
X86X64Context_loadStateVars<kRegClassXyz>(this, src);
// Load masks.
cur->_occupied = src->_occupied;
@@ -1290,7 +1297,7 @@ void X86X64Context::loadState(BaseVarState* src_) {
vdArray[i]->setModified(false);
}
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// ============================================================================
@@ -1463,9 +1470,9 @@ void X86X64Context::switchState(BaseVarState* src_) {
return;
// Switch variables.
X86X64Context_switchStateVars<kRegClassGp>(this, src);
X86X64Context_switchStateVars<kRegClassMm>(this, src);
X86X64Context_switchStateVars<kRegClassXy>(this, src);
X86X64Context_switchStateVars<kRegClassGp >(this, src);
X86X64Context_switchStateVars<kRegClassMm >(this, src);
X86X64Context_switchStateVars<kRegClassXyz>(this, src);
// Calculate changed state.
VarData** vdArray = _contextVd.getData();
@@ -1483,7 +1490,7 @@ void X86X64Context::switchState(BaseVarState* src_) {
}
}
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// ============================================================================
@@ -1495,23 +1502,23 @@ void X86X64Context::intersectStates(BaseVarState* a_, BaseVarState* b_) {
VarState* bState = static_cast<VarState*>(b_);
// TODO: [COMPILER] Intersect states.
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// ============================================================================
// [asmjit::x86x64::X86X64Context - GetJccFlow / GetOppositeJccFlow]
// ============================================================================
//! @internal
static ASMJIT_INLINE BaseNode* X86X64Context_getJccFlow(JumpNode* jNode) {
//! \internal
static ASMJIT_INLINE Node* X86X64Context_getJccFlow(JumpNode* jNode) {
if (jNode->isTaken())
return jNode->getTarget();
else
return jNode->getNext();
}
//! @internal
static ASMJIT_INLINE BaseNode* X86X64Context_getOppositeJccFlow(JumpNode* jNode) {
//! \internal
static ASMJIT_INLINE Node* X86X64Context_getOppositeJccFlow(JumpNode* jNode) {
if (jNode->isTaken())
return jNode->getNext();
else
@@ -1522,7 +1529,7 @@ static ASMJIT_INLINE BaseNode* X86X64Context_getOppositeJccFlow(JumpNode* jNode)
// [asmjit::x86x64::X86X64Context - SingleVarInst]
// ============================================================================
//! @internal
//! \internal
static void X86X64Context_prepareSingleVarInst(uint32_t code, VarAttr* va) {
switch (code) {
// - andn reg, reg ; Set all bits in reg to 0.
@@ -1555,11 +1562,11 @@ static void X86X64Context_prepareSingleVarInst(uint32_t code, VarAttr* va) {
// [asmjit::x86x64::X86X64Context - Helpers]
// ============================================================================
//! @internal
//! \internal
//!
//! Add unreachable-flow data to the unreachable flow list.
static ASMJIT_INLINE Error X86X64Context_addUnreachableNode(X86X64Context* self, BaseNode* node) {
PodList<BaseNode*>::Link* link = self->_baseZone.allocT<PodList<BaseNode*>::Link>();
static ASMJIT_INLINE Error X86X64Context_addUnreachableNode(X86X64Context* self, Node* node) {
PodList<Node*>::Link* link = self->_baseZone.allocT<PodList<Node*>::Link>();
if (link == NULL)
return self->setError(kErrorNoHeapMemory);
@@ -1569,11 +1576,11 @@ static ASMJIT_INLINE Error X86X64Context_addUnreachableNode(X86X64Context* self,
return kErrorOk;
}
//! @internal
//! \internal
//!
//! Add jump-flow data to the jcc flow list.
static ASMJIT_INLINE Error X86X64Context_addJccNode(X86X64Context* self, BaseNode* node) {
PodList<BaseNode*>::Link* link = self->_baseZone.allocT<PodList<BaseNode*>::Link>();
static ASMJIT_INLINE Error X86X64Context_addJccNode(X86X64Context* self, Node* node) {
PodList<Node*>::Link* link = self->_baseZone.allocT<PodList<Node*>::Link>();
if (link == NULL)
ASMJIT_PROPAGATE_ERROR(self->setError(kErrorNoHeapMemory));
@@ -1584,7 +1591,7 @@ static ASMJIT_INLINE Error X86X64Context_addJccNode(X86X64Context* self, BaseNod
return kErrorOk;
}
//! @internal
//! \internal
//!
//! Get mask of all registers actually used to pass function arguments.
static ASMJIT_INLINE RegMask X86X64Context_getUsedArgs(X86X64Context* self, X86X64CallNode* node, X86X64FuncDecl* decl) {
@@ -1813,7 +1820,7 @@ static ASMJIT_INLINE Error X86X64Context_insertSArgNode(
// [asmjit::x86x64::X86X64Context - Fetch]
// ============================================================================
//! @internal
//! \internal
//!
//! Prepare the given function `func`.
//!
@@ -1826,9 +1833,9 @@ Error X86X64Context::fetch() {
uint32_t arch = compiler->getArch();
BaseNode* node_ = func;
BaseNode* next = NULL;
BaseNode* stop = getStop();
Node* node_ = func;
Node* next = NULL;
Node* stop = getStop();
uint32_t groupId = 1;
uint32_t flowId = 0;
@@ -1836,7 +1843,7 @@ Error X86X64Context::fetch() {
VarAttr vaTmpList[80];
SArgData sArgList[80];
PodList<BaseNode*>::Link* jLink = NULL;
PodList<Node*>::Link* jLink = NULL;
// Function flags.
func->clearFuncFlags(
@@ -1913,7 +1920,7 @@ Error X86X64Context::fetch() {
else if (va->_outRegIndex != kInvalidReg) \
va->_allocableRegs = IntUtil::mask(va->_outRegIndex); \
else \
va->_allocableRegs &= ~inRegs._regs[class_]; \
va->_allocableRegs &= ~inRegs.get(class_); \
\
vd->_va = NULL; \
vi->getVa(index)[0] = va[0]; \
@@ -2001,10 +2008,10 @@ _NextGroup:
uint32_t remain[kRegClassCount];
HintNode* cur = node;
remain[kRegClassGp] = _baseRegsCount - 1 - func->hasFuncFlag(kFuncFlagIsNaked);
remain[kRegClassFp] = kRegCountFp;
remain[kRegClassMm] = kRegCountMm;
remain[kRegClassXy] = _baseRegsCount;
remain[kRegClassGp ] = _baseRegsCount - 1 - func->hasFuncFlag(kFuncFlagIsNaked);
remain[kRegClassFp ] = kRegCountFp;
remain[kRegClassMm ] = kRegCountMm;
remain[kRegClassXyz] = _baseRegsCount;
// Merge as many alloc-hints as possible.
for (;;) {
@@ -2020,14 +2027,14 @@ _NextGroup:
regMask = IntUtil::mask(regIndex);
if (va == NULL) {
if ((inRegs._regs[regClass] & regMask) != 0)
if (inRegs.has(regClass, regMask))
break;
if (remain[regClass] == 0)
break;
VI_ADD_VAR(vd, va, kVarAttrInReg, gaRegs[regClass]);
if (regMask != 0) {
inRegs._regs[regClass] ^= static_cast<uint16_t>(regMask);
inRegs.xor_(regClass, regMask);
va->setInRegs(regMask);
va->setInRegIndex(regIndex);
}
@@ -2035,10 +2042,10 @@ _NextGroup:
remain[regClass]--;
}
else if (regMask != 0) {
if ((inRegs._regs[regClass] & regMask) != 0 && va->getInRegs() != regMask)
if (inRegs.has(regClass, regMask) && va->getInRegs() != regMask)
break;
inRegs._regs[regClass] ^= static_cast<uint16_t>(va->getInRegs() | regMask);
inRegs.xor_(regClass, va->getInRegs() | regMask);
va->setInRegs(regMask);
va->setInRegIndex(regIndex);
}
@@ -2160,7 +2167,7 @@ _NextGroup:
if (static_cast<const X86Reg*>(op)->isGp())
c = kRegClassGp;
else
c = kRegClassXy;
c = kRegClassXyz;
if (inReg != kInvalidReg) {
uint32_t mask = IntUtil::mask(inReg);
@@ -2316,7 +2323,7 @@ _NextGroup:
if (node->isJmpOrJcc()) {
JumpNode* jNode = static_cast<JumpNode*>(node);
BaseNode* jNext = jNode->getNext();
Node* jNext = jNode->getNext();
TargetNode* jTarget = jNode->getTarget();
// If this jump is unconditional we put next node to unreachable node
@@ -2378,7 +2385,7 @@ _NextGroup:
// Overlapped function arguments.
if (vd->getVa() != NULL)
return compiler->setError(kErrorCompilerOverlappedArgs);
return compiler->setError(kErrorOverlappedArgs);
VI_ADD_VAR(vd, va, 0, 0);
uint32_t aType = arg.getVarType();
@@ -2575,10 +2582,10 @@ _NextGroup:
}
// Init clobbered.
clobberedRegs.set(kRegClassGp, IntUtil::bits(_baseRegsCount) & (~decl->getPreserved(kRegClassGp)));
clobberedRegs.set(kRegClassFp, IntUtil::bits(kRegCountFp ) );
clobberedRegs.set(kRegClassMm, IntUtil::bits(kRegCountMm ) & (~decl->getPreserved(kRegClassMm)));
clobberedRegs.set(kRegClassXy, IntUtil::bits(_baseRegsCount) & (~decl->getPreserved(kRegClassXy)));
clobberedRegs.set(kRegClassGp , IntUtil::bits(_baseRegsCount) & (~decl->getPreserved(kRegClassGp )));
clobberedRegs.set(kRegClassFp , IntUtil::bits(kRegCountFp ));
clobberedRegs.set(kRegClassMm , IntUtil::bits(kRegCountMm ) & (~decl->getPreserved(kRegClassMm )));
clobberedRegs.set(kRegClassXyz, IntUtil::bits(_baseRegsCount) & (~decl->getPreserved(kRegClassXyz)));
VI_END(node_);
break;
@@ -2606,7 +2613,7 @@ _NoMemory:
// [asmjit::x86x64::X86X64Context - Analyze]
// ============================================================================
//! @internal
//! \internal
struct LivenessTarget {
//! Previous target.
LivenessTarget* prev;
@@ -2620,7 +2627,7 @@ struct LivenessTarget {
Error X86X64Context::analyze() {
FuncNode* func = getFunc();
BaseNode* node = func->getEnd();
Node* node = func->getEnd();
JumpNode* from = NULL;
uint32_t bLen = static_cast<uint32_t>(
@@ -2905,8 +2912,8 @@ static bool X86X64Context_annotateInstruction(X86X64Context* self,
Error X86X64Context::annotate() {
FuncNode* func = getFunc();
BaseNode* node_ = func;
BaseNode* end = func->getEnd();
Node* node_ = func;
Node* end = func->getEnd();
Zone& sa = _compiler->_stringZone;
StringBuilderT<128> sb;
@@ -2958,7 +2965,7 @@ struct X86X64BaseAlloc {
ASMJIT_INLINE VarState* getState() const { return _context->getState(); }
//! Get the node.
ASMJIT_INLINE BaseNode* getNode() const { return _node; }
ASMJIT_INLINE Node* getNode() const { return _node; }
//! Get VarAttr list (all).
ASMJIT_INLINE VarAttr* getVaList() const { return _vaList[0]; }
@@ -2990,7 +2997,7 @@ struct X86X64BaseAlloc {
protected:
// Just to prevent calling these methods by X86X64Context::translate().
ASMJIT_INLINE void init(BaseNode* node, VarInst* vi);
ASMJIT_INLINE void init(Node* node, VarInst* vi);
ASMJIT_INLINE void cleanup();
// --------------------------------------------------------------------------
@@ -3013,7 +3020,7 @@ protected:
X86X64Compiler* _compiler;
//! Node.
BaseNode* _node;
Node* _node;
//! Variable instructions.
VarInst* _vi;
@@ -3033,7 +3040,7 @@ protected:
// [asmjit::x86x64::X86X64BaseAlloc - Init / Cleanup]
// ============================================================================
ASMJIT_INLINE void X86X64BaseAlloc::init(BaseNode* node, VarInst* vi) {
ASMJIT_INLINE void X86X64BaseAlloc::init(Node* node, VarInst* vi) {
_node = node;
_vi = vi;
@@ -3045,10 +3052,10 @@ ASMJIT_INLINE void X86X64BaseAlloc::init(BaseNode* node, VarInst* vi) {
// Setup the lists of variables.
{
VarAttr* va = vi->getVaList();
_vaList[kRegClassGp] = va;
_vaList[kRegClassFp] = va + vi->getVaStart(kRegClassFp);
_vaList[kRegClassMm] = va + vi->getVaStart(kRegClassMm);
_vaList[kRegClassXy] = va + vi->getVaStart(kRegClassXy);
_vaList[kRegClassGp ] = va;
_vaList[kRegClassFp ] = va + vi->getVaStart(kRegClassFp );
_vaList[kRegClassMm ] = va + vi->getVaStart(kRegClassMm );
_vaList[kRegClassXyz] = va + vi->getVaStart(kRegClassXyz);
}
// Setup counters.
@@ -3118,7 +3125,7 @@ ASMJIT_INLINE void X86X64BaseAlloc::unuseAfter() {
// [asmjit::x86x64::X86X64VarAlloc]
// ============================================================================
//! @internal
//! \internal
//!
//! Register allocator context (asm instructions).
struct X86X64VarAlloc : public X86X64BaseAlloc {
@@ -3133,7 +3140,7 @@ struct X86X64VarAlloc : public X86X64BaseAlloc {
// [Run]
// --------------------------------------------------------------------------
ASMJIT_INLINE Error run(BaseNode* node);
ASMJIT_INLINE Error run(Node* node);
// --------------------------------------------------------------------------
// [Init / Cleanup]
@@ -3142,7 +3149,7 @@ struct X86X64VarAlloc : public X86X64BaseAlloc {
protected:
// Just to prevent calling these methods by X86X64Context::translate().
ASMJIT_INLINE void init(BaseNode* node, VarInst* vi);
ASMJIT_INLINE void init(Node* node, VarInst* vi);
ASMJIT_INLINE void cleanup();
// --------------------------------------------------------------------------
@@ -3198,7 +3205,7 @@ protected:
// [asmjit::X86X64VarAlloc - Run]
// ============================================================================
ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) {
ASMJIT_INLINE Error X86X64VarAlloc::run(Node* node_) {
// Initialize.
VarInst* vi = node_->getVarInst<VarInst>();
if (vi == NULL)
@@ -3208,25 +3215,25 @@ ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) {
init(node_, vi);
// Unuse overwritten variables.
unuseBefore<kRegClassGp>();
unuseBefore<kRegClassMm>();
unuseBefore<kRegClassXy>();
unuseBefore<kRegClassGp >();
unuseBefore<kRegClassMm >();
unuseBefore<kRegClassXyz>();
// Plan the allocation. Planner assigns input/output registers for each
// variable and decides whether to allocate it in register or stack.
plan<kRegClassGp>();
plan<kRegClassMm>();
plan<kRegClassXy>();
plan<kRegClassGp >();
plan<kRegClassMm >();
plan<kRegClassXyz>();
// Spill all variables marked by plan().
spill<kRegClassGp>();
spill<kRegClassMm>();
spill<kRegClassXy>();
spill<kRegClassGp >();
spill<kRegClassMm >();
spill<kRegClassXyz>();
// Alloc all variables marked by plan().
alloc<kRegClassGp>();
alloc<kRegClassMm>();
alloc<kRegClassXy>();
alloc<kRegClassGp >();
alloc<kRegClassMm >();
alloc<kRegClassXyz>();
// Translate node operands.
if (node_->getType() == kNodeTypeInst) {
@@ -3271,9 +3278,9 @@ ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) {
}
// Mark variables as modified.
modified<kRegClassGp>();
modified<kRegClassMm>();
modified<kRegClassXy>();
modified<kRegClassGp >();
modified<kRegClassMm >();
modified<kRegClassXyz>();
// Cleanup; disconnect Vd->Va.
cleanup();
@@ -3283,9 +3290,9 @@ ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) {
_context->_clobberedRegs.add(vi->_clobberedRegs);
// Unuse.
unuseAfter<kRegClassGp>();
unuseAfter<kRegClassMm>();
unuseAfter<kRegClassXy>();
unuseAfter<kRegClassGp >();
unuseAfter<kRegClassMm >();
unuseAfter<kRegClassXyz>();
return kErrorOk;
}
@@ -3294,7 +3301,7 @@ ASMJIT_INLINE Error X86X64VarAlloc::run(BaseNode* node_) {
// [asmjit::x86x64::X86X64VarAlloc - Init / Cleanup]
// ============================================================================
ASMJIT_INLINE void X86X64VarAlloc::init(BaseNode* node, VarInst* vi) {
ASMJIT_INLINE void X86X64VarAlloc::init(Node* node, VarInst* vi) {
X86X64BaseAlloc::init(node, vi);
// These will block planner from assigning them during planning. Planner will
@@ -3663,7 +3670,7 @@ ASMJIT_INLINE uint32_t X86X64VarAlloc::guessAlloc(VarData* vd, uint32_t allocabl
uint32_t maxLookAhead = _compiler->getMaxLookAhead();
// Look ahead and calculate mask of special registers on both - input/output.
BaseNode* node = _node;
Node* node = _node;
for (i = 0; i < maxLookAhead; i++) {
// Stop on 'RetNode' and 'EndNode.
if (node->hasFlag(kNodeFlagIsRet))
@@ -3743,7 +3750,7 @@ ASMJIT_INLINE void X86X64VarAlloc::modified() {
// [asmjit::x86x64::X86X64CallAlloc]
// ============================================================================
//! @internal
//! \internal
//!
//! Register allocator context (function call).
struct X86X64CallAlloc : public X86X64BaseAlloc {
@@ -3858,33 +3865,33 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) {
// Plan register allocation. Planner is only able to assign one register per
// variable. If any variable is used multiple times it will be handled later.
plan<kRegClassGp>();
plan<kRegClassMm>();
plan<kRegClassXy>();
plan<kRegClassGp >();
plan<kRegClassMm >();
plan<kRegClassXyz>();
// Spill.
spill<kRegClassGp>();
spill<kRegClassMm>();
spill<kRegClassXy>();
spill<kRegClassGp >();
spill<kRegClassMm >();
spill<kRegClassXyz>();
// Alloc.
alloc<kRegClassGp>();
alloc<kRegClassMm>();
alloc<kRegClassXy>();
alloc<kRegClassGp >();
alloc<kRegClassMm >();
alloc<kRegClassXyz>();
// Unuse clobbered registers that are not used to pass function arguments and
// save variables used to pass function arguments that will be reused later on.
save<kRegClassGp>();
save<kRegClassMm>();
save<kRegClassXy>();
save<kRegClassGp >();
save<kRegClassMm >();
save<kRegClassXyz>();
// Allocate immediates in registers and on the stack.
allocImmsOnStack();
// Duplicate.
duplicate<kRegClassGp>();
duplicate<kRegClassMm>();
duplicate<kRegClassXy>();
duplicate<kRegClassGp >();
duplicate<kRegClassMm >();
duplicate<kRegClassXyz>();
// Translate call operand.
ASMJIT_PROPAGATE_ERROR(X86X64Context_translateOperands(_context, &node->_target, 1));
@@ -3899,17 +3906,17 @@ ASMJIT_INLINE Error X86X64CallAlloc::run(X86X64CallNode* node) {
}
// Clobber.
clobber<kRegClassGp>();
clobber<kRegClassMm>();
clobber<kRegClassXy>();
clobber<kRegClassGp >();
clobber<kRegClassMm >();
clobber<kRegClassXyz>();
// Return.
ret();
// Unuse.
unuseAfter<kRegClassGp>();
unuseAfter<kRegClassMm>();
unuseAfter<kRegClassXy>();
unuseAfter<kRegClassGp >();
unuseAfter<kRegClassMm >();
unuseAfter<kRegClassXyz>();
// Cleanup; disconnect Vd->Va.
cleanup();
@@ -4253,7 +4260,7 @@ ASMJIT_INLINE uint32_t X86X64CallAlloc::guessAlloc(VarData* vd, uint32_t allocab
uint32_t maxLookAhead = _compiler->getMaxLookAhead();
// Look ahead and calculate mask of special registers on both - input/output.
BaseNode* node = _node;
Node* node = _node;
for (i = 0; i < maxLookAhead; i++) {
// Stop on 'RetNode' and 'EndNode.
if (node->hasFlag(kNodeFlagIsRet))
@@ -4392,10 +4399,10 @@ ASMJIT_INLINE void X86X64CallAlloc::ret() {
_context->unuse<kRegClassMm>(vd);
_context->attach<kRegClassMm>(vd, regIndex, true);
break;
case kRegClassXy:
case kRegClassXyz:
if (vd->getRegIndex() != kInvalidReg)
_context->unuse<kRegClassXy>(vd);
_context->attach<kRegClassXy>(vd, regIndex, true);
_context->unuse<kRegClassXyz>(vd);
_context->attach<kRegClassXyz>(vd, regIndex, true);
break;
}
}
@@ -4405,7 +4412,7 @@ ASMJIT_INLINE void X86X64CallAlloc::ret() {
// [asmjit::x86x64::X86X64Context - TranslateOperands]
// ============================================================================
//! @internal
//! \internal
static Error X86X64Context_translateOperands(X86X64Context* self, Operand* opList, uint32_t opCount) {
X86X64Compiler* compiler = self->getCompiler();
const VarInfo* varInfo = _varInfo;
@@ -4460,7 +4467,7 @@ static Error X86X64Context_translateOperands(X86X64Context* self, Operand* opLis
// [asmjit::x86x64::X86X64Context - TranslatePrologEpilog]
// ============================================================================
//! @internal
//! \internal
static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) {
X86X64Compiler* compiler = self->getCompiler();
X86X64FuncDecl* decl = func->getDecl();
@@ -4469,10 +4476,10 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) {
uint32_t regSize = compiler->getRegSize();
// Setup "Save-Restore" registers.
func->_saveRestoreRegs.set(kRegClassGp, clobberedRegs.get(kRegClassGp) & decl->getPreserved(kRegClassGp));
func->_saveRestoreRegs.set(kRegClassFp, 0 );
func->_saveRestoreRegs.set(kRegClassMm, clobberedRegs.get(kRegClassMm) & decl->getPreserved(kRegClassMm));
func->_saveRestoreRegs.set(kRegClassXy, clobberedRegs.get(kRegClassXy) & decl->getPreserved(kRegClassXy));
func->_saveRestoreRegs.set(kRegClassGp , clobberedRegs.get(kRegClassGp ) & decl->getPreserved(kRegClassGp ));
func->_saveRestoreRegs.set(kRegClassFp , 0);
func->_saveRestoreRegs.set(kRegClassMm , clobberedRegs.get(kRegClassMm ) & decl->getPreserved(kRegClassMm ));
func->_saveRestoreRegs.set(kRegClassXyz, clobberedRegs.get(kRegClassXyz) & decl->getPreserved(kRegClassXyz));
ASMJIT_ASSERT(!func->_saveRestoreRegs.has(kRegClassGp, IntUtil::mask(kRegIndexSp)));
@@ -4484,7 +4491,7 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) {
// Require 16-byte alignment if 8-byte vars are used.
if (self->_mem8ByteVarsUsed)
requiredStackAlignment = 16;
else if (func->_saveRestoreRegs.get(kRegClassMm) || func->_saveRestoreRegs.get(kRegClassXy))
else if (func->_saveRestoreRegs.get(kRegClassMm) || func->_saveRestoreRegs.get(kRegClassXyz))
requiredStackAlignment = 16;
else if (IntUtil::inInterval<uint32_t>(func->getRequiredStackAlignment(), 8, 16))
requiredStackAlignment = 16;
@@ -4580,9 +4587,9 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) {
// Setup stack size used to save preserved registers.
{
uint32_t memGpSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassGp)) * regSize;
uint32_t memMmSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassMm)) * 8;
uint32_t memXmmSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassXy)) * 16;
uint32_t memGpSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassGp )) * regSize;
uint32_t memMmSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassMm )) * 8;
uint32_t memXmmSize = IntUtil::bitCount(func->_saveRestoreRegs.get(kRegClassXyz)) * 16;
if (func->hasFuncFlag(kFuncFlagPushPop)) {
func->_pushPopStackSize = memGpSize;
@@ -4663,10 +4670,10 @@ static Error X86X64Context_initFunc(X86X64Context* self, X86X64FuncNode* func) {
return kErrorOk;
}
//! @internal
static Error X86X64Context_patchFuncMem(X86X64Context* self, X86X64FuncNode* func, BaseNode* stop) {
//! \internal
static Error X86X64Context_patchFuncMem(X86X64Context* self, X86X64FuncNode* func, Node* stop) {
X86X64Compiler* compiler = self->getCompiler();
BaseNode* node = func;
Node* node = func;
do {
if (node->getType() == kNodeTypeInst) {
@@ -4702,7 +4709,7 @@ static Error X86X64Context_patchFuncMem(X86X64Context* self, X86X64FuncNode* fun
return kErrorOk;
}
//! @internal
//! \internal
static Error X86X64Context_translatePrologEpilog(X86X64Context* self, X86X64FuncNode* func) {
X86X64Compiler* compiler = self->getCompiler();
X86X64FuncDecl* decl = func->getDecl();
@@ -4733,9 +4740,9 @@ static Error X86X64Context_translatePrologEpilog(X86X64Context* self, X86X64Func
}
uint32_t i, mask;
uint32_t regsGp = func->getSaveRestoreRegs(kRegClassGp);
uint32_t regsMm = func->getSaveRestoreRegs(kRegClassMm);
uint32_t regsXmm = func->getSaveRestoreRegs(kRegClassXy);
uint32_t regsGp = func->getSaveRestoreRegs(kRegClassGp );
uint32_t regsMm = func->getSaveRestoreRegs(kRegClassMm );
uint32_t regsXmm = func->getSaveRestoreRegs(kRegClassXyz);
bool earlyPushPop = false;
bool useLeaEpilog = false;
@@ -4966,10 +4973,10 @@ static Error X86X64Context_translatePrologEpilog(X86X64Context* self, X86X64Func
// [asmjit::x86x64::X86X64Context - Translate - Jump]
// ============================================================================
//! @internal
//! \internal
static void X86X64Context_translateJump(X86X64Context* self, JumpNode* jNode, TargetNode* jTarget) {
X86X64Compiler* compiler = self->getCompiler();
BaseNode* extNode = self->getExtraBlock();
Node* extNode = self->getExtraBlock();
// TODO: [COMPILER] State Change.
compiler->_setCursor(extNode);
@@ -5003,7 +5010,7 @@ static void X86X64Context_translateJump(X86X64Context* self, JumpNode* jNode, Ta
// ============================================================================
static Error X86X64Context_translateRet(X86X64Context* self, RetNode* rNode, TargetNode* exitTarget) {
BaseNode* node = rNode->getNext();
Node* node = rNode->getNext();
while (node != NULL) {
switch (node->getType()) {
@@ -5061,11 +5068,11 @@ Error X86X64Context::translate() {
X86X64CallAlloc cAlloc(this);
// Flow.
BaseNode* node_ = func;
BaseNode* next = NULL;
BaseNode* stop = getStop();
Node* node_ = func;
Node* next = NULL;
Node* stop = getStop();
PodList<BaseNode*>::Link* jLink = _jccList.getFirst();
PodList<Node*>::Link* jLink = _jccList.getFirst();
for (;;) {
while (node_->isTranslated()) {
@@ -5084,7 +5091,7 @@ _NextGroup:
node_ = jLink->getValue();
jLink = jLink->getNext();
BaseNode* jFlow = X86X64Context_getOppositeJccFlow(static_cast<JumpNode*>(node_));
Node* jFlow = X86X64Context_getOppositeJccFlow(static_cast<JumpNode*>(node_));
loadState(node_->getState());
if (jFlow->getState()) {
@@ -5180,7 +5187,7 @@ _NextGroup:
}
}
else {
BaseNode* jNext = node->getNext();
Node* jNext = node->getNext();
if (jTarget->isTranslated()) {
if (jNext->isTranslated()) {
@@ -5245,9 +5252,9 @@ _NextGroup:
uint32_t regIndex = va->getOutRegIndex();
if (regIndex != kInvalidReg && (va->getFlags() & kVarAttrOutConv) == 0) {
switch (vd->getClass()) {
case kRegClassGp: attach<kRegClassGp>(vd, regIndex, true); break;
case kRegClassMm: attach<kRegClassMm>(vd, regIndex, true); break;
case kRegClassXy: attach<kRegClassXy>(vd, regIndex, true); break;
case kRegClassGp : attach<kRegClassGp >(vd, regIndex, true); break;
case kRegClassMm : attach<kRegClassMm >(vd, regIndex, true); break;
case kRegClassXyz: attach<kRegClassXyz>(vd, regIndex, true); break;
}
}
else if (va->hasFlag(kVarAttrOutConv)) {
@@ -5294,8 +5301,8 @@ _Done:
// ============================================================================
template<int LoggingEnabled>
static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64Assembler* assembler, BaseNode* start, BaseNode* stop) {
BaseNode* node_ = start;
static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64Assembler* assembler, Node* start, Node* stop) {
Node* node_ = start;
StringBuilder& sb = self->_stringBuilder;
Logger* logger;
@@ -5365,7 +5372,7 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As
switch (node_->getType()) {
case kNodeTypeAlign: {
AlignNode* node = static_cast<AlignNode*>(node_);
assembler->align(node->getSize());
assembler->align(node->getMode(), node->getOffset());
break;
}
@@ -5562,7 +5569,7 @@ static ASMJIT_INLINE Error X86X64Context_serialize(X86X64Context* self, X86X64As
return kErrorOk;
}
Error X86X64Context::serialize(BaseAssembler* assembler, BaseNode* start, BaseNode* stop) {
Error X86X64Context::serialize(BaseAssembler* assembler, Node* start, Node* stop) {
if (!assembler->hasLogger())
return X86X64Context_serialize<0>(this, static_cast<X86X64Assembler*>(assembler), start, stop);
else

View File

@@ -14,7 +14,6 @@
#include "../base/intutil.h"
#include "../x86/x86assembler.h"
#include "../x86/x86compiler.h"
#include "../x86/x86defs.h"
// [Api-Begin]
#include "../apibegin.h"
@@ -22,14 +21,20 @@
namespace asmjit {
namespace x86x64 {
//! @addtogroup asmjit_x86x64_codegen
//! @{
// ============================================================================
// [asmjit::Context]
// ============================================================================
//! @internal
#if defined(ASMJIT_DEBUG)
# define ASMJIT_X86_CHECK_STATE _checkState();
#else
# define ASMJIT_X86_CHECK_STATE
#endif // ASMJIT_DEBUG
//! \addtogroup asmjit_x86x64_tree
//! \{
//! \internal
//!
//! Compiler context is used by `X86X64Compiler`.
//!
@@ -110,14 +115,8 @@ struct X86X64Context : public BaseContext {
void _checkState();
#if defined(ASMJIT_DEBUG)
#define ASMJIT_CONTEXT_CHECK_STATE _checkState();
#else
#define ASMJIT_CONTEXT_CHECK_STATE
#endif // ASMJIT_DEBUG
ASMJIT_INLINE uint32_t getRegsCount(uint32_t c) const {
if (c == kRegClassGp || c == kRegClassXy)
if (c == kRegClassGp || c == kRegClassXyz)
return _baseRegsCount;
else
return 8;
@@ -154,7 +153,7 @@ struct X86X64Context : public BaseContext {
_x86State._occupied.add(C, regMask);
_x86State._modified.add(C, static_cast<uint32_t>(modified) << regIndex);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
//! Detach.
@@ -178,7 +177,7 @@ struct X86X64Context : public BaseContext {
_x86State._occupied.del(C, regMask);
_x86State._modified.del(C, regMask);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -206,7 +205,7 @@ struct X86X64Context : public BaseContext {
_x86State._occupied.xor_(C, bothRegMask);
_x86State._modified.xor_(C, bothRegMask & -static_cast<int32_t>(vd->isModified()));
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -227,7 +226,7 @@ struct X86X64Context : public BaseContext {
emitLoad(vd, regIndex, "Load");
attach<C>(vd, regIndex, false);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
//! Save.
@@ -247,7 +246,7 @@ struct X86X64Context : public BaseContext {
vd->setModified(false);
_x86State._modified.del(C, regMask);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -270,7 +269,7 @@ struct X86X64Context : public BaseContext {
rebase<C>(vd, regIndex, oldIndex);
}
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
//! Swap two registers
@@ -301,7 +300,7 @@ struct X86X64Context : public BaseContext {
uint32_t m = aVd->isModified() ^ bVd->isModified();
_x86State._modified.xor_(kRegClassGp, (m << aIndex) | (m << bIndex));
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -332,7 +331,7 @@ struct X86X64Context : public BaseContext {
regMask ^= IntUtil::mask(oldRegIndex);
}
else {
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
return;
}
@@ -343,7 +342,7 @@ struct X86X64Context : public BaseContext {
_x86State._occupied.xor_(C, regMask);
_x86State._modified.xor_(C, regMask & -static_cast<int32_t>(vd->isModified()));
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
//! Spill.
@@ -354,7 +353,7 @@ struct X86X64Context : public BaseContext {
ASMJIT_ASSERT(vd->getClass() == C);
if (vd->getState() != kVarStateReg) {
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
return;
}
@@ -367,7 +366,7 @@ struct X86X64Context : public BaseContext {
emitSave(vd, regIndex, "Spill");
detach<C>(vd, regIndex, kVarStateMem);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -384,7 +383,7 @@ struct X86X64Context : public BaseContext {
vd->setModified(true);
_x86State._modified.add(C, regMask);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -406,7 +405,7 @@ struct X86X64Context : public BaseContext {
else
vd->setState(vState);
ASMJIT_CONTEXT_CHECK_STATE
ASMJIT_X86_CHECK_STATE
}
// --------------------------------------------------------------------------
@@ -459,7 +458,7 @@ struct X86X64Context : public BaseContext {
// [Serialize]
// --------------------------------------------------------------------------
virtual Error serialize(BaseAssembler* assembler, BaseNode* start, BaseNode* stop);
virtual Error serialize(BaseAssembler* assembler, Node* start, Node* stop);
// --------------------------------------------------------------------------
// [Members]
@@ -507,7 +506,7 @@ struct X86X64Context : public BaseContext {
StringBuilderT<256> _stringBuilder;
};
//! @}
//! \}
} // x86x64 namespace
} // asmjit namespace

View File

@@ -37,15 +37,11 @@ struct CpuVendor {
};
static const CpuVendor cpuVendorTable[] = {
{ kCpuVendorAmd , { 'A', 'M', 'D', 'i', 's', 'b', 'e', 't', 't', 'e', 'r', '!' } },
{ kCpuVendorAmd , { 'A', 'u', 't', 'h', 'e', 'n', 't', 'i', 'c', 'A', 'M', 'D' } },
{ kCpuVendorVia , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } },
{ kCpuVendorNSM , { 'C', 'y', 'r', 'i', 'x', 'I', 'n', 's', 't', 'e', 'a', 'd' } },
{ kCpuVendorIntel , { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'I', 'n', 't', 'e', 'l' } },
{ kCpuVendorTransmeta, { 'G', 'e', 'n', 'u', 'i', 'n', 'e', 'T', 'M', 'x', '8', '6' } },
{ kCpuVendorNSM , { 'G', 'e', 'o', 'd', 'e', ' ', 'b', 'y', ' ', 'N', 'S', 'C' } },
{ kCpuVendorTransmeta, { 'T', 'r', 'a', 'n', 's', 'm', 'e', 't', 'a', 'C', 'P', 'U' } },
{ kCpuVendorVia , { 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 , 'V', 'I', 'A', 0 } }
{ 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 , { 'C', 'e', 'n', 't', 'a', 'u', 'r', 'H', 'a', 'u', 'l', 's' } }
};
static ASMJIT_INLINE bool cpuVendorEq(const CpuVendor& info, const char* vendorString) {
@@ -162,7 +158,7 @@ void CpuUtil::detect(CpuInfo* cpuInfo) {
::memcpy(cpuInfo->_vendorString + 4, &regs.edx, 4);
::memcpy(cpuInfo->_vendorString + 8, &regs.ecx, 4);
for (i = 0; i < 3; i++) {
for (i = 0; i < ASMJIT_ARRAY_SIZE(cpuVendorTable); i++) {
if (cpuVendorEq(cpuVendorTable[i], cpuInfo->_vendorString)) {
cpuInfo->_vendorId = cpuVendorTable[i].id;
break;

View File

@@ -10,7 +10,6 @@
// [Dependencies - AsmJit]
#include "../base/cpuinfo.h"
#include "../base/defs.h"
// [Api-Begin]
#include "../apibegin.h"
@@ -18,15 +17,15 @@
namespace asmjit {
namespace x86x64 {
//! @addtogroup asmjit_x86x64_cpu_info
//! @{
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct CpuInfo;
//! \addtogroup asmjit_x86x64_general
//! \{
// ============================================================================
// [asmjit::x86x64::kCpuFeature]
// ============================================================================
@@ -221,7 +220,7 @@ struct CpuInfo : public BaseCpuInfo {
uint32_t _maxLogicalProcessors;
};
//! @}
//! \}
} // x86x64 namespace
} // asmjit namespace

View File

@@ -2169,7 +2169,7 @@ struct InstInfo {
//!
//! Move instructions overwrite the first operand or at least part of it,
//! This is a very useful hint that is used by variable liveness analysis
//! and `BaseCompiler` in general to know which variable is completely
//! and `BaseCompiler` in general to know which variable is completely
//! overwritten.
//!
//! All AVX/XOP instructions that have 3 or more operands are considered to

View File

@@ -15,8 +15,8 @@
#include "../base/globals.h"
#include "../base/intutil.h"
#include "../base/string.h"
#include "../x86/x86defs.h"
#include "../x86/x86func.h"
#include "../x86/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
@@ -46,6 +46,13 @@ static ASMJIT_INLINE uint32_t x86ArgTypeToXmmType(uint32_t aType) {
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]
// ============================================================================
@@ -147,44 +154,44 @@ static uint32_t X86X64FuncDecl_initConv(X86X64FuncDecl* self, uint32_t arch, uin
case kFuncConvX64W:
self->_spillZoneSize = 32;
self->_passed.set(kRegClassGp, IntUtil::mask(R(Cx), R(Dx), R(R8), R(R9)));
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] = R(R8);
self->_passedOrderGp[3] = R(R9);
self->_passedOrderGp[2] = 8;
self->_passedOrderGp[3] = 9;
self->_passed.set(kRegClassXy, IntUtil::mask(R(Xmm0), R(Xmm1), R(Xmm2), R(Xmm3)));
self->_passedOrderXmm[0] = R(Xmm0);
self->_passedOrderXmm[1] = R(Xmm1);
self->_passedOrderXmm[2] = R(Xmm2);
self->_passedOrderXmm[3] = R(Xmm3);
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), R(R12), R(R13), R(R14), R(R15)));
self->_preserved.set(kRegClassXy, IntUtil::mask(R(Xmm6), R(Xmm7), R(Xmm8), R(Xmm9), R(Xmm10), R(Xmm11), R(Xmm12), R(Xmm13), R(Xmm14), R(Xmm15)));
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), R(R8), R(R9)));
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] = R(R8);
self->_passedOrderGp[5] = R(R9);
self->_passedOrderGp[4] = 8;
self->_passedOrderGp[5] = 9;
self->_passed.set(kRegClassXy, IntUtil::mask(R(Xmm0), R(Xmm1), R(Xmm2), R(Xmm3), R(Xmm4), R(Xmm5), R(Xmm6), R(Xmm7)));
self->_passedOrderXmm[0] = R(Xmm0);
self->_passedOrderXmm[1] = R(Xmm1);
self->_passedOrderXmm[2] = R(Xmm2);
self->_passedOrderXmm[3] = R(Xmm3);
self->_passedOrderXmm[4] = R(Xmm4);
self->_passedOrderXmm[5] = R(Xmm5);
self->_passedOrderXmm[6] = R(Xmm6);
self->_passedOrderXmm[7] = R(Xmm7);
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), R(R12), R(R13), R(R14), R(R15)));
self->_preserved.set(kRegClassGp, IntUtil::mask(R(Bx), R(Sp), R(Bp), 12, 13, 14, 15));
break;
default:
@@ -271,18 +278,18 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
case kVarTypeMm:
self->_retCount = 1;
self->_retList[0]._varType = static_cast<uint8_t>(ret);
self->_retList[0]._regIndex = kRegIndexMm0;
self->_retList[0]._regIndex = 0;
break;
case kVarTypeFp32:
self->_retCount = 1;
if (arch == kArchX86) {
self->_retList[0]._varType = kVarTypeFp32;
self->_retList[0]._regIndex = kRegIndexFp0;
self->_retList[0]._regIndex = 0;
}
else {
self->_retList[0]._varType = kVarTypeXmmSs;
self->_retList[0]._regIndex = kRegIndexXmm0;
self->_retList[0]._regIndex = 0;
}
break;
@@ -290,11 +297,11 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
self->_retCount = 1;
if (arch == kArchX86) {
self->_retList[0]._varType = kVarTypeFp64;
self->_retList[0]._regIndex = kRegIndexFp0;
self->_retList[0]._regIndex = 0;
}
else {
self->_retList[0]._varType = kVarTypeXmmSd;
self->_retList[0]._regIndex = kRegIndexXmm0;
self->_retList[0]._regIndex = 0;
break;
}
break;
@@ -306,7 +313,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
case kVarTypeXmmPd:
self->_retCount = 1;
self->_retList[0]._varType = static_cast<uint8_t>(ret);
self->_retList[0]._regIndex = kRegIndexXmm0;
self->_retList[0]._regIndex = 0;
break;
}
}
@@ -381,7 +388,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
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(kRegClassXy, IntUtil::mask(arg.getRegIndex()));
self->_used.add(kRegClassXyz, IntUtil::mask(arg.getRegIndex()));
}
}
@@ -430,7 +437,7 @@ static Error X86X64FuncDecl_initFunc(X86X64FuncDecl* self, uint32_t arch,
if (x86ArgIsFp(varType)) {
arg._varType = static_cast<uint8_t>(x86ArgTypeToXmmType(varType));
arg._regIndex = self->_passedOrderXmm[xmmPos++];
self->_used.add(kRegClassXy, IntUtil::mask(arg.getRegIndex()));
self->_used.add(kRegClassXyz, IntUtil::mask(arg.getRegIndex()));
}
}

View File

@@ -9,9 +9,8 @@
#define _ASMJIT_X86_X86FUNC_H
// [Dependencies - AsmJit]
#include "../base/defs.h"
#include "../base/func.h"
#include "../x86/x86defs.h"
#include "../x86/x86util.h"
// [Api-Begin]
#include "../apibegin.h"
@@ -19,8 +18,8 @@
namespace asmjit {
namespace x86x64 {
//! @addtogroup asmjit_x86x64_codegen
//! @{
//! \addtogroup asmjit_x86x64_tree
//! \{
// ============================================================================
// [asmjit::x86x64::kFuncConv]
@@ -83,8 +82,8 @@ ASMJIT_ENUM(kFuncConv) {
//! - Caller.
//!
//! Return value:
//! - Integer types - RAX register.
//! - Floating points - XMM0 register.
//! - Integer types - Rax register.
//! - Floating points - Xmm0 register.
//!
//! Stack is always aligned by 16 bytes.
//!
@@ -109,8 +108,8 @@ ASMJIT_ENUM(kFuncConv) {
//! - Caller.
//!
//! Return value:
//! - Integer types - RAX register.
//! - Floating points - XMM0 register.
//! - Integer types - Rax register.
//! - Floating points - Xmm0 register.
//!
//! Stack is always aligned by 16 bytes.
kFuncConvX64U = 2,
@@ -165,7 +164,7 @@ ASMJIT_ENUM(kFuncConv) {
//! 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,
//! \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,
@@ -184,7 +183,7 @@ ASMJIT_ENUM(kFuncConv) {
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! @note This calling convention differs to GCC one in stack cleaning
//! \note This calling convention differs to GCC one in stack cleaning
//! mechanism.
kFuncConvMsFastCall = 6,
@@ -203,7 +202,7 @@ ASMJIT_ENUM(kFuncConv) {
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! @note Arguments on the stack are in left-to-right order that differs
//! \note Arguments on the stack are in left-to-right order that differs
//! to other fastcall conventions used in different compilers.
kFuncConvBorlandFastCall = 7,
@@ -222,7 +221,7 @@ ASMJIT_ENUM(kFuncConv) {
//! - Integer types - EAX:EDX registers.
//! - Floating points - fp0 register.
//!
//! @note This calling convention should be compatible with `kFuncConvMsFastCall`.
//! \note This calling convention should be compatible with `kFuncConvMsFastCall`.
kFuncConvGccFastCall = 8,
//! GCC specific regparm(1) convention.
@@ -273,7 +272,7 @@ ASMJIT_ENUM(kFuncConv) {
//! - Floating points - fp0 register.
kFuncConvGccRegParm3 = 11,
//! @internal
//! \internal
//!
//! Count of function calling conventions.
_kFuncConvCount = 12,
@@ -282,55 +281,51 @@ ASMJIT_ENUM(kFuncConv) {
// [Host]
// --------------------------------------------------------------------------
//! @def kFuncConvHost
#if defined(ASMJIT_DOCGEN)
//! Default calling convention for current platform / operating system.
kFuncConvHost = DependsOnHost,
//! @def kFuncConvHostCDecl
//! Default C calling convention based on current compiler's settings.
kFuncConvHostCDecl = DependsOnHost,
//! @def kFuncConvHostStdCall
//! Compatibility for `__stdcall` calling convention.
//!
//! @note This enumeration is always set to a value which is compatible with
//! \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,
//! @def kFuncConvHostFastCall
//! Compatibility for `__fastcall` calling convention.
//!
//! @note This enumeration is always set to a value which is compatible with
//! \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`.
#if defined(ASMJIT_HOST_X86)
kFuncConvHostFastCall = DependsOnHost
#elif defined(ASMJIT_HOST_X86)
// X86.
kFuncConvHost = kFuncConvCDecl,
kFuncConvHostCDecl = kFuncConvCDecl,
kFuncConvHostStdCall = kFuncConvStdCall,
# if defined(_MSC_VER)
#if defined(_MSC_VER)
kFuncConvHostFastCall = kFuncConvMsFastCall
# elif defined(__GNUC__)
#elif defined(__GNUC__)
kFuncConvHostFastCall = kFuncConvGccFastCall
# elif defined(__BORLANDC__)
#elif defined(__BORLANDC__)
kFuncConvHostFastCall = kFuncConvBorlandFastCall
# else
# error "asmjit/x86/x86func.h - asmjit::kFuncConvHostFastCall not supported."
# endif
#else
# if defined(ASMJIT_OS_WINDOWS)
#error "kFuncConvHostFastCall not determined."
#endif
#else
// X64.
#if defined(ASMJIT_OS_WINDOWS)
kFuncConvHost = kFuncConvX64W,
# else
#else
kFuncConvHost = kFuncConvX64U,
# endif
#endif
kFuncConvHostCDecl = kFuncConvHost,
kFuncConvHostStdCall = kFuncConvHost,
kFuncConvHostFastCall = kFuncConvHost
#endif // ASMJIT_HOST
#endif
};
// ============================================================================
@@ -385,17 +380,6 @@ ASMJIT_ENUM(kFuncFlags) {
kFuncFlagLFence = 0x04000000
};
// ============================================================================
// [asmjit::x86x64::x86GetArchFromCConv]
// ============================================================================
//! Get architecture by a 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::x86x64::X86X64FuncDecl]
// ============================================================================
@@ -418,7 +402,7 @@ struct X86X64FuncDecl : public FuncDecl {
//! Get used registers (mask).
//!
//! @note The result depends on the function calling convention AND the
//! \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 {
@@ -427,7 +411,7 @@ struct X86X64FuncDecl : public FuncDecl {
//! Get passed registers (mask).
//!
//! @note The result depends on the function calling convention used; the
//! \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);
@@ -435,7 +419,7 @@ struct X86X64FuncDecl : public FuncDecl {
//! Get preserved registers (mask).
//!
//! @note The result depends on the function calling convention used; the
//! \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);
@@ -443,7 +427,7 @@ struct X86X64FuncDecl : public FuncDecl {
//! Get ther order of passed registers (Gp).
//!
//! @note The result depends on the function calling convention used; the
//! \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;
@@ -451,7 +435,7 @@ struct X86X64FuncDecl : public FuncDecl {
//! Get ther order of passed registers (Xmm).
//!
//! @note The result depends on the function calling convention used; the
//! \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;
@@ -465,7 +449,7 @@ struct X86X64FuncDecl : public FuncDecl {
//!
//! This will set function calling convention and setup arguments variables.
//!
//! @note This function will allocate variables, it can be called only once.
//! \note This function will allocate variables, it can be called only once.
ASMJIT_API Error setPrototype(uint32_t conv, const FuncPrototype& p);
// --------------------------------------------------------------------------
@@ -492,7 +476,7 @@ struct X86X64FuncDecl : public FuncDecl {
uint8_t _passedOrderXmm[8];
};
//! @}
//! \}
} // x86x64 namespace
} // asmjit namespace

File diff suppressed because it is too large Load Diff

1837
src/asmjit/x86/x86inst.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,338 @@
// [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/x86operand.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
namespace x86x64 {
// ============================================================================
// [asmjit::x86x64::Variables]
// ============================================================================
#define C(_Class_) kRegClass##_Class_
#define D(_Desc_) kVarDesc##_Desc_
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::x86x64::Registers]
// ============================================================================
const GpReg noGpReg(kInvalidReg, kInvalidReg, 0);
const GpReg al(kRegTypeGpbLo, kRegIndexAx, 1);
const GpReg cl(kRegTypeGpbLo, kRegIndexCx, 1);
const GpReg dl(kRegTypeGpbLo, kRegIndexDx, 1);
const GpReg bl(kRegTypeGpbLo, kRegIndexBx, 1);
const GpReg spl(kRegTypeGpbLo, kRegIndexSp, 1);
const GpReg bpl(kRegTypeGpbLo, kRegIndexBp, 1);
const GpReg sil(kRegTypeGpbLo, kRegIndexSi, 1);
const GpReg dil(kRegTypeGpbLo, kRegIndexDi, 1);
const GpReg r8b(kRegTypeGpbLo, 8, 1);
const GpReg r9b(kRegTypeGpbLo, 9, 1);
const GpReg r10b(kRegTypeGpbLo, 10, 1);
const GpReg r11b(kRegTypeGpbLo, 11, 1);
const GpReg r12b(kRegTypeGpbLo, 12, 1);
const GpReg r13b(kRegTypeGpbLo, 13, 1);
const GpReg r14b(kRegTypeGpbLo, 14, 1);
const GpReg r15b(kRegTypeGpbLo, 15, 1);
const GpReg ah(kRegTypeGpbHi, kRegIndexAx, 1);
const GpReg ch(kRegTypeGpbHi, kRegIndexCx, 1);
const GpReg dh(kRegTypeGpbHi, kRegIndexDx, 1);
const GpReg bh(kRegTypeGpbHi, kRegIndexBx, 1);
const GpReg ax(kRegTypeGpw, kRegIndexAx, 2);
const GpReg cx(kRegTypeGpw, kRegIndexCx, 2);
const GpReg dx(kRegTypeGpw, kRegIndexDx, 2);
const GpReg bx(kRegTypeGpw, kRegIndexBx, 2);
const GpReg sp(kRegTypeGpw, kRegIndexSp, 2);
const GpReg bp(kRegTypeGpw, kRegIndexBp, 2);
const GpReg si(kRegTypeGpw, kRegIndexSi, 2);
const GpReg di(kRegTypeGpw, kRegIndexDi, 2);
const GpReg r8w(kRegTypeGpw, 8, 2);
const GpReg r9w(kRegTypeGpw, 9, 2);
const GpReg r10w(kRegTypeGpw, 10, 2);
const GpReg r11w(kRegTypeGpw, 11, 2);
const GpReg r12w(kRegTypeGpw, 12, 2);
const GpReg r13w(kRegTypeGpw, 13, 2);
const GpReg r14w(kRegTypeGpw, 14, 2);
const GpReg r15w(kRegTypeGpw, 15, 2);
const GpReg eax(kRegTypeGpd, kRegIndexAx, 4);
const GpReg ecx(kRegTypeGpd, kRegIndexCx, 4);
const GpReg edx(kRegTypeGpd, kRegIndexDx, 4);
const GpReg ebx(kRegTypeGpd, kRegIndexBx, 4);
const GpReg esp(kRegTypeGpd, kRegIndexSp, 4);
const GpReg ebp(kRegTypeGpd, kRegIndexBp, 4);
const GpReg esi(kRegTypeGpd, kRegIndexSi, 4);
const GpReg edi(kRegTypeGpd, kRegIndexDi, 4);
const GpReg r8d(kRegTypeGpd, 8, 4);
const GpReg r9d(kRegTypeGpd, 9, 4);
const GpReg r10d(kRegTypeGpd, 10, 4);
const GpReg r11d(kRegTypeGpd, 11, 4);
const GpReg r12d(kRegTypeGpd, 12, 4);
const GpReg r13d(kRegTypeGpd, 13, 4);
const GpReg r14d(kRegTypeGpd, 14, 4);
const GpReg r15d(kRegTypeGpd, 15, 4);
const GpReg rax(kRegTypeGpq, kRegIndexAx, 8);
const GpReg rcx(kRegTypeGpq, kRegIndexCx, 8);
const GpReg rdx(kRegTypeGpq, kRegIndexDx, 8);
const GpReg rbx(kRegTypeGpq, kRegIndexBx, 8);
const GpReg rsp(kRegTypeGpq, kRegIndexSp, 8);
const GpReg rbp(kRegTypeGpq, kRegIndexBp, 8);
const GpReg rsi(kRegTypeGpq, kRegIndexSi, 8);
const GpReg rdi(kRegTypeGpq, kRegIndexDi, 8);
const GpReg r8(kRegTypeGpq, 8, 8);
const GpReg r9(kRegTypeGpq, 9, 8);
const GpReg r10(kRegTypeGpq, 10, 8);
const GpReg r11(kRegTypeGpq, 11, 8);
const GpReg r12(kRegTypeGpq, 12, 8);
const GpReg r13(kRegTypeGpq, 13, 8);
const GpReg r14(kRegTypeGpq, 14, 8);
const GpReg r15(kRegTypeGpq, 15, 8);
const FpReg fp0(kRegTypeFp, 0, 10);
const FpReg fp1(kRegTypeFp, 1, 10);
const FpReg fp2(kRegTypeFp, 2, 10);
const FpReg fp3(kRegTypeFp, 3, 10);
const FpReg fp4(kRegTypeFp, 4, 10);
const FpReg fp5(kRegTypeFp, 5, 10);
const FpReg fp6(kRegTypeFp, 6, 10);
const FpReg fp7(kRegTypeFp, 7, 10);
const MmReg mm0(kRegTypeMm, 0, 8);
const MmReg mm1(kRegTypeMm, 1, 8);
const MmReg mm2(kRegTypeMm, 2, 8);
const MmReg mm3(kRegTypeMm, 3, 8);
const MmReg mm4(kRegTypeMm, 4, 8);
const MmReg mm5(kRegTypeMm, 5, 8);
const MmReg mm6(kRegTypeMm, 6, 8);
const MmReg mm7(kRegTypeMm, 7, 8);
const XmmReg xmm0(kRegTypeXmm, 0, 16);
const XmmReg xmm1(kRegTypeXmm, 1, 16);
const XmmReg xmm2(kRegTypeXmm, 2, 16);
const XmmReg xmm3(kRegTypeXmm, 3, 16);
const XmmReg xmm4(kRegTypeXmm, 4, 16);
const XmmReg xmm5(kRegTypeXmm, 5, 16);
const XmmReg xmm6(kRegTypeXmm, 6, 16);
const XmmReg xmm7(kRegTypeXmm, 7, 16);
const XmmReg xmm8(kRegTypeXmm, 8, 16);
const XmmReg xmm9(kRegTypeXmm, 9, 16);
const XmmReg xmm10(kRegTypeXmm, 10, 16);
const XmmReg xmm11(kRegTypeXmm, 11, 16);
const XmmReg xmm12(kRegTypeXmm, 12, 16);
const XmmReg xmm13(kRegTypeXmm, 13, 16);
const XmmReg xmm14(kRegTypeXmm, 14, 16);
const XmmReg xmm15(kRegTypeXmm, 15, 16);
const YmmReg ymm0(kRegTypeYmm, 0, 32);
const YmmReg ymm1(kRegTypeYmm, 1, 32);
const YmmReg ymm2(kRegTypeYmm, 2, 32);
const YmmReg ymm3(kRegTypeYmm, 3, 32);
const YmmReg ymm4(kRegTypeYmm, 4, 32);
const YmmReg ymm5(kRegTypeYmm, 5, 32);
const YmmReg ymm6(kRegTypeYmm, 6, 32);
const YmmReg ymm7(kRegTypeYmm, 7, 32);
const YmmReg ymm8(kRegTypeYmm, 8, 32);
const YmmReg ymm9(kRegTypeYmm, 9, 32);
const YmmReg ymm10(kRegTypeYmm, 10, 32);
const YmmReg ymm11(kRegTypeYmm, 11, 32);
const YmmReg ymm12(kRegTypeYmm, 12, 32);
const YmmReg ymm13(kRegTypeYmm, 13, 32);
const YmmReg ymm14(kRegTypeYmm, 14, 32);
const YmmReg ymm15(kRegTypeYmm, 15, 32);
const SegReg cs(kRegTypeSeg, kSegCs, 2);
const SegReg ss(kRegTypeSeg, kSegSs, 2);
const SegReg ds(kRegTypeSeg, kSegDs, 2);
const SegReg es(kRegTypeSeg, kSegEs, 2);
const SegReg fs(kRegTypeSeg, kSegFs, 2);
const SegReg gs(kRegTypeSeg, kSegGs, 2);
// ============================================================================
// [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._vmem.index = kInvalidValue;
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
Mem ptr_abs(Ptr pAbs, const X86Reg& index, uint32_t shift, int32_t disp, uint32_t size) {
Mem m(NoInit);
uint32_t flags = shift << kMemShiftIndex;
if (index.isGp()) flags |= Mem::_getGpdFlags(reinterpret_cast<const BaseVar&>(index));
if (index.isXmm()) flags |= kMemVSibXmm << kMemVSibIndex;
if (index.isYmm()) flags |= kMemVSibYmm << kMemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index.getRegIndex();
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
Mem ptr_abs(Ptr pAbs, const X86Var& index, uint32_t shift, int32_t disp, uint32_t size) {
Mem m(NoInit);
uint32_t flags = shift << kMemShiftIndex;
if (index.isGp()) flags |= Mem::_getGpdFlags(reinterpret_cast<const BaseVar&>(index));
if (index.isXmm()) flags |= kMemVSibXmm << kMemVSibIndex;
if (index.isYmm()) flags |= kMemVSibYmm << kMemVSibIndex;
m._init_packed_op_sz_b0_b1_id(kOperandTypeMem, size, kMemTypeAbsolute, flags, kInvalidValue);
m._vmem.index = index.getId();
m._vmem.displacement = static_cast<int32_t>((intptr_t)(pAbs + disp));
return m;
}
} // 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
};
const GpReg zax(kRegTypeGpd, kRegIndexAx, 4);
const GpReg zcx(kRegTypeGpd, kRegIndexCx, 4);
const GpReg zdx(kRegTypeGpd, kRegIndexDx, 4);
const GpReg zbx(kRegTypeGpd, kRegIndexBx, 4);
const GpReg zsp(kRegTypeGpd, kRegIndexSp, 4);
const GpReg zbp(kRegTypeGpd, kRegIndexBp, 4);
const GpReg zsi(kRegTypeGpd, kRegIndexSi, 4);
const GpReg zdi(kRegTypeGpd, kRegIndexDi, 4);
} // x86 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X86
// ============================================================================
// [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
};
const GpReg zax(kRegTypeGpq, kRegIndexAx, 8);
const GpReg zcx(kRegTypeGpq, kRegIndexCx, 8);
const GpReg zdx(kRegTypeGpq, kRegIndexDx, 8);
const GpReg zbx(kRegTypeGpq, kRegIndexBx, 8);
const GpReg zsp(kRegTypeGpq, kRegIndexSp, 8);
const GpReg zbp(kRegTypeGpq, kRegIndexBp, 8);
const GpReg zsi(kRegTypeGpq, kRegIndexSi, 8);
const GpReg zdi(kRegTypeGpq, kRegIndexDi, 8);
} // x64 namespace
} // asmjit namespace
#endif // ASMJIT_BUILD_X64
#include "../apiend.h"
// [Guard]
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64

1988
src/asmjit/x86/x86operand.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,90 @@
// [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::Cond]
// ============================================================================
#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

369
src/asmjit/x86/x86util.h Normal file
View File

@@ -0,0 +1,369 @@
// [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 {
//! 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 {
//! 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];
}
//! 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);
}
//! Pack a shuffle constant to be used with multimedia instrutions.
//!
//! \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 uint32_t mmShuffle(uint32_t z, uint32_t y, uint32_t x, uint32_t w) {
return (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,408 +0,0 @@
# Doxyfile 1.8.7
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
DOXYFILE_ENCODING = UTF-8
PROJECT_NAME = "AsmJit"
PROJECT_NUMBER = "1.1"
PROJECT_BRIEF = "Complete Remote and JIT Assembler for x86/x64"
OUTPUT_DIRECTORY = .
CREATE_SUBDIRS = NO
ALLOW_UNICODE_NAMES = NO
OUTPUT_LANGUAGE = English
# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
# descriptions after the members that are listed in the file and class
# documentation (similar to Javadoc). Set to NO to disable this.
# The default value is: YES.
BRIEF_MEMBER_DESC = YES
# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
# description of a member or function before the detailed description
#
# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
# The default value is: YES.
REPEAT_BRIEF = YES
# This tag implements a quasi-intelligent brief description abbreviator that is
# used to form the text in various listings. Each string in this list, if found
# as the leading text of the brief description, will be stripped from the text
# and the result, after processing the whole list, is used as the annotated
# text. Otherwise, the brief description is used as-is. If left blank, the
# following values are used ($name is automatically replaced with the name of
# the entity):The $name class, The $name widget, The $name file, is, provides,
# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
# doxygen will generate a detailed section even if there is only a brief
# description.
# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
# The default value is: NO.
INLINE_INHERITED_MEMB = NO
# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
# before files name in the file list and in the header files. If set to NO the
# shortest path that makes the file name unique will be used
# The default value is: YES.
FULL_PATH_NAMES = YES
# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
# Stripping is only done if one of the specified strings matches the left-hand
# part of the path. The tag can be used to show relative paths in the file list.
# If left blank the directory from which doxygen is run is used as the path to
# strip.
#
# Note that you can specify absolute paths here, but also relative paths, which
# will be relative from the directory where doxygen is started.
# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
# path mentioned in the documentation of a class, which tells the reader which
# header file to include in order to use a class. If left blank only the name of
# the header file containing the class definition is used. Otherwise one should
# specify the list of include paths that are normally passed to the compiler
# using the -I flag.
STRIP_FROM_INC_PATH =
# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
# less readable) file names. This can be useful is your file systems doesn't
# support long names like on DOS, Mac, or CD-ROM.
# The default value is: NO.
SHORT_NAMES = NO
# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
# first line (until the first dot) of a Javadoc-style comment as the brief
# description. If set to NO, the Javadoc-style will behave just like regular Qt-
# style comments (thus requiring an explicit @brief command for a brief
# description.)
# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
# line (until the first dot) of a Qt-style comment as the brief description. If
# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
# requiring an explicit \brief command for a brief description.)
# The default value is: NO.
QT_AUTOBRIEF = NO
# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
# a brief description. This used to be the default behavior. The new default is
# to treat a multi-line C++ comment block as a detailed description. Set this
# tag to YES if you prefer the old behavior instead.
#
# Note that setting this tag to YES also means that rational rose comments are
# not recognized any more.
# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
# documentation from any documented member that it re-implements.
# The default value is: YES.
INHERIT_DOCS = YES
# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
# new page for each member. If set to NO, the documentation of a member will be
# part of the file/class/namespace that contains it.
# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
TAB_SIZE = 2
MARKDOWN_SUPPORT = YES
AUTOLINK_SUPPORT = NO
IDL_PROPERTY_SUPPORT = NO
# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
# Set the SUBGROUPING tag to YES to allow class member groups of the same type
# (for instance a group of public functions) to be put as a subgroup of that
# type (e.g. under the Public Functions section). Set it to NO to prevent
# subgrouping. Alternatively, this can be done per class using the
# \nosubgrouping command.
# The default value is: YES.
SUBGROUPING = YES
# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
# are shown inside the group in which they are included (e.g. using \ingroup)
# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
# and RTF).
#
# Note that this feature does not work in combination with
# SEPARATE_MEMBER_PAGES.
# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
# with only public data fields or simple typedef fields will be shown inline in
# the documentation of the scope in which they are defined (i.e. file,
# namespace, or group documentation), provided this scope is documented. If set
# to NO, structs, classes, and unions are shown on a separate page (for HTML and
# Man pages) or section (for LaTeX and RTF).
# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
#---------------------------------------------------------------------------
# Build related configuration options
#---------------------------------------------------------------------------
EXTRACT_ALL = NO
EXTRACT_PRIVATE = NO
EXTRACT_PACKAGE = NO
EXTRACT_STATIC = NO
EXTRACT_LOCAL_CLASSES = NO
HIDE_UNDOC_CLASSES = YES
HIDE_FRIEND_COMPOUNDS = YES
HIDE_IN_BODY_DOCS = YES
INTERNAL_DOCS = NO
CASE_SENSE_NAMES = NO
# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
# their full class and namespace scopes in the documentation. If set to YES the
# scope will be hidden.
# The default value is: NO.
HIDE_SCOPE_NAMES = NO
SHOW_INCLUDE_FILES = NO
SHOW_GROUPED_MEMB_INC = NO
INLINE_INFO = YES
SORT_MEMBER_DOCS = NO
SORT_BRIEF_DOCS = NO
SORT_GROUP_NAMES = NO
SORT_BY_SCOPE_NAME = YES
STRICT_PROTO_MATCHING = NO
GENERATE_TODOLIST = NO
GENERATE_TESTLIST = NO
GENERATE_BUGLIST = NO
GENERATE_DEPRECATEDLIST= NO
MAX_INITIALIZER_LINES = 0
SHOW_USED_FILES = NO
SHOW_FILES = NO
SHOW_NAMESPACES = NO
#---------------------------------------------------------------------------
# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
QUIET = YES
WARNINGS = YES
WARN_IF_UNDOCUMENTED = NO
WARN_IF_DOC_ERROR = YES
WARN_NO_PARAMDOC = NO
WARN_FORMAT = "$file:$line: $text"
WARN_LOGFILE =
#---------------------------------------------------------------------------
# Configuration options related to the input files
#---------------------------------------------------------------------------
INPUT = ../src/asmjit
INPUT_ENCODING = UTF-8
RECURSIVE = YES
EXCLUDE =
USE_MDFILE_AS_MAINPAGE = ../README.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
#---------------------------------------------------------------------------
SOURCE_BROWSER = NO
INLINE_SOURCES = NO
STRIP_CODE_COMMENTS = YES
SOURCE_TOOLTIPS = YES
VERBATIM_HEADERS = NO
#---------------------------------------------------------------------------
# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
ALPHABETICAL_INDEX = NO
#---------------------------------------------------------------------------
# Configuration options related to the HTML output
#---------------------------------------------------------------------------
GENERATE_HTML = YES
GENERATE_LATEX = NO
GENERATE_RTF = NO
GENERATE_MAN = NO
HTML_OUTPUT = doc
HTML_FILE_EXTENSION = .html
LAYOUT_FILE = doc-layout.xml
HTML_HEADER = doc-header.html
HTML_FOOTER = doc-footer.html
HTML_STYLESHEET = doc-style.css
HTML_EXTRA_STYLESHEET =
HTML_EXTRA_FILES =
HTML_COLORSTYLE_HUE = 220
HTML_COLORSTYLE_SAT = 100
HTML_COLORSTYLE_GAMMA = 80
HTML_TIMESTAMP = NO
HTML_DYNAMIC_SECTIONS = NO
HTML_INDEX_NUM_ENTRIES = 0
SEARCHENGINE = NO
#---------------------------------------------------------------------------
# Configuration options related to the CHM output
#---------------------------------------------------------------------------
# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
# Windows.
#
# The HTML Help Workshop contains a compiler that can convert all HTML output
# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
# files are now used as the Windows 98 help format, and will replace the old
# Windows help format (.hlp) on all Windows platforms in the future. Compressed
# HTML files also contain an index, a table of contents, and you can search for
# words in the documentation. The HTML workshop also contains a viewer for
# compressed HTML files.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
# The CHM_FILE tag can be used to specify the file name of the resulting .chm
# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
# The HHC_LOCATION tag can be used to specify the location (absolute path
# including file name) of the HTML help compiler ( hhc.exe). If non-empty
# doxygen will try to run the HTML help compiler on the generated index.hhp.
# The file has to be specified with full path.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
# The BINARY_TOC flag controls whether a binary table of contents is generated (
# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
# enables the Previous and Next buttons.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
# The TOC_EXPAND flag can be set to YES to add extra items for group members to
# the table of contents of the HTML help documentation and to the tree view.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If you want full control over the layout of the generated HTML pages it might
# be necessary to disable the index and replace it with your own. The
# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
# of each HTML page. A value of NO enables the index and the value YES disables
# it. Since the tabs in the index contain the same information as the navigation
# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
# structure should be generated to display hierarchical information. If the tag
# value is set to YES, a side panel will be generated containing a tree-like
# index structure (just like the one that is generated for HTML Help). For this
# to work a browser that supports JavaScript, DHTML, CSS and frames is required
# (i.e. any modern browser). Windows users are probably better off using the
# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
# further fine-tune the look of the index. As an example, the default style
# sheet generated by doxygen has an example that shows how to put an image at
# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
# the same information as the tab index, you could consider setting
# DISABLE_INDEX to YES when enabling this option.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.
#
# Note that a value of 0 will completely suppress the enum values from appearing
# in the overview section.
# Minimum value: 0, maximum value: 20, default value: 4.
# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 0
# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
# to set the initial width (in pixels) of the frame in which the tree is shown.
# Minimum value: 0, maximum value: 1500, default value: 250.
# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 250
# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
# external symbols imported via tag files in a separate window.
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
#---------------------------------------------------------------------------
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
ENABLE_PREPROCESSING = YES
MACRO_EXPANSION = YES
EXPAND_ONLY_PREDEF = NO
PREDEFINED = ASMJIT_DOCGEN=1
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
CLASS_GRAPH = NO

View File

@@ -1,5 +1,5 @@
<!DOCTYPE html>
<html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>

View File

@@ -14,7 +14,6 @@
<class>
<briefdescription title=""/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<detaileddescription title=""/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
@@ -49,6 +48,7 @@
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
@@ -67,8 +67,8 @@
<!-- Layout definition for a group page -->
<group>
<briefdescription title=""/>
<groupgraph visible="$GROUP_GRAPHS"/>
<detaileddescription title=""/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
@@ -90,6 +90,7 @@
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
@@ -107,6 +108,5 @@
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
</doxygenlayout>

View File

@@ -531,18 +531,9 @@ table.memberdecls {
background-image:url('nav_g.png');
background-repeat:repeat-x;
background-color: #FFFFFF;
/* opera specific markup */
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
/* firefox specific markup */
-moz-border-radius-bottomleft: 4px;
-moz-border-radius-bottomright: 4px;
-moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
/* webkit specific markup */
-webkit-border-bottom-left-radius: 4px;
-webkit-border-bottom-right-radius: 4px;
-webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
/* box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15); */
}
dl.reflist dt {
@@ -827,11 +818,11 @@ table.fieldtable {
.fieldtable td.fieldname {
padding-top: 3px;
font-weight: bold;
}
.fieldtable td.fielddoc {
border-bottom: 1px solid #A8B8D9;
/*width: 100%;*/
}
.fieldtable td.fielddoc p:first-child {
@@ -966,8 +957,8 @@ dl {
/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
dl.section {
margin-left: 0px;
padding-left: 0px;
margin-left: 0;
padding-left: 0;
}
dl.note {
@@ -977,6 +968,10 @@ dl.note {
border-color: #D0C000;
}
dl.note dd {
margin-left: 0;
}
dl.warning, dl.attention {
margin-left:-7px;
padding-left: 3px;

View File

@@ -225,7 +225,7 @@ var main = function(files) {
main([
{
name: "../src/asmjit/x86/x86defs.cpp",
name: "../src/asmjit/x86/x86inst.cpp",
arch: "x86",
suffixes: [
"a", "ae",