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

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

View File

@@ -27,7 +27,9 @@ Assembler::Assembler() noexcept
_section(nullptr),
_bufferData(nullptr),
_bufferEnd(nullptr),
_bufferPtr(nullptr) {}
_bufferPtr(nullptr),
_op4(),
_op5() {}
Assembler::~Assembler() noexcept {
if (_code) sync();
@@ -45,6 +47,10 @@ Error Assembler::onAttach(CodeHolder* code) noexcept {
_bufferData = p;
_bufferEnd = p + _section->_buffer._capacity;
_bufferPtr = p + _section->_buffer._length;
_op4.reset();
_op5.reset();
return Base::onAttach(code);
}
@@ -53,9 +59,50 @@ Error Assembler::onDetach(CodeHolder* code) noexcept {
_bufferData = nullptr;
_bufferEnd = nullptr;
_bufferPtr = nullptr;
_op4.reset();
_op5.reset();
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]
// ============================================================================
@@ -333,15 +380,20 @@ void Assembler::_emitLog(
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction(
sb, logOptions,
this, getArchType(),
instId, options, _opExtra, opArray, 6);
instId, options, _extraOp, opArray, 6);
if ((logOptions & Logger::kOptionBinaryForm) != 0)
Logging::formatLine(sb, _bufferPtr, emittedSize, relSize, imLen, getInlineComment());
@@ -364,18 +416,23 @@ Error Assembler::_emitFailed(
opArray[1].copyFrom(o1);
opArray[2].copyFrom(o2);
opArray[3].copyFrom(o3);
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
if (options & kOptionOp4Op5Used) {
opArray[4].copyFrom(_op4);
opArray[5].copyFrom(_op5);
}
else {
opArray[4].reset();
opArray[5].reset();
}
Logging::formatInstruction(
sb, 0,
this, getArchType(),
instId, options, _opExtra, opArray, 6);
instId, options, _extraOp, opArray, 6);
resetOptions();
resetExtraOp();
resetInlineComment();
return setLastError(err, sb.getData());
}

View File

@@ -53,6 +53,15 @@ public:
ASMJIT_API Error onAttach(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]
// --------------------------------------------------------------------------
@@ -129,6 +138,9 @@ public:
uint8_t* _bufferData; //!< Start of the CodeBuffer 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.
Operand_ _op4; //!< 5th operand data, used only temporarily.
Operand_ _op5; //!< 6th operand data, used only temporarily.
};
//! \}

View File

@@ -542,31 +542,10 @@ Error CodeBuilder::serialize(CodeEmitter* dst) {
case CBNode::kNodeInst:
case CBNode::kNodeFuncCall: {
CBInst* node = static_cast<CBInst*>(node_);
uint32_t instId = node->getInstId();
uint32_t options = node->getOptions();
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);
CBInst* node = node_->as<CBInst>();
dst->setOptions(node->getOptions());
dst->setExtraOp(node->getExtraOp());
err = dst->emitOpArray(node->getInstId(), node->getOpArray(), node->getOpCount());
break;
}

View File

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

View File

@@ -43,9 +43,7 @@ CodeEmitter::CodeEmitter(uint32_t type) noexcept
_globalOptions(kOptionMaybeFailureCase),
_options(0),
_inlineComment(nullptr),
_op4(),
_op5(),
_opExtra(),
_extraOp(),
_none(),
_nativeGpReg(),
_nativeGpArray(nullptr) {}
@@ -82,15 +80,34 @@ Error CodeEmitter::onDetach(CodeHolder* code) noexcept {
_options = 0;
_inlineComment = nullptr;
_op4.reset();
_op5.reset();
_opExtra.reset();
_extraOp.reset();
_nativeGpReg.reset();
_nativeGpArray = nullptr;
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]
// ============================================================================
@@ -187,99 +204,49 @@ Error CodeEmitter::commentv(const char* fmt, va_list ap) {
// ============================================================================
#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, OP o0) { return _emit(instId, o0, NO, NO, NO); }
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, OP o2) { return _emit(instId, o0, o1, o2, 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, _none, _none, _none); }
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, _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, 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) {
_op4 = o4;
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, int o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
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); }
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) {
_options |= kOptionOp4;
_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, 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, int64_t o0) { return _emit(instId, Imm(o0), _none, _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, int64_t o1) { return _emit(instId, o0, Imm(o1), _none, _none); }
Error CodeEmitter::emit(uint32_t instId, OP o0, OP o1, int64_t o2) { return _emit(instId, o0, o1, Imm(o2), _none); }
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) {
_options |= kOptionOp4;
_op4 = Imm(o4);
return _emit(instId, o0, o1, o2, o3);
}
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); }
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)); }
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
// ============================================================================
// [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)
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 options = getGlobalOptions() | getOptions();
if (!(options & CodeEmitter::kOptionOp4)) opArray[4].reset();
if (!(options & CodeEmitter::kOptionOp5)) opArray[5].reset();
#if defined(ASMJIT_BUILD_X86)
if (ArchInfo::isX86Family(archType))
return X86Inst::validate(archType, instId, options, _opExtra, opArray, 6);
return X86Inst::validate(archType, instId, options, _extraOp, opArray, 6);
#endif
#if defined(ASMJIT_BUILD_ARM)
if (ArchInfo::isArmFamily(archType))
return ArmInst::validate(archType, instId, options, _opExtra, opArray, 6);
return ArmInst::validate(archType, instId, options, _extraOp, opArray, 6);
#endif
return DebugUtils::errored(kErrorInvalidArch);

View File

@@ -101,15 +101,11 @@ public:
//! NOTE: Reserved options should never appear in `CBInst` options.
kOptionReservedMask = 0x00000007U,
//! Instruction has `_op4` (5th operand, indexed from zero).
kOptionOp4 = 0x0000008U,
//! Instruction has `_op5` (6th operand, indexed from zero).
kOptionOp5 = 0x0000010U,
//! Instruction has `_opExtra` operand (mask-op {k} operand when using AVX-512).
kOptionOpExtra = 0x00000020U,
//! Used only by Assembler to mark `_op4` and `_op5` are used.
kOptionOp4Op5Used = 0x00000008U,
//! Prevents following a jump during compilation (CodeCompiler).
kOptionUnfollow = 0x00000040U,
kOptionUnfollow = 0x00000010U,
//! 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
//! HI elements, use `X86Compiler.overwrite().sqrtss(x, y)`.
kOptionOverwrite = 0x00000080U
kOptionOverwrite = 0x00000020U
};
// --------------------------------------------------------------------------
@@ -172,8 +168,12 @@ public:
// [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;
//! 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.
virtual Label newLabel() = 0;
@@ -315,20 +315,12 @@ public:
//! Reset options of the next instruction.
ASMJIT_INLINE void resetOptions() noexcept { _options = 0; }
//! Get if the 5th operand (indexed from zero) of the next instruction is used.
ASMJIT_INLINE bool hasOp4() const noexcept { return (_options & kOptionOp4) != 0; }
//! Get if the 6th operand (indexed from zero) of the next instruction is used.
ASMJIT_INLINE bool hasOp5() const noexcept { return (_options & kOptionOp5) != 0; }
//! Get if the op-mask operand of the next instruction is used.
ASMJIT_INLINE bool hasOpExtra() const noexcept { return (_options & kOptionOpExtra) != 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 an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE const Operand& getExtraOp() const noexcept { return static_cast<const Operand&>(_extraOp); }
//! Set an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void setExtraOp(const Operand_& extraOp) noexcept { _extraOp = extraOp; }
//! Reset an extra operand that will be used by the next instruction (architecture specific).
ASMJIT_INLINE void resetExtraOp() noexcept { _extraOp.setSignature(0); }
//! Get annotation of the next instruction.
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));
}
ASMJIT_INLINE Error emitOpArray(uint32_t instId, const Operand_* opArray, size_t opCount) {
return _emitOpArray(instId, opArray, opCount);
}
// --------------------------------------------------------------------------
// [Validation]
// --------------------------------------------------------------------------
//! 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]
@@ -488,10 +484,7 @@ public:
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).
Operand_ _op4; //!< 5th operand data (indexed from zero) (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_ _extraOp; //!< 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.
Reg _nativeGpReg; //!< Native GP register with zero id.
const Reg* _nativeGpArray; //!< Array of native registers indexed from zero.

View File

@@ -503,6 +503,9 @@ ASMJIT_FAVOR_SIZE static void x86DetectCpuInfo(CpuInfo* cpuInfo) noexcept {
if (regs.ebx & 0x20000000U) cpuInfo->addFeature(CpuInfo::kX86FeatureSHA);
if (regs.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.
if (cpuInfo->hasFeature(CpuInfo::kX86FeatureAVX)) {
if (regs.ebx & 0x00000020U) cpuInfo->addFeature(CpuInfo::kX86FeatureAVX2);

View File

@@ -107,7 +107,7 @@ public:
kX86FeatureSHA, //!< CPU has SHA-1 and SHA-256.
kX86FeatureXSAVE, //!< CPU has XSAVE support - XSAVE/XRSTOR, XSETBV/XGETBV, and XCR.
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.
kX86FeatureAVX2, //!< CPU has AVX2.
kX86FeatureF16C, //!< CPU has F16C.
@@ -121,6 +121,7 @@ public:
kX86FeatureMPX, //!< CPU has MPX (memory protection extensions).
kX86FeatureHLE, //!< CPU has HLE.
kX86FeatureRTM, //!< CPU has RTM.
kX86FeatureTSX, //!< CPU has TSX.
kX86FeatureERMS, //!< CPU has ERMS (enhanced REP MOVSB/STOSB).
kX86FeatureFSGSBASE, //!< CPU has FSGSBASE.
kX86FeatureAVX512_F, //!< CPU has AVX512-F (foundation).

View File

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

View File

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

View File

@@ -235,15 +235,15 @@ Error Logging::formatInstruction(
uint32_t archType,
uint32_t instId,
uint32_t options,
const Operand_& opExtra,
const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept {
#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
#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
return kErrorInvalidArch;
@@ -374,7 +374,7 @@ Error Logging::formatNode(
cb->getArchType(),
node->getInstId(),
node->getOptions(),
node->getOpExtra(),
node->getExtraOp(),
node->getOpArray(), node->getOpCount()));
break;
}
@@ -438,7 +438,7 @@ Error Logging::formatNode(
cb->getArchType(),
node->getInstId(),
node->getOptions(),
node->getOpExtra(),
node->getExtraOp(),
node->getOpArray(), node->getOpCount()));
break;
}

View File

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

View File

@@ -538,7 +538,9 @@ Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o
CodeEmitter::kOptionStrictValidation | // Strict validation.
X86Inst::kOptionRep | // REP/REPZ 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.
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.
#if !defined(ASMJIT_DISABLE_VALIDATION)
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;
}
#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 (ASMJIT_UNLIKELY(!(instFlags & X86Inst::kFlagLock)))
bool xAcqRel = (options & (X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease)) != 0;
if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagLock)) && !xAcqRel))
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);
}
// REP / REPNZ prefix.
// REP and REPNZ prefixes.
if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) {
if (ASMJIT_UNLIKELY(!(instFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz))))
if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz))))
goto InvalidRepPrefix;
if (!_opExtra.isNone() && ASMJIT_UNLIKELY(!X86Reg::isGp(_opExtra, X86Gp::kIdCx)))
if (!_extraOp.isNone() && ASMJIT_UNLIKELY(!X86Reg::isGp(_extraOp, X86Gp::kIdCx)))
goto InvalidRepPrefix;
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:
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:
rbReg = 0;
goto EmitX86R;
@@ -1011,6 +1050,7 @@ CaseX86M_GPB_MulDiv:
// displacement is not encodable so the alternative opcode field
// in X86DB must be zero.
opCode = 0xE8;
opReg = 0;
goto EmitJmpCall;
case X86Inst::kEncodingX86Cmpxchg: {
@@ -1282,6 +1322,7 @@ CaseX86M_GPB_MulDiv:
}
rmRel = &o0;
opReg = 0;
goto EmitJmpCall;
case X86Inst::kEncodingX86JecxzLoop:
@@ -1296,6 +1337,8 @@ CaseX86M_GPB_MulDiv:
rmRel = &o1;
}
opReg = 0;
goto EmitJmpCall;
case X86Inst::kEncodingX86Jmp:
@@ -1311,6 +1354,11 @@ CaseX86M_GPB_MulDiv:
// Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded
// with 8-bit displacement's opcode is stored as an alternative opcode.
opCode = 0xE9;
opReg = 0;
goto EmitJmpCall;
case X86Inst::kEncodingX86JmpRel:
rmRel = &o0;
goto EmitJmpCall;
case X86Inst::kEncodingX86Lea:
@@ -2815,6 +2863,9 @@ CaseVexRm:
break;
case X86Inst::kEncodingVexRm_T1_4X: {
if (!(options & kOptionOp4Op5Used))
goto InvalidInstruction;
if (X86Reg::isZmm(o0 ) && X86Reg::isZmm(o1) &&
X86Reg::isZmm(o2 ) && X86Reg::isZmm(o3) &&
X86Reg::isZmm(_op4) && _op5.isMem()) {
@@ -3374,7 +3425,7 @@ CaseVexRvm_R:
}
case X86Inst::kEncodingVexRvrmiRvmri_Lx: {
if (!(options & CodeEmitter::kOptionOp4) || !_op4.isImm())
if (!(options & CodeEmitter::kOptionOp4Op5Used) || !_op4.isImm())
goto InvalidInstruction;
const uint32_t isign4 = isign3 + (o3.getOp() << 9);
@@ -3987,26 +4038,21 @@ EmitVexEvexR:
// Mark invalid VEX (force EVEX) case: // [@.......|.LL.....|Vvvvv..R|RBBmmmmm].
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.
const uint32_t kAvx512Options = X86Inst::kOptionOpExtra |
X86Inst::kOptionKZ |
X86Inst::kOption1ToX |
X86Inst::kOptionSAE |
X86Inst::kOptionER ;
const uint32_t kAvx512Options = X86Inst::kOptionZMask |
X86Inst::kOption1ToX |
X86Inst::kOptionSAE |
X86Inst::kOptionER ;
if (options & kAvx512Options) {
// Memory broadcast without a memory operand is invalid.
if (ASMJIT_UNLIKELY(options & X86Inst::kOption1ToX))
goto InvalidBroadcast;
// TODO: {sae} and {er}
// 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].
x |= options & X86Inst::kOptionZMask; // [@.......|zLL..aaa|Vvvvv..R|RBBmmmmm].
}
// 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].
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.
const uint32_t kAvx512Options = X86Inst::kOptionOpExtra |
X86Inst::kOption1ToX |
X86Inst::kOptionKZ |
X86Inst::kOptionSAE |
X86Inst::kOptionER ;
const uint32_t kAvx512Options = X86Inst::kOption1ToX |
X86Inst::kOptionZMask |
X86Inst::kOptionSAE |
X86Inst::kOptionER ;
if (options & kAvx512Options) {
// {er} and {sae} are both invalid if memory operand is used.
if (ASMJIT_UNLIKELY(options & (X86Inst::kOptionSAE | X86Inst::kOptionER)))
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].
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....].
@@ -4214,11 +4256,12 @@ EmitJmpCall:
// Jcc instructions with 32-bit displacement use 0x0F prefix,
// other instructions don't. No other prefixes are used by X86.
ASMJIT_ASSERT((opCode8 & X86Inst::kOpCode_MM_Mask) == 0);
ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 ||
(opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 ||
(opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
inst32Size += static_cast<uint32_t>(
(opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
// Only one of these should be used at the same time.
inst32Size += static_cast<uint32_t>(opReg != 0);
inst32Size += static_cast<uint32_t>((opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
if (rmRel->isLabel()) {
label = _code->getLabelEntry(rmRel->as<Label>());
@@ -4227,7 +4270,7 @@ EmitJmpCall:
if (label->isBound()) {
// Bound label.
rel32 = static_cast<uint32_t>((static_cast<uint64_t>(label->getOffset()) - ip - inst32Size) & 0xFFFFFFFFU);
goto EmitJmpCall_Rel;
goto EmitJmpCallRel;
}
else {
// Non-bound label.
@@ -4242,10 +4285,14 @@ EmitJmpCall:
if (ASMJIT_UNLIKELY(!opCode || (options & X86Inst::kOptionShortForm) != 0))
goto InvalidDisplacement;
// Emit [PREFIX] OPCODE [/X] <DISP32>.
if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F);
EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
relOffset = -4;
relSize = 4;
goto EmitRel;
@@ -4264,7 +4311,7 @@ EmitJmpCall:
uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size;
if (getArchType() == ArchInfo::kTypeX86 || Utils::isInt32(static_cast<int64_t>(rel64))) {
rel32 = static_cast<uint32_t>(rel64 & 0xFFFFFFFFU);
goto EmitJmpCall_Rel;
goto EmitJmpCallRel;
}
else {
// Relative displacement exceeds 32-bits - relocator can only
@@ -4299,11 +4346,14 @@ EmitJmpCall:
_code->_trampolinesSize += 8;
}
// Emit [PREFIX] OPCODE + DISP32.
// Emit [PREFIX] OPCODE [/X] DISP32.
if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F);
EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
EMIT_32(0);
}
else {
@@ -4323,7 +4373,7 @@ EmitJmpCall:
// Emit jmp/call with relative displacement known at assembly-time. Decide
// between 8-bit and 32-bit displacement encoding. Some instructions only
// 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)) {
options |= X86Inst::kOptionShortForm;
EMIT_BYTE(opCode8);
@@ -4335,8 +4385,13 @@ EmitJmpCall_Rel:
goto InvalidDisplacement;
options &= ~X86Inst::kOptionShortForm;
if (opCode & X86Inst::kOpCode_MM_Mask) EMIT_BYTE(0x0F);
if (opCode & X86Inst::kOpCode_MM_Mask)
EMIT_BYTE(0x0F);
EMIT_BYTE(opCode);
if (opReg)
EMIT_BYTE(x86EncodeMod(3, opReg, 0));
EMIT_32(rel32);
goto EmitDone;
}
@@ -4417,6 +4472,7 @@ EmitDone:
#endif // !ASMJIT_DISABLE_LOGGING
resetOptions();
resetExtraOp();
resetInlineComment();
_bufferPtr = cursor;
@@ -4436,6 +4492,8 @@ ERROR_HANDLER(InvalidArgument)
ERROR_HANDLER(InvalidLabel)
ERROR_HANDLER(InvalidInstruction)
ERROR_HANDLER(InvalidLockPrefix)
ERROR_HANDLER(InvalidXAcquirePrefix)
ERROR_HANDLER(InvalidXReleasePrefix)
ERROR_HANDLER(InvalidRepPrefix)
ERROR_HANDLER(InvalidRexPrefix)
ERROR_HANDLER(InvalidBroadcast)

View File

@@ -79,6 +79,8 @@ public:
// [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 align(uint32_t mode, uint32_t alignment) override;
};

View File

@@ -107,20 +107,13 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
static_cast<uint32_t>(!o3.isNone()) ;
// Handle failure and rare cases first.
const uint32_t kErrorsAndSpecialCases =
kOptionMaybeFailureCase | // CodeEmitter in error state.
kOptionStrictValidation | // Strict validation.
kOptionOp4 | // Has 5th operand (o4, indexed from zero).
kOptionOp5 ; // Has 6th operand (o5, indexed from zero).
const uint32_t kErrorsAndSpecialCases = kOptionMaybeFailureCase | // CodeEmitter is 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;
// Count 5th and 6th operands.
if (options & kOptionOp4) opCount = 5;
if (options & kOptionOp5) opCount = 6;
#if !defined(ASMJIT_DISABLE_VALIDATION)
// Strict validation.
if (options & kOptionStrictValidation) {
@@ -128,18 +121,16 @@ Error X86Compiler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1
Operand(o0),
Operand(o1),
Operand(o2),
Operand(o3),
Operand(_op4),
Operand(_op5)
Operand(o3)
};
Error err = X86Inst::validate(getArchType(), instId, options, _opExtra, opArray, opCount);
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, _opExtra, opArray, opCount);
Logging::formatInstruction(sb, 0, this, getArchType(), instId, options, _extraOp, opArray, opCount);
return setLastError(err, sb.getData());
#else
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 > 2) opArray[2].copyFrom(o2);
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)
node->_opExtra = _opExtra;
new(node) CBJump(this, instId, options, opArray, opCount);
node->_extraOp = _extraOp;
_extraOp.reset();
CBLabel* jTarget = nullptr;
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 > 2) opArray[2].copyFrom(o2);
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->_opExtra = _opExtra;
node = new(node) CBInst(this, instId, options, opArray, opCount);
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) {
inlineComment = static_cast<char*>(_cbDataZone.dup(inlineComment, ::strlen(inlineComment), true));

View File

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

View File

@@ -362,13 +362,13 @@ public:
//! Use REP/REPZ prefix.
ASMJIT_INLINE This& rep(const X86Gp& zcx) noexcept {
static_cast<This*>(this)->_opExtra = zcx;
return _addOptions(X86Inst::kOptionOpExtra | X86Inst::kOptionRep);
static_cast<This*>(this)->_extraOp = zcx;
return _addOptions(X86Inst::kOptionRep);
}
//! Use REPNZ prefix.
ASMJIT_INLINE This& repnz(const X86Gp& zcx) noexcept {
static_cast<This*>(this)->_opExtra = zcx;
return _addOptions(X86Inst::kOptionOpExtra | X86Inst::kOptionRepnz);
static_cast<This*>(this)->_extraOp = zcx;
return _addOptions(X86Inst::kOptionRepnz);
}
//! Use REP/REPZ prefix.
@@ -404,7 +404,7 @@ public:
ASMJIT_INLINE This& evex() noexcept { return _addOptions(X86Inst::kOptionEvex); }
//! 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+).
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, X86Mem) // ANY
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_0x(leave, Leave) // ANY
ASMJIT_INST_2x(les, Les, X86Gp, X86Mem) // X86
ASMJIT_INST_0x(lfence, Lfence) // SSE2
ASMJIT_INST_2x(lfs, Lfs, X86Gp, 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(lldt, Lldt, X86Gp) // 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(lsl, Lsl, X86Gp, X86Gp) // 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, X86Mem) // ANY
ASMJIT_INST_2x(lzcnt, Lzcnt, X86Gp, X86Gp) // LZCNT
@@ -717,6 +722,7 @@ public:
ASMJIT_INST_2i(ror, Ror, X86Mem, Imm) // ANY
ASMJIT_INST_3i(rorx, Rorx, X86Gp, X86Gp, 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, X86Mem) // ANY
ASMJIT_INST_2i(sbb, Sbb, X86Gp, Imm) // ANY
@@ -795,11 +801,16 @@ public:
ASMJIT_INST_1x(wrfsbase, Wrfsbase, 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_0x(xabort, Xabort) // RTM
ASMJIT_INST_2x(xadd, Xadd, X86Gp, 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, X86Mem, X86Gp) // 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_2x(xor_, Xor, X86Gp, X86Gp) // ANY
ASMJIT_INST_2x(xor_, Xor, X86Gp, X86Mem) // ANY
@@ -807,6 +818,7 @@ public:
ASMJIT_INST_2x(xor_, Xor, X86Mem, X86Gp) // 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_0x(xtest, Xtest) // TSX
// --------------------------------------------------------------------------
// [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(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_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, 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.
@@ -4945,6 +4961,7 @@ struct X86EmitterImplicitT : public X86EmitterExplicitT<This> {
ASMJIT_INST_0x(sysret64, Sysret64) // X64 [IMPLICIT]
ASMJIT_INST_0x(wrmsr, Wrmsr) // ANY [IMPLICIT]
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(xrstor64, Xrstor64, X86Mem) // XSAVE+X64 [IMPLICIT]
ASMJIT_INST_1x(xrstors, Xrstors, X86Mem) // XSAVE [IMPLICIT]

File diff suppressed because it is too large Load Diff

View File

@@ -305,6 +305,10 @@ struct X86Inst {
kIdInvd, // [ANY] {I486}
kIdInvlpg, // [ANY] {I486}
kIdInvpcid, // [ANY] {I486}
kIdIret, // [ANY]
kIdIretd, // [ANY]
kIdIretq, // [X64]
kIdIretw, // [ANY]
kIdJa, // [ANY]
kIdJae, // [ANY]
kIdJb, // [ANY]
@@ -392,10 +396,14 @@ struct X86Inst {
kIdLar, // [ANY]
kIdLddqu, // [ANY] {SSE3}
kIdLdmxcsr, // [ANY] {SSE}
kIdLds, // [X86]
kIdLea, // [ANY]
kIdLeave, // [ANY]
kIdLes, // [X86]
kIdLfence, // [ANY] {SSE2}
kIdLfs, // [ANY]
kIdLgdt, // [ANY]
kIdLgs, // [ANY]
kIdLidt, // [ANY]
kIdLldt, // [ANY]
kIdLmsw, // [ANY]
@@ -404,6 +412,7 @@ struct X86Inst {
kIdLoope, // [ANY]
kIdLoopne, // [ANY]
kIdLsl, // [ANY]
kIdLss, // [ANY]
kIdLtr, // [ANY]
kIdLzcnt, // [ANY] {LZCNT}
kIdMaskmovdqu, // [ANY] {SSE2}
@@ -663,6 +672,7 @@ struct X86Inst {
kIdRoundps, // [ANY] {SSE4_1}
kIdRoundsd, // [ANY] {SSE4_1}
kIdRoundss, // [ANY] {SSE4_1}
kIdRsm, // [X86]
kIdRsqrtps, // [ANY] {SSE}
kIdRsqrtss, // [ANY] {SSE}
kIdSahf, // [ANY] {LAHFSAHF}
@@ -1436,9 +1446,13 @@ struct X86Inst {
kIdWrfsbase, // [X64] {FSGSBASE}
kIdWrgsbase, // [X64] {FSGSBASE}
kIdWrmsr, // [ANY] {MSR}
kIdXabort, // [ANY] {RTM}
kIdXadd, // [ANY] {I486}
kIdXbegin, // [ANY] {RTM}
kIdXchg, // [ANY]
kIdXend, // [ANY] {RTM}
kIdXgetbv, // [ANY] {XSAVE}
kIdXlatb, // [ANY]
kIdXor, // [ANY]
kIdXorpd, // [ANY] {SSE2}
kIdXorps, // [ANY] {SSE}
@@ -1455,6 +1469,7 @@ struct X86Inst {
kIdXsaves, // [ANY] {XSAVE}
kIdXsaves64, // [X64] {XSAVE}
kIdXsetbv, // [ANY] {XSAVE}
kIdXtest, // [ANY] {TSX}
_kIdCount
// ${idData:End}
};
@@ -1464,6 +1479,7 @@ struct X86Inst {
kEncodingNone = 0, //!< Never used.
kEncodingX86Op, //!< X86 [OP].
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_xDX_xAX, //!< X86 [OP] (implicit or explicit '?DX, ?AX' form).
kEncodingX86Op_ZAX, //!< X86 [OP] (implicit or explicit '[EAX|RDX]' form).
@@ -1492,6 +1508,7 @@ struct X86Inst {
kEncodingX86Jcc, //!< X86 jcc.
kEncodingX86JecxzLoop, //!< X86 jcxz, jecxz, jrcxz, loop, loope, loopne.
kEncodingX86Jmp, //!< X86 jmp.
kEncodingX86JmpRel, //!< X86 xbegin.
kEncodingX86Lea, //!< X86 lea.
kEncodingX86Mov, //!< X86 mov (all possible cases).
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.
kFlagRep = 0x00004000U, //!< Instruction can be prefixed by using the REP/REPZ/REPE prefix.
kFlagRepnz = 0x00008000U, //!< Instruction can be prefixed by using the REPNZ/REPNE prefix.
kFlagLock = 0x00010000U, //!< Instruction can be prefixed by using the LOCK prefix.
kFlagRep = 0x00001000U, //!< Instruction can be prefixed by using the REP/REPZ/REPE prefix.
kFlagRepnz = 0x00002000U, //!< Instruction can be prefixed by using the REPNZ/REPNE 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.
kFlagVsib = 0x00040000U, //!< Instruction uses VSIB instead of legacy SIB.
kFlagVex = 0x00080000U, //!< Instruction can be encoded by VEX|XOP (AVX|AVX2|BMI|XOP|...).
@@ -1955,14 +1974,14 @@ struct X86Inst {
//! Instruction options (AsmJit specific).
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,
kOptionOp5 = CodeEmitter::kOptionOp5,
kOptionOpExtra = CodeEmitter::kOptionOpExtra,
kOptionShortForm = 0x00000040U, //!< Emit short-form of the instruction.
kOptionLongForm = 0x00000080U, //!< Emit long-form of the instruction.
kOptionShortForm = 0x00000100U, //!< Emit short-form of the instruction.
kOptionLongForm = 0x00000200U, //!< Emit long-form of the instruction.
kOptionTaken = 0x00000100U, //!< Conditional jump is likely to be taken.
kOptionNotTaken = 0x00000200U, //!< Conditional jump is unlikely to be taken.
kOptionVex3 = 0x00000400U, //!< Use 3-byte VEX prefix if possible (AVX) (must be 0x00000400).
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).
kOptionRepnz = 0x00008000U, //!< REPNZ prefix (string instructions only).
kOptionTaken = 0x00010000U, //!< JCC likely to be taken (historic, only takes effect on P4).
kOptionNotTaken = 0x00020000U, //!< JCC unlikely to be taken (historic, only takes effect on P4).
kOptionXAcquire = 0x00010000U, //!< XACQUIRE prefix (only allowed instructions).
kOptionXRelease = 0x00020000U, //!< XRELEASE prefix (only allowed instructions).
kOptionSAE = 0x00040000U, //!< AVX-512: 'suppress-all-exceptions' {sae}.
kOptionER = 0x00080000U, //!< AVX-512: 'rounding-control' {rc} and {sae}.
kOptionER = 0x00040000U, //!< AVX-512: 'embedded-rounding' {er} and {sae}.
kOptionSAE = 0x00080000U, //!< AVX-512: 'suppress-all-exceptions' {sae}.
kOption1ToX = 0x00100000U, //!< AVX-512: broadcast the first element to all {1tox}.
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).
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).
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).
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.
kMemOpM16 = 0x0002U, //!< Operand can be a 16-bit memory pointer.
kMemOpM32 = 0x0004U, //!< Operand can be a 32-bit memory pointer.
kMemOpM64 = 0x0008U, //!< Operand can be a 64-bit memory pointer.
kMemOpM80 = 0x0010U, //!< Operand can be an 80-bit memory pointer.
kMemOpM128 = 0x0020U, //!< Operand can be a 128-bit memory pointer.
kMemOpM256 = 0x0040U, //!< Operand can be a 256-bit memory pointer.
kMemOpM512 = 0x0080U, //!< Operand can be a 512-bit memory pointer.
kMemOpM1024 = 0x0100U, //!< Operand can be a 1024-bit memory pointer.
kMemOpM48 = 0x0008U, //!< Operand can be a 32-bit memory pointer.
kMemOpM64 = 0x0010U, //!< Operand can be a 64-bit memory pointer.
kMemOpM80 = 0x0020U, //!< Operand can be an 80-bit memory pointer.
kMemOpM128 = 0x0040U, //!< Operand can be a 128-bit memory pointer.
kMemOpM256 = 0x0080U, //!< Operand can be a 256-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.
kMemOpVm32y = 0x0002U, //!< Operand can be a vm32y (vector) pointer.
@@ -2072,9 +2092,9 @@ struct X86Inst {
kMemOpVm64y = 0x0020U, //!< Operand can be a vm64y (vector) pointer.
kMemOpVm64z = 0x0040U, //!< Operand can be a vm64z (vector) pointer.
kMemOpBaseOnly = 0x0200U, //!< Only memory base is allowed (no index, no offset).
kMemOpDs = 0x0400U, //!< Implicit memory operand's DS segment.
kMemOpEs = 0x0800U, //!< Implicit memory operand's ES segment.
kMemOpBaseOnly = 0x0800U, //!< Only memory base is allowed (no index, no offset).
kMemOpDs = 0x1000U, //!< Implicit memory operand's DS segment.
kMemOpEs = 0x2000U, //!< Implicit memory operand's ES segment.
kMemOpMib = 0x4000U, //!< Operand must be MIB (base+index) pointer.
kMemOpAny = 0x8000U //!< Operand can be any scalar memory pointer.
@@ -2429,7 +2449,7 @@ struct X86Inst {
#if !defined(ASMJIT_DISABLE_VALIDATION)
ASMJIT_API static Error validate(
uint32_t archType, uint32_t instId, uint32_t options,
const Operand_& opExtra,
const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept;
#endif // !ASMJIT_DISABLE_VALIDATION

View File

@@ -120,6 +120,7 @@ static const char* x86GetAddressSizeString(uint32_t size) noexcept {
case 1 : return "byte ";
case 2 : return "word ";
case 4 : return "dword ";
case 6 : return "fword ";
case 8 : return "qword ";
case 10: return "tword ";
case 16: return "oword ";
@@ -581,7 +582,7 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
uint32_t archType,
uint32_t instId,
uint32_t options,
const Operand_& opExtra,
const Operand_& extraOp,
const Operand_* opArray, uint32_t opCount) noexcept {
// 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::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 "));
// REP options.
@@ -602,9 +605,9 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
rep = instInfo.hasFlag(X86Inst::kFlagRepnz) ? "repz " : "rep ";
sb.appendString(rep);
if (!opExtra.isNone()) {
if (!extraOp.isNone()) {
ASMJIT_PROPAGATE(sb.appendChar('{'));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, opExtra));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, extraOp));
ASMJIT_PROPAGATE(sb.appendString("} "));
}
}
@@ -655,19 +658,15 @@ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction(
// Support AVX-512 {k}{z}.
if (i == 0) {
const uint32_t kExtMsk = X86Inst::kOptionOpExtra |
X86Inst::kOptionRep |
X86Inst::kOptionRepnz ;
if ((options & kExtMsk) == X86Inst::kOptionOpExtra) {
if (X86Reg::isK(extraOp)) {
ASMJIT_PROPAGATE(sb.appendString(" {"));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, opExtra));
ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, extraOp));
ASMJIT_PROPAGATE(sb.appendChar('}'));
if (options & X86Inst::kOptionKZ)
if (options & X86Inst::kOptionZMask)
ASMJIT_PROPAGATE(sb.appendString("{z}"));
}
else if (options & X86Inst::kOptionKZ) {
else if (options & X86Inst::kOptionZMask) {
ASMJIT_PROPAGATE(sb.appendString(" {z}"));
}
}

View File

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

View File

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

View File

@@ -42,23 +42,23 @@ static void dumpCpu(void) {
#if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
static const DumpCpuFeature armFeaturesList[] = {
{ CpuInfo::kArmFeatureV6 , "ARMv6" },
{ CpuInfo::kArmFeatureV7 , "ARMv7" },
{ CpuInfo::kArmFeatureV8 , "ARMv8" },
{ CpuInfo::kArmFeatureTHUMB , "THUMB" },
{ CpuInfo::kArmFeatureTHUMB2 , "THUMBv2" },
{ CpuInfo::kArmFeatureVFP2 , "VFPv2" },
{ CpuInfo::kArmFeatureVFP3 , "VFPv3" },
{ CpuInfo::kArmFeatureVFP4 , "VFPv4" },
{ CpuInfo::kArmFeatureVFP_D32 , "VFP D32" },
{ CpuInfo::kArmFeatureNEON , "NEON" },
{ CpuInfo::kArmFeatureDSP , "DSP" },
{ CpuInfo::kArmFeatureIDIV , "IDIV" },
{ CpuInfo::kArmFeatureAES , "AES" },
{ CpuInfo::kArmFeatureCRC32 , "CRC32" },
{ CpuInfo::kArmFeatureSHA1 , "SHA1" },
{ CpuInfo::kArmFeatureSHA256 , "SHA256" },
{ CpuInfo::kArmFeatureAtomics64 , "64-bit atomics" }
{ CpuInfo::kArmFeatureV6 , "ARMv6" },
{ CpuInfo::kArmFeatureV7 , "ARMv7" },
{ CpuInfo::kArmFeatureV8 , "ARMv8" },
{ CpuInfo::kArmFeatureTHUMB , "THUMB" },
{ CpuInfo::kArmFeatureTHUMB2 , "THUMBv2" },
{ CpuInfo::kArmFeatureVFP2 , "VFPv2" },
{ CpuInfo::kArmFeatureVFP3 , "VFPv3" },
{ CpuInfo::kArmFeatureVFP4 , "VFPv4" },
{ CpuInfo::kArmFeatureVFP_D32 , "VFP D32" },
{ CpuInfo::kArmFeatureNEON , "NEON" },
{ CpuInfo::kArmFeatureDSP , "DSP" },
{ CpuInfo::kArmFeatureIDIV , "IDIV" },
{ CpuInfo::kArmFeatureAES , "AES" },
{ CpuInfo::kArmFeatureCRC32 , "CRC32" },
{ CpuInfo::kArmFeatureSHA1 , "SHA1" },
{ CpuInfo::kArmFeatureSHA256 , "SHA256" },
{ CpuInfo::kArmFeatureAtomics64 , "64-bit atomics" }
};
INFO("ARM Features:");
@@ -129,6 +129,7 @@ static void dumpCpu(void) {
{ CpuInfo::kX86FeatureMPX , "MPX" },
{ CpuInfo::kX86FeatureHLE , "HLE" },
{ CpuInfo::kX86FeatureRTM , "RTM" },
{ CpuInfo::kX86FeatureTSX , "TSX" },
{ CpuInfo::kX86FeatureERMS , "ERMS" },
{ CpuInfo::kX86FeatureFSGSBASE , "FSGSBASE" },
{ CpuInfo::kX86FeatureAVX512_F , "AVX512-F" },

View File

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