sm-ext-dhooks2/DynamicHooks/thirdparty/AsmJit/base/hlstream.h

1175 lines
40 KiB
C++

// [AsmJit]
// Complete x86/x64 JIT and Remote Assembler for C++.
//
// [License]
// Zlib - See LICENSE.md file in the package.
// [Guard]
#ifndef _ASMJIT_BASE_HLSTREAM_H
#define _ASMJIT_BASE_HLSTREAM_H
#include "../build.h"
#if !defined(ASMJIT_DISABLE_COMPILER)
// [Dependencies]
#include "../base/assembler.h"
#include "../base/operand.h"
// TODO: Cannot depend on it.
#include "../base/compilerfunc.h"
// [Api-Begin]
#include "../apibegin.h"
namespace asmjit {
// ============================================================================
// [Forward Declarations]
// ============================================================================
class Compiler;
struct VarData;
struct VarState;
struct VarMap;
class HLInst;
class HLJump;
class HLLabel;
class HLSentinel;
//! \addtogroup asmjit_base
//! \{
// ============================================================================
// [asmjit::HLNode]
// ============================================================================
//! Base node (HL).
//!
//! Every node represents an abstract instruction, directive, label, or macro
//! instruction that can be serialized to `Assembler`.
class HLNode {
public:
ASMJIT_NO_COPY(HLNode)
// --------------------------------------------------------------------------
// [Type]
// --------------------------------------------------------------------------
//! Type of \ref HLNode.
ASMJIT_ENUM(Type) {
//! Invalid node (internal, don't use).
kTypeNone = 0,
// --------------------------------------------------------------------------
// [Low-Level - Assembler / Compiler]
// --------------------------------------------------------------------------
//! Node is \ref HLInst or \ref HLJump.
kTypeInst,
//! Node is \ref HLData.
kTypeData,
//! Node is \ref HLAlign.
kTypeAlign,
//! Node is \ref HLLabel.
kTypeLabel,
//! Node is \ref HLComment.
kTypeComment,
//! Node is \ref HLSentinel.
kTypeSentinel,
// --------------------------------------------------------------------------
// [High-Level - Compiler-Only]
// --------------------------------------------------------------------------
//! Node is \ref HLHint.
kTypeHint,
//! Node is \ref HLFunc.
kTypeFunc,
//! Node is \ref HLRet.
kTypeRet,
//! Node is \ref HLCall.
kTypeCall,
//! Node is \ref HLCallArg.
kTypeCallArg
};
// --------------------------------------------------------------------------
// [Flags]
// --------------------------------------------------------------------------
ASMJIT_ENUM(Flags) {
//! Whether the node has been translated, thus contains only registers.
kFlagIsTranslated = 0x0001,
//! Whether the node was scheduled - possibly reordered, but basically this
//! is a mark that is set by scheduler after the node has been visited.
kFlagIsScheduled = 0x0002,
//! Whether the node can be safely removed by the `Compiler` in case it's
//! unreachable.
kFlagIsRemovable = 0x0004,
//! Whether the node is informative only and can be safely removed.
kFlagIsInformative = 0x0008,
//! Whether the `HLInst` is a jump.
kFlagIsJmp = 0x0010,
//! Whether the `HLInst` is a conditional jump.
kFlagIsJcc = 0x0020,
//! Whether the `HLInst` is an unconditinal jump or conditional jump that is
//! likely to be taken.
kFlagIsTaken = 0x0040,
//! Whether the `HLNode` will return from a function.
//!
//! This flag is used by both `HLSentinel` and `HLRet`.
kFlagIsRet = 0x0080,
//! Whether the instruction is special.
kFlagIsSpecial = 0x0100,
//! Whether the instruction is an FPU instruction.
kFlagIsFp = 0x0200
};
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLNode`.
//!
//! NOTE: Always use compiler to create nodes.
ASMJIT_INLINE HLNode(Compiler* compiler, uint32_t type) noexcept; // Defined-Later.
//! Destroy the `HLNode`.
//!
//! NOTE: Nodes are zone allocated, there should be no code in the destructor.
ASMJIT_INLINE ~HLNode() noexcept {}
// --------------------------------------------------------------------------
// [Accessors - List]
// --------------------------------------------------------------------------
//! Get previous node in the compiler stream.
ASMJIT_INLINE HLNode* getPrev() const noexcept { return _prev; }
//! Get next node in the compiler stream.
ASMJIT_INLINE HLNode* getNext() const noexcept { return _next; }
// --------------------------------------------------------------------------
// [Accessors - Comment]
// --------------------------------------------------------------------------
//! Get an inline comment string.
ASMJIT_INLINE const char* getComment() const noexcept { return _comment; }
//! Set an inline comment string to `comment`.
ASMJIT_INLINE void setComment(const char* comment) noexcept { _comment = comment; }
// --------------------------------------------------------------------------
// [Accessors - Type and Flags]
// --------------------------------------------------------------------------
//! Get the node type, see \ref Type.
ASMJIT_INLINE uint32_t getType() const noexcept { return _type; }
//! Get the node flags.
ASMJIT_INLINE uint32_t getFlags() const noexcept { return _flags; }
//! Get whether the instruction has flag `flag`.
ASMJIT_INLINE bool hasFlag(uint32_t flag) const noexcept { return (static_cast<uint32_t>(_flags) & flag) != 0; }
//! Set node flags to `flags`.
ASMJIT_INLINE void setFlags(uint32_t flags) noexcept { _flags = static_cast<uint16_t>(flags); }
//! Add instruction `flags`.
ASMJIT_INLINE void orFlags(uint32_t flags) noexcept { _flags |= static_cast<uint16_t>(flags); }
//! And instruction `flags`.
ASMJIT_INLINE void andFlags(uint32_t flags) noexcept { _flags &= static_cast<uint16_t>(flags); }
//! Clear instruction `flags`.
ASMJIT_INLINE void andNotFlags(uint32_t flags) noexcept { _flags &= ~static_cast<uint16_t>(flags); }
//! Get whether the node has beed fetched.
ASMJIT_INLINE bool isFetched() const noexcept { return _flowId != 0; }
//! Get whether the node has been translated.
ASMJIT_INLINE bool isTranslated() const noexcept { return hasFlag(kFlagIsTranslated); }
//! Get whether the node has been translated.
ASMJIT_INLINE bool isScheduled() const noexcept { return hasFlag(kFlagIsScheduled); }
//! Get whether the node is removable if it's in unreachable code block.
ASMJIT_INLINE bool isRemovable() const noexcept { return hasFlag(kFlagIsRemovable); }
//! Get whether the node is informative only (comment, hint).
ASMJIT_INLINE bool isInformative() const noexcept { return hasFlag(kFlagIsInformative); }
//! Whether the node is `HLLabel`.
ASMJIT_INLINE bool isLabel() const noexcept { return _type == kTypeLabel; }
//! Whether the `HLInst` node is an unconditional jump.
ASMJIT_INLINE bool isJmp() const noexcept { return hasFlag(kFlagIsJmp); }
//! Whether the `HLInst` node is a conditional jump.
ASMJIT_INLINE bool isJcc() const noexcept { return hasFlag(kFlagIsJcc); }
//! Whether the `HLInst` node is a conditional/unconditional jump.
ASMJIT_INLINE bool isJmpOrJcc() const noexcept { return hasFlag(kFlagIsJmp | kFlagIsJcc); }
//! Whether the `HLInst` node is a return.
ASMJIT_INLINE bool isRet() const noexcept { return hasFlag(kFlagIsRet); }
//! Get whether the node is `HLInst` and the instruction is special.
ASMJIT_INLINE bool isSpecial() const noexcept { return hasFlag(kFlagIsSpecial); }
//! Get whether the node is `HLInst` and the instruction uses x87-FPU.
ASMJIT_INLINE bool isFp() const noexcept { return hasFlag(kFlagIsFp); }
// --------------------------------------------------------------------------
// [Accessors - FlowId]
// --------------------------------------------------------------------------
//! Get flow index.
ASMJIT_INLINE uint32_t getFlowId() const noexcept { return _flowId; }
//! Set flow index.
ASMJIT_INLINE void setFlowId(uint32_t flowId) noexcept { _flowId = flowId; }
// --------------------------------------------------------------------------
// [Accessors - TokenId]
// --------------------------------------------------------------------------
ASMJIT_INLINE bool hasTokenId(uint32_t id) const noexcept { return _tokenId == id; }
ASMJIT_INLINE uint32_t getTokenId() const noexcept { return _tokenId; }
ASMJIT_INLINE void setTokenId(uint32_t id) noexcept { _tokenId = id; }
// --------------------------------------------------------------------------
// [Accessors - VarMap]
// --------------------------------------------------------------------------
//! Get whether node contains variable allocation instructions.
ASMJIT_INLINE bool hasMap() const noexcept { return _map != nullptr; }
//! Get variable allocation instructions.
ASMJIT_INLINE VarMap* getMap() const noexcept { return _map; }
//! Get variable allocation instructions casted to `T*`.
template<typename T>
ASMJIT_INLINE T* getMap() const noexcept { return static_cast<T*>(_map); }
//! Set variable allocation instructions.
ASMJIT_INLINE void setMap(VarMap* map) noexcept { _map = map; }
// --------------------------------------------------------------------------
// [Accessors - VarState]
// --------------------------------------------------------------------------
//! Get whether the node has an associated `VarState`.
ASMJIT_INLINE bool hasState() const noexcept { return _state != nullptr; }
//! Get node state.
ASMJIT_INLINE VarState* getState() const noexcept { return _state; }
//! Get node state casted to `T*`.
template<typename T>
ASMJIT_INLINE T* getState() const noexcept { return static_cast<T*>(_state); }
//! Set node state.
ASMJIT_INLINE void setState(VarState* state) noexcept { _state = state; }
// --------------------------------------------------------------------------
// [Accessors - Liveness]
// --------------------------------------------------------------------------
//! Get whether the node has variable liveness bits.
ASMJIT_INLINE bool hasLiveness() const noexcept { return _liveness != nullptr; }
//! Get variable liveness bits.
ASMJIT_INLINE BitArray* getLiveness() const noexcept { return _liveness; }
//! Set variable liveness bits.
ASMJIT_INLINE void setLiveness(BitArray* liveness) noexcept { _liveness = liveness; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Previous node.
HLNode* _prev;
//! Next node.
HLNode* _next;
//! Node type, see \ref Type.
uint8_t _type;
//! Count of operands (if the node has operands, otherwise zero).
uint8_t _opCount;
//! Flags, different meaning for every type of the node.
uint16_t _flags;
//! Flow index.
uint32_t _flowId;
//! Processing token ID.
//!
//! Used by some algorithms to mark nodes as visited. If the token is
//! generated in an incrementing way the visitor can just mark nodes it
//! visits and them compare the `HLNode`s token with it's local token.
//! If they match the node has been visited already. Then the visitor
//! doesn't need to clean things up as the next time the token will be
//! different.
uint32_t _tokenId;
// TODO: 32-bit gap
//! Inline comment string, initially set to nullptr.
const char* _comment;
//! Variable mapping (VarAttr to VarData), initially nullptr, filled during
//! fetch phase.
VarMap* _map;
//! Variable liveness bits (initially nullptr, filled by analysis phase).
BitArray* _liveness;
//! Saved state.
//!
//! Initially nullptr, not all nodes have saved state, only branch/flow control
//! nodes.
VarState* _state;
};
// ============================================================================
// [asmjit::HLInst]
// ============================================================================
//! Instruction (HL).
//!
//! Wraps an instruction with its options and operands.
class HLInst : public HLNode {
public:
ASMJIT_NO_COPY(HLInst)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLInst` instance.
ASMJIT_INLINE HLInst(Compiler* compiler, uint32_t instId, uint32_t instOptions, Operand* opList, uint32_t opCount) noexcept
: HLNode(compiler, kTypeInst) {
orFlags(kFlagIsRemovable);
_instId = static_cast<uint16_t>(instId);
_reserved = 0;
_instOptions = instOptions;
_opCount = static_cast<uint8_t>(opCount);
_opList = opList;
_updateMemOp();
}
//! Destroy the `HLInst` instance.
ASMJIT_INLINE ~HLInst() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the instruction id, see `X86InstId`.
ASMJIT_INLINE uint32_t getInstId() const noexcept { return _instId; }
//! Set the instruction id to `instId`.
//!
//! NOTE: Please do not modify instruction code if you don't know what you
//! are doing. Incorrect instruction code and/or operands can cause random
//! errors in production builds and will most probably trigger assertion
//! failures in debug builds.
ASMJIT_INLINE void setInstId(uint32_t instId) noexcept { _instId = static_cast<uint16_t>(instId); }
//! Whether the instruction is either a jump or a conditional jump likely to
//! be taken.
ASMJIT_INLINE bool isTaken() const noexcept { return hasFlag(kFlagIsTaken); }
//! Get emit options.
ASMJIT_INLINE uint32_t getOptions() const noexcept { return _instOptions; }
//! Set emit options.
ASMJIT_INLINE void setOptions(uint32_t options) noexcept { _instOptions = options; }
//! Add emit options.
ASMJIT_INLINE void addOptions(uint32_t options) noexcept { _instOptions |= options; }
//! Mask emit options.
ASMJIT_INLINE void andOptions(uint32_t options) noexcept { _instOptions &= options; }
//! Clear emit options.
ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _instOptions &= ~options; }
//! Get operands count.
ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; }
//! Get operands list.
ASMJIT_INLINE Operand* getOpList() noexcept { return _opList; }
//! \overload
ASMJIT_INLINE const Operand* getOpList() const noexcept { return _opList; }
//! Get whether the instruction contains a memory operand.
ASMJIT_INLINE bool hasMemOp() const noexcept { return _memOpIndex != 0xFF; }
//! Get memory operand.
//!
//! NOTE: Can only be called if the instruction has such operand,
//! see `hasMemOp()`.
ASMJIT_INLINE BaseMem* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<BaseMem*>(&_opList[_memOpIndex]);
}
//! \overload
template<typename T>
ASMJIT_INLINE T* getMemOp() const noexcept {
ASMJIT_ASSERT(hasMemOp());
return static_cast<T*>(&_opList[_memOpIndex]);
}
//! Set memory operand index, `0xFF` means no memory operand.
ASMJIT_INLINE void setMemOpIndex(uint32_t index) noexcept { _memOpIndex = static_cast<uint8_t>(index); }
//! Reset memory operand index to `0xFF` (no operand).
ASMJIT_INLINE void resetMemOpIndex() noexcept { _memOpIndex = 0xFF; }
// --------------------------------------------------------------------------
// [Utils]
// --------------------------------------------------------------------------
ASMJIT_INLINE void _updateMemOp() noexcept {
Operand* opList = getOpList();
uint32_t opCount = getOpCount();
uint32_t i;
for (i = 0; i < opCount; i++)
if (opList[i].isMem())
goto L_Update;
i = 0xFF;
L_Update:
setMemOpIndex(i);
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Instruction ID, see `InstId`.
uint16_t _instId;
//! \internal
uint8_t _memOpIndex;
//! \internal
uint8_t _reserved;
//! Instruction options, see `InstOptions`.
uint32_t _instOptions;
//! Operands list.
Operand* _opList;
};
// ============================================================================
// [asmjit::HLJump]
// ============================================================================
//! Conditional or direct jump (HL).
//!
//! Extension of `HLInst` node, which stores more information about the jump.
class HLJump : public HLInst {
public:
ASMJIT_NO_COPY(HLJump)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
ASMJIT_INLINE HLJump(Compiler* compiler, uint32_t code, uint32_t options, Operand* opList, uint32_t opCount) noexcept
: HLInst(compiler, code, options, opList, opCount),
_target(nullptr),
_jumpNext(nullptr) {}
ASMJIT_INLINE ~HLJump() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
ASMJIT_INLINE HLLabel* getTarget() const noexcept { return _target; }
ASMJIT_INLINE HLJump* getJumpNext() const noexcept { return _jumpNext; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Target node.
HLLabel* _target;
//! Next jump to the same target in a single linked-list.
HLJump* _jumpNext;
};
// ============================================================================
// [asmjit::HLData]
// ============================================================================
//! Data (HL).
//!
//! Wraps `.data` directive. The node contains data that will be placed at the
//! node's position in the assembler stream. The data is considered to be RAW;
//! no analysis nor byte-order conversion is performed on RAW data.
class HLData : public HLNode {
public:
ASMJIT_NO_COPY(HLData)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
enum { kInlineBufferSize = 12 };
//! Create a new `HLData` instance.
ASMJIT_INLINE HLData(Compiler* compiler, void* data, uint32_t size) noexcept
: HLNode(compiler, kTypeData) {
_size = size;
if (size <= kInlineBufferSize) {
if (data != nullptr)
::memcpy(_data.buf, data, size);
}
else {
_data.ptr = static_cast<uint8_t*>(data);
}
}
//! Destroy the `HLData` instance.
ASMJIT_INLINE ~HLData() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get size of the data.
uint32_t getSize() const noexcept { return _size; }
//! Get pointer to the data.
uint8_t* getData() const noexcept { return _size <= kInlineBufferSize ? const_cast<uint8_t*>(_data.buf) : _data.ptr; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
union {
//! data buffer.
uint8_t buf[kInlineBufferSize];
//! Data buffer.
uint8_t* ptr;
} _data;
//! Size of the data.
uint32_t _size;
};
// ============================================================================
// [asmjit::HLAlign]
// ============================================================================
//! Align directive (HL).
//!
//! Wraps `.align` directive.
class HLAlign : public HLNode {
public:
ASMJIT_NO_COPY(HLAlign)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLAlign` instance.
ASMJIT_INLINE HLAlign(Compiler* compiler, uint32_t alignMode, uint32_t offset) noexcept
: HLNode(compiler, kTypeAlign) {
_alignMode = alignMode;
_offset = offset;
}
//! Destroy the `HLAlign` instance.
ASMJIT_INLINE ~HLAlign() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get align mode.
ASMJIT_INLINE uint32_t getAlignMode() const noexcept { return _alignMode; }
//! Set align mode.
ASMJIT_INLINE void setAlignMode(uint32_t alignMode) noexcept { _alignMode = alignMode; }
//! Get align offset in bytes.
ASMJIT_INLINE uint32_t getOffset() const noexcept { return _offset; }
//! Set align offset in bytes to `offset`.
ASMJIT_INLINE void setOffset(uint32_t offset) noexcept { _offset = offset; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Align mode, see \ref AlignMode.
uint32_t _alignMode;
//! Align offset (in bytes).
uint32_t _offset;
};
// ============================================================================
// [asmjit::HLLabel]
// ============================================================================
//! label (HL).
class HLLabel : public HLNode {
public:
ASMJIT_NO_COPY(HLLabel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLLabel` instance.
ASMJIT_INLINE HLLabel(Compiler* compiler, uint32_t labelId) noexcept
: HLNode(compiler, kTypeLabel) {
_id = labelId;
_numRefs = 0;
_from = nullptr;
}
//! Destroy the `HLLabel` instance.
ASMJIT_INLINE ~HLLabel() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get target label.
ASMJIT_INLINE Label getLabel() const noexcept { return Label(_id); }
//! Get target label id.
ASMJIT_INLINE uint32_t getLabelId() const noexcept { return _id; }
//! Get first jmp instruction.
ASMJIT_INLINE HLJump* getFrom() const noexcept { return _from; }
//! Get whether the node has assigned state.
ASMJIT_INLINE bool hasState() const noexcept { return _state != nullptr; }
//! Get state for this target.
ASMJIT_INLINE VarState* getState() const noexcept { return _state; }
//! Set state for this target.
ASMJIT_INLINE void setState(VarState* state) noexcept { _state = state; }
//! Get number of jumps to this target.
ASMJIT_INLINE uint32_t getNumRefs() const noexcept { return _numRefs; }
//! Set number of jumps to this target.
ASMJIT_INLINE void setNumRefs(uint32_t i) noexcept { _numRefs = i; }
//! Add number of jumps to this target.
ASMJIT_INLINE void addNumRefs(uint32_t i = 1) noexcept { _numRefs += i; }
//! Subtract number of jumps to this target.
ASMJIT_INLINE void subNumRefs(uint32_t i = 1) noexcept { _numRefs -= i; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Label id.
uint32_t _id;
//! Count of jumps here.
uint32_t _numRefs;
//! First jump instruction that points to this target (label).
HLJump* _from;
};
// ============================================================================
// [asmjit::HLComment]
// ============================================================================
//! Comment (HL).
class HLComment : public HLNode {
public:
ASMJIT_NO_COPY(HLComment)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLComment` instance.
ASMJIT_INLINE HLComment(Compiler* compiler, const char* comment) noexcept
: HLNode(compiler, kTypeComment) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_comment = comment;
}
//! Destroy the `HLComment` instance.
ASMJIT_INLINE ~HLComment() noexcept {}
};
// ============================================================================
// [asmjit::HLSentinel]
// ============================================================================
//! Sentinel (HL).
class HLSentinel : public HLNode {
public:
ASMJIT_NO_COPY(HLSentinel)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLSentinel` instance.
ASMJIT_INLINE HLSentinel(Compiler* compiler) noexcept
: HLNode(compiler, kTypeSentinel) {
orFlags(kFlagIsRet);
}
//! Destroy the `HLSentinel` instance.
ASMJIT_INLINE ~HLSentinel() noexcept {}
};
// ============================================================================
// [asmjit::HLHint]
// ============================================================================
//! Hint node.
class HLHint : public HLNode {
public:
ASMJIT_NO_COPY(HLHint)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLHint` instance.
ASMJIT_INLINE HLHint(Compiler* compiler, VarData* vd, uint32_t hint, uint32_t value) noexcept
: HLNode(compiler, kTypeHint) {
orFlags(kFlagIsRemovable | kFlagIsInformative);
_vd = vd;
_hint = hint;
_value = value;
}
//! Destroy the `HLHint` instance.
ASMJIT_INLINE ~HLHint() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get variable.
ASMJIT_INLINE VarData* getVd() const noexcept { return _vd; }
//! Get hint it (see `kVarHint)`.
ASMJIT_INLINE uint32_t getHint() const noexcept { return _hint; }
//! Set hint it (see `kVarHint)`.
ASMJIT_INLINE void setHint(uint32_t hint) noexcept { _hint = hint; }
//! Get hint value.
ASMJIT_INLINE uint32_t getValue() const noexcept { return _value; }
//! Set hint value.
ASMJIT_INLINE void setValue(uint32_t value) noexcept { _value = value; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Variable.
VarData* _vd;
//! Hint id.
uint32_t _hint;
//! Value.
uint32_t _value;
};
// ============================================================================
// [asmjit::HLFunc]
// ============================================================================
//! Function (HL).
class HLFunc : public HLNode {
public:
ASMJIT_NO_COPY(HLFunc)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLFunc` instance.
//!
//! Always use `Compiler::addFunc()` to create an `HLFunc` instance.
ASMJIT_INLINE HLFunc(Compiler* compiler) noexcept
: HLNode(compiler, kTypeFunc),
_entryNode(nullptr),
_exitNode(nullptr),
_decl(nullptr),
_end(nullptr),
_args(nullptr),
_funcHints(Utils::mask(kFuncHintNaked)),
_funcFlags(0),
_expectedStackAlignment(0),
_requiredStackAlignment(0),
_redZoneSize(0),
_spillZoneSize(0),
_argStackSize(0),
_memStackSize(0),
_callStackSize(0) {}
//! Destroy the `HLFunc` instance.
ASMJIT_INLINE ~HLFunc() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function entry `HLLabel`.
ASMJIT_INLINE HLLabel* getEntryNode() const noexcept { return _entryNode; }
//! Get function exit `HLLabel`.
ASMJIT_INLINE HLLabel* getExitNode() const noexcept { return _exitNode; }
//! Get function entry label.
ASMJIT_INLINE Label getEntryLabel() const noexcept { return _entryNode->getLabel(); }
//! Get function exit label.
ASMJIT_INLINE Label getExitLabel() const noexcept { return _exitNode->getLabel(); }
//! Get the function end sentinel.
ASMJIT_INLINE HLSentinel* getEnd() const noexcept { return _end; }
//! Get function declaration.
ASMJIT_INLINE FuncDecl* getDecl() const noexcept { return _decl; }
//! Get arguments count.
ASMJIT_INLINE uint32_t getNumArgs() const noexcept { return _decl->getNumArgs(); }
//! Get arguments list.
ASMJIT_INLINE VarData** getArgs() const noexcept { return _args; }
//! Get argument at `i`.
ASMJIT_INLINE VarData* getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < getNumArgs());
return _args[i];
}
//! Set argument at `i`.
ASMJIT_INLINE void setArg(uint32_t i, VarData* vd) noexcept {
ASMJIT_ASSERT(i < getNumArgs());
_args[i] = vd;
}
//! Reset argument at `i`.
ASMJIT_INLINE void resetArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < getNumArgs());
_args[i] = nullptr;
}
//! Get function hints.
ASMJIT_INLINE uint32_t getFuncHints() const noexcept { return _funcHints; }
//! Get function flags.
ASMJIT_INLINE uint32_t getFuncFlags() const noexcept { return _funcFlags; }
//! Get whether the _funcFlags has `flag`
ASMJIT_INLINE bool hasFuncFlag(uint32_t flag) const noexcept { return (_funcFlags & flag) != 0; }
//! Set function `flag`.
ASMJIT_INLINE void addFuncFlags(uint32_t flags) noexcept { _funcFlags |= flags; }
//! Clear function `flag`.
ASMJIT_INLINE void clearFuncFlags(uint32_t flags) noexcept { _funcFlags &= ~flags; }
//! Get whether the function is naked.
ASMJIT_INLINE bool isNaked() const noexcept { return hasFuncFlag(kFuncFlagIsNaked); }
//! Get whether the function is also a caller.
ASMJIT_INLINE bool isCaller() const noexcept { return hasFuncFlag(kFuncFlagIsCaller); }
//! Get whether the required stack alignment is lower than expected one,
//! thus it has to be aligned manually.
ASMJIT_INLINE bool isStackMisaligned() const noexcept { return hasFuncFlag(kFuncFlagIsStackMisaligned); }
//! Get whether the stack pointer is adjusted inside function prolog/epilog.
ASMJIT_INLINE bool isStackAdjusted() const noexcept { return hasFuncFlag(kFuncFlagIsStackAdjusted); }
//! Get whether the function is finished.
ASMJIT_INLINE bool isFinished() const noexcept { return hasFuncFlag(kFuncFlagIsFinished); }
//! Get expected stack alignment.
ASMJIT_INLINE uint32_t getExpectedStackAlignment() const noexcept {
return _expectedStackAlignment;
}
//! Set expected stack alignment.
ASMJIT_INLINE void setExpectedStackAlignment(uint32_t alignment) noexcept {
_expectedStackAlignment = alignment;
}
//! Get required stack alignment.
ASMJIT_INLINE uint32_t getRequiredStackAlignment() const noexcept {
return _requiredStackAlignment;
}
//! Set required stack alignment.
ASMJIT_INLINE void setRequiredStackAlignment(uint32_t alignment) noexcept {
_requiredStackAlignment = alignment;
}
//! Update required stack alignment so it's not lower than expected
//! stack alignment.
ASMJIT_INLINE void updateRequiredStackAlignment() noexcept {
if (_requiredStackAlignment <= _expectedStackAlignment) {
_requiredStackAlignment = _expectedStackAlignment;
clearFuncFlags(kFuncFlagIsStackMisaligned);
}
else {
addFuncFlags(kFuncFlagIsStackMisaligned);
}
}
//! Set stack "Red Zone" size.
ASMJIT_INLINE uint32_t getRedZoneSize() const noexcept { return _redZoneSize; }
//! Get stack "Red Zone" size.
ASMJIT_INLINE void setRedZoneSize(uint32_t s) noexcept { _redZoneSize = static_cast<uint16_t>(s); }
//! Set stack "Spill Zone" size.
ASMJIT_INLINE uint32_t getSpillZoneSize() const noexcept { return _spillZoneSize; }
//! Get stack "Spill Zone" size.
ASMJIT_INLINE void setSpillZoneSize(uint32_t s) noexcept { _spillZoneSize = static_cast<uint16_t>(s); }
//! Get stack size used by function arguments.
ASMJIT_INLINE uint32_t getArgStackSize() const noexcept { return _argStackSize; }
//! Get stack size used by variables and memory allocated on the stack.
ASMJIT_INLINE uint32_t getMemStackSize() const noexcept { return _memStackSize; }
//! Get stack size used by function calls.
ASMJIT_INLINE uint32_t getCallStackSize() const noexcept { return _callStackSize; }
//! Merge stack size used by function call with `s`.
ASMJIT_INLINE void mergeCallStackSize(uint32_t s) noexcept { if (_callStackSize < s) _callStackSize = s; }
// --------------------------------------------------------------------------
// [Hints]
// --------------------------------------------------------------------------
//! Set function hint.
ASMJIT_INLINE void setHint(uint32_t hint, uint32_t value) noexcept {
ASMJIT_ASSERT(hint <= 31);
ASMJIT_ASSERT(value <= 1);
_funcHints &= ~(1 << hint);
_funcHints |= (value << hint);
}
//! Get function hint.
ASMJIT_INLINE uint32_t getHint(uint32_t hint) const noexcept {
ASMJIT_ASSERT(hint <= 31);
return (_funcHints >> hint) & 0x1;
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Function entry.
HLLabel* _entryNode;
//! Function exit.
HLLabel* _exitNode;
//! Function declaration.
FuncDecl* _decl;
//! Function end.
HLSentinel* _end;
//! Arguments list as `VarData`.
VarData** _args;
//! Function hints;
uint32_t _funcHints;
//! Function flags.
uint32_t _funcFlags;
//! Expected stack alignment (we depend on this value).
//!
//! NOTE: It can be global alignment given by the OS or described by the
//! target platform ABI.
uint32_t _expectedStackAlignment;
//! Required stack alignment (required by SIMD instructions).
uint32_t _requiredStackAlignment;
//! The "Red Zone" size - count of bytes which might be accessed by a left
//! function without adjusting the stack pointer (`esp` or `rsp`) (AMD64 ABI).
uint16_t _redZoneSize;
//! The "Spill Zone" size - count of bytes after the function return address
//! that can be used by the function to spill variables in (WIN64 ABI).
uint16_t _spillZoneSize;
//! Stack size needed for function arguments.
uint32_t _argStackSize;
//! Stack size needed for all variables and memory allocated on the stack.
uint32_t _memStackSize;
//! Stack size needed to call other functions.
uint32_t _callStackSize;
};
// ============================================================================
// [asmjit::HLRet]
// ============================================================================
//! Function return (HL).
class HLRet : public HLNode {
public:
ASMJIT_NO_COPY(HLRet)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLRet` instance.
ASMJIT_INLINE HLRet(Compiler* compiler, const Operand& o0, const Operand& o1) noexcept
: HLNode(compiler, kTypeRet) {
orFlags(kFlagIsRet);
_ret[0] = o0;
_ret[1] = o1;
}
//! Destroy the `HLRet` instance.
ASMJIT_INLINE ~HLRet() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the first return operand.
ASMJIT_INLINE Operand& getFirst() noexcept { return _ret[0]; }
//! \overload
ASMJIT_INLINE const Operand& getFirst() const noexcept { return _ret[0]; }
//! Get the second return operand.
ASMJIT_INLINE Operand& getSecond() noexcept { return _ret[1]; }
//! \overload
ASMJIT_INLINE const Operand& getSecond() const noexcept { return _ret[1]; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Ret operand(s).
Operand _ret[2];
};
// ============================================================================
// [asmjit::HLCall]
// ============================================================================
//! Function call (HL).
class HLCall : public HLNode {
public:
ASMJIT_NO_COPY(HLCall)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLCall` instance.
ASMJIT_INLINE HLCall(Compiler* compiler, const Operand& target) noexcept
: HLNode(compiler, kTypeCall),
_decl(nullptr),
_target(target),
_args(nullptr) {
orFlags(kFlagIsRemovable);
}
//! Destroy the `HLCall` instance.
ASMJIT_INLINE ~HLCall() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get function declaration.
ASMJIT_INLINE FuncDecl* getDecl() const noexcept { return _decl; }
//! Get target operand.
ASMJIT_INLINE Operand& getTarget() noexcept { return _target; }
//! \overload
ASMJIT_INLINE const Operand& getTarget() const noexcept { return _target; }
//! Get return at `i`.
ASMJIT_INLINE Operand& getRet(uint32_t i = 0) noexcept {
ASMJIT_ASSERT(i < 2);
return _ret[i];
}
//! \overload
ASMJIT_INLINE const Operand& getRet(uint32_t i = 0) const noexcept {
ASMJIT_ASSERT(i < 2);
return _ret[i];
}
//! Get argument at `i`.
ASMJIT_INLINE Operand& getArg(uint32_t i) noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return _args[i];
}
//! \overload
ASMJIT_INLINE const Operand& getArg(uint32_t i) const noexcept {
ASMJIT_ASSERT(i < kFuncArgCountLoHi);
return _args[i];
}
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Function declaration.
FuncDecl* _decl;
//! Target (address of function, register, label, ...).
Operand _target;
//! Return.
Operand _ret[2];
//! Arguments.
Operand* _args;
};
// ============================================================================
// [asmjit::HLCallArg]
// ============================================================================
//! Function call's argument (HL).
class HLCallArg : public HLNode {
public:
ASMJIT_NO_COPY(HLCallArg)
// --------------------------------------------------------------------------
// [Construction / Destruction]
// --------------------------------------------------------------------------
//! Create a new `HLCallArg` instance.
ASMJIT_INLINE HLCallArg(Compiler* compiler, HLCall* call, VarData* sVd, VarData* cVd) noexcept
: HLNode(compiler, kTypeCallArg),
_call(call),
_sVd(sVd),
_cVd(cVd),
_args(0) {
orFlags(kFlagIsRemovable);
}
//! Destroy the `HLCallArg` instance.
ASMJIT_INLINE ~HLCallArg() noexcept {}
// --------------------------------------------------------------------------
// [Accessors]
// --------------------------------------------------------------------------
//! Get the associated function-call.
ASMJIT_INLINE HLCall* getCall() const noexcept { return _call; }
//! Get source variable.
ASMJIT_INLINE VarData* getSVd() const noexcept { return _sVd; }
//! Get conversion variable.
ASMJIT_INLINE VarData* getCVd() const noexcept { return _cVd; }
// --------------------------------------------------------------------------
// [Members]
// --------------------------------------------------------------------------
//! Associated `HLCall`.
HLCall* _call;
//! Source variable.
VarData* _sVd;
//! Temporary variable used for conversion (or nullptr).
VarData* _cVd;
//! Affected arguments bit-array.
uint32_t _args;
};
// ============================================================================
// [asmjit::HLStream]
// ============================================================================
// TODO:
//! \}
} // asmjit namespace
// [Api-End]
#include "../apiend.h"
// [Guard]
#endif // !ASMJIT_DISABLE_COMPILER
#endif // _ASMJIT_BASE_HLSTREAM_H