Added new instructions + xacquire|xrelease prefixes, reorganized instruction options

This commit is contained in:
kobalicek
2017-02-26 12:19:49 +01:00
parent f589e7165a
commit 4a94223ebd
24 changed files with 2766 additions and 2455 deletions

View File

@@ -27,7 +27,9 @@ Assembler::Assembler() noexcept
_section(nullptr), _section(nullptr),
_bufferData(nullptr), _bufferData(nullptr),
_bufferEnd(nullptr), _bufferEnd(nullptr),
_bufferPtr(nullptr) {} _bufferPtr(nullptr),
_op4(),
_op5() {}
Assembler::~Assembler() noexcept { Assembler::~Assembler() noexcept {
if (_code) sync(); if (_code) sync();
@@ -45,6 +47,10 @@ Error Assembler::onAttach(CodeHolder* code) noexcept {
_bufferData = p; _bufferData = p;
_bufferEnd = p + _section->_buffer._capacity; _bufferEnd = p + _section->_buffer._capacity;
_bufferPtr = p + _section->_buffer._length; _bufferPtr = p + _section->_buffer._length;
_op4.reset();
_op5.reset();
return Base::onAttach(code); return Base::onAttach(code);
} }
@@ -53,9 +59,50 @@ Error Assembler::onDetach(CodeHolder* code) noexcept {
_bufferData = nullptr; _bufferData = nullptr;
_bufferEnd = nullptr; _bufferEnd = nullptr;
_bufferPtr = nullptr; _bufferPtr = nullptr;
_op4.reset();
_op5.reset();
return Base::onDetach(code); return Base::onDetach(code);
} }
// ============================================================================
// [asmjit::Assembler - Code-Generation]
// ============================================================================
Error Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
_op4 = o4;
_op5 = o5;
_options |= kOptionOp4Op5Used;
return _emit(instId, o0, o1, o2, o3);
}
Error Assembler::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5:
_op4 = op[4];
_op5.reset();
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
case 6:
_op4 = op[4];
_op5 = op[5];
_options |= kOptionOp4Op5Used;
return _emit(instId, op[0], op[1], op[2], op[3]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================ // ============================================================================
// [asmjit::Assembler - Sync] // [asmjit::Assembler - Sync]
// ============================================================================ // ============================================================================
@@ -333,15 +380,20 @@ void Assembler::_emitLog(
opArray[1].copyFrom(o1); opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2); opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3); opArray[3].copyFrom(o3);
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4); opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5); opArray[5].copyFrom(_op5);
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset(); }
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset(); else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction( Logging::formatInstruction(
sb, logOptions, sb, logOptions,
this, getArchType(), this, getArchType(),
instId, options, _opExtra, opArray, 6); instId, options, _extraOp, opArray, 6);
if ((logOptions & Logger::kOptionBinaryForm) != 0) if ((logOptions & Logger::kOptionBinaryForm) != 0)
Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment()); Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
@@ -364,18 +416,23 @@ Error Assembler::_emitFailed(
opArray[1].copyFrom(o1); opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2); opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3); opArray[3].copyFrom(o3);
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4); opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5); opArray[5].copyFrom(_op5);
}
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset(); else {
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset(); opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction( Logging::formatInstruction(
sb, 0, sb, 0,
this, getArchType(), this, getArchType(),
instId, options, _opExtra, opArray, 6); instId, options, _extraOp, opArray, 6);
resetOptions(); resetOptions();
resetExtraOp();
resetInlineComment(); resetInlineComment();
return setLastError(err, sb.getData()); return setLastError(err, sb.getData());
} }

View File

@@ -53,6 +53,15 @@ public:
ASMJIT_API Error onAttach(CodeHolder* code) noexcept override; ASMJIT_API Error onAttach(CodeHolder* code) noexcept override;
ASMJIT_API Error onDetach(CodeHolder* code) noexcept override; ASMJIT_API Error onDetach(CodeHolder* code) noexcept override;
// --------------------------------------------------------------------------
// [Code-Generation]
// --------------------------------------------------------------------------
using CodeEmitter::_emit;
ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override;
ASMJIT_API Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) override;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Code-Buffer] // [Code-Buffer]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -129,6 +138,9 @@ public:
uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section. uint8_t* _bufferData; //!< Start of the CodeBuffer of the current section.
uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section. uint8_t* _bufferEnd; //!< End (first invalid byte) of the current section.
uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section. uint8_t* _bufferPtr; //!< Pointer in the CodeBuffer of the current section.
Operand_ _op4; //!< 5th operand data, used only temporarily.
Operand_ _op5; //!< 6th operand data, used only temporarily.
}; };
//! \} //! \}

View File

@@ -542,31 +542,10 @@ Error CodeBuilder::serialize(CodeEmitter* dst) {
case CBNode::kNodeInst: case CBNode::kNodeInst:
case CBNode::kNodeFuncCall: { case CBNode::kNodeFuncCall: {
CBInst* node = static_cast<CBInst*>(node_); CBInst* node = node_->as<CBInst>();
dst->setOptions(node->getOptions());
uint32_t instId = node->getInstId(); dst->setExtraOp(node->getExtraOp());
uint32_t options = node->getOptions(); err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
const Operand* opArray = node->getOpArray();
uint32_t opCount = node->getOpCount();
const Operand_* o0 = &dst->_none;
const Operand_* o1 = &dst->_none;
const Operand_* o2 = &dst->_none;
const Operand_* o3 = &dst->_none;
switch (opCount) {
case 6: dst->_op5 = opArray[5]; options |= CodeEmitter::kOptionOp5; ASMJIT_FALLTHROUGH;
case 5: dst->_op4 = opArray[4]; options |= CodeEmitter::kOptionOp4; ASMJIT_FALLTHROUGH;
case 4: o3 = &opArray[3]; ASMJIT_FALLTHROUGH;
case 3: o2 = &opArray[2]; ASMJIT_FALLTHROUGH;
case 2: o1 = &opArray[1]; ASMJIT_FALLTHROUGH;
case 1: o0 = &opArray[0]; ASMJIT_FALLTHROUGH;
case 0: break;
}
dst->setOptions(options);
err = dst->_emit(instId, *o0, *o1, *o2, *o3);
break; break;
} }

View File

@@ -510,12 +510,14 @@ public:
//! Clear emit options. //! Clear emit options.
ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _options &= ~options; } ASMJIT_INLINE void delOptions(uint32_t options) noexcept { _options &= ~options; }
//! Get op-mask operand (used to represent AVX-512 op-mask selector). //! Get if the node has extra operand.
ASMJIT_INLINE Operand& getOpExtra() noexcept { return _opExtra; } ASMJIT_INLINE bool hasExtraOp() const noexcept { return !_extraOp.isNone(); }
//! Get extra operand operand.
ASMJIT_INLINE Operand& getExtraOp() noexcept { return _extraOp; }
//! \overload //! \overload
ASMJIT_INLINE const Operand& getOpExtra() const noexcept { return _opExtra; } ASMJIT_INLINE const Operand& getExtraOp() const noexcept { return _extraOp; }
//1 Set op-mask operand. //! Set extra operand.
ASMJIT_INLINE void setOpExtra(const Operand& opExtra) noexcept { _opExtra = opExtra; } ASMJIT_INLINE void setExtraOp(const Operand& extraOp) noexcept { _extraOp = extraOp; }
//! Get operands count. //! Get operands count.
ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; } ASMJIT_INLINE uint32_t getOpCount() const noexcept { return _opCount; }
@@ -572,7 +574,7 @@ Update:
uint8_t _memOpIndex; //!< \internal uint8_t _memOpIndex; //!< \internal
uint8_t _reserved; //!< \internal uint8_t _reserved; //!< \internal
uint32_t _options; //!< Instruction options. uint32_t _options; //!< Instruction options.
Operand _opExtra; //!< Extra operand (op-mask {k} on AVX-512). Operand _extraOp; //!< Extra operand (REP {cx} or op-mask {k} on AVX-512).
Operand* _opArray; //!< Instruction operands. Operand* _opArray; //!< Instruction operands.
}; };
@@ -583,7 +585,6 @@ Update:
struct CBInstEx : public CBInst { struct CBInstEx : public CBInst {
Operand _op4; Operand _op4;
Operand _op5; Operand _op5;
Operand _opExtra;
}; };
// ============================================================================ // ============================================================================

View File

@@ -43,9 +43,7 @@ CodeEmitter::CodeEmitter(uint32_t type) noexcept
_globalOptions(kOptionMaybeFailureCase), _globalOptions(kOptionMaybeFailureCase),
_options(0), _options(0),
_inlineComment(nullptr), _inlineComment(nullptr),
_op4(), _extraOp(),
_op5(),
_opExtra(),
_none(), _none(),
_nativeGpReg(), _nativeGpReg(),
_nativeGpArray(nullptr) {} _nativeGpArray(nullptr) {}
@@ -82,15 +80,34 @@ Error CodeEmitter::onDetach(CodeHolder* code) noexcept {
_options = 0; _options = 0;
_inlineComment = nullptr; _inlineComment = nullptr;
_op4.reset();
_op5.reset(); _extraOp.reset();
_opExtra.reset();
_nativeGpReg.reset(); _nativeGpReg.reset();
_nativeGpArray = nullptr; _nativeGpArray = nullptr;
return kErrorOk; return kErrorOk;
} }
// ============================================================================
// [asmjit::CodeEmitter - Code-Generation]
// ============================================================================
Error CodeEmitter::_emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
const Operand_* op = opArray;
switch (opCount) {
case 0: return _emit(instId, _none, _none, _none, _none);
case 1: return _emit(instId, op[0], _none, _none, _none);
case 2: return _emit(instId, op[0], op[1], _none, _none);
case 3: return _emit(instId, op[0], op[1], op[2], _none);
case 4: return _emit(instId, op[0], op[1], op[2], op[3]);
case 5: return _emit(instId, op[0], op[1], op[2], op[3], op[4], _none);
case 6: return _emit(instId, op[0], op[1], op[2], op[3], op[4], op[5]);
default:
return DebugUtils::errored(kErrorInvalidArgument);
}
}
// ============================================================================ // ============================================================================
// [asmjit::CodeEmitter - Finalize] // [asmjit::CodeEmitter - Finalize]
// ============================================================================ // ============================================================================
@@ -187,99 +204,49 @@ Error CodeEmitter::commentv(const char* fmt, va_list ap) {
// ============================================================================ // ============================================================================
#define OP const Operand_& #define OP const Operand_&
#define NO _none
Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, NO, NO, NO, NO); } Error CodeEmitter::emit(uint32_t instId) { return _emit(instId, _none, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, NO, NO, NO); } Error CodeEmitter::emit(uint32_t instId, OP o0) { return _emit(instId, o0, _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, NO, NO); } Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1) { return _emit(instId, o0, o1, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, NO); } Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2) { return _emit(instId, o0, o1, o2, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); } Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3) { return _emit(instId, o0, o1, o2, o3); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { return _emit(instId, o0, o1, o2, o3, o4, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) { return _emit(instId, o0, o1, o2, o3, o4, o5); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4) { Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
_op4 = o4; Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
if (!o4.isNone()) _options |= kOptionOp4;
return _emit(instId, o0, o1, o2, o3);
}
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, OP o5) {
_op4 = o4;
_op5 = o5;
if (!o4.isNone()) _options |= kOptionOp4;
if (!o5.isNone()) _options |= kOptionOp5;
return _emit(instId, o0, o1, o2, o3);
}
Error CodeEmitter::emit(uint32_t instId, int o0) { return _emit(instId, Imm(o0), NO, NO, NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int o1) { return _emit(instId, o0, Imm(o1), NO, NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int o2) { return _emit(instId, o0, o1, Imm(o2), NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int o4) { Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
_options |= kOptionOp4; Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
_op4 = Imm(o4); Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
return _emit(instId, o0, o1, o2, o3);
}
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int o5) {
_op4 = o4;
_op5 = Imm(o5);
_options |= kOptionOp4 | kOptionOp5;
return _emit(instId, o0, o1, o2, o3);
}
Error CodeEmitter::emit(uint32_t instId, int64_t o0) { return _emit(instId, Imm(o0), NO, NO, NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), NO, NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), NO); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); } Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, int64_t o3) { return _emit(instId, o0, o1, o2, Imm(o3)); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, int64_t o4) { return _emit(instId, o0, o1, o2, o3, Imm(o4), _none); }
_options |= kOptionOp4; Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) { return _emit(instId, o0, o1, o2, o3, o4, Imm(o5)); }
_op4 = Imm(o4);
return _emit(instId, o0, o1, o2, o3);
}
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, OP o2, OP o3, OP o4, int64_t o5) {
_op4 = o4;
_op5 = Imm(o5);
_options |= kOptionOp4 | kOptionOp5;
return _emit(instId, o0, o1, o2, o3);
}
#undef NO
#undef OP #undef OP
// ============================================================================ // ============================================================================
// [asmjit::CodeEmitter - Validation] // [asmjit::CodeEmitter - Validation]
// ============================================================================ // ============================================================================
Error CodeEmitter::_validate(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) const noexcept { Error CodeEmitter::_validate(uint32_t instId, const Operand_* opArray, uint32_t opCount) const noexcept {
#if !defined(ASMJIT_DISABLE_VALIDATION) #if !defined(ASMJIT_DISABLE_VALIDATION)
Operand_ opArray[6];
opArray[0].copyFrom(o0);
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
uint32_t archType = getArchType(); uint32_t archType = getArchType();
uint32_t options = getGlobalOptions() | getOptions(); uint32_t options = getGlobalOptions() | getOptions();
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
#if defined(ASMJIT_BUILD_X86) #if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType)) if (ArchInfo::isX86Family(archType))
return X86Inst::validate(archType, instId, options, _opExtra, opArray, 6); return X86Inst::validate(archType, instId, options, _extraOp, opArray, 6);
#endif #endif
#if defined(ASMJIT_BUILD_ARM) #if defined(ASMJIT_BUILD_ARM)
if (ArchInfo::isArmFamily(archType)) if (ArchInfo::isArmFamily(archType))
return ArmInst::validate(archType, instId, options, _opExtra, opArray, 6); return ArmInst::validate(archType, instId, options, _extraOp, opArray, 6);
#endif #endif
return DebugUtils::errored(kErrorInvalidArch); return DebugUtils::errored(kErrorInvalidArch);

View File

@@ -101,15 +101,11 @@ public:
//! NOTE: Reserved options should never appear in `CBInst` options. //! NOTE: Reserved options should never appear in `CBInst` options.
kOptionReservedMask = 0x00000007U, kOptionReservedMask = 0x00000007U,
//! Instruction has `_op4` (5th operand, indexed from zero). //! Used only by Assembler to mark `_op4` and `_op5` are used.
kOptionOp4 = 0x0000008U, kOptionOp4Op5Used = 0x00000008U,
//! Instruction has `_op5` (6th operand, indexed from zero).
kOptionOp5 = 0x0000010U,
//! Instruction has `_opExtra` operand (mask-op {k} operand when using AVX-512).
kOptionOpExtra = 0x00000020U,
//! Prevents following a jump during compilation (CodeCompiler). //! Prevents following a jump during compilation (CodeCompiler).
kOptionUnfollow = 0x00000040U, kOptionUnfollow = 0x00000010U,
//! Overwrite the destination operand (CodeCompiler). //! Overwrite the destination operand (CodeCompiler).
//! //!
@@ -149,7 +145,7 @@ public:
//! //!
//! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use //! - `sqrtss x, y` - only LO element of `x` is changed, if you don't use
//! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`. //! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`.
kOptionOverwrite = 0x00000080U kOptionOverwrite = 0x00000020U
}; };
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
@@ -172,8 +168,12 @@ public:
// [Code-Generation] // [Code-Generation]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Emit instruction. //! Emit instruction having max 4 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0; virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) = 0;
//! Emit instruction having max 6 operands.
virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) = 0;
//! Emit instruction having operands stored in array.
virtual Error _emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount);
//! Create a new label. //! Create a new label.
virtual Label newLabel() = 0; virtual Label newLabel() = 0;
@@ -315,20 +315,12 @@ public:
//! Reset options of the next instruction. //! Reset options of the next instruction.
ASMJIT_INLINE void resetOptions() noexcept { _options = 0; } ASMJIT_INLINE void resetOptions() noexcept { _options = 0; }
//! Get if the 5th operand (indexed from zero) of the next instruction is used. //! Get an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE bool hasOp4() const noexcept { return (_options & kOptionOp4) != 0; } ASMJIT_INLINE const Operand& getExtraOp() const noexcept { return static_cast<const Operand&>(_extraOp); }
//! Get if the 6th operand (indexed from zero) of the next instruction is used. //! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE bool hasOp5() const noexcept { return (_options & kOptionOp5) != 0; } ASMJIT_INLINE void setExtraOp(const Operand_& extraOp) noexcept { _extraOp = extraOp; }
//! Get if the op-mask operand of the next instruction is used. //! Reset an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE bool hasOpExtra() const noexcept { return (_options & kOptionOpExtra) != 0; } ASMJIT_INLINE void resetExtraOp() noexcept { _extraOp.setSignature(0); }
ASMJIT_INLINE const Operand& getOp4() const noexcept { return static_cast<const Operand&>(_op4); }
ASMJIT_INLINE const Operand& getOp5() const noexcept { return static_cast<const Operand&>(_op5); }
ASMJIT_INLINE const Operand& getOpExtra() const noexcept { return static_cast<const Operand&>(_opExtra); }
ASMJIT_INLINE void setOp4(const Operand_& op4) noexcept { _options |= kOptionOp4; _op4 = op4; }
ASMJIT_INLINE void setOp5(const Operand_& op5) noexcept { _options |= kOptionOp5; _op5 = op5; }
ASMJIT_INLINE void setOpExtra(const Operand_& opExtra) noexcept { _options |= kOptionOpExtra; _opExtra = opExtra; }
//! Get annotation of the next instruction. //! Get annotation of the next instruction.
ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; } ASMJIT_INLINE const char* getInlineComment() const noexcept { return _inlineComment; }
@@ -461,12 +453,16 @@ public:
return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5)); return emit(instId, o0, o1, o2, o3, o4, static_cast<int64_t>(o5));
} }
ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
return _emitOpArray(instId, opArray, opCount);
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Validation] // [Validation]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
//! Validate instruction with current options, called by `_emit()` if validation is enabled. //! Validate instruction with current options, called by `_emit()` if validation is enabled.
ASMJIT_API Error _validate(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) const noexcept; ASMJIT_API Error _validate(uint32_t instId, const Operand_* opArray, uint32_t opCount) const noexcept;
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Members] // [Members]
@@ -488,10 +484,7 @@ public:
uint32_t _options; //!< Used to pass instruction options (affects the next instruction). uint32_t _options; //!< Used to pass instruction options (affects the next instruction).
const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction). const char* _inlineComment; //!< Inline comment of the next instruction (affects the next instruction).
Operand_ _op4; //!< 5th operand data (indexed from zero) (affects the next instruction). Operand_ _extraOp; //!< Extra operand (op-mask {k} on AVX-512) (affects the next instruction).
Operand_ _op5; //!< 6th operand data (indexed from zero) (affects the next instruction).
Operand_ _opExtra; //!< Extra operand (op-mask {k} on AVX-512) (affects the next instruction).
Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null. Operand_ _none; //!< Used to pass unused operands to `_emit()` instead of passing null.
Reg _nativeGpReg; //!< Native GP register with zero id. Reg _nativeGpReg; //!< Native GP register with zero id.
const Reg* _nativeGpArray; //!< Array of native registers indexed from zero. const Reg* _nativeGpArray; //!< Array of native registers indexed from zero.

View File

@@ -503,6 +503,9 @@ ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept {
if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA); if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA);
if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1); if (regs.ecx & 0x00000001U) cpuInfo->addFeature(CpuInfo::kX86FeaturePREFETCHWT1);
// TSX is supported if at least one of `HLE` and `RTM` is supported.
if (regs.ebx & 0x00000810U) cpuInfo->addFeature(CpuInfo::kX86FeatureTSX);
// Detect AVX2. // Detect AVX2.
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) { if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2); if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2);

View File

@@ -107,7 +107,7 @@ public:
kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256. kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256.
kX86FeatureXSAVE, //!< CPU has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR. kX86FeatureXSAVE, //!< CPU has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR.
kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support - XSAVEOPT/XSAVEOPT64. kX86FeatureXSAVEOPT, //!< CPU has XSAVEOPT support - XSAVEOPT/XSAVEOPT64.
kX86FeatureOSXSAVE, //!< OS has enabled XSAVE, you can call XGETBV to get XCR content. kX86FeatureOSXSAVE, //!< CPU has XSAVE enabled by OS.
kX86FeatureAVX, //!< CPU has AVX. kX86FeatureAVX, //!< CPU has AVX.
kX86FeatureAVX2, //!< CPU has AVX2. kX86FeatureAVX2, //!< CPU has AVX2.
kX86FeatureF16C, //!< CPU has F16C. kX86FeatureF16C, //!< CPU has F16C.
@@ -121,6 +121,7 @@ public:
kX86FeatureMPX, //!< CPU has MPX (memory protection extensions). kX86FeatureMPX, //!< CPU has MPX (memory protection extensions).
kX86FeatureHLE, //!< CPU has HLE. kX86FeatureHLE, //!< CPU has HLE.
kX86FeatureRTM, //!< CPU has RTM. kX86FeatureRTM, //!< CPU has RTM.
kX86FeatureTSX, //!< CPU has TSX.
kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB). kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
kX86FeatureFSGSBASE, //!< CPU has FSGSBASE. kX86FeatureFSGSBASE, //!< CPU has FSGSBASE.
kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation). kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation).

View File

@@ -49,9 +49,12 @@ static const char errorMessages[] =
"Invalid register kind\0" "Invalid register kind\0"
"Invalid register's physical id\0" "Invalid register's physical id\0"
"Invalid register's virtual id\0" "Invalid register's virtual id\0"
"Invalid LOCK prefix\0" "Invalid prefix combination\0"
"Invalid REP prefix\0" "Invalid lock prefix\0"
"Invalid REX prefix\0" "Invalid xacquire prefix\0"
"Invalid xrelease prefix\0"
"Invalid rep prefix\0"
"Invalid rex prefix\0"
"Invalid mask, expected {k}\0" "Invalid mask, expected {k}\0"
"Invalid use of {k}\0" "Invalid use of {k}\0"
"Invalid use of {k}{z}\0" "Invalid use of {k}{z}\0"

View File

@@ -177,8 +177,14 @@ ASMJIT_ENUM(ErrorCode) {
kErrorInvalidPhysId, kErrorInvalidPhysId,
//! Invalid register's virtual id. //! Invalid register's virtual id.
kErrorInvalidVirtId, kErrorInvalidVirtId,
//! Invalid prefix combination.
kErrorInvalidPrefixCombination,
//! Invalid LOCK prefix. //! Invalid LOCK prefix.
kErrorInvalidLockPrefix, kErrorInvalidLockPrefix,
//! Invalid XACQUIRE prefix.
kErrorInvalidXAcquirePrefix,
//! Invalid XACQUIRE prefix.
kErrorInvalidXReleasePrefix,
//! Invalid REP prefix. //! Invalid REP prefix.
kErrorInvalidRepPrefix, kErrorInvalidRepPrefix,
//! Invalid REX prefix. //! Invalid REX prefix.

View File

@@ -235,15 +235,15 @@ Error Logging::formatInstruction(
uint32_t archType, uint32_t archType,
uint32_t instId, uint32_t instId,
uint32_t options, uint32_t options,
const Operand_& opExtra, const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept { const Operand_* opArray, uint32_t opCount) noexcept {
#if defined(ASMJIT_BUILD_X86) #if defined(ASMJIT_BUILD_X86)
return X86Logging::formatInstruction(sb, logOptions, emitter, archType, instId, options, opExtra, opArray, opCount); return X86Logging::formatInstruction(sb, logOptions, emitter, archType, instId, options, extraOp, opArray, opCount);
#endif // ASMJIT_BUILD_X86 #endif // ASMJIT_BUILD_X86
#if defined(ASMJIT_BUILD_ARM) #if defined(ASMJIT_BUILD_ARM)
return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, instId, options, opExtra, opArray, opCount); return ArmLogging::formatInstruction(sb, logOptions, emitter, archType, instId, options, extraOp, opArray, opCount);
#endif // ASMJIT_BUILD_ARM #endif // ASMJIT_BUILD_ARM
return kErrorInvalidArch; return kErrorInvalidArch;
@@ -374,7 +374,7 @@ Error Logging::formatNode(
cb->getArchType(), cb->getArchType(),
node->getInstId(), node->getInstId(),
node->getOptions(), node->getOptions(),
node->getOpExtra(), node->getExtraOp(),
node->getOpArray(), node->getOpCount())); node->getOpArray(), node->getOpCount()));
break; break;
} }
@@ -438,7 +438,7 @@ Error Logging::formatNode(
cb->getArchType(), cb->getArchType(),
node->getInstId(), node->getInstId(),
node->getOptions(), node->getOptions(),
node->getOpExtra(), node->getExtraOp(),
node->getOpArray(), node->getOpCount())); node->getOpArray(), node->getOpCount()));
break; break;
} }

View File

@@ -251,7 +251,7 @@ struct Logging {
uint32_t archType, uint32_t archType,
uint32_t instId, uint32_t instId,
uint32_t options, uint32_t options,
const Operand_& opExtra, const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept; const Operand_* opArray, uint32_t opCount) noexcept;
#if !defined(ASMJIT_DISABLE_BUILDER) #if !defined(ASMJIT_DISABLE_BUILDER)

View File

@@ -538,7 +538,9 @@ Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o
CodeEmitter::kOptionStrictValidation | // Strict validation. CodeEmitter::kOptionStrictValidation | // Strict validation.
X86Inst::kOptionRep | // REP/REPZ prefix. X86Inst::kOptionRep | // REP/REPZ prefix.
X86Inst::kOptionRepnz | // REPNZ prefix. X86Inst::kOptionRepnz | // REPNZ prefix.
X86Inst::kOptionLock ; // LOCK prefix. X86Inst::kOptionLock | // LOCK prefix.
X86Inst::kOptionXAcquire | // XACQUIRE prefix.
X86Inst::kOptionXRelease ; // XRELEASE prefix.
// Signature of the first 3 operands. // Signature of the first 3 operands.
uint32_t isign3 = o0.getOp() + (o1.getOp() << 3) + (o2.getOp() << 6); uint32_t isign3 = o0.getOp() + (o1.getOp() << 3) + (o2.getOp() << 6);
@@ -564,26 +566,55 @@ Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o
// Strict validation. // Strict validation.
#if !defined(ASMJIT_DISABLE_VALIDATION) #if !defined(ASMJIT_DISABLE_VALIDATION)
if (options & CodeEmitter::kOptionStrictValidation) { if (options & CodeEmitter::kOptionStrictValidation) {
err = _validate(instId, o0, o1, o2, o3); Operand_ opArray[6];
opArray[0].copyFrom(o0);
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
err = _validate(instId, opArray, 6);
if (ASMJIT_UNLIKELY(err)) goto Failed; if (ASMJIT_UNLIKELY(err)) goto Failed;
} }
#endif // !ASMJIT_DISABLE_VALIDATION #endif // !ASMJIT_DISABLE_VALIDATION
uint32_t instFlags = instData->getFlags(); uint32_t iFlags = instData->getFlags();
// LOCK prefix. // LOCK, XACQUIRE, and XRELEASE prefixes.
if (options & X86Inst::kOptionLock) { if (options & X86Inst::kOptionLock) {
if (ASMJIT_UNLIKELY(!(instFlags & X86Inst::kFlagLock))) bool xAcqRel = (options & (X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease)) != 0;
if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagLock)) && !xAcqRel))
goto InvalidLockPrefix; goto InvalidLockPrefix;
if (xAcqRel) {
if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXAcquire) && !(iFlags & X86Inst::kFlagXAcquire)))
goto InvalidXAcquirePrefix;
if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXRelease) && !(iFlags & X86Inst::kFlagXRelease)))
goto InvalidXReleasePrefix;
EMIT_BYTE((options & X86Inst::kOptionXAcquire) ? 0xF2 : 0xF3);
}
EMIT_BYTE(0xF0); EMIT_BYTE(0xF0);
} }
// REP / REPNZ prefix. // REP and REPNZ prefixes.
if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) { if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) {
if (ASMJIT_UNLIKELY(!(instFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz)))) if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz))))
goto InvalidRepPrefix; goto InvalidRepPrefix;
if (!_opExtra.isNone() && ASMJIT_UNLIKELY(!X86Reg::isGp(_opExtra, X86Gp::kIdCx))) if (!_extraOp.isNone() && ASMJIT_UNLIKELY(!X86Reg::isGp(_extraOp, X86Gp::kIdCx)))
goto InvalidRepPrefix; goto InvalidRepPrefix;
EMIT_BYTE((options & X86Inst::kOptionRepnz) ? 0xF2 : 0xF3); EMIT_BYTE((options & X86Inst::kOptionRepnz) ? 0xF2 : 0xF3);
@@ -609,6 +640,14 @@ Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o
case X86Inst::kEncodingX86Op: case X86Inst::kEncodingX86Op:
goto EmitX86Op; goto EmitX86Op;
case X86Inst::kEncodingX86Op_O_I8:
if (ASMJIT_UNLIKELY(isign3 != ENC_OPS1(Imm)))
goto InvalidInstruction;
imVal = o0.as<Imm>().getUInt8();
imLen = 1;
ASMJIT_FALLTHROUGH;
case X86Inst::kEncodingX86Op_O: case X86Inst::kEncodingX86Op_O:
rbReg = 0; rbReg = 0;
goto EmitX86R; goto EmitX86R;
@@ -1011,6 +1050,7 @@ CaseX86M_GPB_MulDiv:
// displacement is not encodable so the alternative opcode field // displacement is not encodable so the alternative opcode field
// in X86DB must be zero. // in X86DB must be zero.
opCode = 0xE8; opCode = 0xE8;
opReg = 0;
goto EmitJmpCall; goto EmitJmpCall;
case X86Inst::kEncodingX86Cmpxchg: { case X86Inst::kEncodingX86Cmpxchg: {
@@ -1282,6 +1322,7 @@ CaseX86M_GPB_MulDiv:
} }
rmRel = &o0; rmRel = &o0;
opReg = 0;
goto EmitJmpCall; goto EmitJmpCall;
case X86Inst::kEncodingX86JecxzLoop: case X86Inst::kEncodingX86JecxzLoop:
@@ -1296,6 +1337,8 @@ CaseX86M_GPB_MulDiv:
rmRel = &o1; rmRel = &o1;
} }
opReg = 0;
goto EmitJmpCall; goto EmitJmpCall;
case X86Inst::kEncodingX86Jmp: case X86Inst::kEncodingX86Jmp:
@@ -1311,6 +1354,11 @@ CaseX86M_GPB_MulDiv:
// Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded // Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded
// with 8-bit displacement's opcode is stored as an alternative opcode. // with 8-bit displacement's opcode is stored as an alternative opcode.
opCode = 0xE9; opCode = 0xE9;
opReg = 0;
goto EmitJmpCall;
case X86Inst::kEncodingX86JmpRel:
rmRel = &o0;
goto EmitJmpCall; goto EmitJmpCall;
case X86Inst::kEncodingX86Lea: case X86Inst::kEncodingX86Lea:
@@ -2815,6 +2863,9 @@ CaseVexRm:
break; break;
case X86Inst::kEncodingVexRm_T1_4X: { case X86Inst::kEncodingVexRm_T1_4X: {
if (!(options & kOptionOp4Op5Used))
goto InvalidInstruction;
if (X86Reg::isZmm(o0 ) && X86Reg::isZmm(o1) && if (X86Reg::isZmm(o0 ) && X86Reg::isZmm(o1) &&
X86Reg::isZmm(o2 ) && X86Reg::isZmm(o3) && X86Reg::isZmm(o2 ) && X86Reg::isZmm(o3) &&
X86Reg::isZmm(_op4) && _op5.isMem()) { X86Reg::isZmm(_op4) && _op5.isMem()) {
@@ -3374,7 +3425,7 @@ CaseVexRvm_R:
} }
case X86Inst::kEncodingVexRvrmiRvmri_Lx: { case X86Inst::kEncodingVexRvrmiRvmri_Lx: {
if (!(options & CodeEmitter::kOptionOp4) || !_op4.isImm()) if (!(options & CodeEmitter::kOptionOp4Op5Used) || !_op4.isImm())
goto InvalidInstruction; goto InvalidInstruction;
const uint32_t isign4 = isign3 + (o3.getOp() << 9); const uint32_t isign4 = isign3 + (o3.getOp() << 9);
@@ -3987,9 +4038,11 @@ EmitVexEvexR:
// Mark invalid VEX (force EVEX) case: // [@.......|.LL.....|Vvvvv..R|RBBmmmmm]. // Mark invalid VEX (force EVEX) case: // [@.......|.LL.....|Vvvvv..R|RBBmmmmm].
x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>()); x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>());
if (X86Reg::isK(_extraOp))
x |= _extraOp.as<Reg>().getId() << 16; // [@.......|.LL..aaa|Vvvvv..R|RBBmmmmm].
// Handle AVX512 options by a single branch. // Handle AVX512 options by a single branch.
const uint32_t kAvx512Options = X86Inst::kOptionOpExtra | const uint32_t kAvx512Options = X86Inst::kOptionZMask |
X86Inst::kOptionKZ |
X86Inst::kOption1ToX | X86Inst::kOption1ToX |
X86Inst::kOptionSAE | X86Inst::kOptionSAE |
X86Inst::kOptionER ; X86Inst::kOptionER ;
@@ -3999,14 +4052,7 @@ EmitVexEvexR:
goto InvalidBroadcast; goto InvalidBroadcast;
// TODO: {sae} and {er} // TODO: {sae} and {er}
x |= options & X86Inst::kOptionZMask; // [@.......|zLL..aaa|Vvvvv..R|RBBmmmmm].
// NOTE: We consider a valid construct internally even when {kz} was
// specified without specifying the register. In that case it would be
// `k0` and basically everything should be zeroed. It's valid EVEX.
if (options & X86Inst::kOptionOpExtra)
x |= _opExtra.getId() << 16;
x |= options & X86Inst::kOptionKZ; // [@.......|zLL..aaa|Vvvvv..R|RBBmmmmm].
} }
// Check if EVEX is required by checking bits in `x` : [@.......|xx...xxx|x......x|.x.x....]. // Check if EVEX is required by checking bits in `x` : [@.......|xx...xxx|x......x|.x.x....].
@@ -4101,10 +4147,12 @@ EmitVexEvexM:
// Mark invalid VEX (force EVEX) case: // [@.......|.LL.X...|Vvvvv..R|RXBmmmmm]. // Mark invalid VEX (force EVEX) case: // [@.......|.LL.X...|Vvvvv..R|RXBmmmmm].
x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>()); x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>());
if (X86Reg::isK(_extraOp))
x |= _extraOp.as<Reg>().getId() << 16; // [@.......|.LL.Xaaa|Vvvvv..R|RXBmmmmm].
// Handle AVX512 options by a single branch. // Handle AVX512 options by a single branch.
const uint32_t kAvx512Options = X86Inst::kOptionOpExtra | const uint32_t kAvx512Options = X86Inst::kOption1ToX |
X86Inst::kOption1ToX | X86Inst::kOptionZMask |
X86Inst::kOptionKZ |
X86Inst::kOptionSAE | X86Inst::kOptionSAE |
X86Inst::kOptionER ; X86Inst::kOptionER ;
if (options & kAvx512Options) { if (options & kAvx512Options) {
@@ -4112,14 +4160,8 @@ EmitVexEvexM:
if (ASMJIT_UNLIKELY(options & (X86Inst::kOptionSAE | X86Inst::kOptionER))) if (ASMJIT_UNLIKELY(options & (X86Inst::kOptionSAE | X86Inst::kOptionER)))
goto InvalidEROrSAE; goto InvalidEROrSAE;
// NOTE: We consider a valid construct internally even when {kz} was
// specified without specifying the register. In that case it would be
// `k0` and basically everything would be zeroed. It's a valid EVEX.
if (options & X86Inst::kOptionOpExtra)
x |= _opExtra.getId() << 16;
x |= options & (X86Inst::kOption1ToX | // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm]. x |= options & (X86Inst::kOption1ToX | // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm].
X86Inst::kOptionKZ ); // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm]. X86Inst::kOptionZMask); // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm].
} }
// Check if EVEX is required by checking bits in `x` : [@.......|xx.xxxxx|x......x|...x....]. // Check if EVEX is required by checking bits in `x` : [@.......|xx.xxxxx|x......x|...x....].
@@ -4217,8 +4259,9 @@ EmitJmpCall:
ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 || ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 ||
(opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F); (opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
inst32Size += static_cast<uint32_t>( // Only one of these should be used at the same time.
(opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F); inst32Size += static_cast<uint32_t>(opReg != 0);
inst32Size += static_cast<uint32_t>((opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
if (rmRel->isLabel()) { if (rmRel->isLabel()) {
label = _code->getLabelEntry(rmRel->as<Label>()); label = _code->getLabelEntry(rmRel->as<Label>());
@@ -4227,7 +4270,7 @@ EmitJmpCall:
if (label->isBound()) { if (label->isBound()) {
// Bound label. // Bound label.
rel32 = static_cast<uint32_t>((static_cast<uint64_t>(label->getOffset()) - ip - inst32Size) & 0xFFFFFFFFU); rel32 = static_cast<uint32_t>((static_cast<uint64_t>(label->getOffset()) - ip - inst32Size) & 0xFFFFFFFFU);
goto EmitJmpCall_Rel; goto EmitJmpCallRel;
} }
else { else {
// Non-bound label. // Non-bound label.
@@ -4242,10 +4285,14 @@ EmitJmpCall:
if (ASMJIT_UNLIKELY(!opCode || (options & X86Inst::kOptionShortForm) != 0)) if (ASMJIT_UNLIKELY(!opCode || (options & X86Inst::kOptionShortForm) != 0))
goto InvalidDisplacement; goto InvalidDisplacement;
// Emit [PREFIX] OPCODE [/X] <DISP32>.
if (opCode & X86Inst::kOpCode_MM_Mask) if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F); EMIT_BYTE(0x0F);
EMIT_BYTE(opCode); EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
relOffset = -4; relOffset = -4;
relSize = 4; relSize = 4;
goto EmitRel; goto EmitRel;
@@ -4264,7 +4311,7 @@ EmitJmpCall:
uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size; uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size;
if (getArchType() == ArchInfo::kTypeX86 || Utils::isInt32(static_cast<int64_t>(rel64))) { if (getArchType() == ArchInfo::kTypeX86 || Utils::isInt32(static_cast<int64_t>(rel64))) {
rel32 = static_cast<uint32_t>(rel64 & 0xFFFFFFFFU); rel32 = static_cast<uint32_t>(rel64 & 0xFFFFFFFFU);
goto EmitJmpCall_Rel; goto EmitJmpCallRel;
} }
else { else {
// Relative displacement exceeds 32-bits - relocator can only // Relative displacement exceeds 32-bits - relocator can only
@@ -4299,11 +4346,14 @@ EmitJmpCall:
_code->_trampolinesSize += 8; _code->_trampolinesSize += 8;
} }
// Emit [PREFIX] OPCODE + DISP32. // Emit [PREFIX] OPCODE [/X] DISP32.
if (opCode & X86Inst::kOpCode_MM_Mask) if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F); EMIT_BYTE(0x0F);
EMIT_BYTE(opCode); EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
EMIT_32(0); EMIT_32(0);
} }
else { else {
@@ -4323,7 +4373,7 @@ EmitJmpCall:
// Emit jmp/call with relative displacement known at assembly-time. Decide // Emit jmp/call with relative displacement known at assembly-time. Decide
// between 8-bit and 32-bit displacement encoding. Some instructions only // between 8-bit and 32-bit displacement encoding. Some instructions only
// allow either 8-bit or 32-bit encoding, others allow both encodings. // allow either 8-bit or 32-bit encoding, others allow both encodings.
EmitJmpCall_Rel: EmitJmpCallRel:
if (Utils::isInt8(static_cast<int32_t>(rel32 + inst32Size - inst8Size)) && opCode8 && !(options & X86Inst::kOptionLongForm)) { if (Utils::isInt8(static_cast<int32_t>(rel32 + inst32Size - inst8Size)) && opCode8 && !(options & X86Inst::kOptionLongForm)) {
options |= X86Inst::kOptionShortForm; options |= X86Inst::kOptionShortForm;
EMIT_BYTE(opCode8); EMIT_BYTE(opCode8);
@@ -4335,8 +4385,13 @@ EmitJmpCall_Rel:
goto InvalidDisplacement; goto InvalidDisplacement;
options &= ~X86Inst::kOptionShortForm; options &= ~X86Inst::kOptionShortForm;
if (opCode & X86Inst::kOpCode_MM_Mask) EMIT_BYTE(0x0F); if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F);
EMIT_BYTE(opCode); EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
EMIT_32(rel32); EMIT_32(rel32);
goto EmitDone; goto EmitDone;
} }
@@ -4417,6 +4472,7 @@ EmitDone:
#endif // !ASMJIT_DISABLE_LOGGING #endif // !ASMJIT_DISABLE_LOGGING
resetOptions(); resetOptions();
resetExtraOp();
resetInlineComment(); resetInlineComment();
_bufferPtr = cursor; _bufferPtr = cursor;
@@ -4436,6 +4492,8 @@ ERROR_HANDLER(InvalidArgument)
ERROR_HANDLER(InvalidLabel) ERROR_HANDLER(InvalidLabel)
ERROR_HANDLER(InvalidInstruction) ERROR_HANDLER(InvalidInstruction)
ERROR_HANDLER(InvalidLockPrefix) ERROR_HANDLER(InvalidLockPrefix)
ERROR_HANDLER(InvalidXAcquirePrefix)
ERROR_HANDLER(InvalidXReleasePrefix)
ERROR_HANDLER(InvalidRepPrefix) ERROR_HANDLER(InvalidRepPrefix)
ERROR_HANDLER(InvalidRexPrefix) ERROR_HANDLER(InvalidRexPrefix)
ERROR_HANDLER(InvalidBroadcast) ERROR_HANDLER(InvalidBroadcast)

View File

@@ -79,6 +79,8 @@ public:
// [Code-Generation] // [Code-Generation]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
using CodeEmitter::_emit;
ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; ASMJIT_API Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override;
ASMJIT_API Error align(uint32_t mode, uint32_t alignment) override; ASMJIT_API Error align(uint32_t mode, uint32_t alignment) override;
}; };

View File

@@ -107,20 +107,13 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
static_cast<uint32_t>(!o3.isNone()) ; static_cast<uint32_t>(!o3.isNone()) ;
// Handle failure and rare cases first. // Handle failure and rare cases first.
const uint32_t kErrorsAndSpecialCases = const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter is in error state.
kOptionMaybeFailureCase | // CodeEmitter in error state. kOptionStrictValidation ; // Strict validation.
kOptionStrictValidation | // Strict validation.
kOptionOp4 | // Has 5th operand (o4, indexed from zero).
kOptionOp5 ; // Has 6th operand (o5, indexed from zero).
if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) { if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
// Don't do anything if we are in error state. // Don't do anything if we are in error state.
if (_lastError) return _lastError; if (_lastError) return _lastError;
// Count 5th and 6th operands.
if (options & kOptionOp4) opCount = 5;
if (options & kOptionOp5) opCount = 6;
#if !defined(ASMJIT_DISABLE_VALIDATION) #if !defined(ASMJIT_DISABLE_VALIDATION)
// Strict validation. // Strict validation.
if (options & kOptionStrictValidation) { if (options & kOptionStrictValidation) {
@@ -128,18 +121,16 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
Operand(o0), Operand(o0),
Operand(o1), Operand(o1),
Operand(o2), Operand(o2),
Operand(o3), Operand(o3)
Operand(_op4),
Operand(_op5)
}; };
Error err = X86Inst::validate(getArchType(), instId, options, _opExtra, opArray, opCount); Error err = X86Inst::validate(getArchType(), instId, options, _extraOp, opArray, opCount);
if (err) { if (err) {
#if !defined(ASMJIT_DISABLE_LOGGING) #if !defined(ASMJIT_DISABLE_LOGGING)
StringBuilderTmp<256> sb; StringBuilderTmp<256> sb;
sb.appendString(DebugUtils::errorAsString(err)); sb.appendString(DebugUtils::errorAsString(err));
sb.appendString(": "); sb.appendString(": ");
Logging::formatInstruction(sb, 0, this, getArchType(), instId, options, _opExtra, opArray, opCount); Logging::formatInstruction(sb, 0, this, getArchType(), instId, options, _extraOp, opArray, opCount);
return setLastError(err, sb.getData()); return setLastError(err, sb.getData());
#else #else
return setLastError(err); return setLastError(err);
@@ -167,12 +158,10 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
if (opCount > 1) opArray[1].copyFrom(o1); if (opCount > 1) opArray[1].copyFrom(o1);
if (opCount > 2) opArray[2].copyFrom(o2); if (opCount > 2) opArray[2].copyFrom(o2);
if (opCount > 3) opArray[3].copyFrom(o3); if (opCount > 3) opArray[3].copyFrom(o3);
if (opCount > 4) opArray[4].copyFrom(_op4);
if (opCount > 5) opArray[5].copyFrom(_op5);
new(node) CBJump(this, instId, options, opArray, opCount);
if (options & CodeEmitter::kOptionOpExtra) new(node) CBJump(this, instId, options, opArray, opCount);
node->_opExtra = _opExtra; node->_extraOp = _extraOp;
_extraOp.reset();
CBLabel* jTarget = nullptr; CBLabel* jTarget = nullptr;
if (!(options & kOptionUnfollow)) { if (!(options & kOptionUnfollow)) {
@@ -221,12 +210,148 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
if (opCount > 1) opArray[1].copyFrom(o1); if (opCount > 1) opArray[1].copyFrom(o1);
if (opCount > 2) opArray[2].copyFrom(o2); if (opCount > 2) opArray[2].copyFrom(o2);
if (opCount > 3) opArray[3].copyFrom(o3); if (opCount > 3) opArray[3].copyFrom(o3);
if (opCount > 4) opArray[4].copyFrom(_op4);
if (opCount > 5) opArray[5].copyFrom(_op5);
node = new(node) CBInst(this, instId, options, opArray, opCount);
if (options & CodeEmitter::kOptionOpExtra) node = new(node) CBInst(this, instId, options, opArray, opCount);
node->_opExtra = _opExtra; node->_extraOp = _extraOp;
_extraOp.reset();
if (inlineComment) {
inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
node->setInlineComment(inlineComment);
}
addNode(node);
return kErrorOk;
}
}
Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) {
uint32_t options = getOptions() | getGlobalOptions();
const char* inlineComment = getInlineComment();
uint32_t opCount = static_cast<uint32_t>(!o0.isNone()) +
static_cast<uint32_t>(!o1.isNone()) +
static_cast<uint32_t>(!o2.isNone()) +
static_cast<uint32_t>(!o3.isNone()) ;
// Count 5th and 6th operands.
if (!o4.isNone()) opCount = 5;
if (!o5.isNone()) opCount = 6;
// Handle failure and rare cases first.
const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter in error state.
kOptionStrictValidation ; // Strict validation.
if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
// Don't do anything if we are in error state.
if (_lastError) return _lastError;
#if !defined(ASMJIT_DISABLE_VALIDATION)
// Strict validation.
if (options & kOptionStrictValidation) {
Operand opArray[] = {
Operand(o0),
Operand(o1),
Operand(o2),
Operand(o3),
Operand(o4),
Operand(o5)
};
Error err = X86Inst::validate(getArchType(), instId, options, _extraOp, opArray, opCount);
if (err) {
#if !defined(ASMJIT_DISABLE_LOGGING)
StringBuilderTmp<256> sb;
sb.appendString(DebugUtils::errorAsString(err));
sb.appendString(": ");
Logging::formatInstruction(sb, 0, this, getArchType(), instId, options, _extraOp, opArray, opCount);
return setLastError(err, sb.getData());
#else
return setLastError(err);
#endif
}
// Clear it as it must be enabled explicitly on assembler side.
options &= ~kOptionStrictValidation;
}
#endif // ASMJIT_DISABLE_VALIDATION
}
resetOptions();
resetInlineComment();
// decide between `CBInst` and `CBJump`.
if (isJumpInst(instId)) {
CBJump* node = _cbHeap.allocT<CBJump>(sizeof(CBJump) + opCount * sizeof(Operand));
Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBJump));
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
if (opCount > 0) opArray[0].copyFrom(o0);
if (opCount > 1) opArray[1].copyFrom(o1);
if (opCount > 2) opArray[2].copyFrom(o2);
if (opCount > 3) opArray[3].copyFrom(o3);
if (opCount > 4) opArray[4].copyFrom(o4);
if (opCount > 5) opArray[5].copyFrom(o5);
new(node) CBJump(this, instId, options, opArray, opCount);
node->_extraOp = _extraOp;
_extraOp.reset();
CBLabel* jTarget = nullptr;
if (!(options & kOptionUnfollow)) {
if (opArray[0].isLabel()) {
Error err = getCBLabel(&jTarget, static_cast<Label&>(opArray[0]));
if (err) return setLastError(err);
}
else {
options |= kOptionUnfollow;
}
}
node->setOptions(options);
node->orFlags(instId == X86Inst::kIdJmp ? CBNode::kFlagIsJmp | CBNode::kFlagIsTaken : CBNode::kFlagIsJcc);
node->_target = jTarget;
node->_jumpNext = nullptr;
if (jTarget) {
node->_jumpNext = static_cast<CBJump*>(jTarget->_from);
jTarget->_from = node;
jTarget->addNumRefs();
}
// The 'jmp' is always taken, conditional jump can contain hint, we detect it.
if (instId == X86Inst::kIdJmp)
node->orFlags(CBNode::kFlagIsTaken);
else if (options & X86Inst::kOptionTaken)
node->orFlags(CBNode::kFlagIsTaken);
if (inlineComment) {
inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));
node->setInlineComment(inlineComment);
}
addNode(node);
return kErrorOk;
}
else {
CBInst* node = _cbHeap.allocT<CBInst>(sizeof(CBInst) + opCount * sizeof(Operand));
Operand* opArray = reinterpret_cast<Operand*>(reinterpret_cast<uint8_t*>(node) + sizeof(CBInst));
if (ASMJIT_UNLIKELY(!node))
return setLastError(DebugUtils::errored(kErrorNoHeapMemory));
if (opCount > 0) opArray[0].copyFrom(o0);
if (opCount > 1) opArray[1].copyFrom(o1);
if (opCount > 2) opArray[2].copyFrom(o2);
if (opCount > 3) opArray[3].copyFrom(o3);
if (opCount > 4) opArray[4].copyFrom(o4);
if (opCount > 5) opArray[5].copyFrom(o5);
node = new(node) CBInst(this, instId, options, opArray, opCount);
node->_extraOp = _extraOp;
_extraOp.reset();
if (inlineComment) { if (inlineComment) {
inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true)); inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));

View File

@@ -72,6 +72,7 @@ public:
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
ASMJIT_API virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override; ASMJIT_API virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) override;
ASMJIT_API virtual Error _emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3, const Operand_& o4, const Operand_& o5) override;
// ------------------------------------------------------------------------- // -------------------------------------------------------------------------
// [Finalize] // [Finalize]

View File

@@ -362,13 +362,13 @@ public:
//! Use REP/REPZ prefix. //! Use REP/REPZ prefix.
ASMJIT_INLINE This& rep(const X86Gp& zcx) noexcept { ASMJIT_INLINE This& rep(const X86Gp& zcx) noexcept {
static_cast<This*>(this)->_opExtra = zcx; static_cast<This*>(this)->_extraOp = zcx;
return _addOptions(X86Inst::kOptionOpExtra | X86Inst::kOptionRep); return _addOptions(X86Inst::kOptionRep);
} }
//! Use REPNZ prefix. //! Use REPNZ prefix.
ASMJIT_INLINE This& repnz(const X86Gp& zcx) noexcept { ASMJIT_INLINE This& repnz(const X86Gp& zcx) noexcept {
static_cast<This*>(this)->_opExtra = zcx; static_cast<This*>(this)->_extraOp = zcx;
return _addOptions(X86Inst::kOptionOpExtra | X86Inst::kOptionRepnz); return _addOptions(X86Inst::kOptionRepnz);
} }
//! Use REP/REPZ prefix. //! Use REP/REPZ prefix.
@@ -404,7 +404,7 @@ public:
ASMJIT_INLINE This& evex() noexcept { return _addOptions(X86Inst::kOptionEvex); } ASMJIT_INLINE This& evex() noexcept { return _addOptions(X86Inst::kOptionEvex); }
//! Use zeroing instead of merging (AVX512+). //! Use zeroing instead of merging (AVX512+).
ASMJIT_INLINE This& z() noexcept { return _addOptions(X86Inst::kOptionKZ); } ASMJIT_INLINE This& z() noexcept { return _addOptions(X86Inst::kOptionZMask); }
//! Broadcast one element to all other elements (AVX512+). //! Broadcast one element to all other elements (AVX512+).
ASMJIT_INLINE This& _1tox() noexcept { return _addOptions(X86Inst::kOption1ToX); } ASMJIT_INLINE This& _1tox() noexcept { return _addOptions(X86Inst::kOption1ToX); }
@@ -591,10 +591,14 @@ public:
ASMJIT_INST_2x(lar, Lar, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(lar, Lar, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(lar, Lar, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(lar, Lar, X86Gp, X86Mem) // ANY
ASMJIT_INST_1x(ldmxcsr, Ldmxcsr, X86Mem) // SSE ASMJIT_INST_1x(ldmxcsr, Ldmxcsr, X86Mem) // SSE
ASMJIT_INST_2x(lds, Lds, X86Gp, X86Mem) // X86
ASMJIT_INST_2x(lea, Lea, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(lea, Lea, X86Gp, X86Mem) // ANY
ASMJIT_INST_0x(leave, Leave) // ANY ASMJIT_INST_0x(leave, Leave) // ANY
ASMJIT_INST_2x(les, Les, X86Gp, X86Mem) // X86
ASMJIT_INST_0x(lfence, Lfence) // SSE2 ASMJIT_INST_0x(lfence, Lfence) // SSE2
ASMJIT_INST_2x(lfs, Lfs, X86Gp, X86Mem) // ANY
ASMJIT_INST_1x(lgdt, Lgdt, X86Mem) // ANY ASMJIT_INST_1x(lgdt, Lgdt, X86Mem) // ANY
ASMJIT_INST_2x(lgs, Lgs, X86Gp, X86Mem) // ANY
ASMJIT_INST_1x(lidt, Lidt, X86Mem) // ANY ASMJIT_INST_1x(lidt, Lidt, X86Mem) // ANY
ASMJIT_INST_1x(lldt, Lldt, X86Gp) // ANY ASMJIT_INST_1x(lldt, Lldt, X86Gp) // ANY
ASMJIT_INST_1x(lldt, Lldt, X86Mem) // ANY ASMJIT_INST_1x(lldt, Lldt, X86Mem) // ANY
@@ -612,6 +616,7 @@ public:
ASMJIT_INST_2x(loopne, Loopne, ZCX, uint64_t) // ANY [EXPLICIT] Decrement xCX; short jump if xCX != 0 && ZF == 0. ASMJIT_INST_2x(loopne, Loopne, ZCX, uint64_t) // ANY [EXPLICIT] Decrement xCX; short jump if xCX != 0 && ZF == 0.
ASMJIT_INST_2x(lsl, Lsl, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(lsl, Lsl, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(lsl, Lsl, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(lsl, Lsl, X86Gp, X86Mem) // ANY
ASMJIT_INST_2x(lss, Lss, X86Gp, X86Mem) // ANY
ASMJIT_INST_1x(ltr, Ltr, X86Gp) // ANY ASMJIT_INST_1x(ltr, Ltr, X86Gp) // ANY
ASMJIT_INST_1x(ltr, Ltr, X86Mem) // ANY ASMJIT_INST_1x(ltr, Ltr, X86Mem) // ANY
ASMJIT_INST_2x(lzcnt, Lzcnt, X86Gp, X86Gp) // LZCNT ASMJIT_INST_2x(lzcnt, Lzcnt, X86Gp, X86Gp) // LZCNT
@@ -717,6 +722,7 @@ public:
ASMJIT_INST_2i(ror, Ror, X86Mem, Imm) // ANY ASMJIT_INST_2i(ror, Ror, X86Mem, Imm) // ANY
ASMJIT_INST_3i(rorx, Rorx, X86Gp, X86Gp, Imm) // BMI2 ASMJIT_INST_3i(rorx, Rorx, X86Gp, X86Gp, Imm) // BMI2
ASMJIT_INST_3i(rorx, Rorx, X86Gp, X86Mem, Imm) // BMI2 ASMJIT_INST_3i(rorx, Rorx, X86Gp, X86Mem, Imm) // BMI2
ASMJIT_INST_0x(rsm, Rsm) // X86
ASMJIT_INST_2x(sbb, Sbb, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(sbb, Sbb, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(sbb, Sbb, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(sbb, Sbb, X86Gp, X86Mem) // ANY
ASMJIT_INST_2i(sbb, Sbb, X86Gp, Imm) // ANY ASMJIT_INST_2i(sbb, Sbb, X86Gp, Imm) // ANY
@@ -795,11 +801,16 @@ public:
ASMJIT_INST_1x(wrfsbase, Wrfsbase, X86Gp) // FSGSBASE ASMJIT_INST_1x(wrfsbase, Wrfsbase, X86Gp) // FSGSBASE
ASMJIT_INST_1x(wrgsbase, Wrgsbase, X86Gp) // FSGSBASE ASMJIT_INST_1x(wrgsbase, Wrgsbase, X86Gp) // FSGSBASE
ASMJIT_INST_3x(wrmsr, Wrmsr, EDX, EAX, ECX) // MSR [EXPLICIT] RDX:EAX -> MSR[ECX] ASMJIT_INST_3x(wrmsr, Wrmsr, EDX, EAX, ECX) // MSR [EXPLICIT] RDX:EAX -> MSR[ECX]
ASMJIT_INST_0x(xabort, Xabort) // RTM
ASMJIT_INST_2x(xadd, Xadd, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(xadd, Xadd, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(xadd, Xadd, X86Mem, X86Gp) // ANY ASMJIT_INST_2x(xadd, Xadd, X86Mem, X86Gp) // ANY
ASMJIT_INST_1x(xbegin, Xbegin, Label) // RTM
ASMJIT_INST_1x(xbegin, Xbegin, Imm) // RTM
ASMJIT_INST_1x(xbegin, Xbegin, uint64_t) // RTM
ASMJIT_INST_2x(xchg, Xchg, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(xchg, Xchg, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(xchg, Xchg, X86Mem, X86Gp) // ANY ASMJIT_INST_2x(xchg, Xchg, X86Mem, X86Gp) // ANY
ASMJIT_INST_2x(xchg, Xchg, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(xchg, Xchg, X86Gp, X86Mem) // ANY
ASMJIT_INST_0x(xend, Xend) // RTM
ASMJIT_INST_3x(xgetbv, Xgetbv, EDX, EAX, ECX) // XSAVE [EXPLICIT] EDX:EAX <- XCR[ECX] ASMJIT_INST_3x(xgetbv, Xgetbv, EDX, EAX, ECX) // XSAVE [EXPLICIT] EDX:EAX <- XCR[ECX]
ASMJIT_INST_2x(xor_, Xor, X86Gp, X86Gp) // ANY ASMJIT_INST_2x(xor_, Xor, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(xor_, Xor, X86Gp, X86Mem) // ANY ASMJIT_INST_2x(xor_, Xor, X86Gp, X86Mem) // ANY
@@ -807,6 +818,7 @@ public:
ASMJIT_INST_2x(xor_, Xor, X86Mem, X86Gp) // ANY ASMJIT_INST_2x(xor_, Xor, X86Mem, X86Gp) // ANY
ASMJIT_INST_2i(xor_, Xor, X86Mem, Imm) // ANY ASMJIT_INST_2i(xor_, Xor, X86Mem, Imm) // ANY
ASMJIT_INST_3x(xsetbv, Xsetbv, EDX, EAX, ECX) // XSAVE [EXPLICIT] XCR[ECX] <- EDX:EAX ASMJIT_INST_3x(xsetbv, Xsetbv, EDX, EAX, ECX) // XSAVE [EXPLICIT] XCR[ECX] <- EDX:EAX
ASMJIT_INST_0x(xtest, Xtest) // TSX
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [FPU Instructions] // [FPU Instructions]
@@ -4913,6 +4925,10 @@ struct X86EmitterImplicitT : public X86EmitterExplicitT<This> {
ASMJIT_INST_1x(idiv, Idiv, X86Mem) // ANY [IMPLICIT] {AH[Rem]: AL[Quot] <- AX / m8} {xDX[Rem]:xAX[Quot] <- DX:AX / m16|m32|m64} ASMJIT_INST_1x(idiv, Idiv, X86Mem) // ANY [IMPLICIT] {AH[Rem]: AL[Quot] <- AX / m8} {xDX[Rem]:xAX[Quot] <- DX:AX / m16|m32|m64}
ASMJIT_INST_1x(imul, Imul, X86Gp) // ANY [IMPLICIT] {AX <- AL * r8} {xAX:xDX <- xAX * r16|r32|r64} ASMJIT_INST_1x(imul, Imul, X86Gp) // ANY [IMPLICIT] {AX <- AL * r8} {xAX:xDX <- xAX * r16|r32|r64}
ASMJIT_INST_1x(imul, Imul, X86Mem) // ANY [IMPLICIT] {AX <- AL * m8} {xAX:xDX <- xAX * m16|m32|m64} ASMJIT_INST_1x(imul, Imul, X86Mem) // ANY [IMPLICIT] {AX <- AL * m8} {xAX:xDX <- xAX * m16|m32|m64}
ASMJIT_INST_0x(iret, Iret) // ANY [IMPLICIT]
ASMJIT_INST_0x(iretd, Iretd) // ANY [IMPLICIT]
ASMJIT_INST_0x(iretq, Iretq) // X64 [IMPLICIT]
ASMJIT_INST_0x(iretw, Iretw) // ANY [IMPLICIT]
ASMJIT_INST_1x(jecxz, Jecxz, Label) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero. ASMJIT_INST_1x(jecxz, Jecxz, Label) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero.
ASMJIT_INST_1x(jecxz, Jecxz, Imm) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero. ASMJIT_INST_1x(jecxz, Jecxz, Imm) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero.
ASMJIT_INST_1x(jecxz, Jecxz, uint64_t) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero. ASMJIT_INST_1x(jecxz, Jecxz, uint64_t) // ANY [IMPLICIT] Short jump if CX/ECX/RCX is zero.
@@ -4945,6 +4961,7 @@ struct X86EmitterImplicitT : public X86EmitterExplicitT<This> {
ASMJIT_INST_0x(sysret64, Sysret64) // X64 [IMPLICIT] ASMJIT_INST_0x(sysret64, Sysret64) // X64 [IMPLICIT]
ASMJIT_INST_0x(wrmsr, Wrmsr) // ANY [IMPLICIT] ASMJIT_INST_0x(wrmsr, Wrmsr) // ANY [IMPLICIT]
ASMJIT_INST_0x(xgetbv, Xgetbv) // XSAVE [IMPLICIT] EDX:EAX <- XCR[ECX] ASMJIT_INST_0x(xgetbv, Xgetbv) // XSAVE [IMPLICIT] EDX:EAX <- XCR[ECX]
ASMJIT_INST_0x(xlatb, Xlatb) // ANY [IMPLICIT]
ASMJIT_INST_1x(xrstor, Xrstor, X86Mem) // XSAVE [IMPLICIT] ASMJIT_INST_1x(xrstor, Xrstor, X86Mem) // XSAVE [IMPLICIT]
ASMJIT_INST_1x(xrstor64, Xrstor64, X86Mem) // XSAVE+X64 [IMPLICIT] ASMJIT_INST_1x(xrstor64, Xrstor64, X86Mem) // XSAVE+X64 [IMPLICIT]
ASMJIT_INST_1x(xrstors, Xrstors, X86Mem) // XSAVE [IMPLICIT] ASMJIT_INST_1x(xrstors, Xrstors, X86Mem) // XSAVE [IMPLICIT]

File diff suppressed because it is too large Load Diff

View File

@@ -305,6 +305,10 @@ struct X86Inst {
kIdInvd, // [ANY] {I486} kIdInvd, // [ANY] {I486}
kIdInvlpg, // [ANY] {I486} kIdInvlpg, // [ANY] {I486}
kIdInvpcid, // [ANY] {I486} kIdInvpcid, // [ANY] {I486}
kIdIret, // [ANY]
kIdIretd, // [ANY]
kIdIretq, // [X64]
kIdIretw, // [ANY]
kIdJa, // [ANY] kIdJa, // [ANY]
kIdJae, // [ANY] kIdJae, // [ANY]
kIdJb, // [ANY] kIdJb, // [ANY]
@@ -392,10 +396,14 @@ struct X86Inst {
kIdLar, // [ANY] kIdLar, // [ANY]
kIdLddqu, // [ANY] {SSE3} kIdLddqu, // [ANY] {SSE3}
kIdLdmxcsr, // [ANY] {SSE} kIdLdmxcsr, // [ANY] {SSE}
kIdLds, // [X86]
kIdLea, // [ANY] kIdLea, // [ANY]
kIdLeave, // [ANY] kIdLeave, // [ANY]
kIdLes, // [X86]
kIdLfence, // [ANY] {SSE2} kIdLfence, // [ANY] {SSE2}
kIdLfs, // [ANY]
kIdLgdt, // [ANY] kIdLgdt, // [ANY]
kIdLgs, // [ANY]
kIdLidt, // [ANY] kIdLidt, // [ANY]
kIdLldt, // [ANY] kIdLldt, // [ANY]
kIdLmsw, // [ANY] kIdLmsw, // [ANY]
@@ -404,6 +412,7 @@ struct X86Inst {
kIdLoope, // [ANY] kIdLoope, // [ANY]
kIdLoopne, // [ANY] kIdLoopne, // [ANY]
kIdLsl, // [ANY] kIdLsl, // [ANY]
kIdLss, // [ANY]
kIdLtr, // [ANY] kIdLtr, // [ANY]
kIdLzcnt, // [ANY] {LZCNT} kIdLzcnt, // [ANY] {LZCNT}
kIdMaskmovdqu, // [ANY] {SSE2} kIdMaskmovdqu, // [ANY] {SSE2}
@@ -663,6 +672,7 @@ struct X86Inst {
kIdRoundps, // [ANY] {SSE4_1} kIdRoundps, // [ANY] {SSE4_1}
kIdRoundsd, // [ANY] {SSE4_1} kIdRoundsd, // [ANY] {SSE4_1}
kIdRoundss, // [ANY] {SSE4_1} kIdRoundss, // [ANY] {SSE4_1}
kIdRsm, // [X86]
kIdRsqrtps, // [ANY] {SSE} kIdRsqrtps, // [ANY] {SSE}
kIdRsqrtss, // [ANY] {SSE} kIdRsqrtss, // [ANY] {SSE}
kIdSahf, // [ANY] {LAHFSAHF} kIdSahf, // [ANY] {LAHFSAHF}
@@ -1436,9 +1446,13 @@ struct X86Inst {
kIdWrfsbase, // [X64] {FSGSBASE} kIdWrfsbase, // [X64] {FSGSBASE}
kIdWrgsbase, // [X64] {FSGSBASE} kIdWrgsbase, // [X64] {FSGSBASE}
kIdWrmsr, // [ANY] {MSR} kIdWrmsr, // [ANY] {MSR}
kIdXabort, // [ANY] {RTM}
kIdXadd, // [ANY] {I486} kIdXadd, // [ANY] {I486}
kIdXbegin, // [ANY] {RTM}
kIdXchg, // [ANY] kIdXchg, // [ANY]
kIdXend, // [ANY] {RTM}
kIdXgetbv, // [ANY] {XSAVE} kIdXgetbv, // [ANY] {XSAVE}
kIdXlatb, // [ANY]
kIdXor, // [ANY] kIdXor, // [ANY]
kIdXorpd, // [ANY] {SSE2} kIdXorpd, // [ANY] {SSE2}
kIdXorps, // [ANY] {SSE} kIdXorps, // [ANY] {SSE}
@@ -1455,6 +1469,7 @@ struct X86Inst {
kIdXsaves, // [ANY] {XSAVE} kIdXsaves, // [ANY] {XSAVE}
kIdXsaves64, // [X64] {XSAVE} kIdXsaves64, // [X64] {XSAVE}
kIdXsetbv, // [ANY] {XSAVE} kIdXsetbv, // [ANY] {XSAVE}
kIdXtest, // [ANY] {TSX}
_kIdCount _kIdCount
// ${idData:End} // ${idData:End}
}; };
@@ -1464,6 +1479,7 @@ struct X86Inst {
kEncodingNone = 0, //!< Never used. kEncodingNone = 0, //!< Never used.
kEncodingX86Op, //!< X86 [OP]. kEncodingX86Op, //!< X86 [OP].
kEncodingX86Op_O, //!< X86 [OP] (opcode and /0-7). kEncodingX86Op_O, //!< X86 [OP] (opcode and /0-7).
kEncodingX86Op_O_I8, //!< X86 [OP] (opcode and /0-7 + 8-bit immediate).
kEncodingX86Op_xAX, //!< X86 [OP] (implicit or explicit '?AX' form). kEncodingX86Op_xAX, //!< X86 [OP] (implicit or explicit '?AX' form).
kEncodingX86Op_xDX_xAX, //!< X86 [OP] (implicit or explicit '?DX, ?AX' form). kEncodingX86Op_xDX_xAX, //!< X86 [OP] (implicit or explicit '?DX, ?AX' form).
kEncodingX86Op_ZAX, //!< X86 [OP] (implicit or explicit '[EAX|RDX]' form). kEncodingX86Op_ZAX, //!< X86 [OP] (implicit or explicit '[EAX|RDX]' form).
@@ -1492,6 +1508,7 @@ struct X86Inst {
kEncodingX86Jcc, //!< X86 jcc. kEncodingX86Jcc, //!< X86 jcc.
kEncodingX86JecxzLoop, //!< X86 jcxz, jecxz, jrcxz, loop, loope, loopne. kEncodingX86JecxzLoop, //!< X86 jcxz, jecxz, jrcxz, loop, loope, loopne.
kEncodingX86Jmp, //!< X86 jmp. kEncodingX86Jmp, //!< X86 jmp.
kEncodingX86JmpRel, //!< X86 xbegin.
kEncodingX86Lea, //!< X86 lea. kEncodingX86Lea, //!< X86 lea.
kEncodingX86Mov, //!< X86 mov (all possible cases). kEncodingX86Mov, //!< X86 mov (all possible cases).
kEncodingX86MovsxMovzx, //!< X86 movsx, movzx. kEncodingX86MovsxMovzx, //!< X86 movsx, movzx.
@@ -1881,9 +1898,11 @@ struct X86Inst {
// //
// These describe optional X86 prefixes that can be used to change the instruction's operation. // These describe optional X86 prefixes that can be used to change the instruction's operation.
kFlagRep = 0x00004000U, //!< Instruction can be prefixed by using the REP/REPZ/REPE prefix. kFlagRep = 0x00001000U, //!< Instruction can be prefixed by using the REP/REPZ/REPE prefix.
kFlagRepnz = 0x00008000U, //!< Instruction can be prefixed by using the REPNZ/REPNE prefix. kFlagRepnz = 0x00002000U, //!< Instruction can be prefixed by using the REPNZ/REPNE prefix.
kFlagLock = 0x00010000U, //!< Instruction can be prefixed by using the LOCK prefix. kFlagLock = 0x00004000U, //!< Instruction can be prefixed by using the LOCK prefix.
kFlagXAcquire = 0x00008000U, //!< Instruction can be prefixed by using the XACQUIRE prefix.
kFlagXRelease = 0x00010000U, //!< Instruction can be prefixed by using the XRELEASE prefix.
kFlagMib = 0x00020000U, //!< Instruction uses MIB (BNDLDX|BNDSTX) to encode two registers. kFlagMib = 0x00020000U, //!< Instruction uses MIB (BNDLDX|BNDSTX) to encode two registers.
kFlagVsib = 0x00040000U, //!< Instruction uses VSIB instead of legacy SIB. kFlagVsib = 0x00040000U, //!< Instruction uses VSIB instead of legacy SIB.
kFlagVex = 0x00080000U, //!< Instruction can be encoded by VEX|XOP (AVX|AVX2|BMI|XOP|...). kFlagVex = 0x00080000U, //!< Instruction can be encoded by VEX|XOP (AVX|AVX2|BMI|XOP|...).
@@ -1955,14 +1974,14 @@ struct X86Inst {
//! Instruction options (AsmJit specific). //! Instruction options (AsmJit specific).
ASMJIT_ENUM(Options) { ASMJIT_ENUM(Options) {
// NOTE: Don't collide with reserved bits used by CodeEmitter (0x000000FF). // NOTE: Don't collide with reserved bits used by CodeEmitter (0x0000003F).
kOptionOp4Op5Used = CodeEmitter::kOptionOp4Op5Used,
kOptionOp4 = CodeEmitter::kOptionOp4, kOptionShortForm = 0x00000040U, //!< Emit short-form of the instruction.
kOptionOp5 = CodeEmitter::kOptionOp5, kOptionLongForm = 0x00000080U, //!< Emit long-form of the instruction.
kOptionOpExtra = CodeEmitter::kOptionOpExtra,
kOptionShortForm = 0x00000100U, //!< Emit short-form of the instruction. kOptionTaken = 0x00000100U, //!< Conditional jump is likely to be taken.
kOptionLongForm = 0x00000200U, //!< Emit long-form of the instruction. kOptionNotTaken = 0x00000200U, //!< Conditional jump is unlikely to be taken.
kOptionVex3 = 0x00000400U, //!< Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400). kOptionVex3 = 0x00000400U, //!< Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400).
kOptionModMR = 0x00000800U, //!< Use ModMR instead of ModRM when it's available. kOptionModMR = 0x00000800U, //!< Use ModMR instead of ModRM when it's available.
@@ -1972,18 +1991,18 @@ struct X86Inst {
kOptionRep = 0x00004000U, //!< REP/REPZ prefix (string instructions only). kOptionRep = 0x00004000U, //!< REP/REPZ prefix (string instructions only).
kOptionRepnz = 0x00008000U, //!< REPNZ prefix (string instructions only). kOptionRepnz = 0x00008000U, //!< REPNZ prefix (string instructions only).
kOptionTaken = 0x00010000U, //!< JCC likely to be taken (historic, only takes effect on P4). kOptionXAcquire = 0x00010000U, //!< XACQUIRE prefix (only allowed instructions).
kOptionNotTaken = 0x00020000U, //!< JCC unlikely to be taken (historic, only takes effect on P4). kOptionXRelease = 0x00020000U, //!< XRELEASE prefix (only allowed instructions).
kOptionSAE = 0x00040000U, //!< AVX-512: 'suppress-all-exceptions' {sae}. kOptionER = 0x00040000U, //!< AVX-512: 'embedded-rounding' {er} and {sae}.
kOptionER = 0x00080000U, //!< AVX-512: 'rounding-control' {rc} and {sae}. kOptionSAE = 0x00080000U, //!< AVX-512: 'suppress-all-exceptions' {sae}.
kOption1ToX = 0x00100000U, //!< AVX-512: broadcast the first element to all {1tox}. kOption1ToX = 0x00100000U, //!< AVX-512: broadcast the first element to all {1tox}.
kOptionRN_SAE = 0x00000000U, //!< AVX-512: round-to-nearest (even) {rn-sae} (bits 00). kOptionRN_SAE = 0x00000000U, //!< AVX-512: round-to-nearest (even) {rn-sae} (bits 00).
kOptionRD_SAE = 0x00200000U, //!< AVX-512: round-down (toward -inf) {rd-sae} (bits 01). kOptionRD_SAE = 0x00200000U, //!< AVX-512: round-down (toward -inf) {rd-sae} (bits 01).
kOptionRU_SAE = 0x00400000U, //!< AVX-512: round-up (toward +inf) {ru-sae} (bits 10). kOptionRU_SAE = 0x00400000U, //!< AVX-512: round-up (toward +inf) {ru-sae} (bits 10).
kOptionRZ_SAE = 0x00600000U, //!< AVX-512: round-toward-zero (truncate) {rz-sae} (bits 11). kOptionRZ_SAE = 0x00600000U, //!< AVX-512: round-toward-zero (truncate) {rz-sae} (bits 11).
kOptionKZ = 0x00800000U, //!< AVX-512: Use zeroing {k}{z} instead of merging {k}. kOptionZMask = 0x00800000U, //!< AVX-512: Use zeroing {k}{z} instead of merging {k}.
_kOptionInvalidRex = 0x01000000U, //!< REX prefix can't be emitted (internal). _kOptionInvalidRex = 0x01000000U, //!< REX prefix can't be emitted (internal).
kOptionOpCodeB = 0x02000000U, //!< REX.B and/or VEX.B field (X64). kOptionOpCodeB = 0x02000000U, //!< REX.B and/or VEX.B field (X64).
@@ -2058,12 +2077,13 @@ struct X86Inst {
kMemOpM8 = 0x0001U, //!< Operand can be an 8-bit memory pointer. kMemOpM8 = 0x0001U, //!< Operand can be an 8-bit memory pointer.
kMemOpM16 = 0x0002U, //!< Operand can be a 16-bit memory pointer. kMemOpM16 = 0x0002U, //!< Operand can be a 16-bit memory pointer.
kMemOpM32 = 0x0004U, //!< Operand can be a 32-bit memory pointer. kMemOpM32 = 0x0004U, //!< Operand can be a 32-bit memory pointer.
kMemOpM64 = 0x0008U, //!< Operand can be a 64-bit memory pointer. kMemOpM48 = 0x0008U, //!< Operand can be a 32-bit memory pointer.
kMemOpM80 = 0x0010U, //!< Operand can be an 80-bit memory pointer. kMemOpM64 = 0x0010U, //!< Operand can be a 64-bit memory pointer.
kMemOpM128 = 0x0020U, //!< Operand can be a 128-bit memory pointer. kMemOpM80 = 0x0020U, //!< Operand can be an 80-bit memory pointer.
kMemOpM256 = 0x0040U, //!< Operand can be a 256-bit memory pointer. kMemOpM128 = 0x0040U, //!< Operand can be a 128-bit memory pointer.
kMemOpM512 = 0x0080U, //!< Operand can be a 512-bit memory pointer. kMemOpM256 = 0x0080U, //!< Operand can be a 256-bit memory pointer.
kMemOpM1024 = 0x0100U, //!< Operand can be a 1024-bit memory pointer. kMemOpM512 = 0x0100U, //!< Operand can be a 512-bit memory pointer.
kMemOpM1024 = 0x0200U, //!< Operand can be a 1024-bit memory pointer.
kMemOpVm32x = 0x0001U, //!< Operand can be a vm32x (vector) pointer. kMemOpVm32x = 0x0001U, //!< Operand can be a vm32x (vector) pointer.
kMemOpVm32y = 0x0002U, //!< Operand can be a vm32y (vector) pointer. kMemOpVm32y = 0x0002U, //!< Operand can be a vm32y (vector) pointer.
@@ -2072,9 +2092,9 @@ struct X86Inst {
kMemOpVm64y = 0x0020U, //!< Operand can be a vm64y (vector) pointer. kMemOpVm64y = 0x0020U, //!< Operand can be a vm64y (vector) pointer.
kMemOpVm64z = 0x0040U, //!< Operand can be a vm64z (vector) pointer. kMemOpVm64z = 0x0040U, //!< Operand can be a vm64z (vector) pointer.
kMemOpBaseOnly = 0x0200U, //!< Only memory base is allowed (no index, no offset). kMemOpBaseOnly = 0x0800U, //!< Only memory base is allowed (no index, no offset).
kMemOpDs = 0x0400U, //!< Implicit memory operand's DS segment. kMemOpDs = 0x1000U, //!< Implicit memory operand's DS segment.
kMemOpEs = 0x0800U, //!< Implicit memory operand's ES segment. kMemOpEs = 0x2000U, //!< Implicit memory operand's ES segment.
kMemOpMib = 0x4000U, //!< Operand must be MIB (base+index) pointer. kMemOpMib = 0x4000U, //!< Operand must be MIB (base+index) pointer.
kMemOpAny = 0x8000U //!< Operand can be any scalar memory pointer. kMemOpAny = 0x8000U //!< Operand can be any scalar memory pointer.
@@ -2429,7 +2449,7 @@ struct X86Inst {
#if !defined(ASMJIT_DISABLE_VALIDATION) #if !defined(ASMJIT_DISABLE_VALIDATION)
ASMJIT_API static Error validate( ASMJIT_API static Error validate(
uint32_t archType, uint32_t instId, uint32_t options, uint32_t archType, uint32_t instId, uint32_t options,
const Operand_& opExtra, const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept; const Operand_* opArray, uint32_t opCount) noexcept;
#endif // !ASMJIT_DISABLE_VALIDATION #endif // !ASMJIT_DISABLE_VALIDATION

View File

@@ -120,6 +120,7 @@ static const char* x86GetAddressSizeString(uint32_t size) noexcept {
case 1 : return "byte "; case 1 : return "byte ";
case 2 : return "word "; case 2 : return "word ";
case 4 : return "dword "; case 4 : return "dword ";
case 6 : return "fword ";
case 8 : return "qword "; case 8 : return "qword ";
case 10: return "tword "; case 10: return "tword ";
case 16: return "oword "; case 16: return "oword ";
@@ -581,7 +582,7 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
uint32_t archType, uint32_t archType,
uint32_t instId, uint32_t instId,
uint32_t options, uint32_t options,
const Operand_& opExtra, const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept { const Operand_* opArray, uint32_t opCount) noexcept {
// Format instruction options and instruction mnemonic. // Format instruction options and instruction mnemonic.
@@ -592,7 +593,9 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
if (options & X86Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short ")); if (options & X86Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short "));
if (options & X86Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long ")); if (options & X86Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long "));
// LOCK option. // LOCK/XACQUIRE/XRELEASE option.
if (options & X86Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.appendString("xacquire "));
if (options & X86Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.appendString("xrelease "));
if (options & X86Inst::kOptionLock) ASMJIT_PROPAGATE(sb.appendString("lock ")); if (options & X86Inst::kOptionLock) ASMJIT_PROPAGATE(sb.appendString("lock "));
// REP options. // REP options.
@@ -602,9 +605,9 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
rep = instInfo.hasFlag(X86Inst::kFlagRepnz) ? "repz " : "rep "; rep = instInfo.hasFlag(X86Inst::kFlagRepnz) ? "repz " : "rep ";
sb.appendString(rep); sb.appendString(rep);
if (!opExtra.isNone()) { if (!extraOp.isNone()) {
ASMJIT_PROPAGATE(sb.appendChar('{')); ASMJIT_PROPAGATE(sb.appendChar('{'));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, opExtra)); ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, extraOp));
ASMJIT_PROPAGATE(sb.appendString("} ")); ASMJIT_PROPAGATE(sb.appendString("} "));
} }
} }
@@ -655,19 +658,15 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
// Support AVX-512 {k}{z}. // Support AVX-512 {k}{z}.
if (i == 0) { if (i == 0) {
const uint32_t kExtMsk = X86Inst::kOptionOpExtra | if (X86Reg::isK(extraOp)) {
X86Inst::kOptionRep |
X86Inst::kOptionRepnz ;
if ((options & kExtMsk) == X86Inst::kOptionOpExtra) {
ASMJIT_PROPAGATE(sb.appendString(" {")); ASMJIT_PROPAGATE(sb.appendString(" {"));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, opExtra)); ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, extraOp));
ASMJIT_PROPAGATE(sb.appendChar('}')); ASMJIT_PROPAGATE(sb.appendChar('}'));
if (options & X86Inst::kOptionKZ) if (options & X86Inst::kOptionZMask)
ASMJIT_PROPAGATE(sb.appendString("{z}")); ASMJIT_PROPAGATE(sb.appendString("{z}"));
} }
else if (options & X86Inst::kOptionKZ) { else if (options & X86Inst::kOptionZMask) {
ASMJIT_PROPAGATE(sb.appendString(" {z}")); ASMJIT_PROPAGATE(sb.appendString(" {z}"));
} }
} }

View File

@@ -50,7 +50,7 @@ struct X86Logging {
uint32_t archType, uint32_t archType,
uint32_t instId, uint32_t instId,
uint32_t options, uint32_t options,
const Operand_& opExtra, const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept; const Operand_* opArray, uint32_t opCount) noexcept;
}; };

View File

@@ -1723,9 +1723,9 @@ _NextGroup:
_avxEnabled = true; _avxEnabled = true;
} }
const Operand_& opExtra = node->getOpExtra(); const Operand_& extraOp = node->getExtraOp();
if ((options & CodeEmitter::kOptionOpExtra) != 0 && opExtra.isReg()) { if (extraOp.isReg()) {
uint32_t id = opExtra.as<Reg>().getId(); uint32_t id = extraOp.as<Reg>().getId();
if (cc()->isVirtRegValid(id)) { if (cc()->isVirtRegValid(id)) {
VirtReg* vreg = cc()->getVirtRegById(id); VirtReg* vreg = cc()->getVirtRegById(id);
TiedReg* tied; TiedReg* tied;
@@ -2119,7 +2119,7 @@ Error X86RAPass::annotate() {
cc()->getArchType(), cc()->getArchType(),
node->getInstId(), node->getInstId(),
node->getOptions(), node->getOptions(),
node->getOpExtra(), node->getExtraOp(),
node->getOpArray(), node->getOpCount()); node->getOpArray(), node->getOpCount());
node_->setInlineComment( node_->setInlineComment(
@@ -2423,6 +2423,8 @@ Error X86VarAlloc::run(CBNode* node_) {
// Translate node operands. // Translate node operands.
if (node_->getType() == CBNode::kNodeInst) { if (node_->getType() == CBNode::kNodeInst) {
CBInst* node = static_cast<CBInst*>(node_); CBInst* node = static_cast<CBInst*>(node_);
if (node->hasExtraOp())
ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, &node->_extraOp, 1));
ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount())); ASMJIT_PROPAGATE(X86RAPass_translateOperands(_context, node->getOpArray(), node->getOpCount()));
} }
else if (node_->getType() == CBNode::kNodePushArg) { else if (node_->getType() == CBNode::kNodePushArg) {
@@ -3622,7 +3624,7 @@ ASMJIT_INLINE void X86CallAlloc::ret() {
static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount) { static Error X86RAPass_translateOperands(X86RAPass* self, Operand_* opArray, uint32_t opCount) {
X86Compiler* cc = self->cc(); X86Compiler* cc = self->cc();
// Translate variables into isters. // Translate variables into registers.
for (uint32_t i = 0; i < opCount; i++) { for (uint32_t i = 0; i < opCount; i++) {
Operand_* op = &opArray[i]; Operand_* op = &opArray[i];
if (op->isVirtReg()) { if (op->isVirtReg()) {

View File

@@ -129,6 +129,7 @@ static void dumpCpu(void) {
{ CpuInfo::kX86FeatureMPX , "MPX" }, { CpuInfo::kX86FeatureMPX , "MPX" },
{ CpuInfo::kX86FeatureHLE , "HLE" }, { CpuInfo::kX86FeatureHLE , "HLE" },
{ CpuInfo::kX86FeatureRTM , "RTM" }, { CpuInfo::kX86FeatureRTM , "RTM" },
{ CpuInfo::kX86FeatureTSX , "TSX" },
{ CpuInfo::kX86FeatureERMS , "ERMS" }, { CpuInfo::kX86FeatureERMS , "ERMS" },
{ CpuInfo::kX86FeatureFSGSBASE , "FSGSBASE" }, { CpuInfo::kX86FeatureFSGSBASE , "FSGSBASE" },
{ CpuInfo::kX86FeatureAVX512_F , "AVX512-F" }, { CpuInfo::kX86FeatureAVX512_F , "AVX512-F" },

View File

@@ -272,12 +272,13 @@ class GenUtils {
for (i = 0; i < group.length; i++) { for (i = 0; i < group.length; i++) {
const inst = group[i]; const inst = group[i];
const name = inst.name; const name = inst.name;
const operands = inst.operands; const operands = inst.operands;
if (inst.attributes.LOCK ) f.Lock = true; if (inst.attributes.LOCK ) f.Lock = true;
if (inst.attributes.REP ) f.Rep = true; if (inst.attributes.REP ) f.Rep = true;
if (inst.attributes.REPNZ ) f.Repnz = true; if (inst.attributes.REPNZ ) f.Repnz = true;
if (inst.attributes.XACQUIRE) f.XAcquire = true;
if (inst.attributes.XRELEASE) f.XRelease = true;
if (inst.fpu) { if (inst.fpu) {
for (var j = 0; j < operands.length; j++) { for (var j = 0; j < operands.length; j++) {
@@ -458,6 +459,7 @@ class GenUtils {
case "loop": case "loop":
case "loope": case "loope":
case "loopne": case "loopne":
case "xbegin":
return "Conditional"; return "Conditional";
case "jmp" : return "Direct"; case "jmp" : return "Direct";
@@ -480,7 +482,7 @@ const RegOp = MapUtils.arrayToMap([
]); ]);
const MemOp = MapUtils.arrayToMap([ const MemOp = MapUtils.arrayToMap([
"m8", "m16", "m32", "m64", "m80", "m128", "m256", "m512", "m1024" "m8", "m16", "m32", "m48", "m64", "m80", "m128", "m256", "m512", "m1024"
]); ]);
const OpSortPriority = { const OpSortPriority = {
@@ -510,22 +512,23 @@ const OpSortPriority = {
"m8" : 32, "m8" : 32,
"m16" : 33, "m16" : 33,
"m32" : 34, "m32" : 34,
"m64" : 35, "m48" : 35,
"m80" : 36, "m64" : 36,
"m128" : 37, "m80" : 37,
"m256" : 38, "m128" : 38,
"m512" : 39, "m256" : 39,
"m1024" : 40, "m512" : 40,
"mib" : 41, "m1024" : 41,
"vm32x" : 42, "mib" : 42,
"vm32y" : 43, "vm32x" : 43,
"vm32z" : 44, "vm32y" : 44,
"vm64x" : 45, "vm32z" : 45,
"vm64y" : 46, "vm64x" : 46,
"vm64z" : 47, "vm64y" : 47,
"memBase" : 48, "vm64z" : 48,
"memES" : 49, "memBase" : 49,
"memDS" : 50, "memES" : 50,
"memDS" : 51,
"i4" : 60, "i4" : 60,
"u4" : 61, "u4" : 61,
@@ -570,6 +573,7 @@ const OpToAsmJitOp = {
"m8" : "MEM(M8)", "m8" : "MEM(M8)",
"m16" : "MEM(M16)", "m16" : "MEM(M16)",
"m32" : "MEM(M32)", "m32" : "MEM(M32)",
"m48" : "MEM(M48)",
"m64" : "MEM(M64)", "m64" : "MEM(M64)",
"m80" : "MEM(M80)", "m80" : "MEM(M80)",
"m128" : "MEM(M128)", "m128" : "MEM(M128)",
@@ -757,15 +761,16 @@ class OSignature {
case "ymm" : case "ymm" :
case "zmm" : mFlags[k] = true; break; case "zmm" : mFlags[k] = true; break;
case "m8" : mFlags.mem = true; mMemFlags.m8 = true; break; case "m8" :
case "m16" : mFlags.mem = true; mMemFlags.m16 = true; break; case "m16" :
case "m32" : mFlags.mem = true; mMemFlags.m32 = true; break; case "m32" :
case "m64" : mFlags.mem = true; mMemFlags.m64 = true; break; case "m48" :
case "m80" : mFlags.mem = true; mMemFlags.m80 = true; break; case "m64" :
case "m128" : mFlags.mem = true; mMemFlags.m128 = true; break; case "m80" :
case "m256" : mFlags.mem = true; mMemFlags.m256 = true; break; case "m128" :
case "m512" : mFlags.mem = true; mMemFlags.m512 = true; break; case "m256" :
case "m1024" : mFlags.mem = true; mMemFlags.m1024 = true; break; case "m512" :
case "m1024" : mFlags.mem = true; mMemFlags[k] = true; break;
case "mib" : mFlags.mem = true; mMemFlags.mib = true; break; case "mib" : mFlags.mem = true; mMemFlags.mib = true; break;
case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break; case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break;
@@ -800,6 +805,12 @@ class OSignature {
mFlags[k] = true; mFlags[k] = true;
break; break;
case "rel16" :
mFlags.i32 = true;
mFlags.i64 = true;
mFlags.rel32 = true;
break;
default: { default: {
switch (k) { switch (k) {
case "es" : mFlags.sreg = true; sRegMask |= 1 << 1; break; case "es" : mFlags.sreg = true; sRegMask |= 1 << 1; break;
@@ -1150,6 +1161,10 @@ class X86Generator extends base.BaseGenerator {
if (mem === "m32int") mem = "m32"; if (mem === "m32int") mem = "m32";
if (mem === "m64int") mem = "m64"; if (mem === "m64int") mem = "m64";
if (mem === "m16_16") mem = "m32";
if (mem === "m16_32") mem = "m48";
if (mem === "m16_64") mem = "m80";
const op = new OSignature(); const op = new OSignature();
if (iop.read) op.flags.read = true; if (iop.read) op.flags.read = true;
@@ -1709,6 +1724,7 @@ class X86Generator extends base.BaseGenerator {
StringUtils.padLeft(inst.opcode1 , 26) + ", " + StringUtils.padLeft(inst.opcode1 , 26) + ", " +
StringUtils.padLeft(inst.writeIndex , 2) + ", " + StringUtils.padLeft(inst.writeIndex , 2) + ", " +
StringUtils.padLeft(inst.writeSize , 2) + ", " + StringUtils.padLeft(inst.writeSize , 2) + ", " +
StringUtils.padLeft("0", 4) + ", " +
StringUtils.padLeft("0", 3) + ", " + StringUtils.padLeft("0", 3) + ", " +
StringUtils.padLeft("0", 3) + ", " + StringUtils.padLeft("0", 3) + ", " +
StringUtils.padLeft("0", 3) + "),\n"; StringUtils.padLeft("0", 3) + "),\n";
@@ -1720,7 +1736,7 @@ class X86Generator extends base.BaseGenerator {
newInstFromInsts(insts) { newInstFromInsts(insts) {
function composeOpCode(obj) { function composeOpCode(obj) {
return `${obj.type}(${obj.prefix},${obj.opcode},${obj.o},${obj.l},${obj.w},${obj.ew},${obj.en})`; return `${obj.type}(${obj.prefix},${obj.opcode},${obj.o},${obj.l},${obj.w},${obj.ew},${obj.en},${obj.tt})`;
} }
function GetAccess(inst) { function GetAccess(inst) {
@@ -1778,7 +1794,8 @@ class X86Generator extends base.BaseGenerator {
l : vexL !== undefined ? vexL : "_", l : vexL !== undefined ? vexL : "_",
w : vexW !== undefined ? vexW : "_", w : vexW !== undefined ? vexW : "_",
ew : evexW !== undefined ? vexEW : "_", ew : evexW !== undefined ? vexEW : "_",
en : "_" en : "_",
tt : "_ "
}); });
return { return {