mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-18 13:04:36 +03:00
[Doc] Mostly documentation update
This commit is contained in:
@@ -966,12 +966,15 @@ namespace asmjit {
|
|||||||
//! with assembler requires the knowledge of the following:
|
//! with assembler requires the knowledge of the following:
|
||||||
//!
|
//!
|
||||||
//! - \ref BaseAssembler and architecture-specific assemblers:
|
//! - \ref BaseAssembler and architecture-specific assemblers:
|
||||||
//! - \ref x86::Assembler - Assembler specific to X86 architecture
|
//! - \ref x86::Assembler - Assembler implementation targeting X86 and X86_64 architectures.
|
||||||
|
//! - \ref a64::Assembler - Assembler implementation targeting AArch64 architecture.
|
||||||
//! - \ref Operand and its variations:
|
//! - \ref Operand and its variations:
|
||||||
//! - \ref BaseReg - Base class for a register operand, inherited by:
|
//! - \ref BaseReg - Base class for a register operand, inherited by:
|
||||||
//! - \ref x86::Reg - Register operand specific to X86 architecture.
|
//! - \ref x86::Reg - Register operand specific to X86 and X86_64 architectures.
|
||||||
|
//! - \ref arm::Reg - Register operand specific to AArch64 architecture.
|
||||||
//! - \ref BaseMem - Base class for a memory operand, inherited by:
|
//! - \ref BaseMem - Base class for a memory operand, inherited by:
|
||||||
//! - \ref x86::Mem - Memory operand specific to X86 architecture.
|
//! - \ref x86::Mem - Memory operand specific to X86 architecture.
|
||||||
|
//! - \ref arm::Mem - Memory operand specific to AArch64 architecture.
|
||||||
//! - \ref Imm - Immediate (value) operand.
|
//! - \ref Imm - Immediate (value) operand.
|
||||||
//! - \ref Label - Label operand.
|
//! - \ref Label - Label operand.
|
||||||
//!
|
//!
|
||||||
@@ -1150,10 +1153,10 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! void testX86Mem() {
|
//! void testX86Mem() {
|
||||||
//! // The same as: dword ptr [rax + rbx].
|
//! // The same as: dword ptr [rax + rbx].
|
||||||
//! x86::Mem a = x86::dword_ptr(rax, rbx);
|
//! x86::Mem a = x86::dword_ptr(x86::rax, x86::rbx);
|
||||||
//!
|
//!
|
||||||
//! // The same as: qword ptr [rdx + rsi << 0 + 1].
|
//! // The same as: qword ptr [rdx + rsi << 0 + 1].
|
||||||
//! x86::Mem b = x86::qword_ptr(rdx, rsi, 0, 1);
|
//! x86::Mem b = x86::qword_ptr(x86::rdx, x86::rsi, 0, 1);
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
@@ -1166,7 +1169,7 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! void testX86Mem() {
|
//! void testX86Mem() {
|
||||||
//! // The same as: dword ptr [rax + 12].
|
//! // The same as: dword ptr [rax + 12].
|
||||||
//! x86::Mem mem = x86::dword_ptr(rax, 12);
|
//! x86::Mem mem = x86::dword_ptr(x86::rax, 12);
|
||||||
//!
|
//!
|
||||||
//! mem.hasBase(); // true.
|
//! mem.hasBase(); // true.
|
||||||
//! mem.hasIndex(); // false.
|
//! mem.hasIndex(); // false.
|
||||||
@@ -1176,8 +1179,8 @@ namespace asmjit {
|
|||||||
//! mem.setSize(0); // Sets the size to 0 (makes it size-less).
|
//! mem.setSize(0); // Sets the size to 0 (makes it size-less).
|
||||||
//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11.
|
//! mem.addOffset(-1); // Adds -1 to the offset and makes it 11.
|
||||||
//! mem.setOffset(0); // Sets the offset to 0.
|
//! mem.setOffset(0); // Sets the offset to 0.
|
||||||
//! mem.setBase(rcx); // Changes BASE to RCX.
|
//! mem.setBase(x86::rcx); // Changes BASE to RCX.
|
||||||
//! mem.setIndex(rax); // Changes INDEX to RAX.
|
//! mem.setIndex(x86::rax); // Changes INDEX to RAX.
|
||||||
//! mem.hasIndex(); // true.
|
//! mem.hasIndex(); // true.
|
||||||
//! }
|
//! }
|
||||||
//! // ...
|
//! // ...
|
||||||
@@ -1269,7 +1272,8 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! ### Builder Examples
|
//! ### Builder Examples
|
||||||
//!
|
//!
|
||||||
//! - \ref x86::Builder provides many X86/X64 examples.
|
//! - \ref x86::Builder - Builder implementation targeting X86 and X86_64 architectures.
|
||||||
|
//! - \ref a64::Builder - Builder implementation targeting AArch64 architecture.
|
||||||
|
|
||||||
|
|
||||||
//! \defgroup asmjit_compiler Compiler
|
//! \defgroup asmjit_compiler Compiler
|
||||||
@@ -1306,7 +1310,8 @@ namespace asmjit {
|
|||||||
//!
|
//!
|
||||||
//! ### Compiler Examples
|
//! ### Compiler Examples
|
||||||
//!
|
//!
|
||||||
//! - \ref x86::Compiler provides many X86/X64 examples.
|
//! - \ref x86::Compiler - Compiler implementation targeting X86 and X86_64 architectures.
|
||||||
|
//! - \ref a64::Compiler - Compiler implementation targeting AArch64 architecture.
|
||||||
//!
|
//!
|
||||||
//! ### Compiler Tips
|
//! ### Compiler Tips
|
||||||
//!
|
//!
|
||||||
@@ -1478,7 +1483,7 @@ namespace asmjit {
|
|||||||
//! The first example illustrates how to format operands:
|
//! The first example illustrates how to format operands:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! #include <asmjit/core.h>
|
//! #include <asmjit/x86.h>
|
||||||
//! #include <stdio.h>
|
//! #include <stdio.h>
|
||||||
//!
|
//!
|
||||||
//! using namespace asmjit;
|
//! using namespace asmjit;
|
||||||
@@ -1503,17 +1508,17 @@ namespace asmjit {
|
|||||||
//! // compatible with what AsmJit normally does.
|
//! // compatible with what AsmJit normally does.
|
||||||
//! Arch arch = Arch::kX64;
|
//! Arch arch = Arch::kX64;
|
||||||
//!
|
//!
|
||||||
//! log(arch, rax); // Prints 'rax'.
|
//! logOperand(arch, rax); // Prints 'rax'.
|
||||||
//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
|
//! logOperand(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`.
|
||||||
//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`.
|
//! logOperand(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`.
|
||||||
//! log(arch, imm(42)); // Prints '42'.
|
//! logOperand(arch, imm(42)); // Prints '42'.
|
||||||
//! }
|
//! }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! Next example illustrates how to format whole instructions:
|
//! Next example illustrates how to format whole instructions:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
//! #include <asmjit/core.h>
|
//! #include <asmjit/x86.h>
|
||||||
//! #include <stdio.h>
|
//! #include <stdio.h>
|
||||||
//! #include <utility>
|
//! #include <utility>
|
||||||
//!
|
//!
|
||||||
@@ -1528,7 +1533,7 @@ namespace asmjit {
|
|||||||
//! FormatFlags formatFlags = FormatFlags::kNone;
|
//! FormatFlags formatFlags = FormatFlags::kNone;
|
||||||
//!
|
//!
|
||||||
//! // The formatter expects operands in an array.
|
//! // The formatter expects operands in an array.
|
||||||
//! Operand_ operands { std::forward<Args>(args)... };
|
//! Operand_ operands[] { std::forward<Args>(args)... };
|
||||||
//!
|
//!
|
||||||
//! StringTmp<128> sb;
|
//! StringTmp<128> sb;
|
||||||
//! Formatter::formatInstruction(
|
//! Formatter::formatInstruction(
|
||||||
@@ -1550,13 +1555,13 @@ namespace asmjit {
|
|||||||
//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'.
|
//! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'.
|
||||||
//! logInstruction(arch,
|
//! logInstruction(arch,
|
||||||
//! BaseInst(Inst::kIdVaddpd),
|
//! BaseInst(Inst::kIdVaddpd),
|
||||||
//! zmm0, zmm1, ptr(rax)._1toN());
|
//! zmm0, zmm1, ptr(rax)._1to8());
|
||||||
//!
|
//!
|
||||||
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
|
//! // BaseInst abstracts instruction id, instruction options, and extraReg.
|
||||||
//! // Prints 'lock add [rax], rcx'.
|
//! // Prints 'lock add [rax], rcx'.
|
||||||
//! logInstruction(arch,
|
//! logInstruction(arch,
|
||||||
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock),
|
//! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock),
|
||||||
//! x86::ptr(rax), rcx);
|
//! ptr(rax), rcx);
|
||||||
//!
|
//!
|
||||||
//! // Similarly an extra register (like AVX-512 selector) can be used.
|
//! // Similarly an extra register (like AVX-512 selector) can be used.
|
||||||
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
|
//! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
//! \addtogroup asmjit_builder
|
//! \addtogroup asmjit_builder
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
@@ -28,6 +29,7 @@ static inline void BaseBuilder_assignInstState(BaseBuilder* self, InstNode* node
|
|||||||
}
|
}
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
ASMJIT_END_NAMESPACE
|
ASMJIT_END_NAMESPACE
|
||||||
|
|
||||||
|
|||||||
@@ -132,8 +132,8 @@ CodeHolder::~CodeHolder() noexcept {
|
|||||||
CodeHolder_resetInternal(this, ResetPolicy::kHard);
|
CodeHolder_resetInternal(this, ResetPolicy::kHard);
|
||||||
}
|
}
|
||||||
|
|
||||||
// CodeHolder - Init & Reset
|
// CodeHolder - Initialization & Reset
|
||||||
// =========================
|
// ===================================
|
||||||
|
|
||||||
inline void CodeHolder_setSectionDefaultName(
|
inline void CodeHolder_setSectionDefaultName(
|
||||||
Section* section,
|
Section* section,
|
||||||
|
|||||||
@@ -1110,7 +1110,7 @@ public:
|
|||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Init & Reset
|
//! \name Initialization & Reset
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Initializes CpuInfo architecture and sub-architecture members to `arch` and `subArch`, respectively.
|
//! Initializes CpuInfo architecture and sub-architecture members to `arch` and `subArch`, respectively.
|
||||||
|
|||||||
@@ -337,10 +337,17 @@ public:
|
|||||||
//! Tests whether the emitter is destroyed (only used during destruction).
|
//! Tests whether the emitter is destroyed (only used during destruction).
|
||||||
ASMJIT_INLINE_NODEBUG bool isDestroyed() const noexcept { return hasEmitterFlag(EmitterFlags::kDestroyed); }
|
ASMJIT_INLINE_NODEBUG bool isDestroyed() const noexcept { return hasEmitterFlag(EmitterFlags::kDestroyed); }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
//! \name Internal Functions
|
||||||
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
|
ASMJIT_INLINE_NODEBUG void _addEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags |= flags; }
|
||||||
ASMJIT_INLINE_NODEBUG void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
|
ASMJIT_INLINE_NODEBUG void _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! \name Target Information
|
//! \name Target Information
|
||||||
//! \{
|
//! \{
|
||||||
@@ -554,23 +561,38 @@ public:
|
|||||||
//! \name Emitter State
|
//! \name Emitter State
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Resets the emitter state, which contains instruction options, extra register, and inline comment.
|
||||||
|
//!
|
||||||
|
//! Emitter can have a state that describes instruction options and extra register used by the instruction. Most
|
||||||
|
//! instructions don't need nor use the state, however, if an instruction uses a prefix such as REX or REP prefix,
|
||||||
|
//! which is set explicitly, then the state would contain it. This allows to mimic the syntax of assemblers such
|
||||||
|
//! as X86. For example `rep().movs(...)` would map to a `REP MOVS` instuction on X86. The same applies to various
|
||||||
|
//! hints and the use of a mask register in AVX-512 mode.
|
||||||
ASMJIT_INLINE_NODEBUG void resetState() noexcept {
|
ASMJIT_INLINE_NODEBUG void resetState() noexcept {
|
||||||
resetInstOptions();
|
resetInstOptions();
|
||||||
resetExtraReg();
|
resetExtraReg();
|
||||||
resetInlineComment();
|
resetInlineComment();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
|
|
||||||
|
//! Grabs the current emitter state and resets the emitter state at the same time, returning the state the emitter
|
||||||
|
//! had before the state was reset.
|
||||||
ASMJIT_INLINE_NODEBUG State _grabState() noexcept {
|
ASMJIT_INLINE_NODEBUG State _grabState() noexcept {
|
||||||
State s{_instOptions | _forcedInstOptions, _extraReg, _inlineComment};
|
State s{_instOptions | _forcedInstOptions, _extraReg, _inlineComment};
|
||||||
resetState();
|
resetState();
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Sections
|
//! \name Sections
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Switches the given `section`.
|
||||||
|
//!
|
||||||
|
//! Once switched, everything is added to the given `section`.
|
||||||
ASMJIT_API virtual Error section(Section* section);
|
ASMJIT_API virtual Error section(Section* section);
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -634,35 +656,51 @@ public:
|
|||||||
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
ASMJIT_API Error _emitI(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5);
|
||||||
|
|
||||||
//! Emits an instruction `instId` with the given `operands`.
|
//! Emits an instruction `instId` with the given `operands`.
|
||||||
|
//!
|
||||||
|
//! This is the most universal way of emitting code, which accepts an instruction identifier and instruction
|
||||||
|
//! operands. This is called an "unchecked" API as emit doesn't provide any type checks at compile-time. This
|
||||||
|
//! allows to emit instruction with just \ref Operand instances, which could be handy in some cases - for
|
||||||
|
//! example emitting generic code where you don't know whether some operand is register, memory, or immediate.
|
||||||
template<typename... Args>
|
template<typename... Args>
|
||||||
ASMJIT_INLINE_NODEBUG Error emit(InstId instId, Args&&... operands) {
|
ASMJIT_INLINE_NODEBUG Error emit(InstId instId, Args&&... operands) {
|
||||||
return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
|
return _emitI(instId, Support::ForwardOp<Args>::forward(operands)...);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Similar to \ref emit(), but uses array of `operands` instead.
|
||||||
ASMJIT_INLINE_NODEBUG Error emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
|
ASMJIT_INLINE_NODEBUG Error emitOpArray(InstId instId, const Operand_* operands, size_t opCount) {
|
||||||
return _emitOpArray(instId, operands, opCount);
|
return _emitOpArray(instId, operands, opCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Similar to \ref emit(), but emits instruction with both instruction options and extra register, followed
|
||||||
|
//! by an array of `operands`.
|
||||||
ASMJIT_FORCE_INLINE Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
|
ASMJIT_FORCE_INLINE Error emitInst(const BaseInst& inst, const Operand_* operands, size_t opCount) {
|
||||||
setInstOptions(inst.options());
|
setInstOptions(inst.options());
|
||||||
setExtraReg(inst.extraReg());
|
setExtraReg(inst.extraReg());
|
||||||
return _emitOpArray(inst.id(), operands, opCount);
|
return _emitOpArray(inst.id(), operands, opCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
//! \cond INTERNAL
|
//! \cond INTERNAL
|
||||||
|
//! \name Emit Internals
|
||||||
|
//! \{
|
||||||
|
|
||||||
//! Emits an instruction - all 6 operands must be defined.
|
//! Emits an instruction - all 6 operands must be defined.
|
||||||
ASMJIT_API virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt);
|
ASMJIT_API virtual Error _emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* oExt);
|
||||||
//! Emits instruction having operands stored in array.
|
//! Emits instruction having operands stored in array.
|
||||||
ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount);
|
ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount);
|
||||||
//! \endcond
|
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! \name Emit Utilities
|
//! \name Emit Utilities
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Emits a function prolog described by the given function `frame`.
|
||||||
ASMJIT_API Error emitProlog(const FuncFrame& frame);
|
ASMJIT_API Error emitProlog(const FuncFrame& frame);
|
||||||
|
//! Emits a function epilog described by the given function `frame`.
|
||||||
ASMJIT_API Error emitEpilog(const FuncFrame& frame);
|
ASMJIT_API Error emitEpilog(const FuncFrame& frame);
|
||||||
|
//! Emits code that reassigns function `frame` arguments to the given `args`.
|
||||||
ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args);
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// CallConv - Init & Reset
|
// CallConv - Initialization & Reset
|
||||||
// =======================
|
// =================================
|
||||||
|
|
||||||
ASMJIT_FAVOR_SIZE Error CallConv::init(CallConvId ccId, const Environment& environment) noexcept {
|
ASMJIT_FAVOR_SIZE Error CallConv::init(CallConvId ccId, const Environment& environment) noexcept {
|
||||||
reset();
|
reset();
|
||||||
|
|||||||
@@ -353,8 +353,15 @@ struct CallConv {
|
|||||||
|
|
||||||
//! Function signature.
|
//! Function signature.
|
||||||
//!
|
//!
|
||||||
//! Contains information about function return type, count of arguments and their TypeIds. Function signature is
|
//! Contains information about a function return type, count of arguments, and their TypeIds. Function signature
|
||||||
//! a low level structure which doesn't contain platform specific or calling convention specific information.
|
//! is a low level structure which doesn't contain platform specific or calling convention specific information.
|
||||||
|
//! It's typically used to describe function arguments in a C-API like form, which is then used to calculate a
|
||||||
|
//! \ref FuncDetail instance, which then maps function signature into a platform and calling convention specific
|
||||||
|
//! format.
|
||||||
|
//!
|
||||||
|
//! Function signature can be built either dynamically by using \ref addArg() and \ref addArgT() functionality,
|
||||||
|
//! or dynamically by using a template-based \ref FuncSignature::build() function, which maps template types
|
||||||
|
//! into a function signature.
|
||||||
struct FuncSignature {
|
struct FuncSignature {
|
||||||
//! \name Constants
|
//! \name Constants
|
||||||
//! \{
|
//! \{
|
||||||
@@ -405,6 +412,12 @@ struct FuncSignature {
|
|||||||
_ret(ret),
|
_ret(ret),
|
||||||
_args{std::forward<Args>(args)...} {}
|
_args{std::forward<Args>(args)...} {}
|
||||||
|
|
||||||
|
//! Builds a function signature based on `RetValueAndArgs`. The first template argument is a function return type,
|
||||||
|
//! and function arguments follow.
|
||||||
|
//!
|
||||||
|
//! \note This function returns a new function signature, which can be passed to functions where it's required. It's
|
||||||
|
//! a convenience function that allows to build function signature statically based on types known at compile time,
|
||||||
|
//! which is common in JIT code generation.
|
||||||
template<typename... RetValueAndArgs>
|
template<typename... RetValueAndArgs>
|
||||||
static ASMJIT_INLINE_NODEBUG constexpr FuncSignature build(CallConvId ccId = CallConvId::kCDecl, uint32_t vaIndex = kNoVarArgs) noexcept {
|
static ASMJIT_INLINE_NODEBUG constexpr FuncSignature build(CallConvId ccId = CallConvId::kCDecl, uint32_t vaIndex = kNoVarArgs) noexcept {
|
||||||
return FuncSignature(ccId, vaIndex, (TypeId(TypeUtils::TypeIdOfT<RetValueAndArgs>::kTypeId))... );
|
return FuncSignature(ccId, vaIndex, (TypeId(TypeUtils::TypeIdOfT<RetValueAndArgs>::kTypeId))... );
|
||||||
@@ -415,16 +428,20 @@ struct FuncSignature {
|
|||||||
//! \name Overloaded Operators
|
//! \name Overloaded Operators
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Copy assignment - function signature can be copied by value.
|
||||||
ASMJIT_FORCE_INLINE FuncSignature& operator=(const FuncSignature& other) noexcept = default;
|
ASMJIT_FORCE_INLINE FuncSignature& operator=(const FuncSignature& other) noexcept = default;
|
||||||
|
|
||||||
|
//! Compares this function signature with `other` for equality..
|
||||||
ASMJIT_FORCE_INLINE bool operator==(const FuncSignature& other) const noexcept { return equals(other); }
|
ASMJIT_FORCE_INLINE bool operator==(const FuncSignature& other) const noexcept { return equals(other); }
|
||||||
|
//! Compares this function signature with `other` for inequality..
|
||||||
ASMJIT_FORCE_INLINE bool operator!=(const FuncSignature& other) const noexcept { return !equals(other); }
|
ASMJIT_FORCE_INLINE bool operator!=(const FuncSignature& other) const noexcept { return !equals(other); }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Init & Reset
|
//! \name Initialization & Reset
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Resets this function signature to a default constructed state.
|
||||||
ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = FuncSignature{}; }
|
ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = FuncSignature{}; }
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
@@ -432,6 +449,7 @@ struct FuncSignature {
|
|||||||
//! \name Equality & Comparison
|
//! \name Equality & Comparison
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Compares this function signature with `other` for equality..
|
||||||
ASMJIT_INLINE_NODEBUG bool equals(const FuncSignature& other) const noexcept {
|
ASMJIT_INLINE_NODEBUG bool equals(const FuncSignature& other) const noexcept {
|
||||||
return _ccId == other._ccId &&
|
return _ccId == other._ccId &&
|
||||||
_argCount == other._argCount &&
|
_argCount == other._argCount &&
|
||||||
@@ -522,7 +540,7 @@ public:
|
|||||||
|
|
||||||
ASMJIT_DEPRECATED("Use FuncSignature instead of FuncSignatureBuilder")
|
ASMJIT_DEPRECATED("Use FuncSignature instead of FuncSignatureBuilder")
|
||||||
typedef FuncSignature FuncSignatureBuilder;
|
typedef FuncSignature FuncSignatureBuilder;
|
||||||
#endif // ASMJIT_NO_DEPRECATED
|
#endif // !ASMJIT_NO_DEPRECATED
|
||||||
|
|
||||||
//! Argument or return value (or its part) as defined by `FuncSignature`, but with register or stack address
|
//! Argument or return value (or its part) as defined by `FuncSignature`, but with register or stack address
|
||||||
//! (and other metadata) assigned.
|
//! (and other metadata) assigned.
|
||||||
@@ -592,11 +610,13 @@ struct FuncValue {
|
|||||||
//!
|
//!
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
|
//! Assigns a register of `regType` and `regId`.
|
||||||
inline void assignRegData(RegType regType, uint32_t regId) noexcept {
|
inline void assignRegData(RegType regType, uint32_t regId) noexcept {
|
||||||
ASMJIT_ASSERT((_data & (kRegTypeMask | kRegIdMask)) == 0);
|
ASMJIT_ASSERT((_data & (kRegTypeMask | kRegIdMask)) == 0);
|
||||||
_data |= (uint32_t(regType) << kRegTypeShift) | (regId << kRegIdShift) | kFlagIsReg;
|
_data |= (uint32_t(regType) << kRegTypeShift) | (regId << kRegIdShift) | kFlagIsReg;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Assigns a stack location at `offset`.
|
||||||
inline void assignStackOffset(int32_t offset) noexcept {
|
inline void assignStackOffset(int32_t offset) noexcept {
|
||||||
ASMJIT_ASSERT((_data & kStackOffsetMask) == 0);
|
ASMJIT_ASSERT((_data & kStackOffsetMask) == 0);
|
||||||
_data |= (uint32_t(offset) << kStackOffsetShift) | kFlagIsStack;
|
_data |= (uint32_t(offset) << kStackOffsetShift) | kFlagIsStack;
|
||||||
@@ -610,7 +630,9 @@ struct FuncValue {
|
|||||||
//! Returns true if the value is initialized (explicit bool cast).
|
//! Returns true if the value is initialized (explicit bool cast).
|
||||||
ASMJIT_INLINE_NODEBUG explicit operator bool() const noexcept { return _data != 0; }
|
ASMJIT_INLINE_NODEBUG explicit operator bool() const noexcept { return _data != 0; }
|
||||||
|
|
||||||
|
//! \cond INTERNAL
|
||||||
ASMJIT_INLINE_NODEBUG void _replaceValue(uint32_t mask, uint32_t value) noexcept { _data = (_data & ~mask) | value; }
|
ASMJIT_INLINE_NODEBUG void _replaceValue(uint32_t mask, uint32_t value) noexcept { _data = (_data & ~mask) | value; }
|
||||||
|
//! \endcond
|
||||||
|
|
||||||
//! Tests whether the `FuncValue` has a flag `flag` set.
|
//! Tests whether the `FuncValue` has a flag `flag` set.
|
||||||
ASMJIT_INLINE_NODEBUG bool hasFlag(uint32_t flag) const noexcept { return Support::test(_data, flag); }
|
ASMJIT_INLINE_NODEBUG bool hasFlag(uint32_t flag) const noexcept { return Support::test(_data, flag); }
|
||||||
@@ -692,40 +714,52 @@ public:
|
|||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Returns values in this value in the pack.
|
||||||
|
//!
|
||||||
|
//! \note The returned array has exactly \ref Globals::kMaxValuePack elements.
|
||||||
ASMJIT_INLINE_NODEBUG FuncValue* values() noexcept { return _values; }
|
ASMJIT_INLINE_NODEBUG FuncValue* values() noexcept { return _values; }
|
||||||
|
//! \overload
|
||||||
ASMJIT_INLINE_NODEBUG const FuncValue* values() const noexcept { return _values; }
|
ASMJIT_INLINE_NODEBUG const FuncValue* values() const noexcept { return _values; }
|
||||||
|
|
||||||
|
//! Resets a value at the given `index` in the pack, which makes it unassigned.
|
||||||
inline void resetValue(size_t index) noexcept {
|
inline void resetValue(size_t index) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
_values[index].reset();
|
_values[index].reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Tests whether the value at the given `index` in the pack is assigned.
|
||||||
inline bool hasValue(size_t index) noexcept {
|
inline bool hasValue(size_t index) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
return _values[index].isInitialized();
|
return _values[index].isInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Assigns a register at the given `index` to `reg` and an optional `typeId`.
|
||||||
inline void assignReg(size_t index, const BaseReg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignReg(size_t index, const BaseReg& reg, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
ASMJIT_ASSERT(reg.isPhysReg());
|
ASMJIT_ASSERT(reg.isPhysReg());
|
||||||
_values[index].initReg(reg.type(), reg.id(), typeId);
|
_values[index].initReg(reg.type(), reg.id(), typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Assigns a register at the given `index` to `regType`, `regId`, and an optional `typeId`.
|
||||||
inline void assignReg(size_t index, RegType regType, uint32_t regId, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignReg(size_t index, RegType regType, uint32_t regId, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
_values[index].initReg(regType, regId, typeId);
|
_values[index].initReg(regType, regId, typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Assigns a stack location at the given `index` to `offset` and an optional `typeId`.
|
||||||
inline void assignStack(size_t index, int32_t offset, TypeId typeId = TypeId::kVoid) noexcept {
|
inline void assignStack(size_t index, int32_t offset, TypeId typeId = TypeId::kVoid) noexcept {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
_values[index].initStack(offset, typeId);
|
_values[index].initStack(offset, typeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//! Accesses the value in the pack at the given `index`.
|
||||||
|
//!
|
||||||
|
//! \note The maximum index value is `Globals::kMaxValuePack - 1`.
|
||||||
inline FuncValue& operator[](size_t index) {
|
inline FuncValue& operator[](size_t index) {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
return _values[index];
|
return _values[index];
|
||||||
}
|
}
|
||||||
|
//! \overload
|
||||||
inline const FuncValue& operator[](size_t index) const {
|
inline const FuncValue& operator[](size_t index) const {
|
||||||
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
ASMJIT_ASSERT(index < Globals::kMaxValuePack);
|
||||||
return _values[index];
|
return _values[index];
|
||||||
@@ -1004,87 +1038,98 @@ public:
|
|||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
//! Function attributes.
|
//! Function attributes.
|
||||||
FuncAttributes _attributes;
|
FuncAttributes _attributes {};
|
||||||
|
|
||||||
//! Target architecture.
|
//! Target architecture.
|
||||||
Arch _arch;
|
Arch _arch {};
|
||||||
//! SP register ID (to access call stack and local stack).
|
//! SP register ID (to access call stack and local stack).
|
||||||
uint8_t _spRegId;
|
uint8_t _spRegId = uint8_t(BaseReg::kIdBad);
|
||||||
//! SA register ID (to access stack arguments).
|
//! SA register ID (to access stack arguments).
|
||||||
uint8_t _saRegId;
|
uint8_t _saRegId = uint8_t(BaseReg::kIdBad);
|
||||||
|
|
||||||
//! Red zone size (copied from CallConv).
|
//! Red zone size (copied from CallConv).
|
||||||
uint8_t _redZoneSize;
|
uint8_t _redZoneSize = 0;
|
||||||
//! Spill zone size (copied from CallConv).
|
//! Spill zone size (copied from CallConv).
|
||||||
uint8_t _spillZoneSize;
|
uint8_t _spillZoneSize = 0;
|
||||||
//! Natural stack alignment (copied from CallConv).
|
//! Natural stack alignment (copied from CallConv).
|
||||||
uint8_t _naturalStackAlignment;
|
uint8_t _naturalStackAlignment = 0;
|
||||||
//! Minimum stack alignment to turn on dynamic alignment.
|
//! Minimum stack alignment to turn on dynamic alignment.
|
||||||
uint8_t _minDynamicAlignment;
|
uint8_t _minDynamicAlignment = 0;
|
||||||
|
|
||||||
//! Call stack alignment.
|
//! Call stack alignment.
|
||||||
uint8_t _callStackAlignment;
|
uint8_t _callStackAlignment = 0;
|
||||||
//! Local stack alignment.
|
//! Local stack alignment.
|
||||||
uint8_t _localStackAlignment;
|
uint8_t _localStackAlignment = 0;
|
||||||
//! Final stack alignment.
|
//! Final stack alignment.
|
||||||
uint8_t _finalStackAlignment;
|
uint8_t _finalStackAlignment = 0;
|
||||||
|
|
||||||
//! Adjustment of the stack before returning (X86-STDCALL).
|
//! Adjustment of the stack before returning (X86-STDCALL).
|
||||||
uint16_t _calleeStackCleanup;
|
uint16_t _calleeStackCleanup = 0;
|
||||||
|
|
||||||
//! Call stack size.
|
//! Call stack size.
|
||||||
uint32_t _callStackSize;
|
uint32_t _callStackSize = 0;
|
||||||
//! Local stack size.
|
//! Local stack size.
|
||||||
uint32_t _localStackSize;
|
uint32_t _localStackSize = 0;
|
||||||
//! Final stack size (sum of call stack and local stack).
|
//! Final stack size (sum of call stack and local stack).
|
||||||
uint32_t _finalStackSize;
|
uint32_t _finalStackSize = 0;
|
||||||
|
|
||||||
//! Local stack offset (non-zero only if call stack is used).
|
//! Local stack offset (non-zero only if call stack is used).
|
||||||
uint32_t _localStackOffset;
|
uint32_t _localStackOffset = 0;
|
||||||
//! Offset relative to SP that contains previous SP (before alignment).
|
//! Offset relative to SP that contains previous SP (before alignment).
|
||||||
uint32_t _daOffset;
|
uint32_t _daOffset = 0;
|
||||||
//! Offset of the first stack argument relative to SP.
|
//! Offset of the first stack argument relative to SP.
|
||||||
uint32_t _saOffsetFromSP;
|
uint32_t _saOffsetFromSP = 0;
|
||||||
//! Offset of the first stack argument relative to SA (_saRegId or FP).
|
//! Offset of the first stack argument relative to SA (_saRegId or FP).
|
||||||
uint32_t _saOffsetFromSA;
|
uint32_t _saOffsetFromSA = 0;
|
||||||
|
|
||||||
//! Local stack adjustment in prolog/epilog.
|
//! Local stack adjustment in prolog/epilog.
|
||||||
uint32_t _stackAdjustment;
|
uint32_t _stackAdjustment = 0;
|
||||||
|
|
||||||
//! Registers that are dirty.
|
//! Registers that are dirty.
|
||||||
Support::Array<RegMask, Globals::kNumVirtGroups> _dirtyRegs;
|
Support::Array<RegMask, Globals::kNumVirtGroups> _dirtyRegs {};
|
||||||
//! Registers that must be preserved (copied from CallConv).
|
//! Registers that must be preserved (copied from CallConv).
|
||||||
Support::Array<RegMask, Globals::kNumVirtGroups> _preservedRegs;
|
Support::Array<RegMask, Globals::kNumVirtGroups> _preservedRegs {};
|
||||||
//! Size to save/restore per register group.
|
//! Size to save/restore per register group.
|
||||||
Support::Array<uint8_t, Globals::kNumVirtGroups> _saveRestoreRegSize;
|
Support::Array<uint8_t, Globals::kNumVirtGroups> _saveRestoreRegSize {};
|
||||||
//! Alignment of save/restore area per register group.
|
//! Alignment of save/restore area per register group.
|
||||||
Support::Array<uint8_t, Globals::kNumVirtGroups> _saveRestoreAlignment;
|
Support::Array<uint8_t, Globals::kNumVirtGroups> _saveRestoreAlignment {};
|
||||||
|
|
||||||
//! Stack size required to save registers with push/pop.
|
//! Stack size required to save registers with push/pop.
|
||||||
uint16_t _pushPopSaveSize;
|
uint16_t _pushPopSaveSize = 0;
|
||||||
//! Stack size required to save extra registers that cannot use push/pop.
|
//! Stack size required to save extra registers that cannot use push/pop.
|
||||||
uint16_t _extraRegSaveSize;
|
uint16_t _extraRegSaveSize = 0;
|
||||||
//! Offset where registers saved/restored via push/pop are stored
|
//! Offset where registers saved/restored via push/pop are stored
|
||||||
uint32_t _pushPopSaveOffset;
|
uint32_t _pushPopSaveOffset = 0;
|
||||||
//! Offset where extra registers that cannot use push/pop are stored.
|
//! Offset where extra registers that cannot use push/pop are stored.
|
||||||
uint32_t _extraRegSaveOffset;
|
uint32_t _extraRegSaveOffset = 0;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
//! \name Construction & Destruction
|
//! \name Construction & Destruction
|
||||||
//! \{
|
//! \{
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG FuncFrame() noexcept { reset(); }
|
//! Creates a default constructed function frame, which has initialized all members to their default values.
|
||||||
|
ASMJIT_INLINE_NODEBUG FuncFrame() noexcept = default;
|
||||||
|
//! Creates a copy of `other` function frame.
|
||||||
ASMJIT_INLINE_NODEBUG FuncFrame(const FuncFrame& other) noexcept = default;
|
ASMJIT_INLINE_NODEBUG FuncFrame(const FuncFrame& other) noexcept = default;
|
||||||
|
|
||||||
ASMJIT_API Error init(const FuncDetail& func) noexcept;
|
//! \}
|
||||||
|
|
||||||
ASMJIT_INLINE_NODEBUG void reset() noexcept {
|
//! \name Initialization & Reset
|
||||||
memset(this, 0, sizeof(FuncFrame));
|
//! \{
|
||||||
_spRegId = BaseReg::kIdBad;
|
|
||||||
_saRegId = BaseReg::kIdBad;
|
//! Initializes the function frame based on `func` detail.
|
||||||
_daOffset = kTagInvalidOffset;
|
ASMJIT_API Error init(const FuncDetail& func) noexcept;
|
||||||
}
|
//! Resets the function frame into its default constructed state.
|
||||||
|
ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = FuncFrame{}; }
|
||||||
|
|
||||||
|
//! \}
|
||||||
|
|
||||||
|
//! \name Overloaded Operators
|
||||||
|
//! \{
|
||||||
|
|
||||||
|
//! Copy assignment - function frame is copy assignable.
|
||||||
|
ASMJIT_INLINE_NODEBUG FuncFrame& operator=(const FuncFrame& other) noexcept = default;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|
||||||
@@ -1529,8 +1574,8 @@ public:
|
|||||||
|
|
||||||
//! Update `FuncFrame` based on function's arguments assignment.
|
//! Update `FuncFrame` based on function's arguments assignment.
|
||||||
//!
|
//!
|
||||||
//! \note You MUST call this in order to use `BaseEmitter::emitArgsAssignment()`, otherwise the FuncFrame would
|
//! \note This function must be called in order to use `BaseEmitter::emitArgsAssignment()`, otherwise the \ref FuncFrame
|
||||||
//! not contain the information necessary to assign all arguments into the registers and/or stack specified.
|
//! would not contain the information necessary to assign all arguments into the registers and/or stack specified.
|
||||||
ASMJIT_API Error updateFuncFrame(FuncFrame& frame) const noexcept;
|
ASMJIT_API Error updateFuncFrame(FuncFrame& frame) const noexcept;
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -174,7 +174,7 @@ public:
|
|||||||
uint32_t fillPattern = 0;
|
uint32_t fillPattern = 0;
|
||||||
|
|
||||||
// Reset the content of `CreateParams`.
|
// Reset the content of `CreateParams`.
|
||||||
inline void reset() noexcept { memset(this, 0, sizeof(*this)); }
|
ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = CreateParams{}; }
|
||||||
};
|
};
|
||||||
|
|
||||||
//! Creates a `JitAllocator` instance.
|
//! Creates a `JitAllocator` instance.
|
||||||
|
|||||||
@@ -21,8 +21,8 @@ static ASMJIT_FORCE_INLINE RATiedReg* RALocal_findTiedRegByWorkId(RATiedReg* tie
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// RALocalAllocator - Init & Reset
|
// RALocalAllocator - Initialization & Reset
|
||||||
// ===============================
|
// =========================================
|
||||||
|
|
||||||
Error RALocalAllocator::init() noexcept {
|
Error RALocalAllocator::init() noexcept {
|
||||||
PhysToWorkMap* physToWorkMap;
|
PhysToWorkMap* physToWorkMap;
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ ASMJIT_BEGIN_NAMESPACE
|
|||||||
// and should never be modified.
|
// and should never be modified.
|
||||||
const Zone::Block Zone::_zeroBlock = { nullptr, nullptr, 0 };
|
const Zone::Block Zone::_zeroBlock = { nullptr, nullptr, 0 };
|
||||||
|
|
||||||
// Zone - Init & Reset
|
// Zone - Initialization & Reset
|
||||||
// ===================
|
// =============================
|
||||||
|
|
||||||
void Zone::_init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
|
void Zone::_init(size_t blockSize, size_t blockAlignment, const Support::Temporary* temporary) noexcept {
|
||||||
ASMJIT_ASSERT(blockSize >= kMinBlockSize);
|
ASMJIT_ASSERT(blockSize >= kMinBlockSize);
|
||||||
@@ -215,8 +215,8 @@ static bool ZoneAllocator_hasDynamicBlock(ZoneAllocator* self, ZoneAllocator::Dy
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// ZoneAllocator - Init & Reset
|
// ZoneAllocator - Initialization & Reset
|
||||||
// ============================
|
// ======================================
|
||||||
|
|
||||||
void ZoneAllocator::reset(Zone* zone) noexcept {
|
void ZoneAllocator::reset(Zone* zone) noexcept {
|
||||||
// Free dynamic blocks.
|
// Free dynamic blocks.
|
||||||
@@ -227,9 +227,9 @@ void ZoneAllocator::reset(Zone* zone) noexcept {
|
|||||||
block = next;
|
block = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Zero the entire class and initialize to the given `zone`.
|
|
||||||
memset(this, 0, sizeof(*this));
|
|
||||||
_zone = zone;
|
_zone = zone;
|
||||||
|
memset(_slots, 0, sizeof(_slots));
|
||||||
|
_dynamicBlocks = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// asmjit::ZoneAllocator - Alloc & Release
|
// asmjit::ZoneAllocator - Alloc & Release
|
||||||
|
|||||||
@@ -9,8 +9,8 @@
|
|||||||
|
|
||||||
ASMJIT_BEGIN_NAMESPACE
|
ASMJIT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
// ZoneStackBase - Init & Reset
|
// ZoneStackBase - Initialization & Reset
|
||||||
// ============================
|
// ======================================
|
||||||
|
|
||||||
Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcept {
|
Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcept {
|
||||||
ZoneAllocator* oldAllocator = _allocator;
|
ZoneAllocator* oldAllocator = _allocator;
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//! printf("Status: %s\n", DebugUtils::errorAsString(err));
|
//! printf("Status: %s\n", DebugUtils::errorAsString(err));
|
||||||
//!
|
//!
|
||||||
//! // Ambiguous operand size - the pointer requires size.
|
//! // Ambiguous operand size - the pointer requires size.
|
||||||
//! err = a.inc(x86::ptr(x86::rax), 1);
|
//! err = a.inc(x86::ptr(x86::rax));
|
||||||
//! printf("Status: %s\n", DebugUtils::errorAsString(err));
|
//! printf("Status: %s\n", DebugUtils::errorAsString(err));
|
||||||
//!
|
//!
|
||||||
//! return 0;
|
//! return 0;
|
||||||
@@ -230,6 +230,9 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//! targets easily. If you want to create a register of native size dynamically by specifying its id it's also possible:
|
//! targets easily. If you want to create a register of native size dynamically by specifying its id it's also possible:
|
||||||
//!
|
//!
|
||||||
//! ```
|
//! ```
|
||||||
|
//! #include <asmjit/x86.h>
|
||||||
|
//! using namespace asmjit;
|
||||||
|
//!
|
||||||
//! void example(x86::Assembler& a) {
|
//! void example(x86::Assembler& a) {
|
||||||
//! x86::Gp zax = a.gpz(x86::Gp::kIdAx);
|
//! x86::Gp zax = a.gpz(x86::Gp::kIdAx);
|
||||||
//! x86::Gp zbx = a.gpz(x86::Gp::kIdBx);
|
//! x86::Gp zbx = a.gpz(x86::Gp::kIdBx);
|
||||||
@@ -360,18 +363,19 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//! x86::Gp src_a = a.zcx();
|
//! x86::Gp src_a = a.zcx();
|
||||||
//! x86::Gp src_b = a.zdx();
|
//! x86::Gp src_b = a.zdx();
|
||||||
//!
|
//!
|
||||||
//! X86::Xmm vec0 = x86::xmm0;
|
//! x86::Xmm vec0 = x86::xmm0;
|
||||||
//! X86::Xmm vec1 = x86::xmm1;
|
//! x86::Xmm vec1 = x86::xmm1;
|
||||||
//!
|
//!
|
||||||
//! // Create/initialize FuncDetail and FuncFrame.
|
//! // Create/initialize FuncDetail and FuncFrame.
|
||||||
//! FuncDetail func;
|
//! FuncDetail func;
|
||||||
//! func.init(FuncSignature::build<void, int*, const int*, const int*>());
|
//! func.init(FuncSignature::build<void, int*, const int*, const int*>(),
|
||||||
|
//! rt.environment());
|
||||||
//!
|
//!
|
||||||
//! FuncFrame frame;
|
//! FuncFrame frame;
|
||||||
//! frame.init(func);
|
//! frame.init(func);
|
||||||
//!
|
//!
|
||||||
//! // Make XMM0 and XMM1 dirty - RegGroup::kVec describes XMM|YMM|ZMM registers.
|
//! // Make XMM0 and XMM1 dirty - RegGroup::kVec describes XMM|YMM|ZMM registers.
|
||||||
//! frame.setDirtyRegs(RegGroup::kVec, IntUtils::mask(0, 1));
|
//! frame.setDirtyRegs(RegGroup::kVec, Support::bitMask(0, 1));
|
||||||
//!
|
//!
|
||||||
//! // Alternatively, if you don't want to use register masks you can pass BaseReg
|
//! // Alternatively, if you don't want to use register masks you can pass BaseReg
|
||||||
//! // to addDirtyRegs(). The following code would add both xmm0 and xmm1.
|
//! // to addDirtyRegs(). The following code would add both xmm0 and xmm1.
|
||||||
@@ -379,7 +383,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//!
|
//!
|
||||||
//! FuncArgsAssignment args(&func); // Create arguments assignment context.
|
//! FuncArgsAssignment args(&func); // Create arguments assignment context.
|
||||||
//! args.assignAll(dst, src_a, src_b);// Assign our registers to arguments.
|
//! args.assignAll(dst, src_a, src_b);// Assign our registers to arguments.
|
||||||
//! args.updateFrameInfo(frame); // Reflect our args in FuncFrame.
|
//! args.updateFuncFrame(frame); // Reflect our args in FuncFrame.
|
||||||
//! frame.finalize(); // Finalize the FuncFrame (updates it).
|
//! frame.finalize(); // Finalize the FuncFrame (updates it).
|
||||||
//!
|
//!
|
||||||
//! a.emitProlog(frame); // Emit function prolog.
|
//! a.emitProlog(frame); // Emit function prolog.
|
||||||
@@ -537,16 +541,16 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//!
|
//!
|
||||||
//! void prefixesExample(x86::Assembler& a) {
|
//! void prefixesExample(x86::Assembler& a) {
|
||||||
//! // Lock prefix for implementing atomics:
|
//! // Lock prefix for implementing atomics:
|
||||||
//! // lock add dword ptr [dst], 1
|
//! // lock add dword ptr [rdi], 1
|
||||||
//! a.lock().add(x86::dword_ptr(dst), 1);
|
//! a.lock().add(x86::dword_ptr(x86::rdi), 1);
|
||||||
//!
|
//!
|
||||||
//! // Similarly, XAcquire/XRelease prefixes are also available:
|
//! // Similarly, XAcquire/XRelease prefixes are also available:
|
||||||
//! // xacquire add dword ptr [dst], 1
|
//! // xacquire add dword ptr [rdi], 1
|
||||||
//! a.xacquire().add(x86::dword_ptr(dst), 1);
|
//! a.xacquire().add(x86::dword_ptr(x86::rdi), 1);
|
||||||
//!
|
//!
|
||||||
//! // Rep prefix (see also repe/repz and repne/repnz):
|
//! // Rep prefix (see also repe/repz and repne/repnz):
|
||||||
//! // rep movs byte ptr [dst], byte ptr [src]
|
//! // rep movs byte ptr [rdi], byte ptr [rsi]
|
||||||
//! a.rep().movs(x86::byte_ptr(dst), x86::byte_ptr(src));
|
//! a.rep().movs(x86::byte_ptr(x86::rdi), x86::byte_ptr(x86::rsi));
|
||||||
//!
|
//!
|
||||||
//! // Forcing REX prefix in 64-bit mode.
|
//! // Forcing REX prefix in 64-bit mode.
|
||||||
//! // rex mov eax, 1
|
//! // rex mov eax, 1
|
||||||
@@ -610,10 +614,10 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86)
|
|||||||
//! // -----------------
|
//! // -----------------
|
||||||
//! //
|
//! //
|
||||||
//! // - Broadcast data is part of memory operand.
|
//! // - Broadcast data is part of memory operand.
|
||||||
//! // - Use x86::Mem::_1toN(), which returns a new x86::Mem operand.
|
//! // - Use x86::Mem::_1to2(), x86::Mem::_1to4(), etc..., which returns a new x86::Mem operand with broadcast.
|
||||||
//!
|
//!
|
||||||
//! // vaddpd zmm0 {k1} {z}, zmm1, [rcx] {1to8}
|
//! // vaddpd zmm0 {k1} {z}, zmm1, [rcx] {1to8}
|
||||||
//! a.k(k1).z().vaddpd(zmm0, zmm1, x86::mem(rcx)._1to8());
|
//! a.k(k1).z().vaddpd(zmm0, zmm1, x86::ptr(rcx)._1to8());
|
||||||
//!
|
//!
|
||||||
//! // Embedded Rounding & Suppress-All-Exceptions
|
//! // Embedded Rounding & Suppress-All-Exceptions
|
||||||
//! // -------------------------------------------
|
//! // -------------------------------------------
|
||||||
|
|||||||
@@ -247,16 +247,17 @@ int TestApp::run() {
|
|||||||
compileTimer.stop();
|
compileTimer.stop();
|
||||||
|
|
||||||
Error err = errorHandler._err;
|
Error err = errorHandler._err;
|
||||||
if (!err) {
|
if (err == kErrorOk) {
|
||||||
finalizeTimer.start();
|
finalizeTimer.start();
|
||||||
err = cc->finalize();
|
err = cc->finalize();
|
||||||
finalizeTimer.stop();
|
finalizeTimer.stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
// The first pass is only for timing serialization and compilation, because otherwise it would be biased by
|
// The first pass is only used for timing of serialization and compilation, because otherwise it would be
|
||||||
// logging, which takes much more time than finalize() does. We want to benchmark Compiler the way it would
|
// biased by logging, which takes much more time than finalize() does. We want to benchmark Compiler the
|
||||||
// be used in production.
|
// way it would be used in the production.
|
||||||
if (pass == 0) {
|
if (pass == 0) {
|
||||||
|
_outputSize += code.codeSize();
|
||||||
compileTime += compileTimer.duration();
|
compileTime += compileTimer.duration();
|
||||||
finalizeTime += finalizeTimer.duration();
|
finalizeTime += finalizeTimer.duration();
|
||||||
continue;
|
continue;
|
||||||
@@ -290,8 +291,6 @@ int TestApp::run() {
|
|||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
|
|
||||||
if (err == kErrorOk) {
|
if (err == kErrorOk) {
|
||||||
_outputSize += code.codeSize();
|
|
||||||
|
|
||||||
StringTmp<128> result;
|
StringTmp<128> result;
|
||||||
StringTmp<128> expect;
|
StringTmp<128> expect;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user