// [AsmJit] // Complete x86/x64 JIT and Remote Assembler for C++. // // [License] // Zlib - See LICENSE.md file in the package. // [Export] #define ASMJIT_EXPORTS // [Guard] #include "../asmjit_build.h" #if !defined(ASMJIT_DISABLE_LOGGING) // [Dependencies] #include "../base/misc_p.h" #include "../x86/x86inst.h" #include "../x86/x86logging_p.h" #include "../x86/x86operand.h" #if !defined(ASMJIT_DISABLE_COMPILER) #include "../base/codecompiler.h" #endif // !ASMJIT_DISABLE_COMPILER // [Api-Begin] #include "../asmjit_apibegin.h" namespace asmjit { // ============================================================================ // [asmjit::X86Logging - Constants] // ============================================================================ struct X86RegFormatInfo { uint8_t count; uint8_t formatIndex; uint8_t specialIndex; uint8_t specialCount; }; static const char x86RegFormatStrings[] = "r%ub" "\0" // #0 "r%uh" "\0" // #5 "r%uw" "\0" // #10 "r%ud" "\0" // #15 "r%u" "\0" // #20 "xmm%u" "\0" // #24 "ymm%u" "\0" // #30 "zmm%u" "\0" // #36 "rip%u" "\0" // #42 "seg%u" "\0" // #48 "fp%u" "\0" // #54 "mm%u" "\0" // #59 "k%u" "\0" // #64 "bnd%u" "\0" // #68 "cr%u" "\0" // #74 "dr%u" "\0" // #79 "rip\0" // #84 "\0\0\0\0" // #88 "\0\0\0\0" // #92 "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 "eax\0" "ecx\0" "edx\0" "ebx\0" "esp\0" "ebp\0" "esi\0" "edi\0" // #160 "rax\0" "rcx\0" "rdx\0" "rbx\0" "rsp\0" "rbp\0" "rsi\0" "rdi\0" // #192 "n/a\0" "es\0\0" "cs\0\0" "ss\0\0" "ds\0\0" "fs\0\0" "gs\0\0" "n/a\0"; // #224 template struct X86RegFormatInfo_T { enum { kFormatIndex = X == X86Reg::kRegGpbLo ? 0 : X == X86Reg::kRegGpbHi ? 5 : X == X86Reg::kRegGpw ? 10 : X == X86Reg::kRegGpd ? 15 : X == X86Reg::kRegGpq ? 20 : X == X86Reg::kRegXmm ? 24 : X == X86Reg::kRegYmm ? 30 : X == X86Reg::kRegZmm ? 36 : X == X86Reg::kRegRip ? 42 : X == X86Reg::kRegSeg ? 48 : X == X86Reg::kRegFp ? 54 : X == X86Reg::kRegMm ? 59 : X == X86Reg::kRegK ? 64 : X == X86Reg::kRegBnd ? 68 : X == X86Reg::kRegCr ? 74 : X == X86Reg::kRegDr ? 79 : 0, kSpecialIndex = X == X86Reg::kRegGpbLo ? 96 : X == X86Reg::kRegGpbHi ? 128 : X == X86Reg::kRegGpw ? 161 : X == X86Reg::kRegGpd ? 160 : X == X86Reg::kRegGpq ? 192 : X == X86Reg::kRegRip ? 84 : X == X86Reg::kRegSeg ? 224 : 0, kSpecialCount = X == X86Reg::kRegGpbLo ? 8 : X == X86Reg::kRegGpbHi ? 4 : X == X86Reg::kRegGpw ? 8 : X == X86Reg::kRegGpd ? 8 : X == X86Reg::kRegGpq ? 8 : X == X86Reg::kRegRip ? 1 : X == X86Reg::kRegSeg ? 7 : 0 }; }; #define ASMJIT_X86_REG_FORMAT(TYPE) { \ X86RegTraits::kCount, \ X86RegFormatInfo_T::kFormatIndex, \ X86RegFormatInfo_T::kSpecialIndex, \ X86RegFormatInfo_T::kSpecialCount \ } static const X86RegFormatInfo x86RegFormatInfo[] = { ASMJIT_TABLE_16(ASMJIT_X86_REG_FORMAT, 0 ), ASMJIT_TABLE_16(ASMJIT_X86_REG_FORMAT, 16) }; static const char* x86GetAddressSizeString(uint32_t size) noexcept { switch (size) { 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 "; case 32: return "yword "; case 64: return "zword "; default: return ""; } } // ============================================================================ // [asmjit::X86Logging - Format Operand] // ============================================================================ ASMJIT_FAVOR_SIZE Error X86Logging::formatOperand( StringBuilder& sb, uint32_t logOptions, const CodeEmitter* emitter, uint32_t archType, const Operand_& op) noexcept { if (op.isReg()) return formatRegister(sb, logOptions, emitter, archType, op.as().getType(), op.as().getId()); if (op.isMem()) { const X86Mem& m = op.as(); ASMJIT_PROPAGATE(sb.appendString(x86GetAddressSizeString(m.getSize()))); // Segment override prefix. uint32_t seg = m.getSegmentId(); if (seg != X86Seg::kIdNone && seg < X86Seg::kIdCount) ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatStrings + 224 + seg * 4)); ASMJIT_PROPAGATE(sb.appendChar('[')); if (m.isAbs()) ASMJIT_PROPAGATE(sb.appendString("abs ")); if (m.hasBase()) { if (m.hasBaseLabel()) { ASMJIT_PROPAGATE(Logging::formatLabel(sb, logOptions, emitter, m.getBaseId())); } else { if (m.isArgHome()) ASMJIT_PROPAGATE(sb.appendString("$")); if (m.isRegHome()) ASMJIT_PROPAGATE(sb.appendString("&")); ASMJIT_PROPAGATE(formatRegister(sb, logOptions, emitter, archType, m.getBaseType(), m.getBaseId())); } } if (m.hasIndex()) { ASMJIT_PROPAGATE(sb.appendChar('+')); ASMJIT_PROPAGATE(formatRegister(sb, logOptions, emitter, archType, m.getIndexType(), m.getIndexId())); if (m.hasShift()) ASMJIT_PROPAGATE(sb.appendFormat("*%u", 1 << m.getShift())); } uint64_t off = static_cast(m.getOffset()); if (off) { uint32_t base = 10; char prefix = '+'; if (static_cast(off) < 0) { off = ~off + 1; prefix = '-'; } ASMJIT_PROPAGATE(sb.appendChar(prefix)); if ((logOptions & Logger::kOptionHexDisplacement) != 0 && off > 9) { ASMJIT_PROPAGATE(sb.appendString("0x", 2)); base = 16; } ASMJIT_PROPAGATE(sb.appendUInt(off, base)); } return sb.appendChar(']'); } if (op.isImm()) { const Imm& i = op.as(); int64_t val = i.getInt64(); if ((logOptions & Logger::kOptionHexImmediate) != 0 && static_cast(val) > 9) return sb.appendUInt(static_cast(val), 16); else return sb.appendInt(val, 10); } if (op.isLabel()) { return Logging::formatLabel(sb, logOptions, emitter, op.getId()); } return sb.appendString(""); } // ============================================================================ // [asmjit::X86Logging - Format Immediate (Extension)] // ============================================================================ struct ImmBits { enum Mode { kModeLookup = 0x0, kModeFormat = 0x1 }; uint8_t mask; uint8_t shift; uint8_t mode; char text[45]; }; ASMJIT_FAVOR_SIZE static Error X86Logging_formatImmShuf(StringBuilder& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept { ASMJIT_PROPAGATE(sb.appendChar('<')); uint32_t mask = (1 << bits) - 1; for (uint32_t i = 0; i < count; i++, u8 >>= bits) { uint32_t value = u8 & mask; if (i != 0) ASMJIT_PROPAGATE(sb.appendChar('|')); ASMJIT_PROPAGATE(sb.appendUInt(value)); } return sb.appendChar('>'); } ASMJIT_FAVOR_SIZE static Error X86Logging_formatImmBits(StringBuilder& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept { uint32_t n = 0; char buf[64]; for (uint32_t i = 0; i < count; i++) { const ImmBits& spec = bits[i]; uint32_t value = (u8 & static_cast(spec.mask)) >> spec.shift; const char* str = nullptr; switch (spec.mode) { case ImmBits::kModeLookup: str = Utils::findPackedString(spec.text, value); break; case ImmBits::kModeFormat: snprintf(buf, sizeof(buf), spec.text, static_cast(value)); str = buf; break; default: return DebugUtils::errored(kErrorInvalidState); } if (!str[0]) continue; ASMJIT_PROPAGATE(sb.appendChar(++n == 1 ? '<' : '|')); ASMJIT_PROPAGATE(sb.appendString(str)); } return n ? sb.appendChar('>') : static_cast(kErrorOk); } ASMJIT_FAVOR_SIZE static Error X86Logging_formatImmText(StringBuilder& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept { ASMJIT_PROPAGATE(sb.appendChar('<')); uint32_t mask = (1 << bits) - 1; uint32_t pos = 0; for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) { uint32_t value = (u8 & mask) + pos; if (i != 0) ASMJIT_PROPAGATE(sb.appendChar('|')); ASMJIT_PROPAGATE(sb.appendString(Utils::findPackedString(text, value))); } return sb.appendChar('>'); } ASMJIT_FAVOR_SIZE static Error X86Logging_formatImmExtended( StringBuilder& sb, uint32_t logOptions, uint32_t instId, uint32_t vecSize, const Imm& imm) noexcept { static const char vcmpx[] = "eq_oq\0" "lt_os\0" "le_os\0" "unord_q\0" "neq_uq\0" "nlt_us\0" "nle_us\0" "ord_q\0" "eq_uq\0" "nge_us\0" "ngt_us\0" "false_oq\0" "neq_oq\0" "ge_os\0" "gt_os\0" "true_uq\0" "eq_os\0" "lt_oq\0" "le_oq\0" "unord_s\0" "neq_us\0" "nlt_uq\0" "nle_uq\0" "ord_s\0" "eq_us\0" "nge_uq\0" "ngt_uq\0" "false_os\0" "neq_os\0" "ge_oq\0" "gt_oq\0" "true_us\0"; // Try to find 7 differences... static const char vpcmpx[] = "eq\0" "lt\0" "le\0" "false\0" "neq\0" "ge\0" "gt\0" "true\0"; static const char vpcomx[] = "lt\0" "le\0" "gt\0" "ge\0" "eq\0" "neq\0" "false\0" "true\0"; static const char vshufpd[] = "a0\0a1\0b0\0b1\0a2\0a3\0b2\0b3\0a4\0a5\0b4\0b5\0a6\0a7\0b6\0b7\0"; static const char vshufps[] = "a0\0a1\0a2\0a3\0a0\0a1\0a2\0a3\0b0\0b1\0b2\0b3\0b0\0b1\0b2\0b3\0"; static const ImmBits vfpclassxx[] = { { 0x07, 0, ImmBits::kModeLookup, "qnan\0" "+0\0" "-0\0" "+inf\0" "-inf\0" "denormal\0" "-finite\0" "snan\0" } }; static const ImmBits vgetmantxx[] = { { 0x03, 0, ImmBits::kModeLookup, "[1, 2)\0" "[1/2, 2)\0" "1/2, 1)\0" "[3/4, 3/2)\0" }, { 0x04, 2, ImmBits::kModeLookup, "\0" "no-sign\0" }, { 0x08, 3, ImmBits::kModeLookup, "\0" "qnan-if-sign\0" } }; static const ImmBits vmpsadbw[] = { { 0x04, 2, ImmBits::kModeLookup, "blk1[0]\0" "blk1[1]\0" }, { 0x03, 0, ImmBits::kModeLookup, "blk2[0]\0" "blk2[1]\0" "blk2[2]\0" "blk2[3]\0" }, { 0x40, 6, ImmBits::kModeLookup, "blk1[4]\0" "blk1[5]\0" }, { 0x30, 4, ImmBits::kModeLookup, "blk2[4]\0" "blk2[5]\0" "blk2[6]\0" "blk2[7]\0" } }; static const ImmBits vpclmulqdq[] = { { 0x01, 0, ImmBits::kModeLookup, "lq\0" "hq\0" }, { 0x10, 4, ImmBits::kModeLookup, "lq\0" "hq\0" } }; static const ImmBits vperm2x128[] = { { 0x0B, 0, ImmBits::kModeLookup, "a0\0" "a1\0" "b0\0" "b1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" }, { 0xB0, 4, ImmBits::kModeLookup, "a0\0" "a1\0" "b0\0" "b1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" } }; static const ImmBits vrangexx[] = { { 0x03, 0, ImmBits::kModeLookup, "min\0" "max\0" "min-abs\0" "max-abs\0" }, { 0x0C, 2, ImmBits::kModeLookup, "sign=src1\0" "sign=src2\0" "sign=0\0" "sign=1\0" } }; static const ImmBits vreducexx_vrndscalexx[] = { { 0x07, 0, ImmBits::kModeLookup, "\0" "\0" "\0" "\0" "round\0" "floor\0" "ceil\0" "truncate\0" }, { 0x08, 3, ImmBits::kModeLookup, "\0" "suppress\0" }, { 0xF0, 4, ImmBits::kModeFormat, "len=%d" } }; static const ImmBits vroundxx[] = { { 0x07, 0, ImmBits::kModeLookup, "round\0" "floor\0" "ceil\0" "truncate\0" "\0" "\0" "\0" "\0" }, { 0x08, 3, ImmBits::kModeLookup, "\0" "inexact\0" } }; uint32_t u8 = imm.getUInt8(); switch (instId) { case X86Inst::kIdVblendpd: case X86Inst::kIdBlendpd: return X86Logging_formatImmShuf(sb, u8, 1, vecSize / 8); case X86Inst::kIdVblendps: case X86Inst::kIdBlendps: return X86Logging_formatImmShuf(sb, u8, 1, vecSize / 4); case X86Inst::kIdVcmppd: case X86Inst::kIdVcmpps: case X86Inst::kIdVcmpsd: case X86Inst::kIdVcmpss: return X86Logging_formatImmText(sb, u8, 5, 0, vcmpx); case X86Inst::kIdCmppd: case X86Inst::kIdCmpps: case X86Inst::kIdCmpsd: case X86Inst::kIdCmpss: return X86Logging_formatImmText(sb, u8, 3, 0, vcmpx); case X86Inst::kIdVdbpsadbw: return X86Logging_formatImmShuf(sb, u8, 2, 4); case X86Inst::kIdVdppd: case X86Inst::kIdVdpps: case X86Inst::kIdDppd: case X86Inst::kIdDpps: return X86Logging_formatImmShuf(sb, u8, 1, 8); case X86Inst::kIdVmpsadbw: case X86Inst::kIdMpsadbw: return X86Logging_formatImmBits(sb, u8, vmpsadbw, std::min(vecSize / 8, 4)); case X86Inst::kIdVpblendw: case X86Inst::kIdPblendw: return X86Logging_formatImmShuf(sb, u8, 1, 8); case X86Inst::kIdVpblendd: return X86Logging_formatImmShuf(sb, u8, 1, std::min(vecSize / 4, 8)); case X86Inst::kIdVpclmulqdq: case X86Inst::kIdPclmulqdq: return X86Logging_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq)); case X86Inst::kIdVroundpd: case X86Inst::kIdVroundps: case X86Inst::kIdVroundsd: case X86Inst::kIdVroundss: case X86Inst::kIdRoundpd: case X86Inst::kIdRoundps: case X86Inst::kIdRoundsd: case X86Inst::kIdRoundss: return X86Logging_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx)); case X86Inst::kIdVshufpd: case X86Inst::kIdShufpd: return X86Logging_formatImmText(sb, u8, 1, 2, vshufpd, std::min(vecSize / 8, 8)); case X86Inst::kIdVshufps: case X86Inst::kIdShufps: return X86Logging_formatImmText(sb, u8, 2, 4, vshufps, 4); case X86Inst::kIdVcvtps2ph: return X86Logging_formatImmBits(sb, u8, vroundxx, 1); case X86Inst::kIdVperm2f128: case X86Inst::kIdVperm2i128: return X86Logging_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128)); case X86Inst::kIdVpermilpd: return X86Logging_formatImmShuf(sb, u8, 1, vecSize / 8); case X86Inst::kIdVpermilps: return X86Logging_formatImmShuf(sb, u8, 2, 4); case X86Inst::kIdVpshufd: case X86Inst::kIdPshufd: return X86Logging_formatImmShuf(sb, u8, 2, 4); case X86Inst::kIdVpshufhw: case X86Inst::kIdVpshuflw: case X86Inst::kIdPshufhw: case X86Inst::kIdPshuflw: case X86Inst::kIdPshufw: return X86Logging_formatImmShuf(sb, u8, 2, 4); // TODO: Maybe? case X86Inst::kIdVfixupimmpd: case X86Inst::kIdVfixupimmps: case X86Inst::kIdVfixupimmsd: case X86Inst::kIdVfixupimmss: return kErrorOk; case X86Inst::kIdVfpclasspd: case X86Inst::kIdVfpclassps: case X86Inst::kIdVfpclasssd: case X86Inst::kIdVfpclassss: return X86Logging_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx)); case X86Inst::kIdVgetmantpd: case X86Inst::kIdVgetmantps: case X86Inst::kIdVgetmantsd: case X86Inst::kIdVgetmantss: return X86Logging_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx)); case X86Inst::kIdVpcmpb: case X86Inst::kIdVpcmpd: case X86Inst::kIdVpcmpq: case X86Inst::kIdVpcmpw: case X86Inst::kIdVpcmpub: case X86Inst::kIdVpcmpud: case X86Inst::kIdVpcmpuq: case X86Inst::kIdVpcmpuw: return X86Logging_formatImmText(sb, u8, 2, 4, vpcmpx, 4); case X86Inst::kIdVpcomb: case X86Inst::kIdVpcomd: case X86Inst::kIdVpcomq: case X86Inst::kIdVpcomw: case X86Inst::kIdVpcomub: case X86Inst::kIdVpcomud: case X86Inst::kIdVpcomuq: case X86Inst::kIdVpcomuw: return X86Logging_formatImmText(sb, u8, 2, 4, vpcomx, 4); case X86Inst::kIdVpermq: case X86Inst::kIdVpermpd: return X86Logging_formatImmShuf(sb, u8, 2, 4); case X86Inst::kIdVpternlogd: case X86Inst::kIdVpternlogq: return X86Logging_formatImmShuf(sb, u8, 1, 8); case X86Inst::kIdVrangepd: case X86Inst::kIdVrangeps: case X86Inst::kIdVrangesd: case X86Inst::kIdVrangess: return X86Logging_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx)); case X86Inst::kIdVreducepd: case X86Inst::kIdVreduceps: case X86Inst::kIdVreducesd: case X86Inst::kIdVreducess: case X86Inst::kIdVrndscalepd: case X86Inst::kIdVrndscaleps: case X86Inst::kIdVrndscalesd: case X86Inst::kIdVrndscaless: return X86Logging_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx)); case X86Inst::kIdVshuff32x4: case X86Inst::kIdVshuff64x2: case X86Inst::kIdVshufi32x4: case X86Inst::kIdVshufi64x2: { uint32_t count = std::max(vecSize / 16, 2); uint32_t bits = count <= 2 ? 1 : 2; return X86Logging_formatImmShuf(sb, u8, bits, count); } default: return kErrorOk; } } // ============================================================================ // [asmjit::X86Logging - Format Register] // ============================================================================ ASMJIT_FAVOR_SIZE Error X86Logging::formatRegister( StringBuilder& sb, uint32_t logOptions, const CodeEmitter* emitter, uint32_t archType, uint32_t rType, uint32_t rId) noexcept { ASMJIT_UNUSED(logOptions); ASMJIT_UNUSED(archType); if (Operand::isPackedId(rId)) { #if !defined(ASMJIT_DISABLE_COMPILER) if (emitter && emitter->getType() == CodeEmitter::kTypeCompiler) { const CodeCompiler* cc = static_cast(emitter); if (cc->isVirtRegValid(rId)) { VirtReg* vReg = cc->getVirtRegById(rId); ASMJIT_ASSERT(vReg != nullptr); const char* name = vReg->getName(); if (name && name[0] != '\0') return sb.appendString(name); else return sb.appendFormat("v%u", static_cast(Operand::unpackId(rId))); } } #endif // !ASMJIT_DISABLE_COMPILER return sb.appendFormat("VirtReg", rType, rId); } else { if (rType < ASMJIT_ARRAY_SIZE(x86RegFormatInfo)) { const X86RegFormatInfo& rfi = x86RegFormatInfo[rType]; if (rId < rfi.specialCount) return sb.appendString(x86RegFormatStrings + rfi.specialIndex + rId * 4); if (rId < rfi.count) return sb.appendFormat(x86RegFormatStrings + rfi.formatIndex, static_cast(rId)); } return sb.appendFormat("PhysReg", rType, rId); } } // ============================================================================ // [asmjit::X86Logging - Format Instruction] // ============================================================================ ASMJIT_FAVOR_SIZE Error X86Logging::formatInstruction( StringBuilder& sb, uint32_t logOptions, const CodeEmitter* emitter, uint32_t archType, const Inst::Detail& detail, const Operand_* opArray, uint32_t opCount) noexcept { uint32_t instId = detail.instId; uint32_t options = detail.options; // Format instruction options and instruction mnemonic. if (instId < X86Inst::_kIdCount) { const X86Inst& instInfo = X86Inst::getInst(instId); // SHORT|LONG options. if (options & X86Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.appendString("short ")); if (options & X86Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.appendString("long ")); // LOCK|XACQUIRE|XRELEASE options. 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|REPNZ options. if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) { sb.appendString((options & X86Inst::kOptionRep) ? "rep " : "repnz "); if (detail.hasExtraReg()) { ASMJIT_PROPAGATE(sb.appendChar('{')); ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, detail.extraReg.toReg())); ASMJIT_PROPAGATE(sb.appendString("} ")); } } // REX options. if (options & X86Inst::kOptionRex) { const uint32_t kRXBWMask = X86Inst::kOptionOpCodeR | X86Inst::kOptionOpCodeX | X86Inst::kOptionOpCodeB | X86Inst::kOptionOpCodeW ; if (options & kRXBWMask) { sb.appendString("rex."); if (options & X86Inst::kOptionOpCodeR) sb.appendChar('r'); if (options & X86Inst::kOptionOpCodeX) sb.appendChar('x'); if (options & X86Inst::kOptionOpCodeB) sb.appendChar('b'); if (options & X86Inst::kOptionOpCodeW) sb.appendChar('w'); sb.appendChar(' '); } else { ASMJIT_PROPAGATE(sb.appendString("rex ")); } } // VEX|EVEX options. if (options & X86Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.appendString("vex3 ")); if (options & X86Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.appendString("evex ")); ASMJIT_PROPAGATE(sb.appendString(instInfo.getName())); } else { ASMJIT_PROPAGATE(sb.appendFormat("", static_cast(instId))); } for (uint32_t i = 0; i < opCount; i++) { const Operand_& op = opArray[i]; if (op.isNone()) break; ASMJIT_PROPAGATE(sb.appendString(i == 0 ? " " : ", ")); ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, op)); if (op.isImm() && (logOptions & Logger::kOptionImmExtended)) { uint32_t vecSize = 16; for (uint32_t j = 0; j < opCount; j++) if (opArray[j].isReg()) vecSize = std::max(vecSize, opArray[j].getSize()); ASMJIT_PROPAGATE(X86Logging_formatImmExtended(sb, logOptions, instId, vecSize, op.as())); } // Support AVX-512 {k}{z}. if (i == 0) { if (detail.extraReg.getKind() == X86Reg::kKindK) { ASMJIT_PROPAGATE(sb.appendString(" {")); ASMJIT_PROPAGATE(formatOperand(sb, logOptions, emitter, archType, detail.extraReg.toReg())); ASMJIT_PROPAGATE(sb.appendChar('}')); if (options & X86Inst::kOptionZMask) ASMJIT_PROPAGATE(sb.appendString("{z}")); } else if (options & X86Inst::kOptionZMask) { ASMJIT_PROPAGATE(sb.appendString(" {z}")); } } // Support AVX-512 {1tox}. if (op.isMem() && (options & X86Inst::kOption1ToX)) ASMJIT_PROPAGATE(sb.appendString(" {1tox}")); } return kErrorOk; } } // asmjit namespace // [Api-End] #include "../asmjit_apiend.h" // [Guard] #endif // !ASMJIT_DISABLE_LOGGING