Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #include "api-build_p.h"
8 : #ifndef ASMJIT_NO_LOGGING
9 :
10 : #include "cpuinfo.h"
11 : #include "misc_p.h"
12 : #include "support.h"
13 : #include "x86formatter_p.h"
14 : #include "x86instapi_p.h"
15 : #include "x86instdb_p.h"
16 : #include "x86operand.h"
17 :
18 : #ifndef ASMJIT_NO_COMPILER
19 : #include "compiler.h"
20 : #endif
21 :
22 : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
23 :
24 : // x86::FormatterInternal - Constants
25 : // ==================================
26 :
27 : struct RegFormatInfo {
28 : struct TypeEntry {
29 : uint8_t index;
30 : };
31 :
32 : struct NameEntry {
33 : uint8_t count;
34 : uint8_t formatIndex;
35 : uint8_t specialIndex;
36 : uint8_t specialCount;
37 : };
38 :
39 : TypeEntry typeEntries[uint32_t(RegType::kMaxValue) + 1];
40 : char typeStrings[128 - 32];
41 :
42 : NameEntry nameEntries[uint32_t(RegType::kMaxValue) + 1];
43 : char nameStrings[280];
44 : };
45 :
46 : template<uint32_t X>
47 : struct RegFormatInfo_T {
48 : enum {
49 : kTypeIndex = X == uint32_t(RegType::kX86_GpbLo) ? 1 :
50 : X == uint32_t(RegType::kX86_GpbHi) ? 8 :
51 : X == uint32_t(RegType::kX86_Gpw ) ? 15 :
52 : X == uint32_t(RegType::kX86_Gpd ) ? 19 :
53 : X == uint32_t(RegType::kX86_Gpq ) ? 23 :
54 : X == uint32_t(RegType::kX86_Xmm ) ? 27 :
55 : X == uint32_t(RegType::kX86_Ymm ) ? 31 :
56 : X == uint32_t(RegType::kX86_Zmm ) ? 35 :
57 : X == uint32_t(RegType::kX86_Mm ) ? 50 :
58 : X == uint32_t(RegType::kX86_KReg ) ? 53 :
59 : X == uint32_t(RegType::kX86_SReg ) ? 43 :
60 : X == uint32_t(RegType::kX86_CReg ) ? 59 :
61 : X == uint32_t(RegType::kX86_DReg ) ? 62 :
62 : X == uint32_t(RegType::kX86_St ) ? 47 :
63 : X == uint32_t(RegType::kX86_Bnd ) ? 55 :
64 : X == uint32_t(RegType::kX86_Tmm ) ? 65 :
65 : X == uint32_t(RegType::kX86_Rip ) ? 39 : 0,
66 :
67 : kFormatIndex = X == uint32_t(RegType::kX86_GpbLo) ? 1 :
68 : X == uint32_t(RegType::kX86_GpbHi) ? 6 :
69 : X == uint32_t(RegType::kX86_Gpw ) ? 11 :
70 : X == uint32_t(RegType::kX86_Gpd ) ? 16 :
71 : X == uint32_t(RegType::kX86_Gpq ) ? 21 :
72 : X == uint32_t(RegType::kX86_Xmm ) ? 25 :
73 : X == uint32_t(RegType::kX86_Ymm ) ? 31 :
74 : X == uint32_t(RegType::kX86_Zmm ) ? 37 :
75 : X == uint32_t(RegType::kX86_Mm ) ? 60 :
76 : X == uint32_t(RegType::kX86_KReg ) ? 65 :
77 : X == uint32_t(RegType::kX86_SReg ) ? 49 :
78 : X == uint32_t(RegType::kX86_CReg ) ? 75 :
79 : X == uint32_t(RegType::kX86_DReg ) ? 80 :
80 : X == uint32_t(RegType::kX86_St ) ? 55 :
81 : X == uint32_t(RegType::kX86_Bnd ) ? 69 :
82 : X == uint32_t(RegType::kX86_Tmm ) ? 89 :
83 : X == uint32_t(RegType::kX86_Rip ) ? 43 : 0,
84 :
85 : kSpecialIndex = X == uint32_t(RegType::kX86_GpbLo) ? 96 :
86 : X == uint32_t(RegType::kX86_GpbHi) ? 128 :
87 : X == uint32_t(RegType::kX86_Gpw ) ? 161 :
88 : X == uint32_t(RegType::kX86_Gpd ) ? 160 :
89 : X == uint32_t(RegType::kX86_Gpq ) ? 192 :
90 : X == uint32_t(RegType::kX86_SReg ) ? 224 :
91 : X == uint32_t(RegType::kX86_Rip ) ? 85 : 0,
92 :
93 : kSpecialCount = X == uint32_t(RegType::kX86_GpbLo) ? 8 :
94 : X == uint32_t(RegType::kX86_GpbHi) ? 4 :
95 : X == uint32_t(RegType::kX86_Gpw ) ? 8 :
96 : X == uint32_t(RegType::kX86_Gpd ) ? 8 :
97 : X == uint32_t(RegType::kX86_Gpq ) ? 8 :
98 : X == uint32_t(RegType::kX86_SReg ) ? 7 :
99 : X == uint32_t(RegType::kX86_Rip ) ? 1 : 0
100 : };
101 : };
102 :
103 : #define ASMJIT_REG_TYPE_ENTRY(TYPE) { \
104 : RegFormatInfo_T<TYPE>::kTypeIndex \
105 : }
106 :
107 : #define ASMJIT_REG_NAME_ENTRY(TYPE) { \
108 : RegTraits<RegType(TYPE)>::kCount, \
109 : RegFormatInfo_T<TYPE>::kFormatIndex, \
110 : RegFormatInfo_T<TYPE>::kSpecialIndex, \
111 : RegFormatInfo_T<TYPE>::kSpecialCount \
112 : }
113 :
114 : static const RegFormatInfo x86RegFormatInfo = {
115 : // Register type entries and strings.
116 : { ASMJIT_LOOKUP_TABLE_32(ASMJIT_REG_TYPE_ENTRY, 0) },
117 :
118 : "\0" // #0
119 : "gpb\0\0\0\0" // #1
120 : "gpb.hi\0" // #8
121 : "gpw\0" // #15
122 : "gpd\0" // #19
123 : "gpq\0" // #23
124 : "xmm\0" // #27
125 : "ymm\0" // #31
126 : "zmm\0" // #35
127 : "rip\0" // #39
128 : "seg\0" // #43
129 : "st\0" // #47
130 : "mm\0" // #50
131 : "k\0" // #53
132 : "bnd\0" // #55
133 : "cr\0" // #59
134 : "dr\0" // #62
135 : "tmm\0" // #65
136 : ,
137 :
138 : // Register name entries and strings.
139 : { ASMJIT_LOOKUP_TABLE_32(ASMJIT_REG_NAME_ENTRY, 0) },
140 :
141 : "\0"
142 : "r%ub\0" // #1
143 : "r%uh\0" // #6
144 : "r%uw\0" // #11
145 : "r%ud\0" // #16
146 : "r%u\0" // #21
147 : "xmm%u\0" // #25
148 : "ymm%u\0" // #31
149 : "zmm%u\0" // #37
150 : "rip%u\0" // #43
151 : "seg%u\0" // #49
152 : "st%u\0" // #55
153 : "mm%u\0" // #60
154 : "k%u\0" // #65
155 : "bnd%u\0" // #69
156 : "cr%u\0" // #75
157 : "dr%u\0" // #80
158 :
159 : "rip\0" // #85
160 : "tmm%u\0" // #89
161 : "\0" // #95
162 :
163 : "al\0\0" "cl\0\0" "dl\0\0" "bl\0\0" "spl\0" "bpl\0" "sil\0" "dil\0" // #96
164 : "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
165 : "eax\0" "ecx\0" "edx\0" "ebx\0" "esp\0" "ebp\0" "esi\0" "edi\0" // #160
166 : "rax\0" "rcx\0" "rdx\0" "rbx\0" "rsp\0" "rbp\0" "rsi\0" "rdi\0" // #192
167 : "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
168 : };
169 : #undef ASMJIT_REG_NAME_ENTRY
170 : #undef ASMJIT_REG_TYPE_ENTRY
171 :
172 0 : static const char* x86GetAddressSizeString(uint32_t size) noexcept {
173 0 : switch (size) {
174 : case 1 : return "byte ptr ";
175 0 : case 2 : return "word ptr ";
176 0 : case 4 : return "dword ptr ";
177 0 : case 6 : return "fword ptr ";
178 0 : case 8 : return "qword ptr ";
179 0 : case 10: return "tbyte ptr ";
180 0 : case 16: return "xmmword ptr ";
181 0 : case 32: return "ymmword ptr ";
182 0 : case 64: return "zmmword ptr ";
183 0 : default: return "";
184 : }
185 : }
186 :
187 : // x86::FormatterInternal - Format FeatureId
188 : // =========================================
189 :
190 0 : Error FormatterInternal::formatFeature(String& sb, uint32_t featureId) noexcept {
191 : // @EnumStringBegin{"enum": "CpuFeatures::X86", "output": "sFeature", "strip": "k"}@
192 : static const char sFeatureString[] =
193 : "None\0"
194 : "MT\0"
195 : "NX\0"
196 : "3DNOW\0"
197 : "3DNOW2\0"
198 : "ADX\0"
199 : "AESNI\0"
200 : "ALTMOVCR8\0"
201 : "AMX_BF16\0"
202 : "AMX_INT8\0"
203 : "AMX_TILE\0"
204 : "AVX\0"
205 : "AVX2\0"
206 : "AVX512_4FMAPS\0"
207 : "AVX512_4VNNIW\0"
208 : "AVX512_BF16\0"
209 : "AVX512_BITALG\0"
210 : "AVX512_BW\0"
211 : "AVX512_CDI\0"
212 : "AVX512_DQ\0"
213 : "AVX512_ERI\0"
214 : "AVX512_F\0"
215 : "AVX512_FP16\0"
216 : "AVX512_IFMA\0"
217 : "AVX512_PFI\0"
218 : "AVX512_VBMI\0"
219 : "AVX512_VBMI2\0"
220 : "AVX512_VL\0"
221 : "AVX512_VNNI\0"
222 : "AVX512_VP2INTERSECT\0"
223 : "AVX512_VPOPCNTDQ\0"
224 : "AVX_VNNI\0"
225 : "BMI\0"
226 : "BMI2\0"
227 : "CET_IBT\0"
228 : "CET_SS\0"
229 : "CLDEMOTE\0"
230 : "CLFLUSH\0"
231 : "CLFLUSHOPT\0"
232 : "CLWB\0"
233 : "CLZERO\0"
234 : "CMOV\0"
235 : "CMPXCHG16B\0"
236 : "CMPXCHG8B\0"
237 : "ENCLV\0"
238 : "ENQCMD\0"
239 : "ERMS\0"
240 : "F16C\0"
241 : "FMA\0"
242 : "FMA4\0"
243 : "FPU\0"
244 : "FSGSBASE\0"
245 : "FXSR\0"
246 : "FXSROPT\0"
247 : "GEODE\0"
248 : "GFNI\0"
249 : "HLE\0"
250 : "HRESET\0"
251 : "I486\0"
252 : "LAHFSAHF\0"
253 : "LWP\0"
254 : "LZCNT\0"
255 : "MCOMMIT\0"
256 : "MMX\0"
257 : "MMX2\0"
258 : "MONITOR\0"
259 : "MONITORX\0"
260 : "MOVBE\0"
261 : "MOVDIR64B\0"
262 : "MOVDIRI\0"
263 : "MPX\0"
264 : "MSR\0"
265 : "MSSE\0"
266 : "OSXSAVE\0"
267 : "OSPKE\0"
268 : "PCLMULQDQ\0"
269 : "PCONFIG\0"
270 : "POPCNT\0"
271 : "PREFETCHW\0"
272 : "PREFETCHWT1\0"
273 : "PTWRITE\0"
274 : "RDPID\0"
275 : "RDPRU\0"
276 : "RDRAND\0"
277 : "RDSEED\0"
278 : "RDTSC\0"
279 : "RDTSCP\0"
280 : "RTM\0"
281 : "SERIALIZE\0"
282 : "SHA\0"
283 : "SKINIT\0"
284 : "SMAP\0"
285 : "SMEP\0"
286 : "SMX\0"
287 : "SNP\0"
288 : "SSE\0"
289 : "SSE2\0"
290 : "SSE3\0"
291 : "SSE4_1\0"
292 : "SSE4_2\0"
293 : "SSE4A\0"
294 : "SSSE3\0"
295 : "SVM\0"
296 : "TBM\0"
297 : "TSX\0"
298 : "TSXLDTRK\0"
299 : "UINTR\0"
300 : "VAES\0"
301 : "VMX\0"
302 : "VPCLMULQDQ\0"
303 : "WAITPKG\0"
304 : "WBNOINVD\0"
305 : "XOP\0"
306 : "XSAVE\0"
307 : "XSAVEC\0"
308 : "XSAVEOPT\0"
309 : "XSAVES\0"
310 : "<Unknown>\0";
311 :
312 : static const uint16_t sFeatureIndex[] = {
313 : 0, 5, 8, 11, 17, 24, 28, 34, 44, 53, 62, 71, 75, 80, 94, 108, 120, 134, 144,
314 : 155, 165, 176, 185, 197, 209, 220, 232, 245, 255, 267, 287, 304, 313, 317,
315 : 322, 330, 337, 346, 354, 365, 370, 377, 382, 393, 403, 409, 416, 421, 426,
316 : 430, 435, 439, 448, 453, 461, 467, 472, 476, 483, 488, 497, 501, 507, 515,
317 : 519, 524, 532, 541, 547, 557, 565, 569, 573, 578, 586, 592, 602, 610, 617,
318 : 627, 639, 647, 653, 659, 666, 673, 679, 686, 690, 700, 704, 711, 716, 721,
319 : 725, 729, 733, 738, 743, 750, 757, 763, 769, 773, 777, 781, 790, 796, 801,
320 : 805, 816, 824, 833, 837, 843, 850, 859, 866
321 : };
322 : // @EnumStringEnd@
323 :
324 0 : return sb.append(sFeatureString + sFeatureIndex[Support::min<uint32_t>(featureId, uint32_t(CpuFeatures::X86::kMaxValue) + 1)]);
325 : }
326 :
327 : // x86::FormatterInternal - Format Register
328 : // ========================================
329 :
330 0 : ASMJIT_FAVOR_SIZE Error FormatterInternal::formatRegister(String& sb, FormatFlags formatFlags, const BaseEmitter* emitter, Arch arch, RegType type, uint32_t id) noexcept {
331 : DebugUtils::unused(arch);
332 : const RegFormatInfo& info = x86RegFormatInfo;
333 :
334 : #ifndef ASMJIT_NO_COMPILER
335 0 : if (Operand::isVirtId(id)) {
336 0 : if (emitter && emitter->emitterType() == EmitterType::kCompiler) {
337 : const BaseCompiler* cc = static_cast<const BaseCompiler*>(emitter);
338 0 : if (cc->isVirtIdValid(id)) {
339 0 : VirtReg* vReg = cc->virtRegById(id);
340 : ASMJIT_ASSERT(vReg != nullptr);
341 :
342 : const char* name = vReg->name();
343 0 : if (name && name[0] != '\0')
344 0 : ASMJIT_PROPAGATE(sb.append(name));
345 : else
346 0 : ASMJIT_PROPAGATE(sb.appendFormat("%%%u", unsigned(Operand::virtIdToIndex(id))));
347 :
348 0 : if (vReg->type() != type && uint32_t(type) <= uint32_t(RegType::kMaxValue) && Support::test(formatFlags, FormatFlags::kRegCasts)) {
349 0 : const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[size_t(type)];
350 0 : if (typeEntry.index)
351 0 : ASMJIT_PROPAGATE(sb.appendFormat("@%s", info.typeStrings + typeEntry.index));
352 : }
353 :
354 0 : return kErrorOk;
355 : }
356 : }
357 : }
358 : #else
359 : DebugUtils::unused(emitter, formatFlags);
360 : #endif
361 :
362 0 : if (uint32_t(type) <= uint32_t(RegType::kMaxValue)) {
363 0 : const RegFormatInfo::NameEntry& nameEntry = info.nameEntries[size_t(type)];
364 :
365 0 : if (id < nameEntry.specialCount)
366 0 : return sb.append(info.nameStrings + nameEntry.specialIndex + id * 4);
367 :
368 0 : if (id < nameEntry.count)
369 0 : return sb.appendFormat(info.nameStrings + nameEntry.formatIndex, unsigned(id));
370 :
371 : const RegFormatInfo::TypeEntry& typeEntry = info.typeEntries[size_t(type)];
372 0 : if (typeEntry.index)
373 0 : return sb.appendFormat("%s@%u", info.typeStrings + typeEntry.index, id);
374 : }
375 :
376 0 : return sb.appendFormat("<Reg-%u>?%u", uint32_t(type), id);
377 : }
378 :
379 : // x86::FormatterInternal - Format Operand
380 : // =======================================
381 :
382 0 : ASMJIT_FAVOR_SIZE Error FormatterInternal::formatOperand(
383 : String& sb,
384 : FormatFlags formatFlags,
385 : const BaseEmitter* emitter,
386 : Arch arch,
387 : const Operand_& op) noexcept {
388 :
389 0 : if (op.isReg())
390 0 : return formatRegister(sb, formatFlags, emitter, arch, op.as<BaseReg>().type(), op.as<BaseReg>().id());
391 :
392 0 : if (op.isMem()) {
393 : const Mem& m = op.as<Mem>();
394 0 : ASMJIT_PROPAGATE(sb.append(x86GetAddressSizeString(m.size())));
395 :
396 : // Segment override prefix.
397 : uint32_t seg = m.segmentId();
398 0 : if (seg != SReg::kIdNone && seg < SReg::kIdCount)
399 0 : ASMJIT_PROPAGATE(sb.appendFormat("%s:", x86RegFormatInfo.nameStrings + 224 + size_t(seg) * 4));
400 :
401 0 : ASMJIT_PROPAGATE(sb.append('['));
402 0 : switch (m.addrType()) {
403 : case Mem::AddrType::kDefault:
404 : break;
405 0 : case Mem::AddrType::kAbs:
406 0 : ASMJIT_PROPAGATE(sb.append("abs "));
407 : break;
408 0 : case Mem::AddrType::kRel:
409 0 : ASMJIT_PROPAGATE(sb.append("rel "));
410 : break;
411 : }
412 :
413 : char opSign = '\0';
414 0 : if (m.hasBase()) {
415 : opSign = '+';
416 0 : if (m.hasBaseLabel()) {
417 0 : ASMJIT_PROPAGATE(Formatter::formatLabel(sb, formatFlags, emitter, m.baseId()));
418 : }
419 : else {
420 : FormatFlags modifiedFlags = formatFlags;
421 0 : if (m.isRegHome()) {
422 0 : ASMJIT_PROPAGATE(sb.append("&"));
423 : modifiedFlags &= ~FormatFlags::kRegCasts;
424 : }
425 0 : ASMJIT_PROPAGATE(formatRegister(sb, modifiedFlags, emitter, arch, m.baseType(), m.baseId()));
426 : }
427 : }
428 :
429 0 : if (m.hasIndex()) {
430 0 : if (opSign)
431 0 : ASMJIT_PROPAGATE(sb.append(opSign));
432 :
433 : opSign = '+';
434 0 : ASMJIT_PROPAGATE(formatRegister(sb, formatFlags, emitter, arch, m.indexType(), m.indexId()));
435 0 : if (m.hasShift())
436 0 : ASMJIT_PROPAGATE(sb.appendFormat("*%u", 1 << m.shift()));
437 : }
438 :
439 0 : uint64_t off = uint64_t(m.offset());
440 0 : if (off || !m.hasBaseOrIndex()) {
441 0 : if (int64_t(off) < 0) {
442 : opSign = '-';
443 0 : off = ~off + 1;
444 : }
445 :
446 0 : if (opSign)
447 0 : ASMJIT_PROPAGATE(sb.append(opSign));
448 :
449 : uint32_t base = 10;
450 0 : if (Support::test(formatFlags, FormatFlags::kHexOffsets) && off > 9) {
451 0 : ASMJIT_PROPAGATE(sb.append("0x", 2));
452 : base = 16;
453 : }
454 :
455 0 : ASMJIT_PROPAGATE(sb.appendUInt(off, base));
456 : }
457 :
458 0 : return sb.append(']');
459 : }
460 :
461 0 : if (op.isImm()) {
462 : const Imm& i = op.as<Imm>();
463 : int64_t val = i.value();
464 :
465 0 : if (Support::test(formatFlags, FormatFlags::kHexImms) && uint64_t(val) > 9) {
466 0 : ASMJIT_PROPAGATE(sb.append("0x", 2));
467 0 : return sb.appendUInt(uint64_t(val), 16);
468 : }
469 : else {
470 0 : return sb.appendInt(val, 10);
471 : }
472 : }
473 :
474 0 : if (op.isLabel()) {
475 0 : return Formatter::formatLabel(sb, formatFlags, emitter, op.id());
476 : }
477 :
478 0 : return sb.append("<None>");
479 : }
480 :
481 : // x86::FormatterInternal - Format Immediate (Extension)
482 : // =====================================================
483 :
484 : static constexpr char kImmCharStart = '{';
485 : static constexpr char kImmCharEnd = '}';
486 : static constexpr char kImmCharOr = '|';
487 :
488 : struct ImmBits {
489 : enum Mode : uint32_t {
490 : kModeLookup = 0,
491 : kModeFormat = 1
492 : };
493 :
494 : uint8_t mask;
495 : uint8_t shift;
496 : uint8_t mode;
497 : char text[48 - 3];
498 : };
499 :
500 0 : ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmShuf(String& sb, uint32_t u8, uint32_t bits, uint32_t count) noexcept {
501 0 : uint32_t mask = (1 << bits) - 1;
502 :
503 0 : for (uint32_t i = 0; i < count; i++, u8 >>= bits) {
504 0 : uint32_t value = u8 & mask;
505 0 : ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr));
506 0 : ASMJIT_PROPAGATE(sb.appendUInt(value));
507 : }
508 :
509 : if (kImmCharEnd)
510 0 : ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
511 :
512 : return kErrorOk;
513 : }
514 :
515 0 : ASMJIT_FAVOR_SIZE static Error FormatterInternal_formatImmBits(String& sb, uint32_t u8, const ImmBits* bits, uint32_t count) noexcept {
516 : uint32_t n = 0;
517 : char buf[64];
518 :
519 0 : for (uint32_t i = 0; i < count; i++) {
520 0 : const ImmBits& spec = bits[i];
521 :
522 0 : uint32_t value = (u8 & uint32_t(spec.mask)) >> spec.shift;
523 : const char* str = nullptr;
524 :
525 0 : switch (spec.mode) {
526 0 : case ImmBits::kModeLookup:
527 0 : str = Support::findPackedString(spec.text, value);
528 : break;
529 :
530 0 : case ImmBits::kModeFormat:
531 0 : snprintf(buf, sizeof(buf), spec.text, unsigned(value));
532 : str = buf;
533 0 : break;
534 :
535 : default:
536 : return DebugUtils::errored(kErrorInvalidState);
537 : }
538 :
539 0 : if (!str[0])
540 0 : continue;
541 :
542 0 : ASMJIT_PROPAGATE(sb.append(++n == 1 ? kImmCharStart : kImmCharOr));
543 0 : ASMJIT_PROPAGATE(sb.append(str));
544 : }
545 :
546 0 : if (n && kImmCharEnd)
547 0 : ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
548 :
549 : return kErrorOk;
550 : }
551 :
552 0 : 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 {
553 : uint32_t mask = (1u << bits) - 1;
554 : uint32_t pos = 0;
555 :
556 0 : for (uint32_t i = 0; i < count; i++, u8 >>= bits, pos += advance) {
557 0 : uint32_t value = (u8 & mask) + pos;
558 0 : ASMJIT_PROPAGATE(sb.append(i == 0 ? kImmCharStart : kImmCharOr));
559 0 : ASMJIT_PROPAGATE(sb.append(Support::findPackedString(text, value)));
560 : }
561 :
562 : if (kImmCharEnd)
563 0 : ASMJIT_PROPAGATE(sb.append(kImmCharEnd));
564 :
565 : return kErrorOk;
566 : }
567 :
568 0 : ASMJIT_FAVOR_SIZE static Error FormatterInternal_explainConst(
569 : String& sb,
570 : FormatFlags formatFlags,
571 : InstId instId,
572 : uint32_t vecSize,
573 : const Imm& imm) noexcept {
574 :
575 : DebugUtils::unused(formatFlags);
576 :
577 : static const char vcmpx[] =
578 : "EQ_OQ\0" "LT_OS\0" "LE_OS\0" "UNORD_Q\0" "NEQ_UQ\0" "NLT_US\0" "NLE_US\0" "ORD_Q\0"
579 : "EQ_UQ\0" "NGE_US\0" "NGT_US\0" "FALSE_OQ\0" "NEQ_OQ\0" "GE_OS\0" "GT_OS\0" "TRUE_UQ\0"
580 : "EQ_OS\0" "LT_OQ\0" "LE_OQ\0" "UNORD_S\0" "NEQ_US\0" "NLT_UQ\0" "NLE_UQ\0" "ORD_S\0"
581 : "EQ_US\0" "NGE_UQ\0" "NGT_UQ\0" "FALSE_OS\0" "NEQ_OS\0" "GE_OQ\0" "GT_OQ\0" "TRUE_US\0";
582 :
583 : // Why to make it compatible...
584 : static const char vpcmpx[] = "EQ\0" "LT\0" "LE\0" "FALSE\0" "NEQ\0" "GE\0" "GT\0" "TRUE\0";
585 : static const char vpcomx[] = "LT\0" "LE\0" "GT\0" "GE\0" "EQ\0" "NEQ\0" "FALSE\0" "TRUE\0";
586 :
587 : static const char vshufpd[] = "A0\0A1\0B0\0B1\0A2\0A3\0B2\0B3\0A4\0A5\0B4\0B5\0A6\0A7\0B6\0B7\0";
588 : static const char vshufps[] = "A0\0A1\0A2\0A3\0A0\0A1\0A2\0A3\0B0\0B1\0B2\0B3\0B0\0B1\0B2\0B3\0";
589 :
590 : static const ImmBits vfpclassxx[] = {
591 : { 0x07u, 0, ImmBits::kModeLookup, "QNAN\0" "+0\0" "-0\0" "+INF\0" "-INF\0" "DENORMAL\0" "-FINITE\0" "SNAN\0" }
592 : };
593 :
594 : static const ImmBits vfixupimmxx[] = {
595 : { 0x01u, 0, ImmBits::kModeLookup, "\0" "+INF_IE\0" },
596 : { 0x02u, 1, ImmBits::kModeLookup, "\0" "-VE_IE\0" },
597 : { 0x04u, 2, ImmBits::kModeLookup, "\0" "-INF_IE\0" },
598 : { 0x08u, 3, ImmBits::kModeLookup, "\0" "SNAN_IE\0" },
599 : { 0x10u, 4, ImmBits::kModeLookup, "\0" "ONE_IE\0" },
600 : { 0x20u, 5, ImmBits::kModeLookup, "\0" "ONE_ZE\0" },
601 : { 0x40u, 6, ImmBits::kModeLookup, "\0" "ZERO_IE\0" },
602 : { 0x80u, 7, ImmBits::kModeLookup, "\0" "ZERO_ZE\0" }
603 : };
604 :
605 : static const ImmBits vgetmantxx[] = {
606 : { 0x03u, 0, ImmBits::kModeLookup, "[1, 2)\0" "[.5, 2)\0" "[.5, 1)\0" "[.75, 1.5)\0" },
607 : { 0x04u, 2, ImmBits::kModeLookup, "\0" "NO_SIGN\0" },
608 : { 0x08u, 3, ImmBits::kModeLookup, "\0" "QNAN_IF_SIGN\0" }
609 : };
610 :
611 : static const ImmBits vmpsadbw[] = {
612 : { 0x04u, 2, ImmBits::kModeLookup, "BLK1[0]\0" "BLK1[1]\0" },
613 : { 0x03u, 0, ImmBits::kModeLookup, "BLK2[0]\0" "BLK2[1]\0" "BLK2[2]\0" "BLK2[3]\0" },
614 : { 0x40u, 6, ImmBits::kModeLookup, "BLK1[4]\0" "BLK1[5]\0" },
615 : { 0x30u, 4, ImmBits::kModeLookup, "BLK2[4]\0" "BLK2[5]\0" "BLK2[6]\0" "BLK2[7]\0" }
616 : };
617 :
618 : static const ImmBits vpclmulqdq[] = {
619 : { 0x01u, 0, ImmBits::kModeLookup, "LQ\0" "HQ\0" },
620 : { 0x10u, 4, ImmBits::kModeLookup, "LQ\0" "HQ\0" }
621 : };
622 :
623 : static const ImmBits vperm2x128[] = {
624 : { 0x0Bu, 0, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" },
625 : { 0xB0u, 4, ImmBits::kModeLookup, "A0\0" "A1\0" "B0\0" "B1\0" "\0" "\0" "\0" "\0" "0\0" "0\0" "0\0" "0\0" }
626 : };
627 :
628 : static const ImmBits vrangexx[] = {
629 : { 0x03u, 0, ImmBits::kModeLookup, "MIN\0" "MAX\0" "MIN_ABS\0" "MAX_ABS\0" },
630 : { 0x0Cu, 2, ImmBits::kModeLookup, "SIGN_A\0" "SIGN_B\0" "SIGN_0\0" "SIGN_1\0" }
631 : };
632 :
633 : static const ImmBits vreducexx_vrndscalexx[] = {
634 : { 0x07u, 0, ImmBits::kModeLookup, "\0" "\0" "\0" "\0" "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" },
635 : { 0x08u, 3, ImmBits::kModeLookup, "\0" "SAE\0" },
636 : { 0xF0u, 4, ImmBits::kModeFormat, "LEN=%d" }
637 : };
638 :
639 : static const ImmBits vroundxx[] = {
640 : { 0x07u, 0, ImmBits::kModeLookup, "ROUND\0" "FLOOR\0" "CEIL\0" "TRUNC\0" "\0" "\0" "\0" "\0" },
641 : { 0x08u, 3, ImmBits::kModeLookup, "\0" "INEXACT\0" }
642 : };
643 :
644 0 : uint32_t u8 = imm.valueAs<uint8_t>();
645 0 : switch (instId) {
646 0 : case Inst::kIdVblendpd:
647 : case Inst::kIdBlendpd:
648 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8);
649 :
650 0 : case Inst::kIdVblendps:
651 : case Inst::kIdBlendps:
652 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 4);
653 :
654 0 : case Inst::kIdVcmppd:
655 : case Inst::kIdVcmpps:
656 : case Inst::kIdVcmpsd:
657 : case Inst::kIdVcmpss:
658 0 : return FormatterInternal_formatImmText(sb, u8, 5, 0, vcmpx);
659 :
660 0 : case Inst::kIdCmppd:
661 : case Inst::kIdCmpps:
662 : case Inst::kIdCmpsd:
663 : case Inst::kIdCmpss:
664 0 : return FormatterInternal_formatImmText(sb, u8, 3, 0, vcmpx);
665 :
666 0 : case Inst::kIdVdbpsadbw:
667 0 : return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
668 :
669 0 : case Inst::kIdVdppd:
670 : case Inst::kIdVdpps:
671 : case Inst::kIdDppd:
672 : case Inst::kIdDpps:
673 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
674 :
675 0 : case Inst::kIdVmpsadbw:
676 : case Inst::kIdMpsadbw:
677 0 : return FormatterInternal_formatImmBits(sb, u8, vmpsadbw, Support::min<uint32_t>(vecSize / 8, 4));
678 :
679 0 : case Inst::kIdVpblendw:
680 : case Inst::kIdPblendw:
681 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
682 :
683 0 : case Inst::kIdVpblendd:
684 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, Support::min<uint32_t>(vecSize / 4, 8));
685 :
686 0 : case Inst::kIdVpclmulqdq:
687 : case Inst::kIdPclmulqdq:
688 0 : return FormatterInternal_formatImmBits(sb, u8, vpclmulqdq, ASMJIT_ARRAY_SIZE(vpclmulqdq));
689 :
690 0 : case Inst::kIdVroundpd:
691 : case Inst::kIdVroundps:
692 : case Inst::kIdVroundsd:
693 : case Inst::kIdVroundss:
694 : case Inst::kIdRoundpd:
695 : case Inst::kIdRoundps:
696 : case Inst::kIdRoundsd:
697 : case Inst::kIdRoundss:
698 0 : return FormatterInternal_formatImmBits(sb, u8, vroundxx, ASMJIT_ARRAY_SIZE(vroundxx));
699 :
700 0 : case Inst::kIdVshufpd:
701 : case Inst::kIdShufpd:
702 0 : return FormatterInternal_formatImmText(sb, u8, 1, 2, vshufpd, Support::min<uint32_t>(vecSize / 8, 8));
703 :
704 0 : case Inst::kIdVshufps:
705 : case Inst::kIdShufps:
706 0 : return FormatterInternal_formatImmText(sb, u8, 2, 4, vshufps, 4);
707 :
708 0 : case Inst::kIdVcvtps2ph:
709 0 : return FormatterInternal_formatImmBits(sb, u8, vroundxx, 1);
710 :
711 0 : case Inst::kIdVperm2f128:
712 : case Inst::kIdVperm2i128:
713 0 : return FormatterInternal_formatImmBits(sb, u8, vperm2x128, ASMJIT_ARRAY_SIZE(vperm2x128));
714 :
715 0 : case Inst::kIdVpermilpd:
716 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, vecSize / 8);
717 :
718 0 : case Inst::kIdVpermilps:
719 0 : return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
720 :
721 0 : case Inst::kIdVpshufd:
722 : case Inst::kIdPshufd:
723 0 : return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
724 :
725 0 : case Inst::kIdVpshufhw:
726 : case Inst::kIdVpshuflw:
727 : case Inst::kIdPshufhw:
728 : case Inst::kIdPshuflw:
729 : case Inst::kIdPshufw:
730 0 : return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
731 :
732 0 : case Inst::kIdVfixupimmpd:
733 : case Inst::kIdVfixupimmps:
734 : case Inst::kIdVfixupimmsd:
735 : case Inst::kIdVfixupimmss:
736 0 : return FormatterInternal_formatImmBits(sb, u8, vfixupimmxx, ASMJIT_ARRAY_SIZE(vfixupimmxx));
737 :
738 0 : case Inst::kIdVfpclasspd:
739 : case Inst::kIdVfpclassps:
740 : case Inst::kIdVfpclasssd:
741 : case Inst::kIdVfpclassss:
742 0 : return FormatterInternal_formatImmBits(sb, u8, vfpclassxx, ASMJIT_ARRAY_SIZE(vfpclassxx));
743 :
744 0 : case Inst::kIdVgetmantpd:
745 : case Inst::kIdVgetmantps:
746 : case Inst::kIdVgetmantsd:
747 : case Inst::kIdVgetmantss:
748 0 : return FormatterInternal_formatImmBits(sb, u8, vgetmantxx, ASMJIT_ARRAY_SIZE(vgetmantxx));
749 :
750 0 : case Inst::kIdVpcmpb:
751 : case Inst::kIdVpcmpd:
752 : case Inst::kIdVpcmpq:
753 : case Inst::kIdVpcmpw:
754 : case Inst::kIdVpcmpub:
755 : case Inst::kIdVpcmpud:
756 : case Inst::kIdVpcmpuq:
757 : case Inst::kIdVpcmpuw:
758 0 : return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcmpx);
759 :
760 0 : case Inst::kIdVpcomb:
761 : case Inst::kIdVpcomd:
762 : case Inst::kIdVpcomq:
763 : case Inst::kIdVpcomw:
764 : case Inst::kIdVpcomub:
765 : case Inst::kIdVpcomud:
766 : case Inst::kIdVpcomuq:
767 : case Inst::kIdVpcomuw:
768 0 : return FormatterInternal_formatImmText(sb, u8, 3, 0, vpcomx);
769 :
770 0 : case Inst::kIdVpermq:
771 : case Inst::kIdVpermpd:
772 0 : return FormatterInternal_formatImmShuf(sb, u8, 2, 4);
773 :
774 0 : case Inst::kIdVpternlogd:
775 : case Inst::kIdVpternlogq:
776 0 : return FormatterInternal_formatImmShuf(sb, u8, 1, 8);
777 :
778 0 : case Inst::kIdVrangepd:
779 : case Inst::kIdVrangeps:
780 : case Inst::kIdVrangesd:
781 : case Inst::kIdVrangess:
782 0 : return FormatterInternal_formatImmBits(sb, u8, vrangexx, ASMJIT_ARRAY_SIZE(vrangexx));
783 :
784 0 : case Inst::kIdVreducepd:
785 : case Inst::kIdVreduceps:
786 : case Inst::kIdVreducesd:
787 : case Inst::kIdVreducess:
788 : case Inst::kIdVrndscalepd:
789 : case Inst::kIdVrndscaleps:
790 : case Inst::kIdVrndscalesd:
791 : case Inst::kIdVrndscaless:
792 0 : return FormatterInternal_formatImmBits(sb, u8, vreducexx_vrndscalexx, ASMJIT_ARRAY_SIZE(vreducexx_vrndscalexx));
793 :
794 0 : case Inst::kIdVshuff32x4:
795 : case Inst::kIdVshuff64x2:
796 : case Inst::kIdVshufi32x4:
797 : case Inst::kIdVshufi64x2: {
798 0 : uint32_t count = Support::max<uint32_t>(vecSize / 16, 2u);
799 0 : uint32_t bits = count <= 2 ? 1u : 2u;
800 0 : return FormatterInternal_formatImmShuf(sb, u8, bits, count);
801 : }
802 :
803 : default:
804 : return kErrorOk;
805 : }
806 : }
807 :
808 : // x86::FormatterInternal - Format Instruction
809 : // ===========================================
810 :
811 0 : ASMJIT_FAVOR_SIZE Error FormatterInternal::formatInstruction(
812 : String& sb,
813 : FormatFlags formatFlags,
814 : const BaseEmitter* emitter,
815 : Arch arch,
816 : const BaseInst& inst, const Operand_* operands, size_t opCount) noexcept {
817 :
818 : InstId instId = inst.id();
819 : InstOptions options = inst.options();
820 :
821 : // Format instruction options and instruction mnemonic.
822 0 : if (instId < Inst::_kIdCount) {
823 : // VEX|EVEX options.
824 0 : if (Support::test(options, InstOptions::kX86_Vex))
825 0 : ASMJIT_PROPAGATE(sb.append("{vex} "));
826 :
827 0 : if (Support::test(options, InstOptions::kX86_Vex3))
828 0 : ASMJIT_PROPAGATE(sb.append("{vex3} "));
829 :
830 0 : if (Support::test(options, InstOptions::kX86_Evex))
831 0 : ASMJIT_PROPAGATE(sb.append("{evex} "));
832 :
833 : // MOD/RM and MOD/MR options
834 0 : if (Support::test(options, InstOptions::kX86_ModRM))
835 0 : ASMJIT_PROPAGATE(sb.append("{modrm} "));
836 0 : else if (Support::test(options, InstOptions::kX86_ModMR))
837 0 : ASMJIT_PROPAGATE(sb.append("{modmr} "));
838 :
839 : // SHORT|LONG options.
840 0 : if (Support::test(options, InstOptions::kShortForm))
841 0 : ASMJIT_PROPAGATE(sb.append("short "));
842 :
843 0 : if (Support::test(options, InstOptions::kLongForm))
844 0 : ASMJIT_PROPAGATE(sb.append("long "));
845 :
846 : // LOCK|XACQUIRE|XRELEASE options.
847 0 : if (Support::test(options, InstOptions::kX86_XAcquire))
848 0 : ASMJIT_PROPAGATE(sb.append("xacquire "));
849 :
850 0 : if (Support::test(options, InstOptions::kX86_XRelease))
851 0 : ASMJIT_PROPAGATE(sb.append("xrelease "));
852 :
853 0 : if (Support::test(options, InstOptions::kX86_Lock))
854 0 : ASMJIT_PROPAGATE(sb.append("lock "));
855 :
856 : // REP|REPNE options.
857 0 : if (Support::test(options, InstOptions::kX86_Rep | InstOptions::kX86_Repne)) {
858 0 : sb.append(Support::test(options, InstOptions::kX86_Rep) ? "rep " : "repnz ");
859 0 : if (inst.hasExtraReg()) {
860 0 : ASMJIT_PROPAGATE(sb.append("{"));
861 0 : ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, emitter, arch, inst.extraReg().toReg<BaseReg>()));
862 0 : ASMJIT_PROPAGATE(sb.append("} "));
863 : }
864 : }
865 :
866 : // REX options.
867 0 : if (Support::test(options, InstOptions::kX86_Rex)) {
868 : const InstOptions kRXBWMask = InstOptions::kX86_OpCodeR |
869 : InstOptions::kX86_OpCodeX |
870 : InstOptions::kX86_OpCodeB |
871 : InstOptions::kX86_OpCodeW ;
872 0 : if (Support::test(options, kRXBWMask)) {
873 0 : ASMJIT_PROPAGATE(sb.append("rex."));
874 0 : if (Support::test(options, InstOptions::kX86_OpCodeR)) sb.append('r');
875 0 : if (Support::test(options, InstOptions::kX86_OpCodeX)) sb.append('x');
876 0 : if (Support::test(options, InstOptions::kX86_OpCodeB)) sb.append('b');
877 0 : if (Support::test(options, InstOptions::kX86_OpCodeW)) sb.append('w');
878 0 : sb.append(' ');
879 : }
880 : else {
881 0 : ASMJIT_PROPAGATE(sb.append("rex "));
882 : }
883 : }
884 :
885 0 : ASMJIT_PROPAGATE(InstInternal::instIdToString(arch, instId, sb));
886 : }
887 : else {
888 0 : ASMJIT_PROPAGATE(sb.appendFormat("[InstId=#%u]", unsigned(instId)));
889 : }
890 :
891 0 : for (uint32_t i = 0; i < opCount; i++) {
892 0 : const Operand_& op = operands[i];
893 0 : if (op.isNone()) break;
894 :
895 0 : ASMJIT_PROPAGATE(sb.append(i == 0 ? " " : ", "));
896 0 : ASMJIT_PROPAGATE(formatOperand(sb, formatFlags, emitter, arch, op));
897 :
898 0 : if (op.isImm() && uint32_t(formatFlags & FormatFlags::kExplainImms)) {
899 : uint32_t vecSize = 16;
900 0 : for (uint32_t j = 0; j < opCount; j++)
901 0 : if (operands[j].isReg())
902 : vecSize = Support::max<uint32_t>(vecSize, operands[j].size());
903 0 : ASMJIT_PROPAGATE(FormatterInternal_explainConst(sb, formatFlags, instId, vecSize, op.as<Imm>()));
904 : }
905 :
906 : // Support AVX-512 masking - {k}{z}.
907 0 : if (i == 0) {
908 0 : if (inst.extraReg().group() == RegGroup::kX86_K) {
909 0 : ASMJIT_PROPAGATE(sb.append(" {"));
910 0 : ASMJIT_PROPAGATE(formatRegister(sb, formatFlags, emitter, arch, inst.extraReg().type(), inst.extraReg().id()));
911 0 : ASMJIT_PROPAGATE(sb.append('}'));
912 :
913 0 : if (Support::test(options, InstOptions::kX86_ZMask))
914 0 : ASMJIT_PROPAGATE(sb.append("{z}"));
915 : }
916 0 : else if (Support::test(options, InstOptions::kX86_ZMask)) {
917 0 : ASMJIT_PROPAGATE(sb.append(" {z}"));
918 : }
919 : }
920 :
921 : // Support AVX-512 broadcast - {1tox}.
922 0 : if (op.isMem() && op.as<Mem>().hasBroadcast()) {
923 0 : ASMJIT_PROPAGATE(sb.appendFormat(" {1to%u}", Support::bitMask(uint32_t(op.as<Mem>().getBroadcast()))));
924 : }
925 : }
926 :
927 : // Support AVX-512 embedded rounding and suppress-all-exceptions {sae}.
928 0 : if (inst.hasOption(InstOptions::kX86_ER | InstOptions::kX86_SAE)) {
929 0 : if (inst.hasOption(InstOptions::kX86_ER)) {
930 0 : uint32_t bits = uint32_t(inst.options() & InstOptions::kX86_ERMask) >> Support::ConstCTZ<uint32_t(InstOptions::kX86_ERMask)>::value;
931 :
932 0 : const char roundingModes[] = "rn\0rd\0ru\0rz";
933 0 : ASMJIT_PROPAGATE(sb.appendFormat(", {%s-sae}", roundingModes + bits * 3));
934 : }
935 : else {
936 0 : ASMJIT_PROPAGATE(sb.append(", {sae}"));
937 : }
938 : }
939 :
940 : return kErrorOk;
941 : }
942 :
943 : ASMJIT_END_SUB_NAMESPACE
944 :
945 : #endif // !ASMJIT_NO_LOGGING
946 :
947 : #endif // __PLUMED_HAS_ASMJIT
|