"plugins/freeEnergy/vscode:/vscode.git/clone" did not exist on "6e543d20f6ebca800cdf7fa92e46a3240d1f8808"
Unverified Commit 6a021413 authored by Tristan Croll's avatar Tristan Croll Committed by GitHub
Browse files

Merge pull request #2 from pandegroup/master

Merge with latest OpenMM
parents 913410fc b9a1bee6
...@@ -157,7 +157,7 @@ ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE) ...@@ -157,7 +157,7 @@ ENDIF (NOT CMAKE_CXX_FLAGS_RELEASE)
SET(OPENMM_LIBRARY_NAME OpenMM) SET(OPENMM_LIBRARY_NAME OpenMM)
SET(OPENMM_MAJOR_VERSION 7) SET(OPENMM_MAJOR_VERSION 7)
SET(OPENMM_MINOR_VERSION 3) SET(OPENMM_MINOR_VERSION 4)
SET(OPENMM_BUILD_VERSION 0) SET(OPENMM_BUILD_VERSION 0)
ADD_DEFINITIONS(-DOPENMM_LIBRARY_NAME=${OPENMM_LIBRARY_NAME} ADD_DEFINITIONS(-DOPENMM_LIBRARY_NAME=${OPENMM_LIBRARY_NAME}
......
...@@ -851,7 +851,7 @@ by the user. That is, the interaction energy of each angle is given by ...@@ -851,7 +851,7 @@ by the user. That is, the interaction energy of each angle is given by
where :math:`f(\theta)` is a user defined mathematical expression. The angle where :math:`f(\theta)` is a user defined mathematical expression. The angle
:math:`\theta` is guaranteed to be in the range [-π, π]. Like PeriodicTorsionForce, it :math:`\theta` is guaranteed to be in the range :math:`[-\pi, +\pi]`\ . Like PeriodicTorsionForce, it
is defined to be zero when the first and last particles are on the same side of is defined to be zero when the first and last particles are on the same side of
the bond formed by the middle two particles (the *cis* configuration). the bond formed by the middle two particles (the *cis* configuration).
...@@ -973,7 +973,7 @@ of four particles. That is, the interaction energy of each bond is given by ...@@ -973,7 +973,7 @@ of four particles. That is, the interaction energy of each bond is given by
where *f*\ (\ *...*\ ) is a user defined mathematical expression. It may where *f*\ (\ *...*\ ) is a user defined mathematical expression. It may
depend on an arbitrary set of positions {\ :math:`x_i`\ }, distances {\ :math:`r_i`\ }, depend on an arbitrary set of positions {\ :math:`x_i`\ }, distances {\ :math:`r_i`\ },
angles {\ :math:`\theta_i`\ }, and dihedral angles {\ :math:`\phi_i`\ } angles {\ :math:`\theta_i`\ }, and dihedral angles {\ :math:`\phi_i`\ }
guaranteed to be in the range [-π, π]. guaranteed to be in the range :math:`[-\pi, +\pi]`\ .
Each distance, angle, or dihedral is defined by specifying a sequence of Each distance, angle, or dihedral is defined by specifying a sequence of
particles chosen from among the particles that make up the bond. A distance particles chosen from among the particles that make up the bond. A distance
...@@ -1209,7 +1209,7 @@ The following operators are supported: + (add), - (subtract), * (multiply), / ...@@ -1209,7 +1209,7 @@ The following operators are supported: + (add), - (subtract), * (multiply), /
(divide), and ^ (power). Parentheses “(“ and “)” may be used for grouping. (divide), and ^ (power). Parentheses “(“ and “)” may be used for grouping.
The following standard functions are supported: sqrt, exp, log, sin, cos, sec, The following standard functions are supported: sqrt, exp, log, sin, cos, sec,
csc, tan, cot, asin, acos, atan, sinh, cosh, tanh, erf, erfc, min, max, abs, csc, tan, cot, asin, acos, atan, atan2, sinh, cosh, tanh, erf, erfc, min, max, abs,
floor, ceil, step, delta, select. step(x) = 0 if x < 0, 1 otherwise. floor, ceil, step, delta, select. step(x) = 0 if x < 0, 1 otherwise.
delta(x) = 1 if x is 0, 0 otherwise. select(x,y,z) = z if x = 0, y otherwise. delta(x) = 1 if x is 0, 0 otherwise. select(x,y,z) = z if x = 0, y otherwise.
Some custom forces allow additional functions to be defined from tabulated values. Some custom forces allow additional functions to be defined from tabulated values.
......
# Generate and install examples. # Generate and install examples.
# #
# This is boilerplate code for generating a set of executables, one per # This is boilerplate code for generating a set of executables, one per
# .cpp file in an "examples" subdirectory. # .cpp file in an "examples" subdirectory.
# #
# For IDEs that can deal with PROJECT_LABEL properties (at least # For IDEs that can deal with PROJECT_LABEL properties (at least
# Visual Studio) the projects for building each of these adhoc # Visual Studio) the projects for building each of these adhoc
# executables will be labeled "Example - TheExampleName" if a file # executables will be labeled "Example - TheExampleName" if a file
# TheExampleName.cpp is found in this directory. # TheExampleName.cpp is found in this directory.
# #
# We check the BUILD_TESTING_{SHARED,STATIC} variables to determine # We check the BUILD_TESTING_{SHARED,STATIC} variables to determine
# whether to build dynamically linked, statically linked, or both # whether to build dynamically linked, statically linked, or both
# versions of the executable. # versions of the executable.
SET(OpenMM_CWRAPPER "OpenMMCWrapper") SET(OpenMM_CWRAPPER "OpenMMCWrapper")
SET(OpenMM_FWRAPPER "OpenMMFortranWrapper") SET(OpenMM_FWRAPPER "OpenMMFortranWrapper")
SET(OpenMM_FMODULE "OpenMMFortranModule") SET(OpenMM_FMODULE "OpenMMFortranModule")
SET(CPP_EXAMPLES HelloArgon HelloSodiumChloride HelloEthane HelloWaterBox) SET(CPP_EXAMPLES HelloArgon HelloSodiumChloride HelloEthane HelloWaterBox)
SET(C_EXAMPLES HelloArgonInC HelloSodiumChlorideInC) SET(C_EXAMPLES HelloArgonInC HelloSodiumChlorideInC)
SET(F_EXAMPLES HelloArgonInFortran HelloSodiumChlorideInFortran) SET(F_EXAMPLES HelloArgonInFortran HelloSodiumChlorideInFortran)
FOREACH(EX_ROOT ${CPP_EXAMPLES}) FOREACH(EX_ROOT ${CPP_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB) IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library # Link with shared library
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.cpp) ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT} SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES PROPERTIES
PROJECT_LABEL "Example - ${EX_ROOT}" PROJECT_LABEL "Example - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}" LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET}) TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ENDIF (OPENMM_BUILD_SHARED_LIB) ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB) IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library # Link with static library
SET(EX_STATIC ${EX_ROOT}Static) SET(EX_STATIC ${EX_ROOT}Static)
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.cpp) ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC} SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES PROPERTIES
PROJECT_LABEL "Example - ${EX_STATIC}" PROJECT_LABEL "Example - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}" LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES") COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET}) TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ENDIF (OPENMM_BUILD_STATIC_LIB) ENDIF (OPENMM_BUILD_STATIC_LIB)
INSTALL(FILES ${EX_ROOT}.cpp DESTINATION examples) INSTALL(FILES ${EX_ROOT}.cpp DESTINATION examples)
ENDFOREACH(EX_ROOT ${CPP_EXAMPLES}) ENDFOREACH(EX_ROOT ${CPP_EXAMPLES})
# Only build wrapper examples if wrappers have been built # Only build wrapper examples if wrappers have been built
IF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS) IF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}/wrappers) INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}/wrappers)
FOREACH(EX_ROOT ${C_EXAMPLES}) FOREACH(EX_ROOT ${C_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB) IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library # Link with shared library
# We need at least one .cpp here to get CMake to include # We need at least one .cpp here to get CMake to include
# C++ libraries on the link line. # C++ libraries on the link line.
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.c Empty.cpp) ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT} SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES PROPERTIES
PROJECT_LABEL "Example C - ${EX_ROOT}" PROJECT_LABEL "Example C - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}" LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}") COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET}) TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ADD_DEPENDENCIES(${EX_ROOT} ApiWrappers) ADD_DEPENDENCIES(${EX_ROOT} ApiWrappers)
ENDIF (OPENMM_BUILD_SHARED_LIB) ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB) IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library # Link with static library
SET(EX_STATIC ${EX_ROOT}Static) SET(EX_STATIC ${EX_ROOT}Static)
# We need at least one .cpp here to get CMake to include # We need at least one .cpp here to get CMake to include
# C++ libraries on the static link line. # C++ libraries on the static link line.
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.c Empty.cpp) ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC} SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES PROPERTIES
PROJECT_LABEL "Example C - ${EX_STATIC}" PROJECT_LABEL "Example C - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}" LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES") COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET}) TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ADD_DEPENDENCIES(${EX_STATIC} ApiWrappers) ADD_DEPENDENCIES(${EX_STATIC} ApiWrappers)
ENDIF (OPENMM_BUILD_STATIC_LIB) ENDIF (OPENMM_BUILD_STATIC_LIB)
ENDFOREACH(EX_ROOT ${C_EXAMPLES}) ENDFOREACH(EX_ROOT ${C_EXAMPLES})
ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS) ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
FOREACH(EX_ROOT ${C_EXAMPLES}) FOREACH(EX_ROOT ${C_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.c DESTINATION examples) INSTALL(FILES ${EX_ROOT}.c DESTINATION examples)
ENDFOREACH(EX_ROOT ${C_EXAMPLES}) ENDFOREACH(EX_ROOT ${C_EXAMPLES})
FOREACH(EX_ROOT ${F_EXAMPLES}) FOREACH(EX_ROOT ${F_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.f90 DESTINATION examples) INSTALL(FILES ${EX_ROOT}.f90 DESTINATION examples)
ENDFOREACH(EX_ROOT ${F_EXAMPLES}) ENDFOREACH(EX_ROOT ${F_EXAMPLES})
INSTALL(FILES simulateAmber.py simulatePdb.py simulateGromacs.py benchmark.py argon-chemical-potential.py input.inpcrd input.prmtop input.pdb input.gro input.top 5dfr_minimized.pdb 5dfr_solv-cube_equil.pdb INSTALL(FILES simulateAmber.py simulatePdb.py simulateGromacs.py benchmark.py argon-chemical-potential.py input.inpcrd input.prmtop input.pdb input.gro input.top 5dfr_minimized.pdb 5dfr_solv-cube_equil.pdb apoa1.pdb
DESTINATION examples) DESTINATION examples)
INSTALL(FILES VisualStudio/HelloArgon.vcproj INSTALL(FILES VisualStudio/HelloArgon.vcproj
VisualStudio/HelloArgon.sln VisualStudio/HelloArgon.sln
VisualStudio/HelloArgonInC.sln VisualStudio/HelloArgonInC.sln
VisualStudio/HelloArgonInC.vcproj VisualStudio/HelloArgonInC.vcproj
VisualStudio/HelloArgonInFortran.sln VisualStudio/HelloArgonInFortran.sln
VisualStudio/HelloArgonInFortran.vfproj VisualStudio/HelloArgonInFortran.vfproj
DESTINATION examples/VisualStudio) DESTINATION examples/VisualStudio)
INSTALL(FILES README.txt DESTINATION examples) INSTALL(FILES README.txt DESTINATION examples)
INSTALL(FILES Makefile NMakefile DESTINATION examples) INSTALL(FILES Makefile NMakefile DESTINATION examples)
INSTALL(FILES MakefileNotes.txt Empty.cpp DESTINATION examples) INSTALL(FILES MakefileNotes.txt Empty.cpp DESTINATION examples)
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++ Copyright (c) 2008-2017, Petr Kobalicek
Copyright (c) 2008-2014, Petr Kobalicek <kobalicek.petr@gmail.com>
This software is provided 'as-is', without any express or implied This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages warranty. In no event will the authors be held liable for any damages
......
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_ARM_H
#define _ASMJIT_ARM_H
// [Dependencies]
#include "./base.h"
#include "./arm/armassembler.h"
#include "./arm/armbuilder.h"
#include "./arm/armcompiler.h"
#include "./arm/arminst.h"
#include "./arm/armoperand.h"
// [Guard]
#endif // _ASMJIT_ARM_H
...@@ -12,368 +12,36 @@ ...@@ -12,368 +12,36 @@
// [asmjit_mainpage] // [asmjit_mainpage]
// ============================================================================ // ============================================================================
//! @mainpage //! \mainpage
//! //!
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++. //! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
//! //!
//! AsmJit is a complete JIT and remote assembler for C++ language. It can //! Introduction provided by the project page at https://github.com/asmjit/asmjit.
//! generate native code for x86 and x64 architectures having support for
//! a full 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 (VM). It doesn't have functionality to
//! implement VM out of the box; however, it can be be used as a JIT backend
//! for your own VM. The usage of AsmJit is not limited at all; it's suitable
//! for multimedia, VM backends or remote code generation.
//!
//! @section AsmJit_Concepts Code Generation Concepts
//!
//! AsmJit has two completely different code generation concepts. The difference
//! is in how the code is generated. The first concept, also referred as the low
//! level concept, is called 'Assembler' and it's the same as writing RAW
//! assembly by using physical registers directly. In this case AsmJit does only
//! instruction encoding, verification and relocation.
//!
//! 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
//! more portable.
//!
//! @section AsmJit_Main_CodeGeneration Code Generation
//!
//! - \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_HomePage AsmJit Homepage
//!
//! - https://github.com/kobalicek/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 `Assembler` is implemented by `X86Assembler`.
//!
//! - See `Assembler` for low level code generation documentation.
//! - See `Compiler` 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.
// ============================================================================ //! \defgroup asmjit_base AsmJit Base API (architecture independent)
// [asmjit_base_compiler]
// ============================================================================
//! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base
//!
//! \brief AsmJit code-tree used by Compiler.
//! //!
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes //! \brief Backend Neutral API.
//! 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 Compiler.
//!
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \defgroup asmjit_base_util AsmJit Utilities //! \defgroup asmjit_x86 AsmJit X86/X64 API
//! \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 //! \brief X86/X64 Backend API.
//! --------------
//!
//! 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 `Vec64`,
//! `Vec128` and `Vec256` 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_x86]
// ============================================================================
//! \defgroup asmjit_x86 X86/X64
//!
//! \brief X86/X64 module
// ============================================================================
// [asmjit_x86_general]
// ============================================================================
//! \defgroup asmjit_x86_general X86/X64 General API
//! \ingroup asmjit_x86
//!
//! \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()` - Address size not specified.
//! - `asmjit::byte_ptr()` - 1 byte.
//! - `asmjit::word_ptr()` - 2 bytes (Gpw size).
//! - `asmjit::dword_ptr()` - 4 bytes (Gpd size).
//! - `asmjit::qword_ptr()` - 8 bytes (Gpq/Mm size).
//! - `asmjit::tword_ptr()` - 10 bytes (FPU).
//! - `asmjit::oword_ptr()` - 16 bytes (Xmm size).
//! - `asmjit::yword_ptr()` - 32 bytes (Ymm size).
//! - `asmjit::zword_ptr()` - 64 bytes (Zmm size).
//!
//! 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 `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 `imm()` or `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 `X86CpuInfo` extends `CpuInfo` 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 `X86CpuInfo` 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 `X86CpuInfo` and setting
//! up its members. `X86CpuUtil::detect` can be used to detect CPU features into
//! an existing `X86CpuInfo` instance - it may become handly if only one property
//! has to be turned on/off.
//!
//! If the high-level interface `X86CpuInfo` offers is not enough there is also
//! `X86CpuUtil::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;
//!
//! // Get `X86CpuInfo` global instance.
//! const X86CpuInfo* cpuInfo = X86CpuInfo::getHost();
//!
//! if (cpuInfo->hasFeature(kX86CpuFeatureSSE2)) {
//! // Processor has SSE2.
//! }
//! else if (cpuInfo->hasFeature(kX86CpuFeatureMMX)) {
//! // 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.
//! X86CpuId out;
//! X86CpuUtil::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_x86_compiler]
// ============================================================================
//! \defgroup asmjit_x86_compiler X86/X64 Code-Tree
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 code-tree and helpers.
// ============================================================================
// [asmjit_x86_inst]
// ============================================================================
//! \defgroup asmjit_x86_inst X86/X64 Instructions
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 low-level instruction definitions.
// ============================================================================
// [asmjit_x86_util]
// ============================================================================
//! \defgroup asmjit_x86_util X86/X64 Utilities
//! \ingroup asmjit_x86
//!
//! \brief X86/X64 utility classes.
// ============================================================================
// [asmjit_contrib]
// ============================================================================
//! \defgroup asmjit_contrib Contributions //! \defgroup asmjit_arm AsmJit ARM32/ARM64 API
//! //!
//! \brief Contributions. //! \brief ARM32/ARM64 Backend API.
// [Dependencies - Base] // [Dependencies]
#include "base.h" #include "./base.h"
// [Dependencies - X86/X64] // [X86/X64]
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64) #if defined(ASMJIT_BUILD_X86)
#include "x86.h" #include "./x86.h"
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64 #endif // ASMJIT_BUILD_X86
// [Dependencies - Host] // [ARM32/ARM64]
#include "host.h" #if defined(ASMJIT_BUILD_ARM)
#include "./arm.h"
#endif // ASMJIT_BUILD_ARM
// [Guard] // [Guard]
#endif // _ASMJIT_ASMJIT_H #endif // _ASMJIT_ASMJIT_H
...@@ -4,81 +4,119 @@ ...@@ -4,81 +4,119 @@
// [License] // [License]
// Zlib - See LICENSE.md file in the package. // Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit] // [Dependencies]
#if !defined(_ASMJIT_BUILD_H) #if !defined(_ASMJIT_BUILD_H)
#include "build.h" # include "./build.h"
#endif // !_ASMJIT_BUILD_H #endif // !_ASMJIT_BUILD_H
// [Guard] // [Guard]
#if !defined(ASMJIT_API_SCOPE) #if !defined(ASMJIT_API_SCOPE)
# define ASMJIT_API_SCOPE # define ASMJIT_API_SCOPE
#else #else
# error "AsmJit - Api-Scope is already active, previous scope not closed by apiend.h?" # error "[asmjit] api-scope is already active, previous scope not closed by asmjit_apiend.h?"
#endif // ASMJIT_API_SCOPE #endif // ASMJIT_API_SCOPE
// ============================================================================ // ============================================================================
// [Override] // [C++ Support]
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_CC_HAS_OVERRIDE) && !defined(override) // [NoExcept]
#if !ASMJIT_CC_HAS_NOEXCEPT && !defined(noexcept)
# define noexcept ASMJIT_NOEXCEPT
# define ASMJIT_UNDEF_NOEXCEPT
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
// [NullPtr]
#if !ASMJIT_CC_HAS_NULLPTR && !defined(nullptr)
# define nullptr NULL
# define ASMJIT_UNDEF_NULLPTR
#endif // !ASMJIT_CC_HAS_NULLPTR && !nullptr
// [Override]
#if !ASMJIT_CC_HAS_OVERRIDE && !defined(override)
# define override # define override
# define ASMJIT_UNDEF_OVERRIDE # define ASMJIT_UNDEF_OVERRIDE
#endif // !ASMJIT_CC_HAS_OVERRIDE && !override #endif // !ASMJIT_CC_HAS_OVERRIDE && !override
// ============================================================================ // ============================================================================
// [NoExcept] // [Compiler Support]
// ============================================================================ // ============================================================================
#if !defined(ASMJIT_CC_HAS_NOEXCEPT) && !defined(noexcept) // [Clang]
# define noexcept ASMJIT_NOEXCEPT #if ASMJIT_CC_CLANG
# define ASMJIT_UNDEF_NOEXCEPT # pragma clang diagnostic push
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept # pragma clang diagnostic ignored "-Wc++11-extensions"
# pragma clang diagnostic ignored "-Wconstant-logical-operand"
# pragma clang diagnostic ignored "-Wunnamed-type-template-args"
#endif // ASMJIT_CC_CLANG
// ============================================================================ // [GCC]
// [MSC] #if ASMJIT_CC_GCC
// ============================================================================ # pragma GCC diagnostic push
# pragma GCC diagnostic ignored "-Wbool-operation"
# if ASMJIT_CC_GCC_GE(8, 0, 0)
# pragma GCC diagnostic ignored "-Wclass-memaccess"
# endif
#endif // ASMJIT_CC_GCC
#if defined(_MSC_VER) // [MSC]
// Disable some warnings we know about #if ASMJIT_CC_MSC
# pragma warning(push) # pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant # pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4201) // nameless struct/union # pragma warning(disable: 4201) // nameless struct/union
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible # pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data
// loss of data # pragma warning(disable: 4251) // struct needs to have dll-interface to be used by clients of struct ...
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used # pragma warning(disable: 4275) // non dll-interface struct ... used as base for dll-interface struct
// by clients of struct ...
# pragma warning(disable: 4275) // non dll-interface struct ... used as base for
// dll-interface struct
# pragma warning(disable: 4355) // this used in base member initializer list # pragma warning(disable: 4355) // this used in base member initializer list
# pragma warning(disable: 4480) // specifying underlying type for enum # pragma warning(disable: 4480) // specifying underlying type for enum
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false' # pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
# pragma warning(disable: 4838) // comversion from 'int' to ...
// Rename symbols. # if _MSC_VER < 1900
# if !defined(vsnprintf) # if !defined(vsnprintf)
# define ASMJIT_UNDEF_VSNPRINTF # define ASMJIT_UNDEF_VSNPRINTF
# define vsnprintf _vsnprintf # define vsnprintf _vsnprintf
# endif // !vsnprintf # endif // !vsnprintf
# if !defined(snprintf) # if !defined(snprintf)
# define ASMJIT_UNDEF_SNPRINTF # define ASMJIT_UNDEF_SNPRINTF
# define snprintf _snprintf # define snprintf _snprintf
# endif // !snprintf # endif // !snprintf
#endif // _MSC_VER # endif
#endif // ASMJIT_CC_MSC
// ============================================================================ // ============================================================================
// [CLang] // [Custom Macros]
// ============================================================================ // ============================================================================
#if defined(__clang__) // [ASMJIT_NON...]
# pragma clang diagnostic push #if ASMJIT_CC_HAS_DELETE_FUNCTION
# pragma clang diagnostic ignored "-Wunnamed-type-template-args" #define ASMJIT_NONCONSTRUCTIBLE(...) \
#endif // __clang__ private: \
__VA_ARGS__() = delete; \
// ============================================================================ __VA_ARGS__(const __VA_ARGS__& other) = delete; \
// [GCC] __VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
// ============================================================================ public:
#define ASMJIT_NONCOPYABLE(...) \
private: \
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
__VA_ARGS__& operator=(const __VA_ARGS__& other) = delete; \
public:
#else
#define ASMJIT_NONCONSTRUCTIBLE(...) \
private: \
inline __VA_ARGS__(); \
inline __VA_ARGS__(const __VA_ARGS__& other); \
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
public:
#define ASMJIT_NONCOPYABLE(...) \
private: \
inline __VA_ARGS__(const __VA_ARGS__& other); \
inline __VA_ARGS__& operator=(const __VA_ARGS__& other); \
public:
#endif // ASMJIT_CC_HAS_DELETE_FUNCTION
#if defined(__GNUC__) && !defined(__clang__) // [ASMJIT_ENUM]
# if __GNUC__ >= 4 && !defined(__MINGW32__) #if defined(_MSC_VER) && _MSC_VER >= 1400
# pragma GCC visibility push(hidden) # define ASMJIT_ENUM(NAME) enum NAME : uint32_t
# endif // GCC 4+ #else
#endif // __GNUC__ # define ASMJIT_ENUM(NAME) enum NAME
#endif
...@@ -8,60 +8,67 @@ ...@@ -8,60 +8,67 @@
#if defined(ASMJIT_API_SCOPE) #if defined(ASMJIT_API_SCOPE)
# undef ASMJIT_API_SCOPE # undef ASMJIT_API_SCOPE
#else #else
# error "AsmJit - Api-Scope not active, forgot to include apibegin.h?" # error "[asmjit] api-scope not active, forgot to include asmjit_apibegin.h?"
#endif // ASMJIT_API_SCOPE #endif // ASMJIT_API_SCOPE
// ============================================================================ // ============================================================================
// [Override] // [C++ Support]
// ============================================================================ // ============================================================================
#if defined(ASMJIT_UNDEF_OVERRIDE)
# undef override
# undef ASMJIT_UNDEF_OVERRIDE
#endif // ASMJIT_UNDEF_OVERRIDE
// ============================================================================
// [NoExcept] // [NoExcept]
// ============================================================================
#if defined(ASMJIT_UNDEF_NOEXCEPT) #if defined(ASMJIT_UNDEF_NOEXCEPT)
# undef noexcept # undef noexcept
# undef ASMJIT_UNDEF_NOEXCEPT # undef ASMJIT_UNDEF_NOEXCEPT
#endif // ASMJIT_UNDEF_NOEXCEPT #endif // ASMJIT_UNDEF_NOEXCEPT
// ============================================================================ // [NullPtr]
// [MSC] #if defined(ASMJIT_UNDEF_NULLPTR)
// ============================================================================ # undef nullptr
# undef ASMJIT_UNDEF_NULLPTR
#if defined(_MSC_VER) #endif // ASMJIT_UNDEF_NULLPTR
# pragma warning(pop)
# if defined(ASMJIT_UNDEF_VSNPRINTF)
# undef vsnprintf
# undef ASMJIT_UNDEF_VSNPRINTF
# endif // ASMJIT_UNDEF_VSNPRINTF
# if defined(ASMJIT_UNDEF_SNPRINTF)
# undef snprintf
# undef ASMJIT_UNDEF_SNPRINTF
# endif // ASMJIT_UNDEF_SNPRINTF
#endif // _MSC_VER // [Override]
#if defined(ASMJIT_UNDEF_OVERRIDE)
# undef override
# undef ASMJIT_UNDEF_OVERRIDE
#endif // ASMJIT_UNDEF_OVERRIDE
// ============================================================================ // ============================================================================
// [CLang] // [Compiler Support]
// ============================================================================ // ============================================================================
#if defined(__clang__) // [Clang]
#if ASMJIT_CC_CLANG
# pragma clang diagnostic pop # pragma clang diagnostic pop
#endif // __clang__ #endif // ASMJIT_CC_CLANG
// ============================================================================
// [GCC] // [GCC]
#if ASMJIT_CC_GCC
# pragma GCC diagnostic pop
#endif // ASMJIT_CC_GCC
// [MSC]
#if ASMJIT_CC_MSC
# pragma warning(pop)
# if _MSC_VER < 1900
# if defined(ASMJIT_UNDEF_VSNPRINTF)
# undef vsnprintf
# undef ASMJIT_UNDEF_VSNPRINTF
# endif // ASMJIT_UNDEF_VSNPRINTF
# if defined(ASMJIT_UNDEF_SNPRINTF)
# undef snprintf
# undef ASMJIT_UNDEF_SNPRINTF
# endif // ASMJIT_UNDEF_SNPRINTF
# endif
#endif // ASMJIT_CC_MSC
// ============================================================================
// [Custom Macros]
// ============================================================================ // ============================================================================
#if defined(__GNUC__) && !defined(__clang__) // [ASMJIT_NON...]
# if __GNUC__ >= 4 && !defined(__MINGW32__) #undef ASMJIT_NONCONSTRUCTIBLE
# pragma GCC visibility pop #undef ASMJIT_NONCOPYABLE
# endif // GCC 4+
#endif // __GNUC__ // [ASMJIT_ENUM]
#undef ASMJIT_ENUM
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BUILD_H
#define _ASMJIT_BUILD_H
// ============================================================================
// [asmjit::Build - Configuration]
// ============================================================================
// AsmJit is by default compiled only for a host processor for the purpose of
// JIT code generation. Both Assembler and CodeCompiler emitters are compiled
// by default. Preprocessor macros can be used to change the default behavior.
// External Config File
// --------------------
//
// Define in case your configuration is generated in an external file to be
// included.
#if defined(ASMJIT_CONFIG_FILE)
# include ASMJIT_CONFIG_FILE
#endif // ASMJIT_CONFIG_FILE
// AsmJit Static Builds and Embedding
// ----------------------------------
//
// These definitions can be used to enable static library build. Embed is used
// when AsmJit's source code is embedded directly in another project, implies
// static build as well.
//
// #define ASMJIT_EMBED // Asmjit is embedded (implies ASMJIT_STATIC).
// #define ASMJIT_STATIC // Define to enable static-library build.
// AsmJit Build Modes
// ------------------
//
// These definitions control the build mode and tracing support. The build mode
// should be auto-detected at compile time, but it's possible to override it in
// case that the auto-detection fails.
//
// Tracing is a feature that is never compiled by default and it's only used to
// debug AsmJit itself.
//
// #define ASMJIT_DEBUG // Define to enable debug-mode.
// #define ASMJIT_RELEASE // Define to enable release-mode.
// AsmJit Build Backends
// ---------------------
//
// These definitions control which backends to compile. If none of these is
// defined AsmJit will use host architecture by default (for JIT code generation).
//
// #define ASMJIT_BUILD_X86 // Define to enable X86 and X64 code-generation.
// #define ASMJIT_BUILD_ARM // Define to enable ARM32 and ARM64 code-generation.
// #define ASMJIT_BUILD_HOST // Define to enable host instruction set.
// AsmJit Build Features
// ---------------------
//
// Flags can be defined to disable standard features. These are handy especially
// when building AsmJit statically and some features are not needed or unwanted
// (like CodeCompiler).
//
// AsmJit features are enabled by default.
// #define ASMJIT_DISABLE_COMPILER // Disable CodeCompiler (completely).
// #define ASMJIT_DISABLE_LOGGING // Disable logging and formatting (completely).
// #define ASMJIT_DISABLE_TEXT // Disable everything that contains text
// // representation (instructions, errors, ...).
// #define ASMJIT_DISABLE_VALIDATION // Disable Validation (completely).
// Prevent compile-time errors caused by misconfiguration.
#if defined(ASMJIT_DISABLE_TEXT) && !defined(ASMJIT_DISABLE_LOGGING)
# error "[asmjit] ASMJIT_DISABLE_TEXT requires ASMJIT_DISABLE_LOGGING to be defined."
#endif // ASMJIT_DISABLE_TEXT && !ASMJIT_DISABLE_LOGGING
// Detect ASMJIT_DEBUG and ASMJIT_RELEASE if not forced from outside.
#if !defined(ASMJIT_DEBUG) && !defined(ASMJIT_RELEASE)
# if !defined(NDEBUG)
# define ASMJIT_DEBUG
# else
# define ASMJIT_RELEASE
# endif
#endif
// ASMJIT_EMBED implies ASMJIT_STATIC.
#if defined(ASMJIT_EMBED) && !defined(ASMJIT_STATIC)
# define ASMJIT_STATIC
#endif
// ============================================================================
// [asmjit::Build - VERSION]
// ============================================================================
// [@VERSION{@]
#define ASMJIT_VERSION_MAJOR 1
#define ASMJIT_VERSION_MINOR 0
#define ASMJIT_VERSION_PATCH 0
#define ASMJIT_VERSION_STRING "1.0.0"
// [@VERSION}@]
// ============================================================================
// [asmjit::Build - WIN32]
// ============================================================================
// [@WIN32_CRT_NO_DEPRECATE{@]
#if defined(_MSC_VER) && defined(ASMJIT_EXPORTS)
# if !defined(_CRT_SECURE_NO_DEPRECATE)
# define _CRT_SECURE_NO_DEPRECATE
# endif
# if !defined(_CRT_SECURE_NO_WARNINGS)
# define _CRT_SECURE_NO_WARNINGS
# endif
#endif
// [@WIN32_CRT_NO_DEPRECATE}@]
// [@WIN32_LEAN_AND_MEAN{@]
#if (defined(_WIN32) || defined(_WINDOWS)) && !defined(_WINDOWS_)
# if !defined(WIN32_LEAN_AND_MEAN)
# define WIN32_LEAN_AND_MEAN
# define ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif
# if !defined(NOMINMAX)
# define NOMINMAX
# define ASMJIT_UNDEF_NOMINMAX
# endif
# include <windows.h>
# if defined(ASMJIT_UNDEF_NOMINMAX)
# undef NOMINMAX
# undef ASMJIT_UNDEF_NOMINMAX
# endif
# if defined(ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN)
# undef WIN32_LEAN_AND_MEAN
# undef ASMJIT_UNDEF_WIN32_LEAN_AND_MEAN
# endif
#endif
// [@WIN32_LEAN_AND_MEAN}@]
// ============================================================================
// [asmjit::Build - OS]
// ============================================================================
// [@OS{@]
#if defined(_WIN32) || defined(_WINDOWS)
#define ASMJIT_OS_WINDOWS (1)
#else
#define ASMJIT_OS_WINDOWS (0)
#endif
#if defined(__APPLE__)
# include <TargetConditionals.h>
# define ASMJIT_OS_MAC (TARGET_OS_MAC)
# define ASMJIT_OS_IOS (TARGET_OS_IPHONE)
#else
# define ASMJIT_OS_MAC (0)
# define ASMJIT_OS_IOS (0)
#endif
#if defined(__ANDROID__)
# define ASMJIT_OS_ANDROID (1)
#else
# define ASMJIT_OS_ANDROID (0)
#endif
#if defined(__linux__) || defined(__ANDROID__)
# define ASMJIT_OS_LINUX (1)
#else
# define ASMJIT_OS_LINUX (0)
#endif
#if defined(__DragonFly__)
# define ASMJIT_OS_DRAGONFLYBSD (1)
#else
# define ASMJIT_OS_DRAGONFLYBSD (0)
#endif
#if defined(__FreeBSD__)
# define ASMJIT_OS_FREEBSD (1)
#else
# define ASMJIT_OS_FREEBSD (0)
#endif
#if defined(__NetBSD__)
# define ASMJIT_OS_NETBSD (1)
#else
# define ASMJIT_OS_NETBSD (0)
#endif
#if defined(__OpenBSD__)
# define ASMJIT_OS_OPENBSD (1)
#else
# define ASMJIT_OS_OPENBSD (0)
#endif
#if defined(__QNXNTO__)
# define ASMJIT_OS_QNX (1)
#else
# define ASMJIT_OS_QNX (0)
#endif
#if defined(__sun)
# define ASMJIT_OS_SOLARIS (1)
#else
# define ASMJIT_OS_SOLARIS (0)
#endif
#if defined(__CYGWIN__)
# define ASMJIT_OS_CYGWIN (1)
#else
# define ASMJIT_OS_CYGWIN (0)
#endif
#define ASMJIT_OS_BSD ( \
ASMJIT_OS_FREEBSD || \
ASMJIT_OS_DRAGONFLYBSD || \
ASMJIT_OS_NETBSD || \
ASMJIT_OS_OPENBSD || \
ASMJIT_OS_MAC)
#define ASMJIT_OS_POSIX (!ASMJIT_OS_WINDOWS)
// [@OS}@]
// ============================================================================
// [asmjit::Build - ARCH]
// ============================================================================
// [@ARCH{@]
// \def ASMJIT_ARCH_ARM32
// True if the target architecture is a 32-bit ARM.
//
// \def ASMJIT_ARCH_ARM64
// True if the target architecture is a 64-bit ARM.
//
// \def ASMJIT_ARCH_X86
// True if the target architecture is a 32-bit X86/IA32
//
// \def ASMJIT_ARCH_X64
// True if the target architecture is a 64-bit X64/AMD64
//
// \def ASMJIT_ARCH_LE
// True if the target architecture is little endian.
//
// \def ASMJIT_ARCH_BE
// True if the target architecture is big endian.
//
// \def ASMJIT_ARCH_64BIT
// True if the target architecture is 64-bit.
#if (defined(_M_X64 ) || defined(__x86_64) || defined(__x86_64__) || \
defined(_M_AMD64) || defined(__amd64 ) || defined(__amd64__ ))
# define ASMJIT_ARCH_X64 1
#else
# define ASMJIT_ARCH_X64 0
#endif
#if (defined(_M_IX86 ) || defined(__X86__ ) || defined(__i386 ) || \
defined(__IA32__) || defined(__I86__ ) || defined(__i386__) || \
defined(__i486__) || defined(__i586__) || defined(__i686__))
# define ASMJIT_ARCH_X86 (!ASMJIT_ARCH_X64)
#else
# define ASMJIT_ARCH_X86 0
#endif
#if defined(__aarch64__)
# define ASMJIT_ARCH_ARM64 1
#else
# define ASMJIT_ARCH_ARM64 0
#endif
#if (defined(_M_ARM ) || defined(__arm ) || defined(__thumb__ ) || \
defined(_M_ARMT ) || defined(__arm__ ) || defined(__thumb2__))
# define ASMJIT_ARCH_ARM32 (!ASMJIT_ARCH_ARM64)
#else
# define ASMJIT_ARCH_ARM32 0
#endif
#define ASMJIT_ARCH_LE ( \
ASMJIT_ARCH_X86 || \
ASMJIT_ARCH_X64 || \
ASMJIT_ARCH_ARM32 || \
ASMJIT_ARCH_ARM64 )
#define ASMJIT_ARCH_BE (!(ASMJIT_ARCH_LE))
#define ASMJIT_ARCH_64BIT (ASMJIT_ARCH_X64 || ASMJIT_ARCH_ARM64)
// [@ARCH}@]
// [@ARCH_UNALIGNED_RW{@]
// \def ASMJIT_ARCH_UNALIGNED_16
// True if the target architecture allows unaligned 16-bit reads and writes.
//
// \def ASMJIT_ARCH_UNALIGNED_32
// True if the target architecture allows unaligned 32-bit reads and writes.
//
// \def ASMJIT_ARCH_UNALIGNED_64
// True if the target architecture allows unaligned 64-bit reads and writes.
#define ASMJIT_ARCH_UNALIGNED_16 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
#define ASMJIT_ARCH_UNALIGNED_32 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
#define ASMJIT_ARCH_UNALIGNED_64 (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64)
// [@ARCH_UNALIGNED_RW}@]
// ============================================================================
// [asmjit::Build - CC]
// ============================================================================
// [@CC{@]
// \def ASMJIT_CC_CLANG
// Non-zero if the detected C++ compiler is CLANG (contains normalized CLANG version).
//
// \def ASMJIT_CC_CODEGEAR
// Non-zero if the detected C++ compiler is CODEGEAR or BORLAND (version not normalized).
//
// \def ASMJIT_CC_INTEL
// Non-zero if the detected C++ compiler is INTEL (version not normalized).
//
// \def ASMJIT_CC_GCC
// Non-zero if the detected C++ compiler is GCC (contains normalized GCC version).
//
// \def ASMJIT_CC_MSC
// Non-zero if the detected C++ compiler is MSC (contains normalized MSC version).
//
// \def ASMJIT_CC_MINGW
// Non-zero if the detected C++ compiler is MINGW32 (set to 32) or MINGW64 (set to 64).
#define ASMJIT_CC_CLANG 0
#define ASMJIT_CC_CODEGEAR 0
#define ASMJIT_CC_GCC 0
#define ASMJIT_CC_INTEL 0
#define ASMJIT_CC_MSC 0
// Intel masquerades as GCC, so check for it first.
#if defined(__INTEL_COMPILER)
# undef ASMJIT_CC_INTEL
# define ASMJIT_CC_INTEL __INTEL_COMPILER
#elif defined(__CODEGEARC__)
# undef ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_CODEGEAR (__CODEGEARC__)
#elif defined(__BORLANDC__)
# undef ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_CODEGEAR (__BORLANDC__)
#elif defined(__clang__) && defined(__clang_minor__)
# undef ASMJIT_CC_CLANG
# define ASMJIT_CC_CLANG (__clang_major__ * 10000000 + __clang_minor__ * 100000 + __clang_patchlevel__)
#elif defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__)
# undef ASMJIT_CC_GCC
# define ASMJIT_CC_GCC (__GNUC__ * 10000000 + __GNUC_MINOR__ * 100000 + __GNUC_PATCHLEVEL__)
#elif defined(_MSC_VER) && defined(_MSC_FULL_VER)
# undef ASMJIT_CC_MSC
# if _MSC_VER == _MSC_FULL_VER / 10000
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 10000))
# else
# define ASMJIT_CC_MSC (_MSC_VER * 100000 + (_MSC_FULL_VER % 100000))
# endif
#else
# error "[asmjit] Unable to detect the C/C++ compiler."
#endif
#if ASMJIT_CC_INTEL && (defined(__GNUC__) || defined(__clang__))
# define ASMJIT_CC_INTEL_COMPAT_MODE 1
# else
# define ASMJIT_CC_INTEL_COMPAT_MODE 0
#endif
#define ASMJIT_CC_CODEGEAR_EQ(x, y) (ASMJIT_CC_CODEGEAR == (((x) << 8) + (y)))
#define ASMJIT_CC_CODEGEAR_GE(x, y) (ASMJIT_CC_CODEGEAR >= (((x) << 8) + (y)))
#define ASMJIT_CC_CLANG_EQ(x, y, z) (ASMJIT_CC_CLANG == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_CLANG_GE(x, y, z) (ASMJIT_CC_CLANG >= ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_GCC_EQ(x, y, z) (ASMJIT_CC_GCC == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_GCC_GE(x, y, z) (ASMJIT_CC_GCC >= ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_INTEL_EQ(x, y) (ASMJIT_CC_INTEL == (((x) * 100) + (y)))
#define ASMJIT_CC_INTEL_GE(x, y) (ASMJIT_CC_INTEL >= (((x) * 100) + (y)))
#define ASMJIT_CC_MSC_EQ(x, y, z) (ASMJIT_CC_MSC == ((x) * 10000000 + (y) * 100000 + (z)))
#define ASMJIT_CC_MSC_GE(x, y, z) (ASMJIT_CC_MSC >= ((x) * 10000000 + (y) * 100000 + (z)))
#if defined(__MINGW64__)
# define ASMJIT_CC_MINGW 64
#elif defined(__MINGW32__)
# define ASMJIT_CC_MINGW 32
#else
# define ASMJIT_CC_MINGW 0
#endif
#if defined(__cplusplus)
# if __cplusplus >= 201103L
# define ASMJIT_CC_CXX_VERSION __cplusplus
# elif defined(__GXX_EXPERIMENTAL_CXX0X__) || ASMJIT_CC_MSC_GE(18, 0, 0) || ASMJIT_CC_INTEL_GE(14, 0)
# define ASMJIT_CC_CXX_VERSION 201103L
# else
# define ASMJIT_CC_CXX_VERSION 199711L
# endif
#endif
#if !defined(ASMJIT_CC_CXX_VERSION)
# define ASMJIT_CC_CXX_VERSION 0
#endif
// [@CC}@]
// [@CC_FEATURES{@]
#if ASMJIT_CC_CLANG
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (__has_attribute(__aligned__))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (__has_attribute(__always_inline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (__has_attribute(__noinline__))
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (__has_attribute(__noreturn__))
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (__has_attribute(__optimize__))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (__has_builtin(__builtin_assume))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (__has_builtin(__builtin_assume_aligned))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (__has_builtin(__builtin_expect))
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (__has_builtin(__builtin_unreachable))
# define ASMJIT_CC_HAS_ALIGNAS (__has_extension(__cxx_alignas__))
# define ASMJIT_CC_HAS_ALIGNOF (__has_extension(__cxx_alignof__))
# define ASMJIT_CC_HAS_CONSTEXPR (__has_extension(__cxx_constexpr__))
# define ASMJIT_CC_HAS_DECLTYPE (__has_extension(__cxx_decltype__))
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (__has_extension(__cxx_defaulted_functions__))
# define ASMJIT_CC_HAS_DELETE_FUNCTION (__has_extension(__cxx_deleted_functions__))
# define ASMJIT_CC_HAS_FINAL (__has_extension(__cxx_override_control__))
# define ASMJIT_CC_HAS_INITIALIZER_LIST (__has_extension(__cxx_generalized_initializers__))
# define ASMJIT_CC_HAS_LAMBDA (__has_extension(__cxx_lambdas__))
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (__has_extension(__cxx_unicode_literals__))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (__has_extension(__cxx_unicode_literals__))
# define ASMJIT_CC_HAS_NOEXCEPT (__has_extension(__cxx_noexcept__))
# define ASMJIT_CC_HAS_NULLPTR (__has_extension(__cxx_nullptr__))
# define ASMJIT_CC_HAS_OVERRIDE (__has_extension(__cxx_override_control__))
# define ASMJIT_CC_HAS_RVALUE (__has_extension(__cxx_rvalue_references__))
# define ASMJIT_CC_HAS_STATIC_ASSERT (__has_extension(__cxx_static_assert__))
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (__has_extension(__cxx_variadic_templates__))
#endif
#if ASMJIT_CC_CODEGEAR
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_ALIGNAS (0)
# define ASMJIT_CC_HAS_ALIGNOF (0)
# define ASMJIT_CC_HAS_CONSTEXPR (0)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (0)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (0)
# define ASMJIT_CC_HAS_FINAL (0)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (0)
# define ASMJIT_CC_HAS_LAMBDA (0)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (0)
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (0)
# define ASMJIT_CC_HAS_NOEXCEPT (0)
# define ASMJIT_CC_HAS_NULLPTR (0)
# define ASMJIT_CC_HAS_OVERRIDE (0)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_CODEGEAR >= 0x0610)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (0)
#endif
#if ASMJIT_CC_GCC
# define ASMJIT_CC_HAS_ATTRIBUTE (1)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_GCC_GE(2, 7, 0))
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_GCC_GE(4, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_GCC_GE(3, 4, 0) && !ASMJIT_CC_MINGW)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_GCC_GE(2, 5, 0))
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_GCC_GE(4, 4, 0))
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (ASMJIT_CC_GCC_GE(4, 7, 0))
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (1)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_GCC_GE(4, 8, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_GCC_GE(4, 4, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_GCC_GE(4, 5, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_GCC_GE(4, 6, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_GCC_GE(4, 7, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_GCC_GE(4, 3, 0) && ASMJIT_CC_CXX_VERSION >= 201103L)
#endif
#if ASMJIT_CC_INTEL
# define ASMJIT_CC_HAS_ATTRIBUTE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (ASMJIT_CC_INTEL_COMPAT_MODE)
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (ASMJIT_CC_INTEL_COMPAT_MODE == 0)
# define ASMJIT_CC_HAS_ASSUME (1)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (1)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_INTEL >= 1500)
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_INTEL >= 1500)
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_INTEL >= 1200)
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_INTEL >= 1400 || (ASMJIT_CC_INTEL_COMPAT_MODE > 0 && ASMJIT_CC_INTEL >= 1206))
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_INTEL >= 1206)
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_INTEL >= 1400)
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_INTEL >= 1110)
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_INTEL >= 1110)
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_INTEL >= 1206)
#endif
#if ASMJIT_CC_MSC
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (1)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (1)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (1)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (1)
# define ASMJIT_CC_HAS_ASSUME (1)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
# define ASMJIT_CC_HAS_ALIGNAS (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_ALIGNOF (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_CONSTEXPR (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_DECLTYPE (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_DEFAULT_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_DELETE_FUNCTION (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_FINAL (ASMJIT_CC_MSC_GE(14, 0, 0))
# define ASMJIT_CC_HAS_INITIALIZER_LIST (ASMJIT_CC_MSC_GE(18, 0, 0))
# define ASMJIT_CC_HAS_LAMBDA (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_NATIVE_CHAR (1)
# if defined(_NATIVE_WCHAR_T_DEFINED)
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (1)
# else
# define ASMJIT_CC_HAS_NATIVE_WCHAR_T (0)
# endif
# define ASMJIT_CC_HAS_NATIVE_CHAR16_T (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NATIVE_CHAR32_T (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NOEXCEPT (ASMJIT_CC_MSC_GE(19, 0, 0))
# define ASMJIT_CC_HAS_NULLPTR (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_OVERRIDE (ASMJIT_CC_MSC_GE(14, 0, 0))
# define ASMJIT_CC_HAS_RVALUE (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_STATIC_ASSERT (ASMJIT_CC_MSC_GE(16, 0, 0))
# define ASMJIT_CC_HAS_VARIADIC_TEMPLATES (ASMJIT_CC_MSC_GE(18, 0, 0))
#endif
// Fixup some vendor specific keywords.
#if !defined(ASMJIT_CC_HAS_ASSUME)
# define ASMJIT_CC_HAS_ASSUME (0)
#endif
#if !defined(ASMJIT_CC_HAS_ASSUME_ALIGNED)
# define ASMJIT_CC_HAS_ASSUME_ALIGNED (0)
#endif
// Fixup compilers that don't support '__attribute__'.
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE)
# define ASMJIT_CC_HAS_ATTRIBUTE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALIGNED (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE)
# define ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE)
# define ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_NORETURN)
# define ASMJIT_CC_HAS_ATTRIBUTE_NORETURN (0)
#endif
#if !defined(ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE)
# define ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE (0)
#endif
// Fixup compilers that don't support '__builtin?'.
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED)
# define ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_EXPECT)
# define ASMJIT_CC_HAS_BUILTIN_EXPECT (0)
#endif
#if !defined(ASMJIT_CC_HAS_BUILTIN_UNREACHABLE)
# define ASMJIT_CC_HAS_BUILTIN_UNREACHABLE (0)
#endif
// Fixup compilers that don't support 'declspec'.
#if !defined(ASMJIT_CC_HAS_DECLSPEC_ALIGN)
# define ASMJIT_CC_HAS_DECLSPEC_ALIGN (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE)
# define ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NOINLINE)
# define ASMJIT_CC_HAS_DECLSPEC_NOINLINE (0)
#endif
#if !defined(ASMJIT_CC_HAS_DECLSPEC_NORETURN)
# define ASMJIT_CC_HAS_DECLSPEC_NORETURN (0)
#endif
// [@CC_FEATURES}@]
// [@CC_API{@]
// \def ASMJIT_API
// The decorated function is asmjit API and should be exported.
#if !defined(ASMJIT_API)
# if defined(ASMJIT_STATIC)
# define ASMJIT_API
# elif ASMJIT_OS_WINDOWS
# if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_CC_MINGW
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __attribute__((__dllexport__))
# else
# define ASMJIT_API __attribute__((__dllimport__))
# endif
# else
# if defined(ASMJIT_EXPORTS)
# define ASMJIT_API __declspec(dllexport)
# else
# define ASMJIT_API __declspec(dllimport)
# endif
# endif
# else
# if ASMJIT_CC_CLANG || ASMJIT_CC_GCC_GE(4, 0, 0) || ASMJIT_CC_INTEL
# define ASMJIT_API __attribute__((__visibility__("default")))
# endif
# endif
#endif
// [@CC_API}@]
// [@CC_VARAPI{@]
// \def ASMJIT_VARAPI
// The decorated variable is part of asmjit API and is exported.
#if !defined(ASMJIT_VARAPI)
# define ASMJIT_VARAPI extern ASMJIT_API
#endif
// [@CC_VARAPI}@]
// [@CC_VIRTAPI{@]
// \def ASMJIT_VIRTAPI
// The decorated class has a virtual table and is part of asmjit API.
//
// This is basically a workaround. When using MSVC and marking class as DLL
// export everything gets exported, which is unwanted in most projects. MSVC
// automatically exports typeinfo and vtable if at least one symbol of the
// class is exported. However, GCC has some strange behavior that even if
// one or more symbol is exported it doesn't export typeinfo unless the
// class itself is decorated with "visibility(default)" (i.e. asmjit_API).
#if (ASMJIT_CC_GCC || ASMJIT_CC_CLANG) && !ASMJIT_OS_WINDOWS
# define ASMJIT_VIRTAPI ASMJIT_API
#else
# define ASMJIT_VIRTAPI
#endif
// [@CC_VIRTAPI}@]
// [@CC_INLINE{@]
// \def ASMJIT_INLINE
// Always inline the decorated function.
#if ASMJIT_CC_HAS_ATTRIBUTE_ALWAYS_INLINE
# define ASMJIT_INLINE inline __attribute__((__always_inline__))
#elif ASMJIT_CC_HAS_DECLSPEC_FORCEINLINE
# define ASMJIT_INLINE __forceinline
#else
# define ASMJIT_INLINE inline
#endif
// [@CC_INLINE}@]
// [@CC_NOINLINE{@]
// \def ASMJIT_NOINLINE
// Never inline the decorated function.
#if ASMJIT_CC_HAS_ATTRIBUTE_NOINLINE
# define ASMJIT_NOINLINE __attribute__((__noinline__))
#elif ASMJIT_CC_HAS_DECLSPEC_NOINLINE
# define ASMJIT_NOINLINE __declspec(noinline)
#else
# define ASMJIT_NOINLINE
#endif
// [@CC_NOINLINE}@]
// [@CC_NORETURN{@]
// \def ASMJIT_NORETURN
// The decorated function never returns (exit, assertion failure, etc...).
#if ASMJIT_CC_HAS_ATTRIBUTE_NORETURN
# define ASMJIT_NORETURN __attribute__((__noreturn__))
#elif ASMJIT_CC_HAS_DECLSPEC_NORETURN
# define ASMJIT_NORETURN __declspec(noreturn)
#else
# define ASMJIT_NORETURN
#endif
// [@CC_NORETURN}@]
// [@CC_CDECL{@]
// \def ASMJIT_CDECL
// Standard C function calling convention decorator (__cdecl).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_CDECL __attribute__((__cdecl__))
# else
# define ASMJIT_CDECL __cdecl
# endif
#else
# define ASMJIT_CDECL
#endif
// [@CC_CDECL}@]
// [@CC_STDCALL{@]
// \def ASMJIT_STDCALL
// StdCall function calling convention decorator (__stdcall).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_STDCALL __attribute__((__stdcall__))
# else
# define ASMJIT_STDCALL __stdcall
# endif
#else
# define ASMJIT_STDCALL
#endif
// [@CC_STDCALL}@]
// [@CC_FASTCALL{@]
// \def ASMJIT_FASTCALL
// FastCall function calling convention decorator (__fastcall).
#if ASMJIT_ARCH_X86
# if ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_FASTCALL __attribute__((__fastcall__))
# else
# define ASMJIT_FASTCALL __fastcall
# endif
#else
# define ASMJIT_FASTCALL
#endif
// [@CC_FASTCALL}@]
// [@CC_REGPARM{@]
// \def ASMJIT_REGPARM(n)
// A custom calling convention which passes n arguments in registers.
#if ASMJIT_ARCH_X86 && ASMJIT_CC_HAS_ATTRIBUTE
# define ASMJIT_REGPARM(n) __attribute__((__regparm__(n)))
#else
# define ASMJIT_REGPARM(n)
#endif
// [@CC_REGPARM}@]
// [@CC_NOEXCEPT{@]
// \def ASMJIT_NOEXCEPT
// The decorated function never throws an exception (noexcept).
#if ASMJIT_CC_HAS_NOEXCEPT
# define ASMJIT_NOEXCEPT noexcept
#else
# define ASMJIT_NOEXCEPT
#endif
// [@CC_NOEXCEPT}@]
// [@CC_NOP{@]
// \def ASMJIT_NOP
// No operation.
#if !defined(ASMJIT_NOP)
# define ASMJIT_NOP ((void)0)
#endif
// [@CC_NOP}@]
// [@CC_ASSUME{@]
// \def ASMJIT_ASSUME(exp)
// Assume that the expression exp is always true.
#if ASMJIT_CC_HAS_ASSUME
# define ASMJIT_ASSUME(exp) __assume(exp)
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME
# define ASMJIT_ASSUME(exp) __builtin_assume(exp)
#elif ASMJIT_CC_HAS_BUILTIN_UNREACHABLE
# define ASMJIT_ASSUME(exp) do { if (!(exp)) __builtin_unreachable(); } while (0)
#else
# define ASMJIT_ASSUME(exp) ((void)0)
#endif
// [@CC_ASSUME}@]
// [@CC_ASSUME_ALIGNED{@]
// \def ASMJIT_ASSUME_ALIGNED(p, alignment)
// Assume that the pointer 'p' is aligned to at least 'alignment' bytes.
#if ASMJIT_CC_HAS_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) __assume_aligned(p, alignment)
#elif ASMJIT_CC_HAS_BUILTIN_ASSUME_ALIGNED
# define ASMJIT_ASSUME_ALIGNED(p, alignment) p = __builtin_assume_aligned(p, alignment)
#else
# define ASMJIT_ASSUME_ALIGNED(p, alignment) ((void)0)
#endif
// [@CC_ASSUME_ALIGNED}@]
// [@CC_EXPECT{@]
// \def ASMJIT_LIKELY(exp)
// Expression exp is likely to be true.
//
// \def ASMJIT_UNLIKELY(exp)
// Expression exp is likely to be false.
#if ASMJIT_CC_HAS_BUILTIN_EXPECT
# define ASMJIT_LIKELY(exp) __builtin_expect(!!(exp), 1)
# define ASMJIT_UNLIKELY(exp) __builtin_expect(!!(exp), 0)
#else
# define ASMJIT_LIKELY(exp) (exp)
# define ASMJIT_UNLIKELY(exp) (exp)
#endif
// [@CC_EXPECT}@]
// [@CC_FALLTHROUGH{@]
// \def ASMJIT_FALLTHROUGH
// The code falls through annotation (switch / case).
#if ASMJIT_CC_CLANG && __cplusplus >= 201103L
# define ASMJIT_FALLTHROUGH [[clang::fallthrough]]
#else
# define ASMJIT_FALLTHROUGH (void)0
#endif
// [@CC_FALLTHROUGH}@]
// [@CC_UNUSED{@]
// \def ASMJIT_UNUSED(x)
// Mark a variable x as unused.
#define ASMJIT_UNUSED(x) (void)(x)
// [@CC_UNUSED}@]
// [@CC_OFFSET_OF{@]
// \def ASMJIT_OFFSET_OF(x, y).
// Get the offset of a member y of a struct x at compile-time.
#define ASMJIT_OFFSET_OF(x, y) ((int)(intptr_t)((const char*)&((const x*)0x1)->y) - 1)
// [@CC_OFFSET_OF}@]
// [@CC_ARRAY_SIZE{@]
// \def ASMJIT_ARRAY_SIZE(x)
// Get the array size of x at compile-time.
#define ASMJIT_ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
// [@CC_ARRAY_SIZE}@]
// ============================================================================
// [asmjit::Build - STDTYPES]
// ============================================================================
// [@STDTYPES{@]
#if defined(__MINGW32__) || defined(__MINGW64__)
# include <sys/types.h>
#endif
#if defined(_MSC_VER) && (_MSC_VER < 1600)
# include <limits.h>
# if !defined(ASMJIT_SUPPRESS_STD_TYPES)
# if (_MSC_VER < 1300)
typedef signed char int8_t;
typedef signed short int16_t;
typedef signed int int32_t;
typedef signed __int64 int64_t;
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
typedef unsigned int uint32_t;
typedef unsigned __int64 uint64_t;
# else
typedef __int8 int8_t;
typedef __int16 int16_t;
typedef __int32 int32_t;
typedef __int64 int64_t;
typedef unsigned __int8 uint8_t;
typedef unsigned __int16 uint16_t;
typedef unsigned __int32 uint32_t;
typedef unsigned __int64 uint64_t;
# endif
# endif
#else
# include <stdint.h>
# include <limits.h>
#endif
// [@STDTYPES}@]
// ============================================================================
// [asmjit::Build - Dependencies]
// ============================================================================
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <new>
#if ASMJIT_OS_POSIX
# include <pthread.h>
#endif // ASMJIT_OS_POSIX
// ============================================================================
// [asmjit::Build - Additional]
// ============================================================================
// Build host architecture if no architecture is selected.
#if !defined(ASMJIT_BUILD_HOST) && \
!defined(ASMJIT_BUILD_X86) && \
!defined(ASMJIT_BUILD_ARM)
# define ASMJIT_BUILD_HOST
#endif
// Detect host architecture if building only for host.
#if defined(ASMJIT_BUILD_HOST)
# if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && !defined(ASMJIT_BUILD_X86)
# define ASMJIT_BUILD_X86
# endif // ASMJIT_ARCH_X86
#endif // ASMJIT_BUILD_HOST
#if ASMJIT_CC_MSC
# define ASMJIT_UINT64_C(x) x##ui64
#else
# define ASMJIT_UINT64_C(x) x##ull
#endif
#if ASMJIT_ARCH_LE
# define ASMJIT_PACK32_4x8(A, B, C, D) ((A) + ((B) << 8) + ((C) << 16) + ((D) << 24))
#else
# define ASMJIT_PACK32_4x8(A, B, C, D) ((D) + ((C) << 8) + ((B) << 16) + ((A) << 24))
#endif
// Internal macros that are only used when building AsmJit itself.
#if defined(ASMJIT_EXPORTS)
# if !defined(ASMJIT_DEBUG) && ASMJIT_CC_HAS_ATTRIBUTE_OPTIMIZE
# define ASMJIT_FAVOR_SIZE __attribute__((__optimize__("Os")))
# else
# define ASMJIT_FAVOR_SIZE
# endif
#endif // ASMJIT_EXPORTS
// ============================================================================
// [asmjit::Build - Test]
// ============================================================================
// Include a unit testing package if this is a `asmjit_test` build.
#if defined(ASMJIT_TEST)
# include "../../test/broken.h"
#endif // ASMJIT_TEST
// [Guard]
#endif // _ASMJIT_BUILD_H
...@@ -8,27 +8,27 @@ ...@@ -8,27 +8,27 @@
#ifndef _ASMJIT_BASE_H #ifndef _ASMJIT_BASE_H
#define _ASMJIT_BASE_H #define _ASMJIT_BASE_H
// [Dependencies - AsmJit] // [Dependencies]
#include "build.h" #include "./base/arch.h"
#include "./base/assembler.h"
#include "base/assembler.h" #include "./base/codebuilder.h"
#include "base/codegen.h" #include "./base/codecompiler.h"
#include "base/compiler.h" #include "./base/codeemitter.h"
#include "base/constpool.h" #include "./base/codeholder.h"
#include "base/containers.h" #include "./base/constpool.h"
#include "base/cpuinfo.h" #include "./base/cpuinfo.h"
#include "base/cputicks.h" #include "./base/func.h"
#include "base/error.h" #include "./base/globals.h"
#include "base/globals.h" #include "./base/inst.h"
#include "base/intutil.h" #include "./base/logging.h"
#include "base/lock.h" #include "./base/operand.h"
#include "base/logger.h" #include "./base/osutils.h"
#include "base/operand.h" #include "./base/runtime.h"
#include "base/runtime.h" #include "./base/simdtypes.h"
#include "base/string.h" #include "./base/string.h"
#include "base/vectypes.h" #include "./base/utils.h"
#include "base/vmem.h" #include "./base/vmem.h"
#include "base/zone.h" #include "./base/zone.h"
// [Guard] // [Guard]
#endif // _ASMJIT_BASE_H #endif // _ASMJIT_BASE_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/arch.h"
#if defined(ASMJIT_BUILD_X86)
#include "../x86/x86operand.h"
#endif // ASMJIT_BUILD_X86
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::ArchInfo]
// ============================================================================
static const uint32_t archInfoTable[] = {
// <-------------+---------------------+-----------------------+-------+
// | Type | SubType | GPInfo|
// <-------------+---------------------+-----------------------+-------+
ASMJIT_PACK32_4x8(ArchInfo::kTypeNone , ArchInfo::kSubTypeNone, 0, 0),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX86 , ArchInfo::kSubTypeNone, 4, 8),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX64 , ArchInfo::kSubTypeNone, 8, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeX32 , ArchInfo::kSubTypeNone, 8, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeA32 , ArchInfo::kSubTypeNone, 4, 16),
ASMJIT_PACK32_4x8(ArchInfo::kTypeA64 , ArchInfo::kSubTypeNone, 8, 32)
};
ASMJIT_FAVOR_SIZE void ArchInfo::init(uint32_t type, uint32_t subType) noexcept {
uint32_t index = type < ASMJIT_ARRAY_SIZE(archInfoTable) ? type : uint32_t(0);
// Make sure the `archInfoTable` array is correctly indexed.
_signature = archInfoTable[index];
ASMJIT_ASSERT(_type == index);
// Even if the architecture is not known we setup its type and sub-type,
// however, such architecture is not really useful.
_type = type;
_subType = subType;
}
// ============================================================================
// [asmjit::ArchUtils]
// ============================================================================
ASMJIT_FAVOR_SIZE Error ArchUtils::typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept {
uint32_t typeId = typeIdInOut;
// Zero the signature so it's clear in case that typeId is not invalid.
regInfo._signature = 0;
#if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType)) {
// Passed RegType instead of TypeId?
if (typeId <= Reg::kRegMax)
typeId = x86OpData.archRegs.regTypeToTypeId[typeId];
if (ASMJIT_UNLIKELY(!TypeId::isValid(typeId)))
return DebugUtils::errored(kErrorInvalidTypeId);
// First normalize architecture dependent types.
if (TypeId::isAbstract(typeId)) {
if (typeId == TypeId::kIntPtr)
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kI32 : TypeId::kI64;
else
typeId = (archType == ArchInfo::kTypeX86) ? TypeId::kU32 : TypeId::kU64;
}
// Type size helps to construct all kinds of registers. If the size is zero
// then the TypeId is invalid.
uint32_t size = TypeId::sizeOf(typeId);
if (ASMJIT_UNLIKELY(!size))
return DebugUtils::errored(kErrorInvalidTypeId);
if (ASMJIT_UNLIKELY(typeId == TypeId::kF80))
return DebugUtils::errored(kErrorInvalidUseOfF80);
uint32_t regType = 0;
switch (typeId) {
case TypeId::kI8:
case TypeId::kU8:
regType = X86Reg::kRegGpbLo;
break;
case TypeId::kI16:
case TypeId::kU16:
regType = X86Reg::kRegGpw;
break;
case TypeId::kI32:
case TypeId::kU32:
regType = X86Reg::kRegGpd;
break;
case TypeId::kI64:
case TypeId::kU64:
if (archType == ArchInfo::kTypeX86)
return DebugUtils::errored(kErrorInvalidUseOfGpq);
regType = X86Reg::kRegGpq;
break;
// F32 and F64 are always promoted to use vector registers.
case TypeId::kF32:
typeId = TypeId::kF32x1;
regType = X86Reg::kRegXmm;
break;
case TypeId::kF64:
typeId = TypeId::kF64x1;
regType = X86Reg::kRegXmm;
break;
// Mask registers {k}.
case TypeId::kMask8:
case TypeId::kMask16:
case TypeId::kMask32:
case TypeId::kMask64:
regType = X86Reg::kRegK;
break;
// MMX registers.
case TypeId::kMmx32:
case TypeId::kMmx64:
regType = X86Reg::kRegMm;
break;
// XMM|YMM|ZMM registers.
default:
if (size <= 16)
regType = X86Reg::kRegXmm;
else if (size == 32)
regType = X86Reg::kRegYmm;
else
regType = X86Reg::kRegZmm;
break;
}
typeIdInOut = typeId;
regInfo._signature = x86OpData.archRegs.regInfo[regType].getSignature();
return kErrorOk;
}
#endif // ASMJIT_BUILD_X86
return DebugUtils::errored(kErrorInvalidArch);
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_ARCH_H
#define _ASMJIT_BASE_ARCH_H
// [Dependencies]
#include "../base/globals.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::ArchInfo]
// ============================================================================
class ArchInfo {
public:
//! Architecture type.
ASMJIT_ENUM(Type) {
kTypeNone = 0, //!< No/Unknown architecture.
// X86 architectures.
kTypeX86 = 1, //!< X86 architecture (32-bit).
kTypeX64 = 2, //!< X64 architecture (64-bit) (AMD64).
kTypeX32 = 3, //!< X32 architecture (DEAD-END).
// ARM architectures.
kTypeA32 = 4, //!< ARM 32-bit architecture (AArch32/ARM/THUMB).
kTypeA64 = 5, //!< ARM 64-bit architecture (AArch64).
//! Architecture detected at compile-time (architecture of the host).
kTypeHost = ASMJIT_ARCH_X86 ? kTypeX86 :
ASMJIT_ARCH_X64 ? kTypeX64 :
ASMJIT_ARCH_ARM32 ? kTypeA32 :
ASMJIT_ARCH_ARM64 ? kTypeA64 : kTypeNone
};
//! Architecture sub-type or execution mode.
ASMJIT_ENUM(SubType) {
kSubTypeNone = 0, //!< Default mode (or no specific mode).
// X86 sub-types.
kSubTypeX86_AVX = 1, //!< Code generation uses AVX by default (VEC instructions).
kSubTypeX86_AVX2 = 2, //!< Code generation uses AVX2 by default (VEC instructions).
kSubTypeX86_AVX512 = 3, //!< Code generation uses AVX-512F by default (+32 vector regs).
kSubTypeX86_AVX512VL = 4, //!< Code generation uses AVX-512F-VL by default (+VL extensions).
// ARM sub-types.
kSubTypeA32_Thumb = 8, //!< THUMB|THUMB2 sub-type (only ARM in 32-bit mode).
#if (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512VL__)
kSubTypeHost = kSubTypeX86_AVX512VL
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX512F__)
kSubTypeHost = kSubTypeX86_AVX512
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX2__)
kSubTypeHost = kSubTypeX86_AVX2
#elif (ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64) && defined(__AVX__)
kSubTypeHost = kSubTypeX86_AVX
#elif (ASMJIT_ARCH_ARM32) && (defined(_M_ARMT) || defined(__thumb__) || defined(__thumb2__))
kSubTypeHost = kSubTypeA32_Thumb
#else
kSubTypeHost = 0
#endif
};
// --------------------------------------------------------------------------
// [Utilities]
// --------------------------------------------------------------------------
static ASMJIT_INLINE bool isX86Family(uint32_t archType) noexcept { return archType >= kTypeX86 && archType <= kTypeX32; }
static ASMJIT_INLINE bool isArmFamily(uint32_t archType) noexcept { return archType >= kTypeA32 && archType <= kTypeA64; }
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE ArchInfo() noexcept : _signature(0) {}
ASMJIT_INLINE ArchInfo(const ArchInfo& other) noexcept = default;
explicit ASMJIT_INLINE ArchInfo(uint32_t type, uint32_t subType = kSubTypeNone) noexcept { init(type, subType); }
ASMJIT_INLINE static ArchInfo host() noexcept { return ArchInfo(kTypeHost, kSubTypeHost); }
// --------------------------------------------------------------------------
// [Init / Reset]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool isInitialized() const noexcept { return _type != kTypeNone; }
ASMJIT_API void init(uint32_t type, uint32_t subType = kSubTypeNone) noexcept;
ASMJIT_INLINE void reset() noexcept { _signature = 0; }
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get if the architecture is 32-bit.
ASMJIT_INLINE bool is32Bit() const noexcept { return _gpSize == 4; }
//! Get if the architecture is 64-bit.
ASMJIT_INLINE bool is64Bit() const noexcept { return _gpSize == 8; }
//! Get architecture type, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get architecture sub-type, see \ref SubType.
//!
//! X86 & X64
//! ---------
//!
//! Architecture subtype describe the highest instruction-set level that can
//! be used.
//!
//! ARM32
//! -----
//!
//! Architecture mode means the instruction encoding to be used when generating
//! machine code, thus mode can be used to force generation of THUMB and THUMB2
//! encoding or regular ARM encoding.
//!
//! ARM64
//! -----
//!
//! No meaning yet.
ASMJIT_INLINE uint32_t getSubType() const noexcept { return _subType; }
//! Get if the architecture is X86, X64, or X32.
ASMJIT_INLINE bool isX86Family() const noexcept { return isX86Family(_type); }
//! Get if the architecture is ARM32 or ARM64.
ASMJIT_INLINE bool isArmFamily() const noexcept { return isArmFamily(_type); }
//! Get a size of a general-purpose register.
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return _gpSize; }
//! Get number of general-purpose registers.
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return _gpCount; }
// --------------------------------------------------------------------------
// [Operator Overload]
// --------------------------------------------------------------------------
ASMJIT_INLINE ArchInfo& operator=(const ArchInfo& other) noexcept = default;
ASMJIT_INLINE bool operator==(const ArchInfo& other) const noexcept { return _signature == other._signature; }
ASMJIT_INLINE bool operator!=(const ArchInfo& other) const noexcept { return _signature != other._signature; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _type; //!< Architecture type.
uint8_t _subType; //!< Architecture sub-type.
uint8_t _gpSize; //!< Default size of a general purpose register.
uint8_t _gpCount; //!< Count of all general purpose registers.
};
uint32_t _signature; //!< Architecture signature (32-bit int).
};
};
// ============================================================================
// [asmjit::ArchRegs]
// ============================================================================
//! Information about all architecture registers.
struct ArchRegs {
//! Register information and signatures indexed by \ref Reg::Type.
RegInfo regInfo[Reg::kRegMax + 1];
//! Count (maximum) of registers per \ref Reg::Type.
uint8_t regCount[Reg::kRegMax + 1];
//! Converts RegType to TypeId, see \ref TypeId::Id.
uint8_t regTypeToTypeId[Reg::kRegMax + 1];
};
// ============================================================================
// [asmjit::ArchUtils]
// ============================================================================
struct ArchUtils {
ASMJIT_API static Error typeIdToRegInfo(uint32_t archType, uint32_t& typeIdInOut, RegInfo& regInfo) noexcept;
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_ARCH_H
...@@ -7,16 +7,14 @@ ...@@ -7,16 +7,14 @@
// [Export] // [Export]
#define ASMJIT_EXPORTS #define ASMJIT_EXPORTS
// [Dependencies - AsmJit] // [Dependencies]
#include "../base/assembler.h" #include "../base/assembler.h"
#include "../base/intutil.h" #include "../base/constpool.h"
#include "../base/utils.h"
#include "../base/vmem.h" #include "../base/vmem.h"
// [Dependenceis - C]
#include <stdarg.h>
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../asmjit_apibegin.h"
namespace asmjit { namespace asmjit {
...@@ -24,356 +22,426 @@ namespace asmjit { ...@@ -24,356 +22,426 @@ namespace asmjit {
// [asmjit::Assembler - Construction / Destruction] // [asmjit::Assembler - Construction / Destruction]
// ============================================================================ // ============================================================================
Assembler::Assembler(Runtime* runtime) : Assembler::Assembler() noexcept
CodeGen(runtime), : CodeEmitter(kTypeAssembler),
_buffer(NULL), _section(nullptr),
_end(NULL), _bufferData(nullptr),
_cursor(NULL), _bufferEnd(nullptr),
_trampolineSize(0), _bufferPtr(nullptr),
_comment(NULL), _op4(),
_unusedLinks(NULL) {} _op5() {}
Assembler::~Assembler() { Assembler::~Assembler() noexcept {
reset(true); if (_code) sync();
} }
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Clear / Reset] // [asmjit::Assembler - Events]
// ============================================================================ // ============================================================================
void Assembler::reset(bool releaseMemory) { Error Assembler::onAttach(CodeHolder* code) noexcept {
// CodeGen members. // Attach to the end of the .text section.
_baseAddress = kNoBaseAddress; _section = code->_sections[0];
_instOptions = 0; uint8_t* p = _section->_buffer._data;
_error = kErrorOk;
_baseZone.reset(releaseMemory); _bufferData = p;
_bufferEnd = p + _section->_buffer._capacity;
_bufferPtr = p + _section->_buffer._length;
// Assembler members. _op4.reset();
if (releaseMemory && _buffer != NULL) { _op5.reset();
ASMJIT_FREE(_buffer);
_buffer = NULL; return Base::onAttach(code);
_end = NULL; }
}
_cursor = _buffer; Error Assembler::onDetach(CodeHolder* code) noexcept {
_trampolineSize = 0; _section = nullptr;
_bufferData = nullptr;
_bufferEnd = nullptr;
_bufferPtr = nullptr;
_comment = NULL; _op4.reset();
_unusedLinks = NULL; _op5.reset();
_labelList.reset(releaseMemory); return Base::onDetach(code);
_relocList.reset(releaseMemory);
} }
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Buffer] // [asmjit::Assembler - Code-Generation]
// ============================================================================ // ============================================================================
Error Assembler::_grow(size_t n) { Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
size_t capacity = getCapacity(); _op4 = o4;
size_t after = getOffset() + n; _op5 = o5;
_options |= kOptionOp4Op5Used;
// Overflow. return _emit(instId, o0, o1, o2, o3);
if (n > IntUtil::maxUInt<uintptr_t>() - capacity) }
return setError(kErrorNoHeapMemory);
// Grow is called when allocation is needed, so it shouldn't happen, but on
// the other hand it is simple to catch and it's not an error.
if (after <= capacity)
return kErrorOk;
if (capacity < kMemAllocOverhead)
capacity = kMemAllocOverhead;
else
capacity += kMemAllocOverhead;
do { Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
size_t oldCapacity = capacity; const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5:
_op4 = op[4];
_op5.reset();
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
case 6:
_op4 = op[4];
_op5 = op[5];
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
if (capacity < kMemAllocGrowMax) // ============================================================================
capacity *= 2; // [asmjit::Assembler - Sync]
else // ============================================================================
capacity += kMemAllocGrowMax;
// Overflow. void Assembler::sync() noexcept {
if (oldCapacity > capacity) ASMJIT_ASSERT(_code != nullptr); // Only called by CodeHolder, so we must be attached.
return setError(kErrorNoHeapMemory); ASMJIT_ASSERT(_section != nullptr); // One section must always be active, no matter what.
} while (capacity - kMemAllocOverhead < after); ASMJIT_ASSERT(_bufferData == _section->_buffer._data); // `_bufferStart` is a shortcut to `_section->buffer.data`.
capacity -= kMemAllocOverhead; // Update only if the current offset is greater than the section length.
return _reserve(capacity); size_t offset = (size_t)(_bufferPtr - _bufferData);
if (_section->getBuffer().getLength() < offset)
_section->_buffer._length = offset;
} }
Error Assembler::_reserve(size_t n) { // ============================================================================
size_t capacity = getCapacity(); // [asmjit::Assembler - Code-Buffer]
if (n <= capacity) // ============================================================================
return kErrorOk;
uint8_t* newBuffer;
if (_buffer == NULL)
newBuffer = static_cast<uint8_t*>(ASMJIT_ALLOC(n));
else
newBuffer = static_cast<uint8_t*>(ASMJIT_REALLOC(_buffer, n));
if (newBuffer == NULL) Error Assembler::setOffset(size_t offset) {
return setError(kErrorNoHeapMemory); if (_lastError) return _lastError;
size_t offset = getOffset(); size_t length = std::max(_section->getBuffer().getLength(), getOffset());
if (ASMJIT_UNLIKELY(offset > length))
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
_buffer = newBuffer; // If the `Assembler` generated any code the `_bufferPtr` may be higher than
_end = _buffer + n; // the section length stored in `CodeHolder` as it doesn't update it each
_cursor = newBuffer + offset; // time it generates machine code. This is the same as calling `sync()`.
if (_section->_buffer._length < length)
_section->_buffer._length = length;
_bufferPtr = _bufferData + offset;
return kErrorOk; return kErrorOk;
} }
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Label] // [asmjit::Assembler - Comment]
// ============================================================================ // ============================================================================
Error Assembler::_registerIndexedLabels(size_t index) { Error Assembler::comment(const char* s, size_t len) {
size_t i = _labelList.getLength(); if (_lastError) return _lastError;
if (index < i)
return kErrorOk;
if (_labelList._grow(index - i) != kErrorOk)
return setError(kErrorNoHeapMemory);
LabelData data;
data.offset = -1;
data.links = NULL;
do { #if !defined(ASMJIT_DISABLE_LOGGING)
_labelList.append(data); if (_globalOptions & kOptionLoggingEnabled) {
} while (++i < index); Logger* logger = _code->getLogger();
logger->log(s, len);
logger->log("\n", 1);
return kErrorOk;
}
#else
ASMJIT_UNUSED(s);
ASMJIT_UNUSED(len);
#endif
return kErrorOk; return kErrorOk;
} }
Error Assembler::_newLabel(Label* dst) { // ============================================================================
dst->_label.op = kOperandTypeLabel; // [asmjit::Assembler - Building Blocks]
dst->_label.size = 0; // ============================================================================
dst->_label.id = OperandUtil::makeLabelId(static_cast<uint32_t>(_labelList.getLength()));
LabelData data;
data.offset = -1;
data.links = NULL;
if (_labelList.append(data) != kErrorOk)
goto _NoMemory;
return kErrorOk;
_NoMemory: Label Assembler::newLabel() {
dst->_label.id = kInvalidValue; uint32_t id = 0;
return setError(kErrorNoHeapMemory); if (!_lastError) {
ASMJIT_ASSERT(_code != nullptr);
Error err = _code->newLabelId(id);
if (ASMJIT_UNLIKELY(err)) setLastError(err);
}
return Label(id);
} }
LabelLink* Assembler::_newLabelLink() { Label Assembler::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
LabelLink* link = _unusedLinks; uint32_t id = 0;
if (!_lastError) {
if (link) { ASMJIT_ASSERT(_code != nullptr);
_unusedLinks = link->prev; Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
if (ASMJIT_UNLIKELY(err)) setLastError(err);
} }
else { return Label(id);
link = _baseZone.allocT<LabelLink>();
if (link == NULL)
return NULL;
}
link->prev = NULL;
link->offset = 0;
link->displacement = 0;
link->relocId = -1;
return link;
} }
Error Assembler::bind(const Label& label) { Error Assembler::bind(const Label& label) {
// Get label data based on label id. if (_lastError) return _lastError;
uint32_t index = label.getId(); ASMJIT_ASSERT(_code != nullptr);
LabelData* data = getLabelData(index);
LabelEntry* le = _code->getLabelEntry(label);
if (ASMJIT_UNLIKELY(!le))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
// Label can be bound only once. // Label can be bound only once.
if (data->offset != -1) if (ASMJIT_UNLIKELY(le->isBound()))
return setError(kErrorLabelAlreadyBound); return setLastError(DebugUtils::errored(kErrorLabelAlreadyBound));
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled) {
StringBuilderTmp<256> sb;
if (le->hasName())
sb.setFormat("%s:", le->getName());
else
sb.setFormat("L%u:", Operand::unpackId(label.getId()));
#if !defined(ASMJIT_DISABLE_LOGGER) size_t binSize = 0;
if (_logger) if (!_code->_logger->hasOption(Logger::kOptionBinaryForm))
_logger->logFormat(kLoggerStyleLabel, "L%u:\n", index); binSize = Globals::kInvalidIndex;
#endif // !ASMJIT_DISABLE_LOGGER
Error error = kErrorOk; Logging::formatLine(sb, nullptr, binSize, 0, 0, getInlineComment());
_code->_logger->log(sb.getData(), sb.getLength());
}
#endif // !ASMJIT_DISABLE_LOGGING
Error err = kErrorOk;
size_t pos = getOffset(); size_t pos = getOffset();
LabelLink* link = data->links; LabelLink* link = le->_links;
LabelLink* prev = NULL; LabelLink* prev = nullptr;
while (link) { while (link) {
intptr_t offset = link->offset; intptr_t offset = link->offset;
uint32_t relocId = link->relocId;
if (link->relocId != -1) { if (relocId != RelocEntry::kInvalidId) {
// Handle RelocData - We have to update RelocData information instead of // Adjust relocation data.
// patching the displacement in LabelData. RelocEntry* re = _code->_relocations[relocId];
_relocList[link->relocId].data += static_cast<Ptr>(pos); re->_data += static_cast<uint64_t>(pos);
} }
else { else {
// Not using relocId, this means that we are overwriting a real // Not using relocId, this means that we are overwriting a real
// displacement in the binary stream. // displacement in the CodeBuffer.
int32_t patchedValue = static_cast<int32_t>( int32_t patchedValue = static_cast<int32_t>(
static_cast<intptr_t>(pos) - offset + link->displacement); static_cast<intptr_t>(pos) - offset + link->rel);
// Size of the value we are going to patch. Only BYTE/DWORD is allowed. // Size of the value we are going to patch. Only BYTE/DWORD is allowed.
uint32_t size = getByteAt(offset); uint32_t size = _bufferData[offset];
ASMJIT_ASSERT(size == 1 || size == 4); if (size == 4)
Utils::writeI32u(_bufferData + offset, static_cast<int32_t>(patchedValue));
if (size == 4) { else if (size == 1 && Utils::isInt8(patchedValue))
setInt32At(offset, patchedValue); _bufferData[offset] = static_cast<uint8_t>(patchedValue & 0xFF);
} else
else { err = DebugUtils::errored(kErrorInvalidDisplacement);
ASMJIT_ASSERT(size == 1);
if (IntUtil::isInt8(patchedValue))
setByteAt(offset, static_cast<uint8_t>(patchedValue & 0xFF));
else
error = kErrorIllegalDisplacement;
}
} }
prev = link->prev; prev = link->prev;
link = prev; _code->_unresolvedLabelsCount--;
} _code->_baseHeap.release(link, sizeof(LabelLink));
// Chain unused links.
link = data->links;
if (link) {
if (prev == NULL)
prev = link;
prev->prev = _unusedLinks; link = prev;
_unusedLinks = link;
} }
// Set as bound (offset is zero or greater and no links). // Set as bound.
data->offset = pos; le->_sectionId = _section->getId();
data->links = NULL; le->_offset = pos;
le->_links = nullptr;
resetInlineComment();
if (error != kErrorOk) if (err != kErrorOk)
return setError(error); return setLastError(err);
return error; return kErrorOk;
} }
// ============================================================================
// [asmjit::Assembler - Embed]
// ============================================================================
Error Assembler::embed(const void* data, uint32_t size) { Error Assembler::embed(const void* data, uint32_t size) {
if (_lastError) return _lastError;
if (getRemainingSpace() < size) { if (getRemainingSpace() < size) {
Error error = _grow(size); Error err = _code->growBuffer(&_section->_buffer, size);
if (error != kErrorOk) if (ASMJIT_UNLIKELY(err != kErrorOk)) return setLastError(err);
return setError(error);
} }
uint8_t* cursor = getCursor(); ::memcpy(_bufferPtr, data, size);
::memcpy(cursor, data, size); _bufferPtr += size;
setCursor(cursor + size);
#if !defined(ASMJIT_DISABLE_LOGGER) #if !defined(ASMJIT_DISABLE_LOGGING)
if (_logger) if (_globalOptions & kOptionLoggingEnabled)
_logger->logBinary(kLoggerStyleData, data, size); _code->_logger->logBinary(data, size);
#endif // !ASMJIT_DISABLE_LOGGER #endif // !ASMJIT_DISABLE_LOGGING
return kErrorOk; return kErrorOk;
} }
// ============================================================================ Error Assembler::embedLabel(const Label& label) {
// [asmjit::Assembler - Reloc] if (_lastError) return _lastError;
// ============================================================================ ASMJIT_ASSERT(_code != nullptr);
RelocEntry* re;
LabelEntry* le = _code->getLabelEntry(label);
if (ASMJIT_UNLIKELY(!le))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
Error err;
uint32_t gpSize = getGpSize();
if (getRemainingSpace() < gpSize) {
err = _code->growBuffer(&_section->_buffer, gpSize);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
}
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
_code->_logger->logf(gpSize == 4 ? ".dd L%u\n" : ".dq L%u\n", Operand::unpackId(label.getId()));
#endif // !ASMJIT_DISABLE_LOGGING
err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, gpSize);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
size_t Assembler::relocCode(void* dst, Ptr baseAddress) const { re->_sourceSectionId = _section->getId();
if (baseAddress == kNoBaseAddress) re->_sourceOffset = static_cast<uint64_t>(getOffset());
baseAddress = hasBaseAddress() ? getBaseAddress() : static_cast<Ptr>((uintptr_t)dst);
else if (getBaseAddress() != baseAddress)
return 0;
return _relocCode(dst, baseAddress); if (le->isBound()) {
re->_targetSectionId = le->getSectionId();
re->_data = static_cast<uint64_t>(static_cast<int64_t>(le->getOffset()));
}
else {
LabelLink* link = _code->newLabelLink(le, _section->getId(), getOffset(), 0);
if (ASMJIT_UNLIKELY(!link))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
link->relocId = re->getId();
}
// Emit dummy DWORD/QWORD depending on the address size.
::memset(_bufferPtr, 0, gpSize);
_bufferPtr += gpSize;
return kErrorOk;
} }
// ============================================================================ Error Assembler::embedConstPool(const Label& label, const ConstPool& pool) {
// [asmjit::Assembler - Make] if (_lastError) return _lastError;
// ============================================================================
if (!isLabelValid(label))
return DebugUtils::errored(kErrorInvalidLabel);
void* Assembler::make() { ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
// Do nothing on error condition or if no instruction has been emitted. ASMJIT_PROPAGATE(bind(label));
if (_error != kErrorOk || getCodeSize() == 0)
return NULL; size_t size = pool.getSize();
if (getRemainingSpace() < size) {
Error err = _code->growBuffer(&_section->_buffer, size);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
}
void* p; uint8_t* p = _bufferPtr;
Error error = _runtime->add(&p, this); pool.fill(p);
if (error != kErrorOk) #if !defined(ASMJIT_DISABLE_LOGGING)
setError(error); if (_globalOptions & kOptionLoggingEnabled)
_code->_logger->logBinary(p, size);
#endif // !ASMJIT_DISABLE_LOGGING
return p; _bufferPtr += size;
return kErrorOk;
} }
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Emit (Helpers)] // [asmjit::Assembler - Emit-Helpers]
// ============================================================================ // ============================================================================
#define NA noOperand #if !defined(ASMJIT_DISABLE_LOGGING)
void Assembler::_emitLog(
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor) {
Error Assembler::emit(uint32_t code) { Logger* logger = _code->getLogger();
return _emit(code, NA, NA, NA, NA); ASMJIT_ASSERT(logger != nullptr);
} ASMJIT_ASSERT(options & CodeEmitter::kOptionLoggingEnabled);
Error Assembler::emit(uint32_t code, const Operand& o0) { StringBuilderTmp<256> sb;
return _emit(code, o0, NA, NA, NA); uint32_t logOptions = logger->getOptions();
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1) { uint8_t* beforeCursor = _bufferPtr;
return _emit(code, o0, o1, NA, NA); intptr_t emittedSize = (intptr_t)(afterCursor - beforeCursor);
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) { sb.appendString(logger->getIndentation());
return _emit(code, o0, o1, o2, NA);
}
Error Assembler::emit(uint32_t code, int o0) { Operand_ opArray[6];
return _emit(code, Imm(o0), NA, NA, NA); opArray[0].copyFrom(o0);
} opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
Error Assembler::emit(uint32_t code, const Operand& o0, int o1) { if (options & kOptionOp4Op5Used) {
return _emit(code, o0, Imm(o1), NA, NA); opArray[4].copyFrom(_op4);
} opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int o2) { Logging::formatInstruction(
return _emit(code, o0, o1, Imm(o2), NA); sb, logOptions,
} this, getArchType(),
Inst::Detail(instId, options, _extraReg), opArray, 6);
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3) { if ((logOptions & Logger::kOptionBinaryForm) != 0)
return _emit(code, o0, o1, o2, Imm(o3)); Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
} else
Logging::formatLine(sb, nullptr, Globals::kInvalidIndex, 0, 0, getInlineComment());
Error Assembler::emit(uint32_t code, int64_t o0) { logger->log(sb.getData(), sb.getLength());
return _emit(code, Imm(o0), NA, NA, NA);
} }
Error Assembler::emit(uint32_t code, const Operand& o0, int64_t o1) { Error Assembler::_emitFailed(
return _emit(code, o0, Imm(o1), NA, NA); Error err,
} uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, int64_t o2) { StringBuilderTmp<256> sb;
return _emit(code, o0, o1, Imm(o2), NA); sb.appendString(DebugUtils::errorAsString(err));
} sb.appendString(": ");
Error Assembler::emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3) { Operand_ opArray[6];
return _emit(code, o0, o1, o2, Imm(o3)); opArray[0].copyFrom(o0);
} opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
#undef NA if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction(
sb, 0,
this, getArchType(),
Inst::Detail(instId, options, _extraReg), opArray, 6);
resetOptions();
resetExtraReg();
resetInlineComment();
return setLastError(err, sb.getData());
}
#endif
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]
#include "../apiend.h" #include "../asmjit_apiend.h"
...@@ -8,536 +8,147 @@ ...@@ -8,536 +8,147 @@
#ifndef _ASMJIT_BASE_ASSEMBLER_H #ifndef _ASMJIT_BASE_ASSEMBLER_H
#define _ASMJIT_BASE_ASSEMBLER_H #define _ASMJIT_BASE_ASSEMBLER_H
// [Dependencies - AsmJit] // [Dependencies]
#include "../base/codegen.h" #include "../base/codeemitter.h"
#include "../base/containers.h" #include "../base/codeholder.h"
#include "../base/error.h"
#include "../base/logger.h"
#include "../base/operand.h" #include "../base/operand.h"
#include "../base/runtime.h" #include "../base/simdtypes.h"
#include "../base/zone.h"
// [Api-Begin] // [Api-Begin]
#include "../apibegin.h" #include "../asmjit_apibegin.h"
namespace asmjit { namespace asmjit {
//! \addtogroup asmjit_base_general //! \addtogroup asmjit_base
//! \{ //! \{
// ============================================================================
// [asmjit::InstId]
// ============================================================================
//! Instruction codes (stub).
ASMJIT_ENUM(InstId) {
//! No instruction.
kInstIdNone = 0
};
// ============================================================================
// [asmjit::InstOptions]
// ============================================================================
//! Instruction options.
ASMJIT_ENUM(InstOptions) {
//! No instruction options.
kInstOptionNone = 0x00000000,
//! 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 = 0x00000001,
//! 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 = 0x00000002,
//! Condition is likely to be taken.
kInstOptionTaken = 0x00000004,
//! Condition is unlikely to be taken.
kInstOptionNotTaken = 0x00000008
};
// ============================================================================
// [asmjit::LabelLink]
// ============================================================================
//! \internal
//!
//! Data structure used to link linked-labels.
struct LabelLink {
//! Previous link.
LabelLink* prev;
//! Offset.
intptr_t offset;
//! Inlined displacement.
intptr_t displacement;
//! RelocId if link must be absolute when relocated.
intptr_t relocId;
};
// ============================================================================
// [asmjit::LabelData]
// ============================================================================
//! \internal
//!
//! Label data.
struct LabelData {
//! Label offset.
intptr_t offset;
//! Label links chain.
LabelLink* links;
};
// ============================================================================
// [asmjit::RelocData]
// ============================================================================
//! \internal
//!
//! Code relocation data (relative vs absolute addresses).
//!
//! X86/X64:
//!
//! X86 architecture uses 32-bit absolute addressing model by memory operands,
//! but 64-bit mode uses relative addressing model (RIP + displacement). In
//! code we are always using relative addressing model for referencing labels
//! and embedded data. In 32-bit mode we must patch all references to absolute
//! address before we can call generated function.
struct RelocData {
//! Type of relocation.
uint32_t type;
//! Size of relocation (4 or 8 bytes).
uint32_t size;
//! Offset from code begin address.
Ptr from;
//! Relative displacement from code begin address (not to `offset`) or
//! absolute address.
Ptr data;
};
// ============================================================================ // ============================================================================
// [asmjit::Assembler] // [asmjit::Assembler]
// ============================================================================ // ============================================================================
//! Base assembler. //! Base assembler.
//! //!
//! This class implements the base interface to an assembler. The architecture //! This class implements a base interface that is used by architecture
//! specific API is implemented by backends. //! specific assemblers.
//! //!
//! \sa Compiler. //! \sa CodeCompiler.
struct ASMJIT_VCLASS Assembler : public CodeGen { class ASMJIT_VIRTAPI Assembler : public CodeEmitter {
ASMJIT_NO_COPY(Assembler) public:
ASMJIT_NONCOPYABLE(Assembler)
typedef CodeEmitter Base;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Construction / Destruction] // [Construction / Destruction]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Create a new `Assembler` instance. //! Create a new `Assembler` instance.
ASMJIT_API Assembler(Runtime* runtime); ASMJIT_API Assembler() noexcept;
//! Destroy the `Assembler` instance. //! Destroy the `Assembler` instance.
ASMJIT_API virtual ~Assembler(); ASMJIT_API virtual ~Assembler() noexcept;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reset] // [Events]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Reset the assembler. ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
//! ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
//! If `releaseMemory` is true all buffers will be released to the system.
ASMJIT_API void reset(bool releaseMemory = false);
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Buffer] // [Code-Generation]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get capacity of the code buffer. using CodeEmitter::_emit;
ASMJIT_INLINE size_t getCapacity() const {
return (size_t)(_end - _buffer);
}
//! Get the number of remaining bytes (space between cursor and the end of
//! the buffer).
ASMJIT_INLINE size_t getRemainingSpace() const {
return (size_t)(_end - _cursor);
}
//! Get buffer.
ASMJIT_INLINE uint8_t* getBuffer() const {
return _buffer;
}
//! Get the end of the buffer (points to the first byte that is outside).
ASMJIT_INLINE uint8_t* getEnd() const {
return _end;
}
//! Get the current position in the buffer.
ASMJIT_INLINE uint8_t* getCursor() const {
return _cursor;
}
//! Set the current position in the buffer.
ASMJIT_INLINE void setCursor(uint8_t* cursor) {
ASMJIT_ASSERT(cursor >= _buffer && cursor <= _end);
_cursor = cursor;
}
//! Get the current offset in the buffer. ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override;
ASMJIT_INLINE size_t getOffset() const { ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override;
return (size_t)(_cursor - _buffer);
}
//! Set the current offset in the buffer to `offset` and get the previous
//! offset value.
ASMJIT_INLINE size_t setOffset(size_t offset) {
ASMJIT_ASSERT(offset < getCapacity());
size_t oldOffset = (size_t)(_cursor - _buffer);
_cursor = _buffer + offset;
return oldOffset;
}
//! Grow the internal buffer.
//!
//! The internal buffer will grow at least by `n` bytes so `n` bytes can be
//! added to it. If `n` is zero or `getOffset() + n` is not greater than the
//! current capacity of the buffer this function does nothing.
ASMJIT_API Error _grow(size_t n);
//! Reserve the internal buffer to at least `n` bytes.
ASMJIT_API Error _reserve(size_t n);
//! Get BYTE at position `pos`.
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);
}
//! 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);
}
//! 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);
}
//! 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);
}
//! 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);
}
//! 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`.
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`.
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`.
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`.
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;
}
//! Set int32_t at position `pos`.
ASMJIT_INLINE void setInt32At(size_t pos, int32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<int32_t*>(_buffer + pos) = x;
}
//! Set uint32_t at position `pos`.
ASMJIT_INLINE void setUInt32At(size_t pos, uint32_t x) {
ASMJIT_ASSERT(pos + 4 <= (size_t)(_end - _buffer));
*reinterpret_cast<uint32_t*>(_buffer + pos) = x;
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [GetCodeSize] // [Code-Buffer]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Get current offset in buffer, same as `getOffset() + getTramplineSize()`. //! Called by \ref CodeHolder::sync().
ASMJIT_INLINE size_t getCodeSize() const { ASMJIT_API virtual void sync() noexcept;
return getOffset() + getTrampolineSize();
}
// -------------------------------------------------------------------------- //! Get the capacity of the current CodeBuffer.
// [GetTrampolineSize] ASMJIT_INLINE size_t getBufferCapacity() const noexcept { return (size_t)(_bufferEnd - _bufferData); }
// -------------------------------------------------------------------------- //! Get the number of remaining bytes in the current CodeBuffer.
ASMJIT_INLINE size_t getRemainingSpace() const noexcept { return (size_t)(_bufferEnd - _bufferPtr); }
//! Get size of all possible trampolines. //! Get the current position in the CodeBuffer.
ASMJIT_INLINE size_t getOffset() const noexcept { return (size_t)(_bufferPtr - _bufferData); }
//! Set the current position in the CodeBuffer to `offset`.
//! //!
//! Trampolines are needed to successfuly generate relative jumps to absolute //! NOTE: The `offset` cannot be outside of the buffer length (even if it's
//! addresses. This value is only non-zero if jmp of call instructions were //! within buffer's capacity).
//! used with immediate operand (this means jumping or calling an absolute ASMJIT_API Error setOffset(size_t offset);
//! address directly).
ASMJIT_INLINE size_t getTrampolineSize() const {
return _trampolineSize;
}
// -------------------------------------------------------------------------- //! Get start of the CodeBuffer of the current section.
// [Label] ASMJIT_INLINE uint8_t* getBufferData() const noexcept { return _bufferData; }
// -------------------------------------------------------------------------- //! Get end (first invalid byte) of the current section.
ASMJIT_INLINE uint8_t* getBufferEnd() const noexcept { return _bufferEnd; }
//! Get number of labels created. //! Get pointer in the CodeBuffer of the current section.
ASMJIT_INLINE size_t getLabelsCount() const { ASMJIT_INLINE uint8_t* getBufferPtr() const noexcept { return _bufferPtr; }
return _labelList.getLength();
}
//! Get whether the `label` is valid (created by the assembler).
ASMJIT_INLINE bool isLabelValid(const Label& label) const {
return isLabelValid(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelValid(uint32_t id) const {
return static_cast<size_t>(id) < _labelList.getLength();
}
//! Get whether the `label` is bound.
//!
//! \note It's an error to pass label that is not valid. Check the validity
//! of the label by using `isLabelValid()` method before the bound check if
//! you are not sure about its validity, otherwise you may hit an assertion
//! failure in debug mode, and undefined behavior in release mode.
ASMJIT_INLINE bool isLabelBound(const Label& label) const {
return isLabelBound(label.getId());
}
//! \overload
ASMJIT_INLINE bool isLabelBound(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset != -1;
}
//! Get `label` offset or -1 if the label is not yet bound.
ASMJIT_INLINE intptr_t getLabelOffset(const Label& label) const {
return getLabelOffset(label.getId());
}
//! \overload
ASMJIT_INLINE intptr_t getLabelOffset(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return _labelList[id].offset;
}
//! Get `LabelData` by `label`.
ASMJIT_INLINE LabelData* getLabelData(const Label& label) const {
return getLabelData(label.getId());
}
//! \overload
ASMJIT_INLINE LabelData* getLabelData(uint32_t id) const {
ASMJIT_ASSERT(isLabelValid(id));
return const_cast<LabelData*>(&_labelList[id]);
}
//! \internal
//!
//! Register labels for other code generator, i.e. `Compiler`.
ASMJIT_API Error _registerIndexedLabels(size_t index);
//! \internal
//!
//! Create and initialize a new `Label`.
ASMJIT_API Error _newLabel(Label* dst);
//! \internal
//!
//! New LabelLink instance.
ASMJIT_API LabelLink* _newLabelLink();
//! Create and return a new `Label`.
ASMJIT_INLINE Label newLabel() {
Label result(NoInit);
_newLabel(&result);
return result;
}
//! Bind label to the current offset.
//!
//! \note Label can be bound only once!
ASMJIT_API virtual Error bind(const Label& label);
// --------------------------------------------------------------------------
// [Embed]
// --------------------------------------------------------------------------
//! Embed data into the code buffer.
ASMJIT_API virtual Error embed(const void* data, uint32_t size);
// --------------------------------------------------------------------------
// [Align]
// --------------------------------------------------------------------------
//! Align target buffer to `m` bytes.
//!
//! Typical usage of this is to align labels at start of the inner loops.
//!
//! Inserts `nop()` instructions or CPU optimized NOPs.
virtual Error align(uint32_t mode, uint32_t offset) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Reloc] // [Code-Generation]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Relocate the code to `baseAddress` and copy to `dst`. ASMJIT_API Label newLabel() override;
//! ASMJIT_API Label newNamedLabel(
//! \param dst Contains the location where the relocated code should be const char* name,
//! copied. The pointer can be address returned by virtual memory allocator size_t nameLength = Globals::kInvalidIndex,
//! or any other address that has sufficient space. uint32_t type = Label::kTypeGlobal,
//! uint32_t parentId = 0) override;
//! \param base Base address used for relocation. The `JitRuntime` always ASMJIT_API Error bind(const Label& label) override;
//! sets the `base` address to be the same as `dst`, but other runtimes, for ASMJIT_API Error embed(const void* data, uint32_t size) override;
//! example `StaticRuntime`, do not have to follow this rule. ASMJIT_API Error embedLabel(const Label& label) override;
//! ASMJIT_API Error embedConstPool(const Label& label, const ConstPool& pool) override;
//! \retval The number bytes actually used. If the code generator reserved ASMJIT_API Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
//! space for possible trampolines, but didn't use it, the number of bytes
//! used can actually be less than the expected worst case. Virtual memory
//! allocator can shrink the memory allocated first time.
//!
//! A given buffer will be overwritten, to get the number of bytes required,
//! use `getCodeSize()`.
ASMJIT_API size_t relocCode(void* dst, Ptr baseAddress = kNoBaseAddress) const;
//! \internal
//!
//! Reloc code.
virtual size_t _relocCode(void* dst, Ptr baseAddress) const = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Make] // [Emit-Helpers]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API virtual void* make(); protected:
#if !defined(ASMJIT_DISABLE_LOGGING)
void _emitLog(
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3,
uint32_t relSize, uint32_t imLen, uint8_t* afterCursor);
// -------------------------------------------------------------------------- Error _emitFailed(
// [Emit] Error err,
// -------------------------------------------------------------------------- uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
#else
ASMJIT_INLINE Error _emitFailed(
uint32_t err,
uint32_t instId, uint32_t options, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
//! Emit an instruction. resetOptions();
ASMJIT_API Error emit(uint32_t code); resetInlineComment();
//! \overload return setLastError(err);
ASMJIT_API Error emit(uint32_t code, const Operand& o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2);
//! \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);
} }
#endif
//! Emit an instruction with integer immediate operand.
ASMJIT_API Error emit(uint32_t code, int o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int o3);
//! \overload
ASMJIT_API Error emit(uint32_t code, int64_t o0);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, int64_t o1);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, int64_t o2);
//! \overload
ASMJIT_API Error emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, int64_t o3);
//! Emit an instruction (virtual).
virtual Error _emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2, const Operand& o3) = 0;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Buffer where the code is emitted (either live or temporary). public:
//! SectionEntry* _section; //!< Current section where the assembling happens.
//! This is actually the base pointer of the buffer, to get the current uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section.
//! position (cursor) look at the `_cursor` member. uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section.
uint8_t* _buffer; uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section.
//! The end of the buffer (points to the first invalid byte).
//! Operand_ _op4; //!< 5th operand data, used only temporarily.
//! The end of the buffer is calculated as <code>_buffer + size</code>. Operand_ _op5; //!< 6th operand data, used only temporarily.
uint8_t* _end;
//! The current position in code `_buffer`.
uint8_t* _cursor;
//! Size of possible trampolines.
uint32_t _trampolineSize;
//! Inline comment that will be logged by the next instruction and set to NULL.
const char* _comment;
//! Unused `LabelLink` structures pool.
LabelLink* _unusedLinks;
//! LabelData list.
PodVector<LabelData> _labelList;
//! RelocData list.
PodVector<RelocData> _relocList;
}; };
//! \} //! \}
// ============================================================================
// [Defined-Later]
// ============================================================================
ASMJIT_INLINE Label::Label(Assembler& a) : Operand(NoInit) {
a._newLabel(this);
}
} // asmjit namespace } // asmjit namespace
// [Api-End] // [Api-End]
#include "../apiend.h" #include "../asmjit_apiend.h"
// [Guard] // [Guard]
#endif // _ASMJIT_BASE_ASSEMBLER_H #endif // _ASMJIT_BASE_ASSEMBLER_H
// [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 "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_BUILDER)
// [Dependencies]
#include "../base/codebuilder.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeBuilder - Construction / Destruction]
// ============================================================================
CodeBuilder::CodeBuilder() noexcept
: CodeEmitter(kTypeBuilder),
_cbBaseZone(32768 - Zone::kZoneOverhead),
_cbDataZone(16384 - Zone::kZoneOverhead),
_cbPassZone(32768 - Zone::kZoneOverhead),
_cbHeap(&_cbBaseZone),
_cbPasses(),
_cbLabels(),
_firstNode(nullptr),
_lastNode(nullptr),
_cursor(nullptr),
_position(0),
_nodeFlags(0) {}
CodeBuilder::~CodeBuilder() noexcept {}
// ============================================================================
// [asmjit::CodeBuilder - Events]
// ============================================================================
Error CodeBuilder::onAttach(CodeHolder* code) noexcept {
return Base::onAttach(code);
}
Error CodeBuilder::onDetach(CodeHolder* code) noexcept {
_cbPasses.reset();
_cbLabels.reset();
_cbHeap.reset(&_cbBaseZone);
_cbBaseZone.reset(false);
_cbDataZone.reset(false);
_cbPassZone.reset(false);
_position = 0;
_nodeFlags = 0;
_firstNode = nullptr;
_lastNode = nullptr;
_cursor = nullptr;
return Base::onDetach(code);
}
// ============================================================================
// [asmjit::CodeBuilder - Node-Factory]
// ============================================================================
Error CodeBuilder::getCBLabel(CBLabel** pOut, uint32_t id) noexcept {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
size_t index = Operand::unpackId(id);
if (ASMJIT_UNLIKELY(index >= _code->getLabelsCount()))
return DebugUtils::errored(kErrorInvalidLabel);
if (index >= _cbLabels.getLength())
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
CBLabel* node = _cbLabels[index];
if (!node) {
node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node))
return DebugUtils::errored(kErrorNoHeapMemory);
_cbLabels[index] = node;
}
*pOut = node;
return kErrorOk;
}
Error CodeBuilder::registerLabelNode(CBLabel* node) noexcept {
if (_lastError) return _lastError;
ASMJIT_ASSERT(_code != nullptr);
// Don't call setLastError() from here, we are noexcept and we are called
// by `newLabelNode()` and `newFuncNode()`, which are noexcept as well.
uint32_t id;
ASMJIT_PROPAGATE(_code->newLabelId(id));
size_t index = Operand::unpackId(id);
// We just added one label so it must be true.
ASMJIT_ASSERT(_cbLabels.getLength() < index + 1);
ASMJIT_PROPAGATE(_cbLabels.resize(&_cbHeap, index + 1));
_cbLabels[index] = node;
node->_id = id;
return kErrorOk;
}
CBLabel* CodeBuilder::newLabelNode() noexcept {
CBLabel* node = newNodeT<CBLabel>();
if (!node || registerLabelNode(node) != kErrorOk)
return nullptr;
return node;
}
CBAlign* CodeBuilder::newAlignNode(uint32_t mode, uint32_t alignment) noexcept {
return newNodeT<CBAlign>(mode, alignment);
}
CBData* CodeBuilder::newDataNode(const void* data, uint32_t size) noexcept {
if (size > CBData::kInlineBufferSize) {
void* cloned = _cbDataZone.alloc(size);
if (!cloned) return nullptr;
if (data) ::memcpy(cloned, data, size);
data = cloned;
}
return newNodeT<CBData>(const_cast<void*>(data), size);
}
CBConstPool* CodeBuilder::newConstPool() noexcept {
CBConstPool* node = newNodeT<CBConstPool>();
if (!node || registerLabelNode(node) != kErrorOk)
return nullptr;
return node;
}
CBComment* CodeBuilder::newCommentNode(const char* s, size_t len) noexcept {
if (s) {
if (len == Globals::kInvalidIndex) len = ::strlen(s);
if (len > 0) {
s = static_cast<char*>(_cbDataZone.dup(s, len, true));
if (!s) return nullptr;
}
}
return newNodeT<CBComment>(s);
}
// ============================================================================
// [asmjit::CodeBuilder - Code-Emitter]
// ============================================================================
Label CodeBuilder::newLabel() {
uint32_t id = kInvalidValue;
if (!_lastError) {
CBLabel* node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node)) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
else {
Error err = registerLabelNode(node);
if (ASMJIT_UNLIKELY(err))
setLastError(err);
else
id = node->getId();
}
}
return Label(id);
}
Label CodeBuilder::newNamedLabel(const char* name, size_t nameLength, uint32_t type, uint32_t parentId) {
uint32_t id = kInvalidValue;
if (!_lastError) {
CBLabel* node = newNodeT<CBLabel>(id);
if (ASMJIT_UNLIKELY(!node)) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
else {
Error err = _code->newNamedLabelId(id, name, nameLength, type, parentId);
if (ASMJIT_UNLIKELY(err))
setLastError(err);
else
id = node->getId();
}
}
return Label(id);
}
Error CodeBuilder::bind(const Label& label) {
if (_lastError) return _lastError;
CBLabel* node;
Error err = getCBLabel(&node, label);
if (ASMJIT_UNLIKELY(err))
return setLastError(err);
addNode(node);
return kErrorOk;
}
Error CodeBuilder::align(uint32_t mode, uint32_t alignment) {
if (_lastError) return _lastError;
CBAlign* node = newAlignNode(mode, alignment);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embed(const void* data, uint32_t size) {
if (_lastError) return _lastError;
CBData* node = newDataNode(data, size);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embedLabel(const Label& label) {
if (_lastError) return _lastError;
CBLabelData* node = newNodeT<CBLabelData>(label.getId());
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
Error CodeBuilder::embedConstPool(const Label& label, const ConstPool& pool) {
if (_lastError) return _lastError;
if (!isLabelValid(label))
return setLastError(DebugUtils::errored(kErrorInvalidLabel));
ASMJIT_PROPAGATE(align(kAlignData, static_cast<uint32_t>(pool.getAlignment())));
ASMJIT_PROPAGATE(bind(label));
CBData* node = newDataNode(nullptr, static_cast<uint32_t>(pool.getSize()));
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
pool.fill(node->getData());
addNode(node);
return kErrorOk;
}
Error CodeBuilder::comment(const char* s, size_t len) {
if (_lastError) return _lastError;
CBComment* node = newCommentNode(s, len);
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeBuilder - Node-Management]
// ============================================================================
CBNode* CodeBuilder::addNode(CBNode* node) noexcept {
ASMJIT_ASSERT(node);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
if (!_cursor) {
if (!_firstNode) {
_firstNode = node;
_lastNode = node;
}
else {
node->_next = _firstNode;
_firstNode->_prev = node;
_firstNode = node;
}
}
else {
CBNode* prev = _cursor;
CBNode* next = _cursor->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
}
_cursor = node;
return node;
}
CBNode* CodeBuilder::addAfter(CBNode* node, CBNode* ref) noexcept {
ASMJIT_ASSERT(node);
ASMJIT_ASSERT(ref);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
CBNode* prev = ref;
CBNode* next = ref->_next;
node->_prev = prev;
node->_next = next;
prev->_next = node;
if (next)
next->_prev = node;
else
_lastNode = node;
return node;
}
CBNode* CodeBuilder::addBefore(CBNode* node, CBNode* ref) noexcept {
ASMJIT_ASSERT(node != nullptr);
ASMJIT_ASSERT(node->_prev == nullptr);
ASMJIT_ASSERT(node->_next == nullptr);
ASMJIT_ASSERT(ref != nullptr);
CBNode* prev = ref->_prev;
CBNode* next = ref;
node->_prev = prev;
node->_next = next;
next->_prev = node;
if (prev)
prev->_next = node;
else
_firstNode = node;
return node;
}
static ASMJIT_INLINE void CodeBuilder_nodeRemoved(CodeBuilder* self, CBNode* node_) noexcept {
if (node_->isJmpOrJcc()) {
CBJump* node = static_cast<CBJump*>(node_);
CBLabel* label = node->getTarget();
if (label) {
// Disconnect.
CBJump** pPrev = &label->_from;
for (;;) {
ASMJIT_ASSERT(*pPrev != nullptr);
CBJump* current = *pPrev;
if (!current) break;
if (current == node) {
*pPrev = node->_jumpNext;
break;
}
pPrev = &current->_jumpNext;
}
label->subNumRefs();
}
}
}
CBNode* CodeBuilder::removeNode(CBNode* node) noexcept {
CBNode* prev = node->_prev;
CBNode* next = node->_next;
if (_firstNode == node)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == node)
_lastNode = prev;
else
next->_prev = prev;
node->_prev = nullptr;
node->_next = nullptr;
if (_cursor == node)
_cursor = prev;
CodeBuilder_nodeRemoved(this, node);
return node;
}
void CodeBuilder::removeNodes(CBNode* first, CBNode* last) noexcept {
if (first == last) {
removeNode(first);
return;
}
CBNode* prev = first->_prev;
CBNode* next = last->_next;
if (_firstNode == first)
_firstNode = next;
else
prev->_next = next;
if (_lastNode == last)
_lastNode = prev;
else
next->_prev = prev;
CBNode* node = first;
for (;;) {
CBNode* next = node->getNext();
ASMJIT_ASSERT(next != nullptr);
node->_prev = nullptr;
node->_next = nullptr;
if (_cursor == node)
_cursor = prev;
CodeBuilder_nodeRemoved(this, node);
if (node == last)
break;
node = next;
}
}
CBNode* CodeBuilder::setCursor(CBNode* node) noexcept {
CBNode* old = _cursor;
_cursor = node;
return old;
}
// ============================================================================
// [asmjit::CodeBuilder - Passes]
// ============================================================================
ASMJIT_FAVOR_SIZE CBPass* CodeBuilder::getPassByName(const char* name) const noexcept {
for (size_t i = 0, len = _cbPasses.getLength(); i < len; i++) {
CBPass* pass = _cbPasses[i];
if (::strcmp(pass->getName(), name) == 0)
return pass;
}
return nullptr;
}
ASMJIT_FAVOR_SIZE Error CodeBuilder::addPass(CBPass* pass) noexcept {
if (ASMJIT_UNLIKELY(pass == nullptr)) {
// Since this is directly called by `addPassT()` we treat `null` argument
// as out-of-memory condition. Otherwise it would be API misuse.
return DebugUtils::errored(kErrorNoHeapMemory);
}
else if (ASMJIT_UNLIKELY(pass->_cb)) {
// Kind of weird, but okay...
if (pass->_cb == this)
return kErrorOk;
return DebugUtils::errored(kErrorInvalidState);
}
ASMJIT_PROPAGATE(_cbPasses.append(&_cbHeap, pass));
pass->_cb = this;
return kErrorOk;
}
ASMJIT_FAVOR_SIZE Error CodeBuilder::deletePass(CBPass* pass) noexcept {
if (ASMJIT_UNLIKELY(pass == nullptr))
return DebugUtils::errored(kErrorInvalidArgument);
if (pass->_cb != nullptr) {
if (pass->_cb != this)
return DebugUtils::errored(kErrorInvalidState);
size_t index = _cbPasses.indexOf(pass);
ASMJIT_ASSERT(index != Globals::kInvalidIndex);
pass->_cb = nullptr;
_cbPasses.removeAt(index);
}
pass->~CBPass();
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeBuilder - Serialization]
// ============================================================================
Error CodeBuilder::serialize(CodeEmitter* dst) {
Error err = kErrorOk;
CBNode* node_ = getFirstNode();
do {
dst->setInlineComment(node_->getInlineComment());
switch (node_->getType()) {
case CBNode::kNodeAlign: {
CBAlign* node = static_cast<CBAlign*>(node_);
err = dst->align(node->getMode(), node->getAlignment());
break;
}
case CBNode::kNodeData: {
CBData* node = static_cast<CBData*>(node_);
err = dst->embed(node->getData(), node->getSize());
break;
}
case CBNode::kNodeFunc:
case CBNode::kNodeLabel: {
CBLabel* node = static_cast<CBLabel*>(node_);
err = dst->bind(node->getLabel());
break;
}
case CBNode::kNodeLabelData: {
CBLabelData* node = static_cast<CBLabelData*>(node_);
err = dst->embedLabel(node->getLabel());
break;
}
case CBNode::kNodeConstPool: {
CBConstPool* node = static_cast<CBConstPool*>(node_);
err = dst->embedConstPool(node->getLabel(), node->getConstPool());
break;
}
case CBNode::kNodeInst:
case CBNode::kNodeFuncCall: {
CBInst* node = node_->as<CBInst>();
dst->setOptions(node->getOptions());
dst->setExtraReg(node->getExtraReg());
err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
break;
}
case CBNode::kNodeComment: {
CBComment* node = static_cast<CBComment*>(node_);
err = dst->comment(node->getInlineComment());
break;
}
default:
break;
}
if (err) break;
node_ = node_->getNext();
} while (node_);
return err;
}
// ============================================================================
// [asmjit::CBPass]
// ============================================================================
CBPass::CBPass(const char* name) noexcept
: _cb(nullptr),
_name(name) {}
CBPass::~CBPass() noexcept {}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_BUILDER
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEBUILDER_H
#define _ASMJIT_BASE_CODEBUILDER_H
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_BUILDER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codeholder.h"
#include "../base/constpool.h"
#include "../base/inst.h"
#include "../base/operand.h"
#include "../base/utils.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
class CBNode;
class CBPass;
class CBAlign;
class CBComment;
class CBConstPool;
class CBData;
class CBInst;
class CBJump;
class CBLabel;
class CBLabelData;
class CBSentinel;
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::CodeBuilder]
// ============================================================================
class ASMJIT_VIRTAPI CodeBuilder : public CodeEmitter {
public:
ASMJIT_NONCOPYABLE(CodeBuilder)
typedef CodeEmitter Base;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeBuilder` instance.
ASMJIT_API CodeBuilder() noexcept;
//! Destroy the `CodeBuilder` instance.
ASMJIT_API virtual ~CodeBuilder() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get a vector of CBPass objects that will be executed by `process()`.
ASMJIT_INLINE const ZoneVector<CBPass*>& getPasses() const noexcept { return _cbPasses; }
//! Get a vector of CBLabel nodes.
//!
//! NOTE: If a label of some index is not associated with `CodeBuilder` it
//! would be null, so always check for nulls if you iterate over the vector.
ASMJIT_INLINE const ZoneVector<CBLabel*>& getLabels() const noexcept { return _cbLabels; }
//! Get the first node.
ASMJIT_INLINE CBNode* getFirstNode() const noexcept { return _firstNode; }
//! Get the last node.
ASMJIT_INLINE CBNode* getLastNode() const noexcept { return _lastNode; }
// --------------------------------------------------------------------------
// [Node-Management]
// --------------------------------------------------------------------------
//! \internal
template<typename T>
ASMJIT_INLINE T* newNodeT() noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this); }
//! \internal
template<typename T, typename P0>
ASMJIT_INLINE T* newNodeT(P0 p0) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0); }
//! \internal
template<typename T, typename P0, typename P1>
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1); }
//! \internal
template<typename T, typename P0, typename P1, typename P2>
ASMJIT_INLINE T* newNodeT(P0 p0, P1 p1, P2 p2) noexcept { return new(_cbHeap.alloc(sizeof(T))) T(this, p0, p1, p2); }
ASMJIT_API Error registerLabelNode(CBLabel* node) noexcept;
//! Get `CBLabel` by `id`.
ASMJIT_API Error getCBLabel(CBLabel** pOut, uint32_t id) noexcept;
//! Get `CBLabel` by `label`.
ASMJIT_INLINE Error getCBLabel(CBLabel** pOut, const Label& label) noexcept { return getCBLabel(pOut, label.getId()); }
//! Create a new \ref CBLabel node.
ASMJIT_API CBLabel* newLabelNode() noexcept;
//! Create a new \ref CBAlign node.
ASMJIT_API CBAlign* newAlignNode(uint32_t mode, uint32_t alignment) noexcept;
//! Create a new \ref CBData node.
ASMJIT_API CBData* newDataNode(const void* data, uint32_t size) noexcept;
//! Create a new \ref CBConstPool node.
ASMJIT_API CBConstPool* newConstPool() noexcept;
//! Create a new \ref CBComment node.
ASMJIT_API CBComment* newCommentNode(const char* s, size_t len) noexcept;
// --------------------------------------------------------------------------
// [Code-Emitter]
// --------------------------------------------------------------------------
ASMJIT_API virtual Label newLabel() override;
ASMJIT_API virtual Label newNamedLabel(const char* name, size_t nameLength = Globals::kInvalidIndex, uint32_t type = Label::kTypeGlobal, uint32_t parentId = kInvalidValue) override;
ASMJIT_API virtual Error bind(const Label& label) override;
ASMJIT_API virtual Error align(uint32_t mode, uint32_t alignment) override;
ASMJIT_API virtual Error embed(const void* data, uint32_t size) override;
ASMJIT_API virtual Error embedLabel(const Label& label) override;
ASMJIT_API virtual Error embedConstPool(const Label& label, const ConstPool& pool) override;
ASMJIT_API virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) override;
// --------------------------------------------------------------------------
// [Node-Management]
// --------------------------------------------------------------------------
//! Add `node` after the current and set current to `node`.
ASMJIT_API CBNode* addNode(CBNode* node) noexcept;
//! Insert `node` after `ref`.
ASMJIT_API CBNode* addAfter(CBNode* node, CBNode* ref) noexcept;
//! Insert `node` before `ref`.
ASMJIT_API CBNode* addBefore(CBNode* node, CBNode* ref) noexcept;
//! Remove `node`.
ASMJIT_API CBNode* removeNode(CBNode* node) noexcept;
//! Remove multiple nodes.
ASMJIT_API void removeNodes(CBNode* first, CBNode* last) noexcept;
//! Get current node.
//!
//! \note If this method returns null it means that nothing has been
//! emitted yet.
ASMJIT_INLINE CBNode* getCursor() const noexcept { return _cursor; }
//! Set the current node without returning the previous node.
ASMJIT_INLINE void _setCursor(CBNode* node) noexcept { _cursor = node; }
//! Set the current node to `node` and return the previous one.
ASMJIT_API CBNode* setCursor(CBNode* node) noexcept;
// --------------------------------------------------------------------------
// [Passes]
// --------------------------------------------------------------------------
template<typename T>
ASMJIT_INLINE T* newPassT() noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(); }
template<typename T, typename P0>
ASMJIT_INLINE T* newPassT(P0 p0) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0); }
template<typename T, typename P0, typename P1>
ASMJIT_INLINE T* newPassT(P0 p0, P1 p1) noexcept { return new(_cbBaseZone.alloc(sizeof(T))) T(p0, p1); }
template<typename T>
ASMJIT_INLINE Error addPassT() noexcept { return addPass(newPassT<T>()); }
template<typename T, typename P0>
ASMJIT_INLINE Error addPassT(P0 p0) noexcept { return addPass(newPassT<P0>(p0)); }
template<typename T, typename P0, typename P1>
ASMJIT_INLINE Error addPassT(P0 p0, P1 p1) noexcept { return addPass(newPassT<P0, P1>(p0, p1)); }
//! Get a `CBPass` by name.
ASMJIT_API CBPass* getPassByName(const char* name) const noexcept;
//! Add `pass` to the list of passes.
ASMJIT_API Error addPass(CBPass* pass) noexcept;
//! Remove `pass` from the list of passes and delete it.
ASMJIT_API Error deletePass(CBPass* pass) noexcept;
// --------------------------------------------------------------------------
// [Serialization]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error serialize(CodeEmitter* dst);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Zone _cbBaseZone; //!< Base zone used to allocate nodes and `CBPass`.
Zone _cbDataZone; //!< Data zone used to allocate data and names.
Zone _cbPassZone; //!< Zone passed to `CBPass::process()`.
ZoneHeap _cbHeap; //!< ZoneHeap that uses `_cbBaseZone`.
ZoneVector<CBPass*> _cbPasses; //!< Array of `CBPass` objects.
ZoneVector<CBLabel*> _cbLabels; //!< Maps label indexes to `CBLabel` nodes.
CBNode* _firstNode; //!< First node of the current section.
CBNode* _lastNode; //!< Last node of the current section.
CBNode* _cursor; //!< Current node (cursor).
uint32_t _position; //!< Flow-id assigned to each new node.
uint32_t _nodeFlags; //!< Flags assigned to each new node.
};
// ============================================================================
// [asmjit::CBPass]
// ============================================================================
//! `CodeBuilder` pass used to code transformations, analysis, and lowering.
class ASMJIT_VIRTAPI CBPass {
public:
ASMJIT_NONCOPYABLE(CBPass);
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API CBPass(const char* name) noexcept;
ASMJIT_API virtual ~CBPass() noexcept;
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Process the code stored in CodeBuffer `cb`.
//!
//! This is the only function that is called by the `CodeBuilder` to process
//! the code. It passes the CodeBuilder itself (`cb`) and also a zone memory
//! allocator `zone`, which will be reset after the `process()` returns. The
//! allocator should be used for all allocations as it's fast and everything
//! it allocates will be released at once when `process()` returns.
virtual Error process(Zone* zone) noexcept = 0;
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE const CodeBuilder* cb() const noexcept { return _cb; }
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CodeBuilder* _cb; //!< CodeBuilder this pass is assigned to.
const char* _name; //!< Name of the pass.
};
// ============================================================================
// [asmjit::CBNode]
// ============================================================================
//! Node (CodeBuilder).
//!
//! Every node represents a building-block used by \ref CodeBuilder. It can be
//! instruction, data, label, comment, directive, or any other high-level
//! representation that can be transformed to the building blocks mentioned.
//! Every class that inherits \ref CodeBuilder can define its own nodes that it
//! can lower to basic nodes.
class CBNode {
public:
ASMJIT_NONCOPYABLE(CBNode)
// --------------------------------------------------------------------------
// [Type]
// --------------------------------------------------------------------------
//! Type of \ref CBNode.
ASMJIT_ENUM(NodeType) {
kNodeNone = 0, //!< Invalid node (internal, don't use).
// [CodeBuilder]
kNodeInst = 1, //!< Node is \ref CBInst or \ref CBJump.
kNodeData = 2, //!< Node is \ref CBData.
kNodeAlign = 3, //!< Node is \ref CBAlign.
kNodeLabel = 4, //!< Node is \ref CBLabel.
kNodeLabelData = 5, //!< Node is \ref CBLabelData.
kNodeConstPool = 6, //!< Node is \ref CBConstPool.
kNodeComment = 7, //!< Node is \ref CBComment.
kNodeSentinel = 8, //!< Node is \ref CBSentinel.
// [CodeCompiler]
kNodeFunc = 16, //!< Node is \ref CCFunc (considered as \ref CBLabel by \ref CodeBuilder).
kNodeFuncExit = 17, //!< Node is \ref CCFuncRet.
kNodeFuncCall = 18, //!< Node is \ref CCFuncCall.
kNodePushArg = 19, //!< Node is \ref CCPushArg.
kNodeHint = 20, //!< Node is \ref CCHint.
// [UserDefined]
kNodeUser = 32 //!< First id of a user-defined node.
};
// --------------------------------------------------------------------------
// [Flags]
// --------------------------------------------------------------------------
ASMJIT_ENUM(Flags) {
//! The node has been translated by the CodeCompiler.
kFlagIsTranslated = 0x0001,
//! If the node can be safely removed (has no effect).
kFlagIsRemovable = 0x0004,
//! If the node is informative only and can be safely removed.
kFlagIsInformative = 0x0008,
//! If the `CBInst` is a jump.
kFlagIsJmp = 0x0010,
//! If the `CBInst` is a conditional jump.
kFlagIsJcc = 0x0020,
//! If the `CBInst` is an unconditional jump or conditional jump that is
//! likely to be taken.
kFlagIsTaken = 0x0040,
//! If the `CBNode` will return from a function.
//!
//! This flag is used by both `CBSentinel` and `CCFuncRet`.
kFlagIsRet = 0x0080,
//! Whether the instruction is special.
kFlagIsSpecial = 0x0100,
//! Whether the instruction is an FPU instruction.
kFlagIsFp = 0x0200
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new \ref CBNode - always use \ref CodeBuilder to allocate nodes.
ASMJIT_INLINE CBNode(CodeBuilder* cb, uint32_t type) noexcept {
_prev = nullptr;
_next = nullptr;
_type = static_cast<uint8_t>(type);
_opCount = 0;
_flags = static_cast<uint16_t>(cb->_nodeFlags);
_position = cb->_position;
_inlineComment = nullptr;
_passData = nullptr;
}
//! Destroy the `CBNode` instance (NEVER CALLED).
ASMJIT_INLINE ~CBNode() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
template<typename T>
ASMJIT_INLINE T* as() noexcept { return static_cast<T*>(this); }
template<typename T>
ASMJIT_INLINE const T* as() const noexcept { return static_cast<const T*>(this); }
//! Get previous node in the compiler stream.
ASMJIT_INLINE CBNode* getPrev() const noexcept { return _prev; }
//! Get next node in the compiler stream.
ASMJIT_INLINE CBNode* getNext() const noexcept { return _next; }
//! Get the node type, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get the node flags.
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
//! Get whether the instruction has flag `flag`.
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast<uint32_t>(_flags) & flag) != 0; }
//! Set node flags to `flags`.
ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast<uint16_t>(flags); }
//! Add instruction `flags`.
ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast<uint16_t>(flags); }
//! And instruction `flags`.
ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast<uint16_t>(flags); }
//! Clear instruction `flags`.
ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast<uint16_t>(flags); }
//! Get whether the node has been translated.
ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); }
//! Get whether the node is removable if it's in unreachable code block.
ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); }
//! Get whether the node is informative only (comment, hint).
ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); }
//! Whether the node is `CBLabel`.
ASMJIT_INLINE bool isLabel() const noexcept { return _type == kNodeLabel; }
//! Whether the `CBInst` node is an unconditional jump.
ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); }
//! Whether the `CBInst` node is a conditional jump.
ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); }
//! Whether the `CBInst` node is a conditional/unconditional jump.
ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); }
//! Whether the `CBInst` node is a return.
ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); }
//! Get whether the node is `CBInst` and the instruction is special.
ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); }
//! Get whether the node is `CBInst` and the instruction uses x87-FPU.
ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); }
ASMJIT_INLINE bool hasPosition() const noexcept { return _position != 0; }
//! Get flow index.
ASMJIT_INLINE uint32_t getPosition() const noexcept { return _position; }
//! Set flow index.
ASMJIT_INLINE void setPosition(uint32_t position) noexcept { _position = position; }
//! Get if the node has an inline comment.
ASMJIT_INLINE bool hasInlineComment() const noexcept { return _inlineComment != nullptr; }
//! Get an inline comment string.
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
//! Set an inline comment string to `s`.
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
//! Set an inline comment string to null.
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
//! Get if the node has associated work-data.
ASMJIT_INLINE bool hasPassData() const noexcept { return _passData != nullptr; }
//! Get work-data - data used during processing & transformations.
template<typename T>
ASMJIT_INLINE T* getPassData() const noexcept { return (T*)_passData; }
//! Set work-data to `data`.
template<typename T>
ASMJIT_INLINE void setPassData(T* data) noexcept { _passData = (void*)data; }
//! Reset work-data to null.
ASMJIT_INLINE void resetPassData() noexcept { _passData = nullptr; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CBNode* _prev; //!< Previous node.
CBNode* _next; //!< Next node.
uint8_t _type; //!< Node type, see \ref NodeType.
uint8_t _opCount; //!< Count of operands or zero.
uint16_t _flags; //!< Flags, different meaning for every type of the node.
uint32_t _position; //!< Flow index.
const char* _inlineComment; //!< Inline comment or null if not used.
void* _passData; //!< Data used exclusively by the current `CBPass`.
};
// ============================================================================
// [asmjit::CBInst]
// ============================================================================
//! Instruction (CodeBuilder).
//!
//! Wraps an instruction with its options and operands.
class CBInst : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBInst)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBInst` instance.
ASMJIT_INLINE CBInst(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBNode(cb, kNodeInst) {
orFlags(kFlagIsRemovable);
_instDetail.instId = static_cast<uint16_t>(instId);
_instDetail.options = options;
_opCount = static_cast<uint8_t>(opCount);
_opArray = opArray;
_updateMemOp();
}
//! Destroy the `CBInst` instance (NEVER CALLED).
ASMJIT_INLINE ~CBInst() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE Inst::Detail& getInstDetail() noexcept { return _instDetail; }
ASMJIT_INLINE const Inst::Detail& getInstDetail() const noexcept { return _instDetail; }
//! Get the instruction id, see \ref Inst::Id.
ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instDetail.instId; }
//! Set the instruction id to `instId`, see \ref Inst::Id.
ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instDetail.instId = instId; }
//! Whether the instruction is either a jump or a conditional jump likely to be taken.
ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); }
//! Get emit options.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instDetail.options; }
//! Set emit options.
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instDetail.options = options; }
//! Add emit options.
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instDetail.options |= options; }
//! Mask emit options.
ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instDetail.options &= options; }
//! Clear emit options.
ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instDetail.options &= ~options; }
//! Get if the node has an extra register operand.
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _instDetail.hasExtraReg(); }
//! Get extra register operand.
ASMJIT_INLINE RegOnly& getExtraReg() noexcept { return _instDetail.extraReg; }
//! \overload
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _instDetail.extraReg; }
//! Set extra register operand to `reg`.
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _instDetail.extraReg.init(reg); }
//! Set extra register operand to `reg`.
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _instDetail.extraReg.init(reg); }
//! Reset extra register operand.
ASMJIT_INLINE void resetExtraReg() noexcept { _instDetail.extraReg.reset(); }
//! Get operands count.
ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; }
//! Get operands list.
ASMJIT_INLINE Operand* getOpArray() noexcept { return _opArray; }
//! \overload
ASMJIT_INLINE const Operand* getOpArray() const noexcept { return _opArray; }
//! Get whether the instruction contains a memory operand.
ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; }
//! Get memory operand.
//!
//! NOTE: Can only be called if the instruction has such operand,
//! see `hasMemOp()`.
ASMJIT_INLINE Mem* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<Mem*>(&_opArray[_memOpIndex]);
}
//! \overload
template<typename T>
ASMJIT_INLINE T* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<T*>(&_opArray[_memOpIndex]);
}
//! Set memory operand index, `0xFF` means no memory operand.
ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast<uint8_t>(index); }
//! Reset memory operand index to `0xFF` (no operand).
ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; }
// --------------------------------------------------------------------------
// [Utils]
// --------------------------------------------------------------------------
ASMJIT_INLINE void _updateMemOp() noexcept {
Operand* opArray = getOpArray();
uint32_t opCount = getOpCount();
uint32_t i;
for (i = 0; i < opCount; i++)
if (opArray[i].isMem())
goto Update;
i = 0xFF;
Update:
setMemOpIndex(i);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
Inst::Detail _instDetail; //!< Instruction id, options, and extra register.
uint8_t _memOpIndex; //!< \internal
uint8_t _reserved[7]; //!< \internal
Operand* _opArray; //!< Instruction operands.
};
// ============================================================================
// [asmjit::CBInstEx]
// ============================================================================
struct CBInstEx : public CBInst {
Operand _op4;
Operand _op5;
};
// ============================================================================
// [asmjit::CBJump]
// ============================================================================
//! Asm jump (conditional or direct).
//!
//! Extension of `CBInst` node, which stores more information about the jump.
class CBJump : public CBInst {
public:
ASMJIT_NONCOPYABLE(CBJump)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE CBJump(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBInst(cb, instId, options, opArray, opCount),
_target(nullptr),
_jumpNext(nullptr) {}
ASMJIT_INLINE ~CBJump() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE CBLabel* getTarget() const noexcept { return _target; }
ASMJIT_INLINE CBJump* getJumpNext() const noexcept { return _jumpNext; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CBLabel* _target; //!< Target node.
CBJump* _jumpNext; //!< Next jump to the same target in a single linked-list.
};
// ============================================================================
// [asmjit::CBData]
// ============================================================================
//! Asm data (CodeBuilder).
//!
//! Wraps `.data` directive. The node contains data that will be placed at the
//! node's position in the assembler stream. The data is considered to be RAW;
//! no analysis nor byte-order conversion is performed on RAW data.
class CBData : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBData)
enum { kInlineBufferSize = static_cast<int>(64 - sizeof(CBNode) - 4) };
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBData` instance.
ASMJIT_INLINE CBData(CodeBuilder* cb, void* data, uint32_t size) noexcept : CBNode(cb, kNodeData) {
if (size <= kInlineBufferSize) {
if (data) ::memcpy(_buf, data, size);
}
else {
_externalPtr = static_cast<uint8_t*>(data);
}
_size = size;
}
//! Destroy the `CBData` instance (NEVER CALLED).
ASMJIT_INLINE ~CBData() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get size of the data.
uint32_t getSize() const noexcept { return _size; }
//! Get pointer to the data.
uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_buf) : _externalPtr; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
struct {
uint8_t _buf[kInlineBufferSize]; //!< Embedded data buffer.
uint32_t _size; //!< Size of the data.
};
struct {
uint8_t* _externalPtr; //!< Pointer to external data.
};
};
};
// ============================================================================
// [asmjit::CBAlign]
// ============================================================================
//! Align directive (CodeBuilder).
//!
//! Wraps `.align` directive.
class CBAlign : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBAlign)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBAlign` instance.
ASMJIT_INLINE CBAlign(CodeBuilder* cb, uint32_t mode, uint32_t alignment) noexcept
: CBNode(cb, kNodeAlign),
_mode(mode),
_alignment(alignment) {}
//! Destroy the `CBAlign` instance (NEVER CALLED).
ASMJIT_INLINE ~CBAlign() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get align mode.
ASMJIT_INLINE uint32_t getMode() const noexcept { return _mode; }
//! Set align mode.
ASMJIT_INLINE void setMode(uint32_t mode) noexcept { _mode = mode; }
//! Get align offset in bytes.
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
//! Set align offset in bytes to `offset`.
ASMJIT_INLINE void setAlignment(uint32_t alignment) noexcept { _alignment = alignment; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _mode; //!< Align mode, see \ref AlignMode.
uint32_t _alignment; //!< Alignment (in bytes).
};
// ============================================================================
// [asmjit::CBLabel]
// ============================================================================
//! Label (CodeBuilder).
class CBLabel : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBLabel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBLabel` instance.
ASMJIT_INLINE CBLabel(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBNode(cb, kNodeLabel),
_id(id),
_numRefs(0),
_from(nullptr) {}
//! Destroy the `CBLabel` instance (NEVER CALLED).
ASMJIT_INLINE ~CBLabel() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the label id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get the label as `Label` operand.
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
//! Get first jmp instruction.
ASMJIT_INLINE CBJump* getFrom() const noexcept { return _from; }
//! Get number of jumps to this target.
ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; }
//! Set number of jumps to this target.
ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; }
//! Add number of jumps to this target.
ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; }
//! Subtract number of jumps to this target.
ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id; //!< Label id.
uint32_t _numRefs; //!< Count of jumps here.
CBJump* _from; //!< Linked-list of nodes that can jump here.
};
// ============================================================================
// [asmjit::CBLabelData]
// ============================================================================
class CBLabelData : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBLabelData)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBLabelData` instance.
ASMJIT_INLINE CBLabelData(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBNode(cb, kNodeLabelData),
_id(id) {}
//! Destroy the `CBLabelData` instance (NEVER CALLED).
ASMJIT_INLINE ~CBLabelData() noexcept {}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
//! Get the label id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get the label as `Label` operand.
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id;
};
// ============================================================================
// [asmjit::CBConstPool]
// ============================================================================
class CBConstPool : public CBLabel {
public:
ASMJIT_NONCOPYABLE(CBConstPool)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBConstPool` instance.
ASMJIT_INLINE CBConstPool(CodeBuilder* cb, uint32_t id = kInvalidValue) noexcept
: CBLabel(cb, id),
_constPool(&cb->_cbBaseZone) { _type = kNodeConstPool; }
//! Destroy the `CBConstPool` instance (NEVER CALLED).
ASMJIT_INLINE ~CBConstPool() noexcept {}
// --------------------------------------------------------------------------
// [Interface]
// --------------------------------------------------------------------------
ASMJIT_INLINE ConstPool& getConstPool() noexcept { return _constPool; }
ASMJIT_INLINE const ConstPool& getConstPool() const noexcept { return _constPool; }
//! Get whether the constant-pool is empty.
ASMJIT_INLINE bool isEmpty() const noexcept { return _constPool.isEmpty(); }
//! Get the size of the constant-pool in bytes.
ASMJIT_INLINE size_t getSize() const noexcept { return _constPool.getSize(); }
//! Get minimum alignment.
ASMJIT_INLINE size_t getAlignment() const noexcept { return _constPool.getAlignment(); }
//! See \ref ConstPool::add().
ASMJIT_INLINE Error add(const void* data, size_t size, size_t& dstOffset) noexcept {
return _constPool.add(data, size, dstOffset);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
ConstPool _constPool;
};
// ============================================================================
// [asmjit::CBComment]
// ============================================================================
//! Comment (CodeBuilder).
class CBComment : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBComment)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBComment` instance.
ASMJIT_INLINE CBComment(CodeBuilder* cb, const char* comment) noexcept : CBNode(cb, kNodeComment) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_inlineComment = comment;
}
//! Destroy the `CBComment` instance (NEVER CALLED).
ASMJIT_INLINE ~CBComment() noexcept {}
};
// ============================================================================
// [asmjit::CBSentinel]
// ============================================================================
//! Sentinel (CodeBuilder).
//!
//! Sentinel is a marker that is completely ignored by the code builder. It's
//! used to remember a position in a code as it never gets removed by any pass.
class CBSentinel : public CBNode {
public:
ASMJIT_NONCOPYABLE(CBSentinel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CBSentinel` instance.
ASMJIT_INLINE CBSentinel(CodeBuilder* cb) noexcept : CBNode(cb, kNodeSentinel) {}
//! Destroy the `CBSentinel` instance (NEVER CALLED).
ASMJIT_INLINE ~CBSentinel() noexcept {}
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_BUILDER
#endif // _ASMJIT_BASE_CODEBUILDER_H
// [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 "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codecompiler.h"
#include "../base/cpuinfo.h"
#include "../base/logging.h"
#include "../base/regalloc_p.h"
#include "../base/utils.h"
#include <stdarg.h>
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Constants]
// ============================================================================
static const char noName[1] = { '\0' };
// ============================================================================
// [asmjit::CCFuncCall - Arg / Ret]
// ============================================================================
bool CCFuncCall::_setArg(uint32_t i, const Operand_& op) noexcept {
if ((i & ~kFuncArgHi) >= _funcDetail.getArgCount())
return false;
_args[i] = op;
return true;
}
bool CCFuncCall::_setRet(uint32_t i, const Operand_& op) noexcept {
if (i >= 2)
return false;
_ret[i] = op;
return true;
}
// ============================================================================
// [asmjit::CodeCompiler - Construction / Destruction]
// ============================================================================
CodeCompiler::CodeCompiler() noexcept
: CodeBuilder(),
_func(nullptr),
_vRegZone(4096 - Zone::kZoneOverhead),
_vRegArray(),
_localConstPool(nullptr),
_globalConstPool(nullptr) {
_type = kTypeCompiler;
}
CodeCompiler::~CodeCompiler() noexcept {}
// ============================================================================
// [asmjit::CodeCompiler - Events]
// ============================================================================
Error CodeCompiler::onAttach(CodeHolder* code) noexcept {
return Base::onAttach(code);
}
Error CodeCompiler::onDetach(CodeHolder* code) noexcept {
_func = nullptr;
_localConstPool = nullptr;
_globalConstPool = nullptr;
_vRegArray.reset();
_vRegZone.reset(false);
return Base::onDetach(code);
}
// ============================================================================
// [asmjit::CodeCompiler - Node-Factory]
// ============================================================================
CCHint* CodeCompiler::newHintNode(Reg& r, uint32_t hint, uint32_t value) noexcept {
if (!r.isVirtReg()) return nullptr;
VirtReg* vr = getVirtReg(r);
return newNodeT<CCHint>(vr, hint, value);
}
// ============================================================================
// [asmjit::CodeCompiler - Func]
// ============================================================================
CCFunc* CodeCompiler::newFunc(const FuncSignature& sign) noexcept {
Error err;
CCFunc* func = newNodeT<CCFunc>();
if (!func) goto _NoMemory;
err = registerLabelNode(func);
if (ASMJIT_UNLIKELY(err)) {
// TODO: Calls setLastError, maybe rethink noexcept?
setLastError(err);
return nullptr;
}
// Create helper nodes.
func->_exitNode = newLabelNode();
func->_end = newNodeT<CBSentinel>();
if (!func->_exitNode || !func->_end)
goto _NoMemory;
// Function prototype.
err = func->getDetail().init(sign);
if (err != kErrorOk) {
setLastError(err);
return nullptr;
}
// If the CodeInfo guarantees higher alignment honor it.
if (_codeInfo.getStackAlignment() > func->_funcDetail._callConv.getNaturalStackAlignment())
func->_funcDetail._callConv.setNaturalStackAlignment(_codeInfo.getStackAlignment());
// Allocate space for function arguments.
func->_args = nullptr;
if (func->getArgCount() != 0) {
func->_args = _cbHeap.allocT<VirtReg*>(func->getArgCount() * sizeof(VirtReg*));
if (!func->_args) goto _NoMemory;
::memset(func->_args, 0, func->getArgCount() * sizeof(VirtReg*));
}
return func;
_NoMemory:
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
CCFunc* CodeCompiler::addFunc(CCFunc* func) {
ASMJIT_ASSERT(_func == nullptr);
_func = func;
addNode(func); // Function node.
CBNode* cursor = getCursor(); // {CURSOR}.
addNode(func->getExitNode()); // Function exit label.
addNode(func->getEnd()); // Function end marker.
_setCursor(cursor);
return func;
}
CCFunc* CodeCompiler::addFunc(const FuncSignature& sign) {
CCFunc* func = newFunc(sign);
if (!func) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
return addFunc(func);
}
CBSentinel* CodeCompiler::endFunc() {
CCFunc* func = getFunc();
if (!func) {
// TODO:
return nullptr;
}
// Add the local constant pool at the end of the function (if exists).
if (_localConstPool) {
setCursor(func->getEnd()->getPrev());
addNode(_localConstPool);
_localConstPool = nullptr;
}
// Mark as finished.
func->_isFinished = true;
_func = nullptr;
CBSentinel* end = func->getEnd();
setCursor(end);
return end;
}
// ============================================================================
// [asmjit::CodeCompiler - Ret]
// ============================================================================
CCFuncRet* CodeCompiler::newRet(const Operand_& o0, const Operand_& o1) noexcept {
CCFuncRet* node = newNodeT<CCFuncRet>(o0, o1);
if (!node) {
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
return node;
}
CCFuncRet* CodeCompiler::addRet(const Operand_& o0, const Operand_& o1) noexcept {
CCFuncRet* node = newRet(o0, o1);
if (!node) return nullptr;
return static_cast<CCFuncRet*>(addNode(node));
}
// ============================================================================
// [asmjit::CodeCompiler - Call]
// ============================================================================
CCFuncCall* CodeCompiler::newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
Error err;
uint32_t nArgs;
CCFuncCall* node = _cbHeap.allocT<CCFuncCall>(sizeof(CCFuncCall) + sizeof(Operand));
Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CCFuncCall));
if (ASMJIT_UNLIKELY(!node))
goto _NoMemory;
opArray[0].copyFrom(o0);
new (node) CCFuncCall(this, instId, 0, opArray, 1);
if ((err = node->getDetail().init(sign)) != kErrorOk) {
setLastError(err);
return nullptr;
}
// If there are no arguments skip the allocation.
if ((nArgs = sign.getArgCount()) == 0)
return node;
node->_args = static_cast<Operand*>(_cbHeap.alloc(nArgs * sizeof(Operand)));
if (!node->_args) goto _NoMemory;
::memset(node->_args, 0, nArgs * sizeof(Operand));
return node;
_NoMemory:
setLastError(DebugUtils::errored(kErrorNoHeapMemory));
return nullptr;
}
CCFuncCall* CodeCompiler::addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept {
CCFuncCall* node = newCall(instId, o0, sign);
if (!node) return nullptr;
return static_cast<CCFuncCall*>(addNode(node));
}
// ============================================================================
// [asmjit::CodeCompiler - Vars]
// ============================================================================
Error CodeCompiler::setArg(uint32_t argIndex, const Reg& r) {
CCFunc* func = getFunc();
if (!func)
return setLastError(DebugUtils::errored(kErrorInvalidState));
if (!isVirtRegValid(r))
return setLastError(DebugUtils::errored(kErrorInvalidVirtId));
VirtReg* vr = getVirtReg(r);
func->setArg(argIndex, vr);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeCompiler - Hint]
// ============================================================================
Error CodeCompiler::_hint(Reg& r, uint32_t hint, uint32_t value) {
if (!r.isVirtReg()) return kErrorOk;
CCHint* node = newHintNode(r, hint, value);
if (!node) return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
addNode(node);
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeCompiler - Vars]
// ============================================================================
VirtReg* CodeCompiler::newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept {
size_t index = _vRegArray.getLength();
if (ASMJIT_UNLIKELY(index > Operand::kPackedIdCount))
return nullptr;
VirtReg* vreg;
if (_vRegArray.willGrow(&_cbHeap, 1) != kErrorOk || !(vreg = _vRegZone.allocZeroedT<VirtReg>()))
return nullptr;
vreg->_id = Operand::packId(static_cast<uint32_t>(index));
vreg->_regInfo._signature = signature;
vreg->_name = noName;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (name && name[0] != '\0')
vreg->_name = static_cast<char*>(_cbDataZone.dup(name, ::strlen(name), true));
#endif // !ASMJIT_DISABLE_LOGGING
vreg->_size = TypeId::sizeOf(typeId);
vreg->_typeId = typeId;
vreg->_alignment = static_cast<uint8_t>(std::min<uint32_t>(vreg->_size, 64));
vreg->_priority = 10;
// The following are only used by `RAPass`.
vreg->_raId = kInvalidValue;
vreg->_state = VirtReg::kStateNone;
vreg->_physId = Globals::kInvalidRegId;
_vRegArray.appendUnsafe(vreg);
return vreg;
}
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* name) {
RegInfo regInfo;
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
out._initReg(regInfo.getSignature(), vReg->getId());
return kErrorOk;
}
Error CodeCompiler::_newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap) {
StringBuilderTmp<256> sb;
sb.appendFormatVA(nameFmt, ap);
return _newReg(out, typeId, sb.getData());
}
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* name) {
RegInfo regInfo;
uint32_t typeId;
if (isVirtRegValid(ref)) {
VirtReg* vRef = getVirtReg(ref);
typeId = vRef->getTypeId();
// NOTE: It's possible to cast one register type to another if it's the
// same register kind. However, VirtReg always contains the TypeId that
// was used to create the register. This means that in some cases we may
// end up having different size of `ref` and `vRef`. In such case we
// adjust the TypeId to match the `ref` register type instead of the
// original register type, which should be the expected behavior.
uint32_t typeSize = TypeId::sizeOf(typeId);
uint32_t refSize = ref.getSize();
if (typeSize != refSize) {
if (TypeId::isInt(typeId)) {
// GP register - change TypeId to match `ref`, but keep sign of `vRef`.
switch (refSize) {
case 1: typeId = TypeId::kI8 | (typeId & 1); break;
case 2: typeId = TypeId::kI16 | (typeId & 1); break;
case 4: typeId = TypeId::kI32 | (typeId & 1); break;
case 8: typeId = TypeId::kI64 | (typeId & 1); break;
default: typeId = TypeId::kVoid; break;
}
}
else if (TypeId::isMmx(typeId)) {
// MMX register - always use 64-bit.
typeId = TypeId::kMmx64;
}
else if (TypeId::isMask(typeId)) {
// Mask register - change TypeId to match `ref` size.
switch (refSize) {
case 1: typeId = TypeId::kMask8; break;
case 2: typeId = TypeId::kMask16; break;
case 4: typeId = TypeId::kMask32; break;
case 8: typeId = TypeId::kMask64; break;
default: typeId = TypeId::kVoid; break;
}
}
else {
// VEC register - change TypeId to match `ref` size, keep vector metadata.
uint32_t elementTypeId = TypeId::elementOf(typeId);
switch (refSize) {
case 16: typeId = TypeId::_kVec128Start + (elementTypeId - TypeId::kI8); break;
case 32: typeId = TypeId::_kVec256Start + (elementTypeId - TypeId::kI8); break;
case 64: typeId = TypeId::_kVec512Start + (elementTypeId - TypeId::kI8); break;
default: typeId = TypeId::kVoid; break;
}
}
if (typeId == TypeId::kVoid)
return setLastError(DebugUtils::errored(kErrorInvalidState));
}
}
else {
typeId = ref.getType();
}
Error err = ArchUtils::typeIdToRegInfo(getArchType(), typeId, regInfo);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
VirtReg* vReg = newVirtReg(typeId, regInfo.getSignature(), name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
out._initReg(regInfo.getSignature(), vReg->getId());
return kErrorOk;
}
Error CodeCompiler::_newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap) {
StringBuilderTmp<256> sb;
sb.appendFormatVA(nameFmt, ap);
return _newReg(out, ref, sb.getData());
}
Error CodeCompiler::_newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name) {
if (size == 0)
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (alignment == 0) alignment = 1;
if (!Utils::isPowerOf2(alignment))
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (alignment > 64) alignment = 64;
VirtReg* vReg = newVirtReg(0, 0, name);
if (ASMJIT_UNLIKELY(!vReg)) {
out.reset();
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
}
vReg->_size = size;
vReg->_isStack = true;
vReg->_alignment = static_cast<uint8_t>(alignment);
// Set the memory operand to GPD/GPQ and its id to VirtReg.
out = Mem(Init, _nativeGpReg.getType(), vReg->getId(), Reg::kRegNone, kInvalidValue, 0, 0, Mem::kSignatureMemRegHomeFlag);
return kErrorOk;
}
Error CodeCompiler::_newConst(Mem& out, uint32_t scope, const void* data, size_t size) {
CBConstPool** pPool;
if (scope == kConstScopeLocal)
pPool = &_localConstPool;
else if (scope == kConstScopeGlobal)
pPool = &_globalConstPool;
else
return setLastError(DebugUtils::errored(kErrorInvalidArgument));
if (!*pPool && !(*pPool = newConstPool()))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
CBConstPool* pool = *pPool;
size_t off;
Error err = pool->add(data, size, off);
if (ASMJIT_UNLIKELY(err)) return setLastError(err);
out = Mem(Init,
Label::kLabelTag, // Base type.
pool->getId(), // Base id.
0, // Index type.
kInvalidValue, // Index id.
static_cast<int32_t>(off), // Offset.
static_cast<uint32_t>(size), // Size.
0); // Flags.
return kErrorOk;
}
Error CodeCompiler::alloc(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, kInvalidValue);
}
Error CodeCompiler::alloc(Reg& reg, uint32_t physId) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, physId);
}
Error CodeCompiler::alloc(Reg& reg, const Reg& physReg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintAlloc, physReg.getId());
}
Error CodeCompiler::save(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintSave, kInvalidValue);
}
Error CodeCompiler::spill(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintSpill, kInvalidValue);
}
Error CodeCompiler::unuse(Reg& reg) {
if (!reg.isVirtReg()) return kErrorOk;
return _hint(reg, CCHint::kHintUnuse, kInvalidValue);
}
uint32_t CodeCompiler::getPriority(Reg& reg) const {
if (!reg.isVirtReg()) return 0;
return getVirtRegById(reg.getId())->getPriority();
}
void CodeCompiler::setPriority(Reg& reg, uint32_t priority) {
if (!reg.isVirtReg()) return;
if (priority > 255) priority = 255;
VirtReg* vreg = getVirtRegById(reg.getId());
if (vreg) vreg->_priority = static_cast<uint8_t>(priority);
}
bool CodeCompiler::getSaveOnUnuse(Reg& reg) const {
if (!reg.isVirtReg()) return false;
VirtReg* vreg = getVirtRegById(reg.getId());
return static_cast<bool>(vreg->_saveOnUnuse);
}
void CodeCompiler::setSaveOnUnuse(Reg& reg, bool value) {
if (!reg.isVirtReg()) return;
VirtReg* vreg = getVirtRegById(reg.getId());
if (!vreg) return;
vreg->_saveOnUnuse = value;
}
void CodeCompiler::rename(Reg& reg, const char* fmt, ...) {
if (!reg.isVirtReg()) return;
VirtReg* vreg = getVirtRegById(reg.getId());
if (!vreg) return;
vreg->_name = noName;
if (fmt && fmt[0] != '\0') {
char buf[64];
va_list ap;
va_start(ap, fmt);
vsnprintf(buf, ASMJIT_ARRAY_SIZE(buf), fmt, ap);
buf[ASMJIT_ARRAY_SIZE(buf) - 1] = '\0';
vreg->_name = static_cast<char*>(_cbDataZone.dup(buf, ::strlen(buf), true));
va_end(ap);
}
}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODECOMPILER_H
#define _ASMJIT_BASE_CODECOMPILER_H
#include "../asmjit_build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/codebuilder.h"
#include "../base/constpool.h"
#include "../base/func.h"
#include "../base/operand.h"
#include "../base/utils.h"
#include "../base/zone.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
struct VirtReg;
struct TiedReg;
struct RAState;
struct RACell;
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::ConstScope]
// ============================================================================
//! Scope of the constant.
ASMJIT_ENUM(ConstScope) {
//! Local constant, always embedded right after the current function.
kConstScopeLocal = 0,
//! Global constant, embedded at the end of the currently compiled code.
kConstScopeGlobal = 1
};
// ============================================================================
// [asmjit::VirtReg]
// ============================================================================
//! Virtual register data (CodeCompiler).
struct VirtReg {
//! A state of a virtual register (used during register allocation).
ASMJIT_ENUM(State) {
kStateNone = 0, //!< Not allocated, not used.
kStateReg = 1, //!< Allocated in register.
kStateMem = 2 //!< Allocated in memory or spilled.
};
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the virtual-register id.
ASMJIT_INLINE uint32_t getId() const noexcept { return _id; }
//! Get virtual-register's name.
ASMJIT_INLINE const char* getName() const noexcept { return _name; }
//! Get a physical register type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _regInfo.getType(); }
//! Get a physical register kind.
ASMJIT_INLINE uint32_t getKind() const noexcept { return _regInfo.getKind(); }
//! Get a physical register size.
ASMJIT_INLINE uint32_t getRegSize() const noexcept { return _regInfo.getSize(); }
//! Get a register signature of this virtual register.
ASMJIT_INLINE uint32_t getSignature() const noexcept { return _regInfo.getSignature(); }
//! Get a register's type-id, see \ref TypeId.
ASMJIT_INLINE uint32_t getTypeId() const noexcept { return _typeId; }
//! Get virtual-register's size.
ASMJIT_INLINE uint32_t getSize() const noexcept { return _size; }
//! Get virtual-register's alignment.
ASMJIT_INLINE uint32_t getAlignment() const noexcept { return _alignment; }
//! Get the virtual-register priority, used by compiler to decide which variable to spill.
ASMJIT_INLINE uint32_t getPriority() const noexcept { return _priority; }
//! Set the virtual-register priority.
ASMJIT_INLINE void setPriority(uint32_t priority) noexcept {
ASMJIT_ASSERT(priority <= 0xFF);
_priority = static_cast<uint8_t>(priority);
}
//! Get variable state, only used by `RAPass`.
ASMJIT_INLINE uint32_t getState() const noexcept { return _state; }
//! Set variable state, only used by `RAPass`.
ASMJIT_INLINE void setState(uint32_t state) {
ASMJIT_ASSERT(state <= 0xFF);
_state = static_cast<uint8_t>(state);
}
//! Get register index.
ASMJIT_INLINE uint32_t getPhysId() const noexcept { return _physId; }
//! Set register index.
ASMJIT_INLINE void setPhysId(uint32_t physId) {
ASMJIT_ASSERT(physId <= Globals::kInvalidRegId);
_physId = static_cast<uint8_t>(physId);
}
//! Reset register index.
ASMJIT_INLINE void resetPhysId() {
_physId = static_cast<uint8_t>(Globals::kInvalidRegId);
}
//! Get home registers mask.
ASMJIT_INLINE uint32_t getHomeMask() const { return _homeMask; }
//! Add a home register index to the home registers mask.
ASMJIT_INLINE void addHomeId(uint32_t physId) { _homeMask |= Utils::mask(physId); }
ASMJIT_INLINE bool isFixed() const noexcept { return static_cast<bool>(_isFixed); }
//! Get whether the VirtReg is only memory allocated on the stack.
ASMJIT_INLINE bool isStack() const noexcept { return static_cast<bool>(_isStack); }
//! Get whether to save variable when it's unused (spill).
ASMJIT_INLINE bool saveOnUnuse() const noexcept { return static_cast<bool>(_saveOnUnuse); }
//! Get whether the variable was changed.
ASMJIT_INLINE bool isModified() const noexcept { return static_cast<bool>(_modified); }
//! Set whether the variable was changed.
ASMJIT_INLINE void setModified(bool modified) noexcept { _modified = modified; }
//! Get home memory offset.
ASMJIT_INLINE int32_t getMemOffset() const noexcept { return _memOffset; }
//! Set home memory offset.
ASMJIT_INLINE void setMemOffset(int32_t offset) noexcept { _memOffset = offset; }
//! Get home memory cell.
ASMJIT_INLINE RACell* getMemCell() const noexcept { return _memCell; }
//! Set home memory cell.
ASMJIT_INLINE void setMemCell(RACell* cell) noexcept { _memCell = cell; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
uint32_t _id; //!< Virtual register id.
RegInfo _regInfo; //!< Physical register info & signature.
const char* _name; //!< Virtual name (user provided).
uint32_t _size; //!< Virtual size (can be smaller than `regInfo._size`).
uint8_t _typeId; //!< Type-id.
uint8_t _alignment; //!< Register's natural alignment (for spilling).
uint8_t _priority; //!< Allocation priority (hint for RAPass that can be ignored).
uint8_t _isFixed : 1; //!< True if this is a fixed register, never reallocated.
uint8_t _isStack : 1; //!< True if the virtual register is only used as a stack.
uint8_t _isMaterialized : 1; //!< Register is constant that is easily created by a single instruction.
uint8_t _saveOnUnuse : 1; //!< Save on unuse (at end of the variable scope).
// -------------------------------------------------------------------------
// The following members are used exclusively by RAPass. They are initialized
// when the VirtReg is created and then changed during RAPass.
// -------------------------------------------------------------------------
uint32_t _raId; //!< Register allocator work-id (used by RAPass).
int32_t _memOffset; //!< Home memory offset.
uint32_t _homeMask; //!< Mask of all registers variable has been allocated to.
uint8_t _state; //!< Variable state (connected with actual `RAState)`.
uint8_t _physId; //!< Actual register index (only used by `RAPass)`, during translate.
uint8_t _modified; //!< Whether variable was changed (connected with actual `RAState)`.
RACell* _memCell; //!< Home memory cell, used by `RAPass` (initially nullptr).
//! Temporary link to TiedReg* used by the `RAPass` used in
//! various phases, but always set back to nullptr when finished.
//!
//! This temporary data is designed to be used by algorithms that need to
//! store some data into variables themselves during compilation. But it's
//! expected that after variable is compiled & translated the data is set
//! back to zero/null. Initial value is nullptr.
TiedReg* _tied;
};
// ============================================================================
// [asmjit::CCHint]
// ============================================================================
//! Hint for register allocator (CodeCompiler).
class CCHint : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCHint)
//! Hint type.
ASMJIT_ENUM(Hint) {
//! Alloc to physical reg.
kHintAlloc = 0,
//! Spill to memory.
kHintSpill = 1,
//! Save if modified.
kHintSave = 2,
//! Save if modified and mark it as unused.
kHintSaveAndUnuse = 3,
//! Mark as unused.
kHintUnuse = 4
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCHint` instance.
ASMJIT_INLINE CCHint(CodeBuilder* cb, VirtReg* vreg, uint32_t hint, uint32_t value) noexcept : CBNode(cb, kNodeHint) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_vreg = vreg;
_hint = hint;
_value = value;
}
//! Destroy the `CCHint` instance (NEVER CALLED).
ASMJIT_INLINE ~CCHint() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get variable.
ASMJIT_INLINE VirtReg* getVReg() const noexcept { return _vreg; }
//! Get hint it, see \ref Hint.
ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; }
//! Set hint it, see \ref Hint.
ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; }
//! Get hint value.
ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; }
//! Set hint value.
ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Variable.
VirtReg* _vreg;
//! Hint id.
uint32_t _hint;
//! Value.
uint32_t _value;
};
// ============================================================================
// [asmjit::CCFunc]
// ============================================================================
//! Function entry (CodeCompiler).
class CCFunc : public CBLabel {
public:
ASMJIT_NONCOPYABLE(CCFunc)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFunc` instance.
//!
//! Always use `CodeCompiler::addFunc()` to create \ref CCFunc.
ASMJIT_INLINE CCFunc(CodeBuilder* cb) noexcept
: CBLabel(cb),
_funcDetail(),
_frameInfo(),
_exitNode(nullptr),
_end(nullptr),
_args(nullptr),
_isFinished(false) {
_type = kNodeFunc;
}
//! Destroy the `CCFunc` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFunc() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function exit `CBLabel`.
ASMJIT_INLINE CBLabel* getExitNode() const noexcept { return _exitNode; }
//! Get function exit label.
ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); }
//! Get "End of Func" sentinel.
ASMJIT_INLINE CBSentinel* getEnd() const noexcept { return _end; }
//! Get function declaration.
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE FuncFrameInfo& getFrameInfo() noexcept { return _frameInfo; }
//! Get function declaration.
ASMJIT_INLINE const FuncFrameInfo& getFrameInfo() const noexcept { return _frameInfo; }
//! Get arguments count.
ASMJIT_INLINE uint32_t getArgCount() const noexcept { return _funcDetail.getArgCount(); }
//! Get returns count.
ASMJIT_INLINE uint32_t getRetCount() const noexcept { return _funcDetail.getRetCount(); }
//! Get arguments list.
ASMJIT_INLINE VirtReg** getArgs() const noexcept { return _args; }
//! Get argument at `i`.
ASMJIT_INLINE VirtReg* getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < getArgCount());
return _args[i];
}
//! Set argument at `i`.
ASMJIT_INLINE void setArg(uint32_t i, VirtReg* vreg) noexcept {
ASMJIT_ASSERT(i < getArgCount());
_args[i] = vreg;
}
//! Reset argument at `i`.
ASMJIT_INLINE void resetArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < getArgCount());
_args[i] = nullptr;
}
ASMJIT_INLINE uint32_t getAttributes() const noexcept { return _frameInfo.getAttributes(); }
ASMJIT_INLINE void addAttributes(uint32_t attrs) noexcept { _frameInfo.addAttributes(attrs); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
FuncDetail _funcDetail; //!< Function detail.
FuncFrameInfo _frameInfo; //!< Function frame information.
CBLabel* _exitNode; //!< Function exit.
CBSentinel* _end; //!< Function end.
VirtReg** _args; //!< Arguments array as `VirtReg`.
//! Function was finished by `Compiler::endFunc()`.
uint8_t _isFinished;
};
// ============================================================================
// [asmjit::CCFuncRet]
// ============================================================================
//! Function return (CodeCompiler).
class CCFuncRet : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCFuncRet)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFuncRet` instance.
ASMJIT_INLINE CCFuncRet(CodeBuilder* cb, const Operand_& o0, const Operand_& o1) noexcept : CBNode(cb, kNodeFuncExit) {
orFlags(kFlagIsRet);
_ret[0].copyFrom(o0);
_ret[1].copyFrom(o1);
}
//! Destroy the `CCFuncRet` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFuncRet() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the first return operand.
ASMJIT_INLINE Operand& getFirst() noexcept { return static_cast<Operand&>(_ret[0]); }
//! \overload
ASMJIT_INLINE const Operand& getFirst() const noexcept { return static_cast<const Operand&>(_ret[0]); }
//! Get the second return operand.
ASMJIT_INLINE Operand& getSecond() noexcept { return static_cast<Operand&>(_ret[1]); }
//! \overload
ASMJIT_INLINE const Operand& getSecond() const noexcept { return static_cast<const Operand&>(_ret[1]); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Return operands.
Operand_ _ret[2];
};
// ============================================================================
// [asmjit::CCFuncCall]
// ============================================================================
//! Function call (CodeCompiler).
class CCFuncCall : public CBInst {
public:
ASMJIT_NONCOPYABLE(CCFuncCall)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCFuncCall` instance.
ASMJIT_INLINE CCFuncCall(CodeBuilder* cb, uint32_t instId, uint32_t options, Operand* opArray, uint32_t opCount) noexcept
: CBInst(cb, instId, options, opArray, opCount),
_funcDetail(),
_args(nullptr) {
_type = kNodeFuncCall;
_ret[0].reset();
_ret[1].reset();
orFlags(kFlagIsRemovable);
}
//! Destroy the `CCFuncCall` instance (NEVER CALLED).
ASMJIT_INLINE ~CCFuncCall() noexcept {}
// --------------------------------------------------------------------------
// [Signature]
// --------------------------------------------------------------------------
//! Set function signature.
ASMJIT_INLINE Error setSignature(const FuncSignature& sign) noexcept {
return _funcDetail.init(sign);
}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function declaration.
ASMJIT_INLINE FuncDetail& getDetail() noexcept { return _funcDetail; }
//! Get function declaration.
ASMJIT_INLINE const FuncDetail& getDetail() const noexcept { return _funcDetail; }
//! Get target operand.
ASMJIT_INLINE Operand& getTarget() noexcept { return static_cast<Operand&>(_opArray[0]); }
//! \overload
ASMJIT_INLINE const Operand& getTarget() const noexcept { return static_cast<const Operand&>(_opArray[0]); }
//! Get return at `i`.
ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept {
ASMJIT_ASSERT(i < 2);
return static_cast<Operand&>(_ret[i]);
}
//! \overload
ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept {
ASMJIT_ASSERT(i < 2);
return static_cast<const Operand&>(_ret[i]);
}
//! Get argument at `i`.
ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return static_cast<Operand&>(_args[i]);
}
//! \overload
ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return static_cast<const Operand&>(_args[i]);
}
//! Set argument at `i` to `op`.
ASMJIT_API bool _setArg(uint32_t i, const Operand_& op) noexcept;
//! Set return at `i` to `op`.
ASMJIT_API bool _setRet(uint32_t i, const Operand_& op) noexcept;
//! Set argument at `i` to `reg`.
ASMJIT_INLINE bool setArg(uint32_t i, const Reg& reg) noexcept { return _setArg(i, reg); }
//! Set argument at `i` to `imm`.
ASMJIT_INLINE bool setArg(uint32_t i, const Imm& imm) noexcept { return _setArg(i, imm); }
//! Set return at `i` to `var`.
ASMJIT_INLINE bool setRet(uint32_t i, const Reg& reg) noexcept { return _setRet(i, reg); }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
FuncDetail _funcDetail; //!< Function detail.
Operand_ _ret[2]; //!< Return.
Operand_* _args; //!< Arguments.
};
// ============================================================================
// [asmjit::CCPushArg]
// ============================================================================
//! Push argument before a function call (CodeCompiler).
class CCPushArg : public CBNode {
public:
ASMJIT_NONCOPYABLE(CCPushArg)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CCPushArg` instance.
ASMJIT_INLINE CCPushArg(CodeBuilder* cb, CCFuncCall* call, VirtReg* src, VirtReg* cvt) noexcept
: CBNode(cb, kNodePushArg),
_call(call),
_src(src),
_cvt(cvt),
_args(0) {
orFlags(kFlagIsRemovable);
}
//! Destroy the `CCPushArg` instance.
ASMJIT_INLINE ~CCPushArg() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the associated function-call.
ASMJIT_INLINE CCFuncCall* getCall() const noexcept { return _call; }
//! Get source variable.
ASMJIT_INLINE VirtReg* getSrcReg() const noexcept { return _src; }
//! Get conversion variable.
ASMJIT_INLINE VirtReg* getCvtReg() const noexcept { return _cvt; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CCFuncCall* _call; //!< Associated `CCFuncCall`.
VirtReg* _src; //!< Source variable.
VirtReg* _cvt; //!< Temporary variable used for conversion (or null).
uint32_t _args; //!< Affected arguments bit-array.
};
// ============================================================================
// [asmjit::CodeCompiler]
// ============================================================================
//! Code emitter that uses virtual registers and performs register allocation.
//!
//! Compiler is a high-level code-generation tool that provides register
//! allocation and automatic handling of function calling conventions. It was
//! primarily designed for merging multiple parts of code into a function
//! without worrying about registers and function calling conventions.
//!
//! CodeCompiler can be used, with a minimum effort, to handle 32-bit and 64-bit
//! code at the same time.
//!
//! CodeCompiler is based on CodeBuilder and contains all the features it
//! provides. It means that the code it stores can be modified (removed, added,
//! injected) and analyzed. When the code is finalized the compiler can emit
//! the code into an Assembler to translate the abstract representation into a
//! machine code.
class ASMJIT_VIRTAPI CodeCompiler : public CodeBuilder {
public:
ASMJIT_NONCOPYABLE(CodeCompiler)
typedef CodeBuilder Base;
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `CodeCompiler` instance.
ASMJIT_API CodeCompiler() noexcept;
//! Destroy the `CodeCompiler` instance.
ASMJIT_API virtual ~CodeCompiler() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
ASMJIT_API virtual Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API virtual Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Node-Factory]
// --------------------------------------------------------------------------
//! \internal
//!
//! Create a new `CCHint`.
ASMJIT_API CCHint* newHintNode(Reg& reg, uint32_t hint, uint32_t value) noexcept;
// --------------------------------------------------------------------------
// [Func]
// --------------------------------------------------------------------------
//! Get the current function.
ASMJIT_INLINE CCFunc* getFunc() const noexcept { return _func; }
//! Create a new `CCFunc`.
ASMJIT_API CCFunc* newFunc(const FuncSignature& sign) noexcept;
//! Add a function `node` to the stream.
ASMJIT_API CCFunc* addFunc(CCFunc* func);
//! Add a new function.
ASMJIT_API CCFunc* addFunc(const FuncSignature& sign);
//! Emit a sentinel that marks the end of the current function.
ASMJIT_API CBSentinel* endFunc();
// --------------------------------------------------------------------------
// [Ret]
// --------------------------------------------------------------------------
//! Create a new `CCFuncRet`.
ASMJIT_API CCFuncRet* newRet(const Operand_& o0, const Operand_& o1) noexcept;
//! Add a new `CCFuncRet`.
ASMJIT_API CCFuncRet* addRet(const Operand_& o0, const Operand_& o1) noexcept;
// --------------------------------------------------------------------------
// [Call]
// --------------------------------------------------------------------------
//! Create a new `CCFuncCall`.
ASMJIT_API CCFuncCall* newCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
//! Add a new `CCFuncCall`.
ASMJIT_API CCFuncCall* addCall(uint32_t instId, const Operand_& o0, const FuncSignature& sign) noexcept;
// --------------------------------------------------------------------------
// [Args]
// --------------------------------------------------------------------------
//! Set a function argument at `argIndex` to `reg`.
ASMJIT_API Error setArg(uint32_t argIndex, const Reg& reg);
// --------------------------------------------------------------------------
// [Hint]
// --------------------------------------------------------------------------
//! Emit a new hint (purely informational node).
ASMJIT_API Error _hint(Reg& reg, uint32_t hint, uint32_t value);
// --------------------------------------------------------------------------
// [VirtReg / Stack]
// --------------------------------------------------------------------------
//! Create a new virtual register representing the given `vti` and `signature`.
//!
//! This function accepts either register type representing a machine-specific
//! register, like `X86Reg`, or RegTag representation, which represents
//! machine independent register, and from the machine-specific register
//! is deduced.
ASMJIT_API VirtReg* newVirtReg(uint32_t typeId, uint32_t signature, const char* name) noexcept;
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* name);
ASMJIT_API Error _newReg(Reg& out, uint32_t typeId, const char* nameFmt, va_list ap);
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* name);
ASMJIT_API Error _newReg(Reg& out, const Reg& ref, const char* nameFmt, va_list ap);
ASMJIT_API Error _newStack(Mem& out, uint32_t size, uint32_t alignment, const char* name);
ASMJIT_API Error _newConst(Mem& out, uint32_t scope, const void* data, size_t size);
// --------------------------------------------------------------------------
// [VirtReg]
// --------------------------------------------------------------------------
//! Get whether the virtual register `r` is valid.
ASMJIT_INLINE bool isVirtRegValid(const Reg& reg) const noexcept {
return isVirtRegValid(reg.getId());
}
//! \overload
ASMJIT_INLINE bool isVirtRegValid(uint32_t id) const noexcept {
size_t index = Operand::unpackId(id);
return index < _vRegArray.getLength();
}
//! Get \ref VirtReg associated with the given `r`.
ASMJIT_INLINE VirtReg* getVirtReg(const Reg& reg) const noexcept {
return getVirtRegById(reg.getId());
}
//! Get \ref VirtReg associated with the given `id`.
ASMJIT_INLINE VirtReg* getVirtRegById(uint32_t id) const noexcept {
ASMJIT_ASSERT(id != kInvalidValue);
size_t index = Operand::unpackId(id);
ASMJIT_ASSERT(index < _vRegArray.getLength());
return _vRegArray[index];
}
//! Get an array of all virtual registers managed by CodeCompiler.
ASMJIT_INLINE const ZoneVector<VirtReg*>& getVirtRegArray() const noexcept { return _vRegArray; }
//! Alloc a virtual register `reg`.
ASMJIT_API Error alloc(Reg& reg);
//! Alloc a virtual register `reg` using `physId` as a register id.
ASMJIT_API Error alloc(Reg& reg, uint32_t physId);
//! Alloc a virtual register `reg` using `ref` as a register operand.
ASMJIT_API Error alloc(Reg& reg, const Reg& ref);
//! Spill a virtual register `reg`.
ASMJIT_API Error spill(Reg& reg);
//! Save a virtual register `reg` if the status is `modified` at this point.
ASMJIT_API Error save(Reg& reg);
//! Unuse a virtual register `reg`.
ASMJIT_API Error unuse(Reg& reg);
//! Get priority of a virtual register `reg`.
ASMJIT_API uint32_t getPriority(Reg& reg) const;
//! Set priority of variable `reg` to `priority`.
ASMJIT_API void setPriority(Reg& reg, uint32_t priority);
//! Get save-on-unuse `reg` property.
ASMJIT_API bool getSaveOnUnuse(Reg& reg) const;
//! Set save-on-unuse `reg` property to `value`.
ASMJIT_API void setSaveOnUnuse(Reg& reg, bool value);
//! Rename variable `reg` to `name`.
//!
//! NOTE: Only new name will appear in the logger.
ASMJIT_API void rename(Reg& reg, const char* fmt, ...);
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CCFunc* _func; //!< Current function.
Zone _vRegZone; //!< Allocates \ref VirtReg objects.
ZoneVector<VirtReg*> _vRegArray; //!< Stores array of \ref VirtReg pointers.
CBConstPool* _localConstPool; //!< Local constant pool, flushed at the end of each function.
CBConstPool* _globalConstPool; //!< Global constant pool, flushed at the end of the compilation.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_CODECOMPILER_H
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Export]
#define ASMJIT_EXPORTS
// [Dependencies]
#include "../base/assembler.h"
#include "../base/utils.h"
#include "../base/vmem.h"
#if defined(ASMJIT_BUILD_X86)
#include "../x86/x86inst.h"
#endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM)
#include "../arm/arminst.h"
#endif // ASMJIT_BUILD_ARM
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
// ============================================================================
// [asmjit::CodeEmitter - Construction / Destruction]
// ============================================================================
CodeEmitter::CodeEmitter(uint32_t type) noexcept
: _codeInfo(),
_code(nullptr),
_nextEmitter(nullptr),
_type(static_cast<uint8_t>(type)),
_destroyed(false),
_finalized(false),
_reserved(false),
_lastError(kErrorNotInitialized),
_privateData(0),
_globalHints(0),
_globalOptions(kOptionMaybeFailureCase),
_options(0),
_extraReg(),
_inlineComment(nullptr),
_none(),
_nativeGpReg(),
_nativeGpArray(nullptr) {}
CodeEmitter::~CodeEmitter() noexcept {
if (_code) {
_destroyed = true;
_code->detach(this);
}
}
// ============================================================================
// [asmjit::CodeEmitter - Events]
// ============================================================================
Error CodeEmitter::onAttach(CodeHolder* code) noexcept {
_codeInfo = code->getCodeInfo();
_lastError = kErrorOk;
_globalHints = code->getGlobalHints();
_globalOptions = code->getGlobalOptions();
return kErrorOk;
}
Error CodeEmitter::onDetach(CodeHolder* code) noexcept {
_codeInfo.reset();
_finalized = false;
_lastError = kErrorNotInitialized;
_privateData = 0;
_globalHints = 0;
_globalOptions = kOptionMaybeFailureCase;
_options = 0;
_extraReg.reset();
_inlineComment = nullptr;
_nativeGpReg.reset();
_nativeGpArray = nullptr;
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeEmitter - Code-Generation]
// ============================================================================
Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none);
case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================
// [asmjit::CodeEmitter - Finalize]
// ============================================================================
Label CodeEmitter::getLabelByName(const char* name, size_t nameLength, uint32_t parentId) noexcept {
return Label(_code ? _code->getLabelIdByName(name, nameLength, parentId) : static_cast<uint32_t>(0));
}
// ============================================================================
// [asmjit::CodeEmitter - Finalize]
// ============================================================================
Error CodeEmitter::finalize() {
// Finalization does nothing by default, overridden by `CodeBuilder`.
return kErrorOk;
}
// ============================================================================
// [asmjit::CodeEmitter - Error Handling]
// ============================================================================
Error CodeEmitter::setLastError(Error error, const char* message) {
// This is fatal, CodeEmitter can't set error without being attached to `CodeHolder`.
ASMJIT_ASSERT(_code != nullptr);
// Special case used to reset the last error.
if (error == kErrorOk) {
_lastError = kErrorOk;
_globalOptions &= ~kOptionMaybeFailureCase;
return kErrorOk;
}
if (!message)
message = DebugUtils::errorAsString(error);
// Logging is skipped if the error is handled by `ErrorHandler`.
ErrorHandler* handler = _code->_errorHandler;
if (handler && handler->handleError(error, message, this))
return error;
// The handler->handleError() function may throw an exception or longjmp()
// to terminate the execution of `setLastError()`. This is the reason why
// we have delayed changing the `_error` member until now.
_lastError = error;
_globalOptions |= kOptionMaybeFailureCase;
return error;
}
// ============================================================================
// [asmjit::CodeEmitter - Helpers]
// ============================================================================
bool CodeEmitter::isLabelValid(uint32_t id) const noexcept {
size_t index = Operand::unpackId(id);
return _code && index < _code->_labels.getLength();
}
Error CodeEmitter::commentf(const char* fmt, ...) {
Error err = _lastError;
if (err) return err;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled) {
va_list ap;
va_start(ap, fmt);
err = _code->_logger->logv(fmt, ap);
va_end(ap);
}
#else
ASMJIT_UNUSED(fmt);
#endif
return err;
}
Error CodeEmitter::commentv(const char* fmt, va_list ap) {
Error err = _lastError;
if (err) return err;
#if !defined(ASMJIT_DISABLE_LOGGING)
if (_globalOptions & kOptionLoggingEnabled)
err = _code->_logger->logv(fmt, ap);
#else
ASMJIT_UNUSED(fmt);
ASMJIT_UNUSED(ap);
#endif
return err;
}
// ============================================================================
// [asmjit::CodeEmitter - Emit]
// ============================================================================
#define OP const Operand_&
Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); }
Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
#undef OP
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_CODEEMITTER_H
#define _ASMJIT_BASE_CODEEMITTER_H
// [Dependencies]
#include "../base/arch.h"
#include "../base/codeholder.h"
#include "../base/operand.h"
// [Api-Begin]
#include "../asmjit_apibegin.h"
namespace asmjit {
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [Forward Declarations]
// ============================================================================
class ConstPool;
// ============================================================================
// [asmjit::CodeEmitter]
// ============================================================================
//! Provides a base foundation to emit code - specialized by \ref Assembler and
//! \ref CodeBuilder.
class ASMJIT_VIRTAPI CodeEmitter {
public:
//! CodeEmitter type.
ASMJIT_ENUM(Type) {
kTypeNone = 0,
kTypeAssembler = 1,
kTypeBuilder = 2,
kTypeCompiler = 3,
kTypeCount = 4
};
//! CodeEmitter hints - global settings that affect machine-code generation.
ASMJIT_ENUM(Hints) {
//! Emit optimized code-alignment sequences.
//!
//! Default `true`.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Default align sequence used by X86/X64 architecture is one-byte (0x90)
//! opcode that is often shown by disassemblers as nop. However there are
//! more optimized align sequences for 2-11 bytes that may execute faster.
//! If this feature is enabled AsmJit will generate specialized sequences
//! for alignment between 2 to 11 bytes.
kHintOptimizedAlign = 0x00000001U,
//! Emit jump-prediction hints.
//!
//! Default `false`.
//!
//! X86/X64 Specific
//! ----------------
//!
//! Jump prediction is usually based on the direction of the jump. If the
//! jump is backward it is usually predicted as taken; and if the jump is
//! forward it is usually predicted as not-taken. The reason is that loops
//! generally use backward jumps and conditions usually use forward jumps.
//! However this behavior can be overridden by using instruction prefixes.
//! If this option is enabled these hints will be emitted.
//!
//! This feature is disabled by default, because the only processor that
//! used to take into consideration prediction hints was P4. Newer processors
//! implement heuristics for branch prediction that ignores any static hints.
kHintPredictedJumps = 0x00000002U
};
//! CodeEmitter options that are merged with instruction options.
ASMJIT_ENUM(Options) {
//! Reserved, used to check for errors in `Assembler::_emit()`. In addition,
//! if an emitter is in error state it will have `kOptionMaybeFailureCase`
//! set
kOptionMaybeFailureCase = 0x00000001U,
//! Perform a strict validation before the instruction is emitted.
kOptionStrictValidation = 0x00000002U,
//! Logging is enabled and `CodeHolder::getLogger()` should return a valid
//! \ref Logger pointer.
kOptionLoggingEnabled = 0x00000004U,
//! Mask of all internal options that are not used to represent instruction
//! options, but are used to instrument Assembler and CodeBuilder. These
//! options are internal and should not be used outside of AsmJit itself.
//!
//! NOTE: Reserved options should never appear in `CBInst` options.
kOptionReservedMask = 0x00000007U,
//! Used only by Assembler to mark `_op4` and `_op5` are used.
kOptionOp4Op5Used = 0x00000008U,
//! Prevents following a jump during compilation (CodeCompiler).
kOptionUnfollow = 0x00000010U,
//! Overwrite the destination operand (CodeCompiler).
//!
//! Hint that is important for register liveness analysis. It tells the
//! compiler that the destination operand will be overwritten now or by
//! adjacent instructions. CodeCompiler knows when a register is completely
//! overwritten by a single instruction, for example you don't have to
//! mark "movaps" or "pxor x, x", however, if a pair of instructions is
//! used and the first of them doesn't completely overwrite the content
//! of the destination, CodeCompiler fails to mark that register as dead.
//!
//! X86/X64 Specific
//! ----------------
//!
//! - All instructions that always overwrite at least the size of the
//! register the virtual-register uses , for example "mov", "movq",
//! "movaps" don't need the overwrite option to be used - conversion,
//! shuffle, and other miscellaneous instructions included.
//!
//! - All instructions that clear the destination register if all operands
//! are the same, for example "xor x, x", "pcmpeqb x x", etc...
//!
//! - Consecutive instructions that partially overwrite the variable until
//! there is no old content require the `overwrite()` to be used. Some
//! examples (not always the best use cases thought):
//!
//! - `movlps xmm0, ?` followed by `movhps xmm0, ?` and vice versa
//! - `movlpd xmm0, ?` followed by `movhpd xmm0, ?` and vice versa
//! - `mov al, ?` followed by `and ax, 0xFF`
//! - `mov al, ?` followed by `mov ah, al`
//! - `pinsrq xmm0, ?, 0` followed by `pinsrq xmm0, ?, 1`
//!
//! - If allocated variable is used temporarily for scalar operations. For
//! example if you allocate a full vector like `X86Compiler::newXmm()`
//! and then use that vector for scalar operations you should use
//! `overwrite()` directive:
//!
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use
//! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`.
kOptionOverwrite = 0x00000020U
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_API CodeEmitter(uint32_t type) noexcept;
ASMJIT_API virtual ~CodeEmitter() noexcept;
// --------------------------------------------------------------------------
// [Events]
// --------------------------------------------------------------------------
//! Called after the \ref CodeEmitter was attached to the \ref CodeHolder.
virtual Error onAttach(CodeHolder* code) noexcept = 0;
//! Called after the \ref CodeEmitter was detached from the \ref CodeHolder.
virtual Error onDetach(CodeHolder* code) noexcept = 0;
// --------------------------------------------------------------------------
// [Code-Generation]
// --------------------------------------------------------------------------
//! Emit instruction having max 4 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0;
//! Emit instruction having max 6 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0;
//! Emit instruction having operands stored in array.
virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount);
//! Create a new label.
virtual Label newLabel() = 0;
//! Create a new named label.
virtual Label newNamedLabel(
const char* name,
size_t nameLength = Globals::kInvalidIndex,
uint32_t type = Label::kTypeGlobal,
uint32_t parentId = 0) = 0;
//! Get a label by name.
//!
//! Returns invalid Label in case that the name is invalid or label was not found.
//!
//! NOTE: This function doesn't trigger ErrorHandler in case the name is
//! invalid or no such label exist. You must always check the validity of the
//! \ref Label returned.
ASMJIT_API Label getLabelByName(
const char* name,
size_t nameLength = Globals::kInvalidIndex,
uint32_t parentId = 0) noexcept;
//! Bind the `label` to the current position of the current section.
//!
//! NOTE: Attempt to bind the same label multiple times will return an error.
virtual Error bind(const Label& label) = 0;
//! Align to the `alignment` specified.
//!
//! The sequence that is used to fill the gap between the aligned location
//! and the current location depends on the align `mode`, see \ref AlignMode.
virtual Error align(uint32_t mode, uint32_t alignment) = 0;
//! Embed raw data into the code-buffer.
virtual Error embed(const void* data, uint32_t size) = 0;
//! Embed absolute label address as data (4 or 8 bytes).
virtual Error embedLabel(const Label& label) = 0;
//! Embed a constant pool into the code-buffer in the following steps:
//! 1. Align by using kAlignData to the minimum `pool` alignment.
//! 2. Bind `label` so it's bound to an aligned location.
//! 3. Emit constant pool data.
virtual Error embedConstPool(const Label& label, const ConstPool& pool) = 0;
//! Emit a comment string `s` with an optional `len` parameter.
virtual Error comment(const char* s, size_t len = Globals::kInvalidIndex) = 0;
// --------------------------------------------------------------------------
// [Code-Generation Status]
// --------------------------------------------------------------------------
//! Get if the CodeEmitter is initialized (i.e. attached to a \ref CodeHolder).
ASMJIT_INLINE bool isInitialized() const noexcept { return _code != nullptr; }
ASMJIT_API virtual Error finalize();
// --------------------------------------------------------------------------
// [Code Information]
// --------------------------------------------------------------------------
//! Get information about the code, see \ref CodeInfo.
ASMJIT_INLINE const CodeInfo& getCodeInfo() const noexcept { return _codeInfo; }
//! Get \ref CodeHolder this CodeEmitter is attached to.
ASMJIT_INLINE CodeHolder* getCode() const noexcept { return _code; }
//! Get information about the architecture, see \ref ArchInfo.
ASMJIT_INLINE const ArchInfo& getArchInfo() const noexcept { return _codeInfo.getArchInfo(); }
//! Get if the target architecture is 32-bit.
ASMJIT_INLINE bool is32Bit() const noexcept { return getArchInfo().is32Bit(); }
//! Get if the target architecture is 64-bit.
ASMJIT_INLINE bool is64Bit() const noexcept { return getArchInfo().is64Bit(); }
//! Get the target architecture type.
ASMJIT_INLINE uint32_t getArchType() const noexcept { return getArchInfo().getType(); }
//! Get the target architecture sub-type.
ASMJIT_INLINE uint32_t getArchSubType() const noexcept { return getArchInfo().getSubType(); }
//! Get the target architecture's GP register size (4 or 8 bytes).
ASMJIT_INLINE uint32_t getGpSize() const noexcept { return getArchInfo().getGpSize(); }
//! Get the number of target GP registers.
ASMJIT_INLINE uint32_t getGpCount() const noexcept { return getArchInfo().getGpCount(); }
// --------------------------------------------------------------------------
// [Code-Emitter Type]
// --------------------------------------------------------------------------
//! Get the type of this CodeEmitter, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
ASMJIT_INLINE bool isAssembler() const noexcept { return _type == kTypeAssembler; }
ASMJIT_INLINE bool isCodeBuilder() const noexcept { return _type == kTypeBuilder; }
ASMJIT_INLINE bool isCodeCompiler() const noexcept { return _type == kTypeCompiler; }
// --------------------------------------------------------------------------
// [Global Information]
// --------------------------------------------------------------------------
//! Get global hints.
ASMJIT_INLINE uint32_t getGlobalHints() const noexcept { return _globalHints; }
//! Get global options.
//!
//! Global options are merged with instruction options before the instruction
//! is encoded. These options have some bits reserved that are used for error
//! checking, logging, and strict validation. Other options are globals that
//! affect each instruction, for example if VEX3 is set globally, it will all
//! instructions, even those that don't have such option set.
ASMJIT_INLINE uint32_t getGlobalOptions() const noexcept { return _globalOptions; }
// --------------------------------------------------------------------------
// [Error Handling]
// --------------------------------------------------------------------------
//! Get if the object is in error state.
//!
//! Error state means that it does not consume anything unless the error
//! state is reset by calling `resetLastError()`. Use `getLastError()` to
//! get the last error that put the object into the error state.
ASMJIT_INLINE bool isInErrorState() const noexcept { return _lastError != kErrorOk; }
//! Get the last error code.
ASMJIT_INLINE Error getLastError() const noexcept { return _lastError; }
//! Set the last error code and propagate it through the error handler.
ASMJIT_API Error setLastError(Error error, const char* message = nullptr);
//! Clear the last error code and return `kErrorOk`.
ASMJIT_INLINE Error resetLastError() noexcept { return setLastError(kErrorOk); }
// --------------------------------------------------------------------------
// [Accessors That Affect the Next Instruction]
// --------------------------------------------------------------------------
//! Get options of the next instruction.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _options; }
//! Set options of the next instruction.
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _options = options; }
//! Add options of the next instruction.
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _options |= options; }
//! Reset options of the next instruction.
ASMJIT_INLINE void resetOptions() noexcept { _options = 0; }
//! Get if the extra register operand is valid.
ASMJIT_INLINE bool hasExtraReg() const noexcept { return _extraReg.isValid(); }
//! Get an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE const RegOnly& getExtraReg() const noexcept { return _extraReg; }
//! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void setExtraReg(const Reg& reg) noexcept { _extraReg.init(reg); }
//! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void setExtraReg(const RegOnly& reg) noexcept { _extraReg.init(reg); }
//! Reset an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void resetExtraReg() noexcept { _extraReg.reset(); }
//! Get annotation of the next instruction.
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
//! Set annotation of the next instruction.
//!
//! NOTE: This string is set back to null by `_emit()`, but until that it has
//! to remain valid as `CodeEmitter` is not required to make a copy of it (and
//! it would be slow to do that for each instruction).
ASMJIT_INLINE void setInlineComment(const char* s) noexcept { _inlineComment = s; }
//! Reset annotation of the next instruction to null.
ASMJIT_INLINE void resetInlineComment() noexcept { _inlineComment = nullptr; }
// --------------------------------------------------------------------------
// [Helpers]
// --------------------------------------------------------------------------
//! Get if the `label` is valid (i.e. registered).
ASMJIT_INLINE bool isLabelValid(const Label& label) const noexcept {
return isLabelValid(label.getId());
}
//! Get if the label `id` is valid (i.e. registered).
ASMJIT_API bool isLabelValid(uint32_t id) const noexcept;
//! Emit a formatted string `fmt`.
ASMJIT_API Error commentf(const char* fmt, ...);
//! Emit a formatted string `fmt` (va_list version).
ASMJIT_API Error commentv(const char* fmt, va_list ap);
// --------------------------------------------------------------------------
// [Emit]
// --------------------------------------------------------------------------
// NOTE: These `emit()` helpers are designed to address a code-bloat generated
// by C++ compilers to call a function having many arguments. Each parameter to
// `_emit()` requires code to pass it, which means that if we default to 4
// operand parameters in `_emit()` and instId the C++ compiler would have to
// generate a virtual function call having 5 parameters, which is quite a lot.
// Since by default asm instructions have 2 to 3 operands it's better to
// introduce helpers that pass those and fill all the remaining with `_none`.
//! Emit an instruction.
ASMJIT_API Error emit(uint32_t instId);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
//! Emit an instruction that has a 32-bit signed immediate operand.
ASMJIT_API Error emit(uint32_t instId, int o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int o5);
//! Emit an instruction that has a 64-bit signed immediate operand.
ASMJIT_API Error emit(uint32_t instId, int64_t o0);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, int64_t o1);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, int64_t o2);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, int64_t o3);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, int64_t o4);
//! \overload
ASMJIT_API Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, int64_t o5);
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, unsigned int o0) {
return emit(instId, static_cast<int64_t>(o0));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, unsigned int o1) {
return emit(instId, o0, static_cast<int64_t>(o1));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, unsigned int o2) {
return emit(instId, o0, o1, static_cast<int64_t>(o2));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, unsigned int o3) {
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, unsigned int o4) {
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, unsigned int o5) {
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, uint64_t o0) {
return emit(instId, static_cast<int64_t>(o0));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, uint64_t o1) {
return emit(instId, o0, static_cast<int64_t>(o1));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, uint64_t o2) {
return emit(instId, o0, o1, static_cast<int64_t>(o2));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, uint64_t o3) {
return emit(instId, o0, o1, o2, static_cast<int64_t>(o3));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, uint64_t o4) {
return emit(instId, o0, o1, o2, o3, static_cast<int64_t>(o4));
}
//! \overload
ASMJIT_INLINE Error emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, uint64_t o5) {
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
}
ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
return _emitOpArray(instId, opArray, opCount);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
CodeInfo _codeInfo; //!< Basic information about the code (matches CodeHolder::_codeInfo).
CodeHolder* _code; //!< CodeHolder the CodeEmitter is attached to.
CodeEmitter* _nextEmitter; //!< Linked list of `CodeEmitter`s attached to the same \ref CodeHolder.
uint8_t _type; //!< See CodeEmitter::Type.
uint8_t _destroyed; //!< Set by ~CodeEmitter() before calling `_code->detach()`.
uint8_t _finalized; //!< True if the CodeEmitter is finalized (CodeBuilder & CodeCompiler).
uint8_t _reserved; //!< \internal
Error _lastError; //!< Last error code.
uint32_t _privateData; //!< Internal private data used freely by any CodeEmitter.
uint32_t _globalHints; //!< Global hints, always in sync with CodeHolder.
uint32_t _globalOptions; //!< Global options, combined with `_options` before used by each instruction.
uint32_t _options; //!< Used to pass instruction options (affects the next instruction).
RegOnly _extraReg; //!< Extra register (op-mask {k} on AVX-512) (affects the next instruction).
const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction).
Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null.
Reg _nativeGpReg; //!< Native GP register with zero id.
const Reg* _nativeGpArray; //!< Array of native registers indexed from zero.
};
//! \}
} // asmjit namespace
// [Api-End]
#include "../asmjit_apiend.h"
// [Guard]
#endif // _ASMJIT_BASE_CODEEMITTER_H
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment