diff options
author | Tim Besard <tim.besard@gmail.com> | 2011-11-02 14:57:47 +0100 |
---|---|---|
committer | Tim Besard <tim.besard@gmail.com> | 2011-11-02 14:57:47 +0100 |
commit | 017f97abaf748a23314f4f52d45da454fd48591a (patch) | |
tree | edbd1f040539f0d99d275d12452bd2747d7f2e36 /lib/AsmJit/CompilerX86X64.h | |
parent | fa1c64acd5e0ad7bc9e549da09cf5be3c794b435 (diff) |
Switching to AsmJit generated chasing routines.
Diffstat (limited to 'lib/AsmJit/CompilerX86X64.h')
-rw-r--r-- | lib/AsmJit/CompilerX86X64.h | 8891 |
1 files changed, 8891 insertions, 0 deletions
diff --git a/lib/AsmJit/CompilerX86X64.h b/lib/AsmJit/CompilerX86X64.h new file mode 100644 index 0000000..ceb228d --- /dev/null +++ b/lib/AsmJit/CompilerX86X64.h @@ -0,0 +1,8891 @@ +// AsmJit - Complete JIT Assembler for C++ Language. + +// Copyright (c) 2008-2010, Petr Kobalicek <kobalicek.petr@gmail.com> +// +// Permission is hereby granted, free of charge, to any person +// obtaining a copy of this software and associated documentation +// files (the "Software"), to deal in the Software without +// restriction, including without limitation the rights to use, +// copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the +// Software is furnished to do so, subject to the following +// conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES +// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +// OTHER DEALINGS IN THE SOFTWARE. + +// [Guard] +#ifndef _ASMJIT_COMPILERX86X64_H +#define _ASMJIT_COMPILERX86X64_H + +#if !defined(_ASMJIT_COMPILER_H) +#warning "AsmJit/CompilerX86X64.h can be only included by AsmJit/Compiler.h" +#endif // _ASMJIT_COMPILER_H + +// [Dependencies] +#include "Build.h" +#include "Assembler.h" +#include "Defs.h" +#include "Operand.h" +#include "Util.h" + +#include <string.h> + +// A little bit C++. +#include <new> + +// [Api-Begin] +#include "ApiBegin.h" + +//! @internal +//! +//! @brief Mark methods not supported by @ref Compiler. These methods are +//! usually used only in function prologs/epilogs or to manage stack. +#define ASMJIT_NOT_SUPPORTED_BY_COMPILER 0 + +namespace AsmJit { + +//! @addtogroup AsmJit_Compiler +//! @{ + +// ============================================================================ +// [Forward Declarations] +// ============================================================================ + +struct CodeGenerator; + +// ============================================================================ +// [AsmJit::TypeToId] +// ============================================================================ + +// Skip documenting this. +#if !defined(ASMJIT_NODOC) + +ASMJIT_DECLARE_TYPE_AS_ID(int8_t, VARIABLE_TYPE_GPD); +ASMJIT_DECLARE_TYPE_AS_ID(uint8_t, VARIABLE_TYPE_GPD); + +ASMJIT_DECLARE_TYPE_AS_ID(int16_t, VARIABLE_TYPE_GPD); +ASMJIT_DECLARE_TYPE_AS_ID(uint16_t, VARIABLE_TYPE_GPD); + +ASMJIT_DECLARE_TYPE_AS_ID(int32_t, VARIABLE_TYPE_GPD); +ASMJIT_DECLARE_TYPE_AS_ID(uint32_t, VARIABLE_TYPE_GPD); + +#if defined(ASMJIT_X64) +ASMJIT_DECLARE_TYPE_AS_ID(int64_t, VARIABLE_TYPE_GPQ); +ASMJIT_DECLARE_TYPE_AS_ID(uint64_t, VARIABLE_TYPE_GPQ); +#endif // ASMJIT_X64 + +ASMJIT_DECLARE_TYPE_AS_ID(float, VARIABLE_TYPE_FLOAT); +ASMJIT_DECLARE_TYPE_AS_ID(double, VARIABLE_TYPE_DOUBLE); + +#endif // !ASMJIT_NODOC + +// ============================================================================ +// [AsmJit::FunctionPrototype] +// ============================================================================ + +//! @brief Calling convention and function argument handling. +struct ASMJIT_API FunctionPrototype +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref FunctionPrototype instance. + FunctionPrototype() ASMJIT_NOTHROW; + //! @brief Destroy the @ref FunctionPrototype instance. + ~FunctionPrototype() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Argument] + // -------------------------------------------------------------------------- + + //! @brief Function argument location. + struct Argument + { + //! @brief Variable type, see @c VARIABLE_TYPE. + uint32_t variableType; + //! @brief Register index if argument is passed through register, otherwise + //! @c INVALID_VALUE. + uint32_t registerIndex; + //! @brief Stack offset if argument is passed through stack, otherwise + //! @c INVALID_VALUE. + int32_t stackOffset; + + //! @brief Get whether the argument is assigned, for private use only. + inline bool isAssigned() const ASMJIT_NOTHROW + { return registerIndex != INVALID_VALUE || stackOffset != (int32_t)INVALID_VALUE; } + }; + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Set function prototype. + //! + //! This will set function calling convention and setup arguments variables. + //! + //! @note This function will allocate variables, it can be called only once. + void setPrototype( + uint32_t callingConvention, + const uint32_t* arguments, + uint32_t argumentsCount, + uint32_t returnValue) ASMJIT_NOTHROW; + + //! @brief Get function calling convention, see @c CALL_CONV. + inline uint32_t getCallingConvention() const ASMJIT_NOTHROW { return _callingConvention; } + + //! @brief Get whether the callee pops the stack. + inline uint32_t getCalleePopsStack() const ASMJIT_NOTHROW { return _calleePopsStack; } + + //! @brief Get function arguments. + inline Argument* getArguments() ASMJIT_NOTHROW { return _arguments; } + //! @brief Get function arguments (const version). + inline const Argument* getArguments() const ASMJIT_NOTHROW { return _arguments; } + + //! @brief Get count of arguments. + inline uint32_t getArgumentsCount() const ASMJIT_NOTHROW { return _argumentsCount; } + + //! @brief Get function return value or @ref INVALID_VALUE if it's void. + inline uint32_t getReturnValue() const ASMJIT_NOTHROW { return _returnValue; } + + //! @brief Get direction of arguments passed on the stack. + //! + //! Direction should be always @c ARGUMENT_DIR_RIGHT_TO_LEFT. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getArgumentsDirection() const ASMJIT_NOTHROW { return _argumentsDirection; } + + //! @brief Get stack size needed for function arguments passed on the stack. + inline uint32_t getArgumentsStackSize() const ASMJIT_NOTHROW { return _argumentsStackSize; } + + //! @brief Get registers used to pass first integer parameters by current + //! calling convention. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline const uint32_t* getArgumentsGPList() const ASMJIT_NOTHROW { return _argumentsGPList; } + + //! @brief Get registers used to pass first SP-FP or DP-FPparameters by + //! current calling convention. + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline const uint32_t* getArgumentsXMMList() const ASMJIT_NOTHROW { return _argumentsXMMList; } + + //! @brief Get bitmask of GP registers which might be used for arguments. + inline uint32_t getArgumentsGP() const ASMJIT_NOTHROW { return _argumentsGP; } + //! @brief Get bitmask of MM registers which might be used for arguments. + inline uint32_t getArgumentsMM() const ASMJIT_NOTHROW { return _argumentsMM; } + //! @brief Get bitmask of XMM registers which might be used for arguments. + inline uint32_t getArgumentsXMM() const ASMJIT_NOTHROW { return _argumentsXMM; } + + //! @brief Get bitmask of general purpose registers that's preserved + //! (non-volatile). + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getPreservedGP() const ASMJIT_NOTHROW { return _preservedGP; } + + //! @brief Get bitmask of MM registers that's preserved (non-volatile). + //! + //! @note No standardized calling function is not preserving MM registers. + //! This member is here for extension writers who need for some reason custom + //! calling convention that can be called through code generated by AsmJit + //! (or other runtime code generator). + inline uint32_t getPreservedMM() const ASMJIT_NOTHROW { return _preservedMM; } + + //! @brief Return bitmask of XMM registers that's preserved (non-volatile). + //! + //! @note This is related to used calling convention, it's not affected by + //! number of function arguments or their types. + inline uint32_t getPreservedXMM() const ASMJIT_NOTHROW { return _preservedXMM; } + + //! @brief Get mask of all GP registers used to pass function arguments. + inline uint32_t getPassedGP() const ASMJIT_NOTHROW { return _passedGP; } + //! @brief Get mask of all MM registers used to pass function arguments. + inline uint32_t getPassedMM() const ASMJIT_NOTHROW { return _passedMM; } + //! @brief Get mask of all XMM registers used to pass function arguments. + inline uint32_t getPassedXMM() const ASMJIT_NOTHROW { return _passedXMM; } + + //! @brief Find argument (id) by the register code. Used mainly by @ref ECall + //! emittable. + uint32_t findArgumentByRegisterCode(uint32_t regCode) const ASMJIT_NOTHROW; + +protected: + + // -------------------------------------------------------------------------- + // [Private] + // -------------------------------------------------------------------------- + + void _clear() ASMJIT_NOTHROW; + void _setCallingConvention(uint32_t callingConvention) ASMJIT_NOTHROW; + void _setPrototype( + const uint32_t* arguments, + uint32_t argumentsCount, + uint32_t returnValue) ASMJIT_NOTHROW; + void _setReturnValue(uint32_t valueId) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Calling convention. + uint32_t _callingConvention; + //! @brief Whether callee pops stack. + uint32_t _calleePopsStack; + + //! @brief List of arguments, their register codes or stack locations. + Argument _arguments[FUNC_MAX_ARGS]; + + //! @brief Function return value. + uint32_t _returnValue; + + //! @brief Count of arguments (in @c _argumentsList). + uint32_t _argumentsCount; + //! @brief Direction for arguments passed on the stack, see @c ARGUMENT_DIR. + uint32_t _argumentsDirection; + //! @brief Count of bytes consumed by arguments on the stack. + uint32_t _argumentsStackSize; + + //! @brief List of registers that's used for first GP arguments. + uint32_t _argumentsGPList[16]; + //! @brief List of registers that's used for first XMM arguments. + uint32_t _argumentsXMMList[16]; + + //! @brief Bitmask for preserved GP registers. + uint32_t _argumentsGP; + //! @brief Bitmask for preserved MM registers. + uint32_t _argumentsMM; + //! @brief Bitmask for preserved XMM registers. + uint32_t _argumentsXMM; + + //! @brief Bitmask for preserved GP registers. + uint32_t _preservedGP; + //! @brief Bitmask for preserved MM registers. + uint32_t _preservedMM; + //! @brief Bitmask for preserved XMM registers. + uint32_t _preservedXMM; + + // Set by _setPrototype(). + + //! @brief Bitmask for GP registers used as function arguments. + uint32_t _passedGP; + //! @brief Bitmask for GP registers used as function arguments. + uint32_t _passedMM; + //! @brief Bitmask for GP registers used as function arguments. + uint32_t _passedXMM; +}; + +// ============================================================================ +// [AsmJit::VarData] +// ============================================================================ + +//! @brief Variable data (used internally by @c Compiler). +struct VarData +{ + // -------------------------------------------------------------------------- + // [Scope] + // -------------------------------------------------------------------------- + + //! @brief Scope (NULL if variable is global). + EFunction* scope; + + //! @brief The first emittable where the variable is accessed. + //! + //! @note If this member is @c NULL then variable is unused. + Emittable* firstEmittable; + //! @brief The first callable (ECall) which is after the @c firstEmittable. + ECall* firstCallable; + //! @brief The last emittable where the variable is accessed. + Emittable* lastEmittable; + + // -------------------------------------------------------------------------- + // [Id / Name] + // -------------------------------------------------------------------------- + + //! @brief Variable name. + const char* name; + //! @brief Variable id. + uint32_t id; + //! @brief Variable type. + uint32_t type; + //! @brief Variable size. + uint32_t size; + + // -------------------------------------------------------------------------- + // [Home] + // -------------------------------------------------------------------------- + + //! @brief Home register index or @c INVALID_VALUE (used by register allocator). + uint32_t homeRegisterIndex; + //! @brief Preferred register index. + uint32_t prefRegisterMask; + + //! @brief Home memory address offset. + int32_t homeMemoryOffset; + //! @brief Used by @c CompilerContext, do not touch (NULL when created). + void* homeMemoryData; + + // -------------------------------------------------------------------------- + // [Actual] + // -------------------------------------------------------------------------- + + //! @brief Actual register index (connected with actual @c StateData). + uint32_t registerIndex; + //! @brief Actual working offset. This member is set before register allocator + //! is called. If workOffset is same as CompilerContext::_currentOffset then + //! this variable is probably used in next instruction and can't be spilled. + uint32_t workOffset; + + //! @brief Next active variable in circullar double-linked list. + VarData* nextActive; + //! @brief Previous active variable in circullar double-linked list. + VarData* prevActive; + + // -------------------------------------------------------------------------- + // [Flags] + // -------------------------------------------------------------------------- + + //! @brief Variable priority. + uint8_t priority; + //! @brief Whether variable content can be calculated by simple instruction + //! + //! This is used mainly by mmx or sse2 code and variable allocator will + //! never reserve space for this variable. Calculated variables are for + //! example all zeros, all ones, etc. + uint8_t calculated; + //! @brief Whether variable is argument passed through register. + uint8_t isRegArgument; + //! @brief Whether variable is argument passed through memory. + uint8_t isMemArgument; + + //! @brief Variable state (connected with actual @c StateData). + uint8_t state; + //! @brief Whether variable was changed (connected with actual @c StateData). + uint8_t changed; + //! @brief Save on unuse (at end of the variable scope). + uint8_t saveOnUnuse; + + // -------------------------------------------------------------------------- + // [Statistics] + // -------------------------------------------------------------------------- + + //! @brief Register read statistics (used by instructions where this variable needs + //! to be read only). + uint32_t registerReadCount; + //! @brief Register write statistics (used by instructions where this variable needs + //! to be write only). + uint32_t registerWriteCount; + //! @brief Register read+write statistics (used by instructions where this variable + //! needs to be read and write). + uint32_t registerRWCount; + + //! @brief Register GPB.LO statistics (for code generator). + uint32_t registerGPBLoCount; + //! @brief Register GPB.HI statistics (for code generator). + uint32_t registerGPBHiCount; + + //! @brief Memory read statistics. + uint32_t memoryReadCount; + //! @brief Memory write statistics. + uint32_t memoryWriteCount; + //! @brief Memory read+write statistics. + uint32_t memoryRWCount; + + // -------------------------------------------------------------------------- + // [Temporary] + // -------------------------------------------------------------------------- + + //! @brief Temporary data that can be used in prepare/translate stage. + //! + //! Initial value is NULL and each emittable/code that will use it must also + //! clear it. + //! + //! This temporary data is designed to be used by algorithms that need to + //! set some state into the variables, do something and then cleanup. See + //! state-switch and function call. + union + { + void* tempPtr; + sysint_t tempInt; + }; +}; + +// ============================================================================ +// [AsmJit::VarMemBlock] +// ============================================================================ + +struct VarMemBlock +{ + int32_t offset; + uint32_t size; + + VarMemBlock* nextUsed; + VarMemBlock* nextFree; +}; + +// ============================================================================ +// [AsmJit::VarAllocRecord] +// ============================================================================ + +//! @brief Variable alloc record (for each instruction that uses variables). +//! +//! Variable record contains pointer to variable data and register allocation +//! flags. These flags are important to determine the best alloc instruction. +struct VarAllocRecord +{ + //! @brief Variable data (the structure owned by @c Compiler). + VarData* vdata; + //! @brief Variable alloc flags, see @c VARIABLE_ALLOC. + uint32_t vflags; + //! @brief Register mask (default is 0). + uint32_t regMask; +}; + +// ============================================================================ +// [AsmJit::VarCallRecord] +// ============================================================================ + +//! @brief Variable call-fn record (for each callable that uses variables). +//! +//! This record contains variables that are used to call a function (using +//! @c ECall emittable). Each variable contains the registers where it must +//! be and registers where the value will be returned. +struct VarCallRecord +{ + //! @brief Variable data (the structure owned by @c Compiler). + VarData* vdata; + uint32_t flags; + + uint8_t inCount; + uint8_t inDone; + + uint8_t outCount; + uint8_t outDone; + + enum FLAGS + { + FLAG_IN_GP = 0x0001, + FLAG_IN_MM = 0x0002, + FLAG_IN_XMM = 0x0004, + FLAG_IN_STACK = 0x0008, + + FLAG_OUT_EAX = 0x0010, + FLAG_OUT_EDX = 0x0020, + FLAG_OUT_ST0 = 0x0040, + FLAG_OUT_ST1 = 0x0080, + FLAG_OUT_MM0 = 0x0100, + FLAG_OUT_XMM0 = 0x0400, + FLAG_OUT_XMM1 = 0x0800, + + FLAG_IN_MEM_PTR = 0x1000, + FLAG_CALL_OPERAND_REG = 0x2000, + FLAG_CALL_OPERAND_MEM = 0x4000, + + FLAG_UNUSE_AFTER_USE = 0x8000 + }; +}; + +// ============================================================================ +// [AsmJit::VarHintRecord] +// ============================================================================ + +struct VarHintRecord +{ + VarData* vdata; + uint32_t hint; +}; + +// ============================================================================ +// [AsmJit::StateData] +// ============================================================================ + +//! @brief State data. +struct StateData +{ + enum { NUM_REGS = 16 + 8 + 16 }; + + inline void clear() ASMJIT_NOTHROW + { + memset(this, 0, sizeof(*this)); + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + union + { + //! @brief All allocated variables in one array. + VarData* regs[NUM_REGS]; + + struct + { + //! @brief Allocated GP registers. + VarData* gp[16]; + //! @brief Allocated MM registers. + VarData* mm[8]; + //! @brief Allocated XMM registers. + VarData* xmm[16]; + }; + }; + + //! @brief Used GP registers bitmask. + uint32_t usedGP; + //! @brief Used MM registers bitmask. + uint32_t usedMM; + //! @brief Used XMM registers bitmask. + uint32_t usedXMM; + + //! @brief Changed GP registers bitmask. + uint32_t changedGP; + //! @brief Changed MM registers bitmask. + uint32_t changedMM; + //! @brief Changed XMM registers bitmask. + uint32_t changedXMM; + + //! @brief Count of variables in @c memVarsData. + uint32_t memVarsCount; + //! @brief Variables stored in memory (@c VARIABLE_STATE_MEMORY). + //! + //! When saving / restoring state it's important to keep registers which are + //! still in memory. Register is always unused when it is going out-of-scope. + //! All variables which are not here are unused (@c VARIABLE_STATE_UNUSED). + VarData* memVarsData[1]; +}; + +// ============================================================================ +// [AsmJit::ForwardJumpData] +// ============================================================================ + +struct ForwardJumpData +{ + EJmp* inst; + StateData* state; + ForwardJumpData* next; +}; + +// ============================================================================ +// [AsmJit::EVariableHint] +// ============================================================================ + +//! @brief Variable hint. +struct ASMJIT_API EVariableHint : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref EVariableHint instance. + EVariableHint(Compiler* c, VarData* vdata, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW; + //! @brief Destroy the @ref EVariableHInt instance. + virtual ~EVariableHint() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + virtual int getMaxSize() const ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Hint] + // -------------------------------------------------------------------------- + + //! @brief Get assigned variable (data). + inline VarData* getVar() const ASMJIT_NOTHROW { return _vdata; } + + //! @brief Get hint it (see @ref VARIABLE_HINT). + inline uint32_t getHintId() const ASMJIT_NOTHROW { return _hintId; } + //! @brief Get hint value. + inline uint32_t getHintValue() const ASMJIT_NOTHROW { return _hintValue; } + + //! @brief Set hint it (see @ref VARIABLE_HINT). + inline void setHintId(uint32_t hintId) ASMJIT_NOTHROW { _hintId = hintId; } + //! @brief Set hint value. + inline void setHintValue(uint32_t hintValue) ASMJIT_NOTHROW { _hintValue = hintValue; } + + VarData* _vdata; + uint32_t _hintId; + uint32_t _hintValue; +}; + +// ============================================================================ +// [AsmJit::EInstruction] +// ============================================================================ + +//! @brief Emittable that represents single instruction and its operands. +struct ASMJIT_API EInstruction : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref EInstruction instance. + EInstruction(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW; + //! @brief Destroy the @ref EInstruction instance. + virtual ~EInstruction() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + + virtual void emit(Assembler& a) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + virtual int getMaxSize() const ASMJIT_NOTHROW; + virtual bool _tryUnuseVar(VarData* v) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Instruction Code] + // -------------------------------------------------------------------------- + + //! @brief Get whether the instruction is special. + inline bool isSpecial() const ASMJIT_NOTHROW { return _isSpecial; } + + //! @brief Get whether the instruction is FPU. + inline bool isFPU() const ASMJIT_NOTHROW { return _isFPU; } + + //! @brief Get instruction code, see @c INST_CODE. + inline uint32_t getCode() const ASMJIT_NOTHROW { return _code; } + + //! @brief Set instruction code to @a code. + //! + //! Please do not modify instruction code if you are not know what you are + //! doing. Incorrect instruction code or operands can raise assertion() at + //! runtime. + inline void setCode(uint32_t code) ASMJIT_NOTHROW { _code = code; } + + // -------------------------------------------------------------------------- + // [Operands] + // -------------------------------------------------------------------------- + + //! @brief Get count of operands in operands array (number between 0 to 2 inclusive). + inline uint32_t getOperandsCount() const ASMJIT_NOTHROW { return _operandsCount; } + + //! @brief Get operands array (3 operands total). + inline Operand* getOperands() ASMJIT_NOTHROW { return _operands; } + //! @brief Get operands array (3 operands total). + inline const Operand* getOperands() const ASMJIT_NOTHROW { return _operands; } + + //! @brief Get memory operand. + inline Mem* getMemOp() ASMJIT_NOTHROW { return _memOp; } + //! @brief Set memory operand. + inline void setMemOp(Mem* op) ASMJIT_NOTHROW { _memOp = op; } + + // -------------------------------------------------------------------------- + // [Variables] + // -------------------------------------------------------------------------- + + //! @brief Get count of variables in instruction operands (and in variables array). + inline uint32_t getVariablesCount() const ASMJIT_NOTHROW { return _variablesCount; } + + //! @brief Get operands array (3 operands total). + inline VarAllocRecord* getVariables() ASMJIT_NOTHROW { return _variables; } + //! @brief Get operands array (3 operands total). + inline const VarAllocRecord* getVariables() const ASMJIT_NOTHROW { return _variables; } + + // -------------------------------------------------------------------------- + // [Jump] + // -------------------------------------------------------------------------- + + //! @brief Get possible jump target. + //! + //! If this instruction is conditional or normal jump then return value is + //! label location (ETarget instance), otherwise return value is @c NULL. + virtual ETarget* getJumpTarget() const ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Instruction code, see @c INST_CODE. + uint32_t _code; + + //! @brief Emit options, see @c EMIT_OPTIONS. + uint32_t _emitOptions; + + //! @brief Operands count. + uint32_t _operandsCount; + + //! @brief Variables count. + uint32_t _variablesCount; + + //! @brief Operands. + Operand* _operands; + //! @brief Memory operand (if instruction contains any). + Mem* _memOp; + + //! @brief Variables (extracted from operands). + VarAllocRecord* _variables; + + //! @brief Whether the instruction is special. + bool _isSpecial; + //! @brief Whether the instruction is FPU. + bool _isFPU; + + //! @brief Whether the one of the operands is GPB.Lo register. + bool _isGPBLoUsed; + //! @brief Whether the one of the operands is GPB.Hi register. + bool _isGPBHiUsed; + + friend struct EFunction; + friend struct CompilerContext; + friend struct CompilerCore; + +private: + ASMJIT_DISABLE_COPY(EInstruction) +}; + +// ============================================================================ +// [AsmJit::EJmp] +// ============================================================================ + +//! @brief Emittable that represents single instruction that can jump somewhere. +struct ASMJIT_API EJmp : public EInstruction +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + EJmp(Compiler* c, uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW; + virtual ~EJmp() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + virtual void emit(Assembler& a) ASMJIT_NOTHROW; + + void _doJump(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Jump] + // -------------------------------------------------------------------------- + + virtual ETarget* getJumpTarget() const ASMJIT_NOTHROW; + + inline EJmp* getJumpNext() const ASMJIT_NOTHROW { return _jumpNext; } + inline bool isTaken() const ASMJIT_NOTHROW { return _isTaken; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + ETarget* _jumpTarget; + EJmp *_jumpNext; + StateData* _state; + bool _isTaken; + + friend struct EFunction; + friend struct CompilerContext; + friend struct CompilerCore; + +private: + ASMJIT_DISABLE_COPY(EJmp) +}; + +// ============================================================================ +// [AsmJit::EFunction] +// ============================================================================ + +//! @brief Function emittable used to generate C/C++ functions. +//! +//! Functions are base blocks for generating assembler output. Each generated +//! assembler stream needs standard entry and leave sequences thats compatible +//! to the operating system conventions - Application Binary Interface (ABI). +//! +//! Function class can be used to generate entry (prolog) and leave (epilog) +//! sequences that is compatible to a given calling convention and to allocate +//! and manage variables that can be allocated to registers or spilled. +//! +//! @note To create function use @c AsmJit::Compiler::newFunction() method, do +//! not create @c EFunction instances using other ways. +//! +//! @sa @c State, @c Var. +struct ASMJIT_API EFunction : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new @c Function instance. + //! + //! @note Always use @c AsmJit::Compiler::newFunction() to create @c Function + //! instance. + EFunction(Compiler* c) ASMJIT_NOTHROW; + //! @brief Destroy @c Function instance. + virtual ~EFunction() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + virtual int getMaxSize() const ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Function Prototype (Calling Convention + Arguments) / Return Value] + // -------------------------------------------------------------------------- + + inline const FunctionPrototype& getPrototype() const ASMJIT_NOTHROW { return _functionPrototype; } + inline uint32_t getHint(uint32_t hint) ASMJIT_NOTHROW { return _hints[hint]; } + + void setPrototype( + uint32_t callingConvention, + const uint32_t* arguments, + uint32_t argumentsCount, + uint32_t returnValue) ASMJIT_NOTHROW; + void setHint(uint32_t hint, uint32_t value) ASMJIT_NOTHROW; + + inline EProlog* getProlog() const ASMJIT_NOTHROW { return _prolog; } + inline EEpilog* getEpilog() const ASMJIT_NOTHROW { return _epilog; } + + inline EFunctionEnd* getEnd() const ASMJIT_NOTHROW { return _end; } + + //! @brief Create variables from FunctionPrototype declaration. This is just + //! parsing what FunctionPrototype generated for current function calling + //! convention and arguments. + void _createVariables() ASMJIT_NOTHROW; + + //! @brief Prepare variables (ids, names, scope, registers). + void _prepareVariables(Emittable* first) ASMJIT_NOTHROW; + + //! @brief Allocate variables (setting correct state, changing masks, etc). + void _allocVariables(CompilerContext& cc) ASMJIT_NOTHROW; + + void _preparePrologEpilog(CompilerContext& cc) ASMJIT_NOTHROW; + void _dumpFunction(CompilerContext& cc) ASMJIT_NOTHROW; + void _emitProlog(CompilerContext& cc) ASMJIT_NOTHROW; + void _emitEpilog(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Function-Call] + // -------------------------------------------------------------------------- + + //! @brief Reserve stack for calling other function and mark function as + //! callee. + void reserveStackForFunctionCall(int32_t size); + + // -------------------------------------------------------------------------- + // [Labels] + // -------------------------------------------------------------------------- + + //! @brief Get function entry label. + //! + //! Entry label can be used to call this function from another code that's + //! being generated. + inline const Label& getEntryLabel() const ASMJIT_NOTHROW { return _entryLabel; } + + //! @brief Get function exit label. + //! + //! Use exit label to jump to function epilog. + inline const Label& getExitLabel() const ASMJIT_NOTHROW { return _exitLabel; } + + // -------------------------------------------------------------------------- + // [Misc] + // -------------------------------------------------------------------------- + + //! @brief Set the _isEspAdjusted member to true. + //! + //! This method is used to tell compiler that the ESP/RSP must be adjusted in + //! function prolog/epilog, because the stack is manipulated (usually caused + //! by the function call, see @c ECall). + inline void mustAdjustEsp() { _isEspAdjusted = true; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Function prototype. + FunctionPrototype _functionPrototype; + //! @brief Function arguments (variable IDs). + VarData** _argumentVariables; + //! @brief Function hints. + uint32_t _hints[16]; + + //! @brief Whether the function stack is aligned by 16-bytes by OS. + //! + //! This is always true for 64-bit mode and for linux. + bool _isStackAlignedByOsTo16Bytes; + + //! @brief Whether the function stack (for variables) is aligned manually + //! by function to 16-bytes. + //! + //! This makes sense only if _isStackAlignedByOsTo16Bytes is false and MOVDQA + //! instruction or other SSE/SSE2 instructions are used to work with variable + //! stored on the stack. + //! + //! Value is determined automatically by these factors, expectations are: + //! + //! 1. There is 16-byte wide variable which address was used (alloc, spill, + //! op). + //! 2. Function can't be naked. + bool _isStackAlignedByFnTo16Bytes; + + //! @brief Whether the function is using naked prolog / epilog + //! + //! Naked prolog / epilog means to omit saving and restoring EBP. + bool _isNaked; + + //! @brief Whether the ESP register is adjusted by the stack size needed + //! to save registers and function variables. + //! + //! Esp is adjusted by 'sub' instruction in prolog and by add function in + //! epilog (only if function is not naked). + bool _isEspAdjusted; + + //! @brief Whether another function is called from this function. + //! + //! If another function is called from this function, it's needed to prepare + //! stack for it. If this member is true then it's likely that true will be + //! also @c _isEspAdjusted one. + bool _isCaller; + + //! @brief Whether to emit prolog / epilog sequence using push & pop + //! instructions (the default). + bool _pePushPop; + + //! @brief Whether to emit EMMS instruction in epilog (auto-detected). + bool _emitEMMS; + + //! @brief Whether to emit SFence instruction in epilog (auto-detected). + //! + //! @note Combination of @c _emitSFence and @c _emitLFence will result in + //! emitting mfence. + bool _emitSFence; + + //! @brief Whether to emit LFence instruction in epilog (auto-detected). + //! + //! @note Combination of @c _emitSFence and @c _emitLFence will result in + //! emitting mfence. + bool _emitLFence; + + //! @brief Whether the function is finished using @c Compiler::endFunction(). + bool _finished; + + //! @brief Bitfield containing modified and preserved GP registers. + uint32_t _modifiedAndPreservedGP; + + //! @brief Bitfield containing modified and preserved MM registers. + uint32_t _modifiedAndPreservedMM; + + //! @brief Bitfield containing modified and preserved XMM registers. + uint32_t _modifiedAndPreservedXMM; + + //! @brief ID mov movdqa instruction (@c INST_MOVDQA or @c INST_MOVDQU). + //! + //! The value is based on stack alignment. If it's guaranteed that stack + //! is aligned to 16-bytes then @c INST_MOVDQA instruction is used, otherwise + //! the @c INST_MOVDQU instruction is used for 16-byte mov. + uint32_t _movDqaInstruction; + + //! @brief Prolog / epilog stack size for PUSH/POP sequences. + int32_t _pePushPopStackSize; + //! @brief Prolog / epilog stack size for MOV sequences. + int32_t _peMovStackSize; + //! @brief Prolog / epilog stack adjust size (to make it 16-byte aligned). + int32_t _peAdjustStackSize; + + //! @brief Memory stack size (for all variables and temporary memory). + int32_t _memStackSize; + //! @brief Like @c _memStackSize, but aligned to 16-bytes. + int32_t _memStackSize16; + + //! @brief Stack size needed to call other functions. + int32_t _functionCallStackSize; + + //! @brief Function entry label. + Label _entryLabel; + //! @brief Function exit label. + Label _exitLabel; + + //! @brief Function prolog emittable. + EProlog* _prolog; + //! @brief Function epilog emittable. + EEpilog* _epilog; + //! @brief Dummy emittable, signalizes end of function. + EFunctionEnd* _end; + +private: + friend struct CompilerContext; + friend struct CompilerCore; + friend struct EProlog; + friend struct EEpilog; +}; + +// ============================================================================ +// [AsmJit::EProlog] +// ============================================================================ + +//! @brief Prolog emittable. +struct ASMJIT_API EProlog : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref EProlog instance. + EProlog(Compiler* c, EFunction* f) ASMJIT_NOTHROW; + //! @brief Destroy the @ref EProlog instance. + virtual ~EProlog() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Get function associated with this prolog. + inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Prolog owner function. + EFunction* _function; + +private: + friend struct CompilerCore; + friend struct EFunction; +}; + +// ============================================================================ +// [AsmJit::EEpilog] +// ============================================================================ + +//! @brief Epilog emittable. +struct ASMJIT_API EEpilog : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref EEpilog instance. + EEpilog(Compiler* c, EFunction* f) ASMJIT_NOTHROW; + //! @brief Destroy the @ref EProlog instance. + virtual ~EEpilog() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Get function associated with this epilog. + inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Epilog owner function. + EFunction* _function; + +private: + friend struct CompilerCore; + friend struct EFunction; +}; + +// ============================================================================ +// [AsmJit::ECall] +// ============================================================================ + +//! @brief Function call. +struct ASMJIT_API ECall : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref ECall instance. + ECall(Compiler* c, EFunction* caller, const Operand* target) ASMJIT_NOTHROW; + //! @brief Destroy the @ref ECall instance. + virtual ~ECall() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + virtual int getMaxSize() const ASMJIT_NOTHROW; + virtual bool _tryUnuseVar(VarData* v) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Internal] + // -------------------------------------------------------------------------- + +protected: + + uint32_t _findTemporaryGpRegister(CompilerContext& cc) ASMJIT_NOTHROW; + uint32_t _findTemporaryXmmRegister(CompilerContext& cc) ASMJIT_NOTHROW; + + VarData* _getOverlappingVariable(CompilerContext& cc, + const FunctionPrototype::Argument& argType) const ASMJIT_NOTHROW; + + void _moveAllocatedVariableToStack(CompilerContext& cc, + VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW; + + void _moveSpilledVariableToStack(CompilerContext& cc, + VarData* vdata, const FunctionPrototype::Argument& argType, + uint32_t temporaryGpReg, + uint32_t temporaryXmmReg) ASMJIT_NOTHROW; + + void _moveSrcVariableToRegister(CompilerContext& cc, + VarData* vdata, const FunctionPrototype::Argument& argType) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Function Prototype (Calling Convention + Arguments) / Return Value] + // -------------------------------------------------------------------------- + +public: + + //! @brief Get function prototype. + inline const FunctionPrototype& getPrototype() const ASMJIT_NOTHROW { return _functionPrototype; } + + //! @brief Set function prototype. + inline void setPrototype(uint32_t cconv, const FunctionDefinition& def) ASMJIT_NOTHROW + { + _setPrototype( + cconv, + def.getArguments(), + def.getArgumentsCount(), + def.getReturnValue()); + } + + //! @brief Set function prototype (internal). + void _setPrototype( + uint32_t callingConvention, + const uint32_t* arguments, + uint32_t argumentsCount, + uint32_t returnValue) ASMJIT_NOTHROW; + + //! @brief Set function argument @a i to @a var. + bool setArgument(uint32_t i, const BaseVar& var) ASMJIT_NOTHROW; + //! @brief Set function argument @a i to @a imm. + bool setArgument(uint32_t i, const Imm& imm) ASMJIT_NOTHROW; + + //! @brief Set return value to + bool setReturn(const Operand& first, const Operand& second = Operand()) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @brief Get caller. + inline EFunction* getCaller() const ASMJIT_NOTHROW { return _caller; } + + //! @brief Get operand (function address). + inline Operand& getTarget() ASMJIT_NOTHROW { return _target; } + //! @overload + inline const Operand& getTarget() const ASMJIT_NOTHROW { return _target; } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Function prototype. + FunctionPrototype _functionPrototype; + + //! @brief Callee (the function that calls me). + EFunction* _caller; + + //! @brief Arguments (operands). + Operand* _args; + + //! @brief Operand (address of function, register, label, ...) + Operand _target; + + //! @brief Return value (operands) + Operand _ret[2]; + + //! @brief Mask of GP registers used as function arguments. + uint32_t _gpParams; + //! @brief Mask of MM registers used as function arguments. + uint32_t _mmParams; + //! @brief Mask of XMM registers used as function arguments. + uint32_t _xmmParams; + + //! @brief Variables count. + uint32_t _variablesCount; + + //! @brief Variables (extracted from operands). + VarCallRecord* _variables; + //! @brief Argument index to @c VarCallRecord. + VarCallRecord* _argumentToVarRecord[FUNC_MAX_ARGS]; + +private: + friend struct CompilerCore; +}; + +// ============================================================================ +// [AsmJit::ERet] +// ============================================================================ + +//! @brief Function return. +struct ASMJIT_API ERet : public Emittable +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref ERet instance. + ERet(Compiler* c, EFunction* function, const Operand* first, const Operand* second) ASMJIT_NOTHROW; + //! @brief Destroy the @ref ERet instance. + virtual ~ERet() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + virtual void prepare(CompilerContext& cc) ASMJIT_NOTHROW; + virtual Emittable* translate(CompilerContext& cc) ASMJIT_NOTHROW; + virtual void emit(Assembler& a) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Utilities] + // -------------------------------------------------------------------------- + + virtual int getMaxSize() const ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Methods] + // -------------------------------------------------------------------------- + + //! @Brief Get function. + inline EFunction* getFunction() ASMJIT_NOTHROW { return _function; } + + //! @brief Get operand (function address). + inline Operand& getFirst() ASMJIT_NOTHROW { return _ret[0]; } + //! @brief Get operand (function address). + inline Operand& getSecond() ASMJIT_NOTHROW { return _ret[1]; } + //! @overload + inline const Operand& getFirst() const ASMJIT_NOTHROW { return _ret[0]; } + //! @overload + inline const Operand& getSecond() const ASMJIT_NOTHROW { return _ret[1]; } + + //! @brief Get whether jump to epilog have to be emitted. + bool shouldEmitJumpToEpilog() const ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + //! @brief Function. + EFunction* _function; + //! @brief Return value (operands) + Operand _ret[2]; + +private: + friend struct CompilerCore; +}; + +// ============================================================================ +// [AsmJit::CompilerContext] +// ============================================================================ + +//! @internal +//! +//! @brief Compiler context is used by @ref Compiler. +//! +//! Compiler context is used during compilation and normally developer doesn't +//! need access to it. The context is user per function (it's reset after each +//! function is generated). +struct ASMJIT_API CompilerContext +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create a new @ref CompilerContext instance. + CompilerContext(Compiler* compiler) ASMJIT_NOTHROW; + //! @brief Destroy the @ref CompilerContext instance. + ~CompilerContext() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Clear] + // -------------------------------------------------------------------------- + + //! @brief Clear context, preparing it for next function generation. + void _clear() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Register Allocator] + // -------------------------------------------------------------------------- + + //! @brief Allocate variable + //! + //! Calls @c allocGPVar, @c allocMMVar or @c allocXMMVar methods. + void allocVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Save variable. + //! + //! Calls @c saveGPVar, @c saveMMVar or @c saveXMMVar methods. + void saveVar(VarData* vdata) ASMJIT_NOTHROW; + //! @brief Spill variable. + //! + //! Calls @c spillGPVar, @c spillMMVar or @c spillXMMVar methods. + void spillVar(VarData* vdata) ASMJIT_NOTHROW; + //! @brief Unuse variable (didn't spill, just forget about it). + void unuseVar(VarData* vdata, uint32_t toState) ASMJIT_NOTHROW; + + //! @brief Helper method that is called for each variable per emittable. + inline void _unuseVarOnEndOfScope(Emittable* e, VarData* v) + { + if (v->lastEmittable == e) + unuseVar(v, VARIABLE_STATE_UNUSED); + } + //! @overload + inline void _unuseVarOnEndOfScope(Emittable* e, VarAllocRecord* rec) + { + VarData* v = rec->vdata; + if (v->lastEmittable == e || (rec->vflags & VARIABLE_ALLOC_UNUSE_AFTER_USE)) + unuseVar(v, VARIABLE_STATE_UNUSED); + } + //! @overload + inline void _unuseVarOnEndOfScope(Emittable* e, VarCallRecord* rec) + { + VarData* v = rec->vdata; + if (v->lastEmittable == e || (rec->flags & VarCallRecord::FLAG_UNUSE_AFTER_USE)) + unuseVar(v, VARIABLE_STATE_UNUSED); + } + + //! @brief Allocate variable (GP). + void allocGPVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Save variable (GP). + void saveGPVar(VarData* vdata) ASMJIT_NOTHROW; + //! @brief Spill variable (GP). + void spillGPVar(VarData* vdata) ASMJIT_NOTHROW; + + //! @brief Allocate variable (MM). + void allocMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Save variable (MM). + void saveMMVar(VarData* vdata) ASMJIT_NOTHROW; + //! @brief Spill variable (MM). + void spillMMVar(VarData* vdata) ASMJIT_NOTHROW; + + //! @brief Allocate variable (XMM). + void allocXMMVar(VarData* vdata, uint32_t regMask, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Save variable (XMM). + void saveXMMVar(VarData* vdata) ASMJIT_NOTHROW; + //! @brief Spill variable (XMM). + void spillXMMVar(VarData* vdata) ASMJIT_NOTHROW; + + //! @brief Emit load variable instruction(s). + void emitLoadVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW; + //! @brief Emit save variable instruction(s). + void emitSaveVar(VarData* vdata, uint32_t regIndex) ASMJIT_NOTHROW; + + //! @brief Emit move variable instruction(s). + void emitMoveVar(VarData* vdata, uint32_t regIndex, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Emit exchange variable instruction(s). + void emitExchangeVar(VarData* vdata, uint32_t regIndex, uint32_t vflags, VarData* other) ASMJIT_NOTHROW; + + //! @brief Called each time a variable is alloceted. + void _postAlloc(VarData* vdata, uint32_t vflags) ASMJIT_NOTHROW; + //! @brief Marks variable home memory as used (must be called at least once + //! for each variable that uses function local memory - stack). + void _markMemoryUsed(VarData* vdata) ASMJIT_NOTHROW; + + Mem _getVarMem(VarData* vdata) ASMJIT_NOTHROW; + + VarData* _getSpillCandidateGP() ASMJIT_NOTHROW; + VarData* _getSpillCandidateMM() ASMJIT_NOTHROW; + VarData* _getSpillCandidateXMM() ASMJIT_NOTHROW; + VarData* _getSpillCandidateGeneric(VarData** varArray, uint32_t count) ASMJIT_NOTHROW; + + inline bool _isActive(VarData* vdata) ASMJIT_NOTHROW { return vdata->nextActive != NULL; } + void _addActive(VarData* vdata) ASMJIT_NOTHROW; + void _freeActive(VarData* vdata) ASMJIT_NOTHROW; + void _freeAllActive() ASMJIT_NOTHROW; + + void _allocatedVariable(VarData* vdata) ASMJIT_NOTHROW; + + inline void _allocatedGPRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedGP |= Util::maskFromIndex(index); _modifiedGPRegisters |= Util::maskFromIndex(index); } + inline void _allocatedMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedMM |= Util::maskFromIndex(index); _modifiedMMRegisters |= Util::maskFromIndex(index); } + inline void _allocatedXMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedXMM |= Util::maskFromIndex(index); _modifiedXMMRegisters |= Util::maskFromIndex(index); } + + inline void _freedGPRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedGP &= ~Util::maskFromIndex(index); } + inline void _freedMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedMM &= ~Util::maskFromIndex(index); } + inline void _freedXMMRegister(uint32_t index) ASMJIT_NOTHROW { _state.usedXMM &= ~Util::maskFromIndex(index); } + + inline void _markGPRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedGPRegisters |= Util::maskFromIndex(index); } + inline void _markMMRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedMMRegisters |= Util::maskFromIndex(index); } + inline void _markXMMRegisterModified(uint32_t index) ASMJIT_NOTHROW { _modifiedXMMRegisters |= Util::maskFromIndex(index); } + + // TODO: Find code which uses this and improve. + inline void _newRegisterHomeIndex(VarData* vdata, uint32_t idx) + { + if (vdata->homeRegisterIndex == INVALID_VALUE) vdata->homeRegisterIndex = idx; + vdata->prefRegisterMask |= (1U << idx); + } + + // TODO: Find code which uses this and improve. + inline void _newRegisterHomeMask(VarData* vdata, uint32_t mask) + { + vdata->prefRegisterMask |= mask; + } + + // -------------------------------------------------------------------------- + // [Operand Patcher] + // -------------------------------------------------------------------------- + + void translateOperands(Operand* operands, uint32_t count) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Accessors] + // -------------------------------------------------------------------------- + + inline Compiler* getCompiler() const ASMJIT_NOTHROW { return _compiler; } + inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } + + inline Emittable* getExtraBlock() const ASMJIT_NOTHROW { return _extraBlock; } + inline void setExtraBlock(Emittable* e) ASMJIT_NOTHROW { _extraBlock = e; } + + // -------------------------------------------------------------------------- + // [Backward Code] + // -------------------------------------------------------------------------- + + void addBackwardCode(EJmp* from) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Forward Jump] + // -------------------------------------------------------------------------- + + void addForwardJump(EJmp* inst) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [State] + // -------------------------------------------------------------------------- + + StateData* _saveState() ASMJIT_NOTHROW; + void _assignState(StateData* state) ASMJIT_NOTHROW; + void _restoreState(StateData* state, uint32_t targetOffset = INVALID_VALUE) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Memory Allocator] + // -------------------------------------------------------------------------- + + VarMemBlock* _allocMemBlock(uint32_t size) ASMJIT_NOTHROW; + void _freeMemBlock(VarMemBlock* mem) ASMJIT_NOTHROW; + + void _allocMemoryOperands() ASMJIT_NOTHROW; + void _patchMemoryOperands(Emittable* start, Emittable* stop) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + + //! @brief Zone memory manager. + Zone _zone; + + //! @brief Compiler instance. + Compiler* _compiler; + //! @brief Function emittable. + EFunction* _function; + + //! @brief Current active scope start emittable. + Emittable* _start; + //! @brief Current active scope end emittable. + Emittable* _stop; + //! @brief Emittable that is used to insert some code after the function body. + Emittable* _extraBlock; + + //! @brief Current state (register allocator). + StateData _state; + //! @brief Link to circullar double-linked list containing all active variables + //! (for current state). + VarData* _active; + + //! @brief Forward jumps (single linked list). + ForwardJumpData* _forwardJumps; + + //! @brief Current offset, used in prepare() stage. Each emittable should increment it. + uint32_t _currentOffset; + + //! @brief Whether current code is unrecheable. + uint32_t _unrecheable; + + //! @brief Global modified GP registers mask (per function). + uint32_t _modifiedGPRegisters; + //! @brief Global modified MM registers mask (per function). + uint32_t _modifiedMMRegisters; + //! @brief Global modified XMM registers mask (per function). + uint32_t _modifiedXMMRegisters; + + //! @brief Whether the EBP/RBP register can be used by register allocator. + uint32_t _allocableEBP; + + //! @brief ESP adjust constant (changed during PUSH/POP or when using + //! stack. + int _adjustESP; + + //! @brief Function arguments base pointer (register). + uint32_t _argumentsBaseReg; + //! @brief Function arguments base offset. + int32_t _argumentsBaseOffset; + //! @brief Function arguments displacement. + int32_t _argumentsActualDisp; + + //! @brief Function variables base pointer (register). + uint32_t _variablesBaseReg; + //! @brief Function variables base offset. + int32_t _variablesBaseOffset; + //! @brief Function variables displacement. + int32_t _variablesActualDisp; + + //! @brief Used memory blocks (for variables, here is each created mem block + //! that can be also in _memFree list). + VarMemBlock* _memUsed; + //! @brief Free memory blocks (freed, prepared for another allocation). + VarMemBlock* _memFree; + //! @brief Count of 4-byte memory blocks used by the function. + uint32_t _mem4BlocksCount; + //! @brief Count of 8-byte memory blocks used by the function. + uint32_t _mem8BlocksCount; + //! @brief Count of 16-byte memory blocks used by the function. + uint32_t _mem16BlocksCount; + //! @brief Count of total bytes of stack memory used by the function. + uint32_t _memBytesTotal; + + //! @brief Whether to emit comments. + bool _emitComments; + + //! @brief List of emittables which need to be translated. These emittables + //! are filled by @c addBackwardCode(). + PodVector<EJmp*> _backCode; + //! @brief Backward code position (starts at 0). + sysuint_t _backPos; +}; + +// ============================================================================ +// [AsmJit::CompilerUtil] +// ============================================================================ + +//! @brief Static class that contains utility methods. +struct ASMJIT_API CompilerUtil +{ + static bool isStack16ByteAligned(); +}; + +// ============================================================================ +// [AsmJit::CompilerCore] +// ============================================================================ + +//! @brief Compiler core. +//! +//! @sa @c AsmJit::Compiler. +struct ASMJIT_API CompilerCore +{ + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create new (empty) instance of @c Compiler. + CompilerCore(CodeGenerator* codeGenerator) ASMJIT_NOTHROW; + //! @brief Destroy @c Compiler instance. + virtual ~CompilerCore() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Code Generator] + // -------------------------------------------------------------------------- + + //! @brief Get code generator. + inline CodeGenerator* getCodeGenerator() const { return _codeGenerator; } + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + //! @brief Get zone memory manager. + inline Zone& getZone() { return _zone; } + + // -------------------------------------------------------------------------- + // [Logging] + // -------------------------------------------------------------------------- + + //! @brief Get logger. + inline Logger* getLogger() const ASMJIT_NOTHROW { return _logger; } + + //! @brief Set logger to @a logger. + virtual void setLogger(Logger* logger) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Error Handling] + // -------------------------------------------------------------------------- + + //! @brief Get error code. + inline uint32_t getError() const ASMJIT_NOTHROW { return _error; } + + //! @brief Set error code. + //! + //! This method is virtual, because higher classes can use it to catch all + //! errors. + virtual void setError(uint32_t error) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Properties] + // -------------------------------------------------------------------------- + + //! @brief Get compiler property. + uint32_t getProperty(uint32_t propertyId); + //! @brief Set compiler property. + void setProperty(uint32_t propertyId, uint32_t value); + + // -------------------------------------------------------------------------- + // [Buffer] + // -------------------------------------------------------------------------- + + //! @brief Clear everything, but not deallocate buffers. + //! + //! @note This method will destroy your code. + void clear() ASMJIT_NOTHROW; + + //! @brief Free internal buffer, all emitters and NULL all pointers. + //! + //! @note This method will destroy your code. + void free() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Emittables] + // -------------------------------------------------------------------------- + + //! @brief Get first emittable. + inline Emittable* getFirstEmittable() const ASMJIT_NOTHROW { return _first; } + + //! @brief Get last emittable. + inline Emittable* getLastEmittable() const ASMJIT_NOTHROW { return _last; } + + //! @brief Get current emittable. + //! + //! @note If this method return @c NULL, it means that nothing emitted yet. + inline Emittable* getCurrentEmittable() const ASMJIT_NOTHROW { return _current; } + + //! @brief Set new current emittable and return previous one. + Emittable* setCurrentEmittable(Emittable* current) ASMJIT_NOTHROW; + + //! @brief Add emittable after current and set current to @a emittable. + void addEmittable(Emittable* emittable) ASMJIT_NOTHROW; + + //! @brief Add emittable after @a ref. + void addEmittableAfter(Emittable* emittable, Emittable* ref) ASMJIT_NOTHROW; + + //! @brief Remove emittable (and if needed set current to previous). + void removeEmittable(Emittable* emittable) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Comment] + // -------------------------------------------------------------------------- + + //! @brief Emit a single comment line that will be logged. + //! + //! Emitting comments are useful to log something. Because assembler can be + //! generated from AST or other data structures, you may sometimes need to + //! log data characteristics or statistics. + //! + //! @note Emitting comment is not directly sent to logger, but instead it's + //! stored in @c AsmJit::Compiler and emitted when @c serialize() method is + //! called. Each comment keeps correct order. + void comment(const char* fmt, ...) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Function Builder] + // -------------------------------------------------------------------------- + + //! @brief Create a new function. + //! + //! @param cconv Calling convention to use (see @c CALL_CONV enum) + //! @param params Function arguments prototype. + //! + //! This method is usually used as a first step when generating functions + //! by @c Compiler. First parameter @a cconv specifies function calling + //! convention to use. Second parameter @a params specifies function + //! arguments. To create function arguments are used templates + //! @c BuildFunction0<>, @c BuildFunction1<...>, @c BuildFunction2<...>, + //! etc... + //! + //! Templates with BuildFunction prefix are used to generate argument IDs + //! based on real C++ types. See next example how to generate function with + //! two 32-bit integer arguments. + //! + //! @code + //! // Building function using AsmJit::Compiler example. + //! + //! // Compiler instance + //! Compiler c; + //! + //! // Begin of function (also emits function @c Prolog) + //! c.newFunction( + //! // Default calling convention (32-bit cdecl or 64-bit for host OS) + //! CALL_CONV_DEFAULT, + //! // Using function builder to generate arguments list + //! BuildFunction2<int, int>()); + //! + //! // End of function (also emits function @c Epilog) + //! c.endFunction(); + //! @endcode + //! + //! You can see that building functions is really easy. Previous code snipped + //! will generate code for function with two 32-bit integer arguments. You + //! can access arguments by @c AsmJit::Function::argument() method. Arguments + //! are indexed from 0 (like everything in C). + //! + //! @code + //! // Accessing function arguments through AsmJit::Function example. + //! + //! // Compiler instance + //! Compiler c; + //! + //! // Begin of function (also emits function @c Prolog) + //! c.newFunction( + //! // Default calling convention (32-bit cdecl or 64-bit for host OS) + //! CALL_CONV_DEFAULT, + //! // Using function builder to generate arguments list + //! BuildFunction2<int, int>()); + //! + //! // Arguments are like other variables, you need to reference them by + //! // variable operands: + //! GPVar a0 = c.argGP(0); + //! GPVar a1 = c.argGP(1); + //! + //! // Use them. + //! c.add(a0, a1); + //! + //! // End of function (emits function epilog and return) + //! c.endFunction(); + //! @endcode + //! + //! Arguments are like variables. How to manipulate with variables is + //! documented in @c AsmJit::Compiler, variables section. + //! + //! @note To get current function use @c currentFunction() method or save + //! pointer to @c AsmJit::Function returned by @c AsmJit::Compiler::newFunction<> + //! method. Recommended is to save the pointer. + //! + //! @sa @c BuildFunction0, @c BuildFunction1, @c BuildFunction2, ... + inline EFunction* newFunction(uint32_t cconv, const FunctionDefinition& def) ASMJIT_NOTHROW + { + return newFunction_( + cconv, + def.getArguments(), + def.getArgumentsCount(), + def.getReturnValue()); + } + + //! @brief Create a new function (low level version). + //! + //! @param cconv Function calling convention (see @c AsmJit::CALL_CONV). + //! @param args Function arguments (see @c AsmJit::VARIABLE_TYPE). + //! @param count Arguments count. + //! + //! This method is internally called from @c newFunction() method and + //! contains arguments thats used internally by @c AsmJit::Compiler. + //! + //! @note To get current function use @c currentFunction() method. + EFunction* newFunction_( + uint32_t cconv, + const uint32_t* arguments, + uint32_t argumentsCount, + uint32_t returnValue) ASMJIT_NOTHROW; + + //! @brief Get current function. + //! + //! This method can be called within @c newFunction() and @c endFunction() + //! block to get current function you are working with. It's recommended + //! to store @c AsmJit::Function pointer returned by @c newFunction<> method, + //! because this allows you in future implement function sections outside of + //! function itself (yeah, this is possible!). + inline EFunction* getFunction() const ASMJIT_NOTHROW { return _function; } + + //! @brief End of current function scope and all variables. + EFunction* endFunction() ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Memory Management] + // -------------------------------------------------------------------------- + + inline EInstruction* newInstruction(uint32_t code, Operand* operandsData, uint32_t operandsCount) ASMJIT_NOTHROW + { + if (code >= _INST_J_BEGIN && code <= _INST_J_END) + { + void* addr = _zone.zalloc(sizeof(EJmp)); + + return new(addr) EJmp( + reinterpret_cast<Compiler*>(this), code, operandsData, operandsCount); + } + else + { + void* addr = _zone.zalloc(sizeof(EInstruction) + operandsCount * sizeof(Operand)); + + return new(addr) EInstruction( + reinterpret_cast<Compiler*>(this), code, operandsData, operandsCount); + } + } + + // -------------------------------------------------------------------------- + // [Emit] + // -------------------------------------------------------------------------- + + //! @brief Emit instruction with no operand. + void _emitInstruction(uint32_t code) ASMJIT_NOTHROW; + + //! @brief Emit instruction with one operand. + void _emitInstruction(uint32_t code, const Operand* o0) ASMJIT_NOTHROW; + + //! @brief Emit instruction with two operands. + void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1) ASMJIT_NOTHROW; + + //! @brief Emit instruction with three operands. + void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2) ASMJIT_NOTHROW; + + //! @brief Emit instruction with four operands (Special instructions). + void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3) ASMJIT_NOTHROW; + + //! @brief Emit instruction with five operands (Special instructions). + void _emitInstruction(uint32_t code, const Operand* o0, const Operand* o1, const Operand* o2, const Operand* o3, const Operand* o4) ASMJIT_NOTHROW; + + //! @brief Private method for emitting jcc. + void _emitJcc(uint32_t code, const Label* label, uint32_t hint) ASMJIT_NOTHROW; + + //! @brief Private method for emitting function call. + ECall* _emitCall(const Operand* o0) ASMJIT_NOTHROW; + + //! @brief Private method for returning a value from the function. + void _emitReturn(const Operand* first, const Operand* second) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Embed] + // -------------------------------------------------------------------------- + + //! @brief Embed data into instruction stream. + void embed(const void* data, sysuint_t len) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Align] + // -------------------------------------------------------------------------- + + //! @brief Align target buffer to @a m bytes. + //! + //! Typical usage of this is to align labels at start of the inner loops. + //! + //! Inserts @c nop() instructions or CPU optimized NOPs. + void align(uint32_t m) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Label] + // -------------------------------------------------------------------------- + + //! @brief Create and return new label. + Label newLabel() ASMJIT_NOTHROW; + + //! @brief Bind label to the current offset. + //! + //! @note Label can be bound only once! + void bind(const Label& label) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Variables] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Create a new variable data. + VarData* _newVarData(const char* name, uint32_t type, uint32_t size) ASMJIT_NOTHROW; + + //! @internal + //! + //! @brief Get variable data. + inline VarData* _getVarData(uint32_t id) const ASMJIT_NOTHROW + { + ASMJIT_ASSERT(id != INVALID_VALUE); + return _varData[id & OPERAND_ID_VALUE_MASK]; + } + + //! @brief Create a new general-purpose variable. + GPVar newGP(uint32_t variableType = VARIABLE_TYPE_GPN, const char* name = NULL) ASMJIT_NOTHROW; + //! @brief Get argument as general-purpose variable. + GPVar argGP(uint32_t index) ASMJIT_NOTHROW; + + //! @brief Create a new MM variable. + MMVar newMM(uint32_t variableType = VARIABLE_TYPE_MM, const char* name = NULL) ASMJIT_NOTHROW; + //! @brief Get argument as MM variable. + MMVar argMM(uint32_t index) ASMJIT_NOTHROW; + + //! @brief Create a new XMM variable. + XMMVar newXMM(uint32_t variableType = VARIABLE_TYPE_XMM, const char* name = NULL) ASMJIT_NOTHROW; + //! @brief Get argument as XMM variable. + XMMVar argXMM(uint32_t index) ASMJIT_NOTHROW; + + //! @internal + //! + //! @brief Serialize variable hint. + void _vhint(BaseVar& var, uint32_t hintId, uint32_t hintValue) ASMJIT_NOTHROW; + + //! @brief Alloc variable @a var. + void alloc(BaseVar& var) ASMJIT_NOTHROW; + //! @brief Alloc variable @a var using @a regIndex as a register index. + void alloc(BaseVar& var, uint32_t regIndex) ASMJIT_NOTHROW; + //! @brief Alloc variable @a var using @a reg as a demanded register. + void alloc(BaseVar& var, const BaseReg& reg) ASMJIT_NOTHROW; + //! @brief Spill variable @a var. + void spill(BaseVar& var) ASMJIT_NOTHROW; + //! @brief Save variable @a var if modified. + void save(BaseVar& var) ASMJIT_NOTHROW; + //! @brief Unuse variable @a var. + void unuse(BaseVar& var) ASMJIT_NOTHROW; + + //! @brief Get memory home of variable @a var. + void getMemoryHome(BaseVar& var, GPVar* home, int* displacement = NULL); + + //! @brief Set memory home of variable @a var. + //! + //! Default memory home location is on stack (ESP/RSP), but when needed the + //! bebahior can be changed by this method. + //! + //! It is an error to chaining memory home locations. For example the given + //! code is invalid: + //! + //! @code + //! Compiler c; + //! + //! ... + //! GPVar v0 = c.newGP(); + //! GPVar v1 = c.newGP(); + //! GPVar v2 = c.newGP(); + //! GPVar v3 = c.newGP(); + //! + //! c.setMemoryHome(v1, v0, 0); // Allowed, [v0] is memory home for v1. + //! c.setMemoryHome(v2, v0, 4); // Allowed, [v0+4] is memory home for v2. + //! c.setMemoryHome(v3, v2); // CHAINING, NOT ALLOWED! + //! @endcode + void setMemoryHome(BaseVar& var, const GPVar& home, int displacement = 0); + + //! @brief Get priority of variable @a var. + uint32_t getPriority(BaseVar& var) const ASMJIT_NOTHROW; + //! @brief Set priority of variable @a var to @a priority. + void setPriority(BaseVar& var, uint32_t priority) ASMJIT_NOTHROW; + + //! @brief Get save-on-unuse @a var property. + bool getSaveOnUnuse(BaseVar& var) const ASMJIT_NOTHROW; + //! @brief Set save-on-unuse @a var property to @a value. + void setSaveOnUnuse(BaseVar& var, bool value) ASMJIT_NOTHROW; + + //! @brief Rename variable @a var to @a name. + //! + //! @note Only new name will appear in the logger. + void rename(BaseVar& var, const char* name) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [State] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Create a new @ref StateData instance. + StateData* _newStateData(uint32_t memVarsCount) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Make] + // -------------------------------------------------------------------------- + + //! @brief Make is convenience method to make currently serialized code and + //! return pointer to generated function. + //! + //! What you need is only to cast this pointer to your function type and call + //! it. Note that if there was an error and calling @c getError() method not + //! returns @c ERROR_NONE (zero) then this function always return @c NULL and + //! error value remains the same. + virtual void* make() ASMJIT_NOTHROW; + + //! @brief Method that will emit everything to @c Assembler instance @a a. + virtual void serialize(Assembler& a) ASMJIT_NOTHROW; + + // -------------------------------------------------------------------------- + // [Data] + // -------------------------------------------------------------------------- + + //! @internal + //! + //! @brief Get target (emittable) from operand @a id (label id). + inline ETarget* _getTarget(uint32_t id) + { + ASMJIT_ASSERT((id & OPERAND_ID_TYPE_MASK) == OPERAND_ID_TYPE_LABEL); + return _targetData[id & OPERAND_ID_VALUE_MASK]; + } + + // -------------------------------------------------------------------------- + // [Members] + // -------------------------------------------------------------------------- + +protected: + + //! @brief Code generator. + CodeGenerator* _codeGenerator; + + //! @brief Zone memory management. + Zone _zone; + + //! @brief Logger. + Logger* _logger; + + //! @brief Last error code. + uint32_t _error; + + //! @brief Properties. + uint32_t _properties; + + //! @brief Contains options for next emitted instruction, clear after each emit. + uint32_t _emitOptions; + + //! @brief Whether compiler was finished the job (register allocator, etc...). + uint32_t _finished; + + //! @brief First emittable. + Emittable* _first; + //! @brief Last emittable. + Emittable* _last; + //! @brief Current emittable. + Emittable* _current; + + //! @brief Current function. + EFunction* _function; + + //! @brief Label data. + PodVector<ETarget*> _targetData; + + //! @brief Variable data. + PodVector<VarData*> _varData; + + //! @brief Variable name id (used to generate unique names per function). + int _varNameId; + + //! @brief Compiler context instance, only available after prepare(). + CompilerContext* _cc; + + friend struct BaseVar; + friend struct CompilerContext; + friend struct EFunction; + friend struct EInstruction; +}; + +// ============================================================================ +// [AsmJit::CompilerIntrinsics] +// ============================================================================ + +//! @brief Implementation of @c Compiler intrinsics. +//! +//! Methods in this class are implemented here, because we wan't to hide them +//! in shared libraries. These methods should be never exported by C++ compiler. +//! +//! @sa @c AsmJit::Compiler. +struct ASMJIT_HIDDEN CompilerIntrinsics : public CompilerCore +{ + // Special X86 instructions: + // - cpuid, + // - cbw, cwde, cdqe, + // - cmpxchg + // - cmpxchg8b, cmpxchg16b, + // - daa, das, + // - imul, mul, idiv, div, + // - mov_ptr + // - lahf, sahf + // - maskmovq, maskmovdqu + // - enter, leave + // - ret + // - monitor, mwait + // - pop, popad, popfd, popfq, + // - push, pushad, pushfd, pushfq + // - rcl, rcr, rol, ror, sal, sar, shl, shr + // - shld, shrd + // - rdtsc. rdtscp + // - lodsb, lodsd, lodsq, lodsw + // - movsb, movsd, movsq, movsw + // - stosb, stosd, stosq, stosw + // - cmpsb, cmpsd, cmpsq, cmpsw + // - scasb, scasd, scasq, scasw + // + // Special X87 instructions: + // - fisttp + + // -------------------------------------------------------------------------- + // [Construction / Destruction] + // -------------------------------------------------------------------------- + + //! @brief Create @c CompilerIntrinsics instance. Always use @c AsmJit::Compiler. + inline CompilerIntrinsics(CodeGenerator* codeGenerator) ASMJIT_NOTHROW : + CompilerCore(codeGenerator) + { + } + + // -------------------------------------------------------------------------- + // [Embed] + // -------------------------------------------------------------------------- + + //! @brief Add 8-bit integer data to the instuction stream. + inline void db(uint8_t x) ASMJIT_NOTHROW { embed(&x, 1); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void dw(uint16_t x) ASMJIT_NOTHROW { embed(&x, 2); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void dd(uint32_t x) ASMJIT_NOTHROW { embed(&x, 4); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void dq(uint64_t x) ASMJIT_NOTHROW { embed(&x, 8); } + + //! @brief Add 8-bit integer data to the instuction stream. + inline void dint8(int8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int8_t)); } + //! @brief Add 8-bit integer data to the instuction stream. + inline void duint8(uint8_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint8_t)); } + + //! @brief Add 16-bit integer data to the instuction stream. + inline void dint16(int16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int16_t)); } + //! @brief Add 16-bit integer data to the instuction stream. + inline void duint16(uint16_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint16_t)); } + + //! @brief Add 32-bit integer data to the instuction stream. + inline void dint32(int32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int32_t)); } + //! @brief Add 32-bit integer data to the instuction stream. + inline void duint32(uint32_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint32_t)); } + + //! @brief Add 64-bit integer data to the instuction stream. + inline void dint64(int64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(int64_t)); } + //! @brief Add 64-bit integer data to the instuction stream. + inline void duint64(uint64_t x) ASMJIT_NOTHROW { embed(&x, sizeof(uint64_t)); } + + //! @brief Add system-integer data to the instuction stream. + inline void dsysint(sysint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysint_t)); } + //! @brief Add system-integer data to the instuction stream. + inline void dsysuint(sysuint_t x) ASMJIT_NOTHROW { embed(&x, sizeof(sysuint_t)); } + + //! @brief Add float data to the instuction stream. + inline void dfloat(float x) ASMJIT_NOTHROW { embed(&x, sizeof(float)); } + //! @brief Add double data to the instuction stream. + inline void ddouble(double x) ASMJIT_NOTHROW { embed(&x, sizeof(double)); } + + //! @brief Add pointer data to the instuction stream. + inline void dptr(void* x) ASMJIT_NOTHROW { embed(&x, sizeof(void*)); } + + //! @brief Add MM data to the instuction stream. + inline void dmm(const MMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(MMData)); } + //! @brief Add XMM data to the instuction stream. + inline void dxmm(const XMMData& x) ASMJIT_NOTHROW { embed(&x, sizeof(XMMData)); } + + //! @brief Add data to the instuction stream. + inline void data(const void* data, sysuint_t size) ASMJIT_NOTHROW { embed(data, size); } + + //! @brief Add data in a given structure instance to the instuction stream. + template<typename T> + inline void dstruct(const T& x) ASMJIT_NOTHROW { embed(&x, sizeof(T)); } + + // -------------------------------------------------------------------------- + // [Custom Instructions] + // -------------------------------------------------------------------------- + + // These emitters are used by custom compiler code (register alloc / spill, + // prolog / epilog generator, ...). + + inline void emit(uint32_t code) ASMJIT_NOTHROW + { + _emitInstruction(code); + } + + inline void emit(uint32_t code, const Operand& o0) ASMJIT_NOTHROW + { + _emitInstruction(code, &o0); + } + + inline void emit(uint32_t code, const Operand& o0, const Operand& o1) ASMJIT_NOTHROW + { + _emitInstruction(code, &o0, &o1); + } + + inline void emit(uint32_t code, const Operand& o0, const Operand& o1, const Operand& o2) ASMJIT_NOTHROW + { + _emitInstruction(code, &o0, &o1, &o2); + } + + // -------------------------------------------------------------------------- + // [X86 Instructions] + // -------------------------------------------------------------------------- + + //! @brief Add with Carry. + inline void adc(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_ADC, &dst, &src); + } + //! @brief Add with Carry. + inline void adc(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_ADC, &dst, &src); + } + //! @brief Add with Carry. + inline void adc(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_ADC, &dst, &src); + } + //! @brief Add with Carry. + inline void adc(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_ADC, &dst, &src); + } + //! @brief Add with Carry. + inline void adc(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_ADC, &dst, &src); + } + + //! @brief Add. + inline void add(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_ADD, &dst, &src); + } + //! @brief Add. + inline void add(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_ADD, &dst, &src); + } + //! @brief Add. + inline void add(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_ADD, &dst, &src); + } + //! @brief Add. + inline void add(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_ADD, &dst, &src); + } + //! @brief Add. + inline void add(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_ADD, &dst, &src); + } + + //! @brief Logical And. + inline void and_(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_AND, &dst, &src); + } + //! @brief Logical And. + inline void and_(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_AND, &dst, &src); + } + //! @brief Logical And. + inline void and_(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_AND, &dst, &src); + } + //! @brief Logical And. + inline void and_(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_AND, &dst, &src); + } + //! @brief Logical And. + inline void and_(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_AND, &dst, &src); + } + + //! @brief Bit Scan Forward. + inline void bsf(const GPVar& dst, const GPVar& src) + { + ASMJIT_ASSERT(!dst.isGPB()); + _emitInstruction(INST_BSF, &dst, &src); + } + //! @brief Bit Scan Forward. + inline void bsf(const GPVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGPB()); + _emitInstruction(INST_BSF, &dst, &src); + } + + //! @brief Bit Scan Reverse. + inline void bsr(const GPVar& dst, const GPVar& src) + { + ASMJIT_ASSERT(!dst.isGPB()); + _emitInstruction(INST_BSR, &dst, &src); + } + //! @brief Bit Scan Reverse. + inline void bsr(const GPVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGPB()); + _emitInstruction(INST_BSR, &dst, &src); + } + + //! @brief Byte swap (32-bit or 64-bit registers only) (i486). + inline void bswap(const GPVar& dst) + { + // ASMJIT_ASSERT(dst.getRegType() == REG_GPD || dst.getRegType() == REG_GPQ); + _emitInstruction(INST_BSWAP, &dst); + } + + //! @brief Bit test. + inline void bt(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_BT, &dst, &src); + } + //! @brief Bit test. + inline void bt(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_BT, &dst, &src); + } + //! @brief Bit test. + inline void bt(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_BT, &dst, &src); + } + //! @brief Bit test. + inline void bt(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_BT, &dst, &src); + } + + //! @brief Bit test and complement. + inline void btc(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_BTC, &dst, &src); + } + //! @brief Bit test and complement. + inline void btc(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_BTC, &dst, &src); + } + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_BTC, &dst, &src); + } + //! @brief Bit test and complement. + inline void btc(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_BTC, &dst, &src); + } + + //! @brief Bit test and reset. + inline void btr(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_BTR, &dst, &src); + } + //! @brief Bit test and reset. + inline void btr(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_BTR, &dst, &src); + } + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_BTR, &dst, &src); + } + //! @brief Bit test and reset. + inline void btr(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_BTR, &dst, &src); + } + + //! @brief Bit test and set. + inline void bts(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_BTS, &dst, &src); + } + //! @brief Bit test and set. + inline void bts(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_BTS, &dst, &src); + } + //! @brief Bit test and set. + inline void bts(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_BTS, &dst, &src); + } + //! @brief Bit test and set. + inline void bts(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_BTS, &dst, &src); + } + + //! @brief Call Procedure. + inline ECall* call(const GPVar& dst) + { + return _emitCall(&dst); + } + //! @brief Call Procedure. + inline ECall* call(const Mem& dst) + { + return _emitCall(&dst); + } + //! @brief Call Procedure. + inline ECall* call(const Imm& dst) + { + return _emitCall(&dst); + } + //! @brief Call Procedure. + //! @overload + inline ECall* call(void* dst) + { + Imm imm((sysint_t)dst); + return _emitCall(&imm); + } + + //! @brief Call Procedure. + inline ECall* call(const Label& label) + { + return _emitCall(&label); + } + + //! @brief Convert Byte to Word (Sign Extend). + inline void cbw(const GPVar& dst) + { + _emitInstruction(INST_CBW, &dst); + } + + //! @brief Convert Word to DWord (Sign Extend). + inline void cwde(const GPVar& dst) + { + _emitInstruction(INST_CWDE, &dst); + } + +#if defined(ASMJIT_X64) + //! @brief Convert DWord to QWord (Sign Extend). + inline void cdqe(const GPVar& dst) + { + _emitInstruction(INST_CDQE, &dst); + } +#endif // ASMJIT_X64 + + //! @brief Clear Carry flag + //! + //! This instruction clears the CF flag in the EFLAGS register. + inline void clc() + { + _emitInstruction(INST_CLC); + } + + //! @brief Clear Direction flag + //! + //! This instruction clears the DF flag in the EFLAGS register. + inline void cld() + { + _emitInstruction(INST_CLD); + } + + //! @brief Complement Carry Flag. + //! + //! This instruction complements the CF flag in the EFLAGS register. + //! (CF = NOT CF) + inline void cmc() + { + _emitInstruction(INST_CMC); + } + + //! @brief Conditional Move. + inline void cmov(CONDITION cc, const GPVar& dst, const GPVar& src) + { + _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); + } + + //! @brief Conditional Move. + inline void cmov(CONDITION cc, const GPVar& dst, const Mem& src) + { + _emitInstruction(ConditionToInstruction::toCMovCC(cc), &dst, &src); + } + + //! @brief Conditional Move. + inline void cmova (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVA , &dst, &src); } + //! @brief Conditional Move. + inline void cmova (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovae (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVAE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovb (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovbe (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVBE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovc (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVC , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVE , &dst, &src); } + //! @brief Conditional Move. + inline void cmove (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovg (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovge (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVGE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovl (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovle (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVLE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovna (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNA , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnae(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNAE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnb (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNB , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnbe(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNBE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnc (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNC , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovne (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovng (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNG , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnge(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNGE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnl (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNL , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovnle(const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNLE, &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovno (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnp (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovns (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovnz (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVNZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovo (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovp (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVP , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpe (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVPE , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovpo (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVPO , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovs (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVS , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GPVar& dst, const GPVar& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } + //! @brief Conditional Move. + inline void cmovz (const GPVar& dst, const Mem& src) { _emitInstruction(INST_CMOVZ , &dst, &src); } + + //! @brief Compare Two Operands. + inline void cmp(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_CMP, &dst, &src); + } + //! @brief Compare Two Operands. + inline void cmp(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CMP, &dst, &src); + } + //! @brief Compare Two Operands. + inline void cmp(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_CMP, &dst, &src); + } + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_CMP, &dst, &src); + } + //! @brief Compare Two Operands. + inline void cmp(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_CMP, &dst, &src); + } + + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const GPVar cmp_1_eax, const GPVar& cmp_2, const GPVar& src) + { + ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); + _emitInstruction(INST_CMPXCHG, &cmp_1_eax, &cmp_2, &src); + } + //! @brief Compare and Exchange (i486). + inline void cmpxchg(const GPVar cmp_1_eax, const Mem& cmp_2, const GPVar& src) + { + ASMJIT_ASSERT(cmp_1_eax.getId() != src.getId()); + _emitInstruction(INST_CMPXCHG, &cmp_1_eax, &cmp_2, &src); + } + + //! @brief Compares the 64-bit value in EDX:EAX with the memory operand (Pentium). + //! + //! If the values are equal, then this instruction stores the 64-bit value + //! in ECX:EBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 64-bit memory operand into the EDX:EAX + //! registers and clears the zero flag. + inline void cmpxchg8b( + const GPVar& cmp_edx, const GPVar& cmp_eax, + const GPVar& cmp_ecx, const GPVar& cmp_ebx, + const Mem& dst) + { + ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && + cmp_eax.getId() != cmp_ecx.getId() && + cmp_ecx.getId() != cmp_ebx.getId()); + + _emitInstruction(INST_CMPXCHG8B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); + } + +#if defined(ASMJIT_X64) + //! @brief Compares the 128-bit value in RDX:RAX with the memory operand (X64). + //! + //! If the values are equal, then this instruction stores the 128-bit value + //! in RCX:RBX into the memory operand and sets the zero flag. Otherwise, + //! this instruction copies the 128-bit memory operand into the RDX:RAX + //! registers and clears the zero flag. + inline void cmpxchg16b( + const GPVar& cmp_edx, const GPVar& cmp_eax, + const GPVar& cmp_ecx, const GPVar& cmp_ebx, + const Mem& dst) + { + ASMJIT_ASSERT(cmp_edx.getId() != cmp_eax.getId() && + cmp_eax.getId() != cmp_ecx.getId() && + cmp_ecx.getId() != cmp_ebx.getId()); + + _emitInstruction(INST_CMPXCHG16B, &cmp_edx, &cmp_eax, &cmp_ecx, &cmp_ebx, &dst); + } +#endif // ASMJIT_X64 + + //! @brief CPU Identification (i486). + inline void cpuid( + const GPVar& inout_eax, + const GPVar& out_ebx, + const GPVar& out_ecx, + const GPVar& out_edx) + { + // Destination variables must be different. + ASMJIT_ASSERT(inout_eax.getId() != out_ebx.getId() && + out_ebx.getId() != out_ecx.getId() && + out_ecx.getId() != out_edx.getId()); + + _emitInstruction(INST_CPUID, &inout_eax, &out_ebx, &out_ecx, &out_edx); + } + +#if defined(ASMJIT_X86) + inline void daa(const GPVar& dst) + { + _emitInstruction(INST_DAA, &dst); + } +#endif // ASMJIT_X86 + +#if defined(ASMJIT_X86) + inline void das(const GPVar& dst) + { + _emitInstruction(INST_DAS, &dst); + } +#endif // ASMJIT_X86 + + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const GPVar& dst) + { + _emitInstruction(INST_DEC, &dst); + } + //! @brief Decrement by 1. + //! @note This instruction can be slower than sub(dst, 1) + inline void dec(const Mem& dst) + { + _emitInstruction(INST_DEC, &dst); + } + + //! @brief Unsigned divide. + //! + //! This instruction divides (unsigned) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void div_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const GPVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_DIV, &dst_lo, &dst_hi, &src); + } + //! @brief Unsigned divide. + //! @overload + inline void div_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_DIV, &dst_lo, &dst_hi, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Make Stack Frame for Procedure Parameters. + inline void enter(const Imm& imm16, const Imm& imm8) + { + _emitInstruction(INST_ENTER, &imm16, &imm8); + } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Signed divide. + //! + //! This instruction divides (signed) the value in the AL, AX, or EAX + //! register by the source operand and stores the result in the AX, + //! DX:AX, or EDX:EAX registers. + inline void idiv_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const GPVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_IDIV, &dst_lo, &dst_hi, &src); + } + //! @brief Signed divide. + //! @overload + inline void idiv_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_IDIV, &dst_lo, &dst_hi, &src); + } + + //! @brief Signed multiply. + //! + //! [dst_lo:dst_hi] = dst_hi * src. + inline void imul_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const GPVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_IMUL, &dst_lo, &dst_hi, &src); + } + //! @overload + inline void imul_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_IMUL, &dst_lo, &dst_hi, &src); + } + + //! @brief Signed multiply. + //! + //! Destination operand (the first operand) is multiplied by the source + //! operand (second operand). The destination operand is a general-purpose + //! register and the source operand is an immediate value, a general-purpose + //! register, or a memory location. The product is then stored in the + //! destination operand location. + inline void imul(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_IMUL, &dst, &src); + } + //! @brief Signed multiply. + //! @overload + inline void imul(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_IMUL, &dst, &src); + } + //! @brief Signed multiply. + //! @overload + inline void imul(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_IMUL, &dst, &src); + } + + //! @brief Signed multiply. + //! + //! source operand (which can be a general-purpose register or a memory + //! location) is multiplied by the second source operand (an immediate + //! value). The product is then stored in the destination operand + //! (a general-purpose register). + inline void imul(const GPVar& dst, const GPVar& src, const Imm& imm) + { + _emitInstruction(INST_IMUL, &dst, &src, &imm); + } + //! @overload + inline void imul(const GPVar& dst, const Mem& src, const Imm& imm) + { + _emitInstruction(INST_IMUL, &dst, &src, &imm); + } + + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const GPVar& dst) + { + _emitInstruction(INST_INC, &dst); + } + //! @brief Increment by 1. + //! @note This instruction can be slower than add(dst, 1) + inline void inc(const Mem& dst) + { + _emitInstruction(INST_INC, &dst); + } + + //! @brief Interrupt 3 - trap to debugger. + inline void int3() + { + _emitInstruction(INST_INT3); + } + + //! @brief Jump to label @a label if condition @a cc is met. + //! + //! This instruction checks the state of one or more of the status flags in + //! the EFLAGS register (CF, OF, PF, SF, and ZF) and, if the flags are in the + //! specified state (condition), performs a jump to the target instruction + //! specified by the destination operand. A condition code (cc) is associated + //! with each instruction to indicate the condition being tested for. If the + //! condition is not satisfied, the jump is not performed and execution + //! continues with the instruction following the Jcc instruction. + inline void j(CONDITION cc, const Label& label, uint32_t hint = HINT_NONE) + { + _emitJcc(ConditionToInstruction::toJCC(cc), &label, hint); + } + + //! @brief Jump to label @a label if condition is met. + inline void ja (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jae (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JAE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jbe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JBE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void je (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jg (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jge (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JGE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jle (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JLE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jna (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNA , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnae(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNAE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnb (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNB , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnbe(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNBE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnc (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNC , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jne (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jng (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNG , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnge(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNGE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnl (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNL , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnle(const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNLE, &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jno (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jns (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jnz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JNZ , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jp (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JP , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpe (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPE , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jpo (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JPO , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void js (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JS , &label, hint); } + //! @brief Jump to label @a label if condition is met. + inline void jz (const Label& label, uint32_t hint = HINT_NONE) { _emitJcc(INST_JZ , &label, hint); } + + //! @brief Jump. + //! @overload + inline void jmp(const GPVar& dst) + { + _emitInstruction(INST_JMP, &dst); + } + //! @brief Jump. + //! @overload + inline void jmp(const Mem& dst) + { + _emitInstruction(INST_JMP, &dst); + } + //! @brief Jump. + //! @overload + inline void jmp(const Imm& dst) + { + _emitInstruction(INST_JMP, &dst); + } + + //! @brief Jump. + //! @overload + inline void jmp(void* dst) + { + Imm imm((sysint_t)dst); + _emitInstruction(INST_JMP, &imm); + } + + //! @brief Jump. + //! + //! This instruction transfers program control to a different point + //! in the instruction stream without recording return information. + //! The destination (target) operand specifies the label of the + //! instruction being jumped to. + inline void jmp(const Label& label) + { + _emitInstruction(INST_JMP, &label); + } + //! @brief Load Effective Address + //! + //! This instruction computes the effective address of the second + //! operand (the source operand) and stores it in the first operand + //! (destination operand). The source operand is a memory address + //! (offset part) specified with one of the processors addressing modes. + //! The destination operand is a general-purpose register. + inline void lea(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_LEA, &dst, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief High Level Procedure Exit. + inline void leave() + { + _emitInstruction(INST_LEAVE); + } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Move. + //! + //! This instruction copies the second operand (source operand) to the first + //! operand (destination operand). The source operand can be an immediate + //! value, general-purpose register, segment register, or memory location. + //! The destination register can be a general-purpose register, segment + //! register, or memory location. Both operands must be the same size, which + //! can be a byte, a word, or a DWORD. + //! + //! @note To move MMX or SSE registers to/from GP registers or memory, use + //! corresponding functions: @c movd(), @c movq(), etc. Passing MMX or SSE + //! registers to @c mov() is illegal. + inline void mov(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOV, &dst, &src); + } + //! @brief Move. + //! @overload + inline void mov(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_MOV, &dst, &src); + } + //! @brief Move. + //! @overload + inline void mov(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_MOV, &dst, &src); + } + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_MOV, &dst, &src); + } + //! @brief Move. + //! @overload + inline void mov(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_MOV, &dst, &src); + } + + //! @brief Move byte, word, dword or qword from absolute address @a src to + //! AL, AX, EAX or RAX register. + inline void mov_ptr(const GPVar& dst, void* src) + { + Imm imm((sysint_t)src); + _emitInstruction(INST_MOV_PTR, &dst, &imm); + } + + //! @brief Move byte, word, dword or qword from AL, AX, EAX or RAX register + //! to absolute address @a dst. + inline void mov_ptr(void* dst, const GPVar& src) + { + Imm imm((sysint_t)dst); + _emitInstruction(INST_MOV_PTR, &imm, &src); + } + + //! @brief Move with Sign-Extension. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and sign + //! extends the value to 16, 32 or 64-bits. + //! + //! @sa movsxd(). + void movsx(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVSX, &dst, &src); + } + //! @brief Move with Sign-Extension. + //! @overload + void movsx(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSX, &dst, &src); + } + +#if defined(ASMJIT_X64) + //! @brief Move DWord to QWord with sign-extension. + inline void movsxd(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVSXD, &dst, &src); + } + //! @brief Move DWord to QWord with sign-extension. + //! @overload + inline void movsxd(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSXD, &dst, &src); + } +#endif // ASMJIT_X64 + + //! @brief Move with Zero-Extend. + //! + //! This instruction copies the contents of the source operand (register + //! or memory location) to the destination operand (register) and zero + //! extends the value to 16 or 32-bits. The size of the converted value + //! depends on the operand-size attribute. + inline void movzx(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVZX, &dst, &src); + } + //! @brief Move with Zero-Extend. + //! @brief Overload + inline void movzx(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVZX, &dst, &src); + } + + //! @brief Unsigned multiply. + //! + //! Source operand (in a general-purpose register or memory location) + //! is multiplied by the value in the AL, AX, or EAX register (depending + //! on the operand size) and the product is stored in the AX, DX:AX, or + //! EDX:EAX registers, respectively. + inline void mul_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const GPVar& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_MUL, &dst_lo, &dst_hi, &src); + } + //! @brief Unsigned multiply. + //! @overload + inline void mul_lo_hi(const GPVar& dst_lo, const GPVar& dst_hi, const Mem& src) + { + // Destination variables must be different. + ASMJIT_ASSERT(dst_lo.getId() != dst_hi.getId()); + + _emitInstruction(INST_MUL, &dst_lo, &dst_hi, &src); + } + + //! @brief Two's Complement Negation. + inline void neg(const GPVar& dst) + { + _emitInstruction(INST_NEG, &dst); + } + //! @brief Two's Complement Negation. + inline void neg(const Mem& dst) + { + _emitInstruction(INST_NEG, &dst); + } + + //! @brief No Operation. + //! + //! This instruction performs no operation. This instruction is a one-byte + //! instruction that takes up space in the instruction stream but does not + //! affect the machine context, except the EIP register. The NOP instruction + //! is an alias mnemonic for the XCHG (E)AX, (E)AX instruction. + inline void nop() + { + _emitInstruction(INST_NOP); + } + + //! @brief One's Complement Negation. + inline void not_(const GPVar& dst) + { + _emitInstruction(INST_NOT, &dst); + } + //! @brief One's Complement Negation. + inline void not_(const Mem& dst) + { + _emitInstruction(INST_NOT, &dst); + } + + //! @brief Logical Inclusive OR. + inline void or_(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_OR, &dst, &src); + } + //! @brief Logical Inclusive OR. + inline void or_(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_OR, &dst, &src); + } + //! @brief Logical Inclusive OR. + inline void or_(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_OR, &dst, &src); + } + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_OR, &dst, &src); + } + //! @brief Logical Inclusive OR. + inline void or_(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_OR, &dst, &src); + } + + //! @brief Pop a Value from the Stack. + //! + //! This instruction loads the value from the top of the stack to the location + //! specified with the destination operand and then increments the stack pointer. + //! The destination operand can be a general purpose register, memory location, + //! or segment register. + inline void pop(const GPVar& dst) + { + _emitInstruction(INST_POP, &dst); + } + + inline void pop(const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() == 2 || dst.getSize() == sizeof(sysint_t)); + _emitInstruction(INST_POP, &dst); + } + +#if defined(ASMJIT_X86) + //! @brief Pop All General-Purpose Registers. + //! + //! Pop EDI, ESI, EBP, EBX, EDX, ECX, and EAX. + inline void popad() + { + _emitInstruction(INST_POPAD); + } +#endif // ASMJIT_X86 + + //! @brief Pop Stack into EFLAGS Register (32-bit or 64-bit). + inline void popf() + { +#if defined(ASMJIT_X86) + popfd(); +#else + popfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Pop Stack into EFLAGS Register (32-bit). + inline void popfd() { _emitInstruction(INST_POPFD); } +#else + //! @brief Pop Stack into EFLAGS Register (64-bit). + inline void popfq() { _emitInstruction(INST_POPFQ); } +#endif + + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + //! + //! @note 32-bit architecture pushed DWORD while 64-bit + //! pushes QWORD. 64-bit mode not provides instruction to + //! push 32-bit register/memory. + inline void push(const GPVar& src) + { + _emitInstruction(INST_PUSH, &src); + } + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Mem& src) + { + ASMJIT_ASSERT(src.getSize() == 2 || src.getSize() == sizeof(sysint_t)); + _emitInstruction(INST_PUSH, &src); + } + //! @brief Push WORD/DWORD/QWORD Onto the Stack. + inline void push(const Imm& src) + { + _emitInstruction(INST_PUSH, &src); + } + +#if defined(ASMJIT_X86) + //! @brief Push All General-Purpose Registers. + //! + //! Push EAX, ECX, EDX, EBX, original ESP, EBP, ESI, and EDI. + inline void pushad() + { + _emitInstruction(INST_PUSHAD); + } +#endif // ASMJIT_X86 + + //! @brief Push EFLAGS Register (32-bit or 64-bit) onto the Stack. + inline void pushf() + { +#if defined(ASMJIT_X86) + pushfd(); +#else + pushfq(); +#endif + } + +#if defined(ASMJIT_X86) + //! @brief Push EFLAGS Register (32-bit) onto the Stack. + inline void pushfd() { _emitInstruction(INST_PUSHFD); } +#else + //! @brief Push EFLAGS Register (64-bit) onto the Stack. + inline void pushfq() { _emitInstruction(INST_PUSHFQ); } +#endif // ASMJIT_X86 + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_RCL, &dst, &src); + } + //! @brief Rotate Bits Left. + inline void rcl(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_RCL, &dst, &src); + } + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rcl(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_RCL, &dst, &src); + } + //! @brief Rotate Bits Left. + inline void rcl(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_RCL, &dst, &src); + } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_RCR, &dst, &src); + } + //! @brief Rotate Bits Right. + inline void rcr(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_RCR, &dst, &src); + } + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void rcr(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_RCR, &dst, &src); + } + //! @brief Rotate Bits Right. + inline void rcr(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_RCR, &dst, &src); + } + + //! @brief Read Time-Stamp Counter (Pentium). + inline void rdtsc(const GPVar& dst_edx, const GPVar& dst_eax) + { + // Destination registers must be different. + ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId()); + + _emitInstruction(INST_RDTSC, &dst_edx, &dst_eax); + } + + //! @brief Read Time-Stamp Counter and Processor ID (New). + inline void rdtscp(const GPVar& dst_edx, const GPVar& dst_eax, const GPVar& dst_ecx) + { + // Destination registers must be different. + ASMJIT_ASSERT(dst_edx.getId() != dst_eax.getId() && + dst_eax.getId() != dst_ecx.getId()); + + _emitInstruction(INST_RDTSCP, &dst_edx, &dst_eax, &dst_ecx); + } + + //! @brief Load ECX/RCX BYTEs from DS:[ESI/RSI] to AL. + inline void rep_lodsb(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_LODSB, &dst_val, &src_addr, &cnt_ecx); + } + + //! @brief Load ECX/RCX DWORDs from DS:[ESI/RSI] to EAX. + inline void rep_lodsd(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_LODSD, &dst_val, &src_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Load ECX/RCX QWORDs from DS:[ESI/RSI] to RAX. + inline void rep_lodsq(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_LODSQ, &dst_val, &src_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + //! @brief Load ECX/RCX WORDs from DS:[ESI/RSI] to AX. + inline void rep_lodsw(const GPVar& dst_val, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=EAX,RAX, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_val.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_LODSW, &dst_val, &src_addr, &cnt_ecx); + } + + //! @brief Move ECX/RCX BYTEs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsb(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_MOVSB, &dst_addr, &src_addr, &cnt_ecx); + } + + //! @brief Move ECX/RCX DWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsd(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_MOVSD, &dst_addr, &src_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Move ECX/RCX QWORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsq(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_MOVSQ, &dst_addr, &src_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Move ECX/RCX WORDs from DS:[ESI/RSI] to ES:[EDI/RDI]. + inline void rep_movsw(const GPVar& dst_addr, const GPVar& src_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=DS:ESI/RSI, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_addr.getId() && src_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_MOVSW, &dst_addr, &src_addr, &cnt_ecx); + } + + //! @brief Fill ECX/RCX BYTEs at ES:[EDI/RDI] with AL. + inline void rep_stosb(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_STOSB, &dst_addr, &src_val, &cnt_ecx); + } + + //! @brief Fill ECX/RCX DWORDs at ES:[EDI/RDI] with EAX. + inline void rep_stosd(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_STOSD, &dst_addr, &src_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Fill ECX/RCX QWORDs at ES:[EDI/RDI] with RAX. + inline void rep_stosq(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_STOSQ, &dst_addr, &src_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Fill ECX/RCX WORDs at ES:[EDI/RDI] with AX. + inline void rep_stosw(const GPVar& dst_addr, const GPVar& src_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to dst=ES:EDI,RDI, src=EAX/RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(dst_addr.getId() != src_val.getId() && src_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REP_STOSW, &dst_addr, &src_val, &cnt_ecx); + } + + //! @brief Repeated find nonmatching BYTEs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsb(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_CMPSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Repeated find nonmatching DWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsd(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_CMPSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Repeated find nonmatching QWORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsq(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_CMPSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Repeated find nonmatching WORDs in ES:[EDI/RDI] and DS:[ESI/RDI]. + inline void repe_cmpsw(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_CMPSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find non-AL BYTE starting at ES:[EDI/RDI]. + inline void repe_scasb(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_SCASB, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find non-EAX DWORD starting at ES:[EDI/RDI]. + inline void repe_scasd(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_SCASD, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find non-RAX QWORD starting at ES:[EDI/RDI]. + inline void repe_scasq(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_SCASQ, &cmp1_addr, &cmp2_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find non-AX WORD starting at ES:[EDI/RDI]. + inline void repe_scasw(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPE_SCASW, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find matching BYTEs in [RDI] and [RSI]. + inline void repne_cmpsb(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_CMPSB, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find matching DWORDs in [RDI] and [RSI]. + inline void repne_cmpsd(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_CMPSD, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find matching QWORDs in [RDI] and [RSI]. + inline void repne_cmpsq(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_CMPSQ, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find matching WORDs in [RDI] and [RSI]. + inline void repne_cmpsw(const GPVar& cmp1_addr, const GPVar& cmp2_addr, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, cmp2=ES:[EDI/RDI], cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_addr.getId() && cmp2_addr.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_CMPSW, &cmp1_addr, &cmp2_addr, &cnt_ecx); + } + + //! @brief Find AL, starting at ES:[EDI/RDI]. + inline void repne_scasb(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AL, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_SCASB, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Find EAX, starting at ES:[EDI/RDI]. + inline void repne_scasd(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=EAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_SCASD, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + +#if defined(ASMJIT_X64) + //! @brief Find RAX, starting at ES:[EDI/RDI]. + inline void repne_scasq(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=RAX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_SCASQ, &cmp1_addr, &cmp2_val, &cnt_ecx); + } +#endif // ASMJIT_X64 + + //! @brief Find AX, starting at ES:[EDI/RDI]. + inline void repne_scasw(const GPVar& cmp1_addr, const GPVar& cmp2_val, const GPVar& cnt_ecx) + { + // All registers must be unique, they will be reallocated to cmp1=ES:EDI,RDI, src=AX, cnt=ECX/RCX. + ASMJIT_ASSERT(cmp1_addr.getId() != cmp2_val.getId() && cmp2_val.getId() != cnt_ecx.getId()); + + _emitInstruction(INST_REPNE_SCASW, &cmp1_addr, &cmp2_val, &cnt_ecx); + } + + //! @brief Return from Procedure. + inline void ret() + { + _emitReturn(NULL, NULL); + } + + //! @brief Return from Procedure. + inline void ret(const GPVar& first) + { + _emitReturn(&first, NULL); + } + + //! @brief Return from Procedure. + inline void ret(const GPVar& first, const GPVar& second) + { + _emitReturn(&first, &second); + } + + //! @brief Return from Procedure. + inline void ret(const XMMVar& first) + { + _emitReturn(&first, NULL); + } + + //! @brief Return from Procedure. + inline void ret(const XMMVar& first, const XMMVar& second) + { + _emitReturn(&first, &second); + } + + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_ROL, &dst, &src); + } + //! @brief Rotate Bits Left. + inline void rol(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_ROL, &dst, &src); + } + //! @brief Rotate Bits Left. + //! @note @a src register can be only @c cl. + inline void rol(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_ROL, &dst, &src); + } + //! @brief Rotate Bits Left. + inline void rol(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_ROL, &dst, &src); + } + + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_ROR, &dst, &src); + } + //! @brief Rotate Bits Right. + inline void ror(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_ROR, &dst, &src); + } + //! @brief Rotate Bits Right. + //! @note @a src register can be only @c cl. + inline void ror(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_ROR, &dst, &src); + } + //! @brief Rotate Bits Right. + inline void ror(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_ROR, &dst, &src); + } + +#if defined(ASMJIT_X86) + //! @brief Store @a var (allocated to AH/AX/EAX/RAX) into Flags. + inline void sahf(const GPVar& var) + { + _emitInstruction(INST_SAHF, &var); + } +#endif // ASMJIT_X86 + + //! @brief Integer subtraction with borrow. + inline void sbb(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SBB, &dst, &src); + } + //! @brief Integer subtraction with borrow. + inline void sbb(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_SBB, &dst, &src); + } + //! @brief Integer subtraction with borrow. + inline void sbb(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SBB, &dst, &src); + } + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SBB, &dst, &src); + } + //! @brief Integer subtraction with borrow. + inline void sbb(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SBB, &dst, &src); + } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SAL, &dst, &src); + } + //! @brief Shift Bits Left. + inline void sal(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SAL, &dst, &src); + } + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void sal(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SAL, &dst, &src); + } + //! @brief Shift Bits Left. + inline void sal(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SAL, &dst, &src); + } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SAR, &dst, &src); + } + //! @brief Shift Bits Right. + inline void sar(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SAR, &dst, &src); + } + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void sar(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SAR, &dst, &src); + } + //! @brief Shift Bits Right. + inline void sar(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SAR, &dst, &src); + } + + //! @brief Set Byte on Condition. + inline void set(CONDITION cc, const GPVar& dst) + { + ASMJIT_ASSERT(dst.getSize() == 1); + _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void set(CONDITION cc, const Mem& dst) + { + ASMJIT_ASSERT(dst.getSize() <= 1); + _emitInstruction(ConditionToInstruction::toSetCC(cc), &dst); + } + + //! @brief Set Byte on Condition. + inline void seta (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETA , &dst); } + //! @brief Set Byte on Condition. + inline void seta (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETA , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETAE , &dst); } + //! @brief Set Byte on Condition. + inline void setae (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETAE , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETB , &dst); } + //! @brief Set Byte on Condition. + inline void setb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETB , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETBE , &dst); } + //! @brief Set Byte on Condition. + inline void setbe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETBE , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETC , &dst); } + //! @brief Set Byte on Condition. + inline void setc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETC , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETE , &dst); } + //! @brief Set Byte on Condition. + inline void sete (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETE , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETG , &dst); } + //! @brief Set Byte on Condition. + inline void setg (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETG , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETGE , &dst); } + //! @brief Set Byte on Condition. + inline void setge (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETGE , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETL , &dst); } + //! @brief Set Byte on Condition. + inline void setl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETL , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETLE , &dst); } + //! @brief Set Byte on Condition. + inline void setle (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETLE , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNA , &dst); } + //! @brief Set Byte on Condition. + inline void setna (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNA , &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnae(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNAE, &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnb (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNB , &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnbe(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNBE, &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNC , &dst); } + //! @brief Set Byte on Condition. + inline void setnc (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNC , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNE , &dst); } + //! @brief Set Byte on Condition. + inline void setne (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNE , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNG , &dst); } + //! @brief Set Byte on Condition. + inline void setng (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNG , &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnge(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNGE, &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnl (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNL , &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setnle(const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNLE, &dst); } + //! @brief Set Byte on Condition. + inline void setno (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNO , &dst); } + //! @brief Set Byte on Condition. + inline void setno (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNO , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNP , &dst); } + //! @brief Set Byte on Condition. + inline void setnp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNP , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNS , &dst); } + //! @brief Set Byte on Condition. + inline void setns (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNS , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETNZ , &dst); } + //! @brief Set Byte on Condition. + inline void setnz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETNZ , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETO , &dst); } + //! @brief Set Byte on Condition. + inline void seto (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETO , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETP , &dst); } + //! @brief Set Byte on Condition. + inline void setp (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETP , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpe (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPE , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETPO , &dst); } + //! @brief Set Byte on Condition. + inline void setpo (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETPO , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETS , &dst); } + //! @brief Set Byte on Condition. + inline void sets (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETS , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const GPVar& dst) { ASMJIT_ASSERT(dst.getSize() == 1); _emitInstruction(INST_SETZ , &dst); } + //! @brief Set Byte on Condition. + inline void setz (const Mem& dst) { ASMJIT_ASSERT(dst.getSize() <= 1); _emitInstruction(INST_SETZ , &dst); } + + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SHL, &dst, &src); + } + //! @brief Shift Bits Left. + inline void shl(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SHL, &dst, &src); + } + //! @brief Shift Bits Left. + //! @note @a src register can be only @c cl. + inline void shl(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SHL, &dst, &src); + } + //! @brief Shift Bits Left. + inline void shl(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SHL, &dst, &src); + } + + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SHR, &dst, &src); + } + //! @brief Shift Bits Right. + inline void shr(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SHR, &dst, &src); + } + //! @brief Shift Bits Right. + //! @note @a src register can be only @c cl. + inline void shr(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SHR, &dst, &src); + } + //! @brief Shift Bits Right. + inline void shr(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SHR, &dst, &src); + } + + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const GPVar& dst, const GPVar& src1, const GPVar& src2) + { + _emitInstruction(INST_SHLD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Left. + inline void shld(const GPVar& dst, const GPVar& src1, const Imm& src2) + { + _emitInstruction(INST_SHLD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Left. + //! @note src2 register can be only @c cl register. + inline void shld(const Mem& dst, const GPVar& src1, const GPVar& src2) + { + _emitInstruction(INST_SHLD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Left. + inline void shld(const Mem& dst, const GPVar& src1, const Imm& src2) + { + _emitInstruction(INST_SHLD, &dst, &src1, &src2); + } + + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const GPVar& dst, const GPVar& src1, const GPVar& src2) + { + _emitInstruction(INST_SHRD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Right. + inline void shrd(const GPVar& dst, const GPVar& src1, const Imm& src2) + { + _emitInstruction(INST_SHRD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Right. + //! @note src2 register can be only @c cl register. + inline void shrd(const Mem& dst, const GPVar& src1, const GPVar& src2) + { + _emitInstruction(INST_SHRD, &dst, &src1, &src2); + } + //! @brief Double Precision Shift Right. + inline void shrd(const Mem& dst, const GPVar& src1, const Imm& src2) + { + _emitInstruction(INST_SHRD, &dst, &src1, &src2); + } + + //! @brief Set Carry Flag to 1. + inline void stc() + { + _emitInstruction(INST_STC); + } + + //! @brief Set Direction Flag to 1. + inline void std() + { + _emitInstruction(INST_STD); + } + + //! @brief Subtract. + inline void sub(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_SUB, &dst, &src); + } + //! @brief Subtract. + inline void sub(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_SUB, &dst, &src); + } + //! @brief Subtract. + inline void sub(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_SUB, &dst, &src); + } + //! @brief Subtract. + inline void sub(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_SUB, &dst, &src); + } + //! @brief Subtract. + inline void sub(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_SUB, &dst, &src); + } + + //! @brief Logical Compare. + inline void test(const GPVar& op1, const GPVar& op2) + { + _emitInstruction(INST_TEST, &op1, &op2); + } + //! @brief Logical Compare. + inline void test(const GPVar& op1, const Imm& op2) + { + _emitInstruction(INST_TEST, &op1, &op2); + } + //! @brief Logical Compare. + inline void test(const Mem& op1, const GPVar& op2) + { + _emitInstruction(INST_TEST, &op1, &op2); + } + //! @brief Logical Compare. + inline void test(const Mem& op1, const Imm& op2) + { + _emitInstruction(INST_TEST, &op1, &op2); + } + + //! @brief Undefined instruction - Raise invalid opcode exception. + inline void ud2() + { + _emitInstruction(INST_UD2); + } + + //! @brief Exchange and Add. + inline void xadd(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_XADD, &dst, &src); + } + //! @brief Exchange and Add. + inline void xadd(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_XADD, &dst, &src); + } + + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_XCHG, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xchg(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_XCHG, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xchg(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_XCHG, &src, &dst); + } + + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_XOR, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_XOR, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const GPVar& dst, const Imm& src) + { + _emitInstruction(INST_XOR, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_XOR, &dst, &src); + } + //! @brief Exchange Register/Memory with Register. + inline void xor_(const Mem& dst, const Imm& src) + { + _emitInstruction(INST_XOR, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [MMX] + // -------------------------------------------------------------------------- + + //! @brief Empty MMX state. + inline void emms() + { + _emitInstruction(INST_EMMS); + } + + //! @brief Move DWord (MMX). + inline void movd(const Mem& dst, const MMVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord (MMX). + inline void movd(const GPVar& dst, const MMVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord (MMX). + inline void movd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord (MMX). + inline void movd(const MMVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + + //! @brief Move QWord (MMX). + inline void movq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } + //! @brief Move QWord (MMX). + inline void movq(const Mem& dst, const MMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const GPVar& dst, const MMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#endif + //! @brief Move QWord (MMX). + inline void movq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#if defined(ASMJIT_X64) + //! @brief Move QWord (MMX). + inline void movq(const MMVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#endif + + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PACKUSWB, &dst, &src); + } + //! @brief Pack with Unsigned Saturation (MMX). + inline void packuswb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PACKUSWB, &dst, &src); + } + + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDB, &dst, &src); + } + //! @brief Packed BYTE Add (MMX). + inline void paddb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDB, &dst, &src); + } + + //! @brief Packed WORD Add (MMX). + inline void paddw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDW, &dst, &src); + } + //! @brief Packed WORD Add (MMX). + inline void paddw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDW, &dst, &src); + } + + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDD, &dst, &src); + } + //! @brief Packed DWORD Add (MMX). + inline void paddd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDD, &dst, &src); + } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDSB, &dst, &src); + } + //! @brief Packed Add with Saturation (MMX). + inline void paddsb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDSB, &dst, &src); + } + + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDSW, &dst, &src); + } + //! @brief Packed Add with Saturation (MMX). + inline void paddsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDSW, &dst, &src); + } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDUSB, &dst, &src); + } + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDUSB, &dst, &src); + } + + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDUSW, &dst, &src); + } + //! @brief Packed Add Unsigned with Saturation (MMX). + inline void paddusw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDUSW, &dst, &src); + } + + //! @brief Logical AND (MMX). + inline void pand(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PAND, &dst, &src); + } + //! @brief Logical AND (MMX). + inline void pand(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAND, &dst, &src); + } + + //! @brief Logical AND Not (MMX). + inline void pandn(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PANDN, &dst, &src); + } + //! @brief Logical AND Not (MMX). + inline void pandn(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PANDN, &dst, &src); + } + + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPEQB, &dst, &src); + } + //! @brief Packed Compare for Equal (BYTES) (MMX). + inline void pcmpeqb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQB, &dst, &src); + } + + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPEQW, &dst, &src); + } + //! @brief Packed Compare for Equal (WORDS) (MMX). + inline void pcmpeqw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQW, &dst, &src); + } + + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPEQD, &dst, &src); + } + //! @brief Packed Compare for Equal (DWORDS) (MMX). + inline void pcmpeqd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQD, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPGTB, &dst, &src); + } + //! @brief Packed Compare for Greater Than (BYTES) (MMX). + inline void pcmpgtb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTB, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPGTW, &dst, &src); + } + //! @brief Packed Compare for Greater Than (WORDS) (MMX). + inline void pcmpgtw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTW, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PCMPGTD, &dst, &src); + } + //! @brief Packed Compare for Greater Than (DWORDS) (MMX). + inline void pcmpgtd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTD, &dst, &src); + } + + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMULHW, &dst, &src); + } + //! @brief Packed Multiply High (MMX). + inline void pmulhw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHW, &dst, &src); + } + + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMULLW, &dst, &src); + } + //! @brief Packed Multiply Low (MMX). + inline void pmullw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULLW, &dst, &src); + } + + //! @brief Bitwise Logical OR (MMX). + inline void por(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_POR, &dst, &src); + } + //! @brief Bitwise Logical OR (MMX). + inline void por(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_POR, &dst, &src); + } + + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMADDWD, &dst, &src); + } + //! @brief Packed Multiply and Add (MMX). + inline void pmaddwd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMADDWD, &dst, &src); + } + + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void pslld(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void psllq(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + //! @brief Packed Shift Left Logical (MMX). + inline void psllw(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psrad(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (MMX). + inline void psraw(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrld(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlq(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + //! @brief Packed Shift Right Logical (MMX). + inline void psrlw(const MMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + + //! @brief Packed Subtract (MMX). + inline void psubb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBB, &dst, &src); + } + //! @brief Packed Subtract (MMX). + inline void psubb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBB, &dst, &src); + } + + //! @brief Packed Subtract (MMX). + inline void psubw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBW, &dst, &src); + } + //! @brief Packed Subtract (MMX). + inline void psubw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBW, &dst, &src); + } + + //! @brief Packed Subtract (MMX). + inline void psubd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBD, &dst, &src); + } + //! @brief Packed Subtract (MMX). + inline void psubd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBD, &dst, &src); + } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBSB, &dst, &src); + } + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBSB, &dst, &src); + } + + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBSW, &dst, &src); + } + //! @brief Packed Subtract with Saturation (MMX). + inline void psubsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBSW, &dst, &src); + } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBUSB, &dst, &src); + } + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBUSB, &dst, &src); + } + + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBUSW, &dst, &src); + } + //! @brief Packed Subtract with Unsigned Saturation (MMX). + inline void psubusw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBUSW, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKHBW, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhbw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHBW, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKHWD, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhwd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHWD, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKHDQ, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpckhdq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHDQ, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKLBW, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpcklbw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLBW, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKLWD, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpcklwd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLWD, &dst, &src); + } + + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PUNPCKLDQ, &dst, &src); + } + //! @brief Unpack High Packed Data (MMX). + inline void punpckldq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLDQ, &dst, &src); + } + + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PXOR, &dst, &src); + } + //! @brief Bitwise Exclusive OR (MMX). + inline void pxor(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PXOR, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [3dNow] + // -------------------------------------------------------------------------- + + //! @brief Faster EMMS (3dNow!). + //! + //! @note Use only for early AMD processors where is only 3dNow! or SSE. If + //! CPU contains SSE2, it's better to use @c emms() ( @c femms() is mapped + //! to @c emms() ). + inline void femms() + { + _emitInstruction(INST_FEMMS); + } + + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PF2ID, &dst, &src); + } + //! @brief Packed SP-FP to Integer Convert (3dNow!). + inline void pf2id(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PF2ID, &dst, &src); + } + + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PF2IW, &dst, &src); + } + //! @brief Packed SP-FP to Integer Word Convert (3dNow!). + inline void pf2iw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PF2IW, &dst, &src); + } + + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFACC, &dst, &src); + } + //! @brief Packed SP-FP Accumulate (3dNow!). + inline void pfacc(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFACC, &dst, &src); + } + + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFADD, &dst, &src); + } + //! @brief Packed SP-FP Addition (3dNow!). + inline void pfadd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFADD, &dst, &src); + } + + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFCMPEQ, &dst, &src); + } + //! @brief Packed SP-FP Compare - dst == src (3dNow!). + inline void pfcmpeq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFCMPEQ, &dst, &src); + } + + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFCMPGE, &dst, &src); + } + //! @brief Packed SP-FP Compare - dst >= src (3dNow!). + inline void pfcmpge(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFCMPGE, &dst, &src); + } + + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFCMPGT, &dst, &src); + } + //! @brief Packed SP-FP Compare - dst > src (3dNow!). + inline void pfcmpgt(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFCMPGT, &dst, &src); + } + + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFMAX, &dst, &src); + } + //! @brief Packed SP-FP Maximum (3dNow!). + inline void pfmax(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFMAX, &dst, &src); + } + + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFMIN, &dst, &src); + } + //! @brief Packed SP-FP Minimum (3dNow!). + inline void pfmin(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFMIN, &dst, &src); + } + + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFMUL, &dst, &src); + } + //! @brief Packed SP-FP Multiply (3dNow!). + inline void pfmul(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFMUL, &dst, &src); + } + + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFNACC, &dst, &src); + } + //! @brief Packed SP-FP Negative Accumulate (3dNow!). + inline void pfnacc(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFNACC, &dst, &src); + } + + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnaxx(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFPNACC, &dst, &src); + } + //! @brief Packed SP-FP Mixed Accumulate (3dNow!). + inline void pfpnacc(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFPNACC, &dst, &src); + } + + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFRCP, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal Approximation (3dNow!). + inline void pfrcp(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFRCP, &dst, &src); + } + + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFRCPIT1, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal, First Iteration Step (3dNow!). + inline void pfrcpit1(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFRCPIT1, &dst, &src); + } + + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFRCPIT2, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal, Second Iteration Step (3dNow!). + inline void pfrcpit2(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFRCPIT2, &dst, &src); + } + + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFRSQIT1, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal Square Root, First Iteration Step (3dNow!). + inline void pfrsqit1(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFRSQIT1, &dst, &src); + } + + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFRSQRT, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal Square Root Approximation (3dNow!). + inline void pfrsqrt(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFRSQRT, &dst, &src); + } + + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFSUB, &dst, &src); + } + //! @brief Packed SP-FP Subtract (3dNow!). + inline void pfsub(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFSUB, &dst, &src); + } + + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PFSUBR, &dst, &src); + } + //! @brief Packed SP-FP Reverse Subtract (3dNow!). + inline void pfsubr(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PFSUBR, &dst, &src); + } + + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PI2FD, &dst, &src); + } + //! @brief Packed DWords to SP-FP (3dNow!). + inline void pi2fd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PI2FD, &dst, &src); + } + + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PI2FW, &dst, &src); + } + //! @brief Packed Words to SP-FP (3dNow!). + inline void pi2fw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PI2FW, &dst, &src); + } + + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSWAPD, &dst, &src); + } + //! @brief Packed swap DWord (3dNow!) + inline void pswapd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSWAPD, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [SSE] + // -------------------------------------------------------------------------- + + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDPS, &dst, &src); + } + //! @brief Packed SP-FP Add (SSE). + inline void addps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDPS, &dst, &src); + } + + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDSS, &dst, &src); + } + //! @brief Scalar SP-FP Add (SSE). + inline void addss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDSS, &dst, &src); + } + + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ANDNPS, &dst, &src); + } + //! @brief Bit-wise Logical And Not For SP-FP (SSE). + inline void andnps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ANDNPS, &dst, &src); + } + + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ANDPS, &dst, &src); + } + //! @brief Bit-wise Logical And For SP-FP (SSE). + inline void andps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ANDPS, &dst, &src); + } + + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_CMPPS, &dst, &src, &imm8); + } + //! @brief Packed SP-FP Compare (SSE). + inline void cmpps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_CMPPS, &dst, &src, &imm8); + } + + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_CMPSS, &dst, &src, &imm8); + } + //! @brief Compare Scalar SP-FP Values (SSE). + inline void cmpss(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_CMPSS, &dst, &src, &imm8); + } + + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_COMISS, &dst, &src); + } + //! @brief Scalar Ordered SP-FP Compare and Set EFLAGS (SSE). + inline void comiss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_COMISS, &dst, &src); + } + + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XMMVar& dst, const MMVar& src) + { + _emitInstruction(INST_CVTPI2PS, &dst, &src); + } + //! @brief Packed Signed INT32 to Packed SP-FP Conversion (SSE). + inline void cvtpi2ps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPI2PS, &dst, &src); + } + + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPS2PI, &dst, &src); + } + //! @brief Packed SP-FP to Packed INT32 Conversion (SSE). + inline void cvtps2pi(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPS2PI, &dst, &src); + } + + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XMMVar& dst, const GPVar& src) + { + _emitInstruction(INST_CVTSI2SS, &dst, &src); + } + //! @brief Scalar Signed INT32 to SP-FP Conversion (SSE). + inline void cvtsi2ss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSI2SS, &dst, &src); + } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTSS2SI, &dst, &src); + } + //! @brief Scalar SP-FP to Signed INT32 Conversion (SSE). + inline void cvtss2si(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSS2SI, &dst, &src); + } + + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTPS2PI, &dst, &src); + } + //! @brief Packed SP-FP to Packed INT32 Conversion (truncate) (SSE). + inline void cvttps2pi(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTPS2PI, &dst, &src); + } + + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTSS2SI, &dst, &src); + } + //! @brief Scalar SP-FP to Signed INT32 Conversion (truncate) (SSE). + inline void cvttss2si(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTSS2SI, &dst, &src); + } + + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_DIVPS, &dst, &src); + } + //! @brief Packed SP-FP Divide (SSE). + inline void divps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_DIVPS, &dst, &src); + } + + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_DIVSS, &dst, &src); + } + //! @brief Scalar SP-FP Divide (SSE). + inline void divss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_DIVSS, &dst, &src); + } + + //! @brief Load Streaming SIMD Extension Control/Status (SSE). + inline void ldmxcsr(const Mem& src) + { + _emitInstruction(INST_LDMXCSR, &src); + } + + //! @brief Byte Mask Write (SSE). + //! + //! @note The default memory location is specified by DS:EDI. + inline void maskmovq(const GPVar& dst_ptr, const MMVar& data, const MMVar& mask) + { + _emitInstruction(INST_MASKMOVQ, &dst_ptr, &data, &mask); + } + + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MAXPS, &dst, &src); + } + //! @brief Packed SP-FP Maximum (SSE). + inline void maxps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MAXPS, &dst, &src); + } + + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MAXSS, &dst, &src); + } + //! @brief Scalar SP-FP Maximum (SSE). + inline void maxss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MAXSS, &dst, &src); + } + + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MINPS, &dst, &src); + } + //! @brief Packed SP-FP Minimum (SSE). + inline void minps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MINPS, &dst, &src); + } + + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MINSS, &dst, &src); + } + //! @brief Scalar SP-FP Minimum (SSE). + inline void minss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MINSS, &dst, &src); + } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVAPS, &dst, &src); + } + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVAPS, &dst, &src); + } + + //! @brief Move Aligned Packed SP-FP Values (SSE). + inline void movaps(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVAPS, &dst, &src); + } + + //! @brief Move DWord. + inline void movd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord. + inline void movd(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord. + inline void movd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + //! @brief Move DWord. + inline void movd(const XMMVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVD, &dst, &src); + } + + //! @brief Move QWord (SSE). + inline void movq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } + //! @brief Move QWord (SSE). + inline void movq(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#endif // ASMJIT_X64 + //! @brief Move QWord (SSE). + inline void movq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#if defined(ASMJIT_X64) + //! @brief Move QWord (SSE). + inline void movq(const XMMVar& dst, const GPVar& src) + { + _emitInstruction(INST_MOVQ, &dst, &src); + } +#endif // ASMJIT_X64 + + //! @brief Move 64 Bits Non Temporal (SSE). + inline void movntq(const Mem& dst, const MMVar& src) + { + _emitInstruction(INST_MOVNTQ, &dst, &src); + } + + //! @brief High to Low Packed SP-FP (SSE). + inline void movhlps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVHLPS, &dst, &src); + } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVHPS, &dst, &src); + } + + //! @brief Move High Packed SP-FP (SSE). + inline void movhps(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVHPS, &dst, &src); + } + + //! @brief Move Low to High Packed SP-FP (SSE). + inline void movlhps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVLHPS, &dst, &src); + } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVLPS, &dst, &src); + } + + //! @brief Move Low Packed SP-FP (SSE). + inline void movlps(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVLPS, &dst, &src); + } + + //! @brief Move Aligned Four Packed SP-FP Non Temporal (SSE). + inline void movntps(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVNTPS, &dst, &src); + } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSS, &dst, &src); + } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSS, &dst, &src); + } + + //! @brief Move Scalar SP-FP (SSE). + inline void movss(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSS, &dst, &src); + } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVUPS, &dst, &src); + } + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVUPS, &dst, &src); + } + + //! @brief Move Unaligned Packed SP-FP Values (SSE). + inline void movups(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVUPS, &dst, &src); + } + + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MULPS, &dst, &src); + } + //! @brief Packed SP-FP Multiply (SSE). + inline void mulps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MULPS, &dst, &src); + } + + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MULSS, &dst, &src); + } + //! @brief Scalar SP-FP Multiply (SSE). + inline void mulss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MULSS, &dst, &src); + } + + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ORPS, &dst, &src); + } + //! @brief Bit-wise Logical OR for SP-FP Data (SSE). + inline void orps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ORPS, &dst, &src); + } + + //! @brief Packed Average (SSE). + inline void pavgb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PAVGB, &dst, &src); + } + //! @brief Packed Average (SSE). + inline void pavgb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAVGB, &dst, &src); + } + + //! @brief Packed Average (SSE). + inline void pavgw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PAVGW, &dst, &src); + } + //! @brief Packed Average (SSE). + inline void pavgw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAVGW, &dst, &src); + } + + //! @brief Extract Word (SSE). + inline void pextrw(const GPVar& dst, const MMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); + } + + //! @brief Insert Word (SSE). + inline void pinsrw(const MMVar& dst, const GPVar& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRW, &dst, &src, &imm8); + } + //! @brief Insert Word (SSE). + inline void pinsrw(const MMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRW, &dst, &src, &imm8); + } + + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMAXSW, &dst, &src); + } + //! @brief Packed Signed Integer Word Maximum (SSE). + inline void pmaxsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXSW, &dst, &src); + } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMAXUB, &dst, &src); + } + //! @brief Packed Unsigned Integer Byte Maximum (SSE). + inline void pmaxub(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXUB, &dst, &src); + } + + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMINSW, &dst, &src); + } + //! @brief Packed Signed Integer Word Minimum (SSE). + inline void pminsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINSW, &dst, &src); + } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMINUB, &dst, &src); + } + //! @brief Packed Unsigned Integer Byte Minimum (SSE). + inline void pminub(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINUB, &dst, &src); + } + + //! @brief Move Byte Mask To Integer (SSE). + inline void pmovmskb(const GPVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMOVMSKB, &dst, &src); + } + + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMULHUW, &dst, &src); + } + //! @brief Packed Multiply High Unsigned (SSE). + inline void pmulhuw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHUW, &dst, &src); + } + + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSADBW, &dst, &src); + } + //! @brief Packed Sum of Absolute Differences (SSE). + inline void psadbw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSADBW, &dst, &src); + } + + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MMVar& dst, const MMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); + } + //! @brief Packed Shuffle word (SSE). + inline void pshufw(const MMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFW, &dst, &src, &imm8); + } + + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_RCPPS, &dst, &src); + } + //! @brief Packed SP-FP Reciprocal (SSE). + inline void rcpps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_RCPPS, &dst, &src); + } + + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_RCPSS, &dst, &src); + } + //! @brief Scalar SP-FP Reciprocal (SSE). + inline void rcpss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_RCPSS, &dst, &src); + } + + //! @brief Prefetch (SSE). + inline void prefetch(const Mem& mem, const Imm& hint) + { + _emitInstruction(INST_PREFETCH, &mem, &hint); + } + + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSADBW, &dst, &src); + } + //! @brief Compute Sum of Absolute Differences (SSE). + inline void psadbw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSADBW, &dst, &src); + } + + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_RSQRTPS, &dst, &src); + } + //! @brief Packed SP-FP Square Root Reciprocal (SSE). + inline void rsqrtps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_RSQRTPS, &dst, &src); + } + + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_RSQRTSS, &dst, &src); + } + //! @brief Scalar SP-FP Square Root Reciprocal (SSE). + inline void rsqrtss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_RSQRTSS, &dst, &src); + } + + //! @brief Store fence (SSE). + inline void sfence() + { + _emitInstruction(INST_SFENCE); + } + + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); + } + //! @brief Shuffle SP-FP (SSE). + inline void shufps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_SHUFPS, &dst, &src, &imm8); + } + + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SQRTPS, &dst, &src); + } + //! @brief Packed SP-FP Square Root (SSE). + inline void sqrtps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SQRTPS, &dst, &src); + } + + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SQRTSS, &dst, &src); + } + //! @brief Scalar SP-FP Square Root (SSE). + inline void sqrtss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SQRTSS, &dst, &src); + } + + //! @brief Store Streaming SIMD Extension Control/Status (SSE). + inline void stmxcsr(const Mem& dst) + { + _emitInstruction(INST_STMXCSR, &dst); + } + + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SUBPS, &dst, &src); + } + //! @brief Packed SP-FP Subtract (SSE). + inline void subps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SUBPS, &dst, &src); + } + + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SUBSS, &dst, &src); + } + //! @brief Scalar SP-FP Subtract (SSE). + inline void subss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SUBSS, &dst, &src); + } + + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UCOMISS, &dst, &src); + } + //! @brief Unordered Scalar SP-FP compare and set EFLAGS (SSE). + inline void ucomiss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UCOMISS, &dst, &src); + } + + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UNPCKHPS, &dst, &src); + } + //! @brief Unpack High Packed SP-FP Data (SSE). + inline void unpckhps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UNPCKHPS, &dst, &src); + } + + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UNPCKLPS, &dst, &src); + } + //! @brief Unpack Low Packed SP-FP Data (SSE). + inline void unpcklps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UNPCKLPS, &dst, &src); + } + + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_XORPS, &dst, &src); + } + //! @brief Bit-wise Logical Xor for SP-FP Data (SSE). + inline void xorps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_XORPS, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [SSE2] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDPD, &dst, &src); + } + //! @brief Packed DP-FP Add (SSE2). + inline void addpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDPD, &dst, &src); + } + + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDSD, &dst, &src); + } + //! @brief Scalar DP-FP Add (SSE2). + inline void addsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDSD, &dst, &src); + } + + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ANDNPD, &dst, &src); + } + //! @brief Bit-wise Logical And Not For DP-FP (SSE2). + inline void andnpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ANDNPD, &dst, &src); + } + + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ANDPD, &dst, &src); + } + //! @brief Bit-wise Logical And For DP-FP (SSE2). + inline void andpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ANDPD, &dst, &src); + } + + //! @brief Flush Cache Line (SSE2). + inline void clflush(const Mem& mem) + { + _emitInstruction(INST_CLFLUSH, &mem); + } + + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_CMPPD, &dst, &src, &imm8); + } + //! @brief Packed DP-FP Compare (SSE2). + inline void cmppd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_CMPPD, &dst, &src, &imm8); + } + + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_CMPSD, &dst, &src, &imm8); + } + //! @brief Compare Scalar SP-FP Values (SSE2). + inline void cmpsd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_CMPSD, &dst, &src, &imm8); + } + + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_COMISD, &dst, &src); + } + //! @brief Scalar Ordered DP-FP Compare and Set EFLAGS (SSE2). + inline void comisd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_COMISD, &dst, &src); + } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTDQ2PD, &dst, &src); + } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtdq2pd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTDQ2PD, &dst, &src); + } + + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTDQ2PS, &dst, &src); + } + //! @brief Convert Packed Dword Integers to Packed SP-FP Values (SSE2). + inline void cvtdq2ps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTDQ2PS, &dst, &src); + } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPD2DQ, &dst, &src); + } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2dq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPD2DQ, &dst, &src); + } + + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPD2PI, &dst, &src); + } + //! @brief Convert Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvtpd2pi(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPD2PI, &dst, &src); + } + + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPD2PS, &dst, &src); + } + //! @brief Convert Packed DP-FP Values to Packed SP-FP Values (SSE2). + inline void cvtpd2ps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPD2PS, &dst, &src); + } + + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XMMVar& dst, const MMVar& src) + { + _emitInstruction(INST_CVTPI2PD, &dst, &src); + } + //! @brief Convert Packed Dword Integers to Packed DP-FP Values (SSE2). + inline void cvtpi2pd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPI2PD, &dst, &src); + } + + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPS2DQ, &dst, &src); + } + //! @brief Convert Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvtps2dq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPS2DQ, &dst, &src); + } + + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTPS2PD, &dst, &src); + } + //! @brief Convert Packed SP-FP Values to Packed DP-FP Values (SSE2). + inline void cvtps2pd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTPS2PD, &dst, &src); + } + + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTSD2SI, &dst, &src); + } + //! @brief Convert Scalar DP-FP Value to Dword Integer (SSE2). + inline void cvtsd2si(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSD2SI, &dst, &src); + } + + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTSD2SS, &dst, &src); + } + //! @brief Convert Scalar DP-FP Value to Scalar SP-FP Value (SSE2). + inline void cvtsd2ss(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSD2SS, &dst, &src); + } + + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XMMVar& dst, const GPVar& src) + { + _emitInstruction(INST_CVTSI2SD, &dst, &src); + } + //! @brief Convert Dword Integer to Scalar DP-FP Value (SSE2). + inline void cvtsi2sd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSI2SD, &dst, &src); + } + + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTSS2SD, &dst, &src); + } + //! @brief Convert Scalar SP-FP Value to Scalar DP-FP Value (SSE2). + inline void cvtss2sd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTSS2SD, &dst, &src); + } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTPD2PI, &dst, &src); + } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2pi(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTPD2PI, &dst, &src); + } + + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTPD2DQ, &dst, &src); + } + //! @brief Convert with Truncation Packed DP-FP Values to Packed Dword Integers (SSE2). + inline void cvttpd2dq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTPD2DQ, &dst, &src); + } + + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTPS2DQ, &dst, &src); + } + //! @brief Convert with Truncation Packed SP-FP Values to Packed Dword Integers (SSE2). + inline void cvttps2dq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTPS2DQ, &dst, &src); + } + + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_CVTTSD2SI, &dst, &src); + } + //! @brief Convert with Truncation Scalar DP-FP Value to Signed Dword Integer (SSE2). + inline void cvttsd2si(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CVTTSD2SI, &dst, &src); + } + + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_DIVPD, &dst, &src); + } + //! @brief Packed DP-FP Divide (SSE2). + inline void divpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_DIVPD, &dst, &src); + } + + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_DIVSD, &dst, &src); + } + //! @brief Scalar DP-FP Divide (SSE2). + inline void divsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_DIVSD, &dst, &src); + } + + //! @brief Load Fence (SSE2). + inline void lfence() + { + _emitInstruction(INST_LFENCE); + } + + //! @brief Store Selected Bytes of Double Quadword (SSE2). + //! + //! @note Target is DS:EDI. + inline void maskmovdqu(const GPVar& dst_ptr, const XMMVar& src, const XMMVar& mask) + { + _emitInstruction(INST_MASKMOVDQU, &dst_ptr, &src, &mask); + } + + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MAXPD, &dst, &src); + } + //! @brief Return Maximum Packed Double-Precision FP Values (SSE2). + inline void maxpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MAXPD, &dst, &src); + } + + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MAXSD, &dst, &src); + } + //! @brief Return Maximum Scalar Double-Precision FP Value (SSE2). + inline void maxsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MAXSD, &dst, &src); + } + + //! @brief Memory Fence (SSE2). + inline void mfence() + { + _emitInstruction(INST_MFENCE); + } + + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MINPD, &dst, &src); + } + //! @brief Return Minimum Packed DP-FP Values (SSE2). + inline void minpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MINPD, &dst, &src); + } + + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MINSD, &dst, &src); + } + //! @brief Return Minimum Scalar DP-FP Value (SSE2). + inline void minsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MINSD, &dst, &src); + } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDQA, &dst, &src); + } + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVDQA, &dst, &src); + } + + //! @brief Move Aligned DQWord (SSE2). + inline void movdqa(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDQA, &dst, &src); + } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDQU, &dst, &src); + } + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVDQU, &dst, &src); + } + + //! @brief Move Unaligned Double Quadword (SSE2). + inline void movdqu(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDQU, &dst, &src); + } + + //! @brief Extract Packed SP-FP Sign Mask (SSE2). + inline void movmskps(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVMSKPS, &dst, &src); + } + + //! @brief Extract Packed DP-FP Sign Mask (SSE2). + inline void movmskpd(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVMSKPD, &dst, &src); + } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSD, &dst, &src); + } + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSD, &dst, &src); + } + + //! @brief Move Scalar Double-Precision FP Value (SSE2). + inline void movsd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSD, &dst, &src); + } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVAPD, &dst, &src); + } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVAPD, &dst, &src); + } + + //! @brief Move Aligned Packed Double-Precision FP Values (SSE2). + inline void movapd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVAPD, &dst, &src); + } + + //! @brief Move Quadword from XMM to MMX Technology Register (SSE2). + inline void movdq2q(const MMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDQ2Q, &dst, &src); + } + + //! @brief Move Quadword from MMX Technology to XMM Register (SSE2). + inline void movq2dq(const XMMVar& dst, const MMVar& src) + { + _emitInstruction(INST_MOVQ2DQ, &dst, &src); + } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVHPD, &dst, &src); + } + + //! @brief Move High Packed Double-Precision FP Value (SSE2). + inline void movhpd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVHPD, &dst, &src); + } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVLPD, &dst, &src); + } + + //! @brief Move Low Packed Double-Precision FP Value (SSE2). + inline void movlpd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVLPD, &dst, &src); + } + + //! @brief Store Double Quadword Using Non-Temporal Hint (SSE2). + inline void movntdq(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVNTDQ, &dst, &src); + } + + //! @brief Store Store DWORD Using Non-Temporal Hint (SSE2). + inline void movnti(const Mem& dst, const GPVar& src) + { + _emitInstruction(INST_MOVNTI, &dst, &src); + } + + //! @brief Store Packed Double-Precision FP Values Using Non-Temporal Hint (SSE2). + inline void movntpd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVNTPD, &dst, &src); + } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVUPD, &dst, &src); + } + + //! @brief Move Unaligned Packed Double-Precision FP Values (SSE2). + inline void movupd(const Mem& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVUPD, &dst, &src); + } + + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MULPD, &dst, &src); + } + //! @brief Packed DP-FP Multiply (SSE2). + inline void mulpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MULPD, &dst, &src); + } + + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MULSD, &dst, &src); + } + //! @brief Scalar DP-FP Multiply (SSE2). + inline void mulsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MULSD, &dst, &src); + } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ORPD, &dst, &src); + } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void orpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ORPD, &dst, &src); + } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PACKSSWB, &dst, &src); + } + //! @brief Pack with Signed Saturation (SSE2). + inline void packsswb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PACKSSWB, &dst, &src); + } + + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PACKSSDW, &dst, &src); + } + //! @brief Pack with Signed Saturation (SSE2). + inline void packssdw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PACKSSDW, &dst, &src); + } + + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PACKUSWB, &dst, &src); + } + //! @brief Pack with Unsigned Saturation (SSE2). + inline void packuswb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PACKUSWB, &dst, &src); + } + + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDB, &dst, &src); + } + //! @brief Packed BYTE Add (SSE2). + inline void paddb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDB, &dst, &src); + } + + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDW, &dst, &src); + } + //! @brief Packed WORD Add (SSE2). + inline void paddw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDW, &dst, &src); + } + + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDD, &dst, &src); + } + //! @brief Packed DWORD Add (SSE2). + inline void paddd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDD, &dst, &src); + } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PADDQ, &dst, &src); + } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDQ, &dst, &src); + } + + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDQ, &dst, &src); + } + //! @brief Packed QWORD Add (SSE2). + inline void paddq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDQ, &dst, &src); + } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDSB, &dst, &src); + } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDSB, &dst, &src); + } + + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDSW, &dst, &src); + } + //! @brief Packed Add with Saturation (SSE2). + inline void paddsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDSW, &dst, &src); + } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDUSB, &dst, &src); + } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDUSB, &dst, &src); + } + + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PADDUSW, &dst, &src); + } + //! @brief Packed Add Unsigned with Saturation (SSE2). + inline void paddusw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PADDUSW, &dst, &src); + } + + //! @brief Logical AND (SSE2). + inline void pand(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PAND, &dst, &src); + } + //! @brief Logical AND (SSE2). + inline void pand(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAND, &dst, &src); + } + + //! @brief Logical AND Not (SSE2). + inline void pandn(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PANDN, &dst, &src); + } + //! @brief Logical AND Not (SSE2). + inline void pandn(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PANDN, &dst, &src); + } + + //! @brief Spin Loop Hint (SSE2). + inline void pause() + { + _emitInstruction(INST_PAUSE); + } + + //! @brief Packed Average (SSE2). + inline void pavgb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PAVGB, &dst, &src); + } + //! @brief Packed Average (SSE2). + inline void pavgb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAVGB, &dst, &src); + } + + //! @brief Packed Average (SSE2). + inline void pavgw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PAVGW, &dst, &src); + } + //! @brief Packed Average (SSE2). + inline void pavgw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PAVGW, &dst, &src); + } + + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPEQB, &dst, &src); + } + //! @brief Packed Compare for Equal (BYTES) (SSE2). + inline void pcmpeqb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQB, &dst, &src); + } + + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPEQW, &dst, &src); + } + //! @brief Packed Compare for Equal (WORDS) (SSE2). + inline void pcmpeqw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQW, &dst, &src); + } + + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPEQD, &dst, &src); + } + //! @brief Packed Compare for Equal (DWORDS) (SSE2). + inline void pcmpeqd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQD, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPGTB, &dst, &src); + } + //! @brief Packed Compare for Greater Than (BYTES) (SSE2). + inline void pcmpgtb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTB, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPGTW, &dst, &src); + } + //! @brief Packed Compare for Greater Than (WORDS) (SSE2). + inline void pcmpgtw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTW, &dst, &src); + } + + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPGTD, &dst, &src); + } + //! @brief Packed Compare for Greater Than (DWORDS) (SSE2). + inline void pcmpgtd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTD, &dst, &src); + } + + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXSW, &dst, &src); + } + //! @brief Packed Signed Integer Word Maximum (SSE2). + inline void pmaxsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXSW, &dst, &src); + } + + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXUB, &dst, &src); + } + //! @brief Packed Unsigned Integer Byte Maximum (SSE2). + inline void pmaxub(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXUB, &dst, &src); + } + + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINSW, &dst, &src); + } + //! @brief Packed Signed Integer Word Minimum (SSE2). + inline void pminsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINSW, &dst, &src); + } + + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINUB, &dst, &src); + } + //! @brief Packed Unsigned Integer Byte Minimum (SSE2). + inline void pminub(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINUB, &dst, &src); + } + + //! @brief Move Byte Mask (SSE2). + inline void pmovmskb(const GPVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVMSKB, &dst, &src); + } + + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULHW, &dst, &src); + } + //! @brief Packed Multiply High (SSE2). + inline void pmulhw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHW, &dst, &src); + } + + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULHUW, &dst, &src); + } + //! @brief Packed Multiply High Unsigned (SSE2). + inline void pmulhuw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHUW, &dst, &src); + } + + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULLW, &dst, &src); + } + //! @brief Packed Multiply Low (SSE2). + inline void pmullw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULLW, &dst, &src); + } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMULUDQ, &dst, &src); + } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULUDQ, &dst, &src); + } + + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULUDQ, &dst, &src); + } + //! @brief Packed Multiply to QWORD (SSE2). + inline void pmuludq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULUDQ, &dst, &src); + } + + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_POR, &dst, &src); + } + //! @brief Bitwise Logical OR (SSE2). + inline void por(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_POR, &dst, &src); + } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void pslld(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLD, &dst, &src); + } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllq(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLQ, &dst, &src); + } + + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + //! @brief Packed Shift Left Logical (SSE2). + inline void psllw(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLW, &dst, &src); + } + + //! @brief Packed Shift Left Logical (SSE2). + inline void pslldq(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSLLDQ, &dst, &src); + } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psrad(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRAD, &dst, &src); + } + + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + //! @brief Packed Shift Right Arithmetic (SSE2). + inline void psraw(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRAW, &dst, &src); + } + + //! @brief Packed Subtract (SSE2). + inline void psubb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBB, &dst, &src); + } + //! @brief Packed Subtract (SSE2). + inline void psubb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBB, &dst, &src); + } + + //! @brief Packed Subtract (SSE2). + inline void psubw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBW, &dst, &src); + } + //! @brief Packed Subtract (SSE2). + inline void psubw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBW, &dst, &src); + } + + //! @brief Packed Subtract (SSE2). + inline void psubd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBD, &dst, &src); + } + //! @brief Packed Subtract (SSE2). + inline void psubd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBD, &dst, &src); + } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSUBQ, &dst, &src); + } + //! @brief Packed Subtract (SSE2). + inline void psubq(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBQ, &dst, &src); + } + + //! @brief Packed Subtract (SSE2). + inline void psubq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBQ, &dst, &src); + } + //! @brief Packed Subtract (SSE2). + inline void psubq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBQ, &dst, &src); + } + + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMADDWD, &dst, &src); + } + //! @brief Packed Multiply and Add (SSE2). + inline void pmaddwd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMADDWD, &dst, &src); + } + + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); + } + //! @brief Shuffle Packed DWORDs (SSE2). + inline void pshufd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFD, &dst, &src, &imm8); + } + + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); + } + //! @brief Shuffle Packed High Words (SSE2). + inline void pshufhw(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFHW, &dst, &src, &imm8); + } + + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); + } + //! @brief Shuffle Packed Low Words (SSE2). + inline void pshuflw(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PSHUFLW, &dst, &src, &imm8); + } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrld(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLD, &dst, &src); + } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlq(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLQ, &dst, &src); + } + + //! @brief DQWord Shift Right Logical (MMX). + inline void psrldq(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLDQ, &dst, &src); + } + + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + //! @brief Packed Shift Right Logical (SSE2). + inline void psrlw(const XMMVar& dst, const Imm& src) + { + _emitInstruction(INST_PSRLW, &dst, &src); + } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBSB, &dst, &src); + } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBSB, &dst, &src); + } + + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBSW, &dst, &src); + } + //! @brief Packed Subtract with Saturation (SSE2). + inline void psubsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBSW, &dst, &src); + } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBUSB, &dst, &src); + } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBUSB, &dst, &src); + } + + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSUBUSW, &dst, &src); + } + //! @brief Packed Subtract with Unsigned Saturation (SSE2). + inline void psubusw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSUBUSW, &dst, &src); + } + + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKHBW, &dst, &src); + } + //! @brief Unpack High Data (SSE2). + inline void punpckhbw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHBW, &dst, &src); + } + + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKHWD, &dst, &src); + } + //! @brief Unpack High Data (SSE2). + inline void punpckhwd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHWD, &dst, &src); + } + + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKHDQ, &dst, &src); + } + //! @brief Unpack High Data (SSE2). + inline void punpckhdq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHDQ, &dst, &src); + } + + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); + } + //! @brief Unpack High Data (SSE2). + inline void punpckhqdq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKHQDQ, &dst, &src); + } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKLBW, &dst, &src); + } + //! @brief Unpack Low Data (SSE2). + inline void punpcklbw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLBW, &dst, &src); + } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKLWD, &dst, &src); + } + //! @brief Unpack Low Data (SSE2). + inline void punpcklwd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLWD, &dst, &src); + } + + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKLDQ, &dst, &src); + } + //! @brief Unpack Low Data (SSE2). + inline void punpckldq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLDQ, &dst, &src); + } + + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); + } + //! @brief Unpack Low Data (SSE2). + inline void punpcklqdq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PUNPCKLQDQ, &dst, &src); + } + + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PXOR, &dst, &src); + } + //! @brief Bitwise Exclusive OR (SSE2). + inline void pxor(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PXOR, &dst, &src); + } + + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); + } + //! @brief Shuffle DP-FP (SSE2). + inline void shufpd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_SHUFPD, &dst, &src, &imm8); + } + + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SQRTPD, &dst, &src); + } + //! @brief Compute Square Roots of Packed DP-FP Values (SSE2). + inline void sqrtpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SQRTPD, &dst, &src); + } + + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SQRTSD, &dst, &src); + } + //! @brief Compute Square Root of Scalar DP-FP Value (SSE2). + inline void sqrtsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SQRTSD, &dst, &src); + } + + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SUBPD, &dst, &src); + } + //! @brief Packed DP-FP Subtract (SSE2). + inline void subpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SUBPD, &dst, &src); + } + + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_SUBSD, &dst, &src); + } + //! @brief Scalar DP-FP Subtract (SSE2). + inline void subsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_SUBSD, &dst, &src); + } + + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UCOMISD, &dst, &src); + } + //! @brief Scalar Unordered DP-FP Compare and Set EFLAGS (SSE2). + inline void ucomisd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UCOMISD, &dst, &src); + } + + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UNPCKHPD, &dst, &src); + } + //! @brief Unpack and Interleave High Packed Double-Precision FP Values (SSE2). + inline void unpckhpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UNPCKHPD, &dst, &src); + } + + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_UNPCKLPD, &dst, &src); + } + //! @brief Unpack and Interleave Low Packed Double-Precision FP Values (SSE2). + inline void unpcklpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_UNPCKLPD, &dst, &src); + } + + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_XORPD, &dst, &src); + } + //! @brief Bit-wise Logical OR for DP-FP Data (SSE2). + inline void xorpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_XORPD, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [SSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDSUBPD, &dst, &src); + } + //! @brief Packed DP-FP Add/Subtract (SSE3). + inline void addsubpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDSUBPD, &dst, &src); + } + + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_ADDSUBPS, &dst, &src); + } + //! @brief Packed SP-FP Add/Subtract (SSE3). + inline void addsubps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_ADDSUBPS, &dst, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + // TODO: NOT IMPLEMENTED BY THE COMPILER. + //! @brief Store Integer with Truncation (SSE3). + inline void fisttp(const Mem& dst) + { + _emitInstruction(INST_FISTTP, &dst); + } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_HADDPD, &dst, &src); + } + //! @brief Packed DP-FP Horizontal Add (SSE3). + inline void haddpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_HADDPD, &dst, &src); + } + + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_HADDPS, &dst, &src); + } + //! @brief Packed SP-FP Horizontal Add (SSE3). + inline void haddps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_HADDPS, &dst, &src); + } + + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_HSUBPD, &dst, &src); + } + //! @brief Packed DP-FP Horizontal Subtract (SSE3). + inline void hsubpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_HSUBPD, &dst, &src); + } + + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_HSUBPS, &dst, &src); + } + //! @brief Packed SP-FP Horizontal Subtract (SSE3). + inline void hsubps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_HSUBPS, &dst, &src); + } + + //! @brief Load Unaligned Integer 128 Bits (SSE3). + inline void lddqu(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_LDDQU, &dst, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Set Up Monitor Address (SSE3). + inline void monitor() + { + _emitInstruction(INST_MONITOR); + } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVDDUP, &dst, &src); + } + //! @brief Move One DP-FP and Duplicate (SSE3). + inline void movddup(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVDDUP, &dst, &src); + } + + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSHDUP, &dst, &src); + } + //! @brief Move Packed SP-FP High and Duplicate (SSE3). + inline void movshdup(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSHDUP, &dst, &src); + } + + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_MOVSLDUP, &dst, &src); + } + //! @brief Move Packed SP-FP Low and Duplicate (SSE3). + inline void movsldup(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVSLDUP, &dst, &src); + } + +#if ASMJIT_NOT_SUPPORTED_BY_COMPILER + //! @brief Monitor Wait (SSE3). + inline void mwait() + { + _emitInstruction(INST_MWAIT); + } +#endif // ASMJIT_NOT_SUPPORTED_BY_COMPILER + + // -------------------------------------------------------------------------- + // [SSSE3] + // -------------------------------------------------------------------------- + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSIGNB, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGNB, &dst, &src); + } + + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSIGNB, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGNB, &dst, &src); + } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSIGNW, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGNW, &dst, &src); + } + + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSIGNW, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGNW, &dst, &src); + } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSIGND, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGND, &dst, &src); + } + + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSIGND, &dst, &src); + } + //! @brief Packed SIGN (SSSE3). + inline void psignd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSIGND, &dst, &src); + } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHADDW, &dst, &src); + } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDW, &dst, &src); + } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHADDW, &dst, &src); + } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDW, &dst, &src); + } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHADDD, &dst, &src); + } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDD, &dst, &src); + } + + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHADDD, &dst, &src); + } + //! @brief Packed Horizontal Add (SSSE3). + inline void phaddd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDD, &dst, &src); + } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHADDSW, &dst, &src); + } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDSW, &dst, &src); + } + + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHADDSW, &dst, &src); + } + //! @brief Packed Horizontal Add and Saturate (SSSE3). + inline void phaddsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHADDSW, &dst, &src); + } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHSUBW, &dst, &src); + } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBW, &dst, &src); + } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHSUBW, &dst, &src); + } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBW, &dst, &src); + } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHSUBD, &dst, &src); + } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBD, &dst, &src); + } + + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHSUBD, &dst, &src); + } + //! @brief Packed Horizontal Subtract (SSSE3). + inline void phsubd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBD, &dst, &src); + } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PHSUBSW, &dst, &src); + } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBSW, &dst, &src); + } + + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHSUBSW, &dst, &src); + } + //! @brief Packed Horizontal Subtract and Saturate (SSSE3). + inline void phsubsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHSUBSW, &dst, &src); + } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMADDUBSW, &dst, &src); + } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMADDUBSW, &dst, &src); + } + + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMADDUBSW, &dst, &src); + } + //! @brief Multiply and Add Packed Signed and Unsigned Bytes (SSSE3). + inline void pmaddubsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMADDUBSW, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PABSB, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSB, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PABSB, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSB, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PABSW, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSW, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PABSW, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSW, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PABSD, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSD, &dst, &src); + } + + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PABSD, &dst, &src); + } + //! @brief Packed Absolute Value (SSSE3). + inline void pabsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PABSD, &dst, &src); + } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PMULHRSW, &dst, &src); + } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHRSW, &dst, &src); + } + + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULHRSW, &dst, &src); + } + //! @brief Packed Multiply High with Round and Scale (SSSE3). + inline void pmulhrsw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULHRSW, &dst, &src); + } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MMVar& dst, const MMVar& src) + { + _emitInstruction(INST_PSHUFB, &dst, &src); + } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const MMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSHUFB, &dst, &src); + } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PSHUFB, &dst, &src); + } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void pshufb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PSHUFB, &dst, &src); + } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MMVar& dst, const MMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); + } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const MMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); + } + + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); + } + //! @brief Packed Shuffle Bytes (SSSE3). + inline void palignr(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PALIGNR, &dst, &src, &imm8); + } + + // -------------------------------------------------------------------------- + // [SSE4.1] + // -------------------------------------------------------------------------- + + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); + } + //! @brief Blend Packed DP-FP Values (SSE4.1). + inline void blendpd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_BLENDPD, &dst, &src, &imm8); + } + + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); + } + //! @brief Blend Packed SP-FP Values (SSE4.1). + inline void blendps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_BLENDPS, &dst, &src, &imm8); + } + + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_BLENDVPD, &dst, &src); + } + //! @brief Variable Blend Packed DP-FP Values (SSE4.1). + inline void blendvpd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_BLENDVPD, &dst, &src); + } + + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_BLENDVPS, &dst, &src); + } + //! @brief Variable Blend Packed SP-FP Values (SSE4.1). + inline void blendvps(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_BLENDVPS, &dst, &src); + } + + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_DPPD, &dst, &src, &imm8); + } + //! @brief Dot Product of Packed DP-FP Values (SSE4.1). + inline void dppd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_DPPD, &dst, &src, &imm8); + } + + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_DPPS, &dst, &src, &imm8); + } + //! @brief Dot Product of Packed SP-FP Values (SSE4.1). + inline void dpps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_DPPS, &dst, &src, &imm8); + } + + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); + } + //! @brief Extract Packed SP-FP Value (SSE4.1). + inline void extractps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_EXTRACTPS, &dst, &src, &imm8); + } + + //! @brief Load Double Quadword Non-Temporal Aligned Hint (SSE4.1). + inline void movntdqa(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_MOVNTDQA, &dst, &src); + } + + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); + } + //! @brief Compute Multiple Packed Sums of Absolute Difference (SSE4.1). + inline void mpsadbw(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_MPSADBW, &dst, &src, &imm8); + } + + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PACKUSDW, &dst, &src); + } + //! @brief Pack with Unsigned Saturation (SSE4.1). + inline void packusdw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PACKUSDW, &dst, &src); + } + + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PBLENDVB, &dst, &src); + } + //! @brief Variable Blend Packed Bytes (SSE4.1). + inline void pblendvb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PBLENDVB, &dst, &src); + } + + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); + } + //! @brief Blend Packed Words (SSE4.1). + inline void pblendw(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PBLENDW, &dst, &src, &imm8); + } + + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPEQQ, &dst, &src); + } + //! @brief Compare Packed Qword Data for Equal (SSE4.1). + inline void pcmpeqq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPEQQ, &dst, &src); + } + + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const GPVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); + } + //! @brief Extract Byte (SSE4.1). + inline void pextrb(const Mem& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRB, &dst, &src, &imm8); + } + + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const GPVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); + } + //! @brief Extract Dword (SSE4.1). + inline void pextrd(const Mem& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRD, &dst, &src, &imm8); + } + + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const GPVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); + } + //! @brief Extract Dword (SSE4.1). + inline void pextrq(const Mem& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRQ, &dst, &src, &imm8); + } + + //! @brief Extract Word (SSE4.1). + inline void pextrw(const GPVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); + } + //! @brief Extract Word (SSE4.1). + inline void pextrw(const Mem& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PEXTRW, &dst, &src, &imm8); + } + + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PHMINPOSUW, &dst, &src); + } + //! @brief Packed Horizontal Word Minimum (SSE4.1). + inline void phminposuw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PHMINPOSUW, &dst, &src); + } + + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XMMVar& dst, const GPVar& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRB, &dst, &src, &imm8); + } + //! @brief Insert Byte (SSE4.1). + inline void pinsrb(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRB, &dst, &src, &imm8); + } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XMMVar& dst, const GPVar& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRD, &dst, &src, &imm8); + } + //! @brief Insert Dword (SSE4.1). + inline void pinsrd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRD, &dst, &src, &imm8); + } + + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XMMVar& dst, const GPVar& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); + } + //! @brief Insert Dword (SSE4.1). + inline void pinsrq(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRQ, &dst, &src, &imm8); + } + + //! @brief Insert Word (SSE2). + inline void pinsrw(const XMMVar& dst, const GPVar& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRW, &dst, &src, &imm8); + } + //! @brief Insert Word (SSE2). + inline void pinsrw(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PINSRW, &dst, &src, &imm8); + } + + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXUW, &dst, &src); + } + //! @brief Maximum of Packed Word Integers (SSE4.1). + inline void pmaxuw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXUW, &dst, &src); + } + + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXSB, &dst, &src); + } + //! @brief Maximum of Packed Signed Byte Integers (SSE4.1). + inline void pmaxsb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXSB, &dst, &src); + } + + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXSD, &dst, &src); + } + //! @brief Maximum of Packed Signed Dword Integers (SSE4.1). + inline void pmaxsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXSD, &dst, &src); + } + + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMAXUD, &dst, &src); + } + //! @brief Maximum of Packed Unsigned Dword Integers (SSE4.1). + inline void pmaxud(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMAXUD, &dst, &src); + } + + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINSB, &dst, &src); + } + //! @brief Minimum of Packed Signed Byte Integers (SSE4.1). + inline void pminsb(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINSB, &dst, &src); + } + + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINUW, &dst, &src); + } + //! @brief Minimum of Packed Word Integers (SSE4.1). + inline void pminuw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINUW, &dst, &src); + } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINUD, &dst, &src); + } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminud(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINUD, &dst, &src); + } + + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMINSD, &dst, &src); + } + //! @brief Minimum of Packed Dword Integers (SSE4.1). + inline void pminsd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMINSD, &dst, &src); + } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXBW, &dst, &src); + } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXBW, &dst, &src); + } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXBD, &dst, &src); + } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXBD, &dst, &src); + } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXBQ, &dst, &src); + } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxbq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXBQ, &dst, &src); + } + + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXWD, &dst, &src); + } + //! @brief Packed Move with Sign Extend (SSE4.1). + inline void pmovsxwd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXWD, &dst, &src); + } + + //! @brief (SSE4.1). + inline void pmovsxwq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXWQ, &dst, &src); + } + //! @brief (SSE4.1). + inline void pmovsxwq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXWQ, &dst, &src); + } + + //! @brief (SSE4.1). + inline void pmovsxdq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVSXDQ, &dst, &src); + } + //! @brief (SSE4.1). + inline void pmovsxdq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVSXDQ, &dst, &src); + } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXBW, &dst, &src); + } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbw(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXBW, &dst, &src); + } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXBD, &dst, &src); + } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXBD, &dst, &src); + } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXBQ, &dst, &src); + } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxbq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXBQ, &dst, &src); + } + + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXWD, &dst, &src); + } + //! @brief Packed Move with Zero Extend (SSE4.1). + inline void pmovzxwd(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXWD, &dst, &src); + } + + //! @brief (SSE4.1). + inline void pmovzxwq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXWQ, &dst, &src); + } + //! @brief (SSE4.1). + inline void pmovzxwq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXWQ, &dst, &src); + } + + //! @brief (SSE4.1). + inline void pmovzxdq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMOVZXDQ, &dst, &src); + } + //! @brief (SSE4.1). + inline void pmovzxdq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMOVZXDQ, &dst, &src); + } + + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULDQ, &dst, &src); + } + //! @brief Multiply Packed Signed Dword Integers (SSE4.1). + inline void pmuldq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULDQ, &dst, &src); + } + + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PMULLD, &dst, &src); + } + //! @brief Multiply Packed Signed Integers and Store Low Result (SSE4.1). + inline void pmulld(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PMULLD, &dst, &src); + } + + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XMMVar& op1, const XMMVar& op2) + { + _emitInstruction(INST_PTEST, &op1, &op2); + } + //! @brief Logical Compare (SSE4.1). + inline void ptest(const XMMVar& op1, const Mem& op2) + { + _emitInstruction(INST_PTEST, &op1, &op2); + } + + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); + } + //! Round Packed SP-FP Values @brief (SSE4.1). + inline void roundps(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDPS, &dst, &src, &imm8); + } + + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); + } + //! @brief Round Scalar SP-FP Values (SSE4.1). + inline void roundss(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDSS, &dst, &src, &imm8); + } + + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); + } + //! @brief Round Packed DP-FP Values (SSE4.1). + inline void roundpd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDPD, &dst, &src, &imm8); + } + + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); + } + //! @brief Round Scalar DP-FP Values (SSE4.1). + inline void roundsd(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_ROUNDSD, &dst, &src, &imm8); + } + + // -------------------------------------------------------------------------- + // [SSE4.2] + // -------------------------------------------------------------------------- + + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_CRC32, &dst, &src); + } + //! @brief Accumulate CRC32 Value (polynomial 0x11EDC6F41) (SSE4.2). + inline void crc32(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_CRC32, &dst, &src); + } + + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); + } + //! @brief Packed Compare Explicit Length Strings, Return Index (SSE4.2). + inline void pcmpestri(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPESTRI, &dst, &src, &imm8); + } + + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); + } + //! @brief Packed Compare Explicit Length Strings, Return Mask (SSE4.2). + inline void pcmpestrm(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPESTRM, &dst, &src, &imm8); + } + + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); + } + //! @brief Packed Compare Implicit Length Strings, Return Index (SSE4.2). + inline void pcmpistri(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPISTRI, &dst, &src, &imm8); + } + + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XMMVar& dst, const XMMVar& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); + } + //! @brief Packed Compare Implicit Length Strings, Return Mask (SSE4.2). + inline void pcmpistrm(const XMMVar& dst, const Mem& src, const Imm& imm8) + { + _emitInstruction(INST_PCMPISTRM, &dst, &src, &imm8); + } + + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XMMVar& dst, const XMMVar& src) + { + _emitInstruction(INST_PCMPGTQ, &dst, &src); + } + //! @brief Compare Packed Data for Greater Than (SSE4.2). + inline void pcmpgtq(const XMMVar& dst, const Mem& src) + { + _emitInstruction(INST_PCMPGTQ, &dst, &src); + } + + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GPVar& dst, const GPVar& src) + { + _emitInstruction(INST_POPCNT, &dst, &src); + } + //! @brief Return the Count of Number of Bits Set to 1 (SSE4.2). + inline void popcnt(const GPVar& dst, const Mem& src) + { + _emitInstruction(INST_POPCNT, &dst, &src); + } + + // -------------------------------------------------------------------------- + // [AMD only] + // -------------------------------------------------------------------------- + + //! @brief Prefetch (3dNow - Amd). + //! + //! Loads the entire 64-byte aligned memory sequence containing the + //! specified memory address into the L1 data cache. The position of + //! the specified memory address within the 64-byte cache line is + //! irrelevant. If a cache hit occurs, or if a memory fault is detected, + //! no bus cycle is initiated and the instruction is treated as a NOP. + inline void amd_prefetch(const Mem& mem) + { + _emitInstruction(INST_AMD_PREFETCH, &mem); + } + + //! @brief Prefetch and set cache to modified (3dNow - Amd). + //! + //! The PREFETCHW instruction loads the prefetched line and sets the + //! cache-line state to Modified, in anticipation of subsequent data + //! writes to the line. The PREFETCH instruction, by contrast, typically + //! sets the cache-line state to Exclusive (depending on the hardware + //! implementation). + inline void amd_prefetchw(const Mem& mem) + { + _emitInstruction(INST_AMD_PREFETCHW, &mem); + } + + // -------------------------------------------------------------------------- + // [Intel only] + // -------------------------------------------------------------------------- + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const GPVar& dst, const Mem& src) + { + ASMJIT_ASSERT(!dst.isGPB()); + _emitInstruction(INST_MOVBE, &dst, &src); + } + + //! @brief Move Data After Swapping Bytes (SSE3 - Intel Atom). + inline void movbe(const Mem& dst, const GPVar& src) + { + ASMJIT_ASSERT(!src.isGPB()); + _emitInstruction(INST_MOVBE, &dst, &src); + } + + // ------------------------------------------------------------------------- + // [Emit Options] + // ------------------------------------------------------------------------- + + //! @brief Assert LOCK# Signal Prefix. + //! + //! This instruction causes the processor's LOCK# signal to be asserted + //! during execution of the accompanying instruction (turns the + //! instruction into an atomic instruction). In a multiprocessor environment, + //! the LOCK# signal insures that the processor has exclusive use of any shared + //! memory while the signal is asserted. + //! + //! The LOCK prefix can be prepended only to the following instructions and + //! to those forms of the instructions that use a memory operand: ADD, ADC, + //! AND, BTC, BTR, BTS, CMPXCHG, DEC, INC, NEG, NOT, OR, SBB, SUB, XOR, XADD, + //! and XCHG. An undefined opcode exception will be generated if the LOCK + //! prefix is used with any other instruction. The XCHG instruction always + //! asserts the LOCK# signal regardless of the presence or absence of the LOCK + //! prefix. + inline void lock() + { + _emitOptions |= EMIT_OPTION_LOCK_PREFIX; + } + + //! @brief Force REX prefix to be emitted. + //! + //! This option should be used carefully, because there are unencodable + //! combinations. If you want to access ah, bh, ch or dh registers then you + //! can't emit REX prefix and it will cause an illegal instruction error. + //! + //! @note REX prefix is only valid for X64/AMD64 platform. + //! + //! @sa @c EMIT_OPTION_REX_PREFIX. + inline void rex() + { + _emitOptions |= EMIT_OPTION_REX_PREFIX; + } +}; + +// ============================================================================ +// [AsmJit::Compiler] +// ============================================================================ + +//! @brief Compiler - high level code generation. +//! +//! This class is used to store instruction stream and allows to modify +//! it on the fly. It uses different concept than @c AsmJit::Assembler class +//! and in fact @c AsmJit::Assembler is only used as a backend. Compiler never +//! emits machine code and each instruction you use is stored to instruction +//! array instead. This allows to modify instruction stream later and for +//! example to reorder instructions to make better performance. +//! +//! Using @c AsmJit::Compiler moves code generation to higher level. Higher +//! level constructs allows to write more abstract and extensible code that +//! is not possible with pure @c AsmJit::Assembler class. Because +//! @c AsmJit::Compiler needs to create many objects and lifetime of these +//! objects is small (same as @c AsmJit::Compiler lifetime itself) it uses +//! very fast memory management model. This model allows to create object +//! instances in nearly zero time (compared to @c malloc() or @c new() +//! operators) so overhead by creating machine code by @c AsmJit::Compiler +//! is minimized. +//! +//! @section AsmJit_Compiler_TheStory The Story +//! +//! Before telling you how Compiler works I'd like to write a story. I'd like +//! to cover reasons why this class was created and why I'm recommending to use +//! it. When I released the first version of AsmJit (0.1) it was a toy. The +//! first function I wrote was function which is still available as testjit and +//! which simply returns 1024. The reason why function works for both 32-bit/ +//! 64-bit mode and for Windows/Unix specific calling conventions is luck, no +//! arguments usage and no registers usage except returning value in EAX/RAX. +//! +//! Then I started a project called BlitJit which was targetted to generating +//! JIT code for computer graphics. After writing some lines I decided that I +//! can't join pieces of code together without abstraction, should be +//! pixels source pointer in ESI/RSI or EDI/RDI or it's completelly +//! irrellevant? What about destination pointer and SSE2 register for reading +//! input pixels? The simple answer might be "just pick some one and use it". +//! +//! Another reason for abstraction is function calling-conventions. It's really +//! not easy to write assembler code for 32-bit and 64-bit platform supporting +//! three calling conventions (32-bit is similar between Windows and Unix, but +//! 64-bit calling conventions are different). +//! +//! At this time I realized that I can't write code which uses named registers, +//! I need to abstract it. In most cases you don't need specific register, you +//! need to emit instruction that does something with 'virtual' register(s), +//! memory, immediate or label. +//! +//! The first version of AsmJit with Compiler was 0.5 (or 0.6?, can't remember). +//! There was support for 32-bit and 64-bit mode, function calling conventions, +//! but when emitting instructions the developer needed to decide which +//! registers are changed, which are only read or completely overwritten. This +//! model helped a lot when generating code, especially when joining more +//! code-sections together, but there was also small possibility for mistakes. +//! Simply the first version of Compiler was great improvement over low-level +//! Assembler class, but the API design wasn't perfect. +//! +//! The second version of Compiler, completelly rewritten and based on +//! different goals, is part of AsmJit starting at version 1.0. This version +//! was designed after the first one and it contains serious improvements over +//! the old one. The first improvement is that you just use instructions with +//! virtual registers - called variables. When using compiler there is no way +//! to use native registers, there are variables instead. AsmJit is smarter +//! than before and it knows which register is needed only for read (r), +//! read/write (w) or overwrite (x). Supported are also instructions which +//! are using some registers in implicit way (these registers are not part of +//! instruction definition in string form). For example to use CPUID instruction +//! you must give it four variables which will be automatically allocated to +//! input/output registers (EAX, EBX, ECX, EDX). +//! +//! Another improvement is algorithm used by a register allocator. In first +//! version the registers were allocated when creating instruction stream. In +//! new version registers are allocated after calling @c Compiler::make(). This +//! means that register allocator has information about scope of all variables +//! and their usage statistics. The algorithm to allocate registers is very +//! simple and it's always called as a 'linear scan register allocator'. When +//! you get out of registers the all possible variables are scored and the worst +//! is spilled. Of course algorithm ignores the variables used for current +//! instruction. +//! +//! In addition, because registers are allocated after the code stream is +//! generated, the state switches between jumps are handled by Compiler too. +//! You don't need to worry about jumps, compiler always do this dirty work +//! for you. +//! +//! The nearly last thing I'd like to present is calling other functions from +//! the generated code. AsmJit uses a @c FunctionPrototype class to hold +//! the function parameters, their position in stack (or register index) and +//! function return value. This class is used internally, but it can be +//! used to create your own function calling-convention. All standard function +//! calling conventions are implemented. +//! +//! Please enjoy the new version of Compiler, it was created for writing a +//! low-level code using high-level API, leaving developer to concentrate to +//! real problems and not to solving a register puzzle. +//! +//! @section AsmJit_Compiler_CodeGeneration Code Generation +//! +//! First that is needed to know about compiler is that compiler never emits +//! machine code. It's used as a middleware between @c AsmJit::Assembler and +//! your code. There is also convenience method @c make() that allows to +//! generate machine code directly without creating @c AsmJit::Assembler +//! instance. +//! +//! Comparison of generating machine code through @c Assembler and directly +//! by @c Compiler: +//! +//! @code +//! // Assembler instance is low level code generation class that emits +//! // machine code. +//! Assembler a; +//! +//! // Compiler instance is high level code generation class that stores all +//! // instructions in internal representation. +//! Compiler c; +//! +//! // ... put your code here ... +//! +//! // Final step - generate code. AsmJit::Compiler::serialize() will serialize +//! // all instructions into Assembler and this ensures generating real machine +//! // code. +//! c.serialize(a); +//! +//! // Your function +//! void* fn = a.make(); +//! @endcode +//! +//! Example how to generate machine code using only @c Compiler (preferred): +//! +//! @code +//! // Compiler instance is enough. +//! Compiler c; +//! +//! // ... put your code here ... +//! +//! // Your function +//! void* fn = c.make(); +//! @endcode +//! +//! You can see that there is @c AsmJit::Compiler::serialize() function that +//! emits instructions into @c AsmJit::Assembler(). This layered architecture +//! means that each class is used for something different and there is no code +//! duplication. For convenience there is also @c AsmJit::Compiler::make() +//! method that can create your function using @c AsmJit::Assembler, but +//! internally (this is preffered bahavior when using @c AsmJit::Compiler). +//! +//! The @c make() method allocates memory using @c CodeGenerator instance passed +//! into the @c Compiler constructor. If code generator is used to create JIT +//! function then virtual memory allocated by @c MemoryManager is used. To get +//! global memory manager use @c MemoryManager::getGlobal(). +//! +//! @code +//! // Compiler instance is enough. +//! Compiler c; +//! +//! // ... put your code using Compiler instance ... +//! +//! // Your function +//! void* fn = c.make(); +//! +//! // Free it if you don't want it anymore +//! // (using global memory manager instance) +//! MemoryManager::getGlobal()->free(fn); +//! @endcode +//! +//! @section AsmJit_Compiler_Functions Functions +//! +//! To build functions with @c Compiler, see @c AsmJit::Compiler::newFunction() +//! method. +//! +//! @section AsmJit_Compiler_Variables Variables +//! +//! Compiler is able to manage variables and function arguments. Internally +//! there is no difference between function argument and variable declared +//! inside. To get function argument you use @c argGP() method and to declare +//! variable use @c newGP(), @c newMM() and @c newXMM() methods. The @c newXXX() +//! methods accept also parameter describing the variable type. For example +//! the @c newGP() method always creates variable which size matches the target +//! architecture size (for 32-bit target the 32-bit variable is created, for +//! 64-bit target the variable size is 64-bit). To override this behavior the +//! variable type must be specified. +//! +//! @code +//! // Compiler and function declaration - void f(int*); +//! Compiler c; +//! c.newFunction(CALL_CONV_DEFAULT, BuildFunction1<int*>()); +//! +//! // Get argument variable (it's pointer). +//! GPVar a1(c.argGP(0)); +//! +//! // Create your variables. +//! GPVar x1(c.newGP(VARIABLE_TYPE_GPD)); +//! GPVar x2(c.newGP(VARIABLE_TYPE_GPD)); +//! +//! // Init your variables. +//! c.mov(x1, 1); +//! c.mov(x2, 2); +//! +//! // ... your code ... +//! c.add(x1, x2); +//! // ... your code ... +//! +//! // Store result to a given pointer in first argument +//! c.mov(dword_ptr(a1), x1); +//! +//! // End of function body. +//! c.endFunction(); +//! +//! // Make the function. +//! typedef void (*MyFn)(int*); +//! MyFn fn = function_cast<MyFn>(c.make()); +//! @endcode +//! +//! This code snipped needs to be explained. You can see that there are more +//! variable types that can be used by @c Compiler. Most useful variables can +//! be allocated using general purpose registers (@c GPVar), MMX registers +//! (@c MMVar) or SSE registers (@c XMMVar). +//! +//! X86/X64 variable types: +//! +//! - @c VARIABLE_TYPE_GPD - 32-bit general purpose register (EAX, EBX, ...). +//! - @c VARIABLE_TYPE_GPQ - 64-bit general purpose register (RAX, RBX, ...). +//! - @c VARIABLE_TYPE_GPN - 32-bit or 64-bit general purpose register, depends +//! to target architecture. Mapped to @c VARIABLE_TYPE_GPD or @c VARIABLE_TYPE_GPQ. +//! +//! - @c VARIABLE_TYPE_X87 - 80-bit floating point stack register st(0 to 7). +//! - @c VARIABLE_TYPE_X87_1F - 32-bit floating point stack register st(0 to 7). +//! - @c VARIABLE_TYPE_X87_1D - 64-bit floating point stack register st(0 to 7). +//! +//! - @c VARIALBE_TYPE_MM - 64-bit MMX register. +//! +//! - @c VARIABLE_TYPE_XMM - 128-bit SSE register. +//! - @c VARIABLE_TYPE_XMM_1F - 128-bit SSE register which contains +//! scalar 32-bit single precision floating point. +//! - @c VARIABLE_TYPE_XMM_1D - 128-bit SSE register which contains +//! scalar 64-bit double precision floating point. +//! - @c VARIABLE_TYPE_XMM_4F - 128-bit SSE register which contains +//! 4 packed 32-bit single precision floating points. +//! - @c VARIABLE_TYPE_XMM_2D - 128-bit SSE register which contains +//! 2 packed 64-bit double precision floating points. +//! +//! Unified variable types: +//! +//! - @c VARIABLE_TYPE_INT32 - 32-bit general purpose register. +//! - @c VARIABLE_TYPE_INT64 - 64-bit general purpose register. +//! - @c VARIABLE_TYPE_INTPTR - 32-bit or 64-bit general purpose register / pointer. +//! +//! - @c VARIABLE_TYPE_FLOAT - 32-bit single precision floating point. +//! - @c VARIABLE_TYPE_DOUBLE - 64-bit double precision floating point. +//! +//! Variable states: +//! +//! - @c VARIABLE_STATE_UNUSED - State that is assigned to newly created +//! variables or to not used variables (dereferenced to zero). +//! - @c VARIABLE_STATE_REGISTER - State that means that variable is currently +//! allocated in register. +//! - @c VARIABLE_STATE_MEMORY - State that means that variable is currently +//! only in memory location. +//! +//! When you create new variable, initial state is always @c VARIABLE_STATE_UNUSED, +//! allocating it to register or spilling to memory changes this state to +//! @c VARIABLE_STATE_REGISTER or @c VARIABLE_STATE_MEMORY, respectively. +//! During variable lifetime it's usual that its state is changed multiple +//! times. To generate better code, you can control allocating and spilling +//! by using up to four types of methods that allows it (see next list). +//! +//! Explicit variable allocating / spilling methods: +//! +//! - @c Compiler::alloc() - Explicit method to alloc variable into +//! register. You can use this before loops or code blocks. +//! +//! - @c Compiler::spill() - Explicit method to spill variable. If variable +//! is in register and you call this method, it's moved to its home memory +//! location. If variable is not in register no operation is performed. +//! +//! - @c Compiler::unuse() - Unuse variable (you can use this to end the +//! variable scope or sub-scope). +//! +//! Please see AsmJit tutorials (testcompiler.cpp and testvariables.cpp) for +//! more complete examples. +//! +//! @section AsmJit_Compiler_MemoryManagement Memory Management +//! +//! @c Compiler Memory management follows these rules: +//! - Everything created by @c Compiler is always freed by @c Compiler. +//! - To get decent performance, compiler always uses larger memory buffer +//! for objects to allocate and when compiler instance is destroyed, this +//! buffer is freed. Destructors of active objects are called when +//! destroying compiler instance. Destructors of abadonded compiler +//! objects are called immediately after abadonding them. +//! - This type of memory management is called 'zone memory management'. +//! +//! This means that you can't use any @c Compiler object after destructing it, +//! it also means that each object like @c Label, @c Var and others are created +//! and managed by @c Compiler itself. These objects contain ID which is used +//! internally by Compiler to store additional information about these objects. +//! +//! @section AsmJit_Compiler_StateManagement Control-Flow and State Management. +//! +//! The @c Compiler automatically manages state of the variables when using +//! control flow instructions like jumps, conditional jumps and calls. There +//! is minimal heuristics for choosing the method how state is saved or restored. +//! +//! Generally the state can be changed only when using jump or conditional jump +//! instruction. When using non-conditional jump then state change is embedded +//! into the instruction stream before the jump. When using conditional jump +//! the @c Compiler decides whether to restore state before the jump or whether +//! to use another block where state is restored. The last case is that no-code +//! have to be emitted and there is no state change (this is of course ideal). +//! +//! Choosing whether to embed 'restore-state' section before conditional jump +//! is quite simple. If jump is likely to be 'taken' then code is embedded, if +//! jump is unlikely to be taken then the small code section for state-switch +//! will be generated instead. +//! +//! Next example is the situation where the extended code block is used to +//! do state-change: +//! +//! @code +//! Compiler c; +//! +//! c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0<Void>()); +//! c.getFunction()->setHint(FUNCTION_HINT_NAKED, true); +//! +//! // Labels. +//! Label L0 = c.newLabel(); +//! +//! // Variables. +//! GPVar var0 = c.newGP(); +//! GPVar var1 = c.newGP(); +//! +//! // Cleanup. After these two lines, the var0 and var1 will be always stored +//! // in registers. Our example is very small, but in larger code the var0 can +//! // be spilled by xor(var1, var1). +//! c.xor_(var0, var0); +//! c.xor_(var1, var1); +//! c.cmp(var0, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We manually spill these variables. +//! c.spill(var0); +//! c.spill(var1); +//! // State: +//! // var0 - memory. +//! // var1 - memory. +//! +//! // Conditional jump to L0. It will be always taken, but compiler thinks that +//! // it is unlikely taken so it will embed state change code somewhere. +//! c.je(L0); +//! +//! // Do something. The variables var0 and var1 will be allocated again. +//! c.add(var0, 1); +//! c.add(var1, 2); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // Bind label here, the state is not changed. +//! c.bind(L0); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We need to use var0 and var1, because if compiler detects that variables +//! // are out of scope then it optimizes the state-change. +//! c.sub(var0, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! c.endFunction(); +//! @endcode +//! +//! The output: +//! +//! @verbatim +//! xor eax, eax ; xor var_0, var_0 +//! xor ecx, ecx ; xor var_1, var_1 +//! cmp eax, ecx ; cmp var_0, var_1 +//! mov [esp - 24], eax ; spill var_0 +//! mov [esp - 28], ecx ; spill var_1 +//! je L0_Switch +//! mov eax, [esp - 24] ; alloc var_0 +//! add eax, 1 ; add var_0, 1 +//! mov ecx, [esp - 28] ; alloc var_1 +//! add ecx, 2 ; add var_1, 2 +//! L0: +//! sub eax, ecx ; sub var_0, var_1 +//! ret +//! +//! ; state-switch begin +//! L0_Switch0: +//! mov eax, [esp - 24] ; alloc var_0 +//! mov ecx, [esp - 28] ; alloc var_1 +//! jmp short L0 +//! ; state-switch end +//! @endverbatim +//! +//! You can see that the state-switch section was generated (see L0_Switch0). +//! The compiler is unable to restore state immediately when emitting the +//! forward jump (the code is generated from first to last instruction and +//! the target state is simply not known at this time). +//! +//! To tell @c Compiler that you want to embed state-switch code before jump +//! it's needed to create backward jump (where also processor expects that it +//! will be taken). To demonstrate the possibility to embed state-switch before +//! jump we use slightly modified code: +//! +//! @code +//! Compiler c; +//! +//! c.newFunction(CALL_CONV_DEFAULT, FunctionBuilder0<Void>()); +//! c.getFunction()->setHint(FUNCTION_HINT_NAKED, true); +//! +//! // Labels. +//! Label L0 = c.newLabel(); +//! +//! // Variables. +//! GPVar var0 = c.newGP(); +//! GPVar var1 = c.newGP(); +//! +//! // Cleanup. After these two lines, the var0 and var1 will be always stored +//! // in registers. Our example is very small, but in larger code the var0 can +//! // be spilled by xor(var1, var1). +//! c.xor_(var0, var0); +//! c.xor_(var1, var1); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // We manually spill these variables. +//! c.spill(var0); +//! c.spill(var1); +//! // State: +//! // var0 - memory. +//! // var1 - memory. +//! +//! // Bind our label here. +//! c.bind(L0); +//! +//! // Do something, the variables will be allocated again. +//! c.add(var0, 1); +//! c.add(var1, 2); +//! // State: +//! // var0 - register. +//! // var1 - register. +//! +//! // Backward conditional jump to L0. The default behavior is that it is taken +//! // so state-change code will be embedded here. +//! c.je(L0); +//! +//! c.endFunction(); +//! @endcode +//! +//! The output: +//! +//! @verbatim +//! xor ecx, ecx ; xor var_0, var_0 +//! xor edx, edx ; xor var_1, var_1 +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! L.2: +//! mov ecx, [esp - 24] ; alloc var_0 +//! add ecx, 1 ; add var_0, 1 +//! mov edx, [esp - 28] ; alloc var_1 +//! add edx, 2 ; add var_1, 2 +//! +//! ; state-switch begin +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! ; state-switch end +//! +//! je short L.2 +//! ret +//! @endverbatim +//! +//! Please notice where the state-switch section is located. The @c Compiler +//! decided that jump is likely to be taken so the state change is embedded +//! before the conditional jump. To change this behavior into the previous +//! case it's needed to add a hint (@c HINT_TAKEN or @c HINT_NOT_TAKEN). +//! +//! Replacing the <code>c.je(L0)</code> by <code>c.je(L0, HINT_NOT_TAKEN) +//! will generate code like this: +//! +//! @verbatim +//! xor ecx, ecx ; xor var_0, var_0 +//! xor edx, edx ; xor var_1, var_1 +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! L0: +//! mov ecx, [esp - 24] ; alloc var_0 +//! add ecx, 1 ; add var_0, a +//! mov edx, [esp - 28] ; alloc var_1 +//! add edx, 2 ; add var_1, 2 +//! je L0_Switch, 2 +//! ret +//! +//! ; state-switch begin +//! L0_Switch: +//! mov [esp - 24], ecx ; spill var_0 +//! mov [esp - 28], edx ; spill var_1 +//! jmp short L0 +//! ; state-switch end +//! @endverbatim +//! +//! This section provided information about how state-change works. The +//! behavior is deterministic and it can be overriden. +//! +//! @section AsmJit_Compiler_AdvancedCodeGeneration Advanced Code Generation +//! +//! This section describes advanced method of code generation available to +//! @c Compiler (but also to @c Assembler). When emitting code to instruction +//! stream the methods like @c mov(), @c add(), @c sub() can be called directly +//! (advantage is static-type control performed also by C++ compiler) or +//! indirectly using @c emit() method. The @c emit() method needs only +//! instruction code and operands. +//! +//! Example of code generating by standard type-safe API: +//! +//! @code +//! Compiler c; +//! GPVar var0 = c.newGP(); +//! GPVar var1 = c.newGP(); +//! +//! ... +//! +//! c.mov(var0, imm(0)); +//! c.add(var0, var1); +//! c.sub(var0, var1); +//! @endcode +//! +//! The code above can be rewritten as: +//! +//! @code +//! Compiler c; +//! GPVar var0 = c.newGP(); +//! GPVar var1 = c.newGP(); +//! +//! ... +//! +//! c.emit(INST_MOV, var0, imm(0)); +//! c.emit(INST_ADD, var0, var1); +//! c.emit(INST_SUB, var0, var1); +//! @endcode +//! +//! The advantage of first snippet is very friendly API and type-safe control +//! that is controlled by the C++ compiler. The advantage of second snippet is +//! availability to replace or generate instruction code in different places. +//! See the next example how the @c emit() method can be used to generate +//! abstract code. +//! +//! Use case: +//! +//! @code +//! bool emitArithmetic(Compiler& c, XMMVar& var0, XMMVar& var1, const char* op) +//! { +//! uint code = INVALID_VALUE; +//! +//! if (strcmp(op, "ADD") == 0) +//! code = INST_ADDSS; +//! else if (strcmp(op, "SUBTRACT") == 0) +//! code = INST_SUBSS; +//! else if (strcmp(op, "MULTIPLY") == 0) +//! code = INST_MULSS; +//! else if (strcmp(op, "DIVIDE") == 0) +//! code = INST_DIVSS; +//! else +//! // Invalid parameter? +//! return false; +//! +//! c.emit(code, var0, var1); +//! } +//! @endcode +//! +//! Other use cases are waiting for you! Be sure that instruction you are +//! emitting is correct and encodable, because if not, Assembler will set +//! error code to @c ERROR_UNKNOWN_INSTRUCTION. +//! +//! @section AsmJit_Compiler_CompilerDetails Compiler Details +//! +//! This section is here for people interested in the compiling process. There +//! are few steps that must be done for each compiled function (or your code). +//! +//! When your @c Compiler instance is ready, you can create function and add +//! emittables using intrinsics or higher level methods implemented by the +//! @c AsmJit::Compiler. When you are done (all instructions serialized) you +//! should call @c AsmJit::Compiler::make() method which will analyze your code, +//! allocate registers and memory for local variables and serialize all emittables +//! to @c AsmJit::Assembler instance. Next steps shows what's done internally +//! before code is serialized into @c AsmJit::Assembler +//! (implemented in @c AsmJit::Compiler::serialize() method). +//! +//! 1. Compiler try to match function and end-function emittables (these +//! emittables define the function-body or function block). +//! +//! 2. For all emittables inside the function-body the virtual functions +//! are called in this order: +//! - Emittable::prepare() +//! - Emittable::translate() +//! - Emittable::emit() +//! - Emittable::post() +//! +//! There is some extra work when emitting function prolog / epilog and +//! register allocator. +//! +//! 3. Emit jump tables data. +//! +//! When everything here ends, @c AsmJit::Assembler contains binary stream +//! that needs only relocation to be callable by C/C++ code. +//! +//! @section AsmJit_Compiler_Differences Summary of Differences between @c Assembler and @c Compiler +//! +//! - Instructions are not translated to machine code immediately, they are +//! stored as emmitables (see @c AsmJit::Emittable, @c AsmJit::EInstruction). +//! - Contains function builder and ability to call other functions. +//! - Contains register allocator and variable management. +//! - Contains a lot of helper methods to simplify the code generation not +//! available/possible in @c AsmJit::Assembler. +//! - Ability to pre-process or post-process the code which is being generated. +struct ASMJIT_API Compiler : public CompilerIntrinsics +{ + //! @brief Create the @c Compiler instance. + Compiler(CodeGenerator* codeGenerator = NULL) ASMJIT_NOTHROW; + //! @brief Destroy the @c Compiler instance. + virtual ~Compiler() ASMJIT_NOTHROW; +}; + +//! @} + +} // AsmJit namespace + +#undef ASMJIT_NOT_SUPPORTED_BY_COMPILER + +// [Api-End] +#include "ApiEnd.h" + +// [Guard] +#endif // _ASMJIT_COMPILERX86X64_H |