mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-17 12:34:35 +03:00
Added new instructions + xacquire|xrelease prefixes, reorganized instruction options
This commit is contained in:
@@ -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);
|
||||||
opArray[4].copyFrom(_op4);
|
|
||||||
opArray[5].copyFrom(_op5);
|
if (options & kOptionOp4Op5Used) {
|
||||||
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
|
opArray[4].copyFrom(_op4);
|
||||||
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
|
opArray[5].copyFrom(_op5);
|
||||||
|
}
|
||||||
|
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);
|
||||||
opArray[4].copyFrom(_op4);
|
|
||||||
opArray[5].copyFrom(_op5);
|
|
||||||
|
|
||||||
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
|
if (options & kOptionOp4Op5Used) {
|
||||||
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
|
opArray[4].copyFrom(_op4);
|
||||||
|
opArray[5].copyFrom(_op5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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.
|
||||||
};
|
};
|
||||||
|
|
||||||
//! \}
|
//! \}
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// ============================================================================
|
// ============================================================================
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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,26 +4038,21 @@ 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 ;
|
|
||||||
if (options & kAvx512Options) {
|
if (options & kAvx512Options) {
|
||||||
// Memory broadcast without a memory operand is invalid.
|
// Memory broadcast without a memory operand is invalid.
|
||||||
if (ASMJIT_UNLIKELY(options & X86Inst::kOption1ToX))
|
if (ASMJIT_UNLIKELY(options & X86Inst::kOption1ToX))
|
||||||
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,25 +4147,21 @@ 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) {
|
||||||
// {er} and {sae} are both invalid if memory operand is used.
|
// {er} and {sae} are both invalid if memory operand is used.
|
||||||
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....].
|
||||||
@@ -4214,11 +4256,12 @@ EmitJmpCall:
|
|||||||
// Jcc instructions with 32-bit displacement use 0x0F prefix,
|
// Jcc instructions with 32-bit displacement use 0x0F prefix,
|
||||||
// other instructions don't. No other prefixes are used by X86.
|
// other instructions don't. No other prefixes are used by X86.
|
||||||
ASMJIT_ASSERT((opCode8 & X86Inst::kOpCode_MM_Mask) == 0);
|
ASMJIT_ASSERT((opCode8 & X86Inst::kOpCode_MM_Mask) == 0);
|
||||||
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)
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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]
|
||||||
|
|||||||
@@ -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
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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}"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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()) {
|
||||||
|
|||||||
@@ -42,23 +42,23 @@ static void dumpCpu(void) {
|
|||||||
|
|
||||||
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
|
||||||
static const DumpCpuFeature armFeaturesList[] = {
|
static const DumpCpuFeature armFeaturesList[] = {
|
||||||
{ CpuInfo::kArmFeatureV6 , "ARMv6" },
|
{ CpuInfo::kArmFeatureV6 , "ARMv6" },
|
||||||
{ CpuInfo::kArmFeatureV7 , "ARMv7" },
|
{ CpuInfo::kArmFeatureV7 , "ARMv7" },
|
||||||
{ CpuInfo::kArmFeatureV8 , "ARMv8" },
|
{ CpuInfo::kArmFeatureV8 , "ARMv8" },
|
||||||
{ CpuInfo::kArmFeatureTHUMB , "THUMB" },
|
{ CpuInfo::kArmFeatureTHUMB , "THUMB" },
|
||||||
{ CpuInfo::kArmFeatureTHUMB2 , "THUMBv2" },
|
{ CpuInfo::kArmFeatureTHUMB2 , "THUMBv2" },
|
||||||
{ CpuInfo::kArmFeatureVFP2 , "VFPv2" },
|
{ CpuInfo::kArmFeatureVFP2 , "VFPv2" },
|
||||||
{ CpuInfo::kArmFeatureVFP3 , "VFPv3" },
|
{ CpuInfo::kArmFeatureVFP3 , "VFPv3" },
|
||||||
{ CpuInfo::kArmFeatureVFP4 , "VFPv4" },
|
{ CpuInfo::kArmFeatureVFP4 , "VFPv4" },
|
||||||
{ CpuInfo::kArmFeatureVFP_D32 , "VFP D32" },
|
{ CpuInfo::kArmFeatureVFP_D32 , "VFP D32" },
|
||||||
{ CpuInfo::kArmFeatureNEON , "NEON" },
|
{ CpuInfo::kArmFeatureNEON , "NEON" },
|
||||||
{ CpuInfo::kArmFeatureDSP , "DSP" },
|
{ CpuInfo::kArmFeatureDSP , "DSP" },
|
||||||
{ CpuInfo::kArmFeatureIDIV , "IDIV" },
|
{ CpuInfo::kArmFeatureIDIV , "IDIV" },
|
||||||
{ CpuInfo::kArmFeatureAES , "AES" },
|
{ CpuInfo::kArmFeatureAES , "AES" },
|
||||||
{ CpuInfo::kArmFeatureCRC32 , "CRC32" },
|
{ CpuInfo::kArmFeatureCRC32 , "CRC32" },
|
||||||
{ CpuInfo::kArmFeatureSHA1 , "SHA1" },
|
{ CpuInfo::kArmFeatureSHA1 , "SHA1" },
|
||||||
{ CpuInfo::kArmFeatureSHA256 , "SHA256" },
|
{ CpuInfo::kArmFeatureSHA256 , "SHA256" },
|
||||||
{ CpuInfo::kArmFeatureAtomics64 , "64-bit atomics" }
|
{ CpuInfo::kArmFeatureAtomics64 , "64-bit atomics" }
|
||||||
};
|
};
|
||||||
|
|
||||||
INFO("ARM Features:");
|
INFO("ARM Features:");
|
||||||
@@ -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" },
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
Reference in New Issue
Block a user