[Bug] Fixed queryFeatures() to properly return AVX-512 requirements of shift instructions that use memory operands

[Bug] Fixed queryFeatures() to properly return AVX-512 requirements of some floating-point conversion instructions
[Opt] Slightly improved the performance of BitWordIterator and friends possibly taking advantage of BMI extensions
[API] Removed BitWordFlipIterator that was never used by the library
[Enh] Log the whole instruction if the validation fails in asmjit::Builder
This commit is contained in:
kobalicek
2022-06-05 22:45:15 +02:00
parent a4cb51b532
commit 33a31f04e8
7 changed files with 40 additions and 39 deletions

View File

@@ -594,10 +594,14 @@ Error BaseBuilder::_emit(InstId instId, const Operand_& o0, const Operand_& o1,
Error err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, opCount, validationFlags);
if (ASMJIT_UNLIKELY(err)) {
#ifndef ASMJIT_NO_LOGGING
return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt);
#else
resetInstOptions();
resetExtraReg();
resetInlineComment();
return reportError(err);
#endif
}
}
#endif

View File

@@ -96,7 +96,7 @@ void logInstructionEmitted(
}
Error logInstructionFailed(
BaseAssembler* self,
BaseEmitter* self,
Error err,
InstId instId,
InstOptions options,
@@ -109,7 +109,7 @@ Error logInstructionFailed(
Operand_ opArray[Globals::kMaxOpCount];
opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
self->_funcs.formatInstruction(sb, FormatFlags::kNone, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
self->_funcs.formatInstruction(sb, FormatFlags::kRegType, self, self->arch(), BaseInst(instId, options, self->extraReg()), opArray, Globals::kMaxOpCount);
if (self->inlineComment()) {
sb.append(" ; ");

View File

@@ -71,7 +71,7 @@ void logInstructionEmitted(
uint32_t relSize, uint32_t immSize, uint8_t* afterCursor);
Error logInstructionFailed(
BaseAssembler* self,
BaseEmitter* self,
Error err,
InstId instId,
InstOptions options,

View File

@@ -37,7 +37,9 @@ enum class FormatFlags : uint32_t {
//! Show casts between virtual register types (Compiler output).
kRegCasts = 0x00000010u,
//! Show positions associated with nodes (Compiler output).
kPositions = 0x00000020u
kPositions = 0x00000020u,
//! Always format a register type (Compiler output).
kRegType = 0x00000040u
};
ASMJIT_DEFINE_ENUM_FLAGS(FormatFlags)

View File

@@ -1227,36 +1227,13 @@ public:
ASMJIT_FORCE_INLINE uint32_t next() noexcept {
ASMJIT_ASSERT(_bitWord != 0);
uint32_t index = ctz(_bitWord);
_bitWord ^= T(1u) << index;
_bitWord &= T(_bitWord - 1);
return index;
}
T _bitWord;
};
// Support - BitWordFlipIterator
// =============================
template<typename T>
class BitWordFlipIterator {
public:
ASMJIT_FORCE_INLINE explicit BitWordFlipIterator(T bitWord) noexcept
: _bitWord(bitWord) {}
ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
ASMJIT_FORCE_INLINE uint32_t nextAndFlip() noexcept {
ASMJIT_ASSERT(_bitWord != 0);
uint32_t index = ctz(_bitWord);
_bitWord ^= T(1u) << index;
return index;
}
T _bitWord;
T _xorMask;
};
// Support - BitVectorOps
// ======================
@@ -1406,7 +1383,7 @@ public:
ASMJIT_ASSERT(bitWord != T(0));
uint32_t bit = ctz(bitWord);
bitWord ^= T(1u) << bit;
bitWord &= T(bitWord - 1u);
size_t n = _idx + bit;
while (!bitWord && (_idx += bitSizeOf<T>()) < _end)
@@ -1471,7 +1448,7 @@ public:
ASMJIT_ASSERT(bitWord != T(0));
uint32_t bit = ctz(bitWord);
bitWord ^= T(1u) << bit;
bitWord &= T(bitWord - 1u);
size_t n = _idx + bit;
while (!bitWord && (_idx += kTSizeInBits) < _end)

View File

@@ -344,7 +344,10 @@ ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, FormatFlag
else
ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(id))));
if (vReg->type() != type && uint32_t(type) <= uint32_t(RegType::kMaxValue) && Support::test(formatFlags, FormatFlags::kRegCasts)) {
bool formatType = (Support::test(formatFlags, FormatFlags::kRegType)) ||
(Support::test(formatFlags, FormatFlags::kRegCasts) && vReg->type() != type);
if (formatType && uint32_t(type) <= uint32_t(RegType::kMaxValue)) {
const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[size_t(type)];
if (typeEntry.index)
ASMJIT_PROPAGATE(sb.appendFormat("@%s", info.typeStrings + typeEntry.index));

View File

@@ -1588,14 +1588,6 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
uint32_t mustUseEvex = 0;
switch (instId) {
// Special case: VPSLLDQ and VPSRLDQ instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode,
// then AVX-512 introduced `reg, reg/mem, imm` combination that uses EVEX prefix. This means that if the
// second operand is memory then this is AVX-512_BW instruction and not AVX/AVX2 instruction.
case Inst::kIdVpslldq:
case Inst::kIdVpsrldq:
mustUseEvex = opCount >= 2 && operands[1].isMem();
break;
// Special case: VPBROADCAST[B|D|Q|W] only supports r32/r64 with EVEX prefix.
case Inst::kIdVpbroadcastb:
case Inst::kIdVpbroadcastd:
@@ -1604,6 +1596,29 @@ Error InstInternal::queryFeatures(Arch arch, const BaseInst& inst, const Operand
mustUseEvex = opCount >= 2 && x86::Reg::isGp(operands[1]);
break;
case Inst::kIdVcvtpd2dq:
case Inst::kIdVcvtpd2ps:
case Inst::kIdVcvttpd2dq:
mustUseEvex = opCount >= 2 && Reg::isYmm(operands[0]);
break;
// Special case: These instructions only allow `reg, reg. imm` combination in AVX|AVX2 mode, then
// AVX-512 introduced `reg, reg/mem, imm` combination that uses EVEX prefix. This means that if
// the second operand is memory then this is AVX-512_BW instruction and not AVX/AVX2 instruction.
case Inst::kIdVpslldq:
case Inst::kIdVpslld:
case Inst::kIdVpsllq:
case Inst::kIdVpsllw:
case Inst::kIdVpsrad:
case Inst::kIdVpsraq:
case Inst::kIdVpsraw:
case Inst::kIdVpsrld:
case Inst::kIdVpsrldq:
case Inst::kIdVpsrlq:
case Inst::kIdVpsrlw:
mustUseEvex = opCount >= 2 && operands[1].isMem();
break;
// Special case: VPERMPD - AVX2 vs AVX512-F case.
case Inst::kIdVpermpd:
mustUseEvex = opCount >= 3 && !operands[2].isImm();