Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Guard]
33 : #include "./asmjit_build.h"
34 : #if defined(ASMJIT_BUILD_X86)
35 :
36 : // [Dependencies]
37 : #include "./cpuinfo.h"
38 : #include "./logging.h"
39 : #include "./misc_p.h"
40 : #include "./utils.h"
41 : #include "./x86assembler.h"
42 : #include "./x86logging_p.h"
43 :
44 : // [Api-Begin]
45 : #include "./asmjit_apibegin.h"
46 :
47 : namespace PLMD {
48 : namespace asmjit {
49 :
50 : // ============================================================================
51 : // [FastUInt8]
52 : // ============================================================================
53 :
54 : #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
55 : typedef unsigned char FastUInt8;
56 : #else
57 : typedef unsigned int FastUInt8;
58 : #endif
59 :
60 : // ============================================================================
61 : // [Constants]
62 : // ============================================================================
63 :
64 : //! \internal
65 : //!
66 : //! X86/X64 bytes used to encode important prefixes.
67 : enum X86Byte {
68 : //! 1-byte REX prefix mask.
69 : kX86ByteRex = 0x40,
70 :
71 : //! 1-byte REX.W component.
72 : kX86ByteRexW = 0x08,
73 :
74 : //! 2-byte VEX prefix:
75 : //! - `[0]` - `0xC5`.
76 : //! - `[1]` - `RvvvvLpp`.
77 : kX86ByteVex2 = 0xC5,
78 :
79 : //! 3-byte VEX prefix.
80 : //! - `[0]` - `0xC4`.
81 : //! - `[1]` - `RXBmmmmm`.
82 : //! - `[2]` - `WvvvvLpp`.
83 : kX86ByteVex3 = 0xC4,
84 :
85 : //! 3-byte XOP prefix.
86 : //! - `[0]` - `0x8F`.
87 : //! - `[1]` - `RXBmmmmm`.
88 : //! - `[2]` - `WvvvvLpp`.
89 : kX86ByteXop3 = 0x8F,
90 :
91 : //! 4-byte EVEX prefix.
92 : //! - `[0]` - `0x62`.
93 : //! - `[1]` - Payload0 or `P[ 7: 0]` - `[R X B R' 0 0 m m]`.
94 : //! - `[2]` - Payload1 or `P[15: 8]` - `[W v v v v 1 p p]`.
95 : //! - `[3]` - Payload2 or `P[23:16]` - `[z L' L b V' a a a]`.
96 : //!
97 : //! Groups:
98 : //! - `P[ 1: 0]` - OPCODE: EVEX.mmmmm, only lowest 2 bits [1:0] used.
99 : //! - `P[ 3: 2]` - ______: Must be 0.
100 : //! - `P[ 4]` - REG-ID: EVEX.R' - 5th bit of 'RRRRR'.
101 : //! - `P[ 5]` - REG-ID: EVEX.B - 4th bit of 'BBBBB'.
102 : //! - `P[ 6]` - REG-ID: EVEX.X - 5th bit of 'BBBBB' or 4th bit of 'XXXX' (with SIB).
103 : //! - `P[ 7]` - REG-ID: EVEX.R - 4th bit of 'RRRRR'.
104 : //! - `P[ 9: 8]` - OPCODE: EVEX.pp.
105 : //! - `P[ 10]` - ______: Must be 1.
106 : //! - `P[14:11]` - REG-ID: 4 bits of 'VVVV'.
107 : //! - `P[ 15]` - OPCODE: EVEX.W.
108 : //! - `P[18:16]` - REG-ID: K register k0...k7 (Merging/Zeroing Vector Ops).
109 : //! - `P[ 19]` - REG-ID: 5th bit of 'VVVVV'.
110 : //! - `P[ 20]` - OPCODE: Broadcast/Rounding Control/SAE bit.
111 : //! - `P[22.21]` - OPCODE: Vector Length (L' and L) / Rounding Control.
112 : //! - `P[ 23]` - OPCODE: Zeroing/Merging.
113 : kX86ByteEvex = 0x62
114 : };
115 :
116 : // AsmJit specific (used to encode VVVVV field in XOP/VEX/EVEX).
117 : enum VexVVVVV {
118 : kVexVVVVVShift = 7,
119 : kVexVVVVVMask = 0x1F << kVexVVVVVShift
120 : };
121 :
122 : //! \internal
123 : //!
124 : //! Instruction 2-byte/3-byte opcode prefix definition.
125 : struct X86OpCodeMM {
126 : uint8_t len;
127 : uint8_t data[3];
128 : };
129 :
130 : //! \internal
131 : //!
132 : //! Mandatory prefixes used to encode legacy [66, F3, F2] or [9B] byte.
133 : static const uint8_t x86OpCodePP[8] = { 0x00, 0x66, 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x9B };
134 :
135 : //! \internal
136 : //!
137 : //! Instruction 2-byte/3-byte opcode prefix data.
138 : static const X86OpCodeMM x86OpCodeMM[] = {
139 : { 0, { 0x00, 0x00, 0 } }, // #00 (0b0000).
140 : { 1, { 0x0F, 0x00, 0 } }, // #01 (0b0001).
141 : { 2, { 0x0F, 0x38, 0 } }, // #02 (0b0010).
142 : { 2, { 0x0F, 0x3A, 0 } }, // #03 (0b0011).
143 : { 2, { 0x0F, 0x01, 0 } }, // #04 (0b0100).
144 : { 0, { 0x00, 0x00, 0 } }, // #05 (0b0101).
145 : { 0, { 0x00, 0x00, 0 } }, // #06 (0b0110).
146 : { 0, { 0x00, 0x00, 0 } }, // #07 (0b0111).
147 : { 0, { 0x00, 0x00, 0 } }, // #08 (0b1000).
148 : { 0, { 0x00, 0x00, 0 } }, // #09 (0b1001).
149 : { 0, { 0x00, 0x00, 0 } }, // #0A (0b1010).
150 : { 0, { 0x00, 0x00, 0 } }, // #0B (0b1011).
151 : { 0, { 0x00, 0x00, 0 } }, // #0C (0b1100).
152 : { 0, { 0x00, 0x00, 0 } }, // #0D (0b1101).
153 : { 0, { 0x00, 0x00, 0 } }, // #0E (0b1110).
154 : { 0, { 0x00, 0x00, 0 } } // #0F (0b1111).
155 : };
156 :
157 : static const uint8_t x86SegmentPrefix[8] = { 0x00, 0x26, 0x2E, 0x36, 0x3E, 0x64, 0x65, 0x00 };
158 : static const uint8_t x86OpCodePushSeg[8] = { 0x00, 0x06, 0x0E, 0x16, 0x1E, 0xA0, 0xA8, 0x00 };
159 : static const uint8_t x86OpCodePopSeg[8] = { 0x00, 0x07, 0x00, 0x17, 0x1F, 0xA1, 0xA9, 0x00 };
160 :
161 : // ============================================================================
162 : // [asmjit::X86MemInfo | X86VEXPrefix | X86LLByRegType | X86CDisp8Table]
163 : // ============================================================================
164 :
165 : //! \internal
166 : //!
167 : //! Memory operand's info bits.
168 : //!
169 : //! A lookup table that contains various information based on the BASE and INDEX
170 : //! information of a memory operand. This is much better and safer than playing
171 : //! with IFs in the code and can check for errors must faster and better.
172 : enum X86MemInfo_Enum {
173 : kX86MemInfo_0 = 0x00,
174 :
175 : kX86MemInfo_BaseGp = 0x01, //!< Has BASE reg, REX.B can be 1, compatible with REX.B byte.
176 : kX86MemInfo_Index = 0x02, //!< Has INDEX reg, REX.X can be 1, compatible with REX.X byte.
177 :
178 : kX86MemInfo_BaseLabel = 0x10, //!< Base is Label.
179 : kX86MemInfo_BaseRip = 0x20, //!< Base is RIP.
180 :
181 : kX86MemInfo_67H_X86 = 0x40, //!< Address-size override in 32-bit mode.
182 : kX86MemInfo_67H_X64 = 0x80, //!< Address-size override in 64-bit mode.
183 : kX86MemInfo_67H_Mask = 0xC0 //!< Contains all address-size override bits.
184 : };
185 :
186 : template<uint32_t X>
187 : struct X86MemInfo_T {
188 : enum {
189 : B = (X ) & 0x1F,
190 : I = (X >> 5) & 0x1F,
191 :
192 : kBase = ((B >= X86Reg::kRegGpw && B <= X86Reg::kRegGpq ) ? kX86MemInfo_BaseGp :
193 : (B == X86Reg::kRegRip ) ? kX86MemInfo_BaseRip :
194 : (B == Label::kLabelTag ) ? kX86MemInfo_BaseLabel : 0),
195 :
196 : kIndex = ((I >= X86Reg::kRegGpw && I <= X86Reg::kRegGpq ) ? kX86MemInfo_Index :
197 : (I >= X86Reg::kRegXmm && I <= X86Reg::kRegZmm ) ? kX86MemInfo_Index : 0),
198 :
199 : k67H = ((B == X86Reg::kRegGpw && I == X86Reg::kRegNone) ? kX86MemInfo_67H_X86 :
200 : (B == X86Reg::kRegGpd && I == X86Reg::kRegNone) ? kX86MemInfo_67H_X64 :
201 : (B == X86Reg::kRegNone && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 :
202 : (B == X86Reg::kRegNone && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 :
203 : (B == X86Reg::kRegGpw && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 :
204 : (B == X86Reg::kRegGpd && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 :
205 : (B == X86Reg::kRegGpw && I == X86Reg::kRegXmm ) ? kX86MemInfo_67H_X86 :
206 : (B == X86Reg::kRegGpd && I == X86Reg::kRegXmm ) ? kX86MemInfo_67H_X64 :
207 : (B == X86Reg::kRegGpw && I == X86Reg::kRegYmm ) ? kX86MemInfo_67H_X86 :
208 : (B == X86Reg::kRegGpd && I == X86Reg::kRegYmm ) ? kX86MemInfo_67H_X64 :
209 : (B == X86Reg::kRegGpw && I == X86Reg::kRegZmm ) ? kX86MemInfo_67H_X86 :
210 : (B == X86Reg::kRegGpd && I == X86Reg::kRegZmm ) ? kX86MemInfo_67H_X64 :
211 : (B == Label::kLabelTag && I == X86Reg::kRegGpw ) ? kX86MemInfo_67H_X86 :
212 : (B == Label::kLabelTag && I == X86Reg::kRegGpd ) ? kX86MemInfo_67H_X64 : 0),
213 :
214 : kValue = kBase | kIndex | k67H | 0x04 | 0x08
215 : };
216 : };
217 :
218 : // The result stored in the LUT is a combination of
219 : // - 67H - Address override prefix - depends on BASE+INDEX register types and
220 : // the target architecture.
221 : // - REX - A possible combination of REX.[B|X|R|W] bits in REX prefix where
222 : // REX.B and REX.X are possibly masked out, but REX.R and REX.W are
223 : // kept as is.
224 : static const uint8_t x86MemInfo[] = { ASMJIT_TABLE_T_1024(X86MemInfo_T, kValue, 0) };
225 :
226 : // VEX3 or XOP xor bits applied to the opcode before emitted. The index to this
227 : // table is 'mmmmm' value, which contains all we need. This is only used by a
228 : // 3 BYTE VEX and XOP prefixes, 2 BYTE VEX prefix is handled differently. The
229 : // idea is to minimize the difference between VEX3 vs XOP when encoding VEX
230 : // or XOP instruction. This should minimize the code required to emit such
231 : // instructions and should also make it faster as we don't need any branch to
232 : // decide between VEX3 vs XOP.
233 : // ____ ___
234 : // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP]
235 : template<uint32_t X>
236 : struct X86VEXPrefix_T {
237 : enum { kValue = ((X & 0x08) ? kX86ByteXop3 : kX86ByteVex3) | (0xF << 19) | (0x7 << 13) };
238 : };
239 : static const uint32_t x86VEXPrefix[] = { ASMJIT_TABLE_T_16(X86VEXPrefix_T, kValue, 0) };
240 :
241 : // Table that contains LL opcode field addressed by a register size / 16. It's
242 : // used to propagate L.256 or L.512 when YMM or ZMM registers are used,
243 : // respectively.
244 : template<uint32_t X>
245 : struct X86LLBySizeDiv16_T {
246 : enum {
247 : kValue = (X & (64 >> 4)) ? X86Inst::kOpCode_LL_512 :
248 : (X & (32 >> 4)) ? X86Inst::kOpCode_LL_256 : 0
249 : };
250 : };
251 : static const uint32_t x86LLBySizeDiv16[] = { ASMJIT_TABLE_T_16(X86LLBySizeDiv16_T, kValue, 0) };
252 :
253 : // Table that contains LL opcode field addressed by a register size / 16. It's
254 : // used to propagate L.256 or L.512 when YMM or ZMM registers are used,
255 : // respectively.
256 : template<uint32_t X>
257 : struct X86LLByRegType_T {
258 : enum {
259 : kValue = X == X86Reg::kRegZmm ? X86Inst::kOpCode_LL_512 :
260 : X == X86Reg::kRegYmm ? X86Inst::kOpCode_LL_256 : 0
261 : };
262 : };
263 : static const uint32_t x86LLByRegType[] = { ASMJIT_TABLE_T_16(X86LLByRegType_T, kValue, 0) };
264 :
265 : // Table that contains a scale (shift left) based on 'TTWLL' field and
266 : // the instruction's tuple-type (TT) field. The scale is then applied to
267 : // the BASE-N stored in each opcode to calculate the final compressed
268 : // displacement used by all EVEX encoded instructions.
269 : template<uint32_t X>
270 : struct X86CDisp8SHL_T {
271 : enum {
272 : TT = (((X) >> 3) << X86Inst::kOpCode_CDTT_Shift),
273 : LL = (((X) >> 0) & 0x3),
274 : W = (((X) >> 2) & 0x1),
275 :
276 : kValue = (TT == X86Inst::kOpCode_CDTT_None ? ((LL==0) ? 0 : (LL==1) ? 0 : 0 ) :
277 : TT == X86Inst::kOpCode_CDTT_ByLL ? ((LL==0) ? 0 : (LL==1) ? 1 : 2 ) :
278 : TT == X86Inst::kOpCode_CDTT_T1W ? ((LL==0) ? W : (LL==1) ? 1+W : 2+W) :
279 : TT == X86Inst::kOpCode_CDTT_DUP ? ((LL==0) ? 0 : (LL==1) ? 2 : 3 ) : 0 ) << X86Inst::kOpCode_CDSHL_Shift
280 : };
281 : };
282 : static const uint32_t x86CDisp8SHL[] = { ASMJIT_TABLE_T_32(X86CDisp8SHL_T, kValue, 0) };
283 :
284 : // Table that contains MOD byte of a 16-bit [BASE + disp] address.
285 : // 0xFF == Invalid.
286 : static const uint8_t x86Mod16BaseTable[8] = {
287 : 0xFF, // AX -> N/A.
288 : 0xFF, // CX -> N/A.
289 : 0xFF, // DX -> N/A.
290 : 0x07, // BX -> 111.
291 : 0xFF, // SP -> N/A.
292 : 0x06, // BP -> 110.
293 : 0x04, // SI -> 100.
294 : 0x05 // DI -> 101.
295 : };
296 :
297 : // Table that contains MOD byte of a 16-bit [BASE + INDEX + disp] combination.
298 : // 0xFF == Invalid.
299 : template<uint32_t X>
300 : struct X86Mod16BaseIndexTable_T {
301 : enum {
302 : B = X >> 3,
303 : I = X & 0x7,
304 :
305 : kValue = ((B == X86Gp::kIdBx && I == X86Gp::kIdSi) || (B == X86Gp::kIdSi && I == X86Gp::kIdBx)) ? 0x00 :
306 : ((B == X86Gp::kIdBx && I == X86Gp::kIdDi) || (B == X86Gp::kIdDi && I == X86Gp::kIdBx)) ? 0x01 :
307 : ((B == X86Gp::kIdBp && I == X86Gp::kIdSi) || (B == X86Gp::kIdSi && I == X86Gp::kIdBp)) ? 0x02 :
308 : ((B == X86Gp::kIdBp && I == X86Gp::kIdDi) || (B == X86Gp::kIdDi && I == X86Gp::kIdBp)) ? 0x03 : 0xFF
309 : };
310 : };
311 : static const uint8_t x86Mod16BaseIndexTable[] = { ASMJIT_TABLE_T_64(X86Mod16BaseIndexTable_T, kValue, 0) };
312 :
313 : // ============================================================================
314 : // [asmjit::X86Assembler - Helpers]
315 : // ============================================================================
316 :
317 : static ASMJIT_INLINE bool x86IsJmpOrCall(uint32_t instId) noexcept {
318 0 : return instId == X86Inst::kIdJmp ||
319 0 : instId == X86Inst::kIdCall;
320 : }
321 :
322 : static ASMJIT_INLINE bool x86IsImplicitMem(const Operand_& op, uint32_t base) noexcept {
323 0 : return op.isMem() && op.as<X86Mem>().getBaseId() == base;
324 : }
325 :
326 : static ASMJIT_INLINE int64_t x86SignExtend32To64(int64_t imm) noexcept {
327 0 : return static_cast<int64_t>(static_cast<int32_t>(imm & 0xFFFFFFFF));
328 : }
329 :
330 : //! Get `O` field of `opCode`.
331 : static ASMJIT_INLINE uint32_t x86ExtractO(uint32_t opCode) noexcept {
332 48254 : return (opCode >> X86Inst::kOpCode_O_Shift) & 0x07;
333 : }
334 :
335 : static ASMJIT_INLINE uint32_t x86ExtractREX(uint32_t opCode, uint32_t options) noexcept {
336 : // kOpCode_REX was designed in a way that when shifted there will be no bytes
337 : // set except REX.[B|X|R|W]. The returned value forms a real REX prefix byte.
338 : // This case is tested by `X86Inst.cpp`.
339 48254 : return (opCode | options) >> X86Inst::kOpCode_REX_Shift;
340 : }
341 :
342 : //! Combine `regId` and `vvvvvId` into a single value (used by AVX and AVX-512).
343 : static ASMJIT_INLINE uint32_t x86PackRegAndVvvvv(uint32_t regId, uint32_t vvvvvId) noexcept {
344 0 : return regId + (vvvvvId << kVexVVVVVShift);
345 : }
346 :
347 : static ASMJIT_INLINE uint32_t x86OpCodeLByVMem(const Operand_& op) noexcept {
348 0 : return x86LLByRegType[op.as<X86Mem>().getIndexType()];
349 : }
350 :
351 : static ASMJIT_INLINE uint32_t x86OpCodeLBySize(uint32_t size) noexcept {
352 0 : return x86LLBySizeDiv16[size / 16];
353 : }
354 :
355 : static ASMJIT_INLINE uint32_t x86ExtractLLMM(uint32_t opCode, uint32_t options) noexcept {
356 0 : uint32_t x = opCode & (X86Inst::kOpCode_LL_Mask | X86Inst::kOpCode_MM_Mask);
357 0 : uint32_t y = options & X86Inst::kOptionVex3;
358 0 : return (x | y) >> X86Inst::kOpCode_MM_Shift;
359 : }
360 :
361 : //! Encode MOD byte.
362 : static ASMJIT_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
363 : ASMJIT_ASSERT(m <= 3);
364 : ASMJIT_ASSERT(o <= 7);
365 : ASMJIT_ASSERT(rm <= 7);
366 0 : return (m << 6) + (o << 3) + rm;
367 : }
368 :
369 : //! Encode SIB byte.
370 : static ASMJIT_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) noexcept {
371 : ASMJIT_ASSERT(s <= 3);
372 : ASMJIT_ASSERT(i <= 7);
373 : ASMJIT_ASSERT(b <= 7);
374 0 : return (s << 6) + (i << 3) + b;
375 : }
376 :
377 : // ============================================================================
378 : // [asmjit::X86Assembler - Construction / Destruction]
379 : // ============================================================================
380 :
381 1944 : X86Assembler::X86Assembler(CodeHolder* code) noexcept : Assembler() {
382 1944 : if (code)
383 1944 : code->attach(this);
384 1944 : }
385 1944 : X86Assembler::~X86Assembler() noexcept {}
386 :
387 : // ============================================================================
388 : // [asmjit::X86Assembler - Events]
389 : // ============================================================================
390 :
391 1944 : Error X86Assembler::onAttach(CodeHolder* code) noexcept {
392 : uint32_t archType = code->getArchType();
393 1944 : if (!ArchInfo::isX86Family(archType))
394 : return DebugUtils::errored(kErrorInvalidArch);
395 :
396 1944 : ASMJIT_PROPAGATE(Base::onAttach(code));
397 :
398 1944 : if (archType == ArchInfo::kTypeX86) {
399 : // 32 bit architecture - X86.
400 : _setAddressOverrideMask(kX86MemInfo_67H_X86);
401 0 : _globalOptions |= X86Inst::_kOptionInvalidRex;
402 0 : _nativeGpArray = x86OpData.gpd;
403 : }
404 : else {
405 : // 64 bit architecture - X64 or X32.
406 : _setAddressOverrideMask(kX86MemInfo_67H_X64);
407 1944 : _nativeGpArray = x86OpData.gpq;
408 : }
409 :
410 1944 : _nativeGpReg = _nativeGpArray[0];
411 1944 : return kErrorOk;
412 : }
413 :
414 0 : Error X86Assembler::onDetach(CodeHolder* code) noexcept {
415 0 : return Base::onDetach(code);
416 : }
417 :
418 : // ============================================================================
419 : // [asmjit::X86Assembler - Helpers]
420 : // ============================================================================
421 :
422 : #define EMIT_BYTE(VAL) \
423 : do { \
424 : cursor[0] = static_cast<uint8_t>((VAL) & 0xFFU); \
425 : cursor += 1; \
426 : } while (0)
427 :
428 : #define EMIT_16(VAL) \
429 : do { \
430 : Utils::writeU16uLE(cursor, \
431 : static_cast<uint32_t>((VAL) & 0xFFFFU)); \
432 : cursor += 2; \
433 : } while (0)
434 :
435 : #define EMIT_32(VAL) \
436 : do { \
437 : Utils::writeU32uLE(cursor, \
438 : static_cast<uint32_t>((VAL) & 0xFFFFFFFFU)); \
439 : cursor += 4; \
440 : } while (0)
441 :
442 : #define ADD_66H_P(EXP) \
443 : do { \
444 : opCode |= (static_cast<uint32_t>(EXP) << X86Inst::kOpCode_PP_Shift); \
445 : } while (0)
446 :
447 : #define ADD_66H_P_BY_SIZE(SIZE) \
448 : do { \
449 : opCode |= (static_cast<uint32_t>((SIZE) & 0x02)) \
450 : << (X86Inst::kOpCode_PP_Shift - 1); \
451 : } while (0)
452 :
453 : #define ADD_REX_W(EXP) \
454 : do { \
455 : if (EXP) \
456 : opCode |= X86Inst::kOpCode_W; \
457 : } while (0)
458 :
459 : #define ADD_REX_W_BY_SIZE(SIZE) \
460 : do { \
461 : if ((SIZE) == 8) \
462 : opCode |= X86Inst::kOpCode_W; \
463 : } while (0)
464 :
465 : #define ADD_PREFIX_BY_SIZE(SIZE) \
466 : do { \
467 : ADD_66H_P_BY_SIZE(SIZE); \
468 : ADD_REX_W_BY_SIZE(SIZE); \
469 : } while (0)
470 :
471 : #define ADD_VEX_W(EXP) \
472 : do { \
473 : opCode |= static_cast<uint32_t>(EXP) << X86Inst::kOpCode_W_Shift; \
474 : } while (0)
475 :
476 : #define EMIT_PP(OPCODE) \
477 : do { \
478 : uint32_t ppIndex = \
479 : ((OPCODE ) >> X86Inst::kOpCode_PP_Shift) & \
480 : (X86Inst::kOpCode_PP_FPUMask >> X86Inst::kOpCode_PP_Shift) ; \
481 : uint8_t ppCode = x86OpCodePP[ppIndex]; \
482 : \
483 : cursor[0] = ppCode; \
484 : cursor += ppIndex != 0; \
485 : } while (0)
486 :
487 : #define EMIT_MM_OP(OPCODE) \
488 : do { \
489 : uint32_t op = OPCODE & (0x00FF | X86Inst::kOpCode_MM_Mask); \
490 : \
491 : uint32_t mmIndex = op >> X86Inst::kOpCode_MM_Shift; \
492 : const X86OpCodeMM& mmCode = x86OpCodeMM[mmIndex]; \
493 : \
494 : if (mmIndex) { \
495 : cursor[0] = mmCode.data[0]; \
496 : cursor[1] = mmCode.data[1]; \
497 : cursor += mmCode.len; \
498 : } \
499 : \
500 : EMIT_BYTE(op); \
501 : } while (0)
502 :
503 : // If the operand is BPL|SPL|SIL|DIL|R8B-15B
504 : // - Force REX prefix
505 : // If the operand is AH|BH|CH|DH
506 : // - patch its index from 0..3 to 4..7 as encoded by X86.
507 : // - Disallow REX prefix.
508 : #define FIXUP_GPB(REG_OP, REG_ID) \
509 : do { \
510 : if (!static_cast<const X86Gp&>(REG_OP).isGpbHi()) { \
511 : options |= (REG_ID >= 4) ? X86Inst::kOptionRex : 0; \
512 : } \
513 : else { \
514 : options |= X86Inst::_kOptionInvalidRex; \
515 : REG_ID += 4; \
516 : } \
517 : } while (0)
518 :
519 : #define ENC_OPS1(OP0) ((Operand::kOp##OP0))
520 : #define ENC_OPS2(OP0, OP1) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3))
521 : #define ENC_OPS3(OP0, OP1, OP2) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3) + ((Operand::kOp##OP2) << 6))
522 : #define ENC_OPS4(OP0, OP1, OP2, OP3) ((Operand::kOp##OP0) + ((Operand::kOp##OP1) << 3) + ((Operand::kOp##OP2) << 6) + ((Operand::kOp##OP3) << 9))
523 :
524 : // ============================================================================
525 : // [asmjit::X86Assembler - Emit]
526 : // ============================================================================
527 :
528 48254 : Error X86Assembler::_emit(uint32_t instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_& o3) {
529 : Error err;
530 :
531 : const Operand_* rmRel; // Memory operand or operand that holds Label|Imm.
532 : uint32_t rmInfo; // Memory operand's info based on x86MemInfo.
533 : uint32_t rbReg; // Memory base or modRM register.
534 : uint32_t rxReg; // Memory index register.
535 : uint32_t opReg; // ModR/M opcode or register id.
536 : uint32_t opCode; // Instruction opcode.
537 :
538 : LabelEntry* label; // Label entry.
539 48254 : RelocEntry* re = nullptr; // Relocation entry.
540 : int32_t relOffset; // Relative offset
541 : FastUInt8 relSize = 0; // Relative size.
542 :
543 : int64_t imVal = 0; // Immediate value (must be 64-bit).
544 : FastUInt8 imLen = 0; // Immediate length.
545 :
546 : const uint32_t kSHR_W_PP = X86Inst::kOpCode_PP_Shift - 16;
547 : const uint32_t kSHR_W_EW = X86Inst::kOpCode_EW_Shift - 23;
548 :
549 48254 : uint8_t* cursor = _bufferPtr;
550 48254 : uint32_t options = static_cast<uint32_t>(instId >= X86Inst::_kIdCount) |
551 48254 : static_cast<uint32_t>((size_t)(_bufferEnd - cursor) < 16) |
552 48254 : getGlobalOptions() | getOptions();
553 :
554 48254 : const X86Inst* instData = X86InstDB::instData + instId;
555 : const X86Inst::CommonData* commonData;
556 :
557 : // Handle failure and rare cases first.
558 : const uint32_t kErrorsAndSpecialCases =
559 : CodeEmitter::kOptionMaybeFailureCase | // Error and buffer check.
560 : CodeEmitter::kOptionStrictValidation | // Strict validation.
561 : X86Inst::kOptionRep | // REP/REPZ prefix.
562 : X86Inst::kOptionRepnz | // REPNZ prefix.
563 : X86Inst::kOptionLock | // LOCK prefix.
564 : X86Inst::kOptionXAcquire | // XACQUIRE prefix.
565 : X86Inst::kOptionXRelease ; // XRELEASE prefix.
566 :
567 : // Signature of the first 3 operands.
568 48254 : uint32_t isign3 = o0.getOp() + (o1.getOp() << 3) + (o2.getOp() << 6);
569 :
570 48254 : if (ASMJIT_UNLIKELY(options & kErrorsAndSpecialCases)) {
571 : // Don't do anything if we are in error state.
572 1944 : if (_lastError) return _lastError;
573 :
574 1944 : if (options & CodeEmitter::kOptionMaybeFailureCase) {
575 : // Unknown instruction.
576 1944 : if (ASMJIT_UNLIKELY(instId >= X86Inst::_kIdCount))
577 0 : goto InvalidArgument;
578 :
579 : // Grow request, happens rarely.
580 1944 : if ((size_t)(_bufferEnd - cursor) < 16) {
581 1944 : err = _code->growBuffer(&_section->_buffer, 16);
582 1944 : if (ASMJIT_UNLIKELY(err)) goto Failed;
583 :
584 1944 : cursor = _bufferPtr;
585 1944 : options &= ~1;
586 : }
587 : }
588 :
589 : // Strict validation.
590 : #if !defined(ASMJIT_DISABLE_VALIDATION)
591 1944 : if (options & CodeEmitter::kOptionStrictValidation) {
592 : Operand_ opArray[6];
593 :
594 : opArray[0].copyFrom(o0);
595 : opArray[1].copyFrom(o1);
596 : opArray[2].copyFrom(o2);
597 : opArray[3].copyFrom(o3);
598 :
599 0 : if (options & kOptionOp4Op5Used) {
600 : opArray[4].copyFrom(_op4);
601 : opArray[5].copyFrom(_op5);
602 : }
603 : else {
604 : opArray[4].reset();
605 : opArray[5].reset();
606 : }
607 :
608 0 : err = Inst::validate(getArchType(), Inst::Detail(instId, options, _extraReg), opArray, 6);
609 0 : if (ASMJIT_UNLIKELY(err)) goto Failed;
610 : }
611 : #endif // !ASMJIT_DISABLE_VALIDATION
612 :
613 : uint32_t iFlags = instData->getFlags();
614 :
615 : // LOCK, XACQUIRE, and XRELEASE prefixes.
616 1944 : if (options & X86Inst::kOptionLock) {
617 0 : bool xAcqRel = (options & (X86Inst::kOptionXAcquire | X86Inst::kOptionXRelease)) != 0;
618 :
619 0 : if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagLock)) && !xAcqRel))
620 0 : goto InvalidLockPrefix;
621 :
622 0 : if (xAcqRel) {
623 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXAcquire) && !(iFlags & X86Inst::kFlagXAcquire)))
624 0 : goto InvalidXAcquirePrefix;
625 :
626 0 : if (ASMJIT_UNLIKELY((options & X86Inst::kOptionXRelease) && !(iFlags & X86Inst::kFlagXRelease)))
627 0 : goto InvalidXReleasePrefix;
628 :
629 0 : EMIT_BYTE((options & X86Inst::kOptionXAcquire) ? 0xF2 : 0xF3);
630 : }
631 :
632 0 : EMIT_BYTE(0xF0);
633 : }
634 :
635 : // REP and REPNZ prefixes.
636 1944 : if (options & (X86Inst::kOptionRep | X86Inst::kOptionRepnz)) {
637 0 : if (ASMJIT_UNLIKELY(!(iFlags & (X86Inst::kFlagRep | X86Inst::kFlagRepnz))))
638 0 : goto InvalidRepPrefix;
639 :
640 0 : if (_extraReg.isValid() && ASMJIT_UNLIKELY(_extraReg.getKind() != X86Reg::kKindGp || _extraReg.getId() != X86Gp::kIdCx))
641 0 : goto InvalidRepPrefix;
642 :
643 0 : EMIT_BYTE((options & X86Inst::kOptionRepnz) ? 0xF2 : 0xF3);
644 : }
645 : }
646 :
647 : // --------------------------------------------------------------------------
648 : // [Encoding Scope]
649 : // --------------------------------------------------------------------------
650 :
651 : opCode = instData->getMainOpCode();
652 : opReg = x86ExtractO(opCode);
653 : commonData = &instData->getCommonData();
654 :
655 48254 : switch (instData->getEncodingType()) {
656 0 : case X86Inst::kEncodingNone:
657 0 : goto EmitDone;
658 :
659 : // ------------------------------------------------------------------------
660 : // [X86]
661 : // ------------------------------------------------------------------------
662 :
663 0 : case X86Inst::kEncodingX86Op:
664 0 : goto EmitX86Op;
665 :
666 0 : case X86Inst::kEncodingX86Op_O_I8:
667 0 : if (ASMJIT_UNLIKELY(isign3 != ENC_OPS1(Imm)))
668 0 : goto InvalidInstruction;
669 :
670 0 : imVal = o0.as<Imm>().getUInt8();
671 : imLen = 1;
672 : ASMJIT_FALLTHROUGH;
673 :
674 0 : case X86Inst::kEncodingX86Op_O:
675 : rbReg = 0;
676 0 : goto EmitX86R;
677 :
678 0 : case X86Inst::kEncodingX86Op_xAX:
679 0 : if (isign3 == 0)
680 0 : goto EmitX86Op;
681 :
682 0 : if (isign3 == ENC_OPS1(Reg) && o0.getId() == X86Gp::kIdAx)
683 0 : goto EmitX86Op;
684 : break;
685 :
686 0 : case X86Inst::kEncodingX86Op_xDX_xAX:
687 0 : if (isign3 == 0)
688 0 : goto EmitX86Op;
689 :
690 0 : if (isign3 == ENC_OPS2(Reg, Reg) && o0.getId() == X86Gp::kIdDx &&
691 : o1.getId() == X86Gp::kIdAx)
692 0 : goto EmitX86Op;
693 : break;
694 :
695 0 : case X86Inst::kEncodingX86Op_ZAX:
696 0 : if (isign3 == 0)
697 0 : goto EmitX86Op;
698 :
699 : rmRel = &o0;
700 0 : if (isign3 == ENC_OPS1(Mem) && x86IsImplicitMem(o0, X86Gp::kIdAx))
701 0 : goto EmitX86OpImplicitMem;
702 :
703 : break;
704 :
705 0 : case X86Inst::kEncodingX86I_xAX:
706 : // Implicit form.
707 0 : if (isign3 == ENC_OPS1(Imm)) {
708 0 : imVal = o0.as<Imm>().getUInt8();
709 : imLen = 1;
710 0 : goto EmitX86Op;
711 : }
712 :
713 : // Explicit form.
714 0 : if (isign3 == ENC_OPS2(Reg, Imm) && o0.getId() == X86Gp::kIdAx) {
715 0 : imVal = o1.as<Imm>().getUInt8();
716 : imLen = 1;
717 0 : goto EmitX86Op;
718 : }
719 : break;
720 :
721 : case X86Inst::kEncodingX86M:
722 : rbReg = o0.getId();
723 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
724 :
725 0 : if (isign3 == ENC_OPS1(Reg))
726 0 : goto EmitX86R;
727 :
728 : rmRel = &o0;
729 0 : if (isign3 == ENC_OPS1(Mem))
730 0 : goto EmitX86M;
731 : break;
732 :
733 : case X86Inst::kEncodingX86M_GPB_MulDiv:
734 0 : CaseX86M_GPB_MulDiv:
735 : // Explicit form?
736 0 : if (isign3 > 0x7) {
737 : // [AX] <- [AX] div|mul r8.
738 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
739 0 : if (ASMJIT_UNLIKELY(!X86Reg::isGpw(o0, X86Gp::kIdAx) || !X86Reg::isGpb(o1)))
740 0 : goto InvalidInstruction;
741 :
742 : rbReg = o1.getId();
743 0 : FIXUP_GPB(o1, rbReg);
744 0 : goto EmitX86R;
745 : }
746 :
747 : // [AX] <- [AX] div|mul m8.
748 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
749 0 : if (ASMJIT_UNLIKELY(!X86Reg::isGpw(o0, X86Gp::kIdAx)))
750 0 : goto InvalidInstruction;
751 :
752 : rmRel = &o1;
753 0 : goto EmitX86M;
754 : }
755 :
756 : // [?DX:?AX] <- [?DX:?AX] div|mul r16|r32|r64
757 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
758 0 : if (ASMJIT_UNLIKELY(o0.getSize() != o1.getSize()))
759 0 : goto InvalidInstruction;
760 : rbReg = o2.getId();
761 :
762 0 : opCode++;
763 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
764 0 : goto EmitX86R;
765 : }
766 :
767 : // [?DX:?AX] <- [?DX:?AX] div|mul m16|m32|m64
768 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
769 0 : if (ASMJIT_UNLIKELY(o0.getSize() != o1.getSize()))
770 0 : goto InvalidInstruction;
771 : rmRel = &o2;
772 :
773 0 : opCode++;
774 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
775 0 : goto EmitX86M;
776 : }
777 :
778 0 : goto InvalidInstruction;
779 : }
780 :
781 : ASMJIT_FALLTHROUGH;
782 :
783 : case X86Inst::kEncodingX86M_GPB:
784 0 : if (isign3 == ENC_OPS1(Reg)) {
785 : rbReg = o0.getId();
786 0 : if (o0.getSize() == 1) {
787 0 : FIXUP_GPB(o0, rbReg);
788 0 : goto EmitX86R;
789 : }
790 : else {
791 0 : opCode++;
792 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
793 0 : goto EmitX86R;
794 : }
795 : }
796 :
797 0 : if (isign3 == ENC_OPS1(Mem)) {
798 0 : if (ASMJIT_UNLIKELY(o0.getSize() == 0))
799 0 : goto AmbiguousOperandSize;
800 : rmRel = &o0;
801 :
802 0 : opCode += o0.getSize() != 1;
803 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
804 0 : goto EmitX86M;
805 : }
806 : break;
807 :
808 0 : case X86Inst::kEncodingX86M_Only:
809 0 : if (isign3 == ENC_OPS1(Mem)) {
810 : rmRel = &o0;
811 0 : goto EmitX86M;
812 : }
813 : break;
814 :
815 : case X86Inst::kEncodingX86Rm:
816 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
817 : ASMJIT_FALLTHROUGH;
818 :
819 : case X86Inst::kEncodingX86Rm_NoRexW:
820 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
821 : opReg = o0.getId();
822 : rbReg = o1.getId();
823 0 : goto EmitX86R;
824 : }
825 :
826 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
827 : opReg = o0.getId();
828 : rmRel = &o1;
829 0 : goto EmitX86M;
830 : }
831 : break;
832 :
833 0 : case X86Inst::kEncodingX86Rm_Raw66H:
834 : // We normally emit either [66|F2|F3], this instruction requires 66+[F2|F3].
835 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
836 : opReg = o0.getId();
837 : rbReg = o1.getId();
838 :
839 0 : if (o0.getSize() == 2)
840 0 : EMIT_BYTE(0x66);
841 : else
842 0 : ADD_REX_W_BY_SIZE(o0.getSize());
843 0 : goto EmitX86R;
844 : }
845 :
846 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
847 : opReg = o0.getId();
848 : rmRel = &o1;
849 :
850 0 : if (o0.getSize() == 2)
851 0 : EMIT_BYTE(0x66);
852 : else
853 0 : ADD_REX_W_BY_SIZE(o0.getSize());
854 0 : goto EmitX86M;
855 : }
856 : break;
857 :
858 : case X86Inst::kEncodingX86Mr:
859 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
860 : ASMJIT_FALLTHROUGH;
861 :
862 : case X86Inst::kEncodingX86Mr_NoSize:
863 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
864 : rbReg = o0.getId();
865 : opReg = o1.getId();
866 0 : goto EmitX86R;
867 : }
868 :
869 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
870 : rmRel = &o0;
871 : opReg = o1.getId();
872 0 : goto EmitX86M;
873 : }
874 : break;
875 :
876 1864 : case X86Inst::kEncodingX86Arith:
877 1864 : if (isign3 == ENC_OPS2(Reg, Reg)) {
878 0 : if (o0.getSize() != o1.getSize())
879 0 : goto OperandSizeMismatch;
880 :
881 : opReg = o0.getId();
882 : rbReg = o1.getId();
883 :
884 0 : if (o0.getSize() == 1) {
885 0 : opCode += 2;
886 0 : FIXUP_GPB(o0, opReg);
887 0 : FIXUP_GPB(o1, rbReg);
888 :
889 0 : if (!(options & X86Inst::kOptionModMR))
890 0 : goto EmitX86R;
891 :
892 : opCode -= 2;
893 : Utils::swap(opReg, rbReg);
894 0 : goto EmitX86R;
895 : }
896 : else {
897 0 : opCode += 3;
898 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
899 :
900 0 : if (!(options & X86Inst::kOptionModMR))
901 0 : goto EmitX86R;
902 :
903 0 : opCode -= 2;
904 : Utils::swap(opReg, rbReg);
905 0 : goto EmitX86R;
906 : }
907 : }
908 :
909 1864 : if (isign3 == ENC_OPS2(Reg, Mem)) {
910 : opReg = o0.getId();
911 : rmRel = &o1;
912 :
913 0 : if (o0.getSize() == 1) {
914 0 : FIXUP_GPB(o0, opReg);
915 0 : opCode += 2;
916 0 : goto EmitX86M;
917 : }
918 : else {
919 0 : opCode += 3;
920 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
921 0 : goto EmitX86M;
922 : }
923 : }
924 :
925 1864 : if (isign3 == ENC_OPS2(Mem, Reg)) {
926 : opReg = o1.getId();
927 : rmRel = &o0;
928 :
929 0 : if (o1.getSize() == 1) {
930 0 : FIXUP_GPB(o1, opReg);
931 0 : goto EmitX86M;
932 : }
933 : else {
934 0 : opCode++;
935 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
936 0 : goto EmitX86M;
937 : }
938 : }
939 :
940 : // The remaining instructions use 0x80 opcode.
941 : opCode = 0x80;
942 :
943 1864 : if (isign3 == ENC_OPS2(Reg, Imm)) {
944 1864 : uint32_t size = o0.getSize();
945 :
946 : rbReg = o0.getId();
947 : imVal = static_cast<const Imm&>(o1).getInt64();
948 :
949 1864 : if (size == 1) {
950 0 : FIXUP_GPB(o0, rbReg);
951 : imLen = 1;
952 : }
953 : else {
954 1864 : if (size == 2) {
955 : ADD_66H_P(1);
956 : }
957 1864 : else if (size == 4) {
958 : // Sign extend so isInt8 returns the right result.
959 : imVal = x86SignExtend32To64(imVal);
960 : }
961 1864 : else if (size == 8) {
962 : // In 64-bit mode it's not possible to use 64-bit immediate.
963 1864 : if (Utils::isUInt32(imVal)) {
964 : // Zero-extend `and` by using a 32-bit GPD destination instead of a 64-bit GPQ.
965 1864 : if (instId == X86Inst::kIdAnd)
966 0 : size = 4;
967 1864 : else if (!Utils::isInt32(imVal))
968 0 : goto InvalidImmediate;
969 : }
970 1864 : ADD_REX_W_BY_SIZE(size);
971 : }
972 :
973 3728 : imLen = std::min<uint32_t>(size, 4);
974 1864 : if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm))
975 : imLen = 1;
976 : }
977 :
978 : // Alternate Form - AL, AX, EAX, RAX.
979 1864 : if (rbReg == 0 && (size == 1 || imLen != 1) && !(options & X86Inst::kOptionLongForm)) {
980 0 : opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W;
981 0 : opCode |= ((opReg << 3) | (0x04 + (size != 1)));
982 0 : imLen = std::min<uint32_t>(size, 4);
983 0 : goto EmitX86Op;
984 : }
985 :
986 1864 : opCode += size != 1 ? (imLen != 1 ? 1 : 3) : 0;
987 1864 : goto EmitX86R;
988 : }
989 :
990 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
991 0 : uint32_t memSize = o0.getSize();
992 :
993 0 : if (ASMJIT_UNLIKELY(memSize == 0))
994 0 : goto AmbiguousOperandSize;
995 :
996 : imVal = static_cast<const Imm&>(o1).getInt64();
997 0 : imLen = std::min<uint32_t>(memSize, 4);
998 :
999 : // Sign extend so isInt8 returns the right result.
1000 0 : if (memSize == 4)
1001 : imVal = x86SignExtend32To64(imVal);
1002 :
1003 0 : if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm))
1004 : imLen = 1;
1005 :
1006 0 : opCode += memSize != 1 ? (imLen != 1 ? 1 : 3) : 0;
1007 0 : ADD_PREFIX_BY_SIZE(memSize);
1008 :
1009 : rmRel = &o0;
1010 0 : goto EmitX86M;
1011 : }
1012 : break;
1013 :
1014 0 : case X86Inst::kEncodingX86Bswap:
1015 0 : if (isign3 == ENC_OPS1(Reg)) {
1016 0 : if (ASMJIT_UNLIKELY(o0.getSize() < 4))
1017 0 : goto InvalidInstruction;
1018 :
1019 : opReg = o0.getId();
1020 0 : ADD_REX_W_BY_SIZE(o0.getSize());
1021 0 : goto EmitX86OpReg;
1022 : }
1023 : break;
1024 :
1025 0 : case X86Inst::kEncodingX86Bt:
1026 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1027 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1028 : opReg = o1.getId();
1029 : rbReg = o0.getId();
1030 0 : goto EmitX86R;
1031 : }
1032 :
1033 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1034 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1035 : opReg = o1.getId();
1036 : rmRel = &o0;
1037 0 : goto EmitX86M;
1038 : }
1039 :
1040 : // The remaining instructions use the secondary opcode/r.
1041 : imVal = static_cast<const Imm&>(o1).getInt64();
1042 : imLen = 1;
1043 :
1044 : opCode = commonData->getAltOpCode();
1045 : opReg = x86ExtractO(opCode);
1046 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1047 :
1048 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1049 : rbReg = o0.getId();
1050 0 : goto EmitX86R;
1051 : }
1052 :
1053 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1054 0 : if (ASMJIT_UNLIKELY(o0.getSize() == 0))
1055 0 : goto AmbiguousOperandSize;
1056 :
1057 : rmRel = &o0;
1058 0 : goto EmitX86M;
1059 : }
1060 : break;
1061 :
1062 1636 : case X86Inst::kEncodingX86Call:
1063 1636 : if (isign3 == ENC_OPS1(Reg)) {
1064 : rbReg = o0.getId();
1065 1636 : goto EmitX86R;
1066 : }
1067 :
1068 : rmRel = &o0;
1069 0 : if (isign3 == ENC_OPS1(Mem))
1070 0 : goto EmitX86M;
1071 :
1072 : // Call with 32-bit displacement use 0xE8 opcode. Call with 8-bit
1073 : // displacement is not encodable so the alternative opcode field
1074 : // in X86DB must be zero.
1075 : opCode = 0xE8;
1076 : opReg = 0;
1077 0 : goto EmitJmpCall;
1078 :
1079 0 : case X86Inst::kEncodingX86Cmpxchg: {
1080 : // Convert explicit to implicit.
1081 0 : if (isign3 & (0x7 << 6)) {
1082 0 : if (!X86Reg::isGp(o2) || o2.getId() != X86Gp::kIdAx)
1083 0 : goto InvalidInstruction;
1084 0 : isign3 &= 0x3F;
1085 : }
1086 :
1087 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1088 0 : if (o0.getSize() != o1.getSize())
1089 0 : goto OperandSizeMismatch;
1090 :
1091 : rbReg = o0.getId();
1092 : opReg = o1.getId();
1093 :
1094 0 : if (o0.getSize() == 1) {
1095 0 : FIXUP_GPB(o0, rbReg);
1096 0 : FIXUP_GPB(o1, opReg);
1097 0 : goto EmitX86R;
1098 : }
1099 : else {
1100 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1101 0 : opCode++;
1102 0 : goto EmitX86R;
1103 : }
1104 : }
1105 :
1106 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1107 : opReg = o1.getId();
1108 : rmRel = &o0;
1109 :
1110 0 : if (o1.getSize() == 1) {
1111 0 : FIXUP_GPB(o0, opReg);
1112 0 : goto EmitX86M;
1113 : }
1114 : else {
1115 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1116 0 : opCode++;
1117 0 : goto EmitX86M;
1118 : }
1119 : }
1120 : break;
1121 : }
1122 :
1123 : case X86Inst::kEncodingX86Crc:
1124 : opReg = o0.getId();
1125 0 : ADD_REX_W_BY_SIZE(o0.getSize());
1126 :
1127 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1128 : rbReg = o1.getId();
1129 :
1130 0 : if (o1.getSize() == 1) {
1131 0 : FIXUP_GPB(o1, rbReg);
1132 0 : goto EmitX86R;
1133 : }
1134 : else {
1135 : // This seems to be the only exception of encoding 66F2 PP prefix.
1136 0 : if (o1.getSize() == 2) EMIT_BYTE(0x66);
1137 :
1138 0 : opCode++;
1139 0 : goto EmitX86R;
1140 : }
1141 : }
1142 :
1143 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1144 : rmRel = &o1;
1145 0 : if (o1.getSize() == 0)
1146 0 : goto AmbiguousOperandSize;
1147 :
1148 : // This seems to be the only exception of encoding 66F2 PP prefix.
1149 0 : if (o1.getSize() == 2) EMIT_BYTE(0x66);
1150 :
1151 0 : opCode += o1.getSize() != 1;
1152 0 : goto EmitX86M;
1153 : }
1154 : break;
1155 :
1156 0 : case X86Inst::kEncodingX86Enter:
1157 0 : if (isign3 == ENC_OPS2(Imm, Imm)) {
1158 : uint32_t iw = static_cast<const Imm&>(o0).getUInt16();
1159 : uint32_t ib = static_cast<const Imm&>(o1).getUInt8();
1160 :
1161 0 : imVal = iw | (ib << 16);
1162 : imLen = 3;
1163 0 : goto EmitX86Op;
1164 : }
1165 : break;
1166 :
1167 0 : case X86Inst::kEncodingX86Imul:
1168 : // First process all forms distinct of `kEncodingX86M_OptB_MulDiv`.
1169 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
1170 : opCode = 0x6B;
1171 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1172 :
1173 : imVal = static_cast<const Imm&>(o2).getInt64();
1174 : imLen = 1;
1175 :
1176 0 : if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) {
1177 0 : opCode -= 2;
1178 0 : imLen = o0.getSize() == 2 ? 2 : 4;
1179 : }
1180 :
1181 : opReg = o0.getId();
1182 : rbReg = o1.getId();
1183 :
1184 0 : goto EmitX86R;
1185 : }
1186 :
1187 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
1188 : opCode = 0x6B;
1189 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1190 :
1191 : imVal = static_cast<const Imm&>(o2).getInt64();
1192 : imLen = 1;
1193 :
1194 : // Sign extend so isInt8 returns the right result.
1195 0 : if (o0.getSize() == 4)
1196 : imVal = x86SignExtend32To64(imVal);
1197 :
1198 0 : if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) {
1199 0 : opCode -= 2;
1200 0 : imLen = o0.getSize() == 2 ? 2 : 4;
1201 : }
1202 :
1203 : opReg = o0.getId();
1204 : rmRel = &o1;
1205 :
1206 0 : goto EmitX86M;
1207 : }
1208 :
1209 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1210 : // Must be explicit 'ax, r8' form.
1211 0 : if (o1.getSize() == 1)
1212 0 : goto CaseX86M_GPB_MulDiv;
1213 :
1214 0 : if (o0.getSize() != o1.getSize())
1215 0 : goto OperandSizeMismatch;
1216 :
1217 : opReg = o0.getId();
1218 : rbReg = o1.getId();
1219 :
1220 : opCode = X86Inst::kOpCode_MM_0F | 0xAF;
1221 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1222 0 : goto EmitX86R;
1223 : }
1224 :
1225 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1226 : // Must be explicit 'ax, m8' form.
1227 0 : if (o1.getSize() == 1)
1228 0 : goto CaseX86M_GPB_MulDiv;
1229 :
1230 : opReg = o0.getId();
1231 : rmRel = &o1;
1232 :
1233 : opCode = X86Inst::kOpCode_MM_0F | 0xAF;
1234 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1235 0 : goto EmitX86M;
1236 : }
1237 :
1238 : // Shorthand to imul 'reg, reg, imm'.
1239 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1240 : opCode = 0x6B;
1241 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1242 :
1243 : imVal = static_cast<const Imm&>(o1).getInt64();
1244 : imLen = 1;
1245 :
1246 : // Sign extend so isInt8 returns the right result.
1247 0 : if (o0.getSize() == 4)
1248 : imVal = x86SignExtend32To64(imVal);
1249 :
1250 0 : if (!Utils::isInt8(imVal) || (options & X86Inst::kOptionLongForm)) {
1251 0 : opCode -= 2;
1252 0 : imLen = o0.getSize() == 2 ? 2 : 4;
1253 : }
1254 :
1255 : opReg = rbReg = o0.getId();
1256 0 : goto EmitX86R;
1257 : }
1258 :
1259 : // Try implicit form.
1260 0 : goto CaseX86M_GPB_MulDiv;
1261 :
1262 0 : case X86Inst::kEncodingX86In:
1263 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1264 0 : if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx))
1265 0 : goto InvalidInstruction;
1266 :
1267 0 : imVal = o1.as<Imm>().getUInt8();
1268 : imLen = 1;
1269 :
1270 0 : opCode = commonData->getAltOpCode() + (o0.getSize() != 1);
1271 0 : ADD_66H_P_BY_SIZE(o0.getSize());
1272 0 : goto EmitX86Op;
1273 : }
1274 :
1275 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1276 0 : if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx || o1.getId() != X86Gp::kIdDx))
1277 0 : goto InvalidInstruction;
1278 :
1279 0 : opCode += o0.getSize() != 1;
1280 0 : ADD_66H_P_BY_SIZE(o0.getSize());
1281 0 : goto EmitX86Op;
1282 : }
1283 : break;
1284 :
1285 0 : case X86Inst::kEncodingX86Ins:
1286 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1287 0 : if (ASMJIT_UNLIKELY(!x86IsImplicitMem(o0, X86Gp::kIdDi) || o1.getId() != X86Gp::kIdDx))
1288 0 : goto InvalidInstruction;
1289 :
1290 : uint32_t size = o0.getSize();
1291 0 : if (ASMJIT_UNLIKELY(size == 0))
1292 0 : goto AmbiguousOperandSize;
1293 :
1294 : rmRel = &o0;
1295 0 : opCode += (size != 1);
1296 :
1297 0 : ADD_66H_P_BY_SIZE(size);
1298 0 : goto EmitX86OpImplicitMem;
1299 : }
1300 : break;
1301 :
1302 0 : case X86Inst::kEncodingX86IncDec:
1303 0 : if (isign3 == ENC_OPS1(Reg)) {
1304 : rbReg = o0.getId();
1305 :
1306 0 : if (o0.getSize() == 1) {
1307 0 : FIXUP_GPB(o0, rbReg);
1308 0 : goto EmitX86R;
1309 : }
1310 :
1311 0 : if (is32Bit()) {
1312 : // INC r16|r32 is only encodable in 32-bit mode (collides with REX).
1313 0 : opCode = commonData->getAltOpCode() + (rbReg & 0x07);
1314 0 : ADD_66H_P_BY_SIZE(o0.getSize());
1315 0 : goto EmitX86Op;
1316 : }
1317 : else {
1318 0 : opCode++;
1319 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1320 0 : goto EmitX86R;
1321 : }
1322 : }
1323 :
1324 0 : if (isign3 == ENC_OPS1(Mem)) {
1325 : rmRel = &o0;
1326 0 : opCode += o0.getSize() != 1;
1327 :
1328 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1329 0 : goto EmitX86M;
1330 : }
1331 : break;
1332 :
1333 0 : case X86Inst::kEncodingX86Int:
1334 0 : if (isign3 == ENC_OPS1(Imm)) {
1335 : imVal = static_cast<const Imm&>(o0).getInt64();
1336 : imLen = 1;
1337 0 : goto EmitX86Op;
1338 : }
1339 : break;
1340 :
1341 0 : case X86Inst::kEncodingX86Jcc:
1342 0 : if (_globalHints & CodeEmitter::kHintPredictedJumps) {
1343 0 : if (options & X86Inst::kOptionTaken)
1344 0 : EMIT_BYTE(0x3E);
1345 0 : if (options & X86Inst::kOptionNotTaken)
1346 0 : EMIT_BYTE(0x2E);
1347 : }
1348 :
1349 : rmRel = &o0;
1350 : opReg = 0;
1351 0 : goto EmitJmpCall;
1352 :
1353 0 : case X86Inst::kEncodingX86JecxzLoop:
1354 : rmRel = &o0;
1355 : // Explicit jecxz|loop [r|e]cx, dst
1356 0 : if (o0.isReg()) {
1357 0 : if (ASMJIT_UNLIKELY(!X86Reg::isGp(o0, X86Gp::kIdCx)))
1358 0 : goto InvalidInstruction;
1359 :
1360 0 : if ((is32Bit() && o0.getSize() == 2) || (is64Bit() && o0.getSize() == 4))
1361 0 : EMIT_BYTE(0x67);
1362 :
1363 : rmRel = &o1;
1364 : }
1365 :
1366 : opReg = 0;
1367 0 : goto EmitJmpCall;
1368 :
1369 0 : case X86Inst::kEncodingX86Jmp:
1370 0 : if (isign3 == ENC_OPS1(Reg)) {
1371 : rbReg = o0.getId();
1372 0 : goto EmitX86R;
1373 : }
1374 :
1375 : rmRel = &o0;
1376 0 : if (isign3 == ENC_OPS1(Mem))
1377 0 : goto EmitX86M;
1378 :
1379 : // Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded
1380 : // with 8-bit displacement's opcode is stored as an alternative opcode.
1381 : opCode = 0xE9;
1382 : opReg = 0;
1383 0 : goto EmitJmpCall;
1384 :
1385 0 : case X86Inst::kEncodingX86JmpRel:
1386 : rmRel = &o0;
1387 0 : goto EmitJmpCall;
1388 :
1389 0 : case X86Inst::kEncodingX86Lea:
1390 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1391 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1392 : opReg = o0.getId();
1393 : rmRel = &o1;
1394 0 : goto EmitX86M;
1395 : }
1396 : break;
1397 :
1398 7652 : case X86Inst::kEncodingX86Mov:
1399 : // Reg <- Reg
1400 7652 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1401 : opReg = o0.getId();
1402 : rbReg = o1.getId();
1403 :
1404 : // Asmjit uses segment registers indexed from 1 to 6, leaving zero as
1405 : // "no segment register used". We have to fix this (decrement the index
1406 : // of the register) when emitting MOV instructions which move to/from
1407 : // a segment register. The segment register is always `opReg`, because
1408 : // the MOV instruction uses either RM or MR encoding.
1409 :
1410 : // GP <- ??
1411 0 : if (X86Reg::isGp(o0)) {
1412 : // GP <- GP
1413 0 : if (X86Reg::isGp(o1)) {
1414 : uint32_t size0 = o0.getSize();
1415 : uint32_t size1 = o1.getSize();
1416 :
1417 0 : if (size0 != size1) {
1418 : // We allow 'mov r64, r32' as it's basically zero-extend.
1419 0 : if (size0 == 8 && size1 == 4)
1420 : size0 = 4; // Zero extend, don't promote to 64-bit.
1421 : else
1422 0 : goto InvalidInstruction;
1423 : }
1424 :
1425 0 : if (size0 == 1) {
1426 0 : FIXUP_GPB(o0, opReg);
1427 0 : FIXUP_GPB(o1, rbReg);
1428 : opCode = 0x8A;
1429 :
1430 0 : if (!(options & X86Inst::kOptionModMR))
1431 0 : goto EmitX86R;
1432 :
1433 : opCode -= 2;
1434 : Utils::swap(opReg, rbReg);
1435 0 : goto EmitX86R;
1436 : }
1437 : else {
1438 : opCode = 0x8B;
1439 0 : ADD_PREFIX_BY_SIZE(size0);
1440 :
1441 0 : if (!(options & X86Inst::kOptionModMR))
1442 0 : goto EmitX86R;
1443 :
1444 0 : opCode -= 2;
1445 : Utils::swap(opReg, rbReg);
1446 0 : goto EmitX86R;
1447 : }
1448 : }
1449 :
1450 : opReg = rbReg;
1451 : rbReg = o0.getId();
1452 :
1453 : // GP <- SEG
1454 0 : if (X86Reg::isSeg(o1)) {
1455 : opCode = 0x8C;
1456 0 : opReg--;
1457 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1458 0 : goto EmitX86R;
1459 : }
1460 :
1461 : // GP <- CR
1462 0 : if (X86Reg::isCr(o1)) {
1463 : opCode = 0x20 | X86Inst::kOpCode_MM_0F;
1464 :
1465 : // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
1466 0 : if ((opReg & 0x8) && is32Bit()) {
1467 0 : EMIT_BYTE(0xF0);
1468 0 : opReg &= 0x7;
1469 : }
1470 0 : goto EmitX86R;
1471 : }
1472 :
1473 : // GP <- DR
1474 0 : if (X86Reg::isDr(o1)) {
1475 : opCode = 0x21 | X86Inst::kOpCode_MM_0F;
1476 0 : goto EmitX86R;
1477 : }
1478 : }
1479 : else {
1480 : // ?? <- GP
1481 0 : if (!X86Reg::isGp(o1))
1482 0 : goto InvalidInstruction;
1483 :
1484 : // SEG <- GP
1485 0 : if (X86Reg::isSeg(o0)) {
1486 : opCode = 0x8E;
1487 0 : opReg--;
1488 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1489 0 : goto EmitX86R;
1490 : }
1491 :
1492 : // CR <- GP
1493 0 : if (X86Reg::isCr(o0)) {
1494 : opCode = 0x22 | X86Inst::kOpCode_MM_0F;
1495 :
1496 : // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
1497 0 : if ((opReg & 0x8) && is32Bit()) {
1498 0 : EMIT_BYTE(0xF0);
1499 0 : opReg &= 0x7;
1500 : }
1501 0 : goto EmitX86R;
1502 : }
1503 :
1504 : // DR <- GP
1505 0 : if (X86Reg::isDr(o0)) {
1506 : opCode = 0x23 | X86Inst::kOpCode_MM_0F;
1507 0 : goto EmitX86R;
1508 : }
1509 : }
1510 :
1511 0 : goto InvalidInstruction;
1512 : }
1513 :
1514 7652 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1515 : opReg = o0.getId();
1516 : rmRel = &o1;
1517 :
1518 : // SEG <- Mem
1519 0 : if (X86Reg::isSeg(o0)) {
1520 : opCode = 0x8E;
1521 0 : opReg--;
1522 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1523 0 : goto EmitX86M;
1524 : }
1525 : // Reg <- Mem
1526 : else {
1527 0 : if (o0.getSize() == 1) {
1528 : opCode = 0;
1529 0 : FIXUP_GPB(o0, opReg);
1530 : }
1531 : else {
1532 : opCode = 1;
1533 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1534 : }
1535 :
1536 : // Handle a special form `mov al|ax|eax|rax, [ptr64]` that doesn't use MOD.
1537 0 : if (o0.getId() == X86Gp::kIdAx && !rmRel->as<X86Mem>().hasBaseOrIndex()) {
1538 : imVal = rmRel->as<X86Mem>().getOffset();
1539 0 : if (!is64Bit() || (is64Bit() && ((options & X86Inst::kOptionLongForm) || !Utils::isInt32(imVal)))) {
1540 0 : opCode += 0xA0;
1541 0 : goto EmitX86OpMovAbs;
1542 : }
1543 : }
1544 :
1545 0 : opCode += 0x8A;
1546 0 : goto EmitX86M;
1547 : }
1548 : }
1549 :
1550 7652 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1551 : opReg = o1.getId();
1552 : rmRel = &o0;
1553 :
1554 : // Mem <- SEG
1555 0 : if (X86Reg::isSeg(o1)) {
1556 : opCode = 0x8C;
1557 0 : opReg--;
1558 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1559 0 : goto EmitX86M;
1560 : }
1561 : // Mem <- Reg
1562 : else {
1563 0 : if (o1.getSize() == 1) {
1564 : opCode = 0;
1565 0 : FIXUP_GPB(o1, opReg);
1566 : }
1567 : else {
1568 : opCode = 1;
1569 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1570 : }
1571 :
1572 : // Handle a special form `mov [ptr64], al|ax|eax|rax` that doesn't use MOD.
1573 0 : if (o1.getId() == X86Gp::kIdAx && !rmRel->as<X86Mem>().hasBaseOrIndex()) {
1574 : imVal = rmRel->as<X86Mem>().getOffset();
1575 0 : if (!is64Bit() || (is64Bit() && ((options & X86Inst::kOptionLongForm) || !Utils::isInt32(imVal)))) {
1576 0 : opCode += 0xA2;
1577 0 : goto EmitX86OpMovAbs;
1578 : }
1579 : }
1580 :
1581 0 : opCode += 0x88;
1582 0 : goto EmitX86M;
1583 : }
1584 : }
1585 :
1586 7652 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1587 : opReg = o0.getId();
1588 7652 : imLen = o0.getSize();
1589 :
1590 7652 : if (imLen == 1) {
1591 0 : FIXUP_GPB(o0, opReg);
1592 :
1593 0 : imVal = static_cast<const Imm&>(o1).getUInt8();
1594 : opCode = 0xB0;
1595 0 : goto EmitX86OpReg;
1596 : }
1597 : else {
1598 : // 64-bit immediate in 64-bit mode is allowed.
1599 : imVal = static_cast<const Imm&>(o1).getInt64();
1600 :
1601 : // Optimize the instruction size by using a 32-bit immediate if possible.
1602 7652 : if (imLen == 8 && !(options & X86Inst::kOptionLongForm)) {
1603 7652 : if (Utils::isUInt32(imVal)) {
1604 : // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ.
1605 : imLen = 4;
1606 : }
1607 7652 : else if (Utils::isInt32(imVal)) {
1608 : // Sign-extend, uses 'C7 /0' opcode.
1609 : rbReg = opReg;
1610 :
1611 : opCode = 0xC7 | X86Inst::kOpCode_W;
1612 : opReg = 0;
1613 :
1614 : imLen = 4;
1615 0 : goto EmitX86R;
1616 : }
1617 : }
1618 :
1619 : opCode = 0xB8;
1620 7652 : ADD_PREFIX_BY_SIZE(imLen);
1621 7652 : goto EmitX86OpReg;
1622 : }
1623 : }
1624 :
1625 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1626 0 : uint32_t memSize = o0.getSize();
1627 :
1628 0 : if (ASMJIT_UNLIKELY(memSize == 0))
1629 0 : goto AmbiguousOperandSize;
1630 :
1631 : imVal = static_cast<const Imm&>(o1).getInt64();
1632 0 : imLen = std::min<uint32_t>(memSize, 4);
1633 :
1634 0 : opCode = 0xC6 + (memSize != 1);
1635 : opReg = 0;
1636 0 : ADD_PREFIX_BY_SIZE(memSize);
1637 :
1638 : rmRel = &o0;
1639 0 : goto EmitX86M;
1640 : }
1641 : break;
1642 :
1643 0 : case X86Inst::kEncodingX86MovsxMovzx:
1644 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1645 : opReg = o0.getId();
1646 : rbReg = o1.getId();
1647 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1648 :
1649 0 : if (o1.getSize() == 1) {
1650 0 : FIXUP_GPB(o1, rbReg);
1651 0 : goto EmitX86R;
1652 : }
1653 : else {
1654 0 : opCode++;
1655 0 : goto EmitX86R;
1656 : }
1657 : }
1658 :
1659 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1660 0 : opCode += o1.getSize() != 1;
1661 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1662 :
1663 : opReg = o0.getId();
1664 : rmRel = &o1;
1665 0 : goto EmitX86M;
1666 : }
1667 : break;
1668 :
1669 0 : case X86Inst::kEncodingX86Out:
1670 0 : if (isign3 == ENC_OPS2(Imm, Reg)) {
1671 0 : if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdAx))
1672 0 : goto InvalidInstruction;
1673 :
1674 0 : imVal = o0.as<Imm>().getUInt8();
1675 : imLen = 1;
1676 :
1677 0 : opCode = commonData->getAltOpCode() + (o1.getSize() != 1);
1678 0 : ADD_66H_P_BY_SIZE(o1.getSize());
1679 0 : goto EmitX86Op;
1680 : }
1681 :
1682 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1683 0 : if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdDx || o1.getId() != X86Gp::kIdAx))
1684 0 : goto InvalidInstruction;
1685 :
1686 0 : opCode += o1.getSize() != 1;
1687 0 : ADD_66H_P_BY_SIZE(o1.getSize());
1688 0 : goto EmitX86Op;
1689 : }
1690 : break;
1691 :
1692 0 : case X86Inst::kEncodingX86Outs:
1693 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1694 0 : if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdDx || !x86IsImplicitMem(o1, X86Gp::kIdSi)))
1695 0 : goto InvalidInstruction;
1696 :
1697 : uint32_t size = o1.getSize();
1698 0 : if (ASMJIT_UNLIKELY(size == 0))
1699 0 : goto AmbiguousOperandSize;
1700 :
1701 : rmRel = &o1;
1702 0 : opCode += (size != 1);
1703 :
1704 0 : ADD_66H_P_BY_SIZE(size);
1705 0 : goto EmitX86OpImplicitMem;
1706 : }
1707 : break;
1708 :
1709 1108 : case X86Inst::kEncodingX86Push:
1710 1108 : if (isign3 == ENC_OPS1(Reg)) {
1711 1108 : if (X86Reg::isSeg(o0)) {
1712 : uint32_t segment = o0.getId();
1713 0 : if (ASMJIT_UNLIKELY(segment >= X86Seg::kIdCount))
1714 0 : goto InvalidSegment;
1715 :
1716 0 : if (segment >= X86Seg::kIdFs)
1717 0 : EMIT_BYTE(0x0F);
1718 :
1719 0 : EMIT_BYTE(x86OpCodePushSeg[segment]);
1720 0 : goto EmitDone;
1721 : }
1722 : else {
1723 1108 : goto CaseX86Pop_Gp;
1724 : }
1725 : }
1726 :
1727 0 : if (isign3 == ENC_OPS1(Imm)) {
1728 : imVal = static_cast<const Imm&>(o0).getInt64();
1729 : imLen = 4;
1730 :
1731 0 : if (Utils::isInt8(imVal) && !(options & X86Inst::kOptionLongForm))
1732 : imLen = 1;
1733 :
1734 : opCode = imLen == 1 ? 0x6A : 0x68;
1735 0 : goto EmitX86Op;
1736 : }
1737 : ASMJIT_FALLTHROUGH;
1738 :
1739 : case X86Inst::kEncodingX86Pop:
1740 1108 : if (isign3 == ENC_OPS1(Reg)) {
1741 1108 : if (X86Reg::isSeg(o0)) {
1742 : uint32_t segment = o0.getId();
1743 0 : if (ASMJIT_UNLIKELY(segment == X86Seg::kIdCs || segment >= X86Seg::kIdCount))
1744 0 : goto InvalidSegment;
1745 :
1746 0 : if (segment >= X86Seg::kIdFs)
1747 0 : EMIT_BYTE(0x0F);
1748 :
1749 0 : EMIT_BYTE(x86OpCodePopSeg[segment]);
1750 0 : goto EmitDone;
1751 : }
1752 : else {
1753 2216 : CaseX86Pop_Gp:
1754 : // We allow 2 byte, 4 byte, and 8 byte register sizes, although PUSH
1755 : // and POP only allow 2 bytes or native size. On 64-bit we simply
1756 : // PUSH/POP 64-bit register even if 32-bit register was given.
1757 2216 : if (ASMJIT_UNLIKELY(o0.getSize() < 2))
1758 0 : goto InvalidInstruction;
1759 :
1760 : opCode = commonData->getAltOpCode();
1761 : opReg = o0.getId();
1762 :
1763 2216 : ADD_66H_P_BY_SIZE(o0.getSize());
1764 2216 : goto EmitX86OpReg;
1765 : }
1766 : }
1767 :
1768 0 : if (isign3 == ENC_OPS1(Mem)) {
1769 0 : if (ASMJIT_UNLIKELY(o0.getSize() == 0))
1770 0 : goto AmbiguousOperandSize;
1771 :
1772 0 : if (ASMJIT_UNLIKELY(o0.getSize() != 2 && o0.getSize() != getGpSize()))
1773 0 : goto InvalidInstruction;
1774 :
1775 0 : ADD_66H_P_BY_SIZE(o0.getSize());
1776 : rmRel = &o0;
1777 0 : goto EmitX86M;
1778 : }
1779 : break;
1780 :
1781 1944 : case X86Inst::kEncodingX86Ret:
1782 1944 : if (isign3 == 0) {
1783 : // 'ret' without immediate, change C2 to C3.
1784 1944 : opCode++;
1785 1944 : goto EmitX86Op;
1786 : }
1787 :
1788 0 : if (isign3 == ENC_OPS1(Imm)) {
1789 : imVal = static_cast<const Imm&>(o0).getInt64();
1790 0 : if (imVal == 0 && !(options & X86Inst::kOptionLongForm)) {
1791 : // 'ret' without immediate, change C2 to C3.
1792 0 : opCode++;
1793 0 : goto EmitX86Op;
1794 : }
1795 : else {
1796 : imLen = 2;
1797 0 : goto EmitX86Op;
1798 : }
1799 : }
1800 : break;
1801 :
1802 : case X86Inst::kEncodingX86Rot:
1803 0 : if (o0.isReg()) {
1804 : rbReg = o0.getId();
1805 :
1806 0 : if (o0.getSize() == 1) {
1807 0 : FIXUP_GPB(o0, rbReg);
1808 : }
1809 : else {
1810 0 : opCode++;
1811 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1812 : }
1813 :
1814 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1815 0 : if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdCx))
1816 0 : goto InvalidInstruction;
1817 :
1818 0 : opCode += 2;
1819 0 : goto EmitX86R;
1820 : }
1821 :
1822 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1823 0 : imVal = static_cast<const Imm&>(o1).getInt64() & 0xFF;
1824 : imLen = 0;
1825 :
1826 0 : if (imVal == 1 && !(options & X86Inst::kOptionLongForm))
1827 0 : goto EmitX86R;
1828 :
1829 : imLen = 1;
1830 0 : opCode -= 0x10;
1831 0 : goto EmitX86R;
1832 : }
1833 : }
1834 : else {
1835 0 : opCode += o0.getSize() != 1;
1836 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1837 :
1838 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1839 0 : if (ASMJIT_UNLIKELY(o1.getId() != X86Gp::kIdCx))
1840 0 : goto InvalidInstruction;
1841 :
1842 0 : opCode += 2;
1843 : rmRel = &o0;
1844 0 : goto EmitX86M;
1845 : }
1846 :
1847 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1848 0 : if (ASMJIT_UNLIKELY(o0.getSize() == 0))
1849 0 : goto AmbiguousOperandSize;
1850 :
1851 0 : imVal = static_cast<const Imm&>(o1).getInt64() & 0xFF;
1852 : imLen = 0;
1853 : rmRel = &o0;
1854 :
1855 0 : if (imVal == 1 && !(options & X86Inst::kOptionLongForm))
1856 0 : goto EmitX86M;
1857 :
1858 : imLen = 1;
1859 0 : opCode -= 0x10;
1860 0 : goto EmitX86M;
1861 : }
1862 : }
1863 : break;
1864 :
1865 0 : case X86Inst::kEncodingX86Set:
1866 0 : if (isign3 == ENC_OPS1(Reg)) {
1867 : rbReg = o0.getId();
1868 0 : FIXUP_GPB(o0, rbReg);
1869 0 : goto EmitX86R;
1870 : }
1871 :
1872 0 : if (isign3 == ENC_OPS1(Mem)) {
1873 : rmRel = &o0;
1874 0 : goto EmitX86M;
1875 : }
1876 : break;
1877 :
1878 0 : case X86Inst::kEncodingX86ShldShrd:
1879 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
1880 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1881 : imVal = static_cast<const Imm&>(o2).getInt64();
1882 : imLen = 1;
1883 :
1884 : opReg = o1.getId();
1885 : rbReg = o0.getId();
1886 0 : goto EmitX86R;
1887 : }
1888 :
1889 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
1890 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1891 : imVal = static_cast<const Imm&>(o2).getInt64();
1892 : imLen = 1;
1893 :
1894 : opReg = o1.getId();
1895 : rmRel = &o0;
1896 0 : goto EmitX86M;
1897 : }
1898 :
1899 : // The following instructions use opCode + 1.
1900 0 : opCode++;
1901 :
1902 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
1903 0 : if (ASMJIT_UNLIKELY(o2.getId() != X86Gp::kIdCx))
1904 0 : goto InvalidInstruction;
1905 :
1906 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1907 : opReg = o1.getId();
1908 : rbReg = o0.getId();
1909 0 : goto EmitX86R;
1910 : }
1911 :
1912 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
1913 0 : if (ASMJIT_UNLIKELY(o2.getId() != X86Gp::kIdCx))
1914 0 : goto InvalidInstruction;
1915 :
1916 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
1917 : opReg = o1.getId();
1918 : rmRel = &o0;
1919 0 : goto EmitX86M;
1920 : }
1921 : break;
1922 :
1923 0 : case X86Inst::kEncodingX86StrRm:
1924 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1925 : rmRel = &o1;
1926 0 : if (ASMJIT_UNLIKELY(rmRel->as<X86Mem>().getOffsetLo32() || !X86Reg::isGp(o0.as<X86Reg>(), X86Gp::kIdAx)))
1927 0 : goto InvalidInstruction;
1928 :
1929 : uint32_t size = o0.getSize();
1930 0 : if (o1.hasSize() && ASMJIT_UNLIKELY(o1.getSize() != size))
1931 0 : goto OperandSizeMismatch;
1932 :
1933 0 : ADD_PREFIX_BY_SIZE(size);
1934 0 : opCode += static_cast<uint32_t>(size != 1);
1935 :
1936 0 : goto EmitX86OpImplicitMem;
1937 : }
1938 : break;
1939 :
1940 0 : case X86Inst::kEncodingX86StrMr:
1941 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1942 : rmRel = &o0;
1943 0 : if (ASMJIT_UNLIKELY(rmRel->as<X86Mem>().getOffsetLo32() || !X86Reg::isGp(o1.as<X86Reg>(), X86Gp::kIdAx)))
1944 0 : goto InvalidInstruction;
1945 :
1946 : uint32_t size = o1.getSize();
1947 0 : if (o0.hasSize() && ASMJIT_UNLIKELY(o0.getSize() != size))
1948 0 : goto OperandSizeMismatch;
1949 :
1950 0 : ADD_PREFIX_BY_SIZE(size);
1951 0 : opCode += static_cast<uint32_t>(size != 1);
1952 :
1953 0 : goto EmitX86OpImplicitMem;
1954 : }
1955 : break;
1956 :
1957 0 : case X86Inst::kEncodingX86StrMm:
1958 0 : if (isign3 == ENC_OPS2(Mem, Mem)) {
1959 0 : if (ASMJIT_UNLIKELY(o0.as<X86Mem>().getBaseIndexType() !=
1960 : o1.as<X86Mem>().getBaseIndexType()))
1961 0 : goto InvalidInstruction;
1962 :
1963 : rmRel = &o1;
1964 0 : if (ASMJIT_UNLIKELY(o0.as<X86Mem>().hasOffset()))
1965 0 : goto InvalidInstruction;
1966 :
1967 : uint32_t size = o1.getSize();
1968 0 : if (ASMJIT_UNLIKELY(size == 0))
1969 0 : goto AmbiguousOperandSize;
1970 :
1971 0 : if (ASMJIT_UNLIKELY(o0.getSize() != size))
1972 0 : goto OperandSizeMismatch;
1973 :
1974 0 : ADD_PREFIX_BY_SIZE(size);
1975 0 : opCode += static_cast<uint32_t>(size != 1);
1976 :
1977 0 : goto EmitX86OpImplicitMem;
1978 : }
1979 : break;
1980 :
1981 0 : case X86Inst::kEncodingX86Test:
1982 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1983 0 : if (o0.getSize() != o1.getSize())
1984 0 : goto OperandSizeMismatch;
1985 :
1986 : rbReg = o0.getId();
1987 : opReg = o1.getId();
1988 :
1989 0 : if (o0.getSize() == 1) {
1990 0 : FIXUP_GPB(o0, rbReg);
1991 0 : FIXUP_GPB(o1, opReg);
1992 0 : goto EmitX86R;
1993 : }
1994 : else {
1995 0 : opCode++;
1996 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
1997 0 : goto EmitX86R;
1998 : }
1999 : }
2000 :
2001 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2002 : opReg = o1.getId();
2003 : rmRel = &o0;
2004 :
2005 0 : if (o1.getSize() == 1) {
2006 0 : FIXUP_GPB(o1, opReg);
2007 0 : goto EmitX86M;
2008 : }
2009 : else {
2010 0 : opCode++;
2011 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
2012 0 : goto EmitX86M;
2013 : }
2014 : }
2015 :
2016 : // The following instructions use the secondary opcode.
2017 : opCode = commonData->getAltOpCode();
2018 : opReg = x86ExtractO(opCode);
2019 :
2020 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2021 : rbReg = o0.getId();
2022 :
2023 0 : if (o0.getSize() == 1) {
2024 0 : FIXUP_GPB(o0, rbReg);
2025 :
2026 0 : imVal = static_cast<const Imm&>(o1).getUInt8();
2027 : imLen = 1;
2028 : }
2029 : else {
2030 0 : opCode++;
2031 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
2032 :
2033 : imVal = static_cast<const Imm&>(o1).getInt64();
2034 0 : imLen = std::min<uint32_t>(o0.getSize(), 4);
2035 : }
2036 :
2037 : // Alternate Form - AL, AX, EAX, RAX.
2038 0 : if (o0.getId() == 0 && !(options & X86Inst::kOptionLongForm)) {
2039 0 : opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W;
2040 0 : opCode |= 0xA8 + (o0.getSize() != 1);
2041 0 : goto EmitX86Op;
2042 : }
2043 :
2044 0 : goto EmitX86R;
2045 : }
2046 :
2047 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
2048 0 : if (ASMJIT_UNLIKELY(o0.getSize() == 0))
2049 0 : goto AmbiguousOperandSize;
2050 :
2051 : imVal = static_cast<const Imm&>(o1).getInt64();
2052 0 : imLen = std::min<uint32_t>(o0.getSize(), 4);
2053 :
2054 0 : opCode += (o0.getSize() != 1);
2055 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
2056 :
2057 : rmRel = &o0;
2058 0 : goto EmitX86M;
2059 : }
2060 : break;
2061 :
2062 0 : case X86Inst::kEncodingX86Xchg:
2063 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2064 : opReg = o0.getId();
2065 : rmRel = &o1;
2066 :
2067 0 : if (o0.getSize() == 1) {
2068 0 : FIXUP_GPB(o0, opReg);
2069 0 : goto EmitX86M;
2070 : }
2071 : else {
2072 0 : opCode++;
2073 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
2074 0 : goto EmitX86M;
2075 : }
2076 : }
2077 : ASMJIT_FALLTHROUGH;
2078 :
2079 : case X86Inst::kEncodingX86Xadd:
2080 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2081 : rbReg = o0.getId();
2082 : opReg = o1.getId();
2083 :
2084 0 : if (o0.getSize() != o1.getSize())
2085 0 : goto OperandSizeMismatch;
2086 :
2087 0 : if (o0.getSize() == 1) {
2088 0 : FIXUP_GPB(o0, rbReg);
2089 0 : FIXUP_GPB(o1, opReg);
2090 0 : goto EmitX86R;
2091 : }
2092 : else {
2093 0 : opCode++;
2094 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
2095 :
2096 : // Special opcode for 'xchg ?ax, reg'.
2097 0 : if (instId == X86Inst::kIdXchg && (opReg == 0 || rbReg == 0)) {
2098 0 : opCode &= X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_W;
2099 0 : opCode |= 0x90;
2100 : // One of `xchg a, b` or `xchg b, a` is AX/EAX/RAX.
2101 0 : opReg += rbReg;
2102 0 : goto EmitX86OpReg;
2103 : }
2104 : else {
2105 0 : goto EmitX86R;
2106 : }
2107 : }
2108 : }
2109 :
2110 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2111 0 : opCode += o1.getSize() != 1;
2112 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
2113 :
2114 : opReg = o1.getId();
2115 : rmRel = &o0;
2116 0 : goto EmitX86M;
2117 : }
2118 : break;
2119 :
2120 0 : case X86Inst::kEncodingX86Fence:
2121 : rbReg = 0;
2122 0 : goto EmitX86R;
2123 :
2124 0 : case X86Inst::kEncodingX86Bndmov:
2125 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2126 : opReg = o0.getId();
2127 : rbReg = o1.getId();
2128 :
2129 : // ModRM encoding:
2130 0 : if (!(options & X86Inst::kOptionModMR))
2131 0 : goto EmitX86R;
2132 :
2133 : // ModMR encoding:
2134 : opCode = commonData->getAltOpCode();
2135 : std::swap(opReg, rbReg);
2136 0 : goto EmitX86R;
2137 : }
2138 :
2139 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2140 : opReg = o0.getId();
2141 : rmRel = &o1;
2142 0 : goto EmitX86M;
2143 : }
2144 :
2145 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2146 : opCode = commonData->getAltOpCode();
2147 :
2148 : rmRel = &o0;
2149 : opReg = o1.getId();
2150 0 : goto EmitX86M;
2151 : }
2152 : break;
2153 :
2154 : // ------------------------------------------------------------------------
2155 : // [FPU]
2156 : // ------------------------------------------------------------------------
2157 :
2158 0 : case X86Inst::kEncodingFpuOp:
2159 0 : goto EmitFpuOp;
2160 :
2161 0 : case X86Inst::kEncodingFpuArith:
2162 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2163 : opReg = o0.getId();
2164 : rbReg = o1.getId();
2165 :
2166 : // We switch to the alternative opcode if the first operand is zero.
2167 0 : if (opReg == 0) {
2168 0 : CaseFpuArith_Reg:
2169 0 : opCode = ((0xD8 << X86Inst::kOpCode_FPU_2B_Shift) ) +
2170 0 : ((opCode >> X86Inst::kOpCode_FPU_2B_Shift) & 0xFF) + rbReg;
2171 0 : goto EmitFpuOp;
2172 : }
2173 0 : else if (rbReg == 0) {
2174 : rbReg = opReg;
2175 0 : opCode = ((0xDC << X86Inst::kOpCode_FPU_2B_Shift) ) +
2176 0 : ((opCode ) & 0xFF) + rbReg;
2177 0 : goto EmitFpuOp;
2178 : }
2179 : else {
2180 0 : goto InvalidInstruction;
2181 : }
2182 : }
2183 :
2184 0 : if (isign3 == ENC_OPS1(Mem)) {
2185 0 : CaseFpuArith_Mem:
2186 : // 0xD8/0xDC, depends on the size of the memory operand; opReg is valid.
2187 0 : opCode = (o0.getSize() == 4) ? 0xD8 : 0xDC;
2188 : // Clear compressed displacement before going to EmitX86M.
2189 0 : opCode &= ~static_cast<uint32_t>(X86Inst::kOpCode_CDSHL_Mask);
2190 :
2191 : rmRel = &o0;
2192 0 : goto EmitX86M;
2193 : }
2194 : break;
2195 :
2196 0 : case X86Inst::kEncodingFpuCom:
2197 0 : if (isign3 == 0) {
2198 : rbReg = 1;
2199 0 : goto CaseFpuArith_Reg;
2200 : }
2201 :
2202 0 : if (isign3 == ENC_OPS1(Reg)) {
2203 : rbReg = o0.getId();
2204 0 : goto CaseFpuArith_Reg;
2205 : }
2206 :
2207 0 : if (isign3 == ENC_OPS1(Mem)) {
2208 0 : goto CaseFpuArith_Mem;
2209 : }
2210 : break;
2211 :
2212 0 : case X86Inst::kEncodingFpuFldFst:
2213 0 : if (isign3 == ENC_OPS1(Mem)) {
2214 : rmRel = &o0;
2215 :
2216 0 : if (o0.getSize() == 4 && commonData->hasFlag(X86Inst::kFlagFpuM32)) {
2217 0 : goto EmitX86M;
2218 : }
2219 :
2220 0 : if (o0.getSize() == 8 && commonData->hasFlag(X86Inst::kFlagFpuM64)) {
2221 0 : opCode += 4;
2222 0 : goto EmitX86M;
2223 : }
2224 :
2225 0 : if (o0.getSize() == 10 && commonData->hasFlag(X86Inst::kFlagFpuM80)) {
2226 : opCode = commonData->getAltOpCode();
2227 : opReg = x86ExtractO(opCode);
2228 0 : goto EmitX86M;
2229 : }
2230 : }
2231 :
2232 0 : if (isign3 == ENC_OPS1(Reg)) {
2233 0 : if (instId == X86Inst::kIdFld ) { opCode = (0xD9 << X86Inst::kOpCode_FPU_2B_Shift) + 0xC0 + o0.getId(); goto EmitFpuOp; }
2234 0 : if (instId == X86Inst::kIdFst ) { opCode = (0xDD << X86Inst::kOpCode_FPU_2B_Shift) + 0xD0 + o0.getId(); goto EmitFpuOp; }
2235 0 : if (instId == X86Inst::kIdFstp) { opCode = (0xDD << X86Inst::kOpCode_FPU_2B_Shift) + 0xD8 + o0.getId(); goto EmitFpuOp; }
2236 : }
2237 : break;
2238 :
2239 0 : case X86Inst::kEncodingFpuM:
2240 0 : if (isign3 == ENC_OPS1(Mem)) {
2241 : // Clear compressed displacement before going to EmitX86M.
2242 0 : opCode &= ~static_cast<uint32_t>(X86Inst::kOpCode_CDSHL_Mask);
2243 :
2244 : rmRel = &o0;
2245 0 : if (o0.getSize() == 2 && commonData->hasFlag(X86Inst::kFlagFpuM16)) {
2246 0 : opCode += 4;
2247 0 : goto EmitX86M;
2248 : }
2249 :
2250 0 : if (o0.getSize() == 4 && commonData->hasFlag(X86Inst::kFlagFpuM32)) {
2251 0 : goto EmitX86M;
2252 : }
2253 :
2254 0 : if (o0.getSize() == 8 && commonData->hasFlag(X86Inst::kFlagFpuM64)) {
2255 0 : opCode = commonData->getAltOpCode() & ~static_cast<uint32_t>(X86Inst::kOpCode_CDSHL_Mask);
2256 : opReg = x86ExtractO(opCode);
2257 0 : goto EmitX86M;
2258 : }
2259 : }
2260 : break;
2261 :
2262 0 : case X86Inst::kEncodingFpuRDef:
2263 0 : if (isign3 == 0) {
2264 0 : opCode += 1;
2265 0 : goto EmitFpuOp;
2266 : }
2267 : ASMJIT_FALLTHROUGH;
2268 :
2269 : case X86Inst::kEncodingFpuR:
2270 0 : if (isign3 == ENC_OPS1(Reg)) {
2271 0 : opCode += o0.getId();
2272 0 : goto EmitFpuOp;
2273 : }
2274 : break;
2275 :
2276 0 : case X86Inst::kEncodingFpuStsw:
2277 0 : if (isign3 == ENC_OPS1(Reg)) {
2278 0 : if (ASMJIT_UNLIKELY(o0.getId() != X86Gp::kIdAx))
2279 0 : goto InvalidInstruction;
2280 :
2281 : opCode = commonData->getAltOpCode();
2282 0 : goto EmitFpuOp;
2283 : }
2284 :
2285 0 : if (isign3 == ENC_OPS1(Mem)) {
2286 : // Clear compressed displacement before going to EmitX86M.
2287 0 : opCode &= ~static_cast<uint32_t>(X86Inst::kOpCode_CDSHL_Mask);
2288 :
2289 : rmRel = &o0;
2290 0 : goto EmitX86M;
2291 : }
2292 : break;
2293 :
2294 : // ------------------------------------------------------------------------
2295 : // [Ext]
2296 : // ------------------------------------------------------------------------
2297 :
2298 0 : case X86Inst::kEncodingExtPextrw:
2299 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2300 0 : ADD_66H_P(X86Reg::isXmm(o1));
2301 :
2302 : imVal = static_cast<const Imm&>(o2).getInt64();
2303 : imLen = 1;
2304 :
2305 : opReg = o0.getId();
2306 : rbReg = o1.getId();
2307 0 : goto EmitX86R;
2308 : }
2309 :
2310 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2311 : // Secondary opcode of 'pextrw' instruction (SSE4.1).
2312 : opCode = commonData->getAltOpCode();
2313 0 : ADD_66H_P(X86Reg::isXmm(o1));
2314 :
2315 : imVal = static_cast<const Imm&>(o2).getInt64();
2316 : imLen = 1;
2317 :
2318 : opReg = o1.getId();
2319 : rmRel = &o0;
2320 0 : goto EmitX86M;
2321 : }
2322 : break;
2323 :
2324 0 : case X86Inst::kEncodingExtExtract:
2325 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2326 0 : ADD_66H_P(X86Reg::isXmm(o1));
2327 :
2328 : imVal = static_cast<const Imm&>(o2).getInt64();
2329 : imLen = 1;
2330 :
2331 : opReg = o1.getId();
2332 : rbReg = o0.getId();
2333 0 : goto EmitX86R;
2334 : }
2335 :
2336 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2337 0 : ADD_66H_P(X86Reg::isXmm(o1));
2338 :
2339 : imVal = static_cast<const Imm&>(o2).getInt64();
2340 : imLen = 1;
2341 :
2342 : opReg = o1.getId();
2343 : rmRel = &o0;
2344 0 : goto EmitX86M;
2345 : }
2346 : break;
2347 :
2348 23804 : case X86Inst::kEncodingExtMov:
2349 : // GP|MMX|XMM <- GP|MMX|XMM
2350 23804 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2351 : opReg = o0.getId();
2352 : rbReg = o1.getId();
2353 :
2354 9308 : if (!(options & X86Inst::kOptionModMR) || !commonData->hasAltOpCode())
2355 9308 : goto EmitX86R;
2356 :
2357 : opCode = commonData->getAltOpCode();
2358 : Utils::swap(opReg, rbReg);
2359 0 : goto EmitX86R;
2360 : }
2361 :
2362 : // GP|MMX|XMM <- Mem
2363 14496 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2364 : opReg = o0.getId();
2365 : rmRel = &o1;
2366 10250 : goto EmitX86M;
2367 : }
2368 :
2369 : // The following instruction uses opCode[1].
2370 : opCode = commonData->getAltOpCode();
2371 :
2372 : // Mem <- GP|MMX|XMM
2373 4246 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2374 : opReg = o1.getId();
2375 : rmRel = &o0;
2376 4246 : goto EmitX86M;
2377 : }
2378 : break;
2379 :
2380 0 : case X86Inst::kEncodingExtMovnti:
2381 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2382 0 : ADD_REX_W(X86Reg::isGpq(o1));
2383 :
2384 : opReg = o1.getId();
2385 : rmRel = &o0;
2386 0 : goto EmitX86M;
2387 : }
2388 : break;
2389 :
2390 0 : case X86Inst::kEncodingExtMovbe:
2391 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2392 0 : if (o0.getSize() == 1)
2393 0 : goto InvalidInstruction;
2394 :
2395 0 : ADD_PREFIX_BY_SIZE(o0.getSize());
2396 : opReg = o0.getId();
2397 : rmRel = &o1;
2398 0 : goto EmitX86M;
2399 : }
2400 :
2401 : // The following instruction uses the secondary opcode.
2402 : opCode = commonData->getAltOpCode();
2403 :
2404 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2405 0 : if (o1.getSize() == 1)
2406 0 : goto InvalidInstruction;
2407 :
2408 0 : ADD_PREFIX_BY_SIZE(o1.getSize());
2409 : opReg = o1.getId();
2410 : rmRel = &o0;
2411 0 : goto EmitX86M;
2412 : }
2413 : break;
2414 :
2415 : case X86Inst::kEncodingExtMovd:
2416 0 : CaseExtMovd:
2417 : opReg = o0.getId();
2418 0 : ADD_66H_P(X86Reg::isXmm(o0));
2419 :
2420 : // MMX/XMM <- Gp
2421 0 : if (isign3 == ENC_OPS2(Reg, Reg) && X86Reg::isGp(o1)) {
2422 : rbReg = o1.getId();
2423 0 : goto EmitX86R;
2424 : }
2425 :
2426 : // MMX/XMM <- Mem
2427 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2428 : rmRel = &o1;
2429 0 : goto EmitX86M;
2430 : }
2431 :
2432 : // The following instructions use the secondary opcode.
2433 0 : opCode &= X86Inst::kOpCode_W;
2434 0 : opCode |= commonData->getAltOpCode();
2435 : opReg = o1.getId();
2436 0 : ADD_66H_P(X86Reg::isXmm(o1));
2437 :
2438 : // GP <- MMX/XMM
2439 0 : if (isign3 == ENC_OPS2(Reg, Reg) && X86Reg::isGp(o0)) {
2440 : rbReg = o0.getId();
2441 0 : goto EmitX86R;
2442 : }
2443 :
2444 : // Mem <- MMX/XMM
2445 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2446 : rmRel = &o0;
2447 0 : goto EmitX86M;
2448 : }
2449 : break;
2450 :
2451 0 : case X86Inst::kEncodingExtMovq:
2452 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2453 : opReg = o0.getId();
2454 : rbReg = o1.getId();
2455 :
2456 : // MMX <- MMX
2457 0 : if (X86Reg::isMm(o0) && X86Reg::isMm(o1)) {
2458 : opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x6F;
2459 :
2460 0 : if (!(options & X86Inst::kOptionModMR))
2461 0 : goto EmitX86R;
2462 :
2463 : opCode += 0x10;
2464 : Utils::swap(opReg, rbReg);
2465 0 : goto EmitX86R;
2466 : }
2467 :
2468 : // XMM <- XMM
2469 0 : if (X86Reg::isXmm(o0) && X86Reg::isXmm(o1)) {
2470 : opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E;
2471 :
2472 0 : if (!(options & X86Inst::kOptionModMR))
2473 0 : goto EmitX86R;
2474 :
2475 : opCode = X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6;
2476 : Utils::swap(opReg, rbReg);
2477 0 : goto EmitX86R;
2478 : }
2479 :
2480 : // MMX <- XMM (MOVDQ2Q)
2481 0 : if (X86Reg::isMm(o0) && X86Reg::isXmm(o1)) {
2482 : opCode = X86Inst::kOpCode_PP_F2 | X86Inst::kOpCode_MM_0F | 0xD6;
2483 0 : goto EmitX86R;
2484 : }
2485 :
2486 : // XMM <- MMX (MOVQ2DQ)
2487 0 : if (X86Reg::isXmm(o0) && X86Reg::isMm(o1)) {
2488 : opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0xD6;
2489 0 : goto EmitX86R;
2490 : }
2491 : }
2492 :
2493 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2494 : opReg = o0.getId();
2495 : rmRel = &o1;
2496 :
2497 : // MMX <- Mem
2498 0 : if (X86Reg::isMm(o0)) {
2499 : opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x6F;
2500 0 : goto EmitX86M;
2501 : }
2502 :
2503 : // XMM <- Mem
2504 0 : if (X86Reg::isXmm(o0)) {
2505 : opCode = X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E;
2506 0 : goto EmitX86M;
2507 : }
2508 : }
2509 :
2510 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2511 : opReg = o1.getId();
2512 : rmRel = &o0;
2513 :
2514 : // Mem <- MMX
2515 0 : if (X86Reg::isMm(o1)) {
2516 : opCode = X86Inst::kOpCode_PP_00 | X86Inst::kOpCode_MM_0F | 0x7F;
2517 0 : goto EmitX86M;
2518 : }
2519 :
2520 : // Mem <- XMM
2521 0 : if (X86Reg::isXmm(o1)) {
2522 : opCode = X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6;
2523 0 : goto EmitX86M;
2524 : }
2525 : }
2526 :
2527 : // MOVQ in other case is simply a MOVD instruction promoted to 64-bit.
2528 0 : opCode |= X86Inst::kOpCode_W;
2529 0 : goto CaseExtMovd;
2530 :
2531 : case X86Inst::kEncodingExtRm_XMM0:
2532 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !X86Reg::isXmm(o2, 0)))
2533 0 : goto InvalidInstruction;
2534 :
2535 0 : isign3 &= 0x3F;
2536 0 : goto CaseExtRm;
2537 :
2538 : case X86Inst::kEncodingExtRm_ZDI:
2539 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, X86Gp::kIdDi)))
2540 0 : goto InvalidInstruction;
2541 :
2542 0 : isign3 &= 0x3F;
2543 0 : goto CaseExtRm;
2544 :
2545 : case X86Inst::kEncodingExtRm_Wx:
2546 0 : ADD_REX_W(X86Reg::isGpq(o0) || o1.getSize() == 8);
2547 : ASMJIT_FALLTHROUGH;
2548 :
2549 : case X86Inst::kEncodingExtRm:
2550 9018 : CaseExtRm:
2551 9018 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2552 : opReg = o0.getId();
2553 : rbReg = o1.getId();
2554 9018 : goto EmitX86R;
2555 : }
2556 :
2557 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2558 : opReg = o0.getId();
2559 : rmRel = &o1;
2560 0 : goto EmitX86M;
2561 : }
2562 : break;
2563 :
2564 0 : case X86Inst::kEncodingExtRm_P:
2565 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2566 0 : ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1));
2567 :
2568 : opReg = o0.getId();
2569 : rbReg = o1.getId();
2570 0 : goto EmitX86R;
2571 : }
2572 :
2573 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2574 0 : ADD_66H_P(X86Reg::isXmm(o0));
2575 :
2576 : opReg = o0.getId();
2577 : rmRel = &o1;
2578 0 : goto EmitX86M;
2579 : }
2580 : break;
2581 :
2582 0 : case X86Inst::kEncodingExtRmRi:
2583 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2584 : opReg = o0.getId();
2585 : rbReg = o1.getId();
2586 0 : goto EmitX86R;
2587 : }
2588 :
2589 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2590 : opReg = o0.getId();
2591 : rmRel = &o1;
2592 0 : goto EmitX86M;
2593 : }
2594 :
2595 : // The following instruction uses the secondary opcode.
2596 : opCode = commonData->getAltOpCode();
2597 : opReg = x86ExtractO(opCode);
2598 :
2599 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2600 : imVal = static_cast<const Imm&>(o1).getInt64();
2601 : imLen = 1;
2602 :
2603 : rbReg = o0.getId();
2604 0 : goto EmitX86R;
2605 : }
2606 : break;
2607 :
2608 0 : case X86Inst::kEncodingExtRmRi_P:
2609 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2610 0 : ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1));
2611 :
2612 : opReg = o0.getId();
2613 : rbReg = o1.getId();
2614 0 : goto EmitX86R;
2615 : }
2616 :
2617 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2618 0 : ADD_66H_P(X86Reg::isXmm(o0));
2619 :
2620 : opReg = o0.getId();
2621 : rmRel = &o1;
2622 0 : goto EmitX86M;
2623 : }
2624 :
2625 : // The following instruction uses the secondary opcode.
2626 : opCode = commonData->getAltOpCode();
2627 : opReg = x86ExtractO(opCode);
2628 :
2629 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2630 0 : ADD_66H_P(X86Reg::isXmm(o0));
2631 :
2632 : imVal = static_cast<const Imm&>(o1).getInt64();
2633 : imLen = 1;
2634 :
2635 : rbReg = o0.getId();
2636 0 : goto EmitX86R;
2637 : }
2638 : break;
2639 :
2640 : case X86Inst::kEncodingExtRmi:
2641 : imVal = static_cast<const Imm&>(o2).getInt64();
2642 : imLen = 1;
2643 :
2644 120 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2645 : opReg = o0.getId();
2646 : rbReg = o1.getId();
2647 120 : goto EmitX86R;
2648 : }
2649 :
2650 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
2651 : opReg = o0.getId();
2652 : rmRel = &o1;
2653 0 : goto EmitX86M;
2654 : }
2655 : break;
2656 :
2657 : case X86Inst::kEncodingExtRmi_P:
2658 : imVal = static_cast<const Imm&>(o2).getInt64();
2659 : imLen = 1;
2660 :
2661 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2662 0 : ADD_66H_P(X86Reg::isXmm(o0) | X86Reg::isXmm(o1));
2663 :
2664 : opReg = o0.getId();
2665 : rbReg = o1.getId();
2666 0 : goto EmitX86R;
2667 : }
2668 :
2669 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
2670 0 : ADD_66H_P(X86Reg::isXmm(o0));
2671 :
2672 : opReg = o0.getId();
2673 : rmRel = &o1;
2674 0 : goto EmitX86M;
2675 : }
2676 : break;
2677 :
2678 : // ------------------------------------------------------------------------
2679 : // [Extrq / Insertq (SSE4A)]
2680 : // ------------------------------------------------------------------------
2681 :
2682 : case X86Inst::kEncodingExtExtrq:
2683 : opReg = o0.getId();
2684 : rbReg = o1.getId();
2685 :
2686 0 : if (isign3 == ENC_OPS2(Reg, Reg))
2687 0 : goto EmitX86R;
2688 :
2689 : // The following instruction uses the secondary opcode.
2690 : opCode = commonData->getAltOpCode();
2691 :
2692 0 : if (isign3 == ENC_OPS3(Reg, Imm, Imm)) {
2693 0 : imVal = (static_cast<const Imm&>(o1).getUInt32() ) +
2694 0 : (static_cast<const Imm&>(o2).getUInt32() << 8) ;
2695 : imLen = 2;
2696 :
2697 : rbReg = x86ExtractO(opCode);
2698 0 : goto EmitX86R;
2699 : }
2700 : break;
2701 :
2702 : case X86Inst::kEncodingExtInsertq: {
2703 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
2704 : opReg = o0.getId();
2705 : rbReg = o1.getId();
2706 :
2707 0 : if (isign4 == ENC_OPS2(Reg, Reg))
2708 0 : goto EmitX86R;
2709 :
2710 : // The following instruction uses the secondary opcode.
2711 : opCode = commonData->getAltOpCode();
2712 :
2713 0 : if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) {
2714 0 : imVal = (static_cast<const Imm&>(o2).getUInt32() ) +
2715 0 : (static_cast<const Imm&>(o3).getUInt32() << 8) ;
2716 : imLen = 2;
2717 0 : goto EmitX86R;
2718 : }
2719 : break;
2720 : }
2721 :
2722 : // ------------------------------------------------------------------------
2723 : // [3dNow]
2724 : // ------------------------------------------------------------------------
2725 :
2726 0 : case X86Inst::kEncodingExt3dNow:
2727 : // Every 3dNow instruction starts with 0x0F0F and the actual opcode is
2728 : // stored as 8-bit immediate.
2729 0 : imVal = opCode & 0xFF;
2730 : imLen = 1;
2731 :
2732 : opCode = X86Inst::kOpCode_MM_0F | 0x0F;
2733 : opReg = o0.getId();
2734 :
2735 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2736 : rbReg = o1.getId();
2737 0 : goto EmitX86R;
2738 : }
2739 :
2740 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2741 : rmRel = &o1;
2742 0 : goto EmitX86M;
2743 : }
2744 : break;
2745 :
2746 : // ------------------------------------------------------------------------
2747 : // [VEX/EVEX]
2748 : // ------------------------------------------------------------------------
2749 :
2750 0 : case X86Inst::kEncodingVexOp:
2751 0 : goto EmitVexEvexOp;
2752 :
2753 0 : case X86Inst::kEncodingVexKmov:
2754 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2755 : opReg = o0.getId();
2756 : rbReg = o1.getId();
2757 :
2758 : // Form 'k, reg'.
2759 0 : if (X86Reg::isGp(o1)) {
2760 : opCode = commonData->getAltOpCode();
2761 0 : goto EmitVexEvexR;
2762 : }
2763 :
2764 : // Form 'reg, k'.
2765 0 : if (X86Reg::isGp(o0)) {
2766 0 : opCode = commonData->getAltOpCode() + 1;
2767 0 : goto EmitVexEvexR;
2768 : }
2769 :
2770 : // Form 'k, k'.
2771 0 : if (!(options & X86Inst::kOptionModMR))
2772 0 : goto EmitVexEvexR;
2773 :
2774 0 : opCode++;
2775 : Utils::swap(opReg, rbReg);
2776 0 : goto EmitVexEvexR;
2777 : }
2778 :
2779 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2780 : opReg = o0.getId();
2781 : rmRel = &o1;
2782 :
2783 0 : goto EmitVexEvexM;
2784 : }
2785 :
2786 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2787 : opReg = o1.getId();
2788 : rmRel = &o0;
2789 :
2790 0 : opCode++;
2791 0 : goto EmitVexEvexM;
2792 : }
2793 : break;
2794 :
2795 0 : case X86Inst::kEncodingVexM:
2796 0 : if (isign3 == ENC_OPS1(Mem)) {
2797 : rmRel = &o0;
2798 0 : goto EmitVexEvexM;
2799 : }
2800 : break;
2801 :
2802 0 : case X86Inst::kEncodingVexM_VM:
2803 0 : if (isign3 == ENC_OPS1(Mem)) {
2804 0 : opCode |= x86OpCodeLByVMem(o0);
2805 : rmRel = &o0;
2806 0 : goto EmitVexEvexM;
2807 : }
2808 : break;
2809 :
2810 : case X86Inst::kEncodingVexMr_Lx:
2811 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2812 :
2813 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2814 : opReg = o1.getId();
2815 : rbReg = o0.getId();
2816 0 : goto EmitVexEvexR;
2817 : }
2818 :
2819 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2820 : opReg = o1.getId();
2821 : rmRel = &o0;
2822 0 : goto EmitVexEvexM;
2823 : }
2824 : break;
2825 :
2826 0 : case X86Inst::kEncodingVexMr_VM:
2827 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2828 0 : opCode |= std::max(x86OpCodeLByVMem(o0), x86OpCodeLBySize(o1.getSize()));
2829 :
2830 : opReg = o1.getId();
2831 : rmRel = &o0;
2832 0 : goto EmitVexEvexM;
2833 : }
2834 : break;
2835 :
2836 : case X86Inst::kEncodingVexMri_Lx:
2837 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2838 : ASMJIT_FALLTHROUGH;
2839 :
2840 0 : case X86Inst::kEncodingVexMri:
2841 : imVal = static_cast<const Imm&>(o2).getInt64();
2842 : imLen = 1;
2843 :
2844 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2845 : opReg = o1.getId();
2846 : rbReg = o0.getId();
2847 0 : goto EmitVexEvexR;
2848 : }
2849 :
2850 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2851 : opReg = o1.getId();
2852 : rmRel = &o0;
2853 0 : goto EmitVexEvexM;
2854 : }
2855 : break;
2856 :
2857 : case X86Inst::kEncodingVexRm_ZDI:
2858 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, X86Gp::kIdDi)))
2859 0 : goto InvalidInstruction;
2860 :
2861 0 : isign3 &= 0x3F;
2862 0 : goto CaseVexRm;
2863 :
2864 : case X86Inst::kEncodingVexRm_Wx:
2865 0 : ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1));
2866 0 : goto CaseVexRm;
2867 :
2868 : case X86Inst::kEncodingVexRm_Lx:
2869 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2870 : ASMJIT_FALLTHROUGH;
2871 :
2872 : case X86Inst::kEncodingVexRm:
2873 0 : CaseVexRm:
2874 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2875 : opReg = o0.getId();
2876 : rbReg = o1.getId();
2877 0 : goto EmitVexEvexR;
2878 : }
2879 :
2880 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2881 : opReg = o0.getId();
2882 : rmRel = &o1;
2883 0 : goto EmitVexEvexM;
2884 : }
2885 : break;
2886 :
2887 0 : case X86Inst::kEncodingVexRm_VM:
2888 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2889 0 : opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize()));
2890 : opReg = o0.getId();
2891 : rmRel = &o1;
2892 0 : goto EmitVexEvexM;
2893 : }
2894 : break;
2895 :
2896 0 : case X86Inst::kEncodingVexRm_T1_4X: {
2897 0 : if (!(options & kOptionOp4Op5Used))
2898 0 : goto InvalidInstruction;
2899 :
2900 0 : if (X86Reg::isZmm(o0 ) && X86Reg::isZmm(o1) &&
2901 0 : X86Reg::isZmm(o2 ) && X86Reg::isZmm(o3) &&
2902 0 : X86Reg::isZmm(_op4) && _op5.isMem()) {
2903 :
2904 : // Registers [o1, o2, o3, _op4] must start aligned and must be consecutive.
2905 : uint32_t i1 = o1.getId();
2906 : uint32_t i2 = o2.getId();
2907 : uint32_t i3 = o3.getId();
2908 : uint32_t i4 = _op4.getId();
2909 :
2910 0 : if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3))
2911 0 : goto NotConsecutiveRegs;
2912 :
2913 : opReg = o0.getId();
2914 0 : rmRel = &_op5;
2915 0 : goto EmitVexEvexM;
2916 : }
2917 : break;
2918 : }
2919 :
2920 : case X86Inst::kEncodingVexRmi_Wx:
2921 0 : ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1));
2922 0 : goto CaseVexRmi;
2923 :
2924 : case X86Inst::kEncodingVexRmi_Lx:
2925 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2926 : ASMJIT_FALLTHROUGH;
2927 :
2928 : case X86Inst::kEncodingVexRmi:
2929 0 : CaseVexRmi:
2930 : imVal = static_cast<const Imm&>(o2).getInt64();
2931 : imLen = 1;
2932 :
2933 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2934 : opReg = o0.getId();
2935 : rbReg = o1.getId();
2936 0 : goto EmitVexEvexR;
2937 : }
2938 :
2939 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
2940 : opReg = o0.getId();
2941 : rmRel = &o1;
2942 0 : goto EmitVexEvexM;
2943 : }
2944 : break;
2945 :
2946 : case X86Inst::kEncodingVexRvm:
2947 0 : CaseVexRvm:
2948 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
2949 0 : CaseVexRvm_R:
2950 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
2951 : rbReg = o2.getId();
2952 0 : goto EmitVexEvexR;
2953 : }
2954 :
2955 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
2956 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
2957 : rmRel = &o2;
2958 0 : goto EmitVexEvexM;
2959 : }
2960 : break;
2961 :
2962 : case X86Inst::kEncodingVexRvm_ZDX_Wx:
2963 0 : if (ASMJIT_UNLIKELY(!o3.isNone() && !X86Reg::isGp(o3, X86Gp::kIdDx)))
2964 0 : goto InvalidInstruction;
2965 : ASMJIT_FALLTHROUGH;
2966 :
2967 : case X86Inst::kEncodingVexRvm_Wx:
2968 0 : ADD_REX_W(X86Reg::isGpq(o0) | (o2.getSize() == 8));
2969 0 : goto CaseVexRvm;
2970 :
2971 : case X86Inst::kEncodingVexRvm_Lx:
2972 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2973 0 : goto CaseVexRvm;
2974 :
2975 : case X86Inst::kEncodingVexRvmr_Lx:
2976 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
2977 : ASMJIT_FALLTHROUGH;
2978 :
2979 0 : case X86Inst::kEncodingVexRvmr: {
2980 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
2981 0 : imVal = o3.getId() << 4;
2982 : imLen = 1;
2983 :
2984 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
2985 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
2986 : rbReg = o2.getId();
2987 0 : goto EmitVexEvexR;
2988 : }
2989 :
2990 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
2991 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
2992 : rmRel = &o2;
2993 0 : goto EmitVexEvexM;
2994 : }
2995 : break;
2996 : }
2997 :
2998 : case X86Inst::kEncodingVexRvmi_Lx:
2999 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3000 : ASMJIT_FALLTHROUGH;
3001 :
3002 0 : case X86Inst::kEncodingVexRvmi: {
3003 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
3004 : imVal = static_cast<const Imm&>(o3).getInt64();
3005 : imLen = 1;
3006 :
3007 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
3008 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3009 : rbReg = o2.getId();
3010 0 : goto EmitVexEvexR;
3011 : }
3012 :
3013 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Imm)) {
3014 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3015 : rmRel = &o2;
3016 0 : goto EmitVexEvexM;
3017 : }
3018 : break;
3019 : }
3020 :
3021 : case X86Inst::kEncodingVexRmv_Wx:
3022 0 : ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o2));
3023 : ASMJIT_FALLTHROUGH;
3024 :
3025 : case X86Inst::kEncodingVexRmv:
3026 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3027 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3028 : rbReg = o1.getId();
3029 0 : goto EmitVexEvexR;
3030 : }
3031 :
3032 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3033 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3034 : rmRel = &o1;
3035 0 : goto EmitVexEvexM;
3036 : }
3037 : break;
3038 :
3039 0 : case X86Inst::kEncodingVexRmvRm_VM:
3040 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3041 : opCode = commonData->getAltOpCode();
3042 0 : opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize()));
3043 :
3044 : opReg = o0.getId();
3045 : rmRel = &o1;
3046 0 : goto EmitVexEvexM;
3047 : }
3048 :
3049 : ASMJIT_FALLTHROUGH;
3050 :
3051 : case X86Inst::kEncodingVexRmv_VM:
3052 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3053 0 : opCode |= std::max(x86OpCodeLByVMem(o1), x86OpCodeLBySize(o0.getSize() | o2.getSize()));
3054 :
3055 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3056 : rmRel = &o1;
3057 0 : goto EmitVexEvexM;
3058 : }
3059 : break;
3060 :
3061 :
3062 : case X86Inst::kEncodingVexRmvi: {
3063 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
3064 : imVal = static_cast<const Imm&>(o3).getInt64();
3065 : imLen = 1;
3066 :
3067 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
3068 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3069 : rbReg = o1.getId();
3070 0 : goto EmitVexEvexR;
3071 : }
3072 :
3073 0 : if (isign4 == ENC_OPS4(Reg, Mem, Reg, Imm)) {
3074 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3075 : rmRel = &o1;
3076 0 : goto EmitVexEvexM;
3077 : }
3078 : break;
3079 : }
3080 :
3081 0 : case X86Inst::kEncodingVexMovdMovq:
3082 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3083 0 : if (X86Reg::isGp(o0)) {
3084 : opCode = commonData->getAltOpCode();
3085 0 : ADD_REX_W_BY_SIZE(o0.getSize());
3086 : opReg = o1.getId();
3087 : rbReg = o0.getId();
3088 0 : goto EmitVexEvexR;
3089 : }
3090 :
3091 0 : if (X86Reg::isGp(o1)) {
3092 0 : ADD_REX_W_BY_SIZE(o1.getSize());
3093 : opReg = o0.getId();
3094 : rbReg = o1.getId();
3095 0 : goto EmitVexEvexR;
3096 : }
3097 :
3098 : // If this is a 'W' version (movq) then allow also vmovq 'xmm|xmm' form.
3099 0 : if (opCode & X86Inst::kOpCode_EW) {
3100 0 : opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF);
3101 0 : opCode |= (X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E);
3102 :
3103 : opReg = o0.getId();
3104 : rbReg = o1.getId();
3105 0 : goto EmitVexEvexR;
3106 : }
3107 : }
3108 :
3109 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3110 0 : if (opCode & X86Inst::kOpCode_EW) {
3111 0 : opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF);
3112 0 : opCode |= (X86Inst::kOpCode_PP_F3 | X86Inst::kOpCode_MM_0F | 0x7E);
3113 : }
3114 :
3115 : opReg = o0.getId();
3116 : rmRel = &o1;
3117 0 : goto EmitVexEvexM;
3118 : }
3119 :
3120 : // The following instruction uses the secondary opcode.
3121 : opCode = commonData->getAltOpCode();
3122 :
3123 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3124 0 : if (opCode & X86Inst::kOpCode_EW) {
3125 0 : opCode &= ~(X86Inst::kOpCode_PP_VEXMask | X86Inst::kOpCode_MM_Mask | 0xFF);
3126 0 : opCode |= (X86Inst::kOpCode_PP_66 | X86Inst::kOpCode_MM_0F | 0xD6);
3127 : }
3128 :
3129 : opReg = o1.getId();
3130 : rmRel = &o0;
3131 0 : goto EmitVexEvexM;
3132 : }
3133 : break;
3134 :
3135 : case X86Inst::kEncodingVexRmMr_Lx:
3136 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3137 : ASMJIT_FALLTHROUGH;
3138 :
3139 0 : case X86Inst::kEncodingVexRmMr:
3140 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3141 : opReg = o0.getId();
3142 : rbReg = o1.getId();
3143 0 : goto EmitVexEvexR;
3144 : }
3145 :
3146 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3147 : opReg = o0.getId();
3148 : rmRel = &o1;
3149 0 : goto EmitVexEvexM;
3150 : }
3151 :
3152 : // The following instruction uses the secondary opcode.
3153 0 : opCode &= X86Inst::kOpCode_LL_Mask;
3154 0 : opCode |= commonData->getAltOpCode();
3155 :
3156 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3157 : opReg = o1.getId();
3158 : rmRel = &o0;
3159 0 : goto EmitVexEvexM;
3160 : }
3161 : break;
3162 :
3163 0 : case X86Inst::kEncodingVexRvmRmv:
3164 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3165 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3166 : rbReg = o1.getId();
3167 :
3168 0 : if (!(options & X86Inst::kOptionModMR))
3169 0 : goto EmitVexEvexR;
3170 :
3171 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3172 : rbReg = o2.getId();
3173 :
3174 0 : ADD_VEX_W(true);
3175 0 : goto EmitVexEvexR;
3176 : }
3177 :
3178 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3179 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3180 : rmRel = &o1;
3181 0 : goto EmitVexEvexM;
3182 : }
3183 :
3184 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3185 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3186 : rmRel = &o2;
3187 :
3188 0 : ADD_VEX_W(true);
3189 0 : goto EmitVexEvexM;
3190 : }
3191 : break;
3192 :
3193 : case X86Inst::kEncodingVexRvmRmi_Lx:
3194 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3195 : ASMJIT_FALLTHROUGH;
3196 :
3197 0 : case X86Inst::kEncodingVexRvmRmi:
3198 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3199 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3200 : rbReg = o2.getId();
3201 0 : goto EmitVexEvexR;
3202 : }
3203 :
3204 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3205 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3206 : rmRel = &o2;
3207 0 : goto EmitVexEvexM;
3208 : }
3209 :
3210 : // The following instructions use the secondary opcode.
3211 0 : opCode &= X86Inst::kOpCode_LL_Mask;
3212 0 : opCode |= commonData->getAltOpCode();
3213 :
3214 : imVal = static_cast<const Imm&>(o2).getInt64();
3215 : imLen = 1;
3216 :
3217 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3218 : opReg = o0.getId();
3219 : rbReg = o1.getId();
3220 0 : goto EmitVexEvexR;
3221 : }
3222 :
3223 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3224 : opReg = o0.getId();
3225 : rmRel = &o1;
3226 0 : goto EmitVexEvexM;
3227 : }
3228 : break;
3229 :
3230 0 : case X86Inst::kEncodingVexRvmRmvRmi:
3231 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3232 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3233 : rbReg = o1.getId();
3234 :
3235 0 : if (!(options & X86Inst::kOptionModMR))
3236 0 : goto EmitVexEvexR;
3237 :
3238 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3239 : rbReg = o2.getId();
3240 :
3241 0 : ADD_VEX_W(true);
3242 0 : goto EmitVexEvexR;
3243 : }
3244 :
3245 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3246 : opReg = x86PackRegAndVvvvv(o0.getId(), o2.getId());
3247 : rmRel = &o1;
3248 :
3249 0 : goto EmitVexEvexM;
3250 : }
3251 :
3252 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3253 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3254 : rmRel = &o2;
3255 :
3256 0 : ADD_VEX_W(true);
3257 0 : goto EmitVexEvexM;
3258 : }
3259 :
3260 : // The following instructions use the secondary opcode.
3261 : opCode = commonData->getAltOpCode();
3262 :
3263 : imVal = static_cast<const Imm&>(o2).getInt64();
3264 : imLen = 1;
3265 :
3266 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3267 : opReg = o0.getId();
3268 : rbReg = o1.getId();
3269 0 : goto EmitVexEvexR;
3270 : }
3271 :
3272 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3273 : opReg = o0.getId();
3274 : rmRel = &o1;
3275 0 : goto EmitVexEvexM;
3276 : }
3277 : break;
3278 :
3279 0 : case X86Inst::kEncodingVexRvmMr:
3280 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3281 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3282 : rbReg = o2.getId();
3283 0 : goto EmitVexEvexR;
3284 : }
3285 :
3286 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3287 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3288 : rmRel = &o2;
3289 0 : goto EmitVexEvexM;
3290 : }
3291 :
3292 : // The following instructions use the secondary opcode.
3293 : opCode = commonData->getAltOpCode();
3294 :
3295 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3296 : opReg = o1.getId();
3297 : rbReg = o0.getId();
3298 0 : goto EmitVexEvexR;
3299 : }
3300 :
3301 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3302 : opReg = o1.getId();
3303 : rmRel = &o0;
3304 0 : goto EmitVexEvexM;
3305 : }
3306 : break;
3307 :
3308 : case X86Inst::kEncodingVexRvmMvr_Lx:
3309 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3310 : ASMJIT_FALLTHROUGH;
3311 :
3312 0 : case X86Inst::kEncodingVexRvmMvr:
3313 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3314 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3315 : rbReg = o2.getId();
3316 0 : goto EmitVexEvexR;
3317 : }
3318 :
3319 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3320 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3321 : rmRel = &o2;
3322 0 : goto EmitVexEvexM;
3323 : }
3324 :
3325 : // The following instruction uses the secondary opcode.
3326 0 : opCode &= X86Inst::kOpCode_LL_Mask;
3327 0 : opCode |= commonData->getAltOpCode();
3328 :
3329 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
3330 : opReg = x86PackRegAndVvvvv(o2.getId(), o1.getId());
3331 : rmRel = &o0;
3332 0 : goto EmitVexEvexM;
3333 : }
3334 : break;
3335 :
3336 : case X86Inst::kEncodingVexRvmVmi_Lx:
3337 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3338 : ASMJIT_FALLTHROUGH;
3339 :
3340 0 : case X86Inst::kEncodingVexRvmVmi:
3341 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3342 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3343 : rbReg = o2.getId();
3344 0 : goto EmitVexEvexR;
3345 : }
3346 :
3347 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3348 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3349 : rmRel = &o2;
3350 0 : goto EmitVexEvexM;
3351 : }
3352 :
3353 : // The following instruction uses the secondary opcode.
3354 0 : opCode &= X86Inst::kOpCode_LL_Mask;
3355 0 : opCode |= commonData->getAltOpCode();
3356 : opReg = x86ExtractO(opCode);
3357 :
3358 : imVal = static_cast<const Imm&>(o2).getInt64();
3359 : imLen = 1;
3360 :
3361 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3362 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3363 : rbReg = o1.getId();
3364 0 : goto EmitVexEvexR;
3365 : }
3366 :
3367 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3368 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3369 : rmRel = &o1;
3370 0 : goto EmitVexEvexM;
3371 : }
3372 : break;
3373 :
3374 : case X86Inst::kEncodingVexVm_Wx:
3375 0 : ADD_REX_W(X86Reg::isGpq(o0) | X86Reg::isGpq(o1));
3376 : ASMJIT_FALLTHROUGH;
3377 :
3378 : case X86Inst::kEncodingVexVm:
3379 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3380 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3381 : rbReg = o1.getId();
3382 0 : goto EmitVexEvexR;
3383 : }
3384 :
3385 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3386 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3387 : rmRel = &o1;
3388 0 : goto EmitVexEvexM;
3389 : }
3390 : break;
3391 :
3392 0 : case X86Inst::kEncodingVexEvexVmi_Lx:
3393 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm))
3394 0 : opCode |= X86Inst::kOpCode_MM_ForceEvex;
3395 : ASMJIT_FALLTHROUGH;
3396 :
3397 : case X86Inst::kEncodingVexVmi_Lx:
3398 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3399 : ASMJIT_FALLTHROUGH;
3400 :
3401 0 : case X86Inst::kEncodingVexVmi:
3402 : imVal = static_cast<const Imm&>(o2).getInt64();
3403 : imLen = 1;
3404 :
3405 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3406 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3407 : rbReg = o1.getId();
3408 0 : goto EmitVexEvexR;
3409 : }
3410 :
3411 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3412 : opReg = x86PackRegAndVvvvv(opReg, o0.getId());
3413 : rmRel = &o1;
3414 0 : goto EmitVexEvexM;
3415 : }
3416 : break;
3417 :
3418 : case X86Inst::kEncodingVexRvrmRvmr_Lx:
3419 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3420 : ASMJIT_FALLTHROUGH;
3421 :
3422 0 : case X86Inst::kEncodingVexRvrmRvmr: {
3423 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
3424 :
3425 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3426 0 : imVal = o3.getId() << 4;
3427 : imLen = 1;
3428 :
3429 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3430 : rbReg = o2.getId();
3431 :
3432 0 : goto EmitVexEvexR;
3433 : }
3434 :
3435 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3436 0 : imVal = o2.getId() << 4;
3437 : imLen = 1;
3438 :
3439 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3440 : rmRel = &o3;
3441 :
3442 0 : ADD_VEX_W(true);
3443 0 : goto EmitVexEvexM;
3444 : }
3445 :
3446 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3447 0 : imVal = o3.getId() << 4;
3448 : imLen = 1;
3449 :
3450 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3451 : rmRel = &o2;
3452 :
3453 0 : goto EmitVexEvexM;
3454 : }
3455 : break;
3456 : }
3457 :
3458 0 : case X86Inst::kEncodingVexRvrmiRvmri_Lx: {
3459 0 : if (!(options & CodeEmitter::kOptionOp4Op5Used) || !_op4.isImm())
3460 0 : goto InvalidInstruction;
3461 :
3462 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
3463 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize() | o2.getSize() | o3.getSize());
3464 :
3465 0 : imVal = static_cast<const Imm&>(_op4).getUInt8() & 0x0F;
3466 : imLen = 1;
3467 :
3468 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3469 0 : imVal |= o3.getId() << 4;
3470 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3471 : rbReg = o2.getId();
3472 :
3473 0 : goto EmitVexEvexR;
3474 : }
3475 :
3476 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3477 0 : imVal |= o2.getId() << 4;
3478 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3479 : rmRel = &o3;
3480 :
3481 0 : ADD_VEX_W(true);
3482 0 : goto EmitVexEvexM;
3483 : }
3484 :
3485 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3486 0 : imVal |= o3.getId() << 4;
3487 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3488 : rmRel = &o2;
3489 :
3490 0 : goto EmitVexEvexM;
3491 : }
3492 : break;
3493 : }
3494 :
3495 0 : case X86Inst::kEncodingVexMovssMovsd:
3496 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3497 0 : goto CaseVexRvm_R;
3498 : }
3499 :
3500 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3501 : opReg = o0.getId();
3502 : rmRel = &o1;
3503 0 : goto EmitVexEvexM;
3504 : }
3505 :
3506 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3507 : opCode = commonData->getAltOpCode();
3508 : opReg = o1.getId();
3509 : rmRel = &o0;
3510 0 : goto EmitVexEvexM;
3511 : }
3512 : break;
3513 :
3514 : // ------------------------------------------------------------------------
3515 : // [FMA4]
3516 : // ------------------------------------------------------------------------
3517 :
3518 : case X86Inst::kEncodingFma4_Lx:
3519 : // It's fine to just check the first operand, second is just for sanity.
3520 0 : opCode |= x86OpCodeLBySize(o0.getSize() | o1.getSize());
3521 : ASMJIT_FALLTHROUGH;
3522 :
3523 0 : case X86Inst::kEncodingFma4: {
3524 0 : const uint32_t isign4 = isign3 + (o3.getOp() << 9);
3525 :
3526 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3527 0 : imVal = o3.getId() << 4;
3528 : imLen = 1;
3529 :
3530 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3531 : rbReg = o2.getId();
3532 :
3533 0 : goto EmitVexEvexR;
3534 : }
3535 :
3536 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3537 0 : imVal = o2.getId() << 4;
3538 : imLen = 1;
3539 :
3540 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3541 : rmRel = &o3;
3542 :
3543 0 : ADD_VEX_W(true);
3544 0 : goto EmitVexEvexM;
3545 : }
3546 :
3547 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3548 0 : imVal = o3.getId() << 4;
3549 : imLen = 1;
3550 :
3551 : opReg = x86PackRegAndVvvvv(o0.getId(), o1.getId());
3552 : rmRel = &o2;
3553 :
3554 0 : goto EmitVexEvexM;
3555 : }
3556 : break;
3557 : }
3558 : }
3559 0 : goto InvalidInstruction;
3560 :
3561 : // --------------------------------------------------------------------------
3562 : // [Emit - X86]
3563 : // --------------------------------------------------------------------------
3564 :
3565 0 : EmitX86OpMovAbs:
3566 : imLen = getGpSize();
3567 :
3568 : // Segment-override prefix.
3569 0 : if (rmRel->as<X86Mem>().hasSegment())
3570 0 : EMIT_BYTE(x86SegmentPrefix[rmRel->as<X86Mem>().getSegmentId()]);
3571 :
3572 0 : EmitX86Op:
3573 : // Emit mandatory instruction prefix.
3574 1944 : EMIT_PP(opCode);
3575 :
3576 : // Emit REX prefix (64-bit only).
3577 : {
3578 : uint32_t rex = x86ExtractREX(opCode, options);
3579 1944 : if (rex) {
3580 0 : if (options & X86Inst::_kOptionInvalidRex)
3581 0 : goto InvalidRexPrefix;
3582 0 : EMIT_BYTE(rex | kX86ByteRex);
3583 : }
3584 : }
3585 :
3586 : // Emit instruction opcodes.
3587 1944 : EMIT_MM_OP(opCode);
3588 :
3589 1944 : if (imLen != 0)
3590 0 : goto EmitImm;
3591 : else
3592 1944 : goto EmitDone;
3593 :
3594 9868 : EmitX86OpReg:
3595 : // Emit mandatory instruction prefix.
3596 9868 : EMIT_PP(opCode);
3597 :
3598 : // Emit REX prefix (64-bit only).
3599 : {
3600 : uint32_t rex = x86ExtractREX(opCode, options) |
3601 9868 : (opReg >> 3); // Rex.B (0x01).
3602 9868 : if (rex) {
3603 7652 : EMIT_BYTE(rex | kX86ByteRex);
3604 7652 : if (options & X86Inst::_kOptionInvalidRex)
3605 0 : goto InvalidRexPrefix;
3606 7652 : opReg &= 0x7;
3607 : }
3608 : }
3609 :
3610 : // Emit instruction opcodes.
3611 9868 : opCode += opReg;
3612 9868 : EMIT_MM_OP(opCode);
3613 :
3614 9868 : if (imLen != 0)
3615 7652 : goto EmitImm;
3616 : else
3617 2216 : goto EmitDone;
3618 :
3619 0 : EmitX86OpImplicitMem:
3620 : // NOTE: Don't change the emit order here, it's compatible with KeyStone/LLVM.
3621 0 : rmInfo = x86MemInfo[rmRel->as<X86Mem>().getBaseIndexType()];
3622 0 : if (ASMJIT_UNLIKELY(rmRel->as<X86Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
3623 0 : goto InvalidInstruction;
3624 :
3625 : // Emit mandatory instruction prefix.
3626 0 : EMIT_PP(opCode);
3627 :
3628 : // Emit REX prefix (64-bit only).
3629 : {
3630 : uint32_t rex = x86ExtractREX(opCode, options);
3631 0 : if (rex) {
3632 0 : if (options & X86Inst::_kOptionInvalidRex)
3633 0 : goto InvalidRexPrefix;
3634 0 : EMIT_BYTE(rex | kX86ByteRex);
3635 : }
3636 : }
3637 :
3638 : // Segment-override prefix.
3639 0 : if (rmRel->as<X86Mem>().hasSegment())
3640 0 : EMIT_BYTE(x86SegmentPrefix[rmRel->as<X86Mem>().getSegmentId()]);
3641 :
3642 : // Address-override prefix.
3643 0 : if (rmInfo & _getAddressOverrideMask())
3644 0 : EMIT_BYTE(0x67);
3645 :
3646 : // Emit instruction opcodes.
3647 0 : EMIT_MM_OP(opCode);
3648 :
3649 : if (imLen != 0)
3650 : goto EmitImm;
3651 : else
3652 0 : goto EmitDone;
3653 :
3654 21946 : EmitX86R:
3655 : // Mandatory instruction prefix.
3656 21946 : EMIT_PP(opCode);
3657 :
3658 : // Rex prefix (64-bit only).
3659 : {
3660 21946 : uint32_t rex = x86ExtractREX(opCode, options) |
3661 21946 : ((opReg & 0x08) >> 1) | // REX.R (0x04).
3662 21946 : ((rbReg ) >> 3) ; // REX.B (0x01).
3663 21946 : if (rex) {
3664 2198 : if (options & X86Inst::_kOptionInvalidRex)
3665 0 : goto InvalidRexPrefix;
3666 2198 : EMIT_BYTE(rex | kX86ByteRex);
3667 2198 : opReg &= 0x07;
3668 2198 : rbReg &= 0x07;
3669 : }
3670 : }
3671 :
3672 : // Instruction opcodes.
3673 21946 : EMIT_MM_OP(opCode);
3674 : // ModR.
3675 21946 : EMIT_BYTE(x86EncodeMod(3, opReg, rbReg));
3676 :
3677 21946 : if (imLen != 0)
3678 1984 : goto EmitImm;
3679 : else
3680 19962 : goto EmitDone;
3681 :
3682 14496 : EmitX86M:
3683 : ASMJIT_ASSERT(rmRel != nullptr);
3684 : ASMJIT_ASSERT(rmRel->getOp() == Operand::kOpMem);
3685 14496 : rmInfo = x86MemInfo[rmRel->as<X86Mem>().getBaseIndexType()];
3686 :
3687 : // GP instructions have never compressed displacement specified.
3688 : ASMJIT_ASSERT((opCode & X86Inst::kOpCode_CDSHL_Mask) == 0);
3689 :
3690 : // Segment-override prefix.
3691 14496 : if (rmRel->as<X86Mem>().hasSegment())
3692 0 : EMIT_BYTE(x86SegmentPrefix[rmRel->as<X86Mem>().getSegmentId()]);
3693 :
3694 : // Address-override prefix.
3695 14496 : if (rmInfo & _getAddressOverrideMask())
3696 0 : EMIT_BYTE(0x67);
3697 :
3698 : // Mandatory instruction prefix.
3699 14496 : EMIT_PP(opCode);
3700 :
3701 : rbReg = rmRel->as<X86Mem>().getBaseId();
3702 : rxReg = rmRel->as<X86Mem>().getIndexId();
3703 :
3704 : // REX prefix (64-bit only).
3705 : {
3706 : uint32_t rex;
3707 :
3708 14496 : rex = (rbReg >> 3) & 0x01; // REX.B (0x01).
3709 14496 : rex |= (rxReg >> 2) & 0x02; // REX.X (0x02).
3710 14496 : rex |= (opReg >> 1) & 0x04; // REX.R (0x04).
3711 :
3712 14496 : rex &= rmInfo;
3713 14496 : rex |= x86ExtractREX(opCode, options);
3714 :
3715 14496 : if (rex) {
3716 82 : if (options & X86Inst::_kOptionInvalidRex)
3717 0 : goto InvalidRexPrefix;
3718 82 : EMIT_BYTE(rex | kX86ByteRex);
3719 82 : opReg &= 0x07;
3720 : }
3721 : }
3722 :
3723 : // Instruction opcodes.
3724 14496 : EMIT_MM_OP(opCode);
3725 : // ... Fall through ...
3726 :
3727 : // --------------------------------------------------------------------------
3728 : // [Emit - MOD/SIB]
3729 : // --------------------------------------------------------------------------
3730 :
3731 14496 : EmitModSib:
3732 14496 : if (!(rmInfo & (kX86MemInfo_Index | kX86MemInfo_67H_X86))) {
3733 : // ==========|> [BASE + DISP8|DISP32].
3734 14496 : if (rmInfo & kX86MemInfo_BaseGp) {
3735 14496 : rbReg &= 0x7;
3736 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3737 :
3738 : uint32_t mod = x86EncodeMod(0, opReg, rbReg);
3739 14496 : if (rbReg == X86Gp::kIdSp) {
3740 : // [XSP|R12].
3741 8428 : if (relOffset == 0) {
3742 1864 : EMIT_BYTE(mod);
3743 1864 : EMIT_BYTE(x86EncodeSib(0, 4, 4));
3744 : }
3745 : // [XSP|R12 + DISP8|DISP32].
3746 : else {
3747 6564 : uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift;
3748 6564 : int32_t cdOffset = relOffset >> cdShift;
3749 :
3750 6564 : if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) {
3751 6564 : EMIT_BYTE(mod + 0x40); // <- MOD(1, opReg, rbReg).
3752 6564 : EMIT_BYTE(x86EncodeSib(0, 4, 4));
3753 6564 : EMIT_BYTE(cdOffset & 0xFF);
3754 : }
3755 : else {
3756 0 : EMIT_BYTE(mod + 0x80); // <- MOD(2, opReg, rbReg).
3757 0 : EMIT_BYTE(x86EncodeSib(0, 4, 4));
3758 0 : EMIT_32(relOffset);
3759 : }
3760 : }
3761 : }
3762 6068 : else if (rbReg != X86Gp::kIdBp && relOffset == 0) {
3763 : // [BASE].
3764 3870 : EMIT_BYTE(mod);
3765 : }
3766 : else {
3767 : // [BASE + DISP8|DISP32].
3768 2198 : uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift;
3769 2198 : int32_t cdOffset = relOffset >> cdShift;
3770 :
3771 2198 : if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) {
3772 2186 : EMIT_BYTE(mod + 0x40);
3773 2186 : EMIT_BYTE(cdOffset & 0xFF);
3774 : }
3775 : else {
3776 12 : EMIT_BYTE(mod + 0x80);
3777 12 : EMIT_32(relOffset);
3778 : }
3779 : }
3780 : }
3781 : // ==========|> [ABSOLUTE | DISP32].
3782 0 : else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
3783 0 : if (is32Bit()) {
3784 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3785 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 5));
3786 0 : EMIT_32(relOffset);
3787 : }
3788 : else {
3789 : uint64_t baseAddress = getCodeInfo().getBaseAddress();
3790 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3791 :
3792 : // Prefer absolute addressing mode if FS|GS segment override is present.
3793 0 : bool absoluteValid = rmRel->as<X86Mem>().getOffsetHi32() == (relOffset >> 31);
3794 0 : bool preferAbsolute = (rmRel->as<X86Mem>().getSegmentId() >= X86Seg::kIdFs) || rmRel->as<X86Mem>().isAbs();
3795 :
3796 : // If we know the base address and the memory operand points to an
3797 : // absolute address it's possible to calculate REL32 that can be
3798 : // be used as [RIP+REL32] in 64-bit mode.
3799 0 : if (baseAddress != Globals::kNoBaseAddress && !preferAbsolute) {
3800 : const uint32_t kModRel32Size = 5;
3801 0 : uint64_t rip64 = baseAddress +
3802 0 : static_cast<uint64_t>((uintptr_t)(cursor - _bufferData)) + imLen + kModRel32Size;
3803 :
3804 0 : uint64_t rel64 = static_cast<uint64_t>(rmRel->as<X86Mem>().getOffset()) - rip64;
3805 0 : if (Utils::isInt32(static_cast<int64_t>(rel64))) {
3806 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 5));
3807 0 : EMIT_32(static_cast<uint32_t>(rel64 & 0xFFFFFFFFU));
3808 0 : if (imLen != 0)
3809 0 : goto EmitImm;
3810 : else
3811 0 : goto EmitDone;
3812 : }
3813 : }
3814 :
3815 0 : if (ASMJIT_UNLIKELY(!absoluteValid))
3816 0 : goto InvalidAddress64Bit;
3817 :
3818 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 4));
3819 0 : EMIT_BYTE(x86EncodeSib(0, 4, 5));
3820 0 : EMIT_32(relOffset);
3821 : }
3822 : }
3823 : // ==========|> [LABEL|RIP + DISP32]
3824 : else {
3825 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 5));
3826 :
3827 0 : if (is32Bit()) {
3828 0 : EmitModSib_LabelRip_X86:
3829 0 : if (ASMJIT_UNLIKELY(_code->_relocations.willGrow(&_code->_baseHeap) != kErrorOk))
3830 0 : goto NoHeapMemory;
3831 :
3832 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3833 0 : if (rmInfo & kX86MemInfo_BaseLabel) {
3834 : // [LABEL->ABS].
3835 0 : label = _code->getLabelEntry(rmRel->as<X86Mem>().getBaseId());
3836 0 : if (!label) goto InvalidLabel;
3837 :
3838 0 : err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, 4);
3839 0 : if (ASMJIT_UNLIKELY(err)) goto Failed;
3840 :
3841 0 : re->_sourceSectionId = _section->getId();
3842 0 : re->_sourceOffset = static_cast<uint64_t>((uintptr_t)(cursor - _bufferData));
3843 0 : re->_data = static_cast<int64_t>(relOffset);
3844 :
3845 0 : if (label->isBound()) {
3846 : // Bound label.
3847 0 : re->_data += static_cast<uint64_t>(label->getOffset());
3848 0 : EMIT_32(0);
3849 : }
3850 : else {
3851 : // Non-bound label.
3852 0 : relOffset = -4 - imLen;
3853 : relSize = 4;
3854 0 : goto EmitRel;
3855 : }
3856 : }
3857 : else {
3858 : // [RIP->ABS].
3859 0 : err = _code->newRelocEntry(&re, RelocEntry::kTypeRelToAbs, 4);
3860 0 : if (ASMJIT_UNLIKELY(err)) goto Failed;
3861 :
3862 0 : re->_sourceSectionId = _section->getId();
3863 0 : re->_sourceOffset = static_cast<uint64_t>((uintptr_t)(cursor - _bufferData));
3864 0 : re->_data = re->_sourceOffset + static_cast<uint64_t>(static_cast<int64_t>(relOffset));
3865 0 : EMIT_32(0);
3866 : }
3867 : }
3868 : else {
3869 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3870 0 : if (rmInfo & kX86MemInfo_BaseLabel) {
3871 : // [RIP].
3872 0 : label = _code->getLabelEntry(rmRel->as<X86Mem>().getBaseId());
3873 0 : if (!label) goto InvalidLabel;
3874 :
3875 0 : relOffset -= (4 + imLen);
3876 0 : if (label->isBound()) {
3877 : // Bound label.
3878 0 : relOffset += label->getOffset() - static_cast<int32_t>((intptr_t)(cursor - _bufferData));
3879 0 : EMIT_32(static_cast<int32_t>(relOffset));
3880 : }
3881 : else {
3882 : // Non-bound label.
3883 : relSize = 4;
3884 0 : goto EmitRel;
3885 : }
3886 : }
3887 : else {
3888 : // [RIP].
3889 0 : EMIT_32(static_cast<int32_t>(relOffset));
3890 : }
3891 : }
3892 : }
3893 : }
3894 0 : else if (!(rmInfo & kX86MemInfo_67H_X86)) {
3895 : // ESP|RSP can't be used as INDEX in pure SIB mode, however, VSIB mode
3896 : // allows XMM4|YMM4|ZMM4 (that's why the check is before the label).
3897 0 : if (ASMJIT_UNLIKELY(rxReg == X86Gp::kIdSp))
3898 0 : goto InvalidAddressIndex;
3899 :
3900 0 : EmitModVSib:
3901 0 : rxReg &= 0x7;
3902 :
3903 : // ==========|> [BASE + INDEX + DISP8|DISP32].
3904 0 : if (rmInfo & kX86MemInfo_BaseGp) {
3905 0 : rbReg &= 0x7;
3906 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3907 :
3908 : uint32_t mod = x86EncodeMod(0, opReg, 4);
3909 : uint32_t sib = x86EncodeSib(rmRel->as<X86Mem>().getShift(), rxReg, rbReg);
3910 :
3911 0 : if (relOffset == 0 && rbReg != X86Gp::kIdBp) {
3912 : // [BASE + INDEX << SHIFT].
3913 0 : EMIT_BYTE(mod);
3914 0 : EMIT_BYTE(sib);
3915 : }
3916 : else {
3917 0 : uint32_t cdShift = (opCode & X86Inst::kOpCode_CDSHL_Mask) >> X86Inst::kOpCode_CDSHL_Shift;
3918 0 : int32_t cdOffset = relOffset >> cdShift;
3919 :
3920 0 : if (Utils::isInt8(cdOffset) && relOffset == (cdOffset << cdShift)) {
3921 : // [BASE + INDEX << SHIFT + DISP8].
3922 0 : EMIT_BYTE(mod + 0x40); // <- MOD(1, opReg, 4).
3923 0 : EMIT_BYTE(sib);
3924 0 : EMIT_BYTE(cdOffset);
3925 : }
3926 : else {
3927 : // [BASE + INDEX << SHIFT + DISP32].
3928 0 : EMIT_BYTE(mod + 0x80); // <- MOD(2, opReg, 4).
3929 0 : EMIT_BYTE(sib);
3930 0 : EMIT_32(relOffset);
3931 : }
3932 : }
3933 : }
3934 : // ==========|> [INDEX + DISP32].
3935 0 : else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
3936 : // [INDEX << SHIFT + DISP32].
3937 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 4));
3938 0 : EMIT_BYTE(x86EncodeSib(rmRel->as<X86Mem>().getShift(), rxReg, 5));
3939 :
3940 : relOffset = rmRel->as<X86Mem>().getOffsetLo32();
3941 0 : EMIT_32(relOffset);
3942 : }
3943 : // ==========|> [LABEL|RIP + INDEX + DISP32].
3944 : else {
3945 0 : if (is32Bit()) {
3946 0 : EMIT_BYTE(x86EncodeMod(0, opReg, 4));
3947 0 : EMIT_BYTE(x86EncodeSib(rmRel->as<X86Mem>().getShift(), rxReg, 5));
3948 0 : goto EmitModSib_LabelRip_X86;
3949 : }
3950 : else {
3951 : // NOTE: This also handles VSIB+RIP, which is not allowed in 64-bit mode.
3952 0 : goto InvalidAddress;
3953 : }
3954 : }
3955 : }
3956 : else {
3957 : // 16-bit address mode (32-bit mode with 67 override prefix).
3958 0 : relOffset = (static_cast<int32_t>(rmRel->as<X86Mem>().getOffsetLo32()) << 16) >> 16;
3959 :
3960 : // NOTE: 16-bit addresses don't use SIB byte and their encoding differs. We
3961 : // use a table-based approach to calculate the proper MOD byte as it's easier.
3962 : // Also, not all BASE [+ INDEX] combinations are supported in 16-bit mode, so
3963 : // this may fail.
3964 : const uint32_t kBaseGpIdx = (kX86MemInfo_BaseGp | kX86MemInfo_Index);
3965 :
3966 0 : if (rmInfo & kBaseGpIdx) {
3967 : // ==========|> [BASE + INDEX + DISP16].
3968 : uint32_t mod;
3969 :
3970 0 : rbReg &= 0x7;
3971 0 : rxReg &= 0x7;
3972 :
3973 0 : if ((rmInfo & kBaseGpIdx) == kBaseGpIdx) {
3974 : uint32_t shf = rmRel->as<X86Mem>().getShift();
3975 0 : if (ASMJIT_UNLIKELY(shf != 0))
3976 0 : goto InvalidAddress;
3977 0 : mod = x86Mod16BaseIndexTable[(rbReg << 3) + rxReg];
3978 : }
3979 : else {
3980 0 : if (rmInfo & kX86MemInfo_Index)
3981 : rbReg = rxReg;
3982 0 : mod = x86Mod16BaseTable[rbReg];
3983 : }
3984 :
3985 0 : if (ASMJIT_UNLIKELY(mod == 0xFF))
3986 0 : goto InvalidAddress;
3987 :
3988 0 : mod += opReg << 3;
3989 0 : if (relOffset == 0 && mod != 0x06) {
3990 0 : EMIT_BYTE(mod);
3991 : }
3992 0 : else if (Utils::isInt8(relOffset)) {
3993 0 : EMIT_BYTE(mod + 0x40);
3994 0 : EMIT_BYTE(relOffset);
3995 : }
3996 : else {
3997 0 : EMIT_BYTE(mod + 0x80);
3998 0 : EMIT_16(relOffset);
3999 : }
4000 : }
4001 : else {
4002 : // Not supported in 16-bit addresses.
4003 0 : if (rmInfo & (kX86MemInfo_BaseRip | kX86MemInfo_BaseLabel))
4004 0 : goto InvalidAddress;
4005 :
4006 : // ==========|> [DISP16].
4007 0 : EMIT_BYTE(opReg | 0x06);
4008 0 : EMIT_16(relOffset);
4009 : }
4010 : }
4011 :
4012 14496 : if (imLen != 0)
4013 0 : goto EmitImm;
4014 : else
4015 14496 : goto EmitDone;
4016 :
4017 : // --------------------------------------------------------------------------
4018 : // [Emit - FPU]
4019 : // --------------------------------------------------------------------------
4020 :
4021 0 : EmitFpuOp:
4022 : // Mandatory instruction prefix.
4023 0 : EMIT_PP(opCode);
4024 :
4025 : // FPU instructions consist of two opcodes.
4026 0 : EMIT_BYTE(opCode >> X86Inst::kOpCode_FPU_2B_Shift);
4027 0 : EMIT_BYTE(opCode);
4028 0 : goto EmitDone;
4029 :
4030 : // --------------------------------------------------------------------------
4031 : // [Emit - VEX / EVEX]
4032 : // --------------------------------------------------------------------------
4033 :
4034 : EmitVexEvexOp:
4035 : {
4036 : // These don't use immediate.
4037 : ASMJIT_ASSERT(imLen == 0);
4038 :
4039 : // Only 'vzeroall' and 'vzeroupper' instructions use this encoding, they
4040 : // don't define 'W' to be '1' so we can just check the 'mmmmm' field. Both
4041 : // functions can encode by using VEV2 prefix so VEV3 is basically only used
4042 : // when forced from outside.
4043 : ASMJIT_ASSERT((opCode & X86Inst::kOpCode_W) == 0);
4044 :
4045 0 : uint32_t x = ((opCode & X86Inst::kOpCode_MM_Mask ) >> (X86Inst::kOpCode_MM_Shift )) |
4046 0 : ((opCode & X86Inst::kOpCode_LL_Mask ) >> (X86Inst::kOpCode_LL_Shift - 10)) |
4047 0 : ((opCode & X86Inst::kOpCode_PP_VEXMask) >> (X86Inst::kOpCode_PP_Shift - 8)) |
4048 0 : ((options & X86Inst::kOptionVex3 ) >> (X86Inst::kOpCode_MM_Shift )) ;
4049 0 : if (x & 0x04U) {
4050 0 : x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|00000Lpp|0000m0mm|00000000].
4051 0 : x ^= (kX86ByteVex3) | // [........|00000Lpp|0000m0mm|__VEX3__].
4052 : (0x07U << 13) | // [........|00000Lpp|1110m0mm|__VEX3__].
4053 0 : (0x0FU << 19) | // [........|01111Lpp|1110m0mm|__VEX3__].
4054 0 : (opCode << 24) ; // [_OPCODE_|01111Lpp|1110m0mm|__VEX3__].
4055 :
4056 0 : EMIT_32(x);
4057 0 : goto EmitDone;
4058 : }
4059 : else {
4060 0 : x = ((x >> 8) ^ x) ^ 0xF9;
4061 0 : EMIT_BYTE(kX86ByteVex2);
4062 0 : EMIT_BYTE(x);
4063 0 : EMIT_BYTE(opCode);
4064 0 : goto EmitDone;
4065 : }
4066 : }
4067 :
4068 0 : EmitVexEvexR:
4069 : {
4070 : // VEX instructions use only 0-1 BYTE immediate.
4071 : ASMJIT_ASSERT(imLen <= 1);
4072 :
4073 : // Construct `x` - a complete EVEX|VEX prefix.
4074 0 : uint32_t x = ((opReg << 4) & 0xF980U) | // [........|........|Vvvvv..R|R.......].
4075 0 : ((rbReg << 2) & 0x0060U) | // [........|........|........|.BB.....].
4076 : (x86ExtractLLMM(opCode, options)) | // [........|.LL.....|Vvvvv..R|RBBmmmmm].
4077 0 : (_extraReg.getId() << 16); // [........|.LL..aaa|Vvvvv..R|RBBmmmmm].
4078 0 : opReg &= 0x7;
4079 :
4080 : // Mark invalid VEX (force EVEX) case: // [@.......|.LL..aaa|Vvvvv..R|RBBmmmmm].
4081 0 : x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>());
4082 :
4083 : // Handle AVX512 options by a single branch.
4084 : const uint32_t kAvx512Options = X86Inst::kOptionZMask |
4085 : X86Inst::kOption1ToX |
4086 : X86Inst::kOptionSAE |
4087 : X86Inst::kOptionER ;
4088 0 : if (options & kAvx512Options) {
4089 : // Memory broadcast without a memory operand is invalid.
4090 0 : if (ASMJIT_UNLIKELY(options & X86Inst::kOption1ToX))
4091 0 : goto InvalidBroadcast;
4092 :
4093 : // TODO: {sae} and {er}
4094 0 : x |= options & X86Inst::kOptionZMask; // [@.......|zLL..aaa|Vvvvv..R|RBBmmmmm].
4095 : }
4096 :
4097 : // Check if EVEX is required by checking bits in `x` : [@.......|xx...xxx|x......x|.x.x....].
4098 0 : if (x & 0x80C78150U) {
4099 0 : uint32_t y = ((x << 4) & 0x00080000U) | // [@.......|....V...|........|........].
4100 0 : ((x >> 4) & 0x00000010U) ; // [@.......|....V...|........|...R....].
4101 0 : x = (x & 0x00FF78E3U) | y; // [........|zLL.Vaaa|0vvvv000|RBBR00mm].
4102 0 : x = (x << 8) | // [zLL.Vaaa|0vvvv000|RBBR00mm|00000000].
4103 0 : ((opCode >> kSHR_W_PP) & 0x00830000U) | // [zLL.Vaaa|Wvvvv0pp|RBBR00mm|00000000].
4104 0 : ((opCode >> kSHR_W_EW) & 0x00800000U) ; // [zLL.Vaaa|Wvvvv0pp|RBBR00mm|00000000] (added EVEX.W).
4105 : // _ ____ ____
4106 0 : x ^= 0x087CF000U | kX86ByteEvex; // [zLL.Vaaa|Wvvvv1pp|RBBR00mm|01100010].
4107 :
4108 : EMIT_32(x);
4109 0 : EMIT_BYTE(opCode);
4110 :
4111 0 : rbReg &= 0x7;
4112 0 : EMIT_BYTE(x86EncodeMod(3, opReg, rbReg));
4113 :
4114 0 : if (imLen == 0) goto EmitDone;
4115 0 : EMIT_BYTE(imVal & 0xFF);
4116 0 : goto EmitDone;
4117 : }
4118 :
4119 : // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|R0B0mmmm].
4120 0 : x |= ((opCode >> (kSHR_W_PP + 8)) & 0x8300U) | // [00000000|00L00000|Wvvvv0pp|R0B0mmmm].
4121 0 : ((x >> 11 ) & 0x0400U) ; // [00000000|00L00000|WvvvvLpp|R0B0mmmm].
4122 :
4123 : // Check if VEX3 is required / forced: [........|........|x.......|..x..x..].
4124 0 : if (x & 0x0008024U) {
4125 0 : uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opCode << 24);
4126 :
4127 : // Clear 'FORCE-VEX3' bit and all high bits.
4128 0 : x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|WvvvvLpp|R0B0m0mm|00000000].
4129 : // ____ _ _
4130 0 : x ^= xorMsk; // [_OPCODE_|WvvvvLpp|R1Bmmmmm|VEX3|XOP].
4131 : EMIT_32(x);
4132 :
4133 0 : rbReg &= 0x7;
4134 0 : EMIT_BYTE(x86EncodeMod(3, opReg, rbReg));
4135 :
4136 0 : if (imLen == 0) goto EmitDone;
4137 0 : EMIT_BYTE(imVal & 0xFF);
4138 0 : goto EmitDone;
4139 : }
4140 : else {
4141 : // 'mmmmm' must be '00001'.
4142 : ASMJIT_ASSERT((x & 0x1F) == 0x01);
4143 :
4144 0 : x = ((x >> 8) ^ x) ^ 0xF9;
4145 0 : EMIT_BYTE(kX86ByteVex2);
4146 0 : EMIT_BYTE(x);
4147 0 : EMIT_BYTE(opCode);
4148 :
4149 0 : rbReg &= 0x7;
4150 0 : EMIT_BYTE(x86EncodeMod(3, opReg, rbReg));
4151 :
4152 0 : if (imLen == 0) goto EmitDone;
4153 0 : EMIT_BYTE(imVal & 0xFF);
4154 0 : goto EmitDone;
4155 : }
4156 : }
4157 :
4158 0 : EmitVexEvexM:
4159 : ASMJIT_ASSERT(rmRel != nullptr);
4160 : ASMJIT_ASSERT(rmRel->getOp() == Operand::kOpMem);
4161 0 : rmInfo = x86MemInfo[rmRel->as<X86Mem>().getBaseIndexType()];
4162 :
4163 : // Segment-override prefix.
4164 0 : if (rmRel->as<X86Mem>().hasSegment())
4165 0 : EMIT_BYTE(x86SegmentPrefix[rmRel->as<X86Mem>().getSegmentId()]);
4166 :
4167 : // Address-override prefix.
4168 0 : if (rmInfo & _getAddressOverrideMask())
4169 0 : EMIT_BYTE(0x67);
4170 :
4171 0 : rbReg = rmRel->as<X86Mem>().hasBaseReg() ? rmRel->as<X86Mem>().getBaseId() : uint32_t(0);
4172 0 : rxReg = rmRel->as<X86Mem>().hasIndexReg() ? rmRel->as<X86Mem>().getIndexId() : uint32_t(0);
4173 :
4174 : {
4175 : // VEX instructions use only 0-1 BYTE immediate.
4176 : ASMJIT_ASSERT(imLen <= 1);
4177 :
4178 : // Construct `x` - a complete EVEX|VEX prefix.
4179 0 : uint32_t x = ((opReg << 4 ) & 0x0000F980U) | // [........|........|Vvvvv..R|R.......].
4180 0 : ((rxReg << 3 ) & 0x00000040U) | // [........|........|........|.X......].
4181 0 : ((rxReg << 15) & 0x00080000U) | // [........|....X...|........|........].
4182 0 : ((rbReg << 2 ) & 0x00000020U) | // [........|........|........|..B.....].
4183 : (x86ExtractLLMM(opCode, options)) | // [........|.LL.X...|Vvvvv..R|RXBmmmmm].
4184 0 : (_extraReg.getId() << 16) ; // [........|.LL.Xaaa|Vvvvv..R|RXBmmmmm].
4185 0 : opReg &= 0x07U;
4186 :
4187 : // Mark invalid VEX (force EVEX) case: // [@.......|.LL.Xaaa|Vvvvv..R|RXBmmmmm].
4188 0 : x |= (~commonData->getFlags() & X86Inst::kFlagVex) << (31 - Utils::firstBitOfT<X86Inst::kFlagVex>());
4189 :
4190 : // Handle AVX512 options by a single branch.
4191 : const uint32_t kAvx512Options = X86Inst::kOption1ToX |
4192 : X86Inst::kOptionZMask |
4193 : X86Inst::kOptionSAE |
4194 : X86Inst::kOptionER ;
4195 0 : if (options & kAvx512Options) {
4196 : // {er} and {sae} are both invalid if memory operand is used.
4197 0 : if (ASMJIT_UNLIKELY(options & (X86Inst::kOptionSAE | X86Inst::kOptionER)))
4198 0 : goto InvalidEROrSAE;
4199 :
4200 0 : x |= options & (X86Inst::kOption1ToX | // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm].
4201 : X86Inst::kOptionZMask); // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm].
4202 : }
4203 :
4204 : // Check if EVEX is required by checking bits in `x` : [@.......|xx.xxxxx|x......x|...x....].
4205 0 : if (x & 0x80DF8110U) {
4206 0 : uint32_t y = ((x << 4) & 0x00080000U) | // [@.......|....V...|........|........].
4207 0 : ((x >> 4) & 0x00000010U) ; // [@.......|....V...|........|...R....].
4208 0 : x = (x & 0x00FF78E3U) | y; // [........|zLLbVaaa|0vvvv000|RXBR00mm].
4209 0 : x = (x << 8) | // [zLLbVaaa|0vvvv000|RBBR00mm|00000000].
4210 0 : ((opCode >> kSHR_W_PP) & 0x00830000U) | // [zLLbVaaa|Wvvvv0pp|RBBR00mm|00000000].
4211 0 : ((opCode >> kSHR_W_EW) & 0x00800000U) ; // [zLLbVaaa|Wvvvv0pp|RBBR00mm|00000000] (added EVEX.W).
4212 : // _ ____ ____
4213 0 : x ^= 0x087CF000U | kX86ByteEvex; // [zLLbVaaa|Wvvvv1pp|RBBR00mm|01100010].
4214 :
4215 : EMIT_32(x);
4216 0 : EMIT_BYTE(opCode);
4217 :
4218 0 : if (opCode & 0x10000000U) {
4219 : // Broadcast, change the compressed displacement scale to either x4 (SHL 2) or x8 (SHL 3)
4220 : // depending on instruction's W. If 'W' is 1 'SHL' must be 3, otherwise it must be 2.
4221 0 : opCode &=~static_cast<uint32_t>(X86Inst::kOpCode_CDSHL_Mask);
4222 0 : opCode |= ((x & 0x00800000U) ? 3 : 2) << X86Inst::kOpCode_CDSHL_Shift;
4223 : }
4224 : else {
4225 : // Add the compressed displacement 'SHF' to the opcode based on 'TTWLL'.
4226 0 : uint32_t TTWLL = ((opCode >> (X86Inst::kOpCode_CDTT_Shift - 3)) & 0x18) +
4227 0 : ((opCode >> (X86Inst::kOpCode_W_Shift - 2)) & 0x04) +
4228 0 : ((x >> 29) & 0x3);
4229 0 : opCode += x86CDisp8SHL[TTWLL];
4230 : }
4231 : }
4232 : else {
4233 : // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|RXB0mmmm].
4234 0 : x |= ((opCode >> (kSHR_W_PP + 8)) & 0x8300U) | // [00000000|00L00000|Wvvvv0pp|RXB0mmmm].
4235 0 : ((x >> 11 ) & 0x0400U) ; // [00000000|00L00000|WvvvvLpp|RXB0mmmm].
4236 :
4237 : // Clear a possible CDisp specified by EVEX.
4238 0 : opCode &= ~X86Inst::kOpCode_CDSHL_Mask;
4239 :
4240 : // Check if VEX3 is required / forced: [........|........|x.......|.xx..x..].
4241 0 : if (x & 0x0008064U) {
4242 0 : uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opCode << 24);
4243 :
4244 : // Clear 'FORCE-VEX3' bit and all high bits.
4245 0 : x = (x & (0x4 ^ 0xFFFF)) << 8; // [00000000|WvvvvLpp|RXB0m0mm|00000000].
4246 : // ____ ___
4247 0 : x ^= xorMsk; // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP].
4248 0 : EMIT_32(x);
4249 : }
4250 : else {
4251 : // 'mmmmm' must be '00001'.
4252 : ASMJIT_ASSERT((x & 0x1F) == 0x01);
4253 :
4254 0 : x = ((x >> 8) ^ x) ^ 0xF9;
4255 0 : EMIT_BYTE(kX86ByteVex2);
4256 0 : EMIT_BYTE(x);
4257 0 : EMIT_BYTE(opCode);
4258 : }
4259 : }
4260 : }
4261 :
4262 : // MOD|SIB address.
4263 0 : if (!commonData->hasFlag(X86Inst::kFlagVsib))
4264 0 : goto EmitModSib;
4265 :
4266 : // MOD|VSIB address without INDEX is invalid.
4267 0 : if (rmInfo & kX86MemInfo_Index)
4268 0 : goto EmitModVSib;
4269 0 : goto InvalidInstruction;
4270 :
4271 : // --------------------------------------------------------------------------
4272 : // [Emit - Jmp/Jcc/Call]
4273 : // --------------------------------------------------------------------------
4274 :
4275 : // TODO: Should be adjusted after the support for multiple sections feature is added.
4276 0 : EmitJmpCall:
4277 : {
4278 : // Emit REX prefix if asked for (64-bit only).
4279 : uint32_t rex = x86ExtractREX(opCode, options);
4280 0 : if (rex) {
4281 0 : if (options & X86Inst::_kOptionInvalidRex)
4282 0 : goto InvalidRexPrefix;
4283 0 : EMIT_BYTE(rex | kX86ByteRex);
4284 : }
4285 :
4286 0 : uint64_t ip = static_cast<uint64_t>((intptr_t)(cursor - _bufferData));
4287 : uint32_t rel32 = 0;
4288 : uint32_t opCode8 = commonData->getAltOpCode();
4289 :
4290 : uint32_t inst8Size = 1 + 1; // OPCODE + REL8 .
4291 : uint32_t inst32Size = 1 + 4; // [PREFIX] OPCODE + REL32.
4292 :
4293 : // Jcc instructions with 32-bit displacement use 0x0F prefix,
4294 : // other instructions don't. No other prefixes are used by X86.
4295 : ASMJIT_ASSERT((opCode8 & X86Inst::kOpCode_MM_Mask) == 0);
4296 : ASMJIT_ASSERT((opCode & X86Inst::kOpCode_MM_Mask) == 0 ||
4297 : (opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
4298 :
4299 : // Only one of these should be used at the same time.
4300 0 : inst32Size += static_cast<uint32_t>(opReg != 0);
4301 0 : inst32Size += static_cast<uint32_t>((opCode & X86Inst::kOpCode_MM_Mask) == X86Inst::kOpCode_MM_0F);
4302 :
4303 0 : if (rmRel->isLabel()) {
4304 0 : label = _code->getLabelEntry(rmRel->as<Label>());
4305 0 : if (!label) goto InvalidLabel;
4306 :
4307 0 : if (label->isBound()) {
4308 : // Bound label.
4309 0 : rel32 = static_cast<uint32_t>((static_cast<uint64_t>(label->getOffset()) - ip - inst32Size) & 0xFFFFFFFFU);
4310 0 : goto EmitJmpCallRel;
4311 : }
4312 : else {
4313 : // Non-bound label.
4314 0 : if (opCode8 && (!opCode || (options & X86Inst::kOptionShortForm))) {
4315 0 : EMIT_BYTE(opCode8);
4316 : relOffset = -1;
4317 : relSize = 1;
4318 0 : goto EmitRel;
4319 : }
4320 : else {
4321 : // Refuse also 'short' prefix, if specified.
4322 0 : if (ASMJIT_UNLIKELY(!opCode || (options & X86Inst::kOptionShortForm) != 0))
4323 0 : goto InvalidDisplacement;
4324 :
4325 : // Emit [PREFIX] OPCODE [/X] <DISP32>.
4326 0 : if (opCode & X86Inst::kOpCode_MM_Mask)
4327 0 : EMIT_BYTE(0x0F);
4328 :
4329 0 : EMIT_BYTE(opCode);
4330 0 : if (opReg)
4331 0 : EMIT_BYTE(x86EncodeMod(3, opReg, 0));
4332 :
4333 : relOffset = -4;
4334 : relSize = 4;
4335 0 : goto EmitRel;
4336 : }
4337 : }
4338 : }
4339 :
4340 0 : if (rmRel->isImm()) {
4341 : uint64_t baseAddress = getCodeInfo().getBaseAddress();
4342 : uint64_t jumpAddress = rmRel->as<Imm>().getUInt64();
4343 :
4344 : // If the base-address is known calculate a relative displacement and
4345 : // check if it fits in 32 bits (which is always true in 32-bit mode).
4346 : // Emit relative displacement as it was a bound label if all checks ok.
4347 0 : if (baseAddress != Globals::kNoBaseAddress) {
4348 0 : uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size;
4349 0 : if (getArchType() == ArchInfo::kTypeX86 || Utils::isInt32(static_cast<int64_t>(rel64))) {
4350 0 : rel32 = static_cast<uint32_t>(rel64 & 0xFFFFFFFFU);
4351 0 : goto EmitJmpCallRel;
4352 : }
4353 : else {
4354 : // Relative displacement exceeds 32-bits - relocator can only
4355 : // insert trampoline for jmp/call, but not for jcc/jecxz.
4356 0 : if (ASMJIT_UNLIKELY(!x86IsJmpOrCall(instId)))
4357 0 : goto InvalidDisplacement;
4358 : }
4359 : }
4360 :
4361 0 : if (ASMJIT_UNLIKELY(_code->_relocations.willGrow(&_code->_baseHeap) != kErrorOk))
4362 0 : goto NoHeapMemory;
4363 :
4364 0 : err = _code->newRelocEntry(&re, RelocEntry::kTypeAbsToRel, 0);
4365 0 : if (ASMJIT_UNLIKELY(err)) goto Failed;
4366 :
4367 0 : re->_sourceSectionId = _section->getId();
4368 0 : re->_data = static_cast<int64_t>(jumpAddress);
4369 :
4370 0 : if (ASMJIT_LIKELY(opCode)) {
4371 : // 64-bit: Emit REX prefix so the instruction can be patched later.
4372 : // REX prefix does nothing if not patched, but allows to patch the
4373 : // instruction to use MOD/M and to point to a memory where the final
4374 : // 64-bit address is stored.
4375 0 : re->_size = 4;
4376 0 : re->_sourceOffset = ip + inst32Size - 4;
4377 :
4378 0 : if (getArchType() != ArchInfo::kTypeX86 && x86IsJmpOrCall(instId)) {
4379 0 : if (!rex) {
4380 0 : re->_sourceOffset++;
4381 0 : EMIT_BYTE(kX86ByteRex);
4382 : }
4383 :
4384 0 : re->_type = RelocEntry::kTypeTrampoline;
4385 0 : _code->_trampolinesSize += 8;
4386 : }
4387 :
4388 : // Emit [PREFIX] OPCODE [/X] DISP32.
4389 0 : if (opCode & X86Inst::kOpCode_MM_Mask)
4390 0 : EMIT_BYTE(0x0F);
4391 :
4392 0 : EMIT_BYTE(opCode);
4393 0 : if (opReg)
4394 0 : EMIT_BYTE(x86EncodeMod(3, opReg, 0));
4395 :
4396 0 : EMIT_32(0);
4397 : }
4398 : else {
4399 0 : re->_size = 1;
4400 0 : re->_sourceOffset = ip + inst8Size - 1;
4401 :
4402 : // Emit OPCODE + DISP8.
4403 0 : EMIT_BYTE(opCode8);
4404 0 : EMIT_BYTE(0);
4405 : }
4406 0 : goto EmitDone;
4407 : }
4408 :
4409 : // Not Label|Imm -> Invalid.
4410 0 : goto InvalidInstruction;
4411 :
4412 : // Emit jmp/call with relative displacement known at assembly-time. Decide
4413 : // between 8-bit and 32-bit displacement encoding. Some instructions only
4414 : // allow either 8-bit or 32-bit encoding, others allow both encodings.
4415 0 : EmitJmpCallRel:
4416 0 : if (Utils::isInt8(static_cast<int32_t>(rel32 + inst32Size - inst8Size)) && opCode8 && !(options & X86Inst::kOptionLongForm)) {
4417 0 : options |= X86Inst::kOptionShortForm;
4418 0 : EMIT_BYTE(opCode8);
4419 0 : EMIT_BYTE(rel32 + inst32Size - inst8Size);
4420 0 : goto EmitDone;
4421 : }
4422 : else {
4423 0 : if (ASMJIT_UNLIKELY(!opCode || (options & X86Inst::kOptionShortForm) != 0))
4424 0 : goto InvalidDisplacement;
4425 :
4426 0 : options &= ~X86Inst::kOptionShortForm;
4427 0 : if (opCode & X86Inst::kOpCode_MM_Mask)
4428 0 : EMIT_BYTE(0x0F);
4429 :
4430 0 : EMIT_BYTE(opCode);
4431 0 : if (opReg)
4432 0 : EMIT_BYTE(x86EncodeMod(3, opReg, 0));
4433 :
4434 0 : EMIT_32(rel32);
4435 0 : goto EmitDone;
4436 : }
4437 : }
4438 :
4439 : // --------------------------------------------------------------------------
4440 : // [Emit - Relative]
4441 : // --------------------------------------------------------------------------
4442 :
4443 0 : EmitRel:
4444 : {
4445 : ASMJIT_ASSERT(!label->isBound());
4446 : ASMJIT_ASSERT(relSize == 1 || relSize == 4);
4447 :
4448 : // Chain with label.
4449 0 : size_t offset = (size_t)(cursor - _bufferData);
4450 0 : LabelLink* link = _code->newLabelLink(label, _section->getId(), offset, relOffset);
4451 :
4452 0 : if (ASMJIT_UNLIKELY(!link))
4453 0 : goto NoHeapMemory;
4454 :
4455 0 : if (re)
4456 0 : link->relocId = re->getId();
4457 :
4458 : // Emit label size as dummy data.
4459 0 : if (relSize == 1)
4460 0 : EMIT_BYTE(0x01);
4461 : else // if (relSize == 4)
4462 0 : EMIT_32(0x04040404);
4463 : }
4464 :
4465 0 : if (imLen == 0)
4466 0 : goto EmitDone;
4467 :
4468 : // --------------------------------------------------------------------------
4469 : // [Emit - Immediate]
4470 : // --------------------------------------------------------------------------
4471 :
4472 0 : EmitImm:
4473 : {
4474 : #if ASMJIT_ARCH_64BIT
4475 9636 : uint32_t i = imLen;
4476 9636 : uint64_t imm = static_cast<uint64_t>(imVal);
4477 : #else
4478 : uint32_t i = imLen;
4479 : uint32_t imm = static_cast<uint32_t>(imVal & 0xFFFFFFFFU);
4480 : #endif
4481 :
4482 : // Many instructions just use a single byte immediate, so make it fast.
4483 9636 : EMIT_BYTE(imm & 0xFFU); if (--i == 0) goto EmitDone;
4484 7652 : imm >>= 8;
4485 7652 : EMIT_BYTE(imm & 0xFFU); if (--i == 0) goto EmitDone;
4486 7652 : imm >>= 8;
4487 7652 : EMIT_BYTE(imm & 0xFFU); if (--i == 0) goto EmitDone;
4488 7652 : imm >>= 8;
4489 7652 : EMIT_BYTE(imm & 0xFFU); if (--i == 0) goto EmitDone;
4490 :
4491 : // Can be 1-4 or 8 bytes, this handles the remaining high DWORD of an 8-byte immediate.
4492 : ASMJIT_ASSERT(i == 4);
4493 :
4494 : #if ASMJIT_ARCH_64BIT
4495 7652 : imm >>= 8;
4496 7652 : EMIT_32(static_cast<uint32_t>(imm));
4497 : #else
4498 : EMIT_32(static_cast<uint32_t>((static_cast<uint64_t>(imVal) >> 32) & 0xFFFFFFFFU));
4499 : #endif
4500 : }
4501 :
4502 : // --------------------------------------------------------------------------
4503 : // [Done]
4504 : // --------------------------------------------------------------------------
4505 :
4506 48254 : EmitDone:
4507 : #if !defined(ASMJIT_DISABLE_LOGGING)
4508 : // Logging is a performance hit anyway, so make it the unlikely case.
4509 48254 : if (ASMJIT_UNLIKELY(options & CodeEmitter::kOptionLoggingEnabled))
4510 0 : _emitLog(instId, options, o0, o1, o2, o3, relSize, imLen, cursor);
4511 : #endif // !ASMJIT_DISABLE_LOGGING
4512 :
4513 : resetOptions();
4514 : resetExtraReg();
4515 : resetInlineComment();
4516 :
4517 48254 : _bufferPtr = cursor;
4518 48254 : return kErrorOk;
4519 :
4520 : // --------------------------------------------------------------------------
4521 : // [Error Cases]
4522 : // --------------------------------------------------------------------------
4523 :
4524 : #define ERROR_HANDLER(ERROR) \
4525 : ERROR: \
4526 : err = DebugUtils::errored(kError##ERROR); \
4527 : goto Failed;
4528 :
4529 0 : ERROR_HANDLER(NoHeapMemory)
4530 0 : ERROR_HANDLER(InvalidArgument)
4531 0 : ERROR_HANDLER(InvalidLabel)
4532 0 : ERROR_HANDLER(InvalidInstruction)
4533 0 : ERROR_HANDLER(InvalidLockPrefix)
4534 0 : ERROR_HANDLER(InvalidXAcquirePrefix)
4535 0 : ERROR_HANDLER(InvalidXReleasePrefix)
4536 0 : ERROR_HANDLER(InvalidRepPrefix)
4537 0 : ERROR_HANDLER(InvalidRexPrefix)
4538 0 : ERROR_HANDLER(InvalidBroadcast)
4539 0 : ERROR_HANDLER(InvalidEROrSAE)
4540 0 : ERROR_HANDLER(InvalidAddress)
4541 0 : ERROR_HANDLER(InvalidAddressIndex)
4542 0 : ERROR_HANDLER(InvalidAddress64Bit)
4543 0 : ERROR_HANDLER(InvalidDisplacement)
4544 0 : ERROR_HANDLER(InvalidSegment)
4545 0 : ERROR_HANDLER(InvalidImmediate)
4546 0 : ERROR_HANDLER(OperandSizeMismatch)
4547 0 : ERROR_HANDLER(AmbiguousOperandSize)
4548 0 : ERROR_HANDLER(NotConsecutiveRegs)
4549 :
4550 0 : Failed:
4551 0 : return _emitFailed(err, instId, options, o0, o1, o2, o3);
4552 : }
4553 :
4554 : // ============================================================================
4555 : // [asmjit::X86Assembler - Align]
4556 : // ============================================================================
4557 :
4558 0 : Error X86Assembler::align(uint32_t mode, uint32_t alignment) {
4559 : #if !defined(ASMJIT_DISABLE_LOGGING)
4560 0 : if (_globalOptions & kOptionLoggingEnabled)
4561 0 : _code->_logger->logf("%s.align %u\n", _code->_logger->getIndentation(), alignment);
4562 : #endif // !ASMJIT_DISABLE_LOGGING
4563 :
4564 0 : if (mode >= kAlignCount)
4565 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
4566 :
4567 0 : if (alignment <= 1)
4568 : return kErrorOk;
4569 :
4570 0 : if (!Utils::isPowerOf2(alignment) || alignment > Globals::kMaxAlignment)
4571 0 : return setLastError(DebugUtils::errored(kErrorInvalidArgument));
4572 :
4573 0 : uint32_t i = static_cast<uint32_t>(Utils::alignDiff<size_t>(getOffset(), alignment));
4574 0 : if (i == 0)
4575 : return kErrorOk;
4576 :
4577 0 : if (getRemainingSpace() < i) {
4578 0 : Error err = _code->growBuffer(&_section->_buffer, i);
4579 0 : if (ASMJIT_UNLIKELY(err)) return setLastError(err);
4580 : }
4581 :
4582 0 : uint8_t* cursor = _bufferPtr;
4583 : uint8_t pattern = 0x00;
4584 :
4585 0 : switch (mode) {
4586 0 : case kAlignCode: {
4587 0 : if (_globalHints & kHintOptimizedAlign) {
4588 : // Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP).
4589 : enum { kMaxNopSize = 9 };
4590 :
4591 : static const uint8_t nopData[kMaxNopSize][kMaxNopSize] = {
4592 : { 0x90 },
4593 : { 0x66, 0x90 },
4594 : { 0x0F, 0x1F, 0x00 },
4595 : { 0x0F, 0x1F, 0x40, 0x00 },
4596 : { 0x0F, 0x1F, 0x44, 0x00, 0x00 },
4597 : { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 },
4598 : { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 },
4599 : { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
4600 : { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
4601 : };
4602 :
4603 : do {
4604 0 : uint32_t n = std::min<uint32_t>(i, kMaxNopSize);
4605 0 : const uint8_t* src = nopData[n - 1];
4606 :
4607 0 : i -= n;
4608 : do {
4609 0 : EMIT_BYTE(*src++);
4610 0 : } while (--n);
4611 0 : } while (i);
4612 : }
4613 :
4614 : pattern = 0x90;
4615 : break;
4616 : }
4617 :
4618 0 : case kAlignData:
4619 : pattern = 0xCC;
4620 0 : break;
4621 :
4622 : case kAlignZero:
4623 : // Pattern already set to zero.
4624 : break;
4625 : }
4626 :
4627 0 : while (i) {
4628 0 : EMIT_BYTE(pattern);
4629 0 : i--;
4630 : }
4631 :
4632 0 : _bufferPtr = cursor;
4633 0 : return kErrorOk;
4634 : }
4635 :
4636 : } // asmjit namespace
4637 : } // namespace PLMD
4638 :
4639 : // [Api-End]
4640 : #include "./asmjit_apiend.h"
4641 :
4642 : // [Guard]
4643 : #endif // ASMJIT_BUILD_X86
4644 : #pragma GCC diagnostic pop
4645 : #endif // __PLUMED_HAS_ASMJIT
|