diff --git a/src/asmjit/core.h b/src/asmjit/core.h index 961e8a6..b26f84d 100644 --- a/src/asmjit/core.h +++ b/src/asmjit/core.h @@ -966,12 +966,15 @@ namespace asmjit { //! with assembler requires the knowledge of the following: //! //! - \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 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 x86::Mem - Memory operand specific to X86 architecture. +//! - \ref arm::Mem - Memory operand specific to AArch64 architecture. //! - \ref Imm - Immediate (value) operand. //! - \ref Label - Label operand. //! @@ -1150,10 +1153,10 @@ namespace asmjit { //! //! void testX86Mem() { //! // 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]. -//! 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() { //! // 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.hasIndex(); // false. @@ -1176,8 +1179,8 @@ namespace asmjit { //! 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.setOffset(0); // Sets the offset to 0. -//! mem.setBase(rcx); // Changes BASE to RCX. -//! mem.setIndex(rax); // Changes INDEX to RAX. +//! mem.setBase(x86::rcx); // Changes BASE to RCX. +//! mem.setIndex(x86::rax); // Changes INDEX to RAX. //! mem.hasIndex(); // true. //! } //! // ... @@ -1269,7 +1272,8 @@ namespace asmjit { //! //! ### 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 @@ -1306,7 +1310,8 @@ namespace asmjit { //! //! ### 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 //! @@ -1478,7 +1483,7 @@ namespace asmjit { //! The first example illustrates how to format operands: //! //! ``` -//! #include +//! #include //! #include //! //! using namespace asmjit; @@ -1503,17 +1508,17 @@ namespace asmjit { //! // compatible with what AsmJit normally does. //! Arch arch = Arch::kX64; //! -//! log(arch, rax); // Prints 'rax'. -//! log(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`. -//! log(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`. -//! log(arch, imm(42)); // Prints '42'. +//! logOperand(arch, rax); // Prints 'rax'. +//! logOperand(arch, ptr(rax, rbx, 2)); // Prints '[rax + rbx * 4]`. +//! logOperand(arch, dword_ptr(rax, rbx, 2)); // Prints 'dword [rax + rbx * 4]`. +//! logOperand(arch, imm(42)); // Prints '42'. //! } //! ``` //! //! Next example illustrates how to format whole instructions: //! //! ``` -//! #include +//! #include //! #include //! #include //! @@ -1528,7 +1533,7 @@ namespace asmjit { //! FormatFlags formatFlags = FormatFlags::kNone; //! //! // The formatter expects operands in an array. -//! Operand_ operands { std::forward(args)... }; +//! Operand_ operands[] { std::forward(args)... }; //! //! StringTmp<128> sb; //! Formatter::formatInstruction( @@ -1550,13 +1555,13 @@ namespace asmjit { //! // Prints 'vaddpd zmm0, zmm1, [rax] {1to8}'. //! logInstruction(arch, //! BaseInst(Inst::kIdVaddpd), -//! zmm0, zmm1, ptr(rax)._1toN()); +//! zmm0, zmm1, ptr(rax)._1to8()); //! //! // BaseInst abstracts instruction id, instruction options, and extraReg. //! // Prints 'lock add [rax], rcx'. //! logInstruction(arch, //! BaseInst(Inst::kIdAdd, InstOptions::kX86_Lock), -//! x86::ptr(rax), rcx); +//! ptr(rax), rcx); //! //! // Similarly an extra register (like AVX-512 selector) can be used. //! // Prints 'vaddpd zmm0 {k2} {z}, zmm1, [rax]'. diff --git a/src/asmjit/core/builder_p.h b/src/asmjit/core/builder_p.h index 303358f..98790fd 100644 --- a/src/asmjit/core/builder_p.h +++ b/src/asmjit/core/builder_p.h @@ -13,6 +13,7 @@ ASMJIT_BEGIN_NAMESPACE +//! \cond INTERNAL //! \addtogroup asmjit_builder //! \{ @@ -28,6 +29,7 @@ static inline void BaseBuilder_assignInstState(BaseBuilder* self, InstNode* node } //! \} +//! \endcond ASMJIT_END_NAMESPACE diff --git a/src/asmjit/core/codeholder.cpp b/src/asmjit/core/codeholder.cpp index 742658c..63b15a3 100644 --- a/src/asmjit/core/codeholder.cpp +++ b/src/asmjit/core/codeholder.cpp @@ -132,8 +132,8 @@ CodeHolder::~CodeHolder() noexcept { CodeHolder_resetInternal(this, ResetPolicy::kHard); } -// CodeHolder - Init & Reset -// ========================= +// CodeHolder - Initialization & Reset +// =================================== inline void CodeHolder_setSectionDefaultName( Section* section, diff --git a/src/asmjit/core/cpuinfo.h b/src/asmjit/core/cpuinfo.h index 06118a0..9e0c41f 100644 --- a/src/asmjit/core/cpuinfo.h +++ b/src/asmjit/core/cpuinfo.h @@ -1110,7 +1110,7 @@ public: //! \} - //! \name Init & Reset + //! \name Initialization & Reset //! \{ //! Initializes CpuInfo architecture and sub-architecture members to `arch` and `subArch`, respectively. diff --git a/src/asmjit/core/emitter.h b/src/asmjit/core/emitter.h index 7e9f14d..09c72a6 100644 --- a/src/asmjit/core/emitter.h +++ b/src/asmjit/core/emitter.h @@ -337,10 +337,17 @@ public: //! Tests whether the emitter is destroyed (only used during destruction). 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 _clearEmitterFlags(EmitterFlags flags) noexcept { _emitterFlags &= _emitterFlags & ~flags; } //! \} + //! \endcond //! \name Target Information //! \{ @@ -554,23 +561,38 @@ public: //! \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 { resetInstOptions(); resetExtraReg(); 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 { State s{_instOptions | _forcedInstOptions, _extraReg, _inlineComment}; resetState(); return s; } + //! \endcond //! \} //! \name Sections //! \{ + //! Switches the given `section`. + //! + //! Once switched, everything is added to the given `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); //! 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 ASMJIT_INLINE_NODEBUG Error emit(InstId instId, Args&&... operands) { return _emitI(instId, Support::ForwardOp::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) { 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) { setInstOptions(inst.options()); setExtraReg(inst.extraReg()); return _emitOpArray(inst.id(), operands, opCount); } + //! \} + //! \cond INTERNAL + //! \name Emit Internals + //! \{ + //! 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); //! Emits instruction having operands stored in array. ASMJIT_API virtual Error _emitOpArray(InstId instId, const Operand_* operands, size_t opCount); - //! \endcond //! \} + //! \endcond //! \name Emit Utilities //! \{ + //! Emits a function prolog described by the given function `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); + //! Emits code that reassigns function `frame` arguments to the given `args`. ASMJIT_API Error emitArgsAssignment(const FuncFrame& frame, const FuncArgsAssignment& args); //! \} diff --git a/src/asmjit/core/func.cpp b/src/asmjit/core/func.cpp index f48c1cd..c8c5457 100644 --- a/src/asmjit/core/func.cpp +++ b/src/asmjit/core/func.cpp @@ -20,8 +20,8 @@ ASMJIT_BEGIN_NAMESPACE -// CallConv - Init & Reset -// ======================= +// CallConv - Initialization & Reset +// ================================= ASMJIT_FAVOR_SIZE Error CallConv::init(CallConvId ccId, const Environment& environment) noexcept { reset(); diff --git a/src/asmjit/core/func.h b/src/asmjit/core/func.h index 81d38be..bf5fb0c 100644 --- a/src/asmjit/core/func.h +++ b/src/asmjit/core/func.h @@ -353,8 +353,15 @@ struct CallConv { //! Function signature. //! -//! Contains information about function return type, count of arguments and their TypeIds. Function signature is -//! a low level structure which doesn't contain platform specific or calling convention specific information. +//! Contains information about a function return type, count of arguments, and their TypeIds. Function signature +//! 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 { //! \name Constants //! \{ @@ -405,6 +412,12 @@ struct FuncSignature { _ret(ret), _args{std::forward(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 static ASMJIT_INLINE_NODEBUG constexpr FuncSignature build(CallConvId ccId = CallConvId::kCDecl, uint32_t vaIndex = kNoVarArgs) noexcept { return FuncSignature(ccId, vaIndex, (TypeId(TypeUtils::TypeIdOfT::kTypeId))... ); @@ -415,16 +428,20 @@ struct FuncSignature { //! \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 bool operator==(const FuncSignature& other) const noexcept { return equals(other); } + //! Compares this function signature with `other` for equality.. + 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); } //! \} - //! \name Init & Reset + //! \name Initialization & Reset //! \{ + //! Resets this function signature to a default constructed state. ASMJIT_INLINE_NODEBUG void reset() noexcept { *this = FuncSignature{}; } //! \} @@ -432,6 +449,7 @@ struct FuncSignature { //! \name Equality & Comparison //! \{ + //! Compares this function signature with `other` for equality.. ASMJIT_INLINE_NODEBUG bool equals(const FuncSignature& other) const noexcept { return _ccId == other._ccId && _argCount == other._argCount && @@ -522,7 +540,7 @@ public: ASMJIT_DEPRECATED("Use FuncSignature instead of 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 //! (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 { ASMJIT_ASSERT((_data & (kRegTypeMask | kRegIdMask)) == 0); _data |= (uint32_t(regType) << kRegTypeShift) | (regId << kRegIdShift) | kFlagIsReg; } + //! Assigns a stack location at `offset`. inline void assignStackOffset(int32_t offset) noexcept { ASMJIT_ASSERT((_data & kStackOffsetMask) == 0); _data |= (uint32_t(offset) << kStackOffsetShift) | kFlagIsStack; @@ -610,7 +630,9 @@ struct FuncValue { //! Returns true if the value is initialized (explicit bool cast). 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; } + //! \endcond //! Tests whether the `FuncValue` has a flag `flag` set. ASMJIT_INLINE_NODEBUG bool hasFlag(uint32_t flag) const noexcept { return Support::test(_data, flag); } @@ -692,40 +714,52 @@ public: 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; } + //! \overload 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 { ASMJIT_ASSERT(index < Globals::kMaxValuePack); _values[index].reset(); } + //! Tests whether the value at the given `index` in the pack is assigned. inline bool hasValue(size_t index) noexcept { ASMJIT_ASSERT(index < Globals::kMaxValuePack); 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 { ASMJIT_ASSERT(index < Globals::kMaxValuePack); ASMJIT_ASSERT(reg.isPhysReg()); _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 { ASMJIT_ASSERT(index < Globals::kMaxValuePack); _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 { ASMJIT_ASSERT(index < Globals::kMaxValuePack); _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) { ASMJIT_ASSERT(index < Globals::kMaxValuePack); return _values[index]; } - + //! \overload inline const FuncValue& operator[](size_t index) const { ASMJIT_ASSERT(index < Globals::kMaxValuePack); return _values[index]; @@ -1004,87 +1038,98 @@ public: //! \{ //! Function attributes. - FuncAttributes _attributes; + FuncAttributes _attributes {}; //! Target architecture. - Arch _arch; + Arch _arch {}; //! 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). - uint8_t _saRegId; + uint8_t _saRegId = uint8_t(BaseReg::kIdBad); //! Red zone size (copied from CallConv). - uint8_t _redZoneSize; + uint8_t _redZoneSize = 0; //! Spill zone size (copied from CallConv). - uint8_t _spillZoneSize; + uint8_t _spillZoneSize = 0; //! Natural stack alignment (copied from CallConv). - uint8_t _naturalStackAlignment; + uint8_t _naturalStackAlignment = 0; //! Minimum stack alignment to turn on dynamic alignment. - uint8_t _minDynamicAlignment; + uint8_t _minDynamicAlignment = 0; //! Call stack alignment. - uint8_t _callStackAlignment; + uint8_t _callStackAlignment = 0; //! Local stack alignment. - uint8_t _localStackAlignment; + uint8_t _localStackAlignment = 0; //! Final stack alignment. - uint8_t _finalStackAlignment; + uint8_t _finalStackAlignment = 0; //! Adjustment of the stack before returning (X86-STDCALL). - uint16_t _calleeStackCleanup; + uint16_t _calleeStackCleanup = 0; //! Call stack size. - uint32_t _callStackSize; + uint32_t _callStackSize = 0; //! Local stack size. - uint32_t _localStackSize; + uint32_t _localStackSize = 0; //! 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). - uint32_t _localStackOffset; + uint32_t _localStackOffset = 0; //! 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. - uint32_t _saOffsetFromSP; + uint32_t _saOffsetFromSP = 0; //! 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. - uint32_t _stackAdjustment; + uint32_t _stackAdjustment = 0; //! Registers that are dirty. - Support::Array _dirtyRegs; + Support::Array _dirtyRegs {}; //! Registers that must be preserved (copied from CallConv). - Support::Array _preservedRegs; + Support::Array _preservedRegs {}; //! Size to save/restore per register group. - Support::Array _saveRestoreRegSize; + Support::Array _saveRestoreRegSize {}; //! Alignment of save/restore area per register group. - Support::Array _saveRestoreAlignment; + Support::Array _saveRestoreAlignment {}; //! 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. - uint16_t _extraRegSaveSize; + uint16_t _extraRegSaveSize = 0; //! 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. - uint32_t _extraRegSaveOffset; + uint32_t _extraRegSaveOffset = 0; //! \} //! \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_API Error init(const FuncDetail& func) noexcept; + //! \} - ASMJIT_INLINE_NODEBUG void reset() noexcept { - memset(this, 0, sizeof(FuncFrame)); - _spRegId = BaseReg::kIdBad; - _saRegId = BaseReg::kIdBad; - _daOffset = kTagInvalidOffset; - } + //! \name Initialization & Reset + //! \{ + + //! Initializes the function frame based on `func` detail. + 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. //! - //! \note You MUST call this in order to use `BaseEmitter::emitArgsAssignment()`, otherwise the FuncFrame would - //! not contain the information necessary to assign all arguments into the registers and/or stack specified. + //! \note This function must be called in order to use `BaseEmitter::emitArgsAssignment()`, otherwise the \ref FuncFrame + //! 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; //! \} diff --git a/src/asmjit/core/jitallocator.h b/src/asmjit/core/jitallocator.h index c64d18d..b694f8c 100644 --- a/src/asmjit/core/jitallocator.h +++ b/src/asmjit/core/jitallocator.h @@ -174,7 +174,7 @@ public: uint32_t fillPattern = 0; // 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. diff --git a/src/asmjit/core/ralocal.cpp b/src/asmjit/core/ralocal.cpp index 6378ec4..16f11a8 100644 --- a/src/asmjit/core/ralocal.cpp +++ b/src/asmjit/core/ralocal.cpp @@ -21,8 +21,8 @@ static ASMJIT_FORCE_INLINE RATiedReg* RALocal_findTiedRegByWorkId(RATiedReg* tie return nullptr; } -// RALocalAllocator - Init & Reset -// =============================== +// RALocalAllocator - Initialization & Reset +// ========================================= Error RALocalAllocator::init() noexcept { PhysToWorkMap* physToWorkMap; diff --git a/src/asmjit/core/zone.cpp b/src/asmjit/core/zone.cpp index d68e110..e1948eb 100644 --- a/src/asmjit/core/zone.cpp +++ b/src/asmjit/core/zone.cpp @@ -16,8 +16,8 @@ ASMJIT_BEGIN_NAMESPACE // and should never be modified. 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 { ASMJIT_ASSERT(blockSize >= kMinBlockSize); @@ -215,8 +215,8 @@ static bool ZoneAllocator_hasDynamicBlock(ZoneAllocator* self, ZoneAllocator::Dy } #endif -// ZoneAllocator - Init & Reset -// ============================ +// ZoneAllocator - Initialization & Reset +// ====================================== void ZoneAllocator::reset(Zone* zone) noexcept { // Free dynamic blocks. @@ -227,9 +227,9 @@ void ZoneAllocator::reset(Zone* zone) noexcept { block = next; } - // Zero the entire class and initialize to the given `zone`. - memset(this, 0, sizeof(*this)); _zone = zone; + memset(_slots, 0, sizeof(_slots)); + _dynamicBlocks = nullptr; } // asmjit::ZoneAllocator - Alloc & Release diff --git a/src/asmjit/core/zonestack.cpp b/src/asmjit/core/zonestack.cpp index 66f706d..7d66670 100644 --- a/src/asmjit/core/zonestack.cpp +++ b/src/asmjit/core/zonestack.cpp @@ -9,8 +9,8 @@ ASMJIT_BEGIN_NAMESPACE -// ZoneStackBase - Init & Reset -// ============================ +// ZoneStackBase - Initialization & Reset +// ====================================== Error ZoneStackBase::_init(ZoneAllocator* allocator, size_t middleIndex) noexcept { ZoneAllocator* oldAllocator = _allocator; diff --git a/src/asmjit/x86/x86assembler.h b/src/asmjit/x86/x86assembler.h index c948ed7..dd980a7 100644 --- a/src/asmjit/x86/x86assembler.h +++ b/src/asmjit/x86/x86assembler.h @@ -151,7 +151,7 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! printf("Status: %s\n", DebugUtils::errorAsString(err)); //! //! // 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)); //! //! 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: //! //! ``` +//! #include +//! using namespace asmjit; +//! //! void example(x86::Assembler& a) { //! x86::Gp zax = a.gpz(x86::Gp::kIdAx); //! 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_b = a.zdx(); //! -//! X86::Xmm vec0 = x86::xmm0; -//! X86::Xmm vec1 = x86::xmm1; +//! x86::Xmm vec0 = x86::xmm0; +//! x86::Xmm vec1 = x86::xmm1; //! //! // Create/initialize FuncDetail and FuncFrame. //! FuncDetail func; -//! func.init(FuncSignature::build()); +//! func.init(FuncSignature::build(), +//! rt.environment()); //! //! FuncFrame frame; //! frame.init(func); //! //! // 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 //! // 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. //! 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). //! //! a.emitProlog(frame); // Emit function prolog. @@ -537,16 +541,16 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! //! void prefixesExample(x86::Assembler& a) { //! // Lock prefix for implementing atomics: -//! // lock add dword ptr [dst], 1 -//! a.lock().add(x86::dword_ptr(dst), 1); +//! // lock add dword ptr [rdi], 1 +//! a.lock().add(x86::dword_ptr(x86::rdi), 1); //! //! // Similarly, XAcquire/XRelease prefixes are also available: -//! // xacquire add dword ptr [dst], 1 -//! a.xacquire().add(x86::dword_ptr(dst), 1); +//! // xacquire add dword ptr [rdi], 1 +//! a.xacquire().add(x86::dword_ptr(x86::rdi), 1); //! //! // Rep prefix (see also repe/repz and repne/repnz): -//! // rep movs byte ptr [dst], byte ptr [src] -//! a.rep().movs(x86::byte_ptr(dst), x86::byte_ptr(src)); +//! // rep movs byte ptr [rdi], byte ptr [rsi] +//! a.rep().movs(x86::byte_ptr(x86::rdi), x86::byte_ptr(x86::rsi)); //! //! // Forcing REX prefix in 64-bit mode. //! // rex mov eax, 1 @@ -610,10 +614,10 @@ ASMJIT_BEGIN_SUB_NAMESPACE(x86) //! // ----------------- //! // //! // - 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} -//! 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 //! // ------------------------------------------- diff --git a/test/asmjit_test_compiler.cpp b/test/asmjit_test_compiler.cpp index 5fe5b77..9062ef1 100644 --- a/test/asmjit_test_compiler.cpp +++ b/test/asmjit_test_compiler.cpp @@ -247,16 +247,17 @@ int TestApp::run() { compileTimer.stop(); Error err = errorHandler._err; - if (!err) { + if (err == kErrorOk) { finalizeTimer.start(); err = cc->finalize(); finalizeTimer.stop(); } - // The first pass is only for timing serialization and compilation, because otherwise it would be biased by - // logging, which takes much more time than finalize() does. We want to benchmark Compiler the way it would - // be used in production. + // The first pass is only used for timing of serialization and compilation, because otherwise it would be + // biased by logging, which takes much more time than finalize() does. We want to benchmark Compiler the + // way it would be used in the production. if (pass == 0) { + _outputSize += code.codeSize(); compileTime += compileTimer.duration(); finalizeTime += finalizeTimer.duration(); continue; @@ -290,8 +291,6 @@ int TestApp::run() { fflush(stdout); if (err == kErrorOk) { - _outputSize += code.codeSize(); - StringTmp<128> result; StringTmp<128> expect;