Added support for more X86 extensions (AMX, AVX512_VP2INTERSECT, MCOMMIT, RDPRU, SERIALIZE, SNP, TSXLDTRK)

This commit is contained in:
kobalicek
2020-06-30 20:42:22 +02:00
parent 3535263419
commit ba30278d66
19 changed files with 3689 additions and 2911 deletions

View File

@@ -44,7 +44,11 @@ TODO
----
* [ ] Core:
* [ ] Add support for user external buffers in CodeHolder.
* [ ] Add support for user external buffers in CodeBuffer / CodeHolder.
* [ ] Register allocator doesn't understand register pairs, affected instructions:
* [ ] v4fmaddps, v4fmaddss, v4fnmaddps, v4fnmaddss
* [ ] vp4dpwssd, vp4dpwssds
* [ ] vp2intersectd, vp2intersectq
* [ ] Ports:
* [ ] ARM/Thumb/AArch64 support.

View File

@@ -789,7 +789,7 @@ Error BaseBuilder::comment(const char* data, size_t size) {
// [asmjit::BaseBuilder - Serialize]
// ============================================================================
Error BaseBuilder::serialize(BaseEmitter* dst) {
Error BaseBuilder::serializeTo(BaseEmitter* dst) {
Error err = kErrorOk;
BaseNode* node_ = _firstNode;

View File

@@ -357,7 +357,7 @@ public:
//! Although not explicitly required the emitter will most probably be of
//! Assembler type. The reason is that there is no known use of serializing
//! nodes held by Builder/Compiler into another Builder-like emitter.
ASMJIT_API Error serialize(BaseEmitter* dst);
ASMJIT_API Error serializeTo(BaseEmitter* dst);
//! \}
@@ -370,6 +370,11 @@ public:
//! \}
#ifndef ASMJIT_NO_DEPRECATED
ASMJIT_DEPRECATED("Use serializeTo() instead, serialize() is now also an instruction.")
inline Error serialize(BaseEmitter* dst) {
return serializeTo(dst);
}
#ifndef ASMJIT_NO_LOGGING
ASMJIT_DEPRECATED("Use Formatter::formatNodeList(sb, formatFlags, builder)")
inline Error dump(String& sb, uint32_t formatFlags = 0) const noexcept {

View File

@@ -674,7 +674,7 @@ public:
kTypeIP = 15,
//! Start of platform dependent register types (must be honored).
kTypeCustom = 16,
//! Maximum possible register id of all architectures.
//! Maximum possible register type value.
kTypeMax = 31
};

View File

@@ -669,6 +669,13 @@ ASMJIT_FAVOR_SPEED Error Assembler::_emit(uint32_t instId, const Operand_& o0, c
// [Encoding Scope]
// --------------------------------------------------------------------------
// How it works? Each case here represents a unique encoding of a group of
// instructions, which is handled separately. The handlers check instruction
// signature, possibly register types, etc, and process this information by
// writing some bits to opcode, opReg/rbReg, immValue/immSize, etc, and then
// at the end of the sequence it uses goto to jump into a lower level handler,
// that actually encodes the instruction.
switch (instInfo->_encoding) {
case InstDB::kEncodingNone:
goto EmitDone;
@@ -854,6 +861,32 @@ CaseX86M_GPB_MulDiv:
}
break;
case InstDB::kEncodingX86R_FromM:
if (isign3 == ENC_OPS1(Mem)) {
rmRel = &o0;
rbReg = o0.id();
goto EmitX86RFromM;
}
break;
case InstDB::kEncodingX86R32_EDX_EAX:
// Explicit form: R32, EDX, EAX.
if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
if (!Reg::isGpd(o1, Gp::kIdDx) || !Reg::isGpd(o2, Gp::kIdAx))
goto InvalidInstruction;
rbReg = o0.id();
goto EmitX86R;
}
// Implicit form: R32.
if (isign3 == ENC_OPS1(Reg)) {
if (!Reg::isGpd(o0))
goto InvalidInstruction;
rbReg = o0.id();
goto EmitX86R;
}
break;
case InstDB::kEncodingX86R_Native:
if (isign3 == ENC_OPS1(Reg)) {
rbReg = o0.id();
@@ -2767,6 +2800,10 @@ CaseExtRm:
case InstDB::kEncodingVexOp:
goto EmitVexEvexOp;
case InstDB::kEncodingVexOpMod:
rbReg = 0;
goto EmitVexEvexR;
case InstDB::kEncodingVexKmov:
if (isign3 == ENC_OPS2(Reg, Reg)) {
opReg = o0.id();
@@ -3007,6 +3044,33 @@ CaseVexRvm_R:
goto CaseVexRvm;
}
case InstDB::kEncodingVexRvm_Lx_2xK: {
if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
// Two registers are encoded as a single register.
// - First K register must be even.
// - Second K register must be first+1.
if ((o0.id() & 1) != 0 || o0.id() + 1 != o1.id())
goto InvalidPhysId;
const Operand_& o3 = opExt[EmitterUtils::kOp3];
opcode |= x86OpcodeLBySize(o2.size());
opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
if (o3.isReg()) {
rbReg = o3.id();
goto EmitVexEvexR;
}
if (o3.isMem()) {
rmRel = &o3;
goto EmitVexEvexM;
}
}
break;
}
case InstDB::kEncodingVexRvmr_Lx: {
opcode |= x86OpcodeLBySize(o0.size() | o1.size());
ASMJIT_FALLTHROUGH;
@@ -3598,6 +3662,49 @@ CaseVexVmi_AfterImm:
}
break;
}
// ------------------------------------------------------------------------
// [AMX]
// ------------------------------------------------------------------------
case InstDB::kEncodingAmxCfg:
if (isign3 == ENC_OPS1(Mem)) {
rmRel = &o0;
goto EmitVexEvexM;
}
break;
case InstDB::kEncodingAmxR:
if (isign3 == ENC_OPS1(Reg)) {
opReg = o0.id();
rbReg = 0;
goto EmitVexEvexR;
}
break;
case InstDB::kEncodingAmxRm:
if (isign3 == ENC_OPS2(Reg, Mem)) {
opReg = o0.id();
rmRel = &o1;
goto EmitVexEvexM;
}
break;
case InstDB::kEncodingAmxMr:
if (isign3 == ENC_OPS2(Mem, Reg)) {
opReg = o1.id();
rmRel = &o0;
goto EmitVexEvexM;
}
break;
case InstDB::kEncodingAmxRmv:
if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
rbReg = o1.id();
goto EmitVexEvexR;
}
break;
}
goto InvalidInstruction;
@@ -3628,6 +3735,10 @@ EmitX86Op:
writer.emitImmediate(uint64_t(immValue), immSize);
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86 - Opcode + Reg]
// --------------------------------------------------------------------------
EmitX86OpReg:
// Emit mandatory instruction prefix.
writer.emitPP(opcode.v);
@@ -3649,8 +3760,11 @@ EmitX86OpReg:
writer.emitImmediate(uint64_t(immValue), immSize);
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86 - Opcode with implicit <mem> operand]
// --------------------------------------------------------------------------
EmitX86OpImplicitMem:
// NOTE: Don't change the emit order here, it's compatible with KeyStone/LLVM.
rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
goto InvalidInstruction;
@@ -3667,19 +3781,26 @@ EmitX86OpImplicitMem:
writer.emit8If(rex | kX86ByteRex, rex != 0);
}
// Emit override prefixes.
writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
// Emit instruction opcodes.
writer.emitMMAndOpcode(opcode.v);
// Emit immediate value.
writer.emitImmediate(uint64_t(immValue), immSize);
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86 - Opcode /r - register]
// --------------------------------------------------------------------------
EmitX86R:
// Mandatory instruction prefix.
writer.emitPP(opcode.v);
// Rex prefix (64-bit only).
// Emit REX prefix (64-bit only).
{
uint32_t rex = opcode.extractRex(options) |
((opReg & 0x08) >> 1) | // REX.R (0x04).
@@ -3694,32 +3815,80 @@ EmitX86R:
rbReg &= 0x07;
}
// Instruction opcodes.
// Emit instruction opcodes.
writer.emitMMAndOpcode(opcode.v);
// ModR.
// Emit ModR.
writer.emit8(x86EncodeMod(3, opReg, rbReg));
// Emit immediate value.
writer.emitImmediate(uint64_t(immValue), immSize);
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86 - Opcode /r - memory base]
// --------------------------------------------------------------------------
EmitX86RFromM:
rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
goto InvalidInstruction;
// Emit mandatory instruction prefix.
writer.emitPP(opcode.v);
// Emit REX prefix (64-bit only).
{
uint32_t rex = opcode.extractRex(options) |
((opReg & 0x08) >> 1) | // REX.R (0x04).
((rbReg ) >> 3) ; // REX.B (0x01).
if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
goto InvalidRexPrefix;
rex &= ~kX86ByteInvalidRex & 0xFF;
writer.emit8If(rex | kX86ByteRex, rex != 0);
opReg &= 0x07;
rbReg &= 0x07;
}
// Emit override prefixes.
writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
// Emit instruction opcodes.
writer.emitMMAndOpcode(opcode.v);
// Emit ModR/M.
writer.emit8(x86EncodeMod(3, opReg, rbReg));
// Emit immediate value.
writer.emitImmediate(uint64_t(immValue), immSize);
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - X86 - Opcode /r - memory operand]
// --------------------------------------------------------------------------
EmitX86M:
// `rmRel` operand must be memory.
ASMJIT_ASSERT(rmRel != nullptr);
ASMJIT_ASSERT(rmRel->opType() == Operand::kOpMem);
ASMJIT_ASSERT((opcode & Opcode::kCDSHL_Mask) == 0);
// Emit override prefixes.
rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
memOpAOMark = writer.cursor();
writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
// Mandatory instruction prefix.
// Emit mandatory instruction prefix.
writer.emitPP(opcode.v);
// Emit REX prefix (64-bit only).
rbReg = rmRel->as<Mem>().baseId();
rxReg = rmRel->as<Mem>().indexId();
// REX prefix (64-bit only).
{
uint32_t rex;
@@ -3738,8 +3907,9 @@ EmitX86M:
opReg &= 0x07;
}
// Instruction opcodes.
// Emit instruction opcodes.
writer.emitMMAndOpcode(opcode.v);
// ... Fall through ...
// --------------------------------------------------------------------------
@@ -3754,25 +3924,28 @@ EmitModSib:
relOffset = rmRel->as<Mem>().offsetLo32();
uint32_t mod = x86EncodeMod(0, opReg, rbReg);
if (rbReg == Gp::kIdSp) {
// [XSP|R12].
if (relOffset == 0) {
bool forceSIB = commonInfo->isTsibOp();
if (rbReg == Gp::kIdSp || forceSIB) {
// TSIB or [XSP|R12].
mod = (mod & 0xF8u) | 0x04u;
if (rbReg != Gp::kIdBp && relOffset == 0) {
writer.emit8(mod);
writer.emit8(x86EncodeSib(0, 4, 4));
writer.emit8(x86EncodeSib(0, 4, rbReg));
}
// [XSP|R12 + DISP8|DISP32].
// TSIB or [XSP|R12 + DISP8|DISP32].
else {
uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
int32_t cdOffset = relOffset >> cdShift;
if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
writer.emit8(mod + 0x40); // <- MOD(1, opReg, rbReg).
writer.emit8(x86EncodeSib(0, 4, 4));
writer.emit8(x86EncodeSib(0, 4, rbReg));
writer.emit8(cdOffset & 0xFF);
}
else {
writer.emit8(mod + 0x80); // <- MOD(2, opReg, rbReg).
writer.emit8(x86EncodeSib(0, 4, 4));
writer.emit8(x86EncodeSib(0, 4, rbReg));
writer.emit32uLE(uint32_t(relOffset));
}
}
@@ -4144,7 +4317,7 @@ EmitFpuOp:
goto EmitDone;
// --------------------------------------------------------------------------
// [Emit - VEX / EVEX]
// [Emit - VEX|EVEX]
// --------------------------------------------------------------------------
EmitVexEvexOp:
@@ -4181,6 +4354,10 @@ EmitVexEvexOp:
}
}
// --------------------------------------------------------------------------
// [Emit - VEX|EVEX - /r (Register)]
// --------------------------------------------------------------------------
EmitVexEvexR:
{
// Construct `x` - a complete EVEX|VEX prefix.
@@ -4288,6 +4465,10 @@ EmitVexEvexR:
}
}
// --------------------------------------------------------------------------
// [Emit - VEX|EVEX - /r (Memory)]
// --------------------------------------------------------------------------
EmitVexEvexM:
ASMJIT_ASSERT(rmRel != nullptr);
ASMJIT_ASSERT(rmRel->opType() == Operand::kOpMem);
@@ -4623,6 +4804,7 @@ EmitDone:
ERROR_HANDLER(InvalidAddressIndex)
ERROR_HANDLER(InvalidAddress64Bit)
ERROR_HANDLER(InvalidDisplacement)
ERROR_HANDLER(InvalidPhysId)
ERROR_HANDLER(InvalidSegment)
ERROR_HANDLER(InvalidImmediate)
ERROR_HANDLER(OperandSizeMismatch)

View File

@@ -48,7 +48,7 @@ Error Builder::finalize() {
Assembler a(_code);
a.addEncodingOptions(encodingOptions());
a.addValidationOptions(validationOptions());
return serialize(&a);
return serializeTo(&a);
}
// ============================================================================

View File

@@ -49,7 +49,7 @@ Error Compiler::finalize() {
Assembler a(_code);
a.addEncodingOptions(encodingOptions());
a.addValidationOptions(validationOptions());
return serialize(&a);
return serializeTo(&a);
}
// ============================================================================
// [asmjit::x86::Compiler - Events]

File diff suppressed because it is too large Load Diff

View File

@@ -259,7 +259,12 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept {
if (bitTest(regs.ecx, 27)) features.add(Features::kMOVDIRI);
if (bitTest(regs.ecx, 28)) features.add(Features::kMOVDIR64B);
if (bitTest(regs.ecx, 29)) features.add(Features::kENQCMD);
if (bitTest(regs.edx, 14)) features.add(Features::kSERIALIZE);
if (bitTest(regs.edx, 16)) features.add(Features::kTSXLDTRK);
if (bitTest(regs.edx, 18)) features.add(Features::kPCONFIG);
if (bitTest(regs.edx, 22)) features.add(Features::kAMX_BF16);
if (bitTest(regs.edx, 24)) features.add(Features::kAMX_TILE);
if (bitTest(regs.edx, 25)) features.add(Features::kAMX_INT8);
// Detect 'TSX' - Requires at least one of `HLE` and `RTM` features.
if (features.hasHLE() || features.hasRTM())
@@ -330,7 +335,7 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept {
uint32_t i = maxId;
// The highest EAX that we understand.
uint32_t kHighestProcessedEAX = 0x80000008u;
uint32_t kHighestProcessedEAX = 0x8000001Fu;
// Several CPUID calls are required to get the whole branc string. It's easy
// to copy one DWORD at a time instead of performing a byte copy.
@@ -357,8 +362,9 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept {
if (bitTest(regs.edx, 21)) features.add(Features::kFXSROPT);
if (bitTest(regs.edx, 22)) features.add(Features::kMMX2);
if (bitTest(regs.edx, 27)) features.add(Features::kRDTSCP);
if (bitTest(regs.edx, 29)) features.add(Features::kPREFETCHW);
if (bitTest(regs.edx, 30)) features.add(Features::k3DNOW2, Features::kMMX2);
if (bitTest(regs.edx, 31)) features.add(Features::k3DNOW);
if (bitTest(regs.edx, 31)) features.add(Features::kPREFETCHW);
if (cpu.hasFeature(Features::kAVX)) {
if (bitTest(regs.ecx, 11)) features.add(Features::kXOP);
@@ -379,12 +385,22 @@ ASMJIT_FAVOR_SIZE void detectCpu(CpuInfo& cpu) noexcept {
*brand++ = regs.ecx;
*brand++ = regs.edx;
// Go directly to the last one.
// Go directly to the next one we are interested in.
if (i == 0x80000004u) i = 0x80000008u - 1;
break;
case 0x80000008u:
if (bitTest(regs.ebx, 0)) features.add(Features::kCLZERO);
if (bitTest(regs.ebx, 0)) features.add(Features::kRDPRU);
if (bitTest(regs.ebx, 8)) features.add(Features::kMCOMMIT);
if (bitTest(regs.ebx, 9)) features.add(Features::kWBNOINVD);
// Go directly to the next one we are interested in.
i = 0x8000001Fu - 1;
break;
case 0x8000001Fu:
if (bitTest(regs.eax, 4)) features.add(Features::kSNP);
break;
}
} while (++i <= maxId);

View File

@@ -52,6 +52,9 @@ public:
kADX, //!< CPU has ADX (multi-precision add-carry instruction extensions).
kAESNI, //!< CPU has AESNI (AES encode/decode instructions).
kALTMOVCR8, //!< CPU has LOCK MOV R<->CR0 (supports `MOV R<->CR8` via `LOCK MOV R<->CR0` in 32-bit mode) [AMD].
kAMX_BF16, //!< CPU has AMX_BF16 (advanced matrix extensions - BF16 instructions).
kAMX_INT8, //!< CPU has AMX_INT8 (advanced matrix extensions - INT8 instructions).
kAMX_TILE, //!< CPU has AMX_TILE (advanced matrix extensions).
kAVX, //!< CPU has AVX (advanced vector extensions).
kAVX2, //!< CPU has AVX2 (advanced vector extensions 2).
kAVX512_4FMAPS, //!< CPU has AVX512_FMAPS (FMA packed single).
@@ -98,6 +101,7 @@ public:
kLAHFSAHF, //!< CPU has LAHF/SAHF (LAHF/SAHF in 64-bit mode) [X86_64].
kLWP, //!< CPU has LWP (lightweight profiling) [AMD].
kLZCNT, //!< CPU has LZCNT (LZCNT instruction).
kMCOMMIT, //!< CPU has MCOMMIT (MCOMMIT instruction).
kMMX, //!< CPU has MMX (MMX base instructions).
kMMX2, //!< CPU has MMX2 (MMX extensions or MMX2).
kMONITOR, //!< CPU has MONITOR (MONITOR/MWAIT instructions).
@@ -116,16 +120,19 @@ public:
kPREFETCHW, //!< CPU has PREFETCHW.
kPREFETCHWT1, //!< CPU has PREFETCHWT1.
kRDPID, //!< CPU has RDPID.
kRDPRU, //!< CPU has RDPRU.
kRDRAND, //!< CPU has RDRAND.
kRDSEED, //!< CPU has RDSEED.
kRDTSC, //!< CPU has RDTSC.
kRDTSCP, //!< CPU has RDTSCP.
kRTM, //!< CPU has RTM.
kSERIALIZE, //!< CPU has SERIALIZE.
kSHA, //!< CPU has SHA (SHA-1 and SHA-256 instructions).
kSKINIT, //!< CPU has SKINIT (SKINIT/STGI instructions) [AMD].
kSMAP, //!< CPU has SMAP (supervisor-mode access prevention).
kSMEP, //!< CPU has SMEP (supervisor-mode execution prevention).
kSMX, //!< CPU has SMX (safer mode extensions).
kSNP, //!< CPU has SNP.
kSSE, //!< CPU has SSE.
kSSE2, //!< CPU has SSE2.
kSSE3, //!< CPU has SSE3.
@@ -136,6 +143,7 @@ public:
kSVM, //!< CPU has SVM (virtualization) [AMD].
kTBM, //!< CPU has TBM (trailing bit manipulation) [AMD].
kTSX, //!< CPU has TSX.
kTSXLDTRK, //!< CPU has TSXLDTRK.
kVAES, //!< CPU has VAES (vector AES 256|512 bit support).
kVMX, //!< CPU has VMX (virtualization) [INTEL].
kVPCLMULQDQ, //!< CPU has VPCLMULQDQ (vector PCLMULQDQ 256|512-bit support).
@@ -183,6 +191,9 @@ public:
ASMJIT_X86_FEATURE(ADX)
ASMJIT_X86_FEATURE(AESNI)
ASMJIT_X86_FEATURE(ALTMOVCR8)
ASMJIT_X86_FEATURE(AMX_BF16)
ASMJIT_X86_FEATURE(AMX_INT8)
ASMJIT_X86_FEATURE(AMX_TILE)
ASMJIT_X86_FEATURE(AVX)
ASMJIT_X86_FEATURE(AVX2)
ASMJIT_X86_FEATURE(AVX512_4FMAPS)
@@ -229,6 +240,7 @@ public:
ASMJIT_X86_FEATURE(LAHFSAHF)
ASMJIT_X86_FEATURE(LWP)
ASMJIT_X86_FEATURE(LZCNT)
ASMJIT_X86_FEATURE(MCOMMIT)
ASMJIT_X86_FEATURE(MMX)
ASMJIT_X86_FEATURE(MMX2)
ASMJIT_X86_FEATURE(MONITOR)
@@ -247,16 +259,19 @@ public:
ASMJIT_X86_FEATURE(PREFETCHW)
ASMJIT_X86_FEATURE(PREFETCHWT1)
ASMJIT_X86_FEATURE(RDPID)
ASMJIT_X86_FEATURE(RDPRU)
ASMJIT_X86_FEATURE(RDRAND)
ASMJIT_X86_FEATURE(RDSEED)
ASMJIT_X86_FEATURE(RDTSC)
ASMJIT_X86_FEATURE(RDTSCP)
ASMJIT_X86_FEATURE(RTM)
ASMJIT_X86_FEATURE(SERIALIZE)
ASMJIT_X86_FEATURE(SHA)
ASMJIT_X86_FEATURE(SKINIT)
ASMJIT_X86_FEATURE(SMAP)
ASMJIT_X86_FEATURE(SMEP)
ASMJIT_X86_FEATURE(SMX)
ASMJIT_X86_FEATURE(SNP)
ASMJIT_X86_FEATURE(SSE)
ASMJIT_X86_FEATURE(SSE2)
ASMJIT_X86_FEATURE(SSE3)
@@ -267,6 +282,7 @@ public:
ASMJIT_X86_FEATURE(SVM)
ASMJIT_X86_FEATURE(TBM)
ASMJIT_X86_FEATURE(TSX)
ASMJIT_X86_FEATURE(TSXLDTRK)
ASMJIT_X86_FEATURE(XSAVE)
ASMJIT_X86_FEATURE(XSAVEC)
ASMJIT_X86_FEATURE(XSAVEOPT)

View File

@@ -78,6 +78,7 @@ struct RegFormatInfo_T {
X == Reg::kTypeDReg ? 62 :
X == Reg::kTypeSt ? 47 :
X == Reg::kTypeBnd ? 55 :
X == Reg::kTypeTmm ? 65 :
X == Reg::kTypeRip ? 39 : 0,
kFormatIndex = X == Reg::kTypeGpbLo ? 1 :
@@ -95,6 +96,7 @@ struct RegFormatInfo_T {
X == Reg::kTypeDReg ? 80 :
X == Reg::kTypeSt ? 55 :
X == Reg::kTypeBnd ? 69 :
X == Reg::kTypeTmm ? 89 :
X == Reg::kTypeRip ? 43 : 0,
kSpecialIndex = X == Reg::kTypeGpbLo ? 96 :
@@ -146,7 +148,9 @@ static const RegFormatInfo x86RegFormatInfo = {
"k\0" // #53
"bnd\0" // #55
"cr\0" // #59
"dr\0", // #62
"dr\0" // #62
"tmm\0" // #65
,
// Register name entries and strings.
{ ASMJIT_LOOKUP_TABLE_32(ASMJIT_REG_NAME_ENTRY, 0) },
@@ -170,7 +174,8 @@ static const RegFormatInfo x86RegFormatInfo = {
"dr%u\0" // #80
"rip\0" // #85
"\0\0\0\0\0\0\0" // #89
"tmm%u\0" // #89
"\0" // #95
"al\0\0" "cl\0\0" "dl\0\0" "bl\0\0" "spl\0" "bpl\0" "sil\0" "dil\0" // #96
"ah\0\0" "ch\0\0" "dh\0\0" "bh\0\0" "n/a\0" "n/a\0" "n/a\0" "n/a\0" // #128
@@ -211,6 +216,9 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"ADX\0"
"AESNI\0"
"ALTMOVCR8\0"
"AMX_BF16\0"
"AMX_INT8\0"
"AMX_TILE\0"
"AVX\0"
"AVX2\0"
"AVX512_4FMAPS\0"
@@ -257,6 +265,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"LAHFSAHF\0"
"LWP\0"
"LZCNT\0"
"MCOMMIT\0"
"MMX\0"
"MMX2\0"
"MONITOR\0"
@@ -275,16 +284,19 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"PREFETCHW\0"
"PREFETCHWT1\0"
"RDPID\0"
"RDPRU\0"
"RDRAND\0"
"RDSEED\0"
"RDTSC\0"
"RDTSCP\0"
"RTM\0"
"SERIALIZE\0"
"SHA\0"
"SKINIT\0"
"SMAP\0"
"SMEP\0"
"SMX\0"
"SNP\0"
"SSE\0"
"SSE2\0"
"SSE3\0"
@@ -295,6 +307,7 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"SVM\0"
"TBM\0"
"TSX\0"
"TSXLDTRK\0"
"VAES\0"
"VMX\0"
"VPCLMULQDQ\0"
@@ -308,13 +321,14 @@ Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept
"<Unknown>\0";
static const uint16_t sFeatureIndex[] = {
0, 5, 8, 11, 17, 24, 28, 34, 44, 48, 53, 67, 81, 93, 107, 117, 128, 138,
149, 158, 170, 181, 193, 206, 216, 228, 248, 265, 269, 274, 283, 291, 302,
307, 314, 319, 330, 340, 346, 353, 358, 363, 367, 372, 376, 385, 390, 398,
404, 409, 413, 418, 427, 431, 437, 441, 446, 454, 463, 469, 479, 487, 491,
495, 500, 508, 518, 526, 534, 541, 551, 563, 569, 576, 583, 589, 596, 600,
604, 611, 616, 621, 625, 629, 634, 639, 646, 653, 659, 665, 669, 673, 677,
682, 686, 697, 705, 714, 718, 724, 731, 740, 747
0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 62, 71, 75, 80, 94, 108, 120, 134, 144,
155, 165, 176, 185, 197, 208, 220, 233, 243, 255, 275, 292, 296, 301, 310,
318, 329, 334, 341, 346, 357, 367, 373, 380, 385, 390, 394, 399, 403, 412,
417, 425, 431, 436, 440, 445, 454, 458, 464, 472, 476, 481, 489, 498, 504,
514, 522, 526, 530, 535, 543, 553, 561, 569, 576, 586, 598, 604, 610, 617,
624, 630, 637, 641, 651, 655, 662, 667, 672, 676, 680, 684, 689, 694, 701,
708, 714, 720, 724, 728, 732, 741, 746, 750, 761, 769, 778, 782, 788, 795,
804, 811
};
// @EnumStringEnd@

View File

@@ -422,6 +422,7 @@ struct Inst : public BaseInst {
kIdLddqu, //!< Instruction 'lddqu' {SSE3}.
kIdLdmxcsr, //!< Instruction 'ldmxcsr' {SSE}.
kIdLds, //!< Instruction 'lds' (X86).
kIdLdtilecfg, //!< Instruction 'ldtilecfg' {AMX_TILE} (X64).
kIdLea, //!< Instruction 'lea'.
kIdLeave, //!< Instruction 'leave'.
kIdLes, //!< Instruction 'les' (X86).
@@ -449,6 +450,7 @@ struct Inst : public BaseInst {
kIdMaxps, //!< Instruction 'maxps' {SSE}.
kIdMaxsd, //!< Instruction 'maxsd' {SSE2}.
kIdMaxss, //!< Instruction 'maxss' {SSE}.
kIdMcommit, //!< Instruction 'mcommit' {MCOMMIT}.
kIdMfence, //!< Instruction 'mfence' {SSE2}.
kIdMinpd, //!< Instruction 'minpd' {SSE2}.
kIdMinps, //!< Instruction 'minps' {SSE}.
@@ -550,6 +552,7 @@ struct Inst : public BaseInst {
kIdPcmpistri, //!< Instruction 'pcmpistri' {SSE4_2}.
kIdPcmpistrm, //!< Instruction 'pcmpistrm' {SSE4_2}.
kIdPcommit, //!< Instruction 'pcommit' {PCOMMIT}.
kIdPconfig, //!< Instruction 'pconfig' {PCONFIG}.
kIdPdep, //!< Instruction 'pdep' {BMI2}.
kIdPext, //!< Instruction 'pext' {BMI2}.
kIdPextrb, //!< Instruction 'pextrb' {SSE4_1}.
@@ -653,6 +656,7 @@ struct Inst : public BaseInst {
kIdPslldq, //!< Instruction 'pslldq' {SSE2}.
kIdPsllq, //!< Instruction 'psllq' {MMX|SSE2}.
kIdPsllw, //!< Instruction 'psllw' {MMX|SSE2}.
kIdPsmash, //!< Instruction 'psmash' {SNP} (X64).
kIdPsrad, //!< Instruction 'psrad' {MMX|SSE2}.
kIdPsraw, //!< Instruction 'psraw' {MMX|SSE2}.
kIdPsrld, //!< Instruction 'psrld' {MMX|SSE2}.
@@ -683,6 +687,7 @@ struct Inst : public BaseInst {
kIdPushf, //!< Instruction 'pushf'.
kIdPushfd, //!< Instruction 'pushfd' (X86).
kIdPushfq, //!< Instruction 'pushfq' (X64).
kIdPvalidate, //!< Instruction 'pvalidate' {SNP}.
kIdPxor, //!< Instruction 'pxor' {MMX|SSE2}.
kIdRcl, //!< Instruction 'rcl'.
kIdRcpps, //!< Instruction 'rcpps' {SSE}.
@@ -693,11 +698,14 @@ struct Inst : public BaseInst {
kIdRdmsr, //!< Instruction 'rdmsr' {MSR}.
kIdRdpid, //!< Instruction 'rdpid' {RDPID}.
kIdRdpmc, //!< Instruction 'rdpmc'.
kIdRdpru, //!< Instruction 'rdpru' {RDPRU}.
kIdRdrand, //!< Instruction 'rdrand' {RDRAND}.
kIdRdseed, //!< Instruction 'rdseed' {RDSEED}.
kIdRdtsc, //!< Instruction 'rdtsc' {RDTSC}.
kIdRdtscp, //!< Instruction 'rdtscp' {RDTSCP}.
kIdRet, //!< Instruction 'ret'.
kIdRmpadjust, //!< Instruction 'rmpadjust' {SNP} (X64).
kIdRmpupdate, //!< Instruction 'rmpupdate' {SNP} (X64).
kIdRol, //!< Instruction 'rol'.
kIdRor, //!< Instruction 'ror'.
kIdRorx, //!< Instruction 'rorx' {BMI2}.
@@ -714,6 +722,7 @@ struct Inst : public BaseInst {
kIdSarx, //!< Instruction 'sarx' {BMI2}.
kIdSbb, //!< Instruction 'sbb'.
kIdScas, //!< Instruction 'scas'.
kIdSerialize, //!< Instruction 'serialize' {SERIALIZE}.
kIdSeta, //!< Instruction 'seta'.
kIdSetae, //!< Instruction 'setae'.
kIdSetb, //!< Instruction 'setb'.
@@ -778,6 +787,7 @@ struct Inst : public BaseInst {
kIdStmxcsr, //!< Instruction 'stmxcsr' {SSE}.
kIdStos, //!< Instruction 'stos'.
kIdStr, //!< Instruction 'str'.
kIdSttilecfg, //!< Instruction 'sttilecfg' {AMX_TILE} (X64).
kIdSub, //!< Instruction 'sub'.
kIdSubpd, //!< Instruction 'subpd' {SSE2}.
kIdSubps, //!< Instruction 'subps' {SSE}.
@@ -791,12 +801,25 @@ struct Inst : public BaseInst {
kIdSysret, //!< Instruction 'sysret' (X64).
kIdSysret64, //!< Instruction 'sysret64' (X64).
kIdT1mskc, //!< Instruction 't1mskc' {TBM}.
kIdTdpbf16ps, //!< Instruction 'tdpbf16ps' {AMX_BF16} (X64).
kIdTdpbssd, //!< Instruction 'tdpbssd' {AMX_INT8} (X64).
kIdTdpbsud, //!< Instruction 'tdpbsud' {AMX_INT8} (X64).
kIdTdpbusd, //!< Instruction 'tdpbusd' {AMX_INT8} (X64).
kIdTdpbuud, //!< Instruction 'tdpbuud' {AMX_INT8} (X64).
kIdTest, //!< Instruction 'test'.
kIdTileloadd, //!< Instruction 'tileloadd' {AMX_TILE} (X64).
kIdTileloaddt1, //!< Instruction 'tileloaddt1' {AMX_TILE} (X64).
kIdTilerelease, //!< Instruction 'tilerelease' {AMX_TILE} (X64).
kIdTilestored, //!< Instruction 'tilestored' {AMX_TILE} (X64).
kIdTilezero, //!< Instruction 'tilezero' {AMX_TILE} (X64).
kIdTpause, //!< Instruction 'tpause' {WAITPKG}.
kIdTzcnt, //!< Instruction 'tzcnt' {BMI}.
kIdTzmsk, //!< Instruction 'tzmsk' {TBM}.
kIdUcomisd, //!< Instruction 'ucomisd' {SSE2}.
kIdUcomiss, //!< Instruction 'ucomiss' {SSE}.
kIdUd2, //!< Instruction 'ud2'.
kIdUmonitor, //!< Instruction 'umonitor' {WAITPKG}.
kIdUmwait, //!< Instruction 'umwait' {WAITPKG}.
kIdUnpckhpd, //!< Instruction 'unpckhpd' {SSE2}.
kIdUnpckhps, //!< Instruction 'unpckhps' {SSE}.
kIdUnpcklpd, //!< Instruction 'unpcklpd' {SSE2}.
@@ -1119,6 +1142,8 @@ struct Inst : public BaseInst {
kIdVmxon, //!< Instruction 'vmxon' {VMX}.
kIdVorpd, //!< Instruction 'vorpd' {AVX|AVX512_DQ+VL}.
kIdVorps, //!< Instruction 'vorps' {AVX|AVX512_DQ+VL}.
kIdVp2intersectd, //!< Instruction 'vp2intersectd' {AVX512_VP2INTERSECT}.
kIdVp2intersectq, //!< Instruction 'vp2intersectq' {AVX512_VP2INTERSECT}.
kIdVp4dpwssd, //!< Instruction 'vp4dpwssd' {AVX512_4VNNIW}.
kIdVp4dpwssds, //!< Instruction 'vp4dpwssds' {AVX512_4VNNIW}.
kIdVpabsb, //!< Instruction 'vpabsb' {AVX|AVX2|AVX512_BW+VL}.
@@ -1538,6 +1563,7 @@ struct Inst : public BaseInst {
kIdXor, //!< Instruction 'xor'.
kIdXorpd, //!< Instruction 'xorpd' {SSE2}.
kIdXorps, //!< Instruction 'xorps' {SSE}.
kIdXresldtrk, //!< Instruction 'xresldtrk' {TSXLDTRK}.
kIdXrstor, //!< Instruction 'xrstor' {XSAVE}.
kIdXrstor64, //!< Instruction 'xrstor64' {XSAVE} (X64).
kIdXrstors, //!< Instruction 'xrstors' {XSAVES}.
@@ -1551,6 +1577,7 @@ struct Inst : public BaseInst {
kIdXsaves, //!< Instruction 'xsaves' {XSAVES}.
kIdXsaves64, //!< Instruction 'xsaves64' {XSAVES} (X64).
kIdXsetbv, //!< Instruction 'xsetbv' {XSAVE}.
kIdXsusldtrk, //!< Instruction 'xsusldtrk' {TSXLDTRK}.
kIdXtest, //!< Instruction 'xtest' {TSX}.
_kIdCount
// ${InstId:End}

View File

@@ -142,6 +142,7 @@ struct X86ValidationData {
(X == Reg::kTypeDReg ) ? InstDB::kOpDReg : \
(X == Reg::kTypeSt ) ? InstDB::kOpSt : \
(X == Reg::kTypeBnd ) ? InstDB::kOpBnd : \
(X == Reg::kTypeTmm ) ? InstDB::kOpTmm : \
(X == Reg::kTypeRip ) ? InstDB::kOpNone : InstDB::kOpNone
static const uint32_t _x86OpFlagFromRegType[Reg::kTypeMax + 1] = { ASMJIT_LOOKUP_TABLE_32(VALUE, 0) };
#undef VALUE
@@ -162,6 +163,7 @@ static const uint32_t _x86OpFlagFromRegType[Reg::kTypeMax + 1] = { ASMJIT_LOOKUP
(X == Reg::kTypeDReg ) ? 0x000000FFu : \
(X == Reg::kTypeSt ) ? 0x000000FFu : \
(X == Reg::kTypeBnd ) ? 0x0000000Fu : \
(X == Reg::kTypeTmm ) ? 0x000000FFu : \
(X == Reg::kTypeRip ) ? 0x00000001u : 0u
#define REG_MASK_FROM_REG_TYPE_X64(X) \
@@ -180,6 +182,7 @@ static const uint32_t _x86OpFlagFromRegType[Reg::kTypeMax + 1] = { ASMJIT_LOOKUP
(X == Reg::kTypeDReg ) ? 0x0000FFFFu : \
(X == Reg::kTypeSt ) ? 0x000000FFu : \
(X == Reg::kTypeBnd ) ? 0x0000000Fu : \
(X == Reg::kTypeTmm ) ? 0x000000FFu : \
(X == Reg::kTypeRip ) ? 0x00000001u : 0u
static const X86ValidationData _x86ValidationData = {
@@ -821,13 +824,15 @@ Error InstInternal::queryRWInfo(uint32_t arch, const BaseInst& inst, const Opera
const InstDB::CommonInfoTableB& tabB = InstDB::_commonInfoTableB[InstDB::_instInfoTable[instId]._commonInfoIndexB];
const InstDB::RWFlagsInfoTable& rwFlags = InstDB::_rwFlagsInfoTable[tabB._rwFlagsIndex];
// Each RWInfo contains two indexes
// [0] - OpCount == 2
// [1] - OpCount != 2
// They are used this way as there are instructions that have 2 and 3
// operand overloads that use different semantics. So instead of adding
// more special cases we just separated their data tables.
const InstDB::RWInfo& instRwInfo = InstDB::rwInfo[InstDB::rwInfoIndex[instId * 2u + uint32_t(opCount != 2)]];
// There are two data tables, one for `opCount == 2` and the second for
// `opCount != 2`. There are two reasons for that:
// - There are instructions that share the same name that have both 2
// or 3 operands, which have different RW information / semantics.
// - There must be 2 tables otherwise the lookup index won't fit into
// 8 bits (there is more than 256 records of combined rwInfo A and B).
const InstDB::RWInfo& instRwInfo = opCount == 2 ? InstDB::rwInfoA[InstDB::rwInfoIndexA[instId]]
: InstDB::rwInfoB[InstDB::rwInfoIndexB[instId]];
const InstDB::RWInfoRm& instRmInfo = InstDB::rwInfoRm[instRwInfo.rmInfo];
out->_instFlags = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -74,17 +74,18 @@ enum OpFlags : uint32_t {
kOpDReg = 0x00001000u, //!< Operand can be DReg (debug register).
kOpSt = 0x00002000u, //!< Operand can be 80-bit ST register (X87).
kOpBnd = 0x00004000u, //!< Operand can be 128-bit BND register.
kOpAllRegs = 0x00007FFFu, //!< Combination of all possible registers.
kOpTmm = 0x00008000u, //!< Operand can be 0..8192-bit TMM register.
kOpAllRegs = 0x0000FFFFu, //!< Combination of all possible registers.
kOpI4 = 0x00010000u, //!< Operand can be unsigned 4-bit immediate.
kOpU4 = 0x00020000u, //!< Operand can be unsigned 4-bit immediate.
kOpI8 = 0x00040000u, //!< Operand can be signed 8-bit immediate.
kOpU8 = 0x00080000u, //!< Operand can be unsigned 8-bit immediate.
kOpI16 = 0x00100000u, //!< Operand can be signed 16-bit immediate.
kOpI4 = 0x00010000u, //!< Operand can be unsigned 4-bit immediate.
kOpU4 = 0x00020000u, //!< Operand can be unsigned 4-bit immediate.
kOpI8 = 0x00040000u, //!< Operand can be signed 8-bit immediate.
kOpU8 = 0x00080000u, //!< Operand can be unsigned 8-bit immediate.
kOpI16 = 0x00100000u, //!< Operand can be signed 16-bit immediate.
kOpU16 = 0x00200000u, //!< Operand can be unsigned 16-bit immediate.
kOpI32 = 0x00400000u, //!< Operand can be signed 32-bit immediate.
kOpI32 = 0x00400000u, //!< Operand can be signed 32-bit immediate.
kOpU32 = 0x00800000u, //!< Operand can be unsigned 32-bit immediate.
kOpI64 = 0x01000000u, //!< Operand can be signed 64-bit immediate.
kOpI64 = 0x01000000u, //!< Operand can be signed 64-bit immediate.
kOpU64 = 0x02000000u, //!< Operand can be unsigned 64-bit immediate.
kOpAllImm = 0x03FF0000u, //!< Operand can be any immediate.
@@ -129,7 +130,8 @@ enum MemFlags : uint32_t {
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.
kMemOpMib = 0x4000u, //!< Operand must be MIB (base+index) pointer.
kMemOpTMem = 0x8000u //!< Operand is a sib_mem (ADX memory operand).
};
// ============================================================================
@@ -156,6 +158,7 @@ enum Flags : uint32_t {
//
// These describe optional X86 prefixes that can be used to change the instruction's operation.
kFlagTsib = 0x00000800u, //!< Instruction uses TSIB (or SIB_MEM) encoding (MODRM followed by SIB).
kFlagRep = 0x00001000u, //!< Instruction can be prefixed with using the REP(REPE) or REPNE prefix.
kFlagRepIgnored = 0x00002000u, //!< Instruction ignores REP|REPNE prefixes, but they are accepted.
kFlagLock = 0x00004000u, //!< Instruction can be prefixed with using the LOCK prefix.
@@ -319,6 +322,8 @@ struct CommonInfo {
inline bool isMibOp() const noexcept { return hasFlag(kFlagMib); }
//! Tests whether the instruction uses VSIB.
inline bool isVsibOp() const noexcept { return hasFlag(kFlagVsib); }
//! Tests whether the instruction uses TSIB (AMX, instruction requires MOD+SIB).
inline bool isTsibOp() const noexcept { return hasFlag(kFlagTsib); }
//! Tests whether the instruction uses VEX (can be set together with EVEX if both are encodable).
inline bool isVex() const noexcept { return hasFlag(kFlagVex); }
//! Tests whether the instruction uses EVEX (can be set together with VEX if both are encodable).

View File

@@ -62,6 +62,8 @@ enum EncodingId : uint32_t {
kEncodingX86M_Only, //!< X86 [M] (restricted to memory operand of any size).
kEncodingX86M_Nop, //!< X86 [M] (special case of NOP instruction).
kEncodingX86R_Native, //!< X86 [R] (register must be either 32-bit or 64-bit depending on arch).
kEncodingX86R_FromM, //!< X86 [R] - which specifies memory address.
kEncodingX86R32_EDX_EAX, //!< X86 [R32] followed by implicit EDX and EAX.
kEncodingX86Rm, //!< X86 [RM] (doesn't handle single-byte size).
kEncodingX86Rm_Raw66H, //!< X86 [RM] (used by LZCNT, POPCNT, and TZCNT).
kEncodingX86Rm_NoSize, //!< X86 [RM] (doesn't add REX.W prefix if 64-bit reg is used).
@@ -132,6 +134,7 @@ enum EncodingId : uint32_t {
kEncodingExtInsertq, //!< EXT insrq (SSE4A).
kEncodingExt3dNow, //!< EXT [RMI] (3DNOW specific).
kEncodingVexOp, //!< VEX [OP].
kEncodingVexOpMod, //!< VEX [OP] with MODR/M.
kEncodingVexKmov, //!< VEX [RM|MR] (used by kmov[b|w|d|q]).
kEncodingVexR_Wx, //!< VEX|EVEX [R] (propagatex VEX.W if GPQ used).
kEncodingVexM, //!< VEX|EVEX [M].
@@ -154,6 +157,7 @@ enum EncodingId : uint32_t {
kEncodingVexRvm_Wx, //!< VEX|EVEX [RVM] (propagates VEX|EVEX.W if GPQ used).
kEncodingVexRvm_ZDX_Wx, //!< VEX|EVEX [RVM<ZDX>] (propagates VEX|EVEX.W if GPQ used).
kEncodingVexRvm_Lx, //!< VEX|EVEX [RVM] (propagates VEX|EVEX.L if YMM used).
kEncodingVexRvm_Lx_2xK, //!< VEX|EVEX [RVM] (vp2intersectd/vp2intersectq).
kEncodingVexRvmr, //!< VEX|EVEX [RVMR].
kEncodingVexRvmr_Lx, //!< VEX|EVEX [RVMR] (propagates VEX|EVEX.L if YMM used).
kEncodingVexRvmi, //!< VEX|EVEX [RVMI].
@@ -187,6 +191,11 @@ enum EncodingId : uint32_t {
kEncodingVexMovssMovsd, //!< VEX|EVEX vmovss, vmovsd.
kEncodingFma4, //!< FMA4 [R, R, R/M, R/M].
kEncodingFma4_Lx, //!< FMA4 [R, R, R/M, R/M] (propagates AVX.L if YMM used).
kEncodingAmxCfg, //!< AMX ldtilecfg/sttilecfg.
kEncodingAmxR, //!< AMX [R] - tilezero.
kEncodingAmxRm, //!< AMX tileloadd/tileloaddt1.
kEncodingAmxMr, //!< AMX tilestored.
kEncodingAmxRmv, //!< AMX instructions that use TMM registers.
kEncodingCount //!< Count of instruction encodings.
};
@@ -288,8 +297,10 @@ struct RWFlagsInfoTable {
uint32_t writeFlags;
};
extern const uint8_t rwInfoIndex[Inst::_kIdCount * 2];
extern const RWInfo rwInfo[];
extern const uint8_t rwInfoIndexA[Inst::_kIdCount];
extern const uint8_t rwInfoIndexB[Inst::_kIdCount];
extern const RWInfo rwInfoA[];
extern const RWInfo rwInfoB[];
extern const RWInfoOp rwInfoOp[];
extern const RWInfoRm rwInfoRm[];
extern const RWFlagsInfoTable _rwFlagsInfoTable[];

View File

@@ -337,14 +337,17 @@ struct Opcode {
k000F3A = kPP_00 | kMM_0F3A, // '0F3A'
k660000 = kPP_66 | kMM_00, // '66'
k660F00 = kPP_66 | kMM_0F, // '660F'
k660F01 = kPP_66 | kMM_0F01, // '660F01'
k660F38 = kPP_66 | kMM_0F38, // '660F38'
k660F3A = kPP_66 | kMM_0F3A, // '660F3A'
kF20000 = kPP_F2 | kMM_00, // 'F2'
kF20F00 = kPP_F2 | kMM_0F, // 'F20F'
kF20F01 = kPP_F2 | kMM_0F01, // 'F20F01'
kF20F38 = kPP_F2 | kMM_0F38, // 'F20F38'
kF20F3A = kPP_F2 | kMM_0F3A, // 'F20F3A'
kF30000 = kPP_F3 | kMM_00, // 'F3'
kF30F00 = kPP_F3 | kMM_0F, // 'F30F'
kF30F01 = kPP_F3 | kMM_0F01, // 'F30F01'
kF30F38 = kPP_F3 | kMM_0F38, // 'F30F38'
kF30F3A = kPP_F3 | kMM_0F3A, // 'F30F3A'
kFPU_00 = kPP_00 | kMM_00, // '__' (FPU)

View File

@@ -108,6 +108,7 @@ class CReg;
class DReg;
class St;
class Bnd;
class Tmm;
class Rip;
// ============================================================================
@@ -142,7 +143,8 @@ ASMJIT_DEFINE_REG_TRAITS(CReg , BaseReg::kTypeCustom + 1, BaseReg::kGroupVirt +
ASMJIT_DEFINE_REG_TRAITS(DReg , BaseReg::kTypeCustom + 2, BaseReg::kGroupVirt + 2, 0 , 16, Type::kIdVoid );
ASMJIT_DEFINE_REG_TRAITS(St , BaseReg::kTypeCustom + 3, BaseReg::kGroupVirt + 3, 10, 8 , Type::kIdF80 );
ASMJIT_DEFINE_REG_TRAITS(Bnd , BaseReg::kTypeCustom + 4, BaseReg::kGroupVirt + 4, 16, 4 , Type::kIdVoid );
ASMJIT_DEFINE_REG_TRAITS(Rip , BaseReg::kTypeIP , BaseReg::kGroupVirt + 5, 0 , 1 , Type::kIdVoid );
ASMJIT_DEFINE_REG_TRAITS(Tmm , BaseReg::kTypeCustom + 5, BaseReg::kGroupVirt + 5, 0 , 8 , Type::kIdVoid );
ASMJIT_DEFINE_REG_TRAITS(Rip , BaseReg::kTypeIP , BaseReg::kGroupVirt + 6, 0 , 1 , Type::kIdVoid );
//! \endcond
//! Register (X86).
@@ -152,41 +154,78 @@ public:
//! Register type.
enum RegType : uint32_t {
kTypeNone = BaseReg::kTypeNone, //!< No register type or invalid register.
kTypeGpbLo = BaseReg::kTypeGp8Lo, //!< Low GPB register (AL, BL, CL, DL, ...).
kTypeGpbHi = BaseReg::kTypeGp8Hi, //!< High GPB register (AH, BH, CH, DH only).
kTypeGpw = BaseReg::kTypeGp16, //!< GPW register.
kTypeGpd = BaseReg::kTypeGp32, //!< GPD register.
kTypeGpq = BaseReg::kTypeGp64, //!< GPQ register (64-bit).
kTypeXmm = BaseReg::kTypeVec128, //!< XMM register (SSE+).
kTypeYmm = BaseReg::kTypeVec256, //!< YMM register (AVX+).
kTypeZmm = BaseReg::kTypeVec512, //!< ZMM register (AVX512+).
kTypeMm = BaseReg::kTypeOther0, //!< MMX register.
kTypeKReg = BaseReg::kTypeOther1, //!< K register (AVX512+).
kTypeSReg = BaseReg::kTypeCustom+0, //!< Segment register (None, ES, CS, SS, DS, FS, GS).
kTypeCReg = BaseReg::kTypeCustom+1, //!< Control register (CR).
kTypeDReg = BaseReg::kTypeCustom+2, //!< Debug register (DR).
kTypeSt = BaseReg::kTypeCustom+3, //!< FPU (x87) register.
kTypeBnd = BaseReg::kTypeCustom+4, //!< Bound register (BND).
kTypeRip = BaseReg::kTypeIP, //!< Instruction pointer (EIP, RIP).
kTypeCount = BaseReg::kTypeCustom+5 //!< Count of register types.
//! No register type or invalid register.
kTypeNone = BaseReg::kTypeNone,
//! Low GPB register (AL, BL, CL, DL, ...).
kTypeGpbLo = BaseReg::kTypeGp8Lo,
//! High GPB register (AH, BH, CH, DH only).
kTypeGpbHi = BaseReg::kTypeGp8Hi,
//! GPW register.
kTypeGpw = BaseReg::kTypeGp16,
//! GPD register.
kTypeGpd = BaseReg::kTypeGp32,
//! GPQ register (64-bit).
kTypeGpq = BaseReg::kTypeGp64,
//! XMM register (SSE+).
kTypeXmm = BaseReg::kTypeVec128,
//! YMM register (AVX+).
kTypeYmm = BaseReg::kTypeVec256,
//! ZMM register (AVX512+).
kTypeZmm = BaseReg::kTypeVec512,
//! MMX register.
kTypeMm = BaseReg::kTypeOther0,
//! K register (AVX512+).
kTypeKReg = BaseReg::kTypeOther1,
//! Instruction pointer (EIP, RIP).
kTypeRip = BaseReg::kTypeIP,
//! Segment register (None, ES, CS, SS, DS, FS, GS).
kTypeSReg = BaseReg::kTypeCustom + 0,
//! Control register (CR).
kTypeCReg = BaseReg::kTypeCustom + 1,
//! Debug register (DR).
kTypeDReg = BaseReg::kTypeCustom + 2,
//! FPU (x87) register.
kTypeSt = BaseReg::kTypeCustom + 3,
//! Bound register (BND).
kTypeBnd = BaseReg::kTypeCustom + 4,
//! TMM register (AMX_TILE)
kTypeTmm = BaseReg::kTypeCustom + 5,
//! Count of register types.
kTypeCount = BaseReg::kTypeCustom + 6
};
//! Register group.
enum RegGroup : uint32_t {
kGroupGp = BaseReg::kGroupGp, //!< GP register group or none (universal).
kGroupVec = BaseReg::kGroupVec, //!< XMM|YMM|ZMM register group (universal).
kGroupMm = BaseReg::kGroupOther0, //!< MMX register group (legacy).
kGroupKReg = BaseReg::kGroupOther1, //!< K register group.
//! GP register group or none (universal).
kGroupGp = BaseReg::kGroupGp,
//! XMM|YMM|ZMM register group (universal).
kGroupVec = BaseReg::kGroupVec,
//! MMX register group (legacy).
kGroupMm = BaseReg::kGroupOther0,
//! K register group.
kGroupKReg = BaseReg::kGroupOther1,
// These are not managed by BaseCompiler nor used by Func-API:
kGroupSReg = BaseReg::kGroupVirt+0, //!< Segment register group.
kGroupCReg = BaseReg::kGroupVirt+1, //!< Control register group.
kGroupDReg = BaseReg::kGroupVirt+2, //!< Debug register group.
kGroupSt = BaseReg::kGroupVirt+3, //!< FPU register group.
kGroupBnd = BaseReg::kGroupVirt+4, //!< Bound register group.
kGroupRip = BaseReg::kGroupVirt+5, //!< Instrucion pointer (IP).
kGroupCount //!< Count of all register groups.
// These are not managed by Compiler nor used by Func-API:
//! Segment register group.
kGroupSReg = BaseReg::kGroupVirt+0,
//! Control register group.
kGroupCReg = BaseReg::kGroupVirt+1,
//! Debug register group.
kGroupDReg = BaseReg::kGroupVirt+2,
//! FPU register group.
kGroupSt = BaseReg::kGroupVirt+3,
//! Bound register group.
kGroupBnd = BaseReg::kGroupVirt+4,
//! TMM register group.
kGroupTmm = BaseReg::kGroupVirt+5,
//! Instrucion pointer (IP).
kGroupRip = BaseReg::kGroupVirt+6,
//! Count of all register groups.
kGroupCount
};
//! Tests whether the register is a GPB register (8-bit).
@@ -221,6 +260,8 @@ public:
constexpr bool isSt() const noexcept { return hasSignature(RegTraits<kTypeSt>::kSignature); }
//! Tests whether the register is a bound register.
constexpr bool isBnd() const noexcept { return hasSignature(RegTraits<kTypeBnd>::kSignature); }
//! Tests whether the register is a TMM register.
constexpr bool isTmm() const noexcept { return hasSignature(RegTraits<kTypeTmm>::kSignature); }
//! Tests whether the register is RIP.
constexpr bool isRip() const noexcept { return hasSignature(RegTraits<kTypeRip>::kSignature); }
@@ -281,6 +322,7 @@ public:
static inline bool isDReg(const Operand_& op) noexcept { return op.as<Reg>().isDReg(); }
static inline bool isSt(const Operand_& op) noexcept { return op.as<Reg>().isSt(); }
static inline bool isBnd(const Operand_& op) noexcept { return op.as<Reg>().isBnd(); }
static inline bool isTmm(const Operand_& op) noexcept { return op.as<Reg>().isTmm(); }
static inline bool isRip(const Operand_& op) noexcept { return op.as<Reg>().isRip(); }
static inline bool isGpb(const Operand_& op, uint32_t rId) noexcept { return isGpb(op) & (op.id() == rId); }
@@ -299,6 +341,7 @@ public:
static inline bool isDReg(const Operand_& op, uint32_t rId) noexcept { return isDReg(op) & (op.id() == rId); }
static inline bool isSt(const Operand_& op, uint32_t rId) noexcept { return isSt(op) & (op.id() == rId); }
static inline bool isBnd(const Operand_& op, uint32_t rId) noexcept { return isBnd(op) & (op.id() == rId); }
static inline bool isTmm(const Operand_& op, uint32_t rId) noexcept { return isTmm(op) & (op.id() == rId); }
static inline bool isRip(const Operand_& op, uint32_t rId) noexcept { return isRip(op) & (op.id() == rId); }
};
@@ -368,19 +411,26 @@ class SReg : public Reg {
//! X86 segment id.
enum Id : uint32_t {
kIdNone = 0, //!< No segment (default).
kIdEs = 1, //!< ES segment.
kIdCs = 2, //!< CS segment.
kIdSs = 3, //!< SS segment.
kIdDs = 4, //!< DS segment.
kIdFs = 5, //!< FS segment.
kIdGs = 6, //!< GS segment.
//! No segment (default).
kIdNone = 0,
//! ES segment.
kIdEs = 1,
//! CS segment.
kIdCs = 2,
//! SS segment.
kIdSs = 3,
//! DS segment.
kIdDs = 4,
//! FS segment.
kIdFs = 5,
//! GS segment.
kIdGs = 6,
//! Count of segment registers supported by AsmJit.
//! Count of X86 segment registers supported by AsmJit.
//!
//! \note X86 architecture has 6 segment registers - ES, CS, SS, DS, FS, GS.
//! X64 architecture lowers them down to just FS and GS. AsmJit supports 7
//! segment registers - all addressable in both and X64 modes and one
//! segment registers - all addressable in both X86 and X64 modes and one
//! extra called `SReg::kIdNone`, which is AsmJit specific and means that
//! there is no segment register specified.
kIdCount = 7
@@ -433,6 +483,8 @@ class DReg : public Reg { ASMJIT_DEFINE_FINAL_REG(DReg, Reg, RegTraits<kTypeDReg
class St : public Reg { ASMJIT_DEFINE_FINAL_REG(St, Reg, RegTraits<kTypeSt>) };
//! 128-bit BND register (BND+).
class Bnd : public Reg { ASMJIT_DEFINE_FINAL_REG(Bnd, Reg, RegTraits<kTypeBnd>) };
//! 8192-bit TMM register (AMX).
class Tmm : public Reg { ASMJIT_DEFINE_FINAL_REG(Tmm, Reg, RegTraits<kTypeTmm>) };
//! RIP register (X86).
class Rip : public Reg { ASMJIT_DEFINE_FINAL_REG(Rip, Reg, RegTraits<kTypeRip>) };
@@ -489,6 +541,8 @@ static constexpr DReg dr(uint32_t rId) noexcept { return DReg(rId); }
static constexpr St st(uint32_t rId) noexcept { return St(rId); }
//! Creates a 128-bit bound register operand.
static constexpr Bnd bnd(uint32_t rId) noexcept { return Bnd(rId); }
//! Creates a TMM register operand.
static constexpr Tmm tmm(uint32_t rId) noexcept { return Tmm(rId); }
static constexpr Gp al = Gp(GpbLo::kSignature, Gp::kIdAx);
static constexpr Gp bl = Gp(GpbLo::kSignature, Gp::kIdBx);
@@ -736,6 +790,15 @@ static constexpr Bnd bnd1 = Bnd(1);
static constexpr Bnd bnd2 = Bnd(2);
static constexpr Bnd bnd3 = Bnd(3);
static constexpr Tmm tmm0 = Tmm(0);
static constexpr Tmm tmm1 = Tmm(1);
static constexpr Tmm tmm2 = Tmm(2);
static constexpr Tmm tmm3 = Tmm(3);
static constexpr Tmm tmm4 = Tmm(4);
static constexpr Tmm tmm5 = Tmm(5);
static constexpr Tmm tmm6 = Tmm(6);
static constexpr Tmm tmm7 = Tmm(7);
static constexpr Rip rip = Rip(0);
#ifndef _DOXYGEN

View File

@@ -221,6 +221,9 @@ class GenUtils {
}
}
if (dbInst.attributes.Tsib)
f.Tsib = true;
if (dbInst.vsibReg)
f.Vsib = true;
@@ -509,7 +512,9 @@ class X86TableGen extends core.TableGen {
String(inst.encoding ).padEnd(19) + ", " +
String(inst.opcode0 ).padEnd(26) + ", " +
String(inst.opcode1 ).padEnd(26) + ", " +
String("0" ).padEnd( 4) + ", " +
String("0" ).padEnd( 3) + ", " +
String("0" ).padEnd( 3) + ", " +
String("0" ).padEnd( 5) + ", " +
String("0" ).padEnd( 3) + ", " +
String("0" ).padEnd( 3) + "),\n";
}
@@ -930,6 +935,7 @@ const OpToAsmJitOp = {
"dreg" : "F(DReg)",
"st" : "F(St)",
"bnd" : "F(Bnd)",
"tmm" : "F(Tmm)",
"mem" : "F(Mem)",
"vm" : "F(Vm)",
@@ -1096,7 +1102,8 @@ class OSignature {
case "mm" :
case "xmm" :
case "ymm" :
case "zmm" : mFlags[k] = true; break;
case "zmm" :
case "tmm" : mFlags[k] = true; break;
case "m8" :
case "m16" :
@@ -1108,8 +1115,9 @@ class OSignature {
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;
case "mib" : mFlags.mem = true; mMemFlags.mib = true; break;
case "mem" : mFlags.mem = true; mMemFlags.mAny = true; break;
case "tmem" : mFlags.mem = true; mMemFlags.mAny = true; break;
case "memBase" : mFlags.mem = true; mMemFlags.memBase = true; break;
case "memDS" : mFlags.mem = true; mMemFlags.memDS = true; break;
@@ -1814,8 +1822,11 @@ class InstRWInfoTable extends core.Task {
constructor() {
super("InstRWInfoTable");
this.rwInfoIndex = [];
this.rwInfoTable = new IndexedArray();
this.rwInfoIndexA = [];
this.rwInfoIndexB = [];
this.rwInfoTableA = new IndexedArray();
this.rwInfoTableB = new IndexedArray();
this.rmInfoTable = new IndexedArray();
this.opInfoTable = new IndexedArray();
@@ -1954,21 +1965,30 @@ class InstRWInfoTable extends core.Task {
CxxUtils.struct(...(rwOpsIndex.map(function(item) { return String(item).padEnd(2); })))
);
this.rwInfoIndex.push(this.rwInfoTable.addIndexed(rwData));
if (i == 0)
this.rwInfoIndexA.push(this.rwInfoTableA.addIndexed(rwData));
else
this.rwInfoIndexB.push(this.rwInfoTableB.addIndexed(rwData));
}
});
var s = "";
s += "const uint8_t InstDB::rwInfoIndex[Inst::_kIdCount * 2] = {\n" + StringUtils.format(this.rwInfoIndex, kIndent, -1) + "\n};\n";
s += "const uint8_t InstDB::rwInfoIndexA[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexA, kIndent, -1) + "\n};\n";
s += "\n";
s += "const InstDB::RWInfo InstDB::rwInfo[] = {\n" + StringUtils.format(this.rwInfoTable, kIndent, true) + "\n};\n";
s += "const uint8_t InstDB::rwInfoIndexB[Inst::_kIdCount] = {\n" + StringUtils.format(this.rwInfoIndexB, kIndent, -1) + "\n};\n";
s += "\n";
s += "const InstDB::RWInfo InstDB::rwInfoA[] = {\n" + StringUtils.format(this.rwInfoTableA, kIndent, true) + "\n};\n";
s += "\n";
s += "const InstDB::RWInfo InstDB::rwInfoB[] = {\n" + StringUtils.format(this.rwInfoTableB, kIndent, true) + "\n};\n";
s += "\n";
s += "const InstDB::RWInfoOp InstDB::rwInfoOp[] = {\n" + StringUtils.format(this.opInfoTable, kIndent, true) + "\n};\n";
s += "\n";
s += "const InstDB::RWInfoRm InstDB::rwInfoRm[] = {\n" + StringUtils.format(this.rmInfoTable, kIndent, true) + "\n};\n";
const size = this.rwInfoIndex.length +
this.rwInfoTable.length * 8 +
const size = this.rwInfoIndexA.length +
this.rwInfoIndexB.length +
this.rwInfoTableA.length * 8 +
this.rwInfoTableB.length * 8 +
this.rmInfoTable.length * 4 +
this.opInfoTable.length * 24;