summaryrefslogtreecommitdiffstatshomepage
path: root/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp
diff options
context:
space:
mode:
Diffstat (limited to '3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp')
-rw-r--r--3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp907
1 files changed, 907 insertions, 0 deletions
diff --git a/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp
new file mode 100644
index 00000000000..06553e401e0
--- /dev/null
+++ b/3rdparty/asmjit/src/asmjit/x86/x86formatter.cpp
@@ -0,0 +1,907 @@
+// AsmJit - Machine code generation for C++
+//
+// * Official AsmJit Home Page: https://asmjit.com
+// * Official Github Repository: https://github.com/asmjit/asmjit
+//
+// Copyright (c) 2008-2020 The AsmJit Authors
+//
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+//
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+//
+// 1. The origin of this software must not be misrepresented; you must not
+// claim that you wrote the original software. If you use this software
+// in a product, an acknowledgment in the product documentation would be
+// appreciated but is not required.
+// 2. Altered source versions must be plainly marked as such, and must not be
+// misrepresented as being the original software.
+// 3. This notice may not be removed or altered from any source distribution.
+
+#include "../core/api-build_p.h"
+#ifndef ASMJIT_NO_LOGGING
+
+#include "../core/misc_p.h"
+#include "../core/support.h"
+#include "../x86/x86features.h"
+#include "../x86/x86formatter_p.h"
+#include "../x86/x86instdb_p.h"
+#include "../x86/x86operand.h"
+
+#ifndef ASMJIT_NO_COMPILER
+ #include "../core/compiler.h"
+#endif
+
+ASMJIT_BEGIN_SUB_NAMESPACE(x86)
+
+// ============================================================================
+// [asmjit::x86::FormatterInternal - Constants]
+// ============================================================================
+
+struct RegFormatInfo {
+ struct TypeEntry {
+ uint8_t index;
+ };
+
+ struct NameEntry {
+ uint8_t count;
+ uint8_t formatIndex;
+ uint8_t specialIndex;
+ uint8_t specialCount;
+ };
+
+ TypeEntry typeEntries[BaseReg::kTypeMax + 1];
+ char typeStrings[128 - 32];
+
+ NameEntry nameEntries[BaseReg::kTypeMax + 1];
+ char nameStrings[280];
+};
+
+template<uint32_t X>
+struct RegFormatInfo_T {
+ enum {
+ kTypeIndex = X == Reg::kTypeGpbLo ? 1 :
+ X == Reg::kTypeGpbHi ? 8 :
+ X == Reg::kTypeGpw ? 15 :
+ X == Reg::kTypeGpd ? 19 :
+ X == Reg::kTypeGpq ? 23 :
+ X == Reg::kTypeXmm ? 27 :
+ X == Reg::kTypeYmm ? 31 :
+ X == Reg::kTypeZmm ? 35 :
+ X == Reg::kTypeMm ? 50 :
+ X == Reg::kTypeKReg ? 53 :
+ X == Reg::kTypeSReg ? 43 :
+ X == Reg::kTypeCReg ? 59 :
+ X == Reg::kTypeDReg ? 62 :
+ X == Reg::kTypeSt ? 47 :
+ X == Reg::kTypeBnd ? 55 :
+ X == Reg::kTypeRip ? 39 : 0,
+
+ kFormatIndex = X == Reg::kTypeGpbLo ? 1 :
+ X == Reg::kTypeGpbHi ? 6 :
+ X == Reg::kTypeGpw ? 11 :
+ X == Reg::kTypeGpd ? 16 :
+ X == Reg::kTypeGpq ? 21 :
+ X == Reg::kTypeXmm ? 25 :
+ X == Reg::kTypeYmm ? 31 :
+ X == Reg::kTypeZmm ? 37 :
+ X == Reg::kTypeMm ? 60 :
+ X == Reg::kTypeKReg ? 65 :
+ X == Reg::kTypeSReg ? 49 :
+ X == Reg::kTypeCReg ? 75 :
+ X == Reg::kTypeDReg ? 80 :
+ X == Reg::kTypeSt ? 55 :
+ X == Reg::kTypeBnd ? 69 :
+ X == Reg::kTypeRip ? 43 : 0,
+
+ kSpecialIndex = X == Reg::kTypeGpbLo ? 96 :
+ X == Reg::kTypeGpbHi ? 128 :
+ X == Reg::kTypeGpw ? 161 :
+ X == Reg::kTypeGpd ? 160 :
+ X == Reg::kTypeGpq ? 192 :
+ X == Reg::kTypeSReg ? 224 :
+ X == Reg::kTypeRip ? 85 : 0,
+
+ kSpecialCount = X == Reg::kTypeGpbLo ? 8 :
+ X == Reg::kTypeGpbHi ? 4 :
+ X == Reg::kTypeGpw ? 8 :
+ X == Reg::kTypeGpd ? 8 :
+ X == Reg::kTypeGpq ? 8 :
+ X == Reg::kTypeSReg ? 7 :
+ X == Reg::kTypeRip ? 1 : 0
+ };
+};
+
+#define ASMJIT_REG_TYPE_ENTRY(TYPE) { \
+ RegFormatInfo_T<TYPE>::kTypeIndex \
+}
+
+#define ASMJIT_REG_NAME_ENTRY(TYPE) { \
+ RegTraits<TYPE>::kCount, \
+ RegFormatInfo_T<TYPE>::kFormatIndex, \
+ RegFormatInfo_T<TYPE>::kSpecialIndex, \
+ RegFormatInfo_T<TYPE>::kSpecialCount \
+}
+
+static const RegFormatInfo x86RegFormatInfo = {
+ // Register type entries and strings.
+ { ASMJIT_LOOKUP_TABLE_32(ASMJIT_REG_TYPE_ENTRY, 0) },
+
+ "\0" // #0
+ "gpb\0\0\0\0" // #1
+ "gpb.hi\0" // #8
+ "gpw\0" // #15
+ "gpd\0" // #19
+ "gpq\0" // #23
+ "xmm\0" // #27
+ "ymm\0" // #31
+ "zmm\0" // #35
+ "rip\0" // #39
+ "seg\0" // #43
+ "st\0" // #47
+ "mm\0" // #50
+ "k\0" // #53
+ "bnd\0" // #55
+ "cr\0" // #59
+ "dr\0", // #62
+
+ // Register name entries and strings.
+ { ASMJIT_LOOKUP_TABLE_32(ASMJIT_REG_NAME_ENTRY, 0) },
+
+ "\0"
+ "r%ub\0" // #1
+ "r%uh\0" // #6
+ "r%uw\0" // #11
+ "r%ud\0" // #16
+ "r%u\0" // #21
+ "xmm%u\0" // #25
+ "ymm%u\0" // #31
+ "zmm%u\0" // #37
+ "rip%u\0" // #43
+ "seg%u\0" // #49
+ "st%u\0" // #55
+ "mm%u\0" // #60
+ "k%u\0" // #65
+ "bnd%u\0" // #69
+ "cr%u\0" // #75
+ "dr%u\0" // #80
+
+ "rip\0" // #85
+ "\0\0\0\0\0\0\0" // #89
+
+ "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
+};
+#undef ASMJIT_REG_NAME_ENTRY
+#undef ASMJIT_REG_TYPE_ENTRY
+
+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::x86::FormatterInternal - Format Feature]
+// ============================================================================
+
+Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept {
+ // @EnumStringBegin{"enum": "x86::Features::Id", "output": "sFeature", "strip": "k"}@
+ static const char sFeatureString[] =
+ "None\0"
+ "MT\0"
+ "NX\0"
+ "3DNOW\0"
+ "3DNOW2\0"
+ "ADX\0"
+ "AESNI\0"
+ "ALTMOVCR8\0"
+ "AVX\0"
+ "AVX2\0"
+ "AVX512_4FMAPS\0"
+ "AVX512_4VNNIW\0"
+ "AVX512_BF16\0"
+ "AVX512_BITALG\0"
+ "AVX512_BW\0"
+ "AVX512_CDI\0"
+ "AVX512_DQ\0"
+ "AVX512_ERI\0"
+ "AVX512_F\0"
+ "AVX512_IFMA\0"
+ "AVX512_PFI\0"
+ "AVX512_VBMI\0"
+ "AVX512_VBMI2\0"
+ "AVX512_VL\0"
+ "AVX512_VNNI\0"
+ "AVX512_VP2INTERSECT\0"
+ "AVX512_VPOPCNTDQ\0"
+ "BMI\0"
+ "BMI2\0"
+ "CLDEMOTE\0"
+ "CLFLUSH\0"
+ "CLFLUSHOPT\0"
+ "CLWB\0"
+ "CLZERO\0"
+ "CMOV\0"
+ "CMPXCHG16B\0"
+ "CMPXCHG8B\0"
+ "ENCLV\0"
+ "ENQCMD\0"
+ "ERMS\0"
+ "F16C\0"
+ "FMA\0"
+ "FMA4\0"
+ "FPU\0"
+ "FSGSBASE\0"
+ "FXSR\0"
+ "FXSROPT\0"
+ "GEODE\0"
+ "GFNI\0"
+ "HLE\0"
+ "I486\0"
+ "LAHFSAHF\0"
+ "LWP\0"
+ "LZCNT\0"
+ "MMX\0"
+ "MMX2\0"
+ "MONITOR\0"
+ "MONITORX\0"
+ "MOVBE\0"
+ "MOVDIR64B\0"
+ "MOVDIRI\0"
+ "MPX\0"
+ "MSR\0"
+ "MSSE\0"
+ "OSXSAVE\0"
+ "PCLMULQDQ\0"
+ "PCOMMIT\0"
+ "PCONFIG\0"
+ "POPCNT\0"
+ "PREFETCHW\0"
+ "PREFETCHWT1\0"
+ "RDPID\0"
+ "RDRAND\0"
+ "RDSEED\0"
+ "RDTSC\0"
+ "RDTSCP\0"
+ "RTM\0"
+ "SHA\0"
+ "SKINIT\0"
+ "SMAP\0"
+ "SMEP\0"
+ "SMX\0"
+ "SSE\0"
+ "SSE2\0"
+ "SSE3\0"
+ "SSE4_1\0"
+ "SSE4_2\0"
+ "SSE4A\0"
+ "SSSE3\0"
+ "SVM\0"
+ "TBM\0"
+ "TSX\0"
+ "VAES\0"
+ "VMX\0"
+ "VPCLMULQDQ\0"
+ "WAITPKG\0"
+ "WBNOINVD\0"
+ "XOP\0"
+ "XSAVE\0"
+ "XSAVEC\0"
+ "XSAVEOPT\0"
+ "XSAVES\0"
+ "<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
+ };
+ // @EnumStringEnd@
+
+ return sb.append(sFeatureString + sFeatureIndex[Support::min<uint32_t>(featureId, x86::Features::kCount)]);
+}
+
+// ============================================================================
+// [asmjit::x86::FormatterInternal - Format Operand]
+// ============================================================================
+
+ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
+ String& sb,
+ uint32_t flags,
+ const BaseEmitter* emitter,
+ uint32_t arch,
+ const Operand_& op) noexcept {
+
+ if (op.isReg())
+ return formatRegister(sb, flags, emitter, arch, op.as<BaseReg>().type(), op.as<BaseReg>().id());
+
+ if (op.isMem()) {
+ const Mem& m = op.as<Mem>();
+ ASMJIT_PROPAGATE(sb.append(x86GetAddressSizeString(m.size())));
+
+ // Segment override prefix.
+ uint32_t seg = m.segmentId();
+ if (seg != SReg::kIdNone && seg < SReg::kIdCount)
+ ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + size_t(seg) * 4));
+
+ ASMJIT_PROPAGATE(sb.append('['));
+ switch (m.addrType()) {
+ case BaseMem::kAddrTypeAbs: ASMJIT_PROPAGATE(sb.append("abs ")); break;
+ case BaseMem::kAddrTypeRel: ASMJIT_PROPAGATE(sb.append("rel ")); break;
+ }
+
+ char opSign = '\0';
+ if (m.hasBase()) {
+ opSign = '+';
+ if (m.hasBaseLabel()) {
+ ASMJIT_PROPAGATE(Formatter::formatLabel(sb, flags, emitter, m.baseId()));
+ }
+ else {
+ uint32_t modifiedFlags = flags;
+ if (m.isRegHome()) {
+ ASMJIT_PROPAGATE(sb.append("&"));
+ modifiedFlags &= ~FormatOptions::kFlagRegCasts;
+ }
+ ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId()));
+ }
+ }
+
+ if (m.hasIndex()) {
+ if (opSign)
+ ASMJIT_PROPAGATE(sb.append(opSign));
+
+ opSign = '+';
+ ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, m.indexType(), m.indexId()));
+ if (m.hasShift())
+ ASMJIT_PROPAGATE(sb.appendFormat("*%u", 1 << m.shift()));
+ }
+
+ uint64_t off = uint64_t(m.offset());
+ if (off || !m.hasBaseOrIndex()) {
+ if (int64_t(off) < 0) {
+ opSign = '-';
+ off = ~off + 1;
+ }
+
+ if (opSign)
+ ASMJIT_PROPAGATE(sb.append(opSign));
+
+ uint32_t base = 10;
+ if ((flags & FormatOptions::kFlagHexOffsets) != 0 && off > 9) {
+ ASMJIT_PROPAGATE(sb.append("0x", 2));
+ base = 16;
+ }
+
+ ASMJIT_PROPAGATE(sb.appendUInt(off, base));
+ }
+
+ return sb.append(']');
+ }
+
+ if (op.isImm()) {
+ const Imm& i = op.as<Imm>();
+ int64_t val = i.value();
+
+ if ((flags & FormatOptions::kFlagHexImms) != 0 && uint64_t(val) > 9) {
+ ASMJIT_PROPAGATE(sb.append("0x", 2));
+ return sb.appendUInt(uint64_t(val), 16);
+ }
+ else {
+ return sb.appendInt(val, 10);
+ }
+ }
+
+ if (op.isLabel()) {
+ return Formatter::formatLabel(sb, flags, emitter, op.id());
+ }
+
+ return sb.append("<None>");
+}
+
+// ============================================================================
+// [asmjit::x86::FormatterInternal - Format Immediate (Extension)]
+// ============================================================================
+
+static constexpr char kImmCharStart = '{';
+static constexpr char kImmCharEnd = '}';
+static constexpr char kImmCharOr = '|';
+
+struct ImmBits {
+ enum Mode : uint32_t {
+ kModeLookup = 0,
+ kModeFormat = 1
+ };
+
+ uint8_t mask;
+ uint8_t shift;
+ uint8_t mode;
+ char text[48 - 3];
+};
+
+ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept {
+ uint32_t mask = (1 << bits) - 1;
+
+ for (uint32_t i = 0; i < count; i++, u8 >>= bits) {
+ uint32_t value = u8 & mask;
+ ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr));
+ ASMJIT_PROPAGATE(sb.appendUInt(value));
+ }
+
+ if (kImmCharEnd)
+ ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
+
+ return kErrorOk;
+}
+
+ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& 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 & uint32_t(spec.mask)) >> spec.shift;
+ const char* str = nullptr;
+
+ switch (spec.mode) {
+ case ImmBits::kModeLookup:
+ str = Support::findPackedString(spec.text, value);
+ break;
+
+ case ImmBits::kModeFormat:
+ snprintf(buf, sizeof(buf), spec.text, unsigned(value));
+ str = buf;
+ break;
+
+ default:
+ return DebugUtils::errored(kErrorInvalidState);
+ }
+
+ if (!str[0])
+ continue;
+
+ ASMJIT_PROPAGATE(sb.append(++n == 1 ? kImmCharStart : kImmCharOr));
+ ASMJIT_PROPAGATE(sb.append(str));
+ }
+
+ if (n && kImmCharEnd)
+ ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
+
+ return kErrorOk;
+}
+
+ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmText(String& sb, uint32_t u8, uint32_t bits, uint32_t advance, const char* text, uint32_t count = 1) noexcept {
+ uint32_t mask = (1u << bits) - 1;
+ uint32_t pos = 0;
+
+ for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) {
+ uint32_t value = (u8 & mask) + pos;
+ ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr));
+ ASMJIT_PROPAGATE(sb.append(Support::findPackedString(text, value)));
+ }
+
+ if (kImmCharEnd)
+ ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
+
+ return kErrorOk;
+}
+
+ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
+ String& sb,
+ uint32_t flags,
+ uint32_t instId,
+ uint32_t vecSize,
+ const Imm& imm) noexcept {
+
+ DebugUtils::unused(flags);
+
+ 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";
+
+ // Why to make it compatible...
+ 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[] = {
+ { 0x07u, 0, ImmBits::kModeLookup, "QNAN\0" "+0\0" "-0\0" "+INF\0" "-INF\0" "DENORMAL\0" "-FINITE\0" "SNAN\0" }
+ };
+
+ static const ImmBits vfixupimmxx[] = {
+ { 0x01u, 0, ImmBits::kModeLookup, "\0" "+INF_IE\0" },
+ { 0x02u, 1, ImmBits::kModeLookup, "\0" "-VE_IE\0" },
+ { 0x04u, 2, ImmBits::kModeLookup, "\0" "-INF_IE\0" },
+ { 0x08u, 3, ImmBits::kModeLookup, "\0" "SNAN_IE\0" },
+ { 0x10u, 4, ImmBits::kModeLookup, "\0" "ONE_IE\0" },
+ { 0x20u, 5, ImmBits::kModeLookup, "\0" "ONE_ZE\0" },
+ { 0x40u, 6, ImmBits::kModeLookup, "\0" "ZERO_IE\0" },
+ { 0x80u, 7, ImmBits::kModeLookup, "\0" "ZERO_ZE\0" }
+ };
+
+ static const ImmBits vgetmantxx[] = {
+ { 0x03u, 0, ImmBits::kModeLookup, "[1, 2)\0" "[.5, 2)\0" "[.5, 1)\0" "[.75, 1.5)\0" },
+ { 0x04u, 2, ImmBits::kModeLookup, "\0" "NO_SIGN\0" },
+ { 0x08u, 3, ImmBits::kModeLookup, "\0" "QNAN_IF_SIGN\0" }
+ };
+
+ static const ImmBits vmpsadbw[] = {
+ { 0x04u, 2, ImmBits::kModeLookup, "BLK1[0]\0" "BLK1[1]\0" },
+ { 0x03u, 0, ImmBits::kModeLookup, "BLK2[0]\0" "BLK2[1]\0" "BLK2[2]\0" "BLK2[3]\0" },
+ { 0x40u, 6, ImmBits::kModeLookup, "BLK1[4]\0" "BLK1[5]\0" },
+ { 0x30u, 4, ImmBits::kModeLookup, "BLK2[4]\0" "BLK2[5]\0" "BLK2[6]\0" "BLK2[7]\0" }
+ };
+
+ static const ImmBits vpclmulqdq[] = {
+ { 0x01u, 0, ImmBits::kModeLookup, "LQ\0" "HQ\0" },
+ { 0x10u, 4, ImmBits::kModeLookup, "LQ\0" "HQ\0" }
+ };
+
+ static const ImmBits vperm2x128[] = {
+ { 0x0Bu, 0, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" },
+ { 0xB0u, 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[] = {
+ { 0x03u, 0, ImmBits::kModeLookup, "MIN\0" "MAX\0" "MIN_ABS\0" "MAX_ABS\0" },
+ { 0x0Cu, 2, ImmBits::kModeLookup, "SIGN_A\0" "SIGN_B\0" "SIGN_0\0" "SIGN_1\0" }
+ };
+
+ static const ImmBits vreducexx_vrndscalexx[] = {
+ { 0x07u, 0, ImmBits::kModeLookup, "\0" "\0" "\0" "\0" "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" },
+ { 0x08u, 3, ImmBits::kModeLookup, "\0" "SAE\0" },
+ { 0xF0u, 4, ImmBits::kModeFormat, "LEN=%d" }
+ };
+
+ static const ImmBits vroundxx[] = {
+ { 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "\0" "\0" "\0" "\0" },
+ { 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" }
+ };
+
+ uint32_t u8 = imm.valueAs<uint8_t>();
+ switch (instId) {
+ case Inst::kIdVblendpd:
+ case Inst::kIdBlendpd:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8);
+
+ case Inst::kIdVblendps:
+ case Inst::kIdBlendps:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 4);
+
+ case Inst::kIdVcmppd:
+ case Inst::kIdVcmpps:
+ case Inst::kIdVcmpsd:
+ case Inst::kIdVcmpss:
+ return FormatterInternal_formatImmText(sb, u8, 5, 0, vcmpx);
+
+ case Inst::kIdCmppd:
+ case Inst::kIdCmpps:
+ case Inst::kIdCmpsd:
+ case Inst::kIdCmpss:
+ return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx);
+
+ case Inst::kIdVdbpsadbw:
+ return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
+
+ case Inst::kIdVdppd:
+ case Inst::kIdVdpps:
+ case Inst::kIdDppd:
+ case Inst::kIdDpps:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
+
+ case Inst::kIdVmpsadbw:
+ case Inst::kIdMpsadbw:
+ return FormatterInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4));
+
+ case Inst::kIdVpblendw:
+ case Inst::kIdPblendw:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
+
+ case Inst::kIdVpblendd:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8));
+
+ case Inst::kIdVpclmulqdq:
+ case Inst::kIdPclmulqdq:
+ return FormatterInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq));
+
+ case Inst::kIdVroundpd:
+ case Inst::kIdVroundps:
+ case Inst::kIdVroundsd:
+ case Inst::kIdVroundss:
+ case Inst::kIdRoundpd:
+ case Inst::kIdRoundps:
+ case Inst::kIdRoundsd:
+ case Inst::kIdRoundss:
+ return FormatterInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx));
+
+ case Inst::kIdVshufpd:
+ case Inst::kIdShufpd:
+ return FormatterInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8));
+
+ case Inst::kIdVshufps:
+ case Inst::kIdShufps:
+ return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4);
+
+ case Inst::kIdVcvtps2ph:
+ return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1);
+
+ case Inst::kIdVperm2f128:
+ case Inst::kIdVperm2i128:
+ return FormatterInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128));
+
+ case Inst::kIdVpermilpd:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8);
+
+ case Inst::kIdVpermilps:
+ return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
+
+ case Inst::kIdVpshufd:
+ case Inst::kIdPshufd:
+ return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
+
+ case Inst::kIdVpshufhw:
+ case Inst::kIdVpshuflw:
+ case Inst::kIdPshufhw:
+ case Inst::kIdPshuflw:
+ case Inst::kIdPshufw:
+ return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
+
+ case Inst::kIdVfixupimmpd:
+ case Inst::kIdVfixupimmps:
+ case Inst::kIdVfixupimmsd:
+ case Inst::kIdVfixupimmss:
+ return FormatterInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx));
+
+ case Inst::kIdVfpclasspd:
+ case Inst::kIdVfpclassps:
+ case Inst::kIdVfpclasssd:
+ case Inst::kIdVfpclassss:
+ return FormatterInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx));
+
+ case Inst::kIdVgetmantpd:
+ case Inst::kIdVgetmantps:
+ case Inst::kIdVgetmantsd:
+ case Inst::kIdVgetmantss:
+ return FormatterInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx));
+
+ case Inst::kIdVpcmpb:
+ case Inst::kIdVpcmpd:
+ case Inst::kIdVpcmpq:
+ case Inst::kIdVpcmpw:
+ case Inst::kIdVpcmpub:
+ case Inst::kIdVpcmpud:
+ case Inst::kIdVpcmpuq:
+ case Inst::kIdVpcmpuw:
+ return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcmpx);
+
+ case Inst::kIdVpcomb:
+ case Inst::kIdVpcomd:
+ case Inst::kIdVpcomq:
+ case Inst::kIdVpcomw:
+ case Inst::kIdVpcomub:
+ case Inst::kIdVpcomud:
+ case Inst::kIdVpcomuq:
+ case Inst::kIdVpcomuw:
+ return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcomx);
+
+ case Inst::kIdVpermq:
+ case Inst::kIdVpermpd:
+ return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
+
+ case Inst::kIdVpternlogd:
+ case Inst::kIdVpternlogq:
+ return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
+
+ case Inst::kIdVrangepd:
+ case Inst::kIdVrangeps:
+ case Inst::kIdVrangesd:
+ case Inst::kIdVrangess:
+ return FormatterInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx));
+
+ case Inst::kIdVreducepd:
+ case Inst::kIdVreduceps:
+ case Inst::kIdVreducesd:
+ case Inst::kIdVreducess:
+ case Inst::kIdVrndscalepd:
+ case Inst::kIdVrndscaleps:
+ case Inst::kIdVrndscalesd:
+ case Inst::kIdVrndscaless:
+ return FormatterInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx));
+
+ case Inst::kIdVshuff32x4:
+ case Inst::kIdVshuff64x2:
+ case Inst::kIdVshufi32x4:
+ case Inst::kIdVshufi64x2: {
+ uint32_t count = Support::max<uint32_t>(vecSize / 16, 2u);
+ uint32_t bits = count <= 2 ? 1u : 2u;
+ return FormatterInternal_formatImmShuf(sb, u8, bits, count);
+ }
+
+ default:
+ return kErrorOk;
+ }
+}
+
+// ============================================================================
+// [asmjit::x86::FormatterInternal - Format Register]
+// ============================================================================
+
+ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, uint32_t flags, const BaseEmitter* emitter, uint32_t arch, uint32_t rType, uint32_t rId) noexcept {
+ DebugUtils::unused(arch);
+ const RegFormatInfo& info = x86RegFormatInfo;
+
+#ifndef ASMJIT_NO_COMPILER
+ if (Operand::isVirtId(rId)) {
+ if (emitter && emitter->emitterType() == BaseEmitter::kTypeCompiler) {
+ const BaseCompiler* cc = static_cast<const BaseCompiler*>(emitter);
+ if (cc->isVirtIdValid(rId)) {
+ VirtReg* vReg = cc->virtRegById(rId);
+ ASMJIT_ASSERT(vReg != nullptr);
+
+ const char* name = vReg->name();
+ if (name && name[0] != '\0')
+ ASMJIT_PROPAGATE(sb.append(name));
+ else
+ ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(rId))));
+
+ if (vReg->type() != rType && rType <= BaseReg::kTypeMax && (flags & FormatOptions::kFlagRegCasts) != 0) {
+ const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[rType];
+ if (typeEntry.index)
+ ASMJIT_PROPAGATE(sb.appendFormat("@%s", info.typeStrings + typeEntry.index));
+ }
+
+ return kErrorOk;
+ }
+ }
+ }
+#else
+ DebugUtils::unused(emitter, flags);
+#endif
+
+ if (ASMJIT_LIKELY(rType <= BaseReg::kTypeMax)) {
+ const RegFormatInfo::NameEntry& nameEntry = info.nameEntries[rType];
+
+ if (rId < nameEntry.specialCount)
+ return sb.append(info.nameStrings + nameEntry.specialIndex + rId * 4);
+
+ if (rId < nameEntry.count)
+ return sb.appendFormat(info.nameStrings + nameEntry.formatIndex, unsigned(rId));
+
+ const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[rType];
+ if (typeEntry.index)
+ return sb.appendFormat("%s@%u", info.typeStrings + typeEntry.index, rId);
+ }
+
+ return sb.appendFormat("Reg?%u@%u", rType, rId);
+}
+
+// ============================================================================
+// [asmjit::x86::FormatterInternal - Format Instruction]
+// ============================================================================
+
+ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
+ String& sb,
+ uint32_t flags,
+ const BaseEmitter* emitter,
+ uint32_t arch,
+ const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
+
+ uint32_t instId = inst.id();
+ uint32_t options = inst.options();
+
+ // Format instruction options and instruction mnemonic.
+ if (instId < Inst::_kIdCount) {
+ // SHORT|LONG options.
+ if (options & Inst::kOptionShortForm) ASMJIT_PROPAGATE(sb.append("short "));
+ if (options & Inst::kOptionLongForm) ASMJIT_PROPAGATE(sb.append("long "));
+
+ // LOCK|XACQUIRE|XRELEASE options.
+ if (options & Inst::kOptionXAcquire) ASMJIT_PROPAGATE(sb.append("xacquire "));
+ if (options & Inst::kOptionXRelease) ASMJIT_PROPAGATE(sb.append("xrelease "));
+ if (options & Inst::kOptionLock) ASMJIT_PROPAGATE(sb.append("lock "));
+
+ // REP|REPNE options.
+ if (options & (Inst::kOptionRep | Inst::kOptionRepne)) {
+ sb.append((options & Inst::kOptionRep) ? "rep " : "repnz ");
+ if (inst.hasExtraReg()) {
+ ASMJIT_PROPAGATE(sb.append("{"));
+ ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, inst.extraReg().toReg<BaseReg>()));
+ ASMJIT_PROPAGATE(sb.append("} "));
+ }
+ }
+
+ // REX options.
+ if (options & Inst::kOptionRex) {
+ const uint32_t kRXBWMask = Inst::kOptionOpCodeR |
+ Inst::kOptionOpCodeX |
+ Inst::kOptionOpCodeB |
+ Inst::kOptionOpCodeW ;
+ if (options & kRXBWMask) {
+ sb.append("rex.");
+ if (options & Inst::kOptionOpCodeR) sb.append('r');
+ if (options & Inst::kOptionOpCodeX) sb.append('x');
+ if (options & Inst::kOptionOpCodeB) sb.append('b');
+ if (options & Inst::kOptionOpCodeW) sb.append('w');
+ sb.append(' ');
+ }
+ else {
+ ASMJIT_PROPAGATE(sb.append("rex "));
+ }
+ }
+
+ // VEX|EVEX options.
+ if (options & Inst::kOptionVex3) ASMJIT_PROPAGATE(sb.append("vex3 "));
+ if (options & Inst::kOptionEvex) ASMJIT_PROPAGATE(sb.append("evex "));
+
+ ASMJIT_PROPAGATE(InstAPI::instIdToString(arch, instId, sb));
+ }
+ else {
+ ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
+ }
+
+ for (uint32_t i = 0; i < opCount; i++) {
+ const Operand_& op = operands[i];
+ if (op.isNone()) break;
+
+ ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
+ ASMJIT_PROPAGATE(formatOperand(sb, flags, emitter, arch, op));
+
+ if (op.isImm() && (flags & FormatOptions::kFlagExplainImms)) {
+ uint32_t vecSize = 16;
+ for (uint32_t j = 0; j < opCount; j++)
+ if (operands[j].isReg())
+ vecSize = Support::max<uint32_t>(vecSize, operands[j].size());
+ ASMJIT_PROPAGATE(FormatterInternal_explainConst(sb, flags, instId, vecSize, op.as<Imm>()));
+ }
+
+ // Support AVX-512 masking - {k}{z}.
+ if (i == 0) {
+ if (inst.extraReg().group() == Reg::kGroupKReg) {
+ ASMJIT_PROPAGATE(sb.append(" {"));
+ ASMJIT_PROPAGATE(formatRegister(sb, flags, emitter, arch, inst.extraReg().type(), inst.extraReg().id()));
+ ASMJIT_PROPAGATE(sb.append('}'));
+
+ if (options & Inst::kOptionZMask)
+ ASMJIT_PROPAGATE(sb.append("{z}"));
+ }
+ else if (options & Inst::kOptionZMask) {
+ ASMJIT_PROPAGATE(sb.append(" {z}"));
+ }
+ }
+
+ // Support AVX-512 broadcast - {1tox}.
+ if (op.isMem() && op.as<Mem>().hasBroadcast()) {
+ ASMJIT_PROPAGATE(sb.appendFormat(" {1to%u}", Support::bitMask(op.as<Mem>().getBroadcast())));
+ }
+ }
+
+ return kErrorOk;
+}
+
+ASMJIT_END_SUB_NAMESPACE
+
+#endif // !ASMJIT_NO_LOGGING