mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-18 13:04:36 +03:00
[Bug] Fixed instruction RW info related to AVX-512 {k} (merging) and {k} {z} (zeroing)
This commit is contained in:
@@ -809,6 +809,20 @@ static ASMJIT_INLINE void rwZeroExtendNonVec(OpRWInfo& opRwInfo, const Reg& reg)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static ASMJIT_INLINE Error rwHandleAVX512(const BaseInst& inst, InstRWInfo* out) noexcept {
|
||||||
|
if (inst.hasExtraReg() && inst.extraReg().type() == Reg::kTypeKReg && out->opCount() > 0) {
|
||||||
|
// AVX-512 instruction that uses a destination with {k} register (zeroing vs masking).
|
||||||
|
out->_extraReg.addOpFlags(OpRWInfo::kRead);
|
||||||
|
out->_extraReg.setReadByteMask(0xFF);
|
||||||
|
if (!inst.hasOption(Inst::kOptionZMask)) {
|
||||||
|
out->_operands[0].addOpFlags(OpRWInfo::kRead);
|
||||||
|
out->_operands[0]._readByteMask |= out->_operands[0]._writeByteMask;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return kErrorOk;
|
||||||
|
}
|
||||||
|
|
||||||
Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Operand_* operands, size_t opCount, InstRWInfo* out) noexcept {
|
||||||
using namespace Status;
|
using namespace Status;
|
||||||
|
|
||||||
@@ -940,15 +954,15 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
} while (it.hasNext());
|
} while (it.hasNext());
|
||||||
}
|
}
|
||||||
|
|
||||||
return kErrorOk;
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (instRwInfo.category) {
|
switch (instRwInfo.category) {
|
||||||
case InstDB::RWInfo::kCategoryMov: {
|
case InstDB::RWInfo::kCategoryMov: {
|
||||||
// Special case for 'movhpd' instruction. Here there are some variants that
|
// Special case for 'mov' instruction. Here there are some variants that
|
||||||
// we have to handle as mov can be used to move between GP, segment, control
|
// we have to handle as 'mov' can be used to move between GP, segment,
|
||||||
// and debug registers. Moving between GP registers also allow to use memory
|
// control and debug registers. Moving between GP registers also allow to
|
||||||
// operand.
|
// use memory operand.
|
||||||
|
|
||||||
if (opCount == 2) {
|
if (opCount == 2) {
|
||||||
if (operands[0].isReg() && operands[1].isReg()) {
|
if (operands[0].isReg() && operands[1].isReg()) {
|
||||||
@@ -1118,7 +1132,7 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
case InstDB::RWInfo::kCategoryMovh64: {
|
case InstDB::RWInfo::kCategoryMovh64: {
|
||||||
// Special case for 'movhpd|movhps' instructions. Note that this is only
|
// Special case for 'movhpd|movhps' instructions. Note that this is only
|
||||||
// required for legacy (non-AVX) variants as AVX instructions use either
|
// required for legacy (non-AVX) variants as AVX instructions use either
|
||||||
// 2 or 3 operands that are use `kCategoryGeneric`.
|
// 2 or 3 operands that are in `kCategoryGeneric` category.
|
||||||
if (opCount == 2) {
|
if (opCount == 2) {
|
||||||
if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
|
if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
|
||||||
out->_operands[0].reset(W, 8);
|
out->_operands[0].reset(W, 8);
|
||||||
@@ -1174,7 +1188,7 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
out->_operands[1]._readByteMask &= 0x00FF00FF00FF00FFu;
|
out->_operands[1]._readByteMask &= 0x00FF00FF00FF00FFu;
|
||||||
|
|
||||||
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
||||||
return kErrorOk;
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
|
if (BaseReg::isVec(operands[0]) && operands[1].isMem()) {
|
||||||
@@ -1185,7 +1199,7 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
out->_operands[1].reset(R | MibRead, o1Size);
|
out->_operands[1].reset(R | MibRead, o1Size);
|
||||||
|
|
||||||
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
||||||
return kErrorOk;
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1259,7 +1273,7 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
if (BaseReg::isVec(operands[0]))
|
if (BaseReg::isVec(operands[0]))
|
||||||
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
rwZeroExtendAvxVec(out->_operands[0], operands[0].as<Vec>());
|
||||||
|
|
||||||
return kErrorOk;
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operands[0].isReg() && operands[1].isMem()) {
|
if (operands[0].isReg() && operands[1].isMem()) {
|
||||||
@@ -1277,7 +1291,8 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
|
|
||||||
out->_operands[0].reset(W | MibRead, size0);
|
out->_operands[0].reset(W | MibRead, size0);
|
||||||
out->_operands[1].reset(R, size1);
|
out->_operands[1].reset(R, size1);
|
||||||
return kErrorOk;
|
|
||||||
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@@ -1328,12 +1343,14 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
|
|||||||
out->_operands[1].addOpFlags(RegM);
|
out->_operands[1].addOpFlags(RegM);
|
||||||
out->_operands[1].setRmSize(size1);
|
out->_operands[1].setRmSize(size1);
|
||||||
}
|
}
|
||||||
return kErrorOk;
|
|
||||||
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (operands[0].isReg() && operands[1].isMem()) {
|
if (operands[0].isReg() && operands[1].isMem()) {
|
||||||
out->_operands[1].addOpFlags(MibRead);
|
out->_operands[1].addOpFlags(MibRead);
|
||||||
return kErrorOk;
|
|
||||||
|
return rwHandleAVX512(inst, out);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -148,6 +148,15 @@ static void printInfoSimple(uint32_t arch, uint32_t instId, Args&&... args) {
|
|||||||
printInfo(arch, inst, opArray, sizeof...(args));
|
printInfo(arch, inst, opArray, sizeof...(args));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template<typename... Args>
|
||||||
|
static void printInfoExtra(uint32_t arch, uint32_t instId, uint32_t options, const BaseReg& extraReg, Args&&... args) {
|
||||||
|
BaseInst inst(instId);
|
||||||
|
inst.addOptions(options);
|
||||||
|
inst.setExtraReg(extraReg);
|
||||||
|
Operand_ opArray[] = { std::forward<Args>(args)... };
|
||||||
|
printInfo(arch, inst, opArray, sizeof...(args));
|
||||||
|
}
|
||||||
|
|
||||||
static void testX86Arch() {
|
static void testX86Arch() {
|
||||||
#if defined(ASMJIT_BUILD_X86)
|
#if defined(ASMJIT_BUILD_X86)
|
||||||
uint32_t arch = Environment::kArchX64;
|
uint32_t arch = Environment::kArchX64;
|
||||||
@@ -183,6 +192,16 @@ static void testX86Arch() {
|
|||||||
printInfoSimple(arch,
|
printInfoSimple(arch,
|
||||||
x86::Inst::kIdVaddpd,
|
x86::Inst::kIdVaddpd,
|
||||||
x86::zmm0, x86::zmm1, x86::zmm2);
|
x86::zmm0, x86::zmm1, x86::zmm2);
|
||||||
|
|
||||||
|
printInfoExtra(arch,
|
||||||
|
x86::Inst::kIdVaddpd, 0,
|
||||||
|
x86::k1,
|
||||||
|
x86::zmm0, x86::zmm1, x86::zmm2);
|
||||||
|
|
||||||
|
printInfoExtra(arch,
|
||||||
|
x86::Inst::kIdVaddpd, x86::Inst::kOptionZMask,
|
||||||
|
x86::k1,
|
||||||
|
x86::zmm0, x86::zmm1, x86::zmm2);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user