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)
SET(OPENMM_LIBRARY_NAME OpenMM)
SET(OPENMM_MAJOR_VERSION 7)
SET(OPENMM_MINOR_VERSION 3)
SET(OPENMM_MINOR_VERSION 4)
SET(OPENMM_BUILD_VERSION 0)
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
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
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
where *f*\ (\ *...*\ ) is a user defined mathematical expression. It may
depend on an arbitrary set of positions {\ :math:`x_i`\ }, distances {\ :math:`r_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
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), /
(divide), and ^ (power). Parentheses “(“ and “)” may be used for grouping.
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.
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.
......
# Generate and install examples.
#
# This is boilerplate code for generating a set of executables, one per
# .cpp file in an "examples" subdirectory.
#
# For IDEs that can deal with PROJECT_LABEL properties (at least
# Visual Studio) the projects for building each of these adhoc
# executables will be labeled "Example - TheExampleName" if a file
# TheExampleName.cpp is found in this directory.
#
# We check the BUILD_TESTING_{SHARED,STATIC} variables to determine
# whether to build dynamically linked, statically linked, or both
# versions of the executable.
SET(OpenMM_CWRAPPER "OpenMMCWrapper")
SET(OpenMM_FWRAPPER "OpenMMFortranWrapper")
SET(OpenMM_FMODULE "OpenMMFortranModule")
SET(CPP_EXAMPLES HelloArgon HelloSodiumChloride HelloEthane HelloWaterBox)
SET(C_EXAMPLES HelloArgonInC HelloSodiumChlorideInC)
SET(F_EXAMPLES HelloArgonInFortran HelloSodiumChlorideInFortran)
FOREACH(EX_ROOT ${CPP_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES
PROJECT_LABEL "Example - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library
SET(EX_STATIC ${EX_ROOT}Static)
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES
PROJECT_LABEL "Example - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ENDIF (OPENMM_BUILD_STATIC_LIB)
INSTALL(FILES ${EX_ROOT}.cpp DESTINATION examples)
ENDFOREACH(EX_ROOT ${CPP_EXAMPLES})
# Only build wrapper examples if wrappers have been built
IF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}/wrappers)
FOREACH(EX_ROOT ${C_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library
# We need at least one .cpp here to get CMake to include
# C++ libraries on the link line.
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES
PROJECT_LABEL "Example C - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ADD_DEPENDENCIES(${EX_ROOT} ApiWrappers)
ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library
SET(EX_STATIC ${EX_ROOT}Static)
# We need at least one .cpp here to get CMake to include
# C++ libraries on the static link line.
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES
PROJECT_LABEL "Example C - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ADD_DEPENDENCIES(${EX_STATIC} ApiWrappers)
ENDIF (OPENMM_BUILD_STATIC_LIB)
ENDFOREACH(EX_ROOT ${C_EXAMPLES})
ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
FOREACH(EX_ROOT ${C_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.c DESTINATION examples)
ENDFOREACH(EX_ROOT ${C_EXAMPLES})
FOREACH(EX_ROOT ${F_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.f90 DESTINATION 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
DESTINATION examples)
INSTALL(FILES VisualStudio/HelloArgon.vcproj
VisualStudio/HelloArgon.sln
VisualStudio/HelloArgonInC.sln
VisualStudio/HelloArgonInC.vcproj
VisualStudio/HelloArgonInFortran.sln
VisualStudio/HelloArgonInFortran.vfproj
DESTINATION examples/VisualStudio)
INSTALL(FILES README.txt DESTINATION examples)
INSTALL(FILES Makefile NMakefile DESTINATION examples)
INSTALL(FILES MakefileNotes.txt Empty.cpp DESTINATION examples)
# Generate and install examples.
#
# This is boilerplate code for generating a set of executables, one per
# .cpp file in an "examples" subdirectory.
#
# For IDEs that can deal with PROJECT_LABEL properties (at least
# Visual Studio) the projects for building each of these adhoc
# executables will be labeled "Example - TheExampleName" if a file
# TheExampleName.cpp is found in this directory.
#
# We check the BUILD_TESTING_{SHARED,STATIC} variables to determine
# whether to build dynamically linked, statically linked, or both
# versions of the executable.
SET(OpenMM_CWRAPPER "OpenMMCWrapper")
SET(OpenMM_FWRAPPER "OpenMMFortranWrapper")
SET(OpenMM_FMODULE "OpenMMFortranModule")
SET(CPP_EXAMPLES HelloArgon HelloSodiumChloride HelloEthane HelloWaterBox)
SET(C_EXAMPLES HelloArgonInC HelloSodiumChlorideInC)
SET(F_EXAMPLES HelloArgonInFortran HelloSodiumChlorideInFortran)
FOREACH(EX_ROOT ${CPP_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES
PROJECT_LABEL "Example - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library
SET(EX_STATIC ${EX_ROOT}Static)
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES
PROJECT_LABEL "Example - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ENDIF (OPENMM_BUILD_STATIC_LIB)
INSTALL(FILES ${EX_ROOT}.cpp DESTINATION examples)
ENDFOREACH(EX_ROOT ${CPP_EXAMPLES})
# Only build wrapper examples if wrappers have been built
IF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
INCLUDE_DIRECTORIES(BEFORE ${PROJECT_BINARY_DIR}/wrappers)
FOREACH(EX_ROOT ${C_EXAMPLES})
IF (OPENMM_BUILD_SHARED_LIB)
# Link with shared library
# We need at least one .cpp here to get CMake to include
# C++ libraries on the link line.
ADD_EXECUTABLE(${EX_ROOT} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_ROOT}
PROPERTIES
PROJECT_LABEL "Example C - ${EX_ROOT}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS}")
TARGET_LINK_LIBRARIES(${EX_ROOT} ${SHARED_TARGET})
ADD_DEPENDENCIES(${EX_ROOT} ApiWrappers)
ENDIF (OPENMM_BUILD_SHARED_LIB)
IF (OPENMM_BUILD_STATIC_LIB)
# Link with static library
SET(EX_STATIC ${EX_ROOT}Static)
# We need at least one .cpp here to get CMake to include
# C++ libraries on the static link line.
ADD_EXECUTABLE(${EX_STATIC} ${EX_ROOT}.c Empty.cpp)
SET_TARGET_PROPERTIES(${EX_STATIC}
PROPERTIES
PROJECT_LABEL "Example C - ${EX_STATIC}"
LINK_FLAGS "${EXTRA_LINK_FLAGS}"
COMPILE_FLAGS "${EXTRA_COMPILE_FLAGS} -DOPENMM_USE_STATIC_LIBRARIES")
TARGET_LINK_LIBRARIES(${EX_STATIC} ${STATIC_TARGET})
ADD_DEPENDENCIES(${EX_STATIC} ApiWrappers)
ENDIF (OPENMM_BUILD_STATIC_LIB)
ENDFOREACH(EX_ROOT ${C_EXAMPLES})
ENDIF(OPENMM_BUILD_C_AND_FORTRAN_WRAPPERS)
FOREACH(EX_ROOT ${C_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.c DESTINATION examples)
ENDFOREACH(EX_ROOT ${C_EXAMPLES})
FOREACH(EX_ROOT ${F_EXAMPLES})
INSTALL(FILES ${EX_ROOT}.f90 DESTINATION 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 apoa1.pdb
DESTINATION examples)
INSTALL(FILES VisualStudio/HelloArgon.vcproj
VisualStudio/HelloArgon.sln
VisualStudio/HelloArgonInC.sln
VisualStudio/HelloArgonInC.vcproj
VisualStudio/HelloArgonInFortran.sln
VisualStudio/HelloArgonInFortran.vfproj
DESTINATION examples/VisualStudio)
INSTALL(FILES README.txt DESTINATION examples)
INSTALL(FILES Makefile NMakefile DESTINATION examples)
INSTALL(FILES MakefileNotes.txt Empty.cpp DESTINATION examples)
AsmJit - Complete x86/x64 JIT and Remote Assembler for C++
Copyright (c) 2008-2014, Petr Kobalicek <kobalicek.petr@gmail.com>
Copyright (c) 2008-2017, Petr Kobalicek
This software is provided 'as-is', without any express or implied
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 @@
// [asmjit_mainpage]
// ============================================================================
//! @mainpage
//! \mainpage
//!
//! AsmJit - Complete x86/x64 JIT and Remote Assembler for C++.
//!
//! AsmJit is a complete JIT and remote assembler for C++ language. It can
//! 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.
//! Introduction provided by the project page at https://github.com/asmjit/asmjit.
// ============================================================================
// [asmjit_base_compiler]
// ============================================================================
//! \defgroup asmjit_base_compiler AsmJit Compiler
//! \ingroup asmjit_base
//!
//! \brief AsmJit code-tree used by Compiler.
//! \defgroup asmjit_base AsmJit Base API (architecture independent)
//!
//! AsmJit intermediate code-tree is a double-linked list that is made of nodes
//! that represent assembler instructions, directives, labels and high-level
//! constructs compiler is using to represent functions and function calls. The
//! node list can only be used together with \ref Compiler.
//!
//! TODO
// ============================================================================
// [asmjit_base_util]
// ============================================================================
//! \brief Backend Neutral API.
//! \defgroup asmjit_base_util AsmJit Utilities
//! \ingroup asmjit_base
//!
//! \brief AsmJit utility classes.
//!
//! AsmJit contains numerous utility classes that are needed by the library
//! itself. The most useful ones have been made public and are now exported.
//! \defgroup asmjit_x86 AsmJit X86/X64 API
//!
//! POD Containers
//! --------------
//!
//! POD containers are used by AsmJit to manage its own data structures. The
//! following classes can be used by AsmJit consumers:
//!
//! - \ref PodVector - Simple growing array-like container for POD data.
//! - \ref StringBuilder - Simple string builder that can append string
//! and integers.
//!
//! Zone Memory Allocator
//! ---------------------
//!
//! Zone memory allocator is an incremental memory allocator that can be used
//! to allocate data of short life-time. It has much better performance
//! characteristics than all other allocators, because the only thing it can do
//! is to increment a pointer and return its previous address. See \ref Zone
//! for more details.
//!
//! CPU Ticks
//! ---------
//!
//! CPU Ticks is a simple helper that can be used to do basic benchmarks. See
//! \ref CpuTicks class for more details.
//!
//! Integer Utilities
//! -----------------
//!
//! Integer utilities are all implemented by a static class \ref IntUtil.
//! There are utilities for bit manipulation and bit counting, utilities to get
//! an integer minimum / maximum and various other helpers required to perform
//! alignment checks and binary casting from float to integer and vica versa.
//!
//! Vector Utilities
//! ----------------
//!
//! SIMD code generation often requires to embed constants after each function
//! or a block of functions generated. AsmJit contains classes `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]
// ============================================================================
//! \brief X86/X64 Backend API.
//! \defgroup asmjit_contrib Contributions
//! \defgroup asmjit_arm AsmJit ARM32/ARM64 API
//!
//! \brief Contributions.
//! \brief ARM32/ARM64 Backend API.
// [Dependencies - Base]
#include "base.h"
// [Dependencies]
#include "./base.h"
// [Dependencies - X86/X64]
#if defined(ASMJIT_BUILD_X86) || defined(ASMJIT_BUILD_X64)
#include "x86.h"
#endif // ASMJIT_BUILD_X86 || ASMJIT_BUILD_X64
// [X86/X64]
#if defined(ASMJIT_BUILD_X86)
#include "./x86.h"
#endif // ASMJIT_BUILD_X86
// [Dependencies - Host]
#include "host.h"
// [ARM32/ARM64]
#if defined(ASMJIT_BUILD_ARM)
#include "./arm.h"
#endif // ASMJIT_BUILD_ARM
// [Guard]
#endif // _ASMJIT_ASMJIT_H
......@@ -4,81 +4,119 @@
// [License]
// Zlib - See LICENSE.md file in the package.
// [Dependencies - AsmJit]
// [Dependencies]
#if !defined(_ASMJIT_BUILD_H)
#include "build.h"
# include "./build.h"
#endif // !_ASMJIT_BUILD_H
// [Guard]
#if !defined(ASMJIT_API_SCOPE)
# define ASMJIT_API_SCOPE
#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
// ============================================================================
// [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 ASMJIT_UNDEF_OVERRIDE
#endif // !ASMJIT_CC_HAS_OVERRIDE && !override
// ============================================================================
// [NoExcept]
// [Compiler Support]
// ============================================================================
#if !defined(ASMJIT_CC_HAS_NOEXCEPT) && !defined(noexcept)
# define noexcept ASMJIT_NOEXCEPT
# define ASMJIT_UNDEF_NOEXCEPT
#endif // !ASMJIT_CC_HAS_NOEXCEPT && !noexcept
// [Clang]
#if ASMJIT_CC_CLANG
# pragma clang diagnostic push
# 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
// ============================================================================
// [MSC]
// ============================================================================
// [GCC]
#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)
// Disable some warnings we know about
// [MSC]
#if ASMJIT_CC_MSC
# pragma warning(push)
# pragma warning(disable: 4127) // conditional expression is constant
# pragma warning(disable: 4201) // nameless struct/union
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible
// loss of data
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used
// by clients of struct ...
# pragma warning(disable: 4275) // non dll-interface struct ... used as base for
// dll-interface struct
# pragma warning(disable: 4244) // '+=' : conversion from 'int' to 'x', possible loss of data
# pragma warning(disable: 4251) // struct needs to have dll-interface to be used 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: 4480) // specifying underlying type for enum
# pragma warning(disable: 4800) // forcing value to bool 'true' or 'false'
// Rename symbols.
# if !defined(vsnprintf)
# define ASMJIT_UNDEF_VSNPRINTF
# define vsnprintf _vsnprintf
# endif // !vsnprintf
# if !defined(snprintf)
# define ASMJIT_UNDEF_SNPRINTF
# define snprintf _snprintf
# endif // !snprintf
#endif // _MSC_VER
# pragma warning(disable: 4838) // comversion from 'int' to ...
# if _MSC_VER < 1900
# if !defined(vsnprintf)
# define ASMJIT_UNDEF_VSNPRINTF
# define vsnprintf _vsnprintf
# endif // !vsnprintf
# if !defined(snprintf)
# define ASMJIT_UNDEF_SNPRINTF
# define snprintf _snprintf
# endif // !snprintf
# endif
#endif // ASMJIT_CC_MSC
// ============================================================================
// [CLang]
// [Custom Macros]
// ============================================================================
#if defined(__clang__)
# pragma clang diagnostic push
# pragma clang diagnostic ignored "-Wunnamed-type-template-args"
#endif // __clang__
// ============================================================================
// [GCC]
// ============================================================================
// [ASMJIT_NON...]
#if ASMJIT_CC_HAS_DELETE_FUNCTION
#define ASMJIT_NONCONSTRUCTIBLE(...) \
private: \
__VA_ARGS__() = delete; \
__VA_ARGS__(const __VA_ARGS__& other) = delete; \
__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__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility push(hidden)
# endif // GCC 4+
#endif // __GNUC__
// [ASMJIT_ENUM]
#if defined(_MSC_VER) && _MSC_VER >= 1400
# define ASMJIT_ENUM(NAME) enum NAME : uint32_t
#else
# define ASMJIT_ENUM(NAME) enum NAME
#endif
......@@ -8,60 +8,67 @@
#if defined(ASMJIT_API_SCOPE)
# undef ASMJIT_API_SCOPE
#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
// ============================================================================
// [Override]
// [C++ Support]
// ============================================================================
#if defined(ASMJIT_UNDEF_OVERRIDE)
# undef override
# undef ASMJIT_UNDEF_OVERRIDE
#endif // ASMJIT_UNDEF_OVERRIDE
// ============================================================================
// [NoExcept]
// ============================================================================
#if defined(ASMJIT_UNDEF_NOEXCEPT)
# undef noexcept
# undef ASMJIT_UNDEF_NOEXCEPT
#endif // ASMJIT_UNDEF_NOEXCEPT
// ============================================================================
// [MSC]
// ============================================================================
#if defined(_MSC_VER)
# 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
// [NullPtr]
#if defined(ASMJIT_UNDEF_NULLPTR)
# undef nullptr
# undef ASMJIT_UNDEF_NULLPTR
#endif // ASMJIT_UNDEF_NULLPTR
#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
#endif // __clang__
#endif // ASMJIT_CC_CLANG
// ============================================================================
// [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__)
# if __GNUC__ >= 4 && !defined(__MINGW32__)
# pragma GCC visibility pop
# endif // GCC 4+
#endif // __GNUC__
// [ASMJIT_NON...]
#undef ASMJIT_NONCONSTRUCTIBLE
#undef ASMJIT_NONCOPYABLE
// [ASMJIT_ENUM]
#undef ASMJIT_ENUM
This diff is collapsed.
......@@ -8,27 +8,27 @@
#ifndef _ASMJIT_BASE_H
#define _ASMJIT_BASE_H
// [Dependencies - AsmJit]
#include "build.h"
#include "base/assembler.h"
#include "base/codegen.h"
#include "base/compiler.h"
#include "base/constpool.h"
#include "base/containers.h"
#include "base/cpuinfo.h"
#include "base/cputicks.h"
#include "base/error.h"
#include "base/globals.h"
#include "base/intutil.h"
#include "base/lock.h"
#include "base/logger.h"
#include "base/operand.h"
#include "base/runtime.h"
#include "base/string.h"
#include "base/vectypes.h"
#include "base/vmem.h"
#include "base/zone.h"
// [Dependencies]
#include "./base/arch.h"
#include "./base/assembler.h"
#include "./base/codebuilder.h"
#include "./base/codecompiler.h"
#include "./base/codeemitter.h"
#include "./base/codeholder.h"
#include "./base/constpool.h"
#include "./base/cpuinfo.h"
#include "./base/func.h"
#include "./base/globals.h"
#include "./base/inst.h"
#include "./base/logging.h"
#include "./base/operand.h"
#include "./base/osutils.h"
#include "./base/runtime.h"
#include "./base/simdtypes.h"
#include "./base/string.h"
#include "./base/utils.h"
#include "./base/vmem.h"
#include "./base/zone.h"
// [Guard]
#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
This diff is collapsed.
This diff is collapsed.
// [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
This diff is collapsed.
// [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
This diff is collapsed.
// [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"
This diff is collapsed.
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