mirror of
https://github.com/asmjit/asmjit.git
synced 2025-12-16 20:17:05 +03:00
[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:
@@ -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
|
||||
|
||||
@@ -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(" ; ");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user