Line data Source code
1 : #ifdef __PLUMED_HAS_ASMJIT
2 : // This file is part of AsmJit project <https://asmjit.com>
3 : //
4 : // See asmjit.h or LICENSE.md for license and copyright information
5 : // SPDX-License-Identifier: Zlib
6 :
7 : #include "api-build_p.h"
8 : #if !defined(ASMJIT_NO_X86)
9 :
10 : #include "assembler.h"
11 : #include "codewriter_p.h"
12 : #include "cpuinfo.h"
13 : #include "emitterutils_p.h"
14 : #include "formatter.h"
15 : #include "logger.h"
16 : #include "misc_p.h"
17 : #include "support.h"
18 : #include "x86assembler.h"
19 : #include "x86emithelper_p.h"
20 : #include "x86instapi_p.h"
21 : #include "x86instdb_p.h"
22 : #include "x86formatter_p.h"
23 : #include "x86opcode_p.h"
24 :
25 : ASMJIT_BEGIN_SUB_NAMESPACE(x86)
26 :
27 : typedef Support::FastUInt8 FastUInt8;
28 :
29 : // x86::Assembler - Constants
30 : // ==========================
31 :
32 : //! X86 bytes used to encode important prefixes.
33 : enum X86Byte : uint32_t {
34 : //! 1-byte REX prefix mask.
35 : kX86ByteRex = 0x40,
36 :
37 : //! 1-byte REX.W component.
38 : kX86ByteRexW = 0x08,
39 :
40 : kX86ByteInvalidRex = 0x80,
41 :
42 : //! 2-byte VEX prefix:
43 : //! - `[0]` - `0xC5`.
44 : //! - `[1]` - `RvvvvLpp`.
45 : kX86ByteVex2 = 0xC5,
46 :
47 : //! 3-byte VEX prefix:
48 : //! - `[0]` - `0xC4`.
49 : //! - `[1]` - `RXBmmmmm`.
50 : //! - `[2]` - `WvvvvLpp`.
51 : kX86ByteVex3 = 0xC4,
52 :
53 : //! 3-byte XOP prefix:
54 : //! - `[0]` - `0x8F`.
55 : //! - `[1]` - `RXBmmmmm`.
56 : //! - `[2]` - `WvvvvLpp`.
57 : kX86ByteXop3 = 0x8F,
58 :
59 : //! 4-byte EVEX prefix:
60 : //! - `[0]` - `0x62`.
61 : //! - `[1]` - Payload0 or `P[ 7: 0]` - `[R X B R' 0 m m m]`.
62 : //! - `[2]` - Payload1 or `P[15: 8]` - `[W v v v v 1 p p]`.
63 : //! - `[3]` - Payload2 or `P[23:16]` - `[z L' L b V' a a a]`.
64 : //!
65 : //! Payload:
66 : //! - `P[ 2: 0]` - OPCODE: EVEX.mmmmm, only lowest 3 bits [2:0] used.
67 : //! - `P[ 3]` - ______: Must be 0.
68 : //! - `P[ 4]` - REG-ID: EVEX.R' - 5th bit of 'RRRRR'.
69 : //! - `P[ 5]` - REG-ID: EVEX.B - 4th bit of 'BBBBB'.
70 : //! - `P[ 6]` - REG-ID: EVEX.X - 5th bit of 'BBBBB' or 4th bit of 'XXXX' (with SIB).
71 : //! - `P[ 7]` - REG-ID: EVEX.R - 4th bit of 'RRRRR'.
72 : //! - `P[ 9: 8]` - OPCODE: EVEX.pp.
73 : //! - `P[ 10]` - ______: Must be 1.
74 : //! - `P[14:11]` - REG-ID: 4 bits of 'VVVV'.
75 : //! - `P[ 15]` - OPCODE: EVEX.W.
76 : //! - `P[18:16]` - REG-ID: K register k0...k7 (Merging/Zeroing Vector Ops).
77 : //! - `P[ 19]` - REG-ID: 5th bit of 'VVVVV'.
78 : //! - `P[ 20]` - OPCODE: Broadcast/Rounding Control/SAE bit.
79 : //! - `P[22.21]` - OPCODE: Vector Length (L' and L) / Rounding Control.
80 : //! - `P[ 23]` - OPCODE: Zeroing/Merging.
81 : kX86ByteEvex = 0x62
82 : };
83 :
84 : // AsmJit specific (used to encode VVVVV field in XOP/VEX/EVEX).
85 : enum VexVVVVV : uint32_t {
86 : kVexVVVVVShift = 7,
87 : kVexVVVVVMask = 0x1F << kVexVVVVVShift
88 : };
89 :
90 : //! Instruction 2-byte/3-byte opcode prefix definition.
91 : struct X86OpcodeMM {
92 : uint8_t size;
93 : uint8_t data[3];
94 : };
95 :
96 : //! Mandatory prefixes used to encode legacy [66, F3, F2] or [9B] byte.
97 : static const uint8_t x86OpcodePP[8] = { 0x00, 0x66, 0xF3, 0xF2, 0x00, 0x00, 0x00, 0x9B };
98 :
99 : //! Instruction 2-byte/3-byte opcode prefix data.
100 : static const X86OpcodeMM x86OpcodeMM[] = {
101 : { 0, { 0x00, 0x00, 0 } }, // #00 (0b0000).
102 : { 1, { 0x0F, 0x00, 0 } }, // #01 (0b0001).
103 : { 2, { 0x0F, 0x38, 0 } }, // #02 (0b0010).
104 : { 2, { 0x0F, 0x3A, 0 } }, // #03 (0b0011).
105 : { 2, { 0x0F, 0x01, 0 } }, // #04 (0b0100).
106 : { 0, { 0x00, 0x00, 0 } }, // #05 (0b0101).
107 : { 0, { 0x00, 0x00, 0 } }, // #06 (0b0110).
108 : { 0, { 0x00, 0x00, 0 } }, // #07 (0b0111).
109 : { 0, { 0x00, 0x00, 0 } }, // #08 (0b1000).
110 : { 0, { 0x00, 0x00, 0 } }, // #09 (0b1001).
111 : { 0, { 0x00, 0x00, 0 } }, // #0A (0b1010).
112 : { 0, { 0x00, 0x00, 0 } }, // #0B (0b1011).
113 : { 0, { 0x00, 0x00, 0 } }, // #0C (0b1100).
114 : { 0, { 0x00, 0x00, 0 } }, // #0D (0b1101).
115 : { 0, { 0x00, 0x00, 0 } }, // #0E (0b1110).
116 : { 0, { 0x00, 0x00, 0 } } // #0F (0b1111).
117 : };
118 :
119 : static const uint8_t x86SegmentPrefix[8] = {
120 : 0x00, // None.
121 : 0x26, // ES.
122 : 0x2E, // CS.
123 : 0x36, // SS.
124 : 0x3E, // DS.
125 : 0x64, // FS.
126 : 0x65 // GS.
127 : };
128 :
129 : static const uint32_t x86OpcodePushSReg[8] = {
130 : Opcode::k000000 | 0x00, // None.
131 : Opcode::k000000 | 0x06, // Push ES.
132 : Opcode::k000000 | 0x0E, // Push CS.
133 : Opcode::k000000 | 0x16, // Push SS.
134 : Opcode::k000000 | 0x1E, // Push DS.
135 : Opcode::k000F00 | 0xA0, // Push FS.
136 : Opcode::k000F00 | 0xA8 // Push GS.
137 : };
138 :
139 : static const uint32_t x86OpcodePopSReg[8] = {
140 : Opcode::k000000 | 0x00, // None.
141 : Opcode::k000000 | 0x07, // Pop ES.
142 : Opcode::k000000 | 0x00, // Pop CS.
143 : Opcode::k000000 | 0x17, // Pop SS.
144 : Opcode::k000000 | 0x1F, // Pop DS.
145 : Opcode::k000F00 | 0xA1, // Pop FS.
146 : Opcode::k000F00 | 0xA9 // Pop GS.
147 : };
148 :
149 : // x86::Assembler - X86MemInfo | X86VEXPrefix | X86LLByRegType | X86CDisp8Table
150 : // ============================================================================
151 :
152 : //! Memory operand's info bits.
153 : //!
154 : //! A lookup table that contains various information based on the BASE and INDEX information of a memory operand. This
155 : //! is much better and safer than playing with IFs in the code and can check for errors must faster and better.
156 : enum X86MemInfo_Enum {
157 : kX86MemInfo_0 = 0x00,
158 :
159 : kX86MemInfo_BaseGp = 0x01, //!< Has BASE reg, REX.B can be 1, compatible with REX.B byte.
160 : kX86MemInfo_Index = 0x02, //!< Has INDEX reg, REX.X can be 1, compatible with REX.X byte.
161 :
162 : kX86MemInfo_BaseLabel = 0x10, //!< Base is Label.
163 : kX86MemInfo_BaseRip = 0x20, //!< Base is RIP.
164 :
165 : kX86MemInfo_67H_X86 = 0x40, //!< Address-size override in 32-bit mode.
166 : kX86MemInfo_67H_X64 = 0x80, //!< Address-size override in 64-bit mode.
167 : kX86MemInfo_67H_Mask = 0xC0 //!< Contains all address-size override bits.
168 : };
169 :
170 : template<uint32_t X>
171 : struct X86MemInfo_T {
172 : enum : uint32_t {
173 : B = (X ) & 0x1F,
174 : I = (X >> 5) & 0x1F,
175 :
176 : kBase = (B >= uint32_t(RegType::kX86_Gpw) && B <= uint32_t(RegType::kX86_Gpq)) ? kX86MemInfo_BaseGp :
177 : (B == uint32_t(RegType::kX86_Rip) ) ? kX86MemInfo_BaseRip :
178 : (B == uint32_t(RegType::kLabelTag) ) ? kX86MemInfo_BaseLabel : 0,
179 :
180 : kIndex = (I >= uint32_t(RegType::kX86_Gpw) && I <= uint32_t(RegType::kX86_Gpq)) ? kX86MemInfo_Index :
181 : (I >= uint32_t(RegType::kX86_Xmm) && I <= uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_Index : 0,
182 :
183 : k67H = (B == uint32_t(RegType::kX86_Gpw) && I == uint32_t(RegType::kNone) ) ? kX86MemInfo_67H_X86 :
184 : (B == uint32_t(RegType::kX86_Gpd) && I == uint32_t(RegType::kNone) ) ? kX86MemInfo_67H_X64 :
185 : (B == uint32_t(RegType::kNone) && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86 :
186 : (B == uint32_t(RegType::kNone) && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64 :
187 : (B == uint32_t(RegType::kX86_Gpw) && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86 :
188 : (B == uint32_t(RegType::kX86_Gpd) && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64 :
189 : (B == uint32_t(RegType::kX86_Gpw) && I == uint32_t(RegType::kX86_Xmm)) ? kX86MemInfo_67H_X86 :
190 : (B == uint32_t(RegType::kX86_Gpd) && I == uint32_t(RegType::kX86_Xmm)) ? kX86MemInfo_67H_X64 :
191 : (B == uint32_t(RegType::kX86_Gpw) && I == uint32_t(RegType::kX86_Ymm)) ? kX86MemInfo_67H_X86 :
192 : (B == uint32_t(RegType::kX86_Gpd) && I == uint32_t(RegType::kX86_Ymm)) ? kX86MemInfo_67H_X64 :
193 : (B == uint32_t(RegType::kX86_Gpw) && I == uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_67H_X86 :
194 : (B == uint32_t(RegType::kX86_Gpd) && I == uint32_t(RegType::kX86_Zmm)) ? kX86MemInfo_67H_X64 :
195 : (B == uint32_t(RegType::kLabelTag) && I == uint32_t(RegType::kX86_Gpw)) ? kX86MemInfo_67H_X86 :
196 : (B == uint32_t(RegType::kLabelTag) && I == uint32_t(RegType::kX86_Gpd)) ? kX86MemInfo_67H_X64 : 0,
197 :
198 : kValue = kBase | kIndex | k67H | 0x04 | 0x08
199 : };
200 : };
201 :
202 : // The result stored in the LUT is a combination of
203 : // - 67H - Address override prefix - depends on BASE+INDEX register types and the target architecture.
204 : // - REX - A possible combination of REX.[B|X|R|W] bits in REX prefix where REX.B and REX.X are possibly
205 : // masked out, but REX.R and REX.W are kept as is.
206 : #define VALUE(x) X86MemInfo_T<x>::kValue
207 : static const uint8_t x86MemInfo[] = { ASMJIT_LOOKUP_TABLE_1024(VALUE, 0) };
208 : #undef VALUE
209 :
210 : // VEX3 or XOP xor bits applied to the opcode before emitted. The index to this table is 'mmmmm' value, which
211 : // contains all we need. This is only used by a 3 BYTE VEX and XOP prefixes, 2 BYTE VEX prefix is handled differently.
212 : // The idea is to minimize the difference between VEX3 vs XOP when encoding VEX or XOP instruction. This should
213 : // minimize the code required to emit such instructions and should also make it faster as we don't need any branch to
214 : // decide between VEX3 vs XOP.
215 : // ____ ___
216 : // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP]
217 : #define VALUE(x) ((x & 0x08) ? kX86ByteXop3 : kX86ByteVex3) | (0xF << 19) | (0x7 << 13)
218 : static const uint32_t x86VEXPrefix[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
219 : #undef VALUE
220 :
221 : // Table that contains LL opcode field addressed by a register size / 16. It's used to propagate L.256 or L.512 when
222 : // YMM or ZMM registers are used, respectively.
223 : #define VALUE(x) (x & (64 >> 4)) ? Opcode::kLL_2 : \
224 : (x & (32 >> 4)) ? Opcode::kLL_1 : Opcode::kLL_0
225 : static const uint32_t x86LLBySizeDiv16[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
226 : #undef VALUE
227 :
228 : // Table that contains LL opcode field addressed by a register size / 16. It's used to propagate L.256 or L.512 when
229 : // YMM or ZMM registers are used, respectively.
230 : #define VALUE(x) x == uint32_t(RegType::kX86_Zmm) ? Opcode::kLL_2 : \
231 : x == uint32_t(RegType::kX86_Ymm) ? Opcode::kLL_1 : Opcode::kLL_0
232 : static const uint32_t x86LLByRegType[] = { ASMJIT_LOOKUP_TABLE_16(VALUE, 0) };
233 : #undef VALUE
234 :
235 : // Table that contains a scale (shift left) based on 'TTWLL' field and the instruction's tuple-type (TT) field. The
236 : // scale is then applied to the BASE-N stored in each opcode to calculate the final compressed displacement used by
237 : // all EVEX encoded instructions.
238 : template<uint32_t X>
239 : struct X86CDisp8SHL_T {
240 : enum {
241 : TT = (X >> 3) << Opcode::kCDTT_Shift,
242 : LL = (X >> 0) & 0x3,
243 : W = (X >> 2) & 0x1,
244 :
245 : kValue = (TT == Opcode::kCDTT_None ? ((LL==0) ? 0 : (LL==1) ? 0 : 0 ) :
246 : TT == Opcode::kCDTT_ByLL ? ((LL==0) ? 0 : (LL==1) ? 1 : 2 ) :
247 : TT == Opcode::kCDTT_T1W ? ((LL==0) ? W : (LL==1) ? 1+W : 2+W) :
248 : TT == Opcode::kCDTT_DUP ? ((LL==0) ? 0 : (LL==1) ? 2 : 3 ) : 0) << Opcode::kCDSHL_Shift
249 : };
250 : };
251 :
252 : #define VALUE(x) X86CDisp8SHL_T<x>::kValue
253 : static const uint32_t x86CDisp8SHL[] = { ASMJIT_LOOKUP_TABLE_32(VALUE, 0) };
254 : #undef VALUE
255 :
256 : // Table that contains MOD byte of a 16-bit [BASE + disp] address.
257 : // 0xFF == Invalid.
258 : static const uint8_t x86Mod16BaseTable[8] = {
259 : 0xFF, // AX -> N/A.
260 : 0xFF, // CX -> N/A.
261 : 0xFF, // DX -> N/A.
262 : 0x07, // BX -> 111.
263 : 0xFF, // SP -> N/A.
264 : 0x06, // BP -> 110.
265 : 0x04, // SI -> 100.
266 : 0x05 // DI -> 101.
267 : };
268 :
269 : // Table that contains MOD byte of a 16-bit [BASE + INDEX + disp] combination.
270 : // 0xFF == Invalid.
271 : template<uint32_t X>
272 : struct X86Mod16BaseIndexTable_T {
273 : enum {
274 : B = X >> 3,
275 : I = X & 0x7,
276 :
277 : kValue = ((B == Gp::kIdBx && I == Gp::kIdSi) || (B == Gp::kIdSi && I == Gp::kIdBx)) ? 0x00 :
278 : ((B == Gp::kIdBx && I == Gp::kIdDi) || (B == Gp::kIdDi && I == Gp::kIdBx)) ? 0x01 :
279 : ((B == Gp::kIdBp && I == Gp::kIdSi) || (B == Gp::kIdSi && I == Gp::kIdBp)) ? 0x02 :
280 : ((B == Gp::kIdBp && I == Gp::kIdDi) || (B == Gp::kIdDi && I == Gp::kIdBp)) ? 0x03 : 0xFF
281 : };
282 : };
283 :
284 : #define VALUE(x) X86Mod16BaseIndexTable_T<x>::kValue
285 : static const uint8_t x86Mod16BaseIndexTable[] = { ASMJIT_LOOKUP_TABLE_64(VALUE, 0) };
286 : #undef VALUE
287 :
288 : // x86::Assembler - Helpers
289 : // ========================
290 :
291 : static ASMJIT_FORCE_INLINE bool x86IsJmpOrCall(InstId instId) noexcept {
292 0 : return instId == Inst::kIdJmp || instId == Inst::kIdCall;
293 : }
294 :
295 : static ASMJIT_FORCE_INLINE bool x86IsImplicitMem(const Operand_& op, uint32_t base) noexcept {
296 0 : return op.isMem() && op.as<Mem>().baseId() == base && !op.as<Mem>().hasOffset();
297 : }
298 :
299 : //! Combine `regId` and `vvvvvId` into a single value (used by AVX and AVX-512).
300 : static ASMJIT_FORCE_INLINE uint32_t x86PackRegAndVvvvv(uint32_t regId, uint32_t vvvvvId) noexcept {
301 0 : return regId + (vvvvvId << kVexVVVVVShift);
302 : }
303 :
304 : static ASMJIT_FORCE_INLINE uint32_t x86OpcodeLByVMem(const Operand_& op) noexcept {
305 0 : return x86LLByRegType[size_t(op.as<Mem>().indexType())];
306 : }
307 :
308 : static ASMJIT_FORCE_INLINE uint32_t x86OpcodeLBySize(uint32_t size) noexcept {
309 8481 : return x86LLBySizeDiv16[size / 16];
310 : }
311 :
312 : //! Encode MOD byte.
313 : static ASMJIT_FORCE_INLINE uint32_t x86EncodeMod(uint32_t m, uint32_t o, uint32_t rm) noexcept {
314 : ASMJIT_ASSERT(m <= 3);
315 : ASMJIT_ASSERT(o <= 7);
316 : ASMJIT_ASSERT(rm <= 7);
317 142105 : return (m << 6) + (o << 3) + rm;
318 : }
319 :
320 : //! Encode SIB byte.
321 : static ASMJIT_FORCE_INLINE uint32_t x86EncodeSib(uint32_t s, uint32_t i, uint32_t b) noexcept {
322 : ASMJIT_ASSERT(s <= 3);
323 : ASMJIT_ASSERT(i <= 7);
324 : ASMJIT_ASSERT(b <= 7);
325 71131 : return (s << 6) + (i << 3) + b;
326 : }
327 :
328 : static ASMJIT_FORCE_INLINE bool x86IsRexInvalid(uint32_t rex) noexcept {
329 : // Validates the following possibilities:
330 : // REX == 0x00 -> OKAY (X86_32 / X86_64).
331 : // REX == 0x40-0x4F -> OKAY (X86_64).
332 : // REX == 0x80 -> OKAY (X86_32 mode, rex prefix not used).
333 : // REX == 0x81-0xCF -> BAD (X86_32 mode, rex prefix used).
334 135367 : return rex > kX86ByteInvalidRex;
335 : }
336 :
337 : static ASMJIT_FORCE_INLINE uint32_t x86GetForceEvex3MaskInLastBit(InstOptions options) noexcept {
338 : constexpr uint32_t kVex3Bit = Support::ConstCTZ<uint32_t(InstOptions::kX86_Vex3)>::value;
339 256642 : return uint32_t(options & InstOptions::kX86_Vex3) << (31 - kVex3Bit);
340 : }
341 :
342 : template<typename T>
343 0 : static ASMJIT_FORCE_INLINE constexpr T x86SignExtendI32(T imm) noexcept { return T(int64_t(int32_t(imm & T(0xFFFFFFFF)))); }
344 :
345 : static ASMJIT_FORCE_INLINE uint32_t x86AltOpcodeOf(const InstDB::InstInfo* info) noexcept {
346 30882 : return InstDB::_altOpcodeTable[info->_altOpcodeIndex];
347 : }
348 :
349 : // x86::Assembler - X86BufferWriter
350 : // ================================
351 :
352 : class X86BufferWriter : public CodeWriter {
353 : public:
354 : ASMJIT_FORCE_INLINE explicit X86BufferWriter(Assembler* a) noexcept
355 : : CodeWriter(a) {}
356 :
357 : ASMJIT_FORCE_INLINE void emitPP(uint32_t opcode) noexcept {
358 135367 : uint32_t ppIndex = (opcode >> Opcode::kPP_Shift) &
359 : (Opcode::kPP_FPUMask >> Opcode::kPP_Shift) ;
360 0 : emit8If(x86OpcodePP[ppIndex], ppIndex != 0);
361 : }
362 :
363 : ASMJIT_FORCE_INLINE void emitMMAndOpcode(uint32_t opcode) noexcept {
364 135367 : uint32_t mmIndex = (opcode & Opcode::kMM_Mask) >> Opcode::kMM_Shift;
365 : const X86OpcodeMM& mmCode = x86OpcodeMM[mmIndex];
366 :
367 135367 : emit8If(mmCode.data[0], mmCode.size > 0);
368 115728 : emit8If(mmCode.data[1], mmCode.size > 1);
369 : emit8(opcode);
370 20 : }
371 :
372 : ASMJIT_FORCE_INLINE void emitSegmentOverride(uint32_t segmentId) noexcept {
373 : ASMJIT_ASSERT(segmentId < ASMJIT_ARRAY_SIZE(x86SegmentPrefix));
374 :
375 142105 : FastUInt8 prefix = x86SegmentPrefix[segmentId];
376 0 : emit8If(prefix, prefix != 0);
377 0 : }
378 :
379 : template<typename CondT>
380 : ASMJIT_FORCE_INLINE void emitAddressOverride(CondT condition) noexcept {
381 : emit8If(0x67, condition);
382 : }
383 :
384 : ASMJIT_FORCE_INLINE void emitImmByteOrDWord(uint64_t immValue, FastUInt8 immSize) noexcept {
385 114557 : if (!immSize)
386 : return;
387 :
388 : ASMJIT_ASSERT(immSize == 1 || immSize == 4);
389 :
390 : #if ASMJIT_ARCH_BITS >= 64
391 : uint64_t imm = uint64_t(immValue);
392 : #else
393 : uint32_t imm = uint32_t(immValue & 0xFFFFFFFFu);
394 : #endif
395 :
396 : // Many instructions just use a single byte immediate, so make it fast.
397 : emit8(imm & 0xFFu);
398 1724 : if (immSize == 1) return;
399 :
400 0 : imm >>= 8;
401 : emit8(imm & 0xFFu);
402 0 : imm >>= 8;
403 : emit8(imm & 0xFFu);
404 0 : imm >>= 8;
405 : emit8(imm & 0xFFu);
406 : }
407 :
408 : ASMJIT_FORCE_INLINE void emitImmediate(uint64_t immValue, FastUInt8 immSize) noexcept {
409 : #if ASMJIT_ARCH_BITS >= 64
410 : uint64_t imm = immValue;
411 277452 : if (immSize >= 4) {
412 : emit32uLE(imm & 0xFFFFFFFFu);
413 756 : imm >>= 32;
414 88236 : immSize = FastUInt8(immSize - 4u);
415 : }
416 : #else
417 : uint32_t imm = uint32_t(immValue & 0xFFFFFFFFu);
418 : if (immSize >= 4) {
419 : emit32uLE(imm);
420 : imm = uint32_t(immValue >> 32);
421 : immSize = FastUInt8(immSize - 4u);
422 : }
423 : #endif
424 :
425 277452 : if (!immSize)
426 : return;
427 : emit8(imm & 0xFFu);
428 97869 : imm >>= 8;
429 :
430 97869 : if (--immSize == 0)
431 : return;
432 : emit8(imm & 0xFFu);
433 88236 : imm >>= 8;
434 :
435 88236 : if (--immSize == 0)
436 : return;
437 : emit8(imm & 0xFFu);
438 88236 : imm >>= 8;
439 :
440 88236 : if (--immSize == 0)
441 : return;
442 : emit8(imm & 0xFFu);
443 : }
444 : };
445 :
446 : // If the operand is BPL|SPL|SIL|DIL|R8B-15B
447 : // - Force REX prefix
448 : // If the operand is AH|BH|CH|DH
449 : // - patch its index from 0..3 to 4..7 as encoded by X86.
450 : // - Disallow REX prefix.
451 : #define FIXUP_GPB(REG_OP, REG_ID) \
452 : do { \
453 : if (!static_cast<const Gp&>(REG_OP).isGpbHi()) { \
454 : options |= (REG_ID) >= 4 ? InstOptions::kX86_Rex \
455 : : InstOptions::kNone; \
456 : } \
457 : else { \
458 : options |= InstOptions::kX86_InvalidRex; \
459 : REG_ID += 4; \
460 : } \
461 : } while (0)
462 :
463 : #define ENC_OPS1(OP0) \
464 : (uint32_t(OperandType::k##OP0))
465 :
466 : #define ENC_OPS2(OP0, OP1) \
467 : (uint32_t(OperandType::k##OP0) + \
468 : (uint32_t(OperandType::k##OP1) << 3))
469 :
470 : #define ENC_OPS3(OP0, OP1, OP2) \
471 : (uint32_t(OperandType::k##OP0) + \
472 : (uint32_t(OperandType::k##OP1) << 3) + \
473 : (uint32_t(OperandType::k##OP2) << 6))
474 :
475 : #define ENC_OPS4(OP0, OP1, OP2, OP3) \
476 : (uint32_t(OperandType::k##OP0) + \
477 : (uint32_t(OperandType::k##OP1) << 3) + \
478 : (uint32_t(OperandType::k##OP2) << 6) + \
479 : (uint32_t(OperandType::k##OP3) << 9))
480 :
481 : // x86::Assembler - Movabs Heuristics
482 : // ==================================
483 :
484 : static ASMJIT_FORCE_INLINE uint32_t x86GetMovAbsInstSize64Bit(uint32_t regSize, InstOptions options, const Mem& rmRel) noexcept {
485 : uint32_t segmentPrefixSize = rmRel.segmentId() != 0;
486 0 : uint32_t _66hPrefixSize = regSize == 2;
487 0 : uint32_t rexPrefixSize = regSize == 8 || Support::test(options, InstOptions::kX86_Rex);
488 : uint32_t opCodeByteSize = 1;
489 : uint32_t immediateSize = 8;
490 :
491 0 : return segmentPrefixSize + _66hPrefixSize + rexPrefixSize + opCodeByteSize + immediateSize;
492 : }
493 :
494 : static ASMJIT_FORCE_INLINE bool x86ShouldUseMovabs(Assembler* self, X86BufferWriter& writer, uint32_t regSize, InstOptions options, const Mem& rmRel) noexcept {
495 0 : if (self->is32Bit()) {
496 : // There is no relative addressing, just decide whether to use MOV encoded with MOD R/M or absolute.
497 0 : return !Support::test(options, InstOptions::kX86_ModMR | InstOptions::kX86_ModMR);
498 : }
499 : else {
500 : // If the addressing type is REL or MOD R/M was specified then absolute mov won't be used.
501 0 : if (rmRel.addrType() == Mem::AddrType::kRel || Support::test(options, InstOptions::kX86_ModMR))
502 : return false;
503 :
504 : int64_t addrValue = rmRel.offset();
505 : uint64_t baseAddress = self->code()->baseAddress();
506 :
507 : // If the address type is default, it means to basically check whether relative addressing is possible. However,
508 : // this is only possible when the base address is known - relative encoding uses RIP+N it has to be calculated.
509 0 : if (rmRel.addrType() == Mem::AddrType::kDefault && baseAddress != Globals::kNoBaseAddress && !rmRel.hasSegment()) {
510 : uint32_t instructionSize = x86GetMovAbsInstSize64Bit(regSize, options, rmRel);
511 0 : uint64_t virtualOffset = uint64_t(writer.offsetFrom(self->_bufferData));
512 0 : uint64_t rip64 = baseAddress + self->_section->offset() + virtualOffset + instructionSize;
513 0 : uint64_t rel64 = uint64_t(addrValue) - rip64;
514 :
515 0 : if (Support::isInt32(int64_t(rel64)))
516 : return false;
517 : }
518 : else {
519 : if (Support::isInt32(addrValue))
520 : return false;
521 : }
522 :
523 0 : return uint64_t(addrValue) > 0xFFFFFFFFu;
524 : }
525 : }
526 :
527 : // x86::Assembler - Construction & Destruction
528 : // ===========================================
529 :
530 27492 : Assembler::Assembler(CodeHolder* code) noexcept : BaseAssembler() {
531 27492 : _archMask = (uint64_t(1) << uint32_t(Arch::kX86)) |
532 : (uint64_t(1) << uint32_t(Arch::kX64)) ;
533 27492 : assignEmitterFuncs(this);
534 :
535 27492 : if (code)
536 27492 : code->attach(this);
537 27492 : }
538 27492 : Assembler::~Assembler() noexcept {}
539 :
540 : // x86::Assembler - Emit (Low-Level)
541 : // =================================
542 :
543 392009 : ASMJIT_FAVOR_SPEED Error Assembler::_emit(InstId instId, const Operand_& o0, const Operand_& o1, const Operand_& o2, const Operand_* opExt) {
544 : constexpr uint32_t kVSHR_W = Opcode::kW_Shift - 23;
545 : constexpr uint32_t kVSHR_PP = Opcode::kPP_Shift - 16;
546 : constexpr uint32_t kVSHR_PP_EW = Opcode::kPP_Shift - 16;
547 :
548 : constexpr InstOptions kRequiresSpecialHandling =
549 : InstOptions::kReserved | // Logging/Validation/Error.
550 : InstOptions::kX86_Rep | // REP/REPE prefix.
551 : InstOptions::kX86_Repne | // REPNE prefix.
552 : InstOptions::kX86_Lock | // LOCK prefix.
553 : InstOptions::kX86_XAcquire | // XACQUIRE prefix.
554 : InstOptions::kX86_XRelease ; // XRELEASE prefix.
555 :
556 : Error err;
557 :
558 : Opcode opcode; // Instruction opcode.
559 : InstOptions options; // Instruction options.
560 : uint32_t isign3; // A combined signature of first 3 operands.
561 :
562 : const Operand_* rmRel; // Memory operand or operand that holds Label|Imm.
563 : uint32_t rmInfo; // Memory operand's info based on x86MemInfo.
564 : uint32_t rbReg; // Memory base or modRM register.
565 : uint32_t rxReg; // Memory index register.
566 : uint32_t opReg; // ModR/M opcode or register id.
567 :
568 : LabelEntry* label; // Label entry.
569 392009 : RelocEntry* re = nullptr; // Relocation entry.
570 : int32_t relOffset; // Relative offset
571 : FastUInt8 relSize = 0; // Relative size.
572 : uint8_t* memOpAOMark = nullptr; // Marker that points before 'address-override prefix' is emitted.
573 :
574 : int64_t immValue = 0; // Immediate value (must be 64-bit).
575 : FastUInt8 immSize = 0; // Immediate size.
576 :
577 : X86BufferWriter writer(this);
578 :
579 392009 : if (instId >= Inst::_kIdCount)
580 : instId = 0;
581 :
582 : const InstDB::InstInfo* instInfo = &InstDB::_instInfoTable[instId];
583 : const InstDB::CommonInfo* commonInfo = &instInfo->commonInfo();
584 :
585 : // Signature of the first 3 operands.
586 392009 : isign3 = (uint32_t(o0.opType()) ) +
587 392009 : (uint32_t(o1.opType()) << 3) +
588 392009 : (uint32_t(o2.opType()) << 6);
589 :
590 : // Combine all instruction options and also check whether the instruction is valid. All options
591 : // that require special handling (including invalid instruction) are handled by the next branch.
592 392009 : options = InstOptions((instId == 0) | ((size_t)(_bufferEnd - writer.cursor()) < 16)) | instOptions() | forcedInstOptions();
593 :
594 : // Handle failure and rare cases first.
595 392009 : if (ASMJIT_UNLIKELY(Support::test(options, kRequiresSpecialHandling))) {
596 27492 : if (ASMJIT_UNLIKELY(!_code))
597 0 : return reportError(DebugUtils::errored(kErrorNotInitialized));
598 :
599 : // Unknown instruction.
600 27492 : if (ASMJIT_UNLIKELY(instId == 0))
601 0 : goto InvalidInstruction;
602 :
603 : // Grow request, happens rarely.
604 : err = writer.ensureSpace(this, 16);
605 27492 : if (ASMJIT_UNLIKELY(err))
606 0 : goto Failed;
607 :
608 : #ifndef ASMJIT_NO_VALIDATION
609 : // Strict validation.
610 27492 : if (hasDiagnosticOption(DiagnosticOptions::kValidateAssembler)) {
611 : Operand_ opArray[Globals::kMaxOpCount];
612 : EmitterUtils::opArrayFromEmitArgs(opArray, o0, o1, o2, opExt);
613 :
614 0 : err = _funcs.validate(arch(), BaseInst(instId, options, _extraReg), opArray, Globals::kMaxOpCount, ValidationFlags::kNone);
615 0 : if (ASMJIT_UNLIKELY(err))
616 0 : goto Failed;
617 : }
618 : #endif
619 :
620 : InstDB::InstFlags iFlags = instInfo->flags();
621 :
622 : // LOCK, XACQUIRE, and XRELEASE prefixes.
623 27492 : if (Support::test(options, InstOptions::kX86_Lock)) {
624 : bool xAcqRel = Support::test(options, InstOptions::kX86_XAcquire | InstOptions::kX86_XRelease);
625 :
626 0 : if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kLock) && !xAcqRel))
627 0 : goto InvalidLockPrefix;
628 :
629 0 : if (xAcqRel) {
630 0 : if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XAcquire) && !Support::test(iFlags, InstDB::InstFlags::kXAcquire)))
631 0 : goto InvalidXAcquirePrefix;
632 :
633 0 : if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_XRelease) && !Support::test(iFlags, InstDB::InstFlags::kXRelease)))
634 0 : goto InvalidXReleasePrefix;
635 :
636 0 : writer.emit8(Support::test(options, InstOptions::kX86_XAcquire) ? 0xF2 : 0xF3);
637 : }
638 :
639 : writer.emit8(0xF0);
640 : }
641 :
642 : // REP and REPNE prefixes.
643 27492 : if (Support::test(options, InstOptions::kX86_Rep | InstOptions::kX86_Repne)) {
644 0 : if (ASMJIT_UNLIKELY(!Support::test(iFlags, InstDB::InstFlags::kRep)))
645 0 : goto InvalidRepPrefix;
646 :
647 0 : if (ASMJIT_UNLIKELY(_extraReg.isReg() && (_extraReg.group() != RegGroup::kGp || _extraReg.id() != Gp::kIdCx)))
648 0 : goto InvalidRepPrefix;
649 :
650 0 : writer.emit8(Support::test(options, InstOptions::kX86_Repne) ? 0xF2 : 0xF3);
651 : }
652 : }
653 :
654 : // This sequence seems to be the fastest.
655 392009 : opcode = InstDB::_mainOpcodeTable[instInfo->_mainOpcodeIndex];
656 : opReg = opcode.extractModO();
657 : rbReg = 0;
658 392009 : opcode |= instInfo->_mainOpcodeValue;
659 :
660 : // Encoding Scope
661 : // --------------
662 :
663 : // How it works? Each case here represents a unique encoding of a group of instructions, which is handled
664 : // separately. The handlers check instruction signature, possibly register types, etc, and process this
665 : // information by writing some bits to opcode, opReg/rbReg, immValue/immSize, etc, and then at the end of
666 : // the sequence it uses goto to jump into a lower level handler, that actually encodes the instruction.
667 :
668 392009 : switch (instInfo->_encoding) {
669 0 : case InstDB::kEncodingNone:
670 0 : goto EmitDone;
671 :
672 : // Base Instructions
673 : // -----------------
674 :
675 0 : case InstDB::kEncodingX86Op:
676 0 : goto EmitX86Op;
677 :
678 : case InstDB::kEncodingX86Op_Mod11RM:
679 : rbReg = opcode.extractModRM();
680 0 : goto EmitX86R;
681 :
682 : case InstDB::kEncodingX86Op_Mod11RM_I8:
683 : // The first operand must be immediate, we don't care of other operands as they could be implicit.
684 0 : if (!o0.isImm())
685 0 : goto InvalidInstruction;
686 :
687 : rbReg = opcode.extractModRM();
688 0 : immValue = o0.as<Imm>().valueAs<uint8_t>();
689 : immSize = 1;
690 0 : goto EmitX86R;
691 :
692 : case InstDB::kEncodingX86Op_xAddr:
693 0 : if (ASMJIT_UNLIKELY(!o0.isReg()))
694 0 : goto InvalidInstruction;
695 :
696 0 : rmInfo = x86MemInfo[size_t(o0.as<Reg>().type())];
697 0 : writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
698 0 : goto EmitX86Op;
699 :
700 0 : case InstDB::kEncodingX86Op_xAX:
701 0 : if (isign3 == 0)
702 0 : goto EmitX86Op;
703 :
704 0 : if (isign3 == ENC_OPS1(Reg) && o0.id() == Gp::kIdAx)
705 0 : goto EmitX86Op;
706 : break;
707 :
708 0 : case InstDB::kEncodingX86Op_xDX_xAX:
709 0 : if (isign3 == 0)
710 0 : goto EmitX86Op;
711 :
712 0 : if (isign3 == ENC_OPS2(Reg, Reg) && o0.id() == Gp::kIdDx && o1.id() == Gp::kIdAx)
713 0 : goto EmitX86Op;
714 : break;
715 :
716 0 : case InstDB::kEncodingX86Op_MemZAX:
717 0 : if (isign3 == 0)
718 0 : goto EmitX86Op;
719 :
720 : rmRel = &o0;
721 0 : if (isign3 == ENC_OPS1(Mem) && x86IsImplicitMem(o0, Gp::kIdAx))
722 0 : goto EmitX86OpImplicitMem;
723 :
724 : break;
725 :
726 0 : case InstDB::kEncodingX86I_xAX:
727 : // Implicit form.
728 0 : if (isign3 == ENC_OPS1(Imm)) {
729 0 : immValue = o0.as<Imm>().valueAs<uint8_t>();
730 : immSize = 1;
731 0 : goto EmitX86Op;
732 : }
733 :
734 : // Explicit form.
735 0 : if (isign3 == ENC_OPS2(Reg, Imm) && o0.id() == Gp::kIdAx) {
736 0 : immValue = o1.as<Imm>().valueAs<uint8_t>();
737 : immSize = 1;
738 0 : goto EmitX86Op;
739 : }
740 : break;
741 :
742 : case InstDB::kEncodingX86M_NoMemSize:
743 0 : if (o0.isReg())
744 : opcode.addPrefixBySize(o0.size());
745 0 : goto CaseX86M_NoSize;
746 :
747 : case InstDB::kEncodingX86M:
748 : opcode.addPrefixBySize(o0.size());
749 : ASMJIT_FALLTHROUGH;
750 :
751 : case InstDB::kEncodingX86M_NoSize:
752 0 : CaseX86M_NoSize:
753 : rbReg = o0.id();
754 0 : if (isign3 == ENC_OPS1(Reg))
755 0 : goto EmitX86R;
756 :
757 : rmRel = &o0;
758 0 : if (isign3 == ENC_OPS1(Mem))
759 0 : goto EmitX86M;
760 : break;
761 :
762 : case InstDB::kEncodingX86M_GPB_MulDiv:
763 0 : CaseX86M_GPB_MulDiv:
764 : // Explicit form?
765 0 : if (isign3 > 0x7) {
766 : // [AX] <- [AX] div|mul r8.
767 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
768 0 : if (ASMJIT_UNLIKELY(!Reg::isGpw(o0, Gp::kIdAx) || !Reg::isGpb(o1)))
769 0 : goto InvalidInstruction;
770 :
771 : rbReg = o1.id();
772 0 : FIXUP_GPB(o1, rbReg);
773 0 : goto EmitX86R;
774 : }
775 :
776 : // [AX] <- [AX] div|mul m8.
777 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
778 0 : if (ASMJIT_UNLIKELY(!Reg::isGpw(o0, Gp::kIdAx)))
779 0 : goto InvalidInstruction;
780 :
781 : rmRel = &o1;
782 0 : goto EmitX86M;
783 : }
784 :
785 : // [?DX:?AX] <- [?DX:?AX] div|mul r16|r32|r64
786 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
787 0 : if (ASMJIT_UNLIKELY(o0.size() != o1.size()))
788 0 : goto InvalidInstruction;
789 :
790 : opcode.addArithBySize(o0.size());
791 : rbReg = o2.id();
792 0 : goto EmitX86R;
793 : }
794 :
795 : // [?DX:?AX] <- [?DX:?AX] div|mul m16|m32|m64
796 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
797 0 : if (ASMJIT_UNLIKELY(o0.size() != o1.size()))
798 0 : goto InvalidInstruction;
799 :
800 : opcode.addArithBySize(o0.size());
801 : rmRel = &o2;
802 0 : goto EmitX86M;
803 : }
804 :
805 0 : goto InvalidInstruction;
806 : }
807 :
808 : ASMJIT_FALLTHROUGH;
809 :
810 : case InstDB::kEncodingX86M_GPB:
811 0 : if (isign3 == ENC_OPS1(Reg)) {
812 : opcode.addArithBySize(o0.size());
813 : rbReg = o0.id();
814 :
815 0 : if (o0.size() != 1)
816 0 : goto EmitX86R;
817 :
818 0 : FIXUP_GPB(o0, rbReg);
819 0 : goto EmitX86R;
820 : }
821 :
822 0 : if (isign3 == ENC_OPS1(Mem)) {
823 0 : if (ASMJIT_UNLIKELY(o0.size() == 0))
824 0 : goto AmbiguousOperandSize;
825 :
826 : opcode.addArithBySize(o0.size());
827 : rmRel = &o0;
828 0 : goto EmitX86M;
829 : }
830 : break;
831 :
832 0 : case InstDB::kEncodingX86M_Only_EDX_EAX:
833 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg) && Reg::isGpd(o1, Gp::kIdDx) && Reg::isGpd(o2, Gp::kIdAx)) {
834 : rmRel = &o0;
835 0 : goto EmitX86M;
836 : }
837 : ASMJIT_FALLTHROUGH;
838 :
839 : case InstDB::kEncodingX86M_Only:
840 0 : if (isign3 == ENC_OPS1(Mem)) {
841 : rmRel = &o0;
842 0 : goto EmitX86M;
843 : }
844 : break;
845 :
846 0 : case InstDB::kEncodingX86M_Nop:
847 0 : if (isign3 == ENC_OPS1(None))
848 0 : goto EmitX86Op;
849 :
850 : // Single operand NOP instruction "0F 1F /0".
851 : opcode = Opcode::k000F00 | 0x1F;
852 : opReg = 0;
853 :
854 0 : if (isign3 == ENC_OPS1(Reg)) {
855 : opcode.addPrefixBySize(o0.size());
856 : rbReg = o0.id();
857 0 : goto EmitX86R;
858 : }
859 :
860 0 : if (isign3 == ENC_OPS1(Mem)) {
861 : opcode.addPrefixBySize(o0.size());
862 : rmRel = &o0;
863 0 : goto EmitX86M;
864 : }
865 :
866 : // Two operand NOP instruction "0F 1F /r".
867 : opReg = o1.id();
868 : opcode.addPrefixBySize(o1.size());
869 :
870 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
871 : rbReg = o0.id();
872 0 : goto EmitX86R;
873 : }
874 :
875 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
876 : rmRel = &o0;
877 0 : goto EmitX86M;
878 : }
879 : break;
880 :
881 0 : case InstDB::kEncodingX86R_FromM:
882 0 : if (isign3 == ENC_OPS1(Mem)) {
883 : rmRel = &o0;
884 : rbReg = o0.id();
885 0 : goto EmitX86RFromM;
886 : }
887 : break;
888 :
889 0 : case InstDB::kEncodingX86R32_EDX_EAX:
890 : // Explicit form: R32, EDX, EAX.
891 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
892 0 : if (!Reg::isGpd(o1, Gp::kIdDx) || !Reg::isGpd(o2, Gp::kIdAx))
893 0 : goto InvalidInstruction;
894 : rbReg = o0.id();
895 0 : goto EmitX86R;
896 : }
897 :
898 : // Implicit form: R32.
899 0 : if (isign3 == ENC_OPS1(Reg)) {
900 0 : if (!Reg::isGpd(o0))
901 0 : goto InvalidInstruction;
902 : rbReg = o0.id();
903 0 : goto EmitX86R;
904 : }
905 : break;
906 :
907 0 : case InstDB::kEncodingX86R_Native:
908 0 : if (isign3 == ENC_OPS1(Reg)) {
909 : rbReg = o0.id();
910 0 : goto EmitX86R;
911 : }
912 : break;
913 :
914 : case InstDB::kEncodingX86Rm:
915 : opcode.addPrefixBySize(o0.size());
916 : ASMJIT_FALLTHROUGH;
917 :
918 0 : case InstDB::kEncodingX86Rm_NoSize:
919 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
920 : opReg = o0.id();
921 : rbReg = o1.id();
922 0 : goto EmitX86R;
923 : }
924 :
925 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
926 : opReg = o0.id();
927 : rmRel = &o1;
928 0 : goto EmitX86M;
929 : }
930 : break;
931 :
932 0 : case InstDB::kEncodingX86Rm_Raw66H:
933 : // We normally emit either [66|F2|F3], this instruction requires 66+[F2|F3].
934 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
935 : opReg = o0.id();
936 : rbReg = o1.id();
937 :
938 0 : if (o0.size() == 2)
939 : writer.emit8(0x66);
940 : else
941 : opcode.addWBySize(o0.size());
942 0 : goto EmitX86R;
943 : }
944 :
945 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
946 : opReg = o0.id();
947 : rmRel = &o1;
948 :
949 0 : if (o0.size() == 2)
950 : writer.emit8(0x66);
951 : else
952 : opcode.addWBySize(o0.size());
953 0 : goto EmitX86M;
954 : }
955 : break;
956 :
957 : case InstDB::kEncodingX86Mr:
958 : opcode.addPrefixBySize(o0.size());
959 : ASMJIT_FALLTHROUGH;
960 :
961 0 : case InstDB::kEncodingX86Mr_NoSize:
962 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
963 : rbReg = o0.id();
964 : opReg = o1.id();
965 0 : goto EmitX86R;
966 : }
967 :
968 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
969 : rmRel = &o0;
970 : opReg = o1.id();
971 0 : goto EmitX86M;
972 : }
973 : break;
974 :
975 9980 : case InstDB::kEncodingX86Arith:
976 : if (isign3 == ENC_OPS2(Reg, Reg)) {
977 : opcode.addArithBySize(o0.size());
978 :
979 0 : if (o0.size() != o1.size())
980 0 : goto OperandSizeMismatch;
981 :
982 : rbReg = o0.id();
983 : opReg = o1.id();
984 :
985 0 : if (o0.size() == 1) {
986 0 : FIXUP_GPB(o0, rbReg);
987 0 : FIXUP_GPB(o1, opReg);
988 : }
989 :
990 : // MOD/MR: The default encoding used if not instructed otherwise..
991 0 : if (!Support::test(options, InstOptions::kX86_ModRM))
992 0 : goto EmitX86R;
993 :
994 : // MOD/RM: Alternative encoding selected via instruction options.
995 : opcode += 2;
996 : std::swap(opReg, rbReg);
997 0 : goto EmitX86R;
998 : }
999 :
1000 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1001 : opcode += 2;
1002 : opcode.addArithBySize(o0.size());
1003 :
1004 : opReg = o0.id();
1005 : rmRel = &o1;
1006 :
1007 0 : if (o0.size() != 1)
1008 0 : goto EmitX86M;
1009 :
1010 0 : FIXUP_GPB(o0, opReg);
1011 0 : goto EmitX86M;
1012 : }
1013 :
1014 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1015 : opcode.addArithBySize(o1.size());
1016 : opReg = o1.id();
1017 : rmRel = &o0;
1018 :
1019 0 : if (o1.size() != 1)
1020 0 : goto EmitX86M;
1021 :
1022 0 : FIXUP_GPB(o1, opReg);
1023 0 : goto EmitX86M;
1024 : }
1025 :
1026 : // The remaining instructions use 0x80 opcode.
1027 : opcode = 0x80;
1028 :
1029 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1030 : uint32_t size = o0.size();
1031 :
1032 : rbReg = o0.id();
1033 : immValue = o1.as<Imm>().value();
1034 :
1035 9980 : if (size == 1) {
1036 0 : FIXUP_GPB(o0, rbReg);
1037 : immSize = 1;
1038 : }
1039 : else {
1040 9980 : if (size == 2) {
1041 : opcode |= Opcode::kPP_66;
1042 : }
1043 9980 : else if (size == 4) {
1044 : // Sign extend so isInt8 returns the right result.
1045 : immValue = x86SignExtendI32<int64_t>(immValue);
1046 : }
1047 9980 : else if (size == 8) {
1048 9980 : bool canTransformTo32Bit = instId == Inst::kIdAnd && Support::isUInt32(immValue);
1049 :
1050 : if (!Support::isInt32(immValue)) {
1051 : // We would do this by default when `kOptionOptimizedForSize` is
1052 : // enabled, however, in this case we just force this as otherwise
1053 : // we would have to fail.
1054 0 : if (canTransformTo32Bit)
1055 : size = 4;
1056 : else
1057 0 : goto InvalidImmediate;
1058 : }
1059 9980 : else if (canTransformTo32Bit && hasEncodingOption(EncodingOptions::kOptimizeForSize)) {
1060 : size = 4;
1061 : }
1062 :
1063 : opcode.addWBySize(size);
1064 : }
1065 :
1066 9980 : immSize = FastUInt8(Support::min<uint32_t>(size, 4));
1067 9224 : if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
1068 : immSize = 1;
1069 : }
1070 :
1071 : // Short form - AL, AX, EAX, RAX.
1072 9980 : if (rbReg == 0 && (size == 1 || immSize != 1) && !Support::test(options, InstOptions::kLongForm)) {
1073 : opcode &= Opcode::kPP_66 | Opcode::kW;
1074 0 : opcode |= ((opReg << 3) | (0x04 + (size != 1)));
1075 0 : immSize = FastUInt8(Support::min<uint32_t>(size, 4));
1076 0 : goto EmitX86Op;
1077 : }
1078 :
1079 9980 : opcode += size != 1 ? (immSize != 1 ? 1 : 3) : 0;
1080 9980 : goto EmitX86R;
1081 : }
1082 :
1083 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1084 : uint32_t memSize = o0.size();
1085 :
1086 0 : if (ASMJIT_UNLIKELY(memSize == 0))
1087 0 : goto AmbiguousOperandSize;
1088 :
1089 : immValue = o1.as<Imm>().value();
1090 0 : immSize = FastUInt8(Support::min<uint32_t>(memSize, 4));
1091 :
1092 : // Sign extend so isInt8 returns the right result.
1093 0 : if (memSize == 4)
1094 : immValue = x86SignExtendI32<int64_t>(immValue);
1095 :
1096 0 : if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
1097 : immSize = 1;
1098 :
1099 0 : opcode += memSize != 1 ? (immSize != 1 ? 1 : 3) : 0;
1100 : opcode.addPrefixBySize(memSize);
1101 :
1102 : rmRel = &o0;
1103 0 : goto EmitX86M;
1104 : }
1105 : break;
1106 :
1107 0 : case InstDB::kEncodingX86Bswap:
1108 0 : if (isign3 == ENC_OPS1(Reg)) {
1109 0 : if (ASMJIT_UNLIKELY(o0.size() == 1))
1110 0 : goto InvalidInstruction;
1111 :
1112 : opReg = o0.id();
1113 : opcode.addPrefixBySize(o0.size());
1114 0 : goto EmitX86OpReg;
1115 : }
1116 : break;
1117 :
1118 0 : case InstDB::kEncodingX86Bt:
1119 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1120 : opcode.addPrefixBySize(o1.size());
1121 : opReg = o1.id();
1122 : rbReg = o0.id();
1123 0 : goto EmitX86R;
1124 : }
1125 :
1126 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1127 : opcode.addPrefixBySize(o1.size());
1128 : opReg = o1.id();
1129 : rmRel = &o0;
1130 0 : goto EmitX86M;
1131 : }
1132 :
1133 : // The remaining instructions use the secondary opcode/r.
1134 : immValue = o1.as<Imm>().value();
1135 : immSize = 1;
1136 :
1137 : opcode = x86AltOpcodeOf(instInfo);
1138 : opcode.addPrefixBySize(o0.size());
1139 : opReg = opcode.extractModO();
1140 :
1141 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1142 : rbReg = o0.id();
1143 0 : goto EmitX86R;
1144 : }
1145 :
1146 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1147 0 : if (ASMJIT_UNLIKELY(o0.size() == 0))
1148 0 : goto AmbiguousOperandSize;
1149 :
1150 : rmRel = &o0;
1151 0 : goto EmitX86M;
1152 : }
1153 : break;
1154 :
1155 9639 : case InstDB::kEncodingX86Call:
1156 9639 : if (isign3 == ENC_OPS1(Reg)) {
1157 : rbReg = o0.id();
1158 9639 : goto EmitX86R;
1159 : }
1160 :
1161 : rmRel = &o0;
1162 0 : if (isign3 == ENC_OPS1(Mem))
1163 0 : goto EmitX86M;
1164 :
1165 : // Call with 32-bit displacement use 0xE8 opcode. Call with 8-bit displacement is not encodable so the
1166 : // alternative opcode field in X86DB must be zero.
1167 : opcode = 0xE8;
1168 : opReg = 0;
1169 0 : goto EmitJmpCall;
1170 :
1171 0 : case InstDB::kEncodingX86Cmpxchg: {
1172 : // Convert explicit to implicit.
1173 0 : if (isign3 & (0x7 << 6)) {
1174 0 : if (!Reg::isGp(o2) || o2.id() != Gp::kIdAx)
1175 0 : goto InvalidInstruction;
1176 0 : isign3 &= 0x3F;
1177 : }
1178 :
1179 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1180 0 : if (o0.size() != o1.size())
1181 0 : goto OperandSizeMismatch;
1182 :
1183 : opcode.addArithBySize(o0.size());
1184 : rbReg = o0.id();
1185 : opReg = o1.id();
1186 :
1187 0 : if (o0.size() != 1)
1188 0 : goto EmitX86R;
1189 :
1190 0 : FIXUP_GPB(o0, rbReg);
1191 0 : FIXUP_GPB(o1, opReg);
1192 0 : goto EmitX86R;
1193 : }
1194 :
1195 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1196 : opcode.addArithBySize(o1.size());
1197 : opReg = o1.id();
1198 : rmRel = &o0;
1199 :
1200 0 : if (o1.size() != 1)
1201 0 : goto EmitX86M;
1202 :
1203 0 : FIXUP_GPB(o1, opReg);
1204 0 : goto EmitX86M;
1205 : }
1206 : break;
1207 : }
1208 :
1209 0 : case InstDB::kEncodingX86Cmpxchg8b_16b: {
1210 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
1211 : const Operand_& o4 = opExt[EmitterUtils::kOp4];
1212 :
1213 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
1214 0 : if (o3.isReg() && o4.isReg()) {
1215 : rmRel = &o0;
1216 0 : goto EmitX86M;
1217 : }
1218 : }
1219 :
1220 0 : if (isign3 == ENC_OPS1(Mem)) {
1221 : rmRel = &o0;
1222 0 : goto EmitX86M;
1223 : }
1224 : break;
1225 : }
1226 :
1227 : case InstDB::kEncodingX86Crc:
1228 : opReg = o0.id();
1229 : opcode.addWBySize(o0.size());
1230 :
1231 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1232 : rbReg = o1.id();
1233 :
1234 0 : if (o1.size() == 1) {
1235 0 : FIXUP_GPB(o1, rbReg);
1236 0 : goto EmitX86R;
1237 : }
1238 : else {
1239 : // This seems to be the only exception of encoding '66F2' prefix.
1240 0 : if (o1.size() == 2) writer.emit8(0x66);
1241 :
1242 : opcode.add(1);
1243 0 : goto EmitX86R;
1244 : }
1245 : }
1246 :
1247 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1248 : rmRel = &o1;
1249 0 : if (o1.size() == 0)
1250 0 : goto AmbiguousOperandSize;
1251 :
1252 : // This seems to be the only exception of encoding '66F2' prefix.
1253 0 : if (o1.size() == 2) writer.emit8(0x66);
1254 :
1255 0 : opcode += o1.size() != 1;
1256 0 : goto EmitX86M;
1257 : }
1258 : break;
1259 :
1260 0 : case InstDB::kEncodingX86Enter:
1261 0 : if (isign3 == ENC_OPS2(Imm, Imm)) {
1262 0 : uint32_t iw = o0.as<Imm>().valueAs<uint16_t>();
1263 0 : uint32_t ib = o1.as<Imm>().valueAs<uint8_t>();
1264 :
1265 0 : immValue = iw | (ib << 16);
1266 : immSize = 3;
1267 0 : goto EmitX86Op;
1268 : }
1269 : break;
1270 :
1271 0 : case InstDB::kEncodingX86Imul:
1272 : // First process all forms distinct of `kEncodingX86M_OptB_MulDiv`.
1273 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
1274 : opcode = 0x6B;
1275 : opcode.addPrefixBySize(o0.size());
1276 :
1277 : immValue = o2.as<Imm>().value();
1278 : immSize = 1;
1279 :
1280 0 : if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
1281 : opcode -= 2;
1282 0 : immSize = o0.size() == 2 ? 2 : 4;
1283 : }
1284 :
1285 : opReg = o0.id();
1286 : rbReg = o1.id();
1287 :
1288 0 : goto EmitX86R;
1289 : }
1290 :
1291 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
1292 : opcode = 0x6B;
1293 : opcode.addPrefixBySize(o0.size());
1294 :
1295 : immValue = o2.as<Imm>().value();
1296 : immSize = 1;
1297 :
1298 : // Sign extend so isInt8 returns the right result.
1299 0 : if (o0.size() == 4)
1300 : immValue = x86SignExtendI32<int64_t>(immValue);
1301 :
1302 0 : if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
1303 : opcode -= 2;
1304 0 : immSize = o0.size() == 2 ? 2 : 4;
1305 : }
1306 :
1307 : opReg = o0.id();
1308 : rmRel = &o1;
1309 :
1310 0 : goto EmitX86M;
1311 : }
1312 :
1313 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1314 : // Must be explicit 'ax, r8' form.
1315 0 : if (o1.size() == 1)
1316 0 : goto CaseX86M_GPB_MulDiv;
1317 :
1318 0 : if (o0.size() != o1.size())
1319 0 : goto OperandSizeMismatch;
1320 :
1321 : opReg = o0.id();
1322 : rbReg = o1.id();
1323 :
1324 : opcode = Opcode::k000F00 | 0xAF;
1325 : opcode.addPrefixBySize(o0.size());
1326 0 : goto EmitX86R;
1327 : }
1328 :
1329 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1330 : // Must be explicit 'ax, m8' form.
1331 0 : if (o1.size() == 1)
1332 0 : goto CaseX86M_GPB_MulDiv;
1333 :
1334 : opReg = o0.id();
1335 : rmRel = &o1;
1336 :
1337 : opcode = Opcode::k000F00 | 0xAF;
1338 : opcode.addPrefixBySize(o0.size());
1339 0 : goto EmitX86M;
1340 : }
1341 :
1342 : // Shorthand to imul 'reg, reg, imm'.
1343 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1344 : opcode = 0x6B;
1345 : opcode.addPrefixBySize(o0.size());
1346 :
1347 : immValue = o1.as<Imm>().value();
1348 : immSize = 1;
1349 :
1350 : // Sign extend so isInt8 returns the right result.
1351 0 : if (o0.size() == 4)
1352 : immValue = x86SignExtendI32<int64_t>(immValue);
1353 :
1354 0 : if (!Support::isInt8(immValue) || Support::test(options, InstOptions::kLongForm)) {
1355 : opcode -= 2;
1356 0 : immSize = o0.size() == 2 ? 2 : 4;
1357 : }
1358 :
1359 : opReg = rbReg = o0.id();
1360 0 : goto EmitX86R;
1361 : }
1362 :
1363 : // Try implicit form.
1364 0 : goto CaseX86M_GPB_MulDiv;
1365 :
1366 0 : case InstDB::kEncodingX86In:
1367 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1368 0 : if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx))
1369 0 : goto InvalidInstruction;
1370 :
1371 0 : immValue = o1.as<Imm>().valueAs<uint8_t>();
1372 : immSize = 1;
1373 :
1374 0 : opcode = x86AltOpcodeOf(instInfo) + (o0.size() != 1);
1375 : opcode.add66hBySize(o0.size());
1376 0 : goto EmitX86Op;
1377 : }
1378 :
1379 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1380 0 : if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx || o1.id() != Gp::kIdDx))
1381 0 : goto InvalidInstruction;
1382 :
1383 0 : opcode += o0.size() != 1;
1384 : opcode.add66hBySize(o0.size());
1385 0 : goto EmitX86Op;
1386 : }
1387 : break;
1388 :
1389 0 : case InstDB::kEncodingX86Ins:
1390 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1391 0 : if (ASMJIT_UNLIKELY(!x86IsImplicitMem(o0, Gp::kIdDi) || o1.id() != Gp::kIdDx))
1392 0 : goto InvalidInstruction;
1393 :
1394 : uint32_t size = o0.size();
1395 0 : if (ASMJIT_UNLIKELY(size == 0))
1396 0 : goto AmbiguousOperandSize;
1397 :
1398 : rmRel = &o0;
1399 0 : opcode += (size != 1);
1400 :
1401 : opcode.add66hBySize(size);
1402 0 : goto EmitX86OpImplicitMem;
1403 : }
1404 : break;
1405 :
1406 0 : case InstDB::kEncodingX86IncDec:
1407 0 : if (isign3 == ENC_OPS1(Reg)) {
1408 : rbReg = o0.id();
1409 :
1410 0 : if (o0.size() == 1) {
1411 0 : FIXUP_GPB(o0, rbReg);
1412 0 : goto EmitX86R;
1413 : }
1414 :
1415 0 : if (is32Bit()) {
1416 : // INC r16|r32 is only encodable in 32-bit mode (collides with REX).
1417 0 : opcode = x86AltOpcodeOf(instInfo) + (rbReg & 0x07);
1418 : opcode.add66hBySize(o0.size());
1419 0 : goto EmitX86Op;
1420 : }
1421 : else {
1422 : opcode.addArithBySize(o0.size());
1423 0 : goto EmitX86R;
1424 : }
1425 : }
1426 :
1427 0 : if (isign3 == ENC_OPS1(Mem)) {
1428 0 : if (!o0.size())
1429 0 : goto AmbiguousOperandSize;
1430 : opcode.addArithBySize(o0.size());
1431 : rmRel = &o0;
1432 0 : goto EmitX86M;
1433 : }
1434 : break;
1435 :
1436 0 : case InstDB::kEncodingX86Int:
1437 0 : if (isign3 == ENC_OPS1(Imm)) {
1438 : immValue = o0.as<Imm>().value();
1439 : immSize = 1;
1440 0 : goto EmitX86Op;
1441 : }
1442 : break;
1443 :
1444 0 : case InstDB::kEncodingX86Jcc:
1445 0 : if (Support::test(options, InstOptions::kTaken | InstOptions::kNotTaken) && hasEncodingOption(EncodingOptions::kPredictedJumps)) {
1446 0 : uint8_t prefix = Support::test(options, InstOptions::kTaken) ? uint8_t(0x3E) : uint8_t(0x2E);
1447 : writer.emit8(prefix);
1448 : }
1449 :
1450 : rmRel = &o0;
1451 : opReg = 0;
1452 0 : goto EmitJmpCall;
1453 :
1454 0 : case InstDB::kEncodingX86JecxzLoop:
1455 : rmRel = &o0;
1456 : // Explicit jecxz|loop [r|e]cx, dst
1457 0 : if (o0.isReg()) {
1458 0 : if (ASMJIT_UNLIKELY(!Reg::isGp(o0, Gp::kIdCx)))
1459 0 : goto InvalidInstruction;
1460 :
1461 0 : writer.emitAddressOverride((is32Bit() && o0.size() == 2) || (is64Bit() && o0.size() == 4));
1462 : rmRel = &o1;
1463 : }
1464 :
1465 : opReg = 0;
1466 0 : goto EmitJmpCall;
1467 :
1468 0 : case InstDB::kEncodingX86Jmp:
1469 0 : if (isign3 == ENC_OPS1(Reg)) {
1470 : rbReg = o0.id();
1471 0 : goto EmitX86R;
1472 : }
1473 :
1474 : rmRel = &o0;
1475 0 : if (isign3 == ENC_OPS1(Mem))
1476 0 : goto EmitX86M;
1477 :
1478 : // Jump encoded with 32-bit displacement use 0xE9 opcode. Jump encoded with 8-bit displacement's opcode is
1479 : // stored as an alternative opcode.
1480 : opcode = 0xE9;
1481 : opReg = 0;
1482 0 : goto EmitJmpCall;
1483 :
1484 0 : case InstDB::kEncodingX86JmpRel:
1485 : rmRel = &o0;
1486 0 : goto EmitJmpCall;
1487 :
1488 0 : case InstDB::kEncodingX86LcallLjmp:
1489 0 : if (isign3 == ENC_OPS1(Mem)) {
1490 : rmRel = &o0;
1491 : uint32_t mSize = rmRel->size();
1492 0 : if (mSize == 0) {
1493 : mSize = registerSize();
1494 : }
1495 : else {
1496 0 : mSize -= 2;
1497 0 : if (mSize != 2 && mSize != 4 && mSize != registerSize())
1498 0 : goto InvalidAddress;
1499 : }
1500 : opcode.addPrefixBySize(mSize);
1501 0 : goto EmitX86M;
1502 : }
1503 :
1504 0 : if (isign3 == ENC_OPS2(Imm, Imm)) {
1505 0 : if (!is32Bit())
1506 0 : goto InvalidInstruction;
1507 :
1508 : const Imm& imm0 = o0.as<Imm>();
1509 : const Imm& imm1 = o1.as<Imm>();
1510 :
1511 0 : if (imm0.value() > 0xFFFFu || imm1.value() > 0xFFFFFFFFu)
1512 0 : goto InvalidImmediate;
1513 :
1514 : opcode = x86AltOpcodeOf(instInfo);
1515 0 : immValue = imm1.value() | (imm0.value() << 32);
1516 : immSize = 6;
1517 0 : goto EmitX86Op;
1518 : }
1519 : break;
1520 :
1521 0 : case InstDB::kEncodingX86Lea:
1522 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1523 : opcode.addPrefixBySize(o0.size());
1524 : opReg = o0.id();
1525 : rmRel = &o1;
1526 0 : goto EmitX86M;
1527 : }
1528 : break;
1529 :
1530 88256 : case InstDB::kEncodingX86Mov:
1531 : // Reg <- Reg
1532 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1533 : // Asmjit uses segment registers indexed from 1 to 6, leaving zero as "no segment register used". We have to
1534 : // fix this (decrement the index of the register) when emitting MOV instructions which move to/from a segment
1535 : // register. The segment register is always `opReg`, because the MOV instruction uses either RM or MR encoding.
1536 :
1537 : // GP <- ??
1538 0 : if (Reg::isGp(o0)) {
1539 : rbReg = o0.id();
1540 : opReg = o1.id();
1541 :
1542 : // GP <- GP
1543 0 : if (Reg::isGp(o1)) {
1544 : uint32_t opSize = o0.size();
1545 0 : if (opSize != o1.size())
1546 0 : goto InvalidInstruction;
1547 :
1548 0 : if (opSize == 1) {
1549 0 : FIXUP_GPB(o0, rbReg);
1550 0 : FIXUP_GPB(o1, opReg);
1551 : opcode = 0x88;
1552 :
1553 0 : if (!Support::test(options, InstOptions::kX86_ModRM))
1554 0 : goto EmitX86R;
1555 :
1556 : opcode += 2;
1557 : std::swap(opReg, rbReg);
1558 0 : goto EmitX86R;
1559 : }
1560 : else {
1561 : opcode = 0x89;
1562 : opcode.addPrefixBySize(opSize);
1563 :
1564 0 : if (!Support::test(options, InstOptions::kX86_ModRM))
1565 0 : goto EmitX86R;
1566 :
1567 : opcode += 2;
1568 : std::swap(opReg, rbReg);
1569 0 : goto EmitX86R;
1570 : }
1571 : }
1572 :
1573 : // GP <- SReg
1574 0 : if (Reg::isSReg(o1)) {
1575 : opcode = 0x8C;
1576 : opcode.addPrefixBySize(o0.size());
1577 0 : opReg--;
1578 0 : goto EmitX86R;
1579 : }
1580 :
1581 : // GP <- CReg
1582 0 : if (Reg::isCReg(o1)) {
1583 : opcode = Opcode::k000F00 | 0x20;
1584 :
1585 : // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
1586 0 : if ((opReg & 0x8) && is32Bit()) {
1587 : writer.emit8(0xF0);
1588 0 : opReg &= 0x7;
1589 : }
1590 0 : goto EmitX86R;
1591 : }
1592 :
1593 : // GP <- DReg
1594 0 : if (Reg::isDReg(o1)) {
1595 : opcode = Opcode::k000F00 | 0x21;
1596 0 : goto EmitX86R;
1597 : }
1598 : }
1599 : else {
1600 : opReg = o0.id();
1601 : rbReg = o1.id();
1602 :
1603 : // ?? <- GP
1604 0 : if (!Reg::isGp(o1))
1605 0 : goto InvalidInstruction;
1606 :
1607 : // SReg <- GP
1608 0 : if (Reg::isSReg(o0)) {
1609 : opcode = 0x8E;
1610 : opcode.addPrefixBySize(o1.size());
1611 0 : opReg--;
1612 0 : goto EmitX86R;
1613 : }
1614 :
1615 : // CReg <- GP
1616 0 : if (Reg::isCReg(o0)) {
1617 : opcode = Opcode::k000F00 | 0x22;
1618 :
1619 : // Use `LOCK MOV` in 32-bit mode if CR8+ register is accessed (AMD extension).
1620 0 : if ((opReg & 0x8) && is32Bit()) {
1621 : writer.emit8(0xF0);
1622 0 : opReg &= 0x7;
1623 : }
1624 0 : goto EmitX86R;
1625 : }
1626 :
1627 : // DReg <- GP
1628 0 : if (Reg::isDReg(o0)) {
1629 : opcode = Opcode::k000F00 | 0x23;
1630 0 : goto EmitX86R;
1631 : }
1632 : }
1633 :
1634 0 : goto InvalidInstruction;
1635 : }
1636 :
1637 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1638 : opReg = o0.id();
1639 : rmRel = &o1;
1640 :
1641 : // SReg <- Mem
1642 10 : if (Reg::isSReg(o0)) {
1643 : opcode = 0x8E;
1644 : opcode.addPrefixBySize(o1.size());
1645 0 : opReg--;
1646 0 : goto EmitX86M;
1647 : }
1648 : // Reg <- Mem
1649 : else {
1650 : opcode = 0;
1651 : opcode.addArithBySize(o0.size());
1652 :
1653 : // Handle a special form of `mov al|ax|eax|rax, [ptr64]` that doesn't use MOD.
1654 10 : if (opReg == Gp::kIdAx && !rmRel->as<Mem>().hasBaseOrIndex()) {
1655 0 : if (x86ShouldUseMovabs(this, writer, o0.size(), options, rmRel->as<Mem>())) {
1656 : opcode += 0xA0;
1657 : immValue = rmRel->as<Mem>().offset();
1658 0 : goto EmitX86OpMovAbs;
1659 : }
1660 : }
1661 :
1662 10 : if (o0.size() == 1)
1663 0 : FIXUP_GPB(o0, opReg);
1664 :
1665 : opcode += 0x8A;
1666 10 : goto EmitX86M;
1667 : }
1668 : }
1669 :
1670 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1671 : opReg = o1.id();
1672 : rmRel = &o0;
1673 :
1674 : // Mem <- SReg
1675 10 : if (Reg::isSReg(o1)) {
1676 : opcode = 0x8C;
1677 : opcode.addPrefixBySize(o0.size());
1678 0 : opReg--;
1679 0 : goto EmitX86M;
1680 : }
1681 : // Mem <- Reg
1682 : else {
1683 : opcode = 0;
1684 : opcode.addArithBySize(o1.size());
1685 :
1686 : // Handle a special form of `mov [ptr64], al|ax|eax|rax` that doesn't use MOD.
1687 10 : if (opReg == Gp::kIdAx && !rmRel->as<Mem>().hasBaseOrIndex()) {
1688 0 : if (x86ShouldUseMovabs(this, writer, o1.size(), options, rmRel->as<Mem>())) {
1689 : opcode += 0xA2;
1690 : immValue = rmRel->as<Mem>().offset();
1691 0 : goto EmitX86OpMovAbs;
1692 : }
1693 : }
1694 :
1695 10 : if (o1.size() == 1)
1696 0 : FIXUP_GPB(o1, opReg);
1697 :
1698 : opcode += 0x88;
1699 10 : goto EmitX86M;
1700 : }
1701 : }
1702 :
1703 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1704 : opReg = o0.id();
1705 88236 : immSize = FastUInt8(o0.size());
1706 :
1707 88236 : if (immSize == 1) {
1708 0 : FIXUP_GPB(o0, opReg);
1709 :
1710 : opcode = 0xB0;
1711 0 : immValue = o1.as<Imm>().valueAs<uint8_t>();
1712 0 : goto EmitX86OpReg;
1713 : }
1714 : else {
1715 : // 64-bit immediate in 64-bit mode is allowed.
1716 : immValue = o1.as<Imm>().value();
1717 :
1718 : // Optimize the instruction size by using a 32-bit immediate if possible.
1719 88236 : if (immSize == 8 && !Support::test(options, InstOptions::kLongForm)) {
1720 88236 : if (Support::isUInt32(immValue) && hasEncodingOption(EncodingOptions::kOptimizeForSize)) {
1721 : // Zero-extend by using a 32-bit GPD destination instead of a 64-bit GPQ.
1722 : immSize = 4;
1723 : }
1724 : else if (Support::isInt32(immValue)) {
1725 : // Sign-extend, uses 'C7 /0' opcode.
1726 : rbReg = opReg;
1727 :
1728 : opcode = Opcode::kW | 0xC7;
1729 : opReg = 0;
1730 :
1731 : immSize = 4;
1732 0 : goto EmitX86R;
1733 : }
1734 : }
1735 :
1736 : opcode = 0xB8;
1737 : opcode.addPrefixBySize(immSize);
1738 88236 : goto EmitX86OpReg;
1739 : }
1740 : }
1741 :
1742 : if (isign3 == ENC_OPS2(Mem, Imm)) {
1743 : uint32_t memSize = o0.size();
1744 0 : if (ASMJIT_UNLIKELY(memSize == 0))
1745 0 : goto AmbiguousOperandSize;
1746 :
1747 0 : opcode = 0xC6 + (memSize != 1);
1748 : opcode.addPrefixBySize(memSize);
1749 : opReg = 0;
1750 : rmRel = &o0;
1751 :
1752 : immValue = o1.as<Imm>().value();
1753 0 : immSize = FastUInt8(Support::min<uint32_t>(memSize, 4));
1754 0 : goto EmitX86M;
1755 : }
1756 : break;
1757 :
1758 0 : case InstDB::kEncodingX86Movabs:
1759 : // Reg <- Mem
1760 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1761 : opReg = o0.id();
1762 : rmRel = &o1;
1763 :
1764 : opcode = 0xA0;
1765 : opcode.addArithBySize(o0.size());
1766 :
1767 0 : if (ASMJIT_UNLIKELY(!o0.as<Reg>().isGp()) || opReg != Gp::kIdAx)
1768 0 : goto InvalidInstruction;
1769 :
1770 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasBaseOrIndex()))
1771 0 : goto InvalidAddress;
1772 :
1773 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().addrType() == Mem::AddrType::kRel))
1774 0 : goto InvalidAddress;
1775 :
1776 : immValue = rmRel->as<Mem>().offset();
1777 0 : goto EmitX86OpMovAbs;
1778 : }
1779 :
1780 : // Mem <- Reg
1781 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1782 : opReg = o1.id();
1783 : rmRel = &o0;
1784 :
1785 : opcode = 0xA2;
1786 : opcode.addArithBySize(o1.size());
1787 :
1788 0 : if (ASMJIT_UNLIKELY(!o1.as<Reg>().isGp()) || opReg != Gp::kIdAx)
1789 0 : goto InvalidInstruction;
1790 :
1791 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasBaseOrIndex()))
1792 0 : goto InvalidAddress;
1793 :
1794 : immValue = rmRel->as<Mem>().offset();
1795 0 : goto EmitX86OpMovAbs;
1796 : }
1797 :
1798 : // Reg <- Imm.
1799 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
1800 0 : if (ASMJIT_UNLIKELY(!o0.as<Reg>().isGpq()))
1801 0 : goto InvalidInstruction;
1802 :
1803 : opReg = o0.id();
1804 : opcode = 0xB8;
1805 :
1806 : immSize = 8;
1807 : immValue = o1.as<Imm>().value();
1808 :
1809 : opcode.addPrefixBySize(8);
1810 0 : goto EmitX86OpReg;
1811 : }
1812 : break;
1813 :
1814 : case InstDB::kEncodingX86MovsxMovzx:
1815 0 : opcode.add(o1.size() != 1);
1816 : opcode.addPrefixBySize(o0.size());
1817 :
1818 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1819 : opReg = o0.id();
1820 : rbReg = o1.id();
1821 :
1822 0 : if (o1.size() != 1)
1823 0 : goto EmitX86R;
1824 :
1825 0 : FIXUP_GPB(o1, rbReg);
1826 0 : goto EmitX86R;
1827 : }
1828 :
1829 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1830 : opReg = o0.id();
1831 : rmRel = &o1;
1832 0 : goto EmitX86M;
1833 : }
1834 : break;
1835 :
1836 0 : case InstDB::kEncodingX86MovntiMovdiri:
1837 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
1838 : opcode.addWIf(Reg::isGpq(o1));
1839 :
1840 : opReg = o1.id();
1841 : rmRel = &o0;
1842 0 : goto EmitX86M;
1843 : }
1844 : break;
1845 :
1846 0 : case InstDB::kEncodingX86EnqcmdMovdir64b:
1847 0 : if (isign3 == ENC_OPS2(Mem, Mem)) {
1848 : const Mem& m0 = o0.as<Mem>();
1849 : // This is the only required validation, the rest is handled afterwards.
1850 0 : if (ASMJIT_UNLIKELY(m0.baseType() != o1.as<Mem>().baseType() ||
1851 : m0.hasIndex() ||
1852 : m0.hasOffset() ||
1853 : (m0.hasSegment() && m0.segmentId() != SReg::kIdEs)))
1854 0 : goto InvalidInstruction;
1855 :
1856 : // The first memory operand is passed via register, the second memory operand is RM.
1857 : opReg = o0.as<Mem>().baseId();
1858 : rmRel = &o1;
1859 0 : goto EmitX86M;
1860 : }
1861 : break;
1862 :
1863 0 : case InstDB::kEncodingX86Out:
1864 0 : if (isign3 == ENC_OPS2(Imm, Reg)) {
1865 0 : if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdAx))
1866 0 : goto InvalidInstruction;
1867 :
1868 0 : opcode = x86AltOpcodeOf(instInfo) + (o1.size() != 1);
1869 : opcode.add66hBySize(o1.size());
1870 :
1871 0 : immValue = o0.as<Imm>().valueAs<uint8_t>();
1872 : immSize = 1;
1873 0 : goto EmitX86Op;
1874 : }
1875 :
1876 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1877 0 : if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdDx || o1.id() != Gp::kIdAx))
1878 0 : goto InvalidInstruction;
1879 :
1880 0 : opcode.add(o1.size() != 1);
1881 : opcode.add66hBySize(o1.size());
1882 0 : goto EmitX86Op;
1883 : }
1884 : break;
1885 :
1886 0 : case InstDB::kEncodingX86Outs:
1887 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
1888 0 : if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdDx || !x86IsImplicitMem(o1, Gp::kIdSi)))
1889 0 : goto InvalidInstruction;
1890 :
1891 : uint32_t size = o1.size();
1892 0 : if (ASMJIT_UNLIKELY(size == 0))
1893 0 : goto AmbiguousOperandSize;
1894 :
1895 : rmRel = &o1;
1896 0 : opcode.add(size != 1);
1897 : opcode.add66hBySize(size);
1898 0 : goto EmitX86OpImplicitMem;
1899 : }
1900 : break;
1901 :
1902 0 : case InstDB::kEncodingX86Push:
1903 0 : if (isign3 == ENC_OPS1(Reg)) {
1904 0 : if (Reg::isSReg(o0)) {
1905 : uint32_t segment = o0.id();
1906 0 : if (ASMJIT_UNLIKELY(segment >= SReg::kIdCount))
1907 0 : goto InvalidSegment;
1908 :
1909 0 : opcode = x86OpcodePushSReg[segment];
1910 0 : goto EmitX86Op;
1911 : }
1912 : else {
1913 0 : goto CaseX86PushPop_Gp;
1914 : }
1915 : }
1916 :
1917 0 : if (isign3 == ENC_OPS1(Imm)) {
1918 : immValue = o0.as<Imm>().value();
1919 : immSize = 4;
1920 :
1921 0 : if (Support::isInt8(immValue) && !Support::test(options, InstOptions::kLongForm))
1922 : immSize = 1;
1923 :
1924 : opcode = immSize == 1 ? 0x6A : 0x68;
1925 0 : goto EmitX86Op;
1926 : }
1927 : ASMJIT_FALLTHROUGH;
1928 :
1929 : case InstDB::kEncodingX86Pop:
1930 0 : if (isign3 == ENC_OPS1(Reg)) {
1931 0 : if (Reg::isSReg(o0)) {
1932 : uint32_t segment = o0.id();
1933 0 : if (ASMJIT_UNLIKELY(segment == SReg::kIdCs || segment >= SReg::kIdCount))
1934 0 : goto InvalidSegment;
1935 :
1936 0 : opcode = x86OpcodePopSReg[segment];
1937 0 : goto EmitX86Op;
1938 : }
1939 : else {
1940 0 : CaseX86PushPop_Gp:
1941 : // We allow 2 byte, 4 byte, and 8 byte register sizes, although PUSH and POP only allow 2 bytes or
1942 : // native size. On 64-bit we simply PUSH/POP 64-bit register even if 32-bit register was given.
1943 0 : if (ASMJIT_UNLIKELY(o0.size() < 2))
1944 0 : goto InvalidInstruction;
1945 :
1946 : opcode = x86AltOpcodeOf(instInfo);
1947 : opcode.add66hBySize(o0.size());
1948 : opReg = o0.id();
1949 0 : goto EmitX86OpReg;
1950 : }
1951 : }
1952 :
1953 0 : if (isign3 == ENC_OPS1(Mem)) {
1954 0 : if (ASMJIT_UNLIKELY(o0.size() == 0))
1955 0 : goto AmbiguousOperandSize;
1956 :
1957 0 : if (ASMJIT_UNLIKELY(o0.size() != 2 && o0.size() != registerSize()))
1958 0 : goto InvalidInstruction;
1959 :
1960 : opcode.add66hBySize(o0.size());
1961 : rmRel = &o0;
1962 0 : goto EmitX86M;
1963 : }
1964 : break;
1965 :
1966 27492 : case InstDB::kEncodingX86Ret:
1967 27492 : if (isign3 == 0) {
1968 : // 'ret' without immediate, change C2 to C3.
1969 : opcode.add(1);
1970 27492 : goto EmitX86Op;
1971 : }
1972 :
1973 0 : if (isign3 == ENC_OPS1(Imm)) {
1974 : immValue = o0.as<Imm>().value();
1975 0 : if (immValue == 0 && !Support::test(options, InstOptions::kLongForm)) {
1976 : // 'ret' without immediate, change C2 to C3.
1977 : opcode.add(1);
1978 0 : goto EmitX86Op;
1979 : }
1980 : else {
1981 : immSize = 2;
1982 0 : goto EmitX86Op;
1983 : }
1984 : }
1985 : break;
1986 :
1987 : case InstDB::kEncodingX86Rot:
1988 0 : if (o0.isReg()) {
1989 : opcode.addArithBySize(o0.size());
1990 : rbReg = o0.id();
1991 :
1992 0 : if (o0.size() == 1)
1993 0 : FIXUP_GPB(o0, rbReg);
1994 :
1995 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
1996 0 : if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdCx))
1997 0 : goto InvalidInstruction;
1998 :
1999 : opcode += 2;
2000 0 : goto EmitX86R;
2001 : }
2002 :
2003 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2004 0 : immValue = o1.as<Imm>().value() & 0xFF;
2005 : immSize = 0;
2006 :
2007 0 : if (immValue == 1 && !Support::test(options, InstOptions::kLongForm))
2008 0 : goto EmitX86R;
2009 :
2010 : opcode -= 0x10;
2011 : immSize = 1;
2012 0 : goto EmitX86R;
2013 : }
2014 : }
2015 : else {
2016 0 : if (ASMJIT_UNLIKELY(o0.size() == 0))
2017 0 : goto AmbiguousOperandSize;
2018 : opcode.addArithBySize(o0.size());
2019 :
2020 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2021 0 : if (ASMJIT_UNLIKELY(o1.id() != Gp::kIdCx))
2022 0 : goto InvalidInstruction;
2023 :
2024 : opcode += 2;
2025 : rmRel = &o0;
2026 0 : goto EmitX86M;
2027 : }
2028 :
2029 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
2030 : rmRel = &o0;
2031 0 : immValue = o1.as<Imm>().value() & 0xFF;
2032 : immSize = 0;
2033 :
2034 0 : if (immValue == 1 && !Support::test(options, InstOptions::kLongForm))
2035 0 : goto EmitX86M;
2036 :
2037 : opcode -= 0x10;
2038 : immSize = 1;
2039 0 : goto EmitX86M;
2040 : }
2041 : }
2042 : break;
2043 :
2044 0 : case InstDB::kEncodingX86Set:
2045 0 : if (isign3 == ENC_OPS1(Reg)) {
2046 : rbReg = o0.id();
2047 0 : FIXUP_GPB(o0, rbReg);
2048 0 : goto EmitX86R;
2049 : }
2050 :
2051 0 : if (isign3 == ENC_OPS1(Mem)) {
2052 : rmRel = &o0;
2053 0 : goto EmitX86M;
2054 : }
2055 : break;
2056 :
2057 0 : case InstDB::kEncodingX86ShldShrd:
2058 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2059 : opcode.addPrefixBySize(o0.size());
2060 : opReg = o1.id();
2061 : rbReg = o0.id();
2062 :
2063 : immValue = o2.as<Imm>().value();
2064 : immSize = 1;
2065 0 : goto EmitX86R;
2066 : }
2067 :
2068 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2069 : opcode.addPrefixBySize(o1.size());
2070 : opReg = o1.id();
2071 : rmRel = &o0;
2072 :
2073 : immValue = o2.as<Imm>().value();
2074 : immSize = 1;
2075 0 : goto EmitX86M;
2076 : }
2077 :
2078 : // The following instructions use opcode + 1.
2079 : opcode.add(1);
2080 :
2081 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
2082 0 : if (ASMJIT_UNLIKELY(o2.id() != Gp::kIdCx))
2083 0 : goto InvalidInstruction;
2084 :
2085 : opcode.addPrefixBySize(o0.size());
2086 : opReg = o1.id();
2087 : rbReg = o0.id();
2088 0 : goto EmitX86R;
2089 : }
2090 :
2091 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
2092 0 : if (ASMJIT_UNLIKELY(o2.id() != Gp::kIdCx))
2093 0 : goto InvalidInstruction;
2094 :
2095 : opcode.addPrefixBySize(o1.size());
2096 : opReg = o1.id();
2097 : rmRel = &o0;
2098 0 : goto EmitX86M;
2099 : }
2100 : break;
2101 :
2102 0 : case InstDB::kEncodingX86StrRm:
2103 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2104 : rmRel = &o1;
2105 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().offsetLo32() || !Reg::isGp(o0.as<Reg>(), Gp::kIdAx)))
2106 0 : goto InvalidInstruction;
2107 :
2108 : uint32_t size = o0.size();
2109 0 : if (o1.hasSize() && ASMJIT_UNLIKELY(o1.size() != size))
2110 0 : goto OperandSizeMismatch;
2111 :
2112 : opcode.addArithBySize(size);
2113 0 : goto EmitX86OpImplicitMem;
2114 : }
2115 : break;
2116 :
2117 0 : case InstDB::kEncodingX86StrMr:
2118 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2119 : rmRel = &o0;
2120 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().offsetLo32() || !Reg::isGp(o1.as<Reg>(), Gp::kIdAx)))
2121 0 : goto InvalidInstruction;
2122 :
2123 : uint32_t size = o1.size();
2124 0 : if (o0.hasSize() && ASMJIT_UNLIKELY(o0.size() != size))
2125 0 : goto OperandSizeMismatch;
2126 :
2127 : opcode.addArithBySize(size);
2128 0 : goto EmitX86OpImplicitMem;
2129 : }
2130 : break;
2131 :
2132 0 : case InstDB::kEncodingX86StrMm:
2133 0 : if (isign3 == ENC_OPS2(Mem, Mem)) {
2134 0 : if (ASMJIT_UNLIKELY(o0.as<Mem>().baseAndIndexTypes() !=
2135 : o1.as<Mem>().baseAndIndexTypes()))
2136 0 : goto InvalidInstruction;
2137 :
2138 : rmRel = &o1;
2139 0 : if (ASMJIT_UNLIKELY(o0.as<Mem>().hasOffset()))
2140 0 : goto InvalidInstruction;
2141 :
2142 : uint32_t size = o1.size();
2143 0 : if (ASMJIT_UNLIKELY(size == 0))
2144 0 : goto AmbiguousOperandSize;
2145 :
2146 0 : if (ASMJIT_UNLIKELY(o0.size() != size))
2147 0 : goto OperandSizeMismatch;
2148 :
2149 : opcode.addArithBySize(size);
2150 0 : goto EmitX86OpImplicitMem;
2151 : }
2152 : break;
2153 :
2154 0 : case InstDB::kEncodingX86Test:
2155 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2156 0 : if (o0.size() != o1.size())
2157 0 : goto OperandSizeMismatch;
2158 :
2159 : opcode.addArithBySize(o0.size());
2160 : rbReg = o0.id();
2161 : opReg = o1.id();
2162 :
2163 0 : if (o0.size() != 1)
2164 0 : goto EmitX86R;
2165 :
2166 0 : FIXUP_GPB(o0, rbReg);
2167 0 : FIXUP_GPB(o1, opReg);
2168 0 : goto EmitX86R;
2169 : }
2170 :
2171 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2172 : opcode.addArithBySize(o1.size());
2173 : opReg = o1.id();
2174 : rmRel = &o0;
2175 :
2176 0 : if (o1.size() != 1)
2177 0 : goto EmitX86M;
2178 :
2179 0 : FIXUP_GPB(o1, opReg);
2180 0 : goto EmitX86M;
2181 : }
2182 :
2183 : // The following instructions use the secondary opcode.
2184 : opcode = x86AltOpcodeOf(instInfo);
2185 : opReg = opcode.extractModO();
2186 :
2187 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2188 : opcode.addArithBySize(o0.size());
2189 : rbReg = o0.id();
2190 :
2191 0 : if (o0.size() == 1) {
2192 0 : FIXUP_GPB(o0, rbReg);
2193 0 : immValue = o1.as<Imm>().valueAs<uint8_t>();
2194 : immSize = 1;
2195 : }
2196 : else {
2197 : immValue = o1.as<Imm>().value();
2198 0 : immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4));
2199 : }
2200 :
2201 : // Short form - AL, AX, EAX, RAX.
2202 0 : if (rbReg == 0 && !Support::test(options, InstOptions::kLongForm)) {
2203 : opcode &= Opcode::kPP_66 | Opcode::kW;
2204 0 : opcode |= 0xA8 + (o0.size() != 1);
2205 0 : goto EmitX86Op;
2206 : }
2207 :
2208 0 : goto EmitX86R;
2209 : }
2210 :
2211 0 : if (isign3 == ENC_OPS2(Mem, Imm)) {
2212 0 : if (ASMJIT_UNLIKELY(o0.size() == 0))
2213 0 : goto AmbiguousOperandSize;
2214 :
2215 : opcode.addArithBySize(o0.size());
2216 : rmRel = &o0;
2217 :
2218 : immValue = o1.as<Imm>().value();
2219 0 : immSize = FastUInt8(Support::min<uint32_t>(o0.size(), 4));
2220 0 : goto EmitX86M;
2221 : }
2222 : break;
2223 :
2224 0 : case InstDB::kEncodingX86Xchg:
2225 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2226 : opcode.addArithBySize(o0.size());
2227 : opReg = o0.id();
2228 : rmRel = &o1;
2229 :
2230 0 : if (o0.size() != 1)
2231 0 : goto EmitX86M;
2232 :
2233 0 : FIXUP_GPB(o0, opReg);
2234 0 : goto EmitX86M;
2235 : }
2236 : ASMJIT_FALLTHROUGH;
2237 :
2238 : case InstDB::kEncodingX86Xadd:
2239 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2240 : rbReg = o0.id();
2241 : opReg = o1.id();
2242 :
2243 : uint32_t opSize = o0.size();
2244 0 : if (opSize != o1.size())
2245 0 : goto OperandSizeMismatch;
2246 :
2247 0 : if (opSize == 1) {
2248 0 : FIXUP_GPB(o0, rbReg);
2249 0 : FIXUP_GPB(o1, opReg);
2250 0 : goto EmitX86R;
2251 : }
2252 :
2253 : // Special cases for 'xchg ?ax, reg'.
2254 0 : if (instId == Inst::kIdXchg && (opReg == 0 || rbReg == 0)) {
2255 0 : if (is64Bit() && opReg == rbReg && opSize >= 4) {
2256 0 : if (opSize == 8) {
2257 : // Encode 'xchg rax, rax' as '90' (REX and other prefixes are optional).
2258 : opcode &= Opcode::kW;
2259 : opcode |= 0x90;
2260 0 : goto EmitX86OpReg;
2261 : }
2262 : else {
2263 : // Encode 'xchg eax, eax' by by using a generic path.
2264 : }
2265 : }
2266 0 : else if (!Support::test(options, InstOptions::kLongForm)) {
2267 : // The special encoding encodes only one register, which is non-zero.
2268 0 : opReg += rbReg;
2269 :
2270 : opcode.addArithBySize(opSize);
2271 : opcode &= Opcode::kW | Opcode::kPP_66;
2272 : opcode |= 0x90;
2273 0 : goto EmitX86OpReg;
2274 : }
2275 : }
2276 :
2277 : opcode.addArithBySize(opSize);
2278 0 : goto EmitX86R;
2279 : }
2280 :
2281 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2282 : opcode.addArithBySize(o1.size());
2283 : opReg = o1.id();
2284 : rmRel = &o0;
2285 :
2286 0 : if (o1.size() == 1) {
2287 0 : FIXUP_GPB(o1, opReg);
2288 : }
2289 :
2290 0 : goto EmitX86M;
2291 : }
2292 : break;
2293 :
2294 0 : case InstDB::kEncodingX86Fence:
2295 : rbReg = 0;
2296 0 : goto EmitX86R;
2297 :
2298 0 : case InstDB::kEncodingX86Bndmov:
2299 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2300 : opReg = o0.id();
2301 : rbReg = o1.id();
2302 :
2303 : // ModRM encoding:
2304 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
2305 0 : goto EmitX86R;
2306 :
2307 : // ModMR encoding:
2308 : opcode = x86AltOpcodeOf(instInfo);
2309 : std::swap(opReg, rbReg);
2310 0 : goto EmitX86R;
2311 : }
2312 :
2313 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2314 : opReg = o0.id();
2315 : rmRel = &o1;
2316 0 : goto EmitX86M;
2317 : }
2318 :
2319 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2320 : opcode = x86AltOpcodeOf(instInfo);
2321 :
2322 : rmRel = &o0;
2323 : opReg = o1.id();
2324 0 : goto EmitX86M;
2325 : }
2326 : break;
2327 :
2328 : // FPU Instructions
2329 : // ----------------
2330 :
2331 0 : case InstDB::kEncodingFpuOp:
2332 0 : goto EmitFpuOp;
2333 :
2334 0 : case InstDB::kEncodingFpuArith:
2335 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2336 : opReg = o0.id();
2337 : rbReg = o1.id();
2338 :
2339 : // We switch to the alternative opcode if the first operand is zero.
2340 0 : if (opReg == 0) {
2341 0 : CaseFpuArith_Reg:
2342 : opcode = ((0xD8 << Opcode::kFPU_2B_Shift) ) +
2343 0 : ((opcode >> Opcode::kFPU_2B_Shift) & 0xFF) + rbReg;
2344 0 : goto EmitFpuOp;
2345 : }
2346 0 : else if (rbReg == 0) {
2347 : rbReg = opReg;
2348 : opcode = ((0xDC << Opcode::kFPU_2B_Shift) ) +
2349 0 : ((opcode ) & 0xFF) + rbReg;
2350 0 : goto EmitFpuOp;
2351 : }
2352 : else {
2353 0 : goto InvalidInstruction;
2354 : }
2355 : }
2356 :
2357 0 : if (isign3 == ENC_OPS1(Mem)) {
2358 0 : CaseFpuArith_Mem:
2359 : // 0xD8/0xDC, depends on the size of the memory operand; opReg is valid.
2360 0 : opcode = (o0.size() == 4) ? 0xD8 : 0xDC;
2361 : // Clear compressed displacement before going to EmitX86M.
2362 : opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
2363 :
2364 : rmRel = &o0;
2365 0 : goto EmitX86M;
2366 : }
2367 : break;
2368 :
2369 0 : case InstDB::kEncodingFpuCom:
2370 0 : if (isign3 == 0) {
2371 : rbReg = 1;
2372 0 : goto CaseFpuArith_Reg;
2373 : }
2374 :
2375 0 : if (isign3 == ENC_OPS1(Reg)) {
2376 : rbReg = o0.id();
2377 0 : goto CaseFpuArith_Reg;
2378 : }
2379 :
2380 0 : if (isign3 == ENC_OPS1(Mem)) {
2381 0 : goto CaseFpuArith_Mem;
2382 : }
2383 : break;
2384 :
2385 0 : case InstDB::kEncodingFpuFldFst:
2386 0 : if (isign3 == ENC_OPS1(Mem)) {
2387 : rmRel = &o0;
2388 :
2389 0 : if (o0.size() == 4 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM32)) {
2390 0 : goto EmitX86M;
2391 : }
2392 :
2393 0 : if (o0.size() == 8 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM64)) {
2394 : opcode += 4;
2395 0 : goto EmitX86M;
2396 : }
2397 :
2398 0 : if (o0.size() == 10 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM80)) {
2399 : opcode = x86AltOpcodeOf(instInfo);
2400 : opReg = opcode.extractModO();
2401 0 : goto EmitX86M;
2402 : }
2403 : }
2404 :
2405 0 : if (isign3 == ENC_OPS1(Reg)) {
2406 0 : if (instId == Inst::kIdFld ) { opcode = (0xD9 << Opcode::kFPU_2B_Shift) + 0xC0 + o0.id(); goto EmitFpuOp; }
2407 0 : if (instId == Inst::kIdFst ) { opcode = (0xDD << Opcode::kFPU_2B_Shift) + 0xD0 + o0.id(); goto EmitFpuOp; }
2408 0 : if (instId == Inst::kIdFstp) { opcode = (0xDD << Opcode::kFPU_2B_Shift) + 0xD8 + o0.id(); goto EmitFpuOp; }
2409 : }
2410 : break;
2411 :
2412 0 : case InstDB::kEncodingFpuM:
2413 0 : if (isign3 == ENC_OPS1(Mem)) {
2414 : // Clear compressed displacement before going to EmitX86M.
2415 : opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
2416 :
2417 : rmRel = &o0;
2418 0 : if (o0.size() == 2 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM16)) {
2419 : opcode += 4;
2420 0 : goto EmitX86M;
2421 : }
2422 :
2423 0 : if (o0.size() == 4 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM32)) {
2424 0 : goto EmitX86M;
2425 : }
2426 :
2427 0 : if (o0.size() == 8 && commonInfo->hasFlag(InstDB::InstFlags::kFpuM64)) {
2428 0 : opcode = x86AltOpcodeOf(instInfo) & ~uint32_t(Opcode::kCDSHL_Mask);
2429 : opReg = opcode.extractModO();
2430 0 : goto EmitX86M;
2431 : }
2432 : }
2433 : break;
2434 :
2435 0 : case InstDB::kEncodingFpuRDef:
2436 0 : if (isign3 == 0) {
2437 : opcode += 1;
2438 0 : goto EmitFpuOp;
2439 : }
2440 : ASMJIT_FALLTHROUGH;
2441 :
2442 : case InstDB::kEncodingFpuR:
2443 0 : if (isign3 == ENC_OPS1(Reg)) {
2444 : opcode += o0.id();
2445 0 : goto EmitFpuOp;
2446 : }
2447 : break;
2448 :
2449 0 : case InstDB::kEncodingFpuStsw:
2450 0 : if (isign3 == ENC_OPS1(Reg)) {
2451 0 : if (ASMJIT_UNLIKELY(o0.id() != Gp::kIdAx))
2452 0 : goto InvalidInstruction;
2453 :
2454 : opcode = x86AltOpcodeOf(instInfo);
2455 0 : goto EmitFpuOp;
2456 : }
2457 :
2458 0 : if (isign3 == ENC_OPS1(Mem)) {
2459 : // Clear compressed displacement before going to EmitX86M.
2460 : opcode &= ~uint32_t(Opcode::kCDSHL_Mask);
2461 :
2462 : rmRel = &o0;
2463 0 : goto EmitX86M;
2464 : }
2465 : break;
2466 :
2467 : // Ext Instructions (Legacy Extensions)
2468 : // ------------------------------------
2469 :
2470 0 : case InstDB::kEncodingExtPextrw:
2471 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2472 : opcode.add66hIf(Reg::isXmm(o1));
2473 :
2474 : immValue = o2.as<Imm>().value();
2475 : immSize = 1;
2476 :
2477 : opReg = o0.id();
2478 : rbReg = o1.id();
2479 0 : goto EmitX86R;
2480 : }
2481 :
2482 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2483 : // Secondary opcode of 'pextrw' instruction (SSE4.1).
2484 : opcode = x86AltOpcodeOf(instInfo);
2485 : opcode.add66hIf(Reg::isXmm(o1));
2486 :
2487 : immValue = o2.as<Imm>().value();
2488 : immSize = 1;
2489 :
2490 : opReg = o1.id();
2491 : rmRel = &o0;
2492 0 : goto EmitX86M;
2493 : }
2494 : break;
2495 :
2496 0 : case InstDB::kEncodingExtExtract:
2497 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2498 : opcode.add66hIf(Reg::isXmm(o1));
2499 :
2500 : immValue = o2.as<Imm>().value();
2501 : immSize = 1;
2502 :
2503 : opReg = o1.id();
2504 : rbReg = o0.id();
2505 0 : goto EmitX86R;
2506 : }
2507 :
2508 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
2509 : opcode.add66hIf(Reg::isXmm(o1));
2510 :
2511 : immValue = o2.as<Imm>().value();
2512 : immSize = 1;
2513 :
2514 : opReg = o1.id();
2515 : rmRel = &o0;
2516 0 : goto EmitX86M;
2517 : }
2518 : break;
2519 :
2520 0 : case InstDB::kEncodingExtMov:
2521 : // GP|MM|XMM <- GP|MM|XMM
2522 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2523 : opReg = o0.id();
2524 : rbReg = o1.id();
2525 :
2526 0 : if (!Support::test(options, InstOptions::kX86_ModMR) || !instInfo->_altOpcodeIndex)
2527 0 : goto EmitX86R;
2528 :
2529 : opcode = x86AltOpcodeOf(instInfo);
2530 : std::swap(opReg, rbReg);
2531 0 : goto EmitX86R;
2532 : }
2533 :
2534 : // GP|MM|XMM <- Mem
2535 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2536 : opReg = o0.id();
2537 : rmRel = &o1;
2538 0 : goto EmitX86M;
2539 : }
2540 :
2541 : // The following instruction uses opcode[1].
2542 : opcode = x86AltOpcodeOf(instInfo);
2543 :
2544 : // Mem <- GP|MM|XMM
2545 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2546 : opReg = o1.id();
2547 : rmRel = &o0;
2548 0 : goto EmitX86M;
2549 : }
2550 : break;
2551 :
2552 0 : case InstDB::kEncodingExtMovbe:
2553 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2554 0 : if (o0.size() == 1)
2555 0 : goto InvalidInstruction;
2556 :
2557 : opcode.addPrefixBySize(o0.size());
2558 : opReg = o0.id();
2559 : rmRel = &o1;
2560 0 : goto EmitX86M;
2561 : }
2562 :
2563 : // The following instruction uses the secondary opcode.
2564 : opcode = x86AltOpcodeOf(instInfo);
2565 :
2566 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2567 0 : if (o1.size() == 1)
2568 0 : goto InvalidInstruction;
2569 :
2570 : opcode.addPrefixBySize(o1.size());
2571 : opReg = o1.id();
2572 : rmRel = &o0;
2573 0 : goto EmitX86M;
2574 : }
2575 : break;
2576 :
2577 : case InstDB::kEncodingExtMovd:
2578 0 : CaseExtMovd:
2579 : opReg = o0.id();
2580 : opcode.add66hIf(Reg::isXmm(o0));
2581 :
2582 : // MM/XMM <- Gp
2583 0 : if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o1)) {
2584 : rbReg = o1.id();
2585 0 : goto EmitX86R;
2586 : }
2587 :
2588 : // MM/XMM <- Mem
2589 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2590 : rmRel = &o1;
2591 0 : goto EmitX86M;
2592 : }
2593 :
2594 : // The following instructions use the secondary opcode.
2595 : opcode &= Opcode::kW;
2596 : opcode |= x86AltOpcodeOf(instInfo);
2597 : opReg = o1.id();
2598 : opcode.add66hIf(Reg::isXmm(o1));
2599 :
2600 : // GP <- MM/XMM
2601 0 : if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o0)) {
2602 : rbReg = o0.id();
2603 0 : goto EmitX86R;
2604 : }
2605 :
2606 : // Mem <- MM/XMM
2607 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2608 : rmRel = &o0;
2609 0 : goto EmitX86M;
2610 : }
2611 : break;
2612 :
2613 0 : case InstDB::kEncodingExtMovq:
2614 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2615 : opReg = o0.id();
2616 : rbReg = o1.id();
2617 :
2618 : // MM <- MM
2619 0 : if (Reg::isMm(o0) && Reg::isMm(o1)) {
2620 : opcode = Opcode::k000F00 | 0x6F;
2621 :
2622 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
2623 0 : goto EmitX86R;
2624 :
2625 : opcode += 0x10;
2626 : std::swap(opReg, rbReg);
2627 0 : goto EmitX86R;
2628 : }
2629 :
2630 : // XMM <- XMM
2631 0 : if (Reg::isXmm(o0) && Reg::isXmm(o1)) {
2632 : opcode = Opcode::kF30F00 | 0x7E;
2633 :
2634 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
2635 0 : goto EmitX86R;
2636 :
2637 : opcode = Opcode::k660F00 | 0xD6;
2638 : std::swap(opReg, rbReg);
2639 0 : goto EmitX86R;
2640 : }
2641 : }
2642 :
2643 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2644 : opReg = o0.id();
2645 : rmRel = &o1;
2646 :
2647 : // MM <- Mem
2648 0 : if (Reg::isMm(o0)) {
2649 : opcode = Opcode::k000F00 | 0x6F;
2650 0 : goto EmitX86M;
2651 : }
2652 :
2653 : // XMM <- Mem
2654 0 : if (Reg::isXmm(o0)) {
2655 : opcode = Opcode::kF30F00 | 0x7E;
2656 0 : goto EmitX86M;
2657 : }
2658 : }
2659 :
2660 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2661 : opReg = o1.id();
2662 : rmRel = &o0;
2663 :
2664 : // Mem <- MM
2665 0 : if (Reg::isMm(o1)) {
2666 : opcode = Opcode::k000F00 | 0x7F;
2667 0 : goto EmitX86M;
2668 : }
2669 :
2670 : // Mem <- XMM
2671 0 : if (Reg::isXmm(o1)) {
2672 : opcode = Opcode::k660F00 | 0xD6;
2673 0 : goto EmitX86M;
2674 : }
2675 : }
2676 :
2677 : // MOVQ in other case is simply a MOVD instruction promoted to 64-bit.
2678 : opcode |= Opcode::kW;
2679 0 : goto CaseExtMovd;
2680 :
2681 : case InstDB::kEncodingExtRm_XMM0:
2682 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !Reg::isXmm(o2, 0)))
2683 0 : goto InvalidInstruction;
2684 :
2685 0 : isign3 &= 0x3F;
2686 0 : goto CaseExtRm;
2687 :
2688 : case InstDB::kEncodingExtRm_ZDI:
2689 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, Gp::kIdDi)))
2690 0 : goto InvalidInstruction;
2691 :
2692 0 : isign3 &= 0x3F;
2693 0 : goto CaseExtRm;
2694 :
2695 : case InstDB::kEncodingExtRm_Wx:
2696 0 : opcode.addWIf(o1.size() == 8);
2697 : ASMJIT_FALLTHROUGH;
2698 :
2699 0 : case InstDB::kEncodingExtRm_Wx_GpqOnly:
2700 : opcode.addWIf(Reg::isGpq(o0));
2701 : ASMJIT_FALLTHROUGH;
2702 :
2703 : case InstDB::kEncodingExtRm:
2704 0 : CaseExtRm:
2705 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2706 : opReg = o0.id();
2707 : rbReg = o1.id();
2708 0 : goto EmitX86R;
2709 : }
2710 :
2711 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2712 : opReg = o0.id();
2713 : rmRel = &o1;
2714 0 : goto EmitX86M;
2715 : }
2716 : break;
2717 :
2718 0 : case InstDB::kEncodingExtRm_P:
2719 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2720 0 : opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
2721 :
2722 : opReg = o0.id();
2723 : rbReg = o1.id();
2724 0 : goto EmitX86R;
2725 : }
2726 :
2727 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2728 : opcode.add66hIf(Reg::isXmm(o0));
2729 :
2730 : opReg = o0.id();
2731 : rmRel = &o1;
2732 0 : goto EmitX86M;
2733 : }
2734 : break;
2735 :
2736 0 : case InstDB::kEncodingExtRmRi:
2737 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2738 : opReg = o0.id();
2739 : rbReg = o1.id();
2740 0 : goto EmitX86R;
2741 : }
2742 :
2743 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2744 : opReg = o0.id();
2745 : rmRel = &o1;
2746 0 : goto EmitX86M;
2747 : }
2748 :
2749 : // The following instruction uses the secondary opcode.
2750 : opcode = x86AltOpcodeOf(instInfo);
2751 : opReg = opcode.extractModO();
2752 :
2753 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2754 : immValue = o1.as<Imm>().value();
2755 : immSize = 1;
2756 :
2757 : rbReg = o0.id();
2758 0 : goto EmitX86R;
2759 : }
2760 : break;
2761 :
2762 0 : case InstDB::kEncodingExtRmRi_P:
2763 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2764 0 : opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
2765 :
2766 : opReg = o0.id();
2767 : rbReg = o1.id();
2768 0 : goto EmitX86R;
2769 : }
2770 :
2771 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2772 : opcode.add66hIf(Reg::isXmm(o0));
2773 :
2774 : opReg = o0.id();
2775 : rmRel = &o1;
2776 0 : goto EmitX86M;
2777 : }
2778 :
2779 : // The following instruction uses the secondary opcode.
2780 : opcode = x86AltOpcodeOf(instInfo);
2781 : opReg = opcode.extractModO();
2782 :
2783 0 : if (isign3 == ENC_OPS2(Reg, Imm)) {
2784 : opcode.add66hIf(Reg::isXmm(o0));
2785 :
2786 : immValue = o1.as<Imm>().value();
2787 : immSize = 1;
2788 :
2789 : rbReg = o0.id();
2790 0 : goto EmitX86R;
2791 : }
2792 : break;
2793 :
2794 : case InstDB::kEncodingExtRmi:
2795 : immValue = o2.as<Imm>().value();
2796 : immSize = 1;
2797 :
2798 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2799 : opReg = o0.id();
2800 : rbReg = o1.id();
2801 0 : goto EmitX86R;
2802 : }
2803 :
2804 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
2805 : opReg = o0.id();
2806 : rmRel = &o1;
2807 0 : goto EmitX86M;
2808 : }
2809 : break;
2810 :
2811 : case InstDB::kEncodingExtRmi_P:
2812 : immValue = o2.as<Imm>().value();
2813 : immSize = 1;
2814 :
2815 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
2816 0 : opcode.add66hIf(Reg::isXmm(o0) | Reg::isXmm(o1));
2817 :
2818 : opReg = o0.id();
2819 : rbReg = o1.id();
2820 0 : goto EmitX86R;
2821 : }
2822 :
2823 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
2824 : opcode.add66hIf(Reg::isXmm(o0));
2825 :
2826 : opReg = o0.id();
2827 : rmRel = &o1;
2828 0 : goto EmitX86M;
2829 : }
2830 : break;
2831 :
2832 : // Extrq & Insertq (SSE4A)
2833 : // -----------------------
2834 :
2835 : case InstDB::kEncodingExtExtrq:
2836 : opReg = o0.id();
2837 : rbReg = o1.id();
2838 :
2839 0 : if (isign3 == ENC_OPS2(Reg, Reg))
2840 0 : goto EmitX86R;
2841 :
2842 0 : if (isign3 == ENC_OPS3(Reg, Imm, Imm)) {
2843 : // This variant of the instruction uses the secondary opcode.
2844 : opcode = x86AltOpcodeOf(instInfo);
2845 : rbReg = opReg;
2846 : opReg = opcode.extractModO();
2847 :
2848 0 : immValue = (uint32_t(o1.as<Imm>().valueAs<uint8_t>()) ) +
2849 0 : (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) << 8) ;
2850 : immSize = 2;
2851 0 : goto EmitX86R;
2852 : }
2853 : break;
2854 :
2855 0 : case InstDB::kEncodingExtInsertq: {
2856 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
2857 0 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
2858 :
2859 : opReg = o0.id();
2860 : rbReg = o1.id();
2861 :
2862 0 : if (isign4 == ENC_OPS2(Reg, Reg))
2863 0 : goto EmitX86R;
2864 :
2865 0 : if (isign4 == ENC_OPS4(Reg, Reg, Imm, Imm)) {
2866 : // This variant of the instruction uses the secondary opcode.
2867 : opcode = x86AltOpcodeOf(instInfo);
2868 :
2869 0 : immValue = (uint32_t(o2.as<Imm>().valueAs<uint8_t>()) ) +
2870 0 : (uint32_t(o3.as<Imm>().valueAs<uint8_t>()) << 8) ;
2871 : immSize = 2;
2872 0 : goto EmitX86R;
2873 : }
2874 : break;
2875 : }
2876 :
2877 : // 3DNOW Instructions
2878 : // ------------------
2879 :
2880 0 : case InstDB::kEncodingExt3dNow:
2881 : // Every 3dNow instruction starts with 0x0F0F and the actual opcode is
2882 : // stored as 8-bit immediate.
2883 0 : immValue = opcode.v & 0xFFu;
2884 : immSize = 1;
2885 :
2886 : opcode = Opcode::k000F00 | 0x0F;
2887 : opReg = o0.id();
2888 :
2889 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2890 : rbReg = o1.id();
2891 0 : goto EmitX86R;
2892 : }
2893 :
2894 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2895 : rmRel = &o1;
2896 0 : goto EmitX86M;
2897 : }
2898 : break;
2899 :
2900 : // VEX/EVEX Instructions
2901 : // ---------------------
2902 :
2903 0 : case InstDB::kEncodingVexOp:
2904 0 : goto EmitVexOp;
2905 :
2906 0 : case InstDB::kEncodingVexOpMod:
2907 : rbReg = 0;
2908 0 : goto EmitVexEvexR;
2909 :
2910 0 : case InstDB::kEncodingVexKmov:
2911 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2912 : opReg = o0.id();
2913 : rbReg = o1.id();
2914 :
2915 : // Form 'k, reg'.
2916 0 : if (Reg::isGp(o1)) {
2917 : opcode = x86AltOpcodeOf(instInfo);
2918 0 : goto EmitVexEvexR;
2919 : }
2920 :
2921 : // Form 'reg, k'.
2922 0 : if (Reg::isGp(o0)) {
2923 0 : opcode = x86AltOpcodeOf(instInfo) + 1;
2924 0 : goto EmitVexEvexR;
2925 : }
2926 :
2927 : // Form 'k, k'.
2928 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
2929 0 : goto EmitVexEvexR;
2930 :
2931 : opcode.add(1);
2932 : std::swap(opReg, rbReg);
2933 0 : goto EmitVexEvexR;
2934 : }
2935 :
2936 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
2937 : opReg = o0.id();
2938 : rmRel = &o1;
2939 :
2940 0 : goto EmitVexEvexM;
2941 : }
2942 :
2943 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2944 : opcode.add(1);
2945 : opReg = o1.id();
2946 : rmRel = &o0;
2947 0 : goto EmitVexEvexM;
2948 : }
2949 : break;
2950 :
2951 0 : case InstDB::kEncodingVexR_Wx:
2952 0 : if (isign3 == ENC_OPS1(Reg)) {
2953 : rbReg = o0.id();
2954 : opcode.addWIf(o0.as<Reg>().isGpq());
2955 0 : goto EmitVexEvexR;
2956 : }
2957 : break;
2958 :
2959 0 : case InstDB::kEncodingVexM:
2960 0 : if (isign3 == ENC_OPS1(Mem)) {
2961 : rmRel = &o0;
2962 0 : goto EmitVexEvexM;
2963 : }
2964 : break;
2965 :
2966 0 : case InstDB::kEncodingVexM_VM:
2967 0 : if (isign3 == ENC_OPS1(Mem)) {
2968 : rmRel = &o0;
2969 0 : goto EmitVexEvexM;
2970 : }
2971 : break;
2972 :
2973 : case InstDB::kEncodingVexMr_Lx:
2974 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
2975 :
2976 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
2977 : opReg = o1.id();
2978 : rbReg = o0.id();
2979 0 : goto EmitVexEvexR;
2980 : }
2981 :
2982 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2983 : opReg = o1.id();
2984 : rmRel = &o0;
2985 0 : goto EmitVexEvexM;
2986 : }
2987 : break;
2988 :
2989 0 : case InstDB::kEncodingVexMr_VM:
2990 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
2991 : opcode |= Support::max(x86OpcodeLByVMem(o0), x86OpcodeLBySize(o1.size()));
2992 :
2993 : opReg = o1.id();
2994 : rmRel = &o0;
2995 0 : goto EmitVexEvexM;
2996 : }
2997 : break;
2998 :
2999 0 : case InstDB::kEncodingVexMri_Vpextrw:
3000 : // Use 'vpextrw reg, xmm1, i8' when possible.
3001 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3002 : opcode = Opcode::k660F00 | 0xC5;
3003 :
3004 : opReg = o0.id();
3005 : rbReg = o1.id();
3006 :
3007 : immValue = o2.as<Imm>().value();
3008 : immSize = 1;
3009 0 : goto EmitVexEvexR;
3010 : }
3011 :
3012 0 : goto CaseVexMri;
3013 :
3014 : case InstDB::kEncodingVexMri_Lx:
3015 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3016 : ASMJIT_FALLTHROUGH;
3017 :
3018 : case InstDB::kEncodingVexMri:
3019 0 : CaseVexMri:
3020 : immValue = o2.as<Imm>().value();
3021 : immSize = 1;
3022 :
3023 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3024 : opReg = o1.id();
3025 : rbReg = o0.id();
3026 0 : goto EmitVexEvexR;
3027 : }
3028 :
3029 0 : if (isign3 == ENC_OPS3(Mem, Reg, Imm)) {
3030 : opReg = o1.id();
3031 : rmRel = &o0;
3032 0 : goto EmitVexEvexM;
3033 : }
3034 : break;
3035 :
3036 : case InstDB::kEncodingVexRm_ZDI:
3037 0 : if (ASMJIT_UNLIKELY(!o2.isNone() && !x86IsImplicitMem(o2, Gp::kIdDi)))
3038 0 : goto InvalidInstruction;
3039 :
3040 0 : isign3 &= 0x3F;
3041 0 : goto CaseVexRm;
3042 :
3043 : case InstDB::kEncodingVexRm_Wx:
3044 0 : opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
3045 0 : goto CaseVexRm;
3046 :
3047 : case InstDB::kEncodingVexRm_Lx_Narrow:
3048 0 : if (o1.size())
3049 : opcode |= x86OpcodeLBySize(o1.size());
3050 0 : else if (o0.size() == 32)
3051 : opcode |= Opcode::kLL_2;
3052 0 : goto CaseVexRm;
3053 :
3054 0 : case InstDB::kEncodingVexRm_Lx_Bcst:
3055 0 : if (isign3 == ENC_OPS2(Reg, Reg) && Reg::isGp(o1.as<Reg>())) {
3056 0 : opcode = x86AltOpcodeOf(instInfo) | x86OpcodeLBySize(o0.size() | o1.size());
3057 : opReg = o0.id();
3058 : rbReg = o1.id();
3059 0 : goto EmitVexEvexR;
3060 : }
3061 : ASMJIT_FALLTHROUGH;
3062 :
3063 : case InstDB::kEncodingVexRm_Lx:
3064 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3065 : ASMJIT_FALLTHROUGH;
3066 :
3067 : case InstDB::kEncodingVexRm:
3068 0 : CaseVexRm:
3069 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3070 : opReg = o0.id();
3071 : rbReg = o1.id();
3072 0 : goto EmitVexEvexR;
3073 : }
3074 :
3075 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3076 : opReg = o0.id();
3077 : rmRel = &o1;
3078 0 : goto EmitVexEvexM;
3079 : }
3080 : break;
3081 :
3082 0 : case InstDB::kEncodingVexRm_VM:
3083 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3084 : opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size()));
3085 : opReg = o0.id();
3086 : rmRel = &o1;
3087 0 : goto EmitVexEvexM;
3088 : }
3089 : break;
3090 :
3091 0 : case InstDB::kEncodingVexRm_T1_4X: {
3092 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3093 : const Operand_& o4 = opExt[EmitterUtils::kOp4];
3094 0 : const Operand_& o5 = opExt[EmitterUtils::kOp5];
3095 :
3096 0 : if (Reg::isVec(o0) && Reg::isVec(o1) && Reg::isVec(o2) && Reg::isVec(o3) && Reg::isVec(o4) && o5.isMem()) {
3097 : // Registers [o1, o2, o3, o4] must start aligned and must be consecutive.
3098 : uint32_t i1 = o1.id();
3099 : uint32_t i2 = o2.id();
3100 : uint32_t i3 = o3.id();
3101 : uint32_t i4 = o4.id();
3102 :
3103 0 : if (ASMJIT_UNLIKELY((i1 & 0x3) != 0 || i2 != i1 + 1 || i3 != i1 + 2 || i4 != i1 + 3))
3104 0 : goto NotConsecutiveRegs;
3105 :
3106 : opReg = x86PackRegAndVvvvv(o0.id(), i1);
3107 : rmRel = &o5;
3108 0 : goto EmitVexEvexM;
3109 : }
3110 : break;
3111 : }
3112 :
3113 : case InstDB::kEncodingVexRmi_Wx:
3114 0 : opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
3115 0 : goto CaseVexRmi;
3116 :
3117 : case InstDB::kEncodingVexRmi_Lx:
3118 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3119 : ASMJIT_FALLTHROUGH;
3120 :
3121 : case InstDB::kEncodingVexRmi:
3122 0 : CaseVexRmi:
3123 : immValue = o2.as<Imm>().value();
3124 : immSize = 1;
3125 :
3126 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3127 : opReg = o0.id();
3128 : rbReg = o1.id();
3129 0 : goto EmitVexEvexR;
3130 : }
3131 :
3132 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3133 : opReg = o0.id();
3134 : rmRel = &o1;
3135 0 : goto EmitVexEvexM;
3136 : }
3137 : break;
3138 :
3139 : case InstDB::kEncodingVexRvm:
3140 102527 : CaseVexRvm:
3141 102527 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3142 111048 : CaseVexRvm_R:
3143 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3144 : rbReg = o2.id();
3145 111048 : goto EmitVexEvexR;
3146 : }
3147 :
3148 22286 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3149 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3150 : rmRel = &o2;
3151 22286 : goto EmitVexEvexM;
3152 : }
3153 : break;
3154 :
3155 0 : case InstDB::kEncodingVexRvm_ZDX_Wx: {
3156 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3157 0 : if (ASMJIT_UNLIKELY(!o3.isNone() && !Reg::isGp(o3, Gp::kIdDx)))
3158 0 : goto InvalidInstruction;
3159 : ASMJIT_FALLTHROUGH;
3160 : }
3161 :
3162 : case InstDB::kEncodingVexRvm_Wx: {
3163 0 : opcode.addWIf(Reg::isGpq(o0) | (o2.size() == 8));
3164 0 : goto CaseVexRvm;
3165 : }
3166 :
3167 : case InstDB::kEncodingVexRvm_Lx_KEvex: {
3168 : opcode.forceEvexIf(Reg::isKReg(o0));
3169 : ASMJIT_FALLTHROUGH;
3170 : }
3171 :
3172 6539 : case InstDB::kEncodingVexRvm_Lx: {
3173 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3174 6539 : goto CaseVexRvm;
3175 : }
3176 :
3177 0 : case InstDB::kEncodingVexRvm_Lx_2xK: {
3178 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3179 : // Two registers are encoded as a single register.
3180 : // - First K register must be even.
3181 : // - Second K register must be first+1.
3182 0 : if ((o0.id() & 1) != 0 || o0.id() + 1 != o1.id())
3183 0 : goto InvalidPhysId;
3184 :
3185 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3186 :
3187 : opcode |= x86OpcodeLBySize(o2.size());
3188 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3189 :
3190 0 : if (o3.isReg()) {
3191 : rbReg = o3.id();
3192 0 : goto EmitVexEvexR;
3193 : }
3194 :
3195 0 : if (o3.isMem()) {
3196 : rmRel = &o3;
3197 0 : goto EmitVexEvexM;
3198 : }
3199 : }
3200 : break;
3201 : }
3202 :
3203 : case InstDB::kEncodingVexRvmr_Lx: {
3204 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3205 : ASMJIT_FALLTHROUGH;
3206 : }
3207 :
3208 157 : case InstDB::kEncodingVexRvmr: {
3209 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3210 157 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3211 :
3212 157 : immValue = o3.id() << 4;
3213 : immSize = 1;
3214 :
3215 157 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3216 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3217 : rbReg = o2.id();
3218 157 : goto EmitVexEvexR;
3219 : }
3220 :
3221 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3222 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3223 : rmRel = &o2;
3224 0 : goto EmitVexEvexM;
3225 : }
3226 : break;
3227 : }
3228 :
3229 : case InstDB::kEncodingVexRvmi_KEvex:
3230 : opcode.forceEvexIf(Reg::isKReg(o0));
3231 1970 : goto VexRvmi;
3232 :
3233 : case InstDB::kEncodingVexRvmi_Lx_KEvex:
3234 : opcode.forceEvexIf(Reg::isKReg(o0));
3235 : ASMJIT_FALLTHROUGH;
3236 :
3237 0 : case InstDB::kEncodingVexRvmi_Lx:
3238 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3239 : ASMJIT_FALLTHROUGH;
3240 :
3241 : case InstDB::kEncodingVexRvmi:
3242 1976 : VexRvmi:
3243 : {
3244 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3245 1976 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3246 :
3247 : immValue = o3.as<Imm>().value();
3248 : immSize = 1;
3249 :
3250 1976 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
3251 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3252 : rbReg = o2.id();
3253 1567 : goto EmitVexEvexR;
3254 : }
3255 :
3256 409 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Imm)) {
3257 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3258 : rmRel = &o2;
3259 409 : goto EmitVexEvexM;
3260 : }
3261 : break;
3262 : }
3263 :
3264 : case InstDB::kEncodingVexRmv_Wx:
3265 0 : opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o2));
3266 : ASMJIT_FALLTHROUGH;
3267 :
3268 0 : case InstDB::kEncodingVexRmv:
3269 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3270 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3271 : rbReg = o1.id();
3272 0 : goto EmitVexEvexR;
3273 : }
3274 :
3275 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3276 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3277 : rmRel = &o1;
3278 0 : goto EmitVexEvexM;
3279 : }
3280 : break;
3281 :
3282 0 : case InstDB::kEncodingVexRmvRm_VM:
3283 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3284 : opcode = x86AltOpcodeOf(instInfo);
3285 : opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size()));
3286 :
3287 : opReg = o0.id();
3288 : rmRel = &o1;
3289 0 : goto EmitVexEvexM;
3290 : }
3291 : ASMJIT_FALLTHROUGH;
3292 :
3293 : case InstDB::kEncodingVexRmv_VM:
3294 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3295 : opcode |= Support::max(x86OpcodeLByVMem(o1), x86OpcodeLBySize(o0.size() | o2.size()));
3296 :
3297 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3298 : rmRel = &o1;
3299 0 : goto EmitVexEvexM;
3300 : }
3301 : break;
3302 :
3303 :
3304 0 : case InstDB::kEncodingVexRmvi: {
3305 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3306 0 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3307 :
3308 : immValue = o3.as<Imm>().value();
3309 : immSize = 1;
3310 :
3311 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Imm)) {
3312 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3313 : rbReg = o1.id();
3314 0 : goto EmitVexEvexR;
3315 : }
3316 :
3317 0 : if (isign4 == ENC_OPS4(Reg, Mem, Reg, Imm)) {
3318 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3319 : rmRel = &o1;
3320 0 : goto EmitVexEvexM;
3321 : }
3322 : break;
3323 : }
3324 :
3325 0 : case InstDB::kEncodingVexMovdMovq:
3326 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3327 0 : if (Reg::isGp(o0)) {
3328 : opcode = x86AltOpcodeOf(instInfo);
3329 : opcode.addWBySize(o0.size());
3330 : opReg = o1.id();
3331 : rbReg = o0.id();
3332 0 : goto EmitVexEvexR;
3333 : }
3334 :
3335 0 : if (Reg::isGp(o1)) {
3336 : opcode.addWBySize(o1.size());
3337 : opReg = o0.id();
3338 : rbReg = o1.id();
3339 0 : goto EmitVexEvexR;
3340 : }
3341 :
3342 : // If this is a 'W' version (movq) then allow also vmovq 'xmm|xmm' form.
3343 0 : if (opcode & Opcode::kEvex_W_1) {
3344 : opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
3345 : opcode |= (Opcode::kF30F00 | 0x7E);
3346 :
3347 : opReg = o0.id();
3348 : rbReg = o1.id();
3349 0 : goto EmitVexEvexR;
3350 : }
3351 : }
3352 :
3353 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3354 0 : if (opcode & Opcode::kEvex_W_1) {
3355 : opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
3356 : opcode |= (Opcode::kF30F00 | 0x7E);
3357 : }
3358 :
3359 : opReg = o0.id();
3360 : rmRel = &o1;
3361 0 : goto EmitVexEvexM;
3362 : }
3363 :
3364 : // The following instruction uses the secondary opcode.
3365 : opcode = x86AltOpcodeOf(instInfo);
3366 :
3367 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3368 0 : if (opcode & Opcode::kEvex_W_1) {
3369 : opcode &= ~(Opcode::kPP_VEXMask | Opcode::kMM_Mask | 0xFF);
3370 : opcode |= (Opcode::k660F00 | 0xD6);
3371 : }
3372 :
3373 : opReg = o1.id();
3374 : rmRel = &o0;
3375 0 : goto EmitVexEvexM;
3376 : }
3377 : break;
3378 :
3379 : case InstDB::kEncodingVexRmMr_Lx:
3380 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3381 : ASMJIT_FALLTHROUGH;
3382 :
3383 1785 : case InstDB::kEncodingVexRmMr:
3384 1785 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3385 : opReg = o0.id();
3386 : rbReg = o1.id();
3387 1785 : goto EmitVexEvexR;
3388 : }
3389 :
3390 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3391 : opReg = o0.id();
3392 : rmRel = &o1;
3393 0 : goto EmitVexEvexM;
3394 : }
3395 :
3396 : // The following instruction uses the secondary opcode.
3397 : opcode &= Opcode::kLL_Mask;
3398 : opcode |= x86AltOpcodeOf(instInfo);
3399 :
3400 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3401 : opReg = o1.id();
3402 : rmRel = &o0;
3403 0 : goto EmitVexEvexM;
3404 : }
3405 : break;
3406 :
3407 0 : case InstDB::kEncodingVexRvmRmv:
3408 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3409 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3410 : rbReg = o1.id();
3411 :
3412 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
3413 0 : goto EmitVexEvexR;
3414 :
3415 : opcode.addW();
3416 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3417 : rbReg = o2.id();
3418 0 : goto EmitVexEvexR;
3419 : }
3420 :
3421 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3422 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3423 : rmRel = &o1;
3424 0 : goto EmitVexEvexM;
3425 : }
3426 :
3427 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3428 : opcode.addW();
3429 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3430 : rmRel = &o2;
3431 0 : goto EmitVexEvexM;
3432 : }
3433 : break;
3434 :
3435 : case InstDB::kEncodingVexRvmRmi_Lx:
3436 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3437 : ASMJIT_FALLTHROUGH;
3438 :
3439 0 : case InstDB::kEncodingVexRvmRmi:
3440 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3441 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3442 : rbReg = o2.id();
3443 0 : goto EmitVexEvexR;
3444 : }
3445 :
3446 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3447 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3448 : rmRel = &o2;
3449 0 : goto EmitVexEvexM;
3450 : }
3451 :
3452 : // The following instructions use the secondary opcode.
3453 : opcode &= Opcode::kLL_Mask;
3454 : opcode |= x86AltOpcodeOf(instInfo);
3455 :
3456 : immValue = o2.as<Imm>().value();
3457 : immSize = 1;
3458 :
3459 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3460 : opReg = o0.id();
3461 : rbReg = o1.id();
3462 0 : goto EmitVexEvexR;
3463 : }
3464 :
3465 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3466 : opReg = o0.id();
3467 : rmRel = &o1;
3468 0 : goto EmitVexEvexM;
3469 : }
3470 : break;
3471 :
3472 0 : case InstDB::kEncodingVexRvmRmvRmi:
3473 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3474 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3475 : rbReg = o1.id();
3476 :
3477 0 : if (!Support::test(options, InstOptions::kX86_ModMR))
3478 0 : goto EmitVexEvexR;
3479 :
3480 : opcode.addW();
3481 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3482 : rbReg = o2.id();
3483 0 : goto EmitVexEvexR;
3484 : }
3485 :
3486 0 : if (isign3 == ENC_OPS3(Reg, Mem, Reg)) {
3487 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3488 : rmRel = &o1;
3489 0 : goto EmitVexEvexM;
3490 : }
3491 :
3492 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3493 : opcode.addW();
3494 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3495 : rmRel = &o2;
3496 0 : goto EmitVexEvexM;
3497 : }
3498 :
3499 : // The following instructions use the secondary opcode.
3500 : opcode = x86AltOpcodeOf(instInfo);
3501 :
3502 : immValue = o2.as<Imm>().value();
3503 : immSize = 1;
3504 :
3505 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3506 : opReg = o0.id();
3507 : rbReg = o1.id();
3508 0 : goto EmitVexEvexR;
3509 : }
3510 :
3511 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3512 : opReg = o0.id();
3513 : rmRel = &o1;
3514 0 : goto EmitVexEvexM;
3515 : }
3516 : break;
3517 :
3518 0 : case InstDB::kEncodingVexRvmMr:
3519 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3520 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3521 : rbReg = o2.id();
3522 0 : goto EmitVexEvexR;
3523 : }
3524 :
3525 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3526 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3527 : rmRel = &o2;
3528 0 : goto EmitVexEvexM;
3529 : }
3530 :
3531 : // The following instructions use the secondary opcode.
3532 : opcode = x86AltOpcodeOf(instInfo);
3533 :
3534 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3535 : opReg = o1.id();
3536 : rbReg = o0.id();
3537 0 : goto EmitVexEvexR;
3538 : }
3539 :
3540 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3541 : opReg = o1.id();
3542 : rmRel = &o0;
3543 0 : goto EmitVexEvexM;
3544 : }
3545 : break;
3546 :
3547 : case InstDB::kEncodingVexRvmMvr_Lx:
3548 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3549 : ASMJIT_FALLTHROUGH;
3550 :
3551 0 : case InstDB::kEncodingVexRvmMvr:
3552 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3553 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3554 : rbReg = o2.id();
3555 0 : goto EmitVexEvexR;
3556 : }
3557 :
3558 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3559 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3560 : rmRel = &o2;
3561 0 : goto EmitVexEvexM;
3562 : }
3563 :
3564 : // The following instruction uses the secondary opcode.
3565 : opcode &= Opcode::kLL_Mask;
3566 : opcode |= x86AltOpcodeOf(instInfo);
3567 :
3568 0 : if (isign3 == ENC_OPS3(Mem, Reg, Reg)) {
3569 : opReg = x86PackRegAndVvvvv(o2.id(), o1.id());
3570 : rmRel = &o0;
3571 0 : goto EmitVexEvexM;
3572 : }
3573 : break;
3574 :
3575 : case InstDB::kEncodingVexRvmVmi_Lx_MEvex:
3576 : opcode.forceEvexIf(o1.isMem());
3577 : ASMJIT_FALLTHROUGH;
3578 :
3579 0 : case InstDB::kEncodingVexRvmVmi_Lx:
3580 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3581 : ASMJIT_FALLTHROUGH;
3582 :
3583 0 : case InstDB::kEncodingVexRvmVmi:
3584 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3585 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3586 : rbReg = o2.id();
3587 0 : goto EmitVexEvexR;
3588 : }
3589 :
3590 0 : if (isign3 == ENC_OPS3(Reg, Reg, Mem)) {
3591 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3592 : rmRel = &o2;
3593 0 : goto EmitVexEvexM;
3594 : }
3595 :
3596 : // The following instruction uses the secondary opcode.
3597 : opcode &= Opcode::kLL_Mask | Opcode::kMM_ForceEvex;
3598 : opcode |= x86AltOpcodeOf(instInfo);
3599 : opReg = opcode.extractModO();
3600 :
3601 : immValue = o2.as<Imm>().value();
3602 : immSize = 1;
3603 :
3604 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3605 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3606 : rbReg = o1.id();
3607 0 : goto EmitVexEvexR;
3608 : }
3609 :
3610 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3611 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3612 : rmRel = &o1;
3613 0 : goto EmitVexEvexM;
3614 : }
3615 : break;
3616 :
3617 : case InstDB::kEncodingVexVm_Wx:
3618 0 : opcode.addWIf(Reg::isGpq(o0) | Reg::isGpq(o1));
3619 : ASMJIT_FALLTHROUGH;
3620 :
3621 0 : case InstDB::kEncodingVexVm:
3622 0 : if (isign3 == ENC_OPS2(Reg, Reg)) {
3623 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3624 : rbReg = o1.id();
3625 0 : goto EmitVexEvexR;
3626 : }
3627 :
3628 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3629 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3630 : rmRel = &o1;
3631 0 : goto EmitVexEvexM;
3632 : }
3633 : break;
3634 :
3635 0 : case InstDB::kEncodingVexVmi_Lx_MEvex:
3636 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm))
3637 : opcode.forceEvex();
3638 : ASMJIT_FALLTHROUGH;
3639 :
3640 : case InstDB::kEncodingVexVmi_Lx:
3641 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3642 : ASMJIT_FALLTHROUGH;
3643 :
3644 0 : case InstDB::kEncodingVexVmi:
3645 : immValue = o2.as<Imm>().value();
3646 : immSize = 1;
3647 :
3648 0 : CaseVexVmi_AfterImm:
3649 0 : if (isign3 == ENC_OPS3(Reg, Reg, Imm)) {
3650 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3651 : rbReg = o1.id();
3652 0 : goto EmitVexEvexR;
3653 : }
3654 :
3655 0 : if (isign3 == ENC_OPS3(Reg, Mem, Imm)) {
3656 : opReg = x86PackRegAndVvvvv(opReg, o0.id());
3657 : rmRel = &o1;
3658 0 : goto EmitVexEvexM;
3659 : }
3660 : break;
3661 :
3662 : case InstDB::kEncodingVexVmi4_Wx:
3663 0 : opcode.addWIf(Reg::isGpq(o0) || o1.size() == 8);
3664 : immValue = o2.as<Imm>().value();
3665 : immSize = 4;
3666 0 : goto CaseVexVmi_AfterImm;
3667 :
3668 : case InstDB::kEncodingVexRvrmRvmr_Lx:
3669 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3670 : ASMJIT_FALLTHROUGH;
3671 :
3672 0 : case InstDB::kEncodingVexRvrmRvmr: {
3673 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3674 0 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3675 :
3676 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3677 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3678 : rbReg = o2.id();
3679 :
3680 0 : immValue = o3.id() << 4;
3681 : immSize = 1;
3682 0 : goto EmitVexEvexR;
3683 : }
3684 :
3685 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3686 : opcode.addW();
3687 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3688 : rmRel = &o3;
3689 :
3690 0 : immValue = o2.id() << 4;
3691 : immSize = 1;
3692 0 : goto EmitVexEvexM;
3693 : }
3694 :
3695 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3696 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3697 : rmRel = &o2;
3698 :
3699 0 : immValue = o3.id() << 4;
3700 : immSize = 1;
3701 0 : goto EmitVexEvexM;
3702 : }
3703 : break;
3704 : }
3705 :
3706 0 : case InstDB::kEncodingVexRvrmiRvmri_Lx: {
3707 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3708 : const Operand_& o4 = opExt[EmitterUtils::kOp4];
3709 :
3710 0 : if (ASMJIT_UNLIKELY(!o4.isImm()))
3711 0 : goto InvalidInstruction;
3712 :
3713 0 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3714 : opcode |= x86OpcodeLBySize(o0.size() | o1.size() | o2.size() | o3.size());
3715 :
3716 0 : immValue = o4.as<Imm>().valueAs<uint8_t>() & 0x0F;
3717 : immSize = 1;
3718 :
3719 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3720 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3721 : rbReg = o2.id();
3722 :
3723 0 : immValue |= o3.id() << 4;
3724 0 : goto EmitVexEvexR;
3725 : }
3726 :
3727 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3728 : opcode.addW();
3729 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3730 : rmRel = &o3;
3731 :
3732 0 : immValue |= o2.id() << 4;
3733 0 : goto EmitVexEvexM;
3734 : }
3735 :
3736 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3737 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3738 : rmRel = &o2;
3739 :
3740 0 : immValue |= o3.id() << 4;
3741 0 : goto EmitVexEvexM;
3742 : }
3743 : break;
3744 : }
3745 :
3746 150197 : case InstDB::kEncodingVexMovssMovsd:
3747 150197 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3748 30807 : goto CaseVexRvm_R;
3749 : }
3750 :
3751 119390 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3752 : opReg = o0.id();
3753 : rmRel = &o1;
3754 88508 : goto EmitVexEvexM;
3755 : }
3756 :
3757 30882 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3758 : opcode = x86AltOpcodeOf(instInfo);
3759 : opReg = o1.id();
3760 : rmRel = &o0;
3761 30882 : goto EmitVexEvexM;
3762 : }
3763 : break;
3764 :
3765 : // FMA4 Instructions
3766 : // -----------------
3767 :
3768 : case InstDB::kEncodingFma4_Lx:
3769 : // It's fine to just check the first operand, second is just for sanity.
3770 : opcode |= x86OpcodeLBySize(o0.size() | o1.size());
3771 : ASMJIT_FALLTHROUGH;
3772 :
3773 0 : case InstDB::kEncodingFma4: {
3774 : const Operand_& o3 = opExt[EmitterUtils::kOp3];
3775 0 : const uint32_t isign4 = isign3 + (uint32_t(o3.opType()) << 9);
3776 :
3777 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Reg)) {
3778 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3779 :
3780 0 : if (!Support::test(options, InstOptions::kX86_ModMR)) {
3781 : // MOD/RM - Encoding preferred by LLVM.
3782 : opcode.addW();
3783 : rbReg = o3.id();
3784 :
3785 0 : immValue = o2.id() << 4;
3786 : immSize = 1;
3787 0 : goto EmitVexEvexR;
3788 : }
3789 : else {
3790 : // MOD/MR - Alternative encoding.
3791 : rbReg = o2.id();
3792 :
3793 0 : immValue = o3.id() << 4;
3794 : immSize = 1;
3795 0 : goto EmitVexEvexR;
3796 : }
3797 : }
3798 :
3799 0 : if (isign4 == ENC_OPS4(Reg, Reg, Reg, Mem)) {
3800 : opcode.addW();
3801 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3802 : rmRel = &o3;
3803 :
3804 0 : immValue = o2.id() << 4;
3805 : immSize = 1;
3806 0 : goto EmitVexEvexM;
3807 : }
3808 :
3809 0 : if (isign4 == ENC_OPS4(Reg, Reg, Mem, Reg)) {
3810 : opReg = x86PackRegAndVvvvv(o0.id(), o1.id());
3811 : rmRel = &o2;
3812 :
3813 0 : immValue = o3.id() << 4;
3814 : immSize = 1;
3815 0 : goto EmitVexEvexM;
3816 : }
3817 : break;
3818 : }
3819 :
3820 : // AMX Instructions
3821 : // ----------------
3822 :
3823 0 : case InstDB::kEncodingAmxCfg:
3824 0 : if (isign3 == ENC_OPS1(Mem)) {
3825 : rmRel = &o0;
3826 0 : goto EmitVexEvexM;
3827 : }
3828 : break;
3829 :
3830 0 : case InstDB::kEncodingAmxR:
3831 0 : if (isign3 == ENC_OPS1(Reg)) {
3832 : opReg = o0.id();
3833 : rbReg = 0;
3834 0 : goto EmitVexEvexR;
3835 : }
3836 : break;
3837 :
3838 0 : case InstDB::kEncodingAmxRm:
3839 0 : if (isign3 == ENC_OPS2(Reg, Mem)) {
3840 : opReg = o0.id();
3841 : rmRel = &o1;
3842 0 : goto EmitVexEvexM;
3843 : }
3844 : break;
3845 :
3846 0 : case InstDB::kEncodingAmxMr:
3847 0 : if (isign3 == ENC_OPS2(Mem, Reg)) {
3848 : opReg = o1.id();
3849 : rmRel = &o0;
3850 0 : goto EmitVexEvexM;
3851 : }
3852 : break;
3853 :
3854 0 : case InstDB::kEncodingAmxRmv:
3855 0 : if (isign3 == ENC_OPS3(Reg, Reg, Reg)) {
3856 : opReg = x86PackRegAndVvvvv(o0.id(), o2.id());
3857 : rbReg = o1.id();
3858 0 : goto EmitVexEvexR;
3859 : }
3860 : break;
3861 : }
3862 :
3863 0 : goto InvalidInstruction;
3864 :
3865 : // Emit - X86 Opcode
3866 : // -----------------
3867 :
3868 0 : EmitX86OpMovAbs:
3869 0 : immSize = FastUInt8(registerSize());
3870 : writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
3871 :
3872 27492 : EmitX86Op:
3873 : // Emit mandatory instruction prefix.
3874 : writer.emitPP(opcode.v);
3875 :
3876 : // Emit REX prefix (64-bit only).
3877 : {
3878 : uint32_t rex = opcode.extractRex(options);
3879 27492 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
3880 0 : goto InvalidRexPrefix;
3881 27492 : rex &= ~kX86ByteInvalidRex & 0xFF;
3882 27492 : writer.emit8If(rex | kX86ByteRex, rex != 0);
3883 : }
3884 :
3885 : // Emit instruction opcodes.
3886 : writer.emitMMAndOpcode(opcode.v);
3887 27492 : writer.emitImmediate(uint64_t(immValue), immSize);
3888 27492 : goto EmitDone;
3889 :
3890 : // Emit - X86 - Opcode + Reg
3891 : // -------------------------
3892 :
3893 88236 : EmitX86OpReg:
3894 : // Emit mandatory instruction prefix.
3895 : writer.emitPP(opcode.v);
3896 :
3897 : // Emit REX prefix (64-bit only).
3898 : {
3899 88236 : uint32_t rex = opcode.extractRex(options) | (opReg >> 3); // Rex.B (0x01).
3900 88236 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
3901 0 : goto InvalidRexPrefix;
3902 88236 : rex &= ~kX86ByteInvalidRex & 0xFF;
3903 88236 : writer.emit8If(rex | kX86ByteRex, rex != 0);
3904 :
3905 88236 : opReg &= 0x7;
3906 : }
3907 :
3908 : // Emit instruction opcodes.
3909 : opcode += opReg;
3910 : writer.emitMMAndOpcode(opcode.v);
3911 88236 : writer.emitImmediate(uint64_t(immValue), immSize);
3912 88236 : goto EmitDone;
3913 :
3914 : // Emit - X86 - Opcode with Implicit <mem> Operand
3915 : // -----------------------------------------------
3916 :
3917 0 : EmitX86OpImplicitMem:
3918 0 : rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
3919 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
3920 0 : goto InvalidInstruction;
3921 :
3922 : // Emit mandatory instruction prefix.
3923 : writer.emitPP(opcode.v);
3924 :
3925 : // Emit REX prefix (64-bit only).
3926 : {
3927 : uint32_t rex = opcode.extractRex(options);
3928 0 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
3929 0 : goto InvalidRexPrefix;
3930 0 : rex &= ~kX86ByteInvalidRex & 0xFF;
3931 0 : writer.emit8If(rex | kX86ByteRex, rex != 0);
3932 : }
3933 :
3934 : // Emit override prefixes.
3935 : writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
3936 0 : writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
3937 :
3938 : // Emit instruction opcodes.
3939 : writer.emitMMAndOpcode(opcode.v);
3940 :
3941 : // Emit immediate value.
3942 : writer.emitImmediate(uint64_t(immValue), immSize);
3943 0 : goto EmitDone;
3944 :
3945 : // Emit - X86 - Opcode /r - Register
3946 : // ---------------------------------
3947 :
3948 19619 : EmitX86R:
3949 : // Mandatory instruction prefix.
3950 : writer.emitPP(opcode.v);
3951 :
3952 : // Emit REX prefix (64-bit only).
3953 : {
3954 19619 : uint32_t rex = opcode.extractRex(options) |
3955 19619 : ((opReg & 0x08) >> 1) | // REX.R (0x04).
3956 19619 : ((rbReg & 0x08) >> 3) ; // REX.B (0x01).
3957 :
3958 19619 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
3959 0 : goto InvalidRexPrefix;
3960 19619 : rex &= ~kX86ByteInvalidRex & 0xFF;
3961 19619 : writer.emit8If(rex | kX86ByteRex, rex != 0);
3962 :
3963 : opReg &= 0x07;
3964 19619 : rbReg &= 0x07;
3965 : }
3966 :
3967 : // Emit instruction opcodes.
3968 : writer.emitMMAndOpcode(opcode.v);
3969 :
3970 : // Emit ModR.
3971 : writer.emit8(x86EncodeMod(3, opReg, rbReg));
3972 :
3973 : // Emit immediate value.
3974 19619 : writer.emitImmediate(uint64_t(immValue), immSize);
3975 19619 : goto EmitDone;
3976 :
3977 : // Emit - X86 - Opcode /r - Memory Base
3978 : // ------------------------------------
3979 :
3980 : EmitX86RFromM:
3981 0 : rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
3982 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().hasOffset() || (rmInfo & kX86MemInfo_Index)))
3983 0 : goto InvalidInstruction;
3984 :
3985 : // Emit mandatory instruction prefix.
3986 : writer.emitPP(opcode.v);
3987 :
3988 : // Emit REX prefix (64-bit only).
3989 : {
3990 : uint32_t rex = opcode.extractRex(options) |
3991 : ((opReg & 0x08) >> 1) | // REX.R (0x04).
3992 0 : ((rbReg ) >> 3) ; // REX.B (0x01).
3993 :
3994 0 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
3995 0 : goto InvalidRexPrefix;
3996 0 : rex &= ~kX86ByteInvalidRex & 0xFF;
3997 0 : writer.emit8If(rex | kX86ByteRex, rex != 0);
3998 :
3999 : opReg &= 0x07;
4000 0 : rbReg &= 0x07;
4001 : }
4002 :
4003 : // Emit override prefixes.
4004 : writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
4005 0 : writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
4006 :
4007 : // Emit instruction opcodes.
4008 : writer.emitMMAndOpcode(opcode.v);
4009 :
4010 : // Emit ModR/M.
4011 : writer.emit8(x86EncodeMod(3, opReg, rbReg));
4012 :
4013 : // Emit immediate value.
4014 : writer.emitImmediate(uint64_t(immValue), immSize);
4015 0 : goto EmitDone;
4016 :
4017 : // Emit - X86 - Opcode /r - memory Operand
4018 : // ---------------------------------------
4019 :
4020 20 : EmitX86M:
4021 : // `rmRel` operand must be memory.
4022 : ASMJIT_ASSERT(rmRel != nullptr);
4023 : ASMJIT_ASSERT(rmRel->opType() == OperandType::kMem);
4024 : ASMJIT_ASSERT((opcode & Opcode::kCDSHL_Mask) == 0);
4025 :
4026 : // Emit override prefixes.
4027 20 : rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
4028 : writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
4029 :
4030 : memOpAOMark = writer.cursor();
4031 20 : writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
4032 :
4033 : // Emit mandatory instruction prefix.
4034 : writer.emitPP(opcode.v);
4035 :
4036 : // Emit REX prefix (64-bit only).
4037 : rbReg = rmRel->as<Mem>().baseId();
4038 : rxReg = rmRel->as<Mem>().indexId();
4039 : {
4040 : uint32_t rex;
4041 :
4042 20 : rex = (rbReg >> 3) & 0x01; // REX.B (0x01).
4043 20 : rex |= (rxReg >> 2) & 0x02; // REX.X (0x02).
4044 20 : rex |= (opReg >> 1) & 0x04; // REX.R (0x04).
4045 :
4046 20 : rex &= rmInfo;
4047 20 : rex |= opcode.extractRex(options);
4048 :
4049 20 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
4050 0 : goto InvalidRexPrefix;
4051 20 : rex &= ~kX86ByteInvalidRex & 0xFF;
4052 20 : writer.emit8If(rex | kX86ByteRex, rex != 0);
4053 :
4054 20 : opReg &= 0x07;
4055 : }
4056 :
4057 : // Emit instruction opcodes.
4058 : writer.emitMMAndOpcode(opcode.v);
4059 :
4060 : // ... Fall through ...
4061 :
4062 : // Emit - MOD/SIB
4063 : // --------------
4064 :
4065 142105 : EmitModSib:
4066 142105 : if (!(rmInfo & (kX86MemInfo_Index | kX86MemInfo_67H_X86))) {
4067 : // ==========|> [BASE + DISP8|DISP32].
4068 142105 : if (rmInfo & kX86MemInfo_BaseGp) {
4069 142105 : rbReg &= 0x7;
4070 : relOffset = rmRel->as<Mem>().offsetLo32();
4071 :
4072 : uint32_t mod = x86EncodeMod(0, opReg, rbReg);
4073 : bool forceSIB = commonInfo->isTsibOp();
4074 :
4075 142105 : if (rbReg == Gp::kIdSp || forceSIB) {
4076 : // TSIB or [XSP|R12].
4077 71131 : mod = (mod & 0xF8u) | 0x04u;
4078 71131 : if (rbReg != Gp::kIdBp && relOffset == 0) {
4079 : writer.emit8(mod);
4080 : writer.emit8(x86EncodeSib(0, 4, rbReg));
4081 : }
4082 : // TSIB or [XSP|R12 + DISP8|DISP32].
4083 : else {
4084 63178 : uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
4085 63178 : int32_t cdOffset = relOffset >> cdShift;
4086 :
4087 32614 : if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
4088 32614 : writer.emit8(mod + 0x40); // <- MOD(1, opReg, rbReg).
4089 : writer.emit8(x86EncodeSib(0, 4, rbReg));
4090 : writer.emit8(cdOffset & 0xFF);
4091 : }
4092 : else {
4093 30564 : writer.emit8(mod + 0x80); // <- MOD(2, opReg, rbReg).
4094 : writer.emit8(x86EncodeSib(0, 4, rbReg));
4095 : writer.emit32uLE(uint32_t(relOffset));
4096 : }
4097 : }
4098 : }
4099 70974 : else if (rbReg != Gp::kIdBp && relOffset == 0) {
4100 : // [BASE].
4101 : writer.emit8(mod);
4102 : }
4103 : else {
4104 : // [BASE + DISP8|DISP32].
4105 19963 : uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
4106 19963 : int32_t cdOffset = relOffset >> cdShift;
4107 :
4108 13828 : if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
4109 13828 : writer.emit8(mod + 0x40);
4110 : writer.emit8(cdOffset & 0xFF);
4111 : }
4112 : else {
4113 6135 : writer.emit8(mod + 0x80);
4114 : writer.emit32uLE(uint32_t(relOffset));
4115 : }
4116 : }
4117 : }
4118 : // ==========|> [ABSOLUTE | DISP32].
4119 0 : else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
4120 : Mem::AddrType addrType = rmRel->as<Mem>().addrType();
4121 : relOffset = rmRel->as<Mem>().offsetLo32();
4122 :
4123 0 : if (is32Bit()) {
4124 : // Explicit relative addressing doesn't work in 32-bit mode.
4125 0 : if (ASMJIT_UNLIKELY(addrType == Mem::AddrType::kRel))
4126 0 : goto InvalidAddress;
4127 :
4128 : writer.emit8(x86EncodeMod(0, opReg, 5));
4129 : writer.emit32uLE(uint32_t(relOffset));
4130 : }
4131 : else {
4132 0 : bool isOffsetI32 = rmRel->as<Mem>().offsetHi32() == (relOffset >> 31);
4133 0 : bool isOffsetU32 = rmRel->as<Mem>().offsetHi32() == 0;
4134 : uint64_t baseAddress = code()->baseAddress();
4135 :
4136 : // If relative addressing was not explicitly set then we can try to guess. By guessing we check some
4137 : // properties of the memory operand and try to base the decision on the segment prefix and the address type.
4138 0 : if (addrType == Mem::AddrType::kDefault) {
4139 0 : if (baseAddress == Globals::kNoBaseAddress) {
4140 : // Prefer absolute addressing mode if the offset is 32-bit.
4141 0 : addrType = isOffsetI32 || isOffsetU32 ? Mem::AddrType::kAbs
4142 : : Mem::AddrType::kRel;
4143 : }
4144 : else {
4145 : // Prefer absolute addressing mode if FS|GS segment override is present.
4146 0 : bool hasFsGs = rmRel->as<Mem>().segmentId() >= SReg::kIdFs;
4147 : // Prefer absolute addressing mode if this is LEA with 32-bit immediate.
4148 0 : bool isLea32 = (instId == Inst::kIdLea) && (isOffsetI32 || isOffsetU32);
4149 :
4150 0 : addrType = hasFsGs || isLea32 ? Mem::AddrType::kAbs
4151 : : Mem::AddrType::kRel;
4152 : }
4153 : }
4154 :
4155 0 : if (addrType == Mem::AddrType::kRel) {
4156 : uint32_t kModRel32Size = 5;
4157 0 : uint64_t virtualOffset = uint64_t(writer.offsetFrom(_bufferData)) + immSize + kModRel32Size;
4158 :
4159 0 : if (baseAddress == Globals::kNoBaseAddress || _section->id() != 0) {
4160 : // Create a new RelocEntry as we cannot calculate the offset right now.
4161 0 : err = _code->newRelocEntry(&re, RelocType::kAbsToRel);
4162 0 : if (ASMJIT_UNLIKELY(err))
4163 0 : goto Failed;
4164 :
4165 : writer.emit8(x86EncodeMod(0, opReg, 5));
4166 :
4167 0 : re->_sourceSectionId = _section->id();
4168 0 : re->_sourceOffset = offset();
4169 : re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 4);
4170 0 : re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
4171 0 : re->_payload = uint64_t(rmRel->as<Mem>().offset());
4172 :
4173 : writer.emit32uLE(0);
4174 0 : writer.emitImmediate(uint64_t(immValue), immSize);
4175 0 : goto EmitDone;
4176 : }
4177 : else {
4178 0 : uint64_t rip64 = baseAddress + _section->offset() + virtualOffset;
4179 0 : uint64_t rel64 = uint64_t(rmRel->as<Mem>().offset()) - rip64;
4180 :
4181 0 : if (Support::isInt32(int64_t(rel64))) {
4182 : writer.emit8(x86EncodeMod(0, opReg, 5));
4183 0 : writer.emit32uLE(uint32_t(rel64 & 0xFFFFFFFFu));
4184 0 : writer.emitImmediate(uint64_t(immValue), immSize);
4185 0 : goto EmitDone;
4186 : }
4187 : else {
4188 : // We must check the original address type as we have modified
4189 : // `addrType`. We failed if the original address type is 'rel'.
4190 0 : if (ASMJIT_UNLIKELY(rmRel->as<Mem>().isRel()))
4191 0 : goto InvalidAddress;
4192 : }
4193 : }
4194 : }
4195 :
4196 : // Handle unsigned 32-bit address that doesn't work with sign extension. Consider the following instructions:
4197 : //
4198 : // 1. lea rax, [-1] - Sign extended to 0xFFFFFFFFFFFFFFFF
4199 : // 2. lea rax, [0xFFFFFFFF] - Zero extended to 0x00000000FFFFFFFF
4200 : // 3. add rax, [-1] - Sign extended to 0xFFFFFFFFFFFFFFFF
4201 : // 4. add rax, [0xFFFFFFFF] - Zero extended to 0x00000000FFFFFFFF
4202 : //
4203 : // Sign extension is naturally performed by the CPU so we don't have to bother, however, zero extension
4204 : // requires address-size override prefix, which we probably don't have at this moment. So to make the address
4205 : // valid we need to insert it at `memOpAOMark` if it's not already there.
4206 : //
4207 : // If this is 'lea' instruction then it's possible to remove REX.W part from REX prefix (if it's there), which
4208 : // would be one-byte shorter than inserting address-size override.
4209 : //
4210 : // NOTE: If we don't do this then these instructions are unencodable.
4211 0 : if (!isOffsetI32) {
4212 : // 64-bit absolute address is unencodable.
4213 0 : if (ASMJIT_UNLIKELY(!isOffsetU32))
4214 0 : goto InvalidAddress64Bit;
4215 :
4216 : // We only patch the existing code if we don't have address-size override.
4217 0 : if (*memOpAOMark != 0x67) {
4218 0 : if (instId == Inst::kIdLea) {
4219 : // LEA: Remove REX.W, if present. This is easy as we know that 'lea' doesn't use any PP prefix so if REX
4220 : // prefix was emitted it would be at `memOpAOMark`.
4221 : uint32_t rex = *memOpAOMark;
4222 0 : if (rex & kX86ByteRex) {
4223 : rex &= (~kX86ByteRexW) & 0xFF;
4224 0 : *memOpAOMark = uint8_t(rex);
4225 :
4226 : // We can remove the REX prefix completely if it was not forced.
4227 0 : if (rex == kX86ByteRex && !Support::test(options, InstOptions::kX86_Rex))
4228 : writer.remove8(memOpAOMark);
4229 : }
4230 : }
4231 : else {
4232 : // Any other instruction: Insert address-size override prefix.
4233 : writer.insert8(memOpAOMark, 0x67);
4234 : }
4235 : }
4236 : }
4237 :
4238 : // Emit 32-bit absolute address.
4239 : writer.emit8(x86EncodeMod(0, opReg, 4));
4240 : writer.emit8(x86EncodeSib(0, 4, 5));
4241 : writer.emit32uLE(uint32_t(relOffset));
4242 : }
4243 : }
4244 : // ==========|> [LABEL|RIP + DISP32]
4245 : else {
4246 : writer.emit8(x86EncodeMod(0, opReg, 5));
4247 :
4248 0 : if (is32Bit()) {
4249 0 : EmitModSib_LabelRip_X86:
4250 0 : if (ASMJIT_UNLIKELY(_code->_relocations.willGrow(_code->allocator()) != kErrorOk))
4251 0 : goto OutOfMemory;
4252 :
4253 : relOffset = rmRel->as<Mem>().offsetLo32();
4254 0 : if (rmInfo & kX86MemInfo_BaseLabel) {
4255 : // [LABEL->ABS].
4256 0 : label = _code->labelEntry(rmRel->as<Mem>().baseId());
4257 0 : if (ASMJIT_UNLIKELY(!label))
4258 0 : goto InvalidLabel;
4259 :
4260 0 : err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
4261 0 : if (ASMJIT_UNLIKELY(err))
4262 0 : goto Failed;
4263 :
4264 0 : re->_sourceSectionId = _section->id();
4265 0 : re->_sourceOffset = offset();
4266 : re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, 4);
4267 0 : re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
4268 0 : re->_payload = uint64_t(int64_t(relOffset));
4269 :
4270 0 : if (label->isBound()) {
4271 : // Label bound to the current section.
4272 0 : re->_payload += label->offset();
4273 0 : re->_targetSectionId = label->section()->id();
4274 : writer.emit32uLE(0);
4275 : }
4276 : else {
4277 : // Non-bound label or label bound to a different section.
4278 0 : relOffset = -4 - immSize;
4279 : relSize = 4;
4280 0 : goto EmitRel;
4281 : }
4282 : }
4283 : else {
4284 : // [RIP->ABS].
4285 0 : err = _code->newRelocEntry(&re, RelocType::kRelToAbs);
4286 0 : if (ASMJIT_UNLIKELY(err))
4287 0 : goto Failed;
4288 :
4289 0 : re->_sourceSectionId = _section->id();
4290 0 : re->_targetSectionId = _section->id();
4291 : re->_format.resetToSimpleValue(OffsetType::kUnsignedOffset, 4);
4292 0 : re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
4293 0 : re->_sourceOffset = offset();
4294 0 : re->_payload = re->_sourceOffset + re->_format.regionSize() + uint64_t(int64_t(relOffset));
4295 :
4296 : writer.emit32uLE(0);
4297 : }
4298 : }
4299 : else {
4300 : relOffset = rmRel->as<Mem>().offsetLo32();
4301 0 : if (rmInfo & kX86MemInfo_BaseLabel) {
4302 : // [RIP].
4303 0 : label = _code->labelEntry(rmRel->as<Mem>().baseId());
4304 0 : if (ASMJIT_UNLIKELY(!label))
4305 0 : goto InvalidLabel;
4306 :
4307 0 : relOffset -= (4 + immSize);
4308 0 : if (label->isBoundTo(_section)) {
4309 : // Label bound to the current section.
4310 0 : relOffset += int32_t(label->offset() - writer.offsetFrom(_bufferData));
4311 0 : writer.emit32uLE(uint32_t(relOffset));
4312 : }
4313 : else {
4314 : // Non-bound label or label bound to a different section.
4315 : relSize = 4;
4316 0 : goto EmitRel;
4317 : }
4318 : }
4319 : else {
4320 : // [RIP].
4321 : writer.emit32uLE(uint32_t(relOffset));
4322 : }
4323 : }
4324 : }
4325 : }
4326 0 : else if (!(rmInfo & kX86MemInfo_67H_X86)) {
4327 : // ESP|RSP can't be used as INDEX in pure SIB mode, however, VSIB mode allows XMM4|YMM4|ZMM4 (that's why the
4328 : // check is before the label).
4329 0 : if (ASMJIT_UNLIKELY(rxReg == Gp::kIdSp))
4330 0 : goto InvalidAddressIndex;
4331 :
4332 0 : EmitModVSib:
4333 0 : rxReg &= 0x7;
4334 :
4335 : // ==========|> [BASE + INDEX + DISP8|DISP32].
4336 0 : if (rmInfo & kX86MemInfo_BaseGp) {
4337 0 : rbReg &= 0x7;
4338 : relOffset = rmRel->as<Mem>().offsetLo32();
4339 :
4340 : uint32_t mod = x86EncodeMod(0, opReg, 4);
4341 : uint32_t sib = x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, rbReg);
4342 :
4343 0 : if (relOffset == 0 && rbReg != Gp::kIdBp) {
4344 : // [BASE + INDEX << SHIFT].
4345 : writer.emit8(mod);
4346 : writer.emit8(sib);
4347 : }
4348 : else {
4349 0 : uint32_t cdShift = (opcode & Opcode::kCDSHL_Mask) >> Opcode::kCDSHL_Shift;
4350 0 : int32_t cdOffset = relOffset >> cdShift;
4351 :
4352 0 : if (Support::isInt8(cdOffset) && relOffset == int32_t(uint32_t(cdOffset) << cdShift)) {
4353 : // [BASE + INDEX << SHIFT + DISP8].
4354 0 : writer.emit8(mod + 0x40); // <- MOD(1, opReg, 4).
4355 : writer.emit8(sib);
4356 : writer.emit8(uint32_t(cdOffset));
4357 : }
4358 : else {
4359 : // [BASE + INDEX << SHIFT + DISP32].
4360 0 : writer.emit8(mod + 0x80); // <- MOD(2, opReg, 4).
4361 : writer.emit8(sib);
4362 : writer.emit32uLE(uint32_t(relOffset));
4363 : }
4364 : }
4365 : }
4366 : // ==========|> [INDEX + DISP32].
4367 0 : else if (!(rmInfo & (kX86MemInfo_BaseLabel | kX86MemInfo_BaseRip))) {
4368 : // [INDEX << SHIFT + DISP32].
4369 : writer.emit8(x86EncodeMod(0, opReg, 4));
4370 : writer.emit8(x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, 5));
4371 :
4372 : relOffset = rmRel->as<Mem>().offsetLo32();
4373 : writer.emit32uLE(uint32_t(relOffset));
4374 : }
4375 : // ==========|> [LABEL|RIP + INDEX + DISP32].
4376 : else {
4377 0 : if (is32Bit()) {
4378 : writer.emit8(x86EncodeMod(0, opReg, 4));
4379 : writer.emit8(x86EncodeSib(rmRel->as<Mem>().shift(), rxReg, 5));
4380 0 : goto EmitModSib_LabelRip_X86;
4381 : }
4382 : else {
4383 : // NOTE: This also handles VSIB+RIP, which is not allowed in 64-bit mode.
4384 0 : goto InvalidAddress;
4385 : }
4386 : }
4387 : }
4388 : else {
4389 : // 16-bit address mode (32-bit mode with 67 override prefix).
4390 0 : relOffset = (int32_t(rmRel->as<Mem>().offsetLo32()) << 16) >> 16;
4391 :
4392 : // NOTE: 16-bit addresses don't use SIB byte and their encoding differs. We use a table-based approach to
4393 : // calculate the proper MOD byte as it's easier. Also, not all BASE [+ INDEX] combinations are supported
4394 : // in 16-bit mode, so this may fail.
4395 : const uint32_t kBaseGpIdx = (kX86MemInfo_BaseGp | kX86MemInfo_Index);
4396 :
4397 0 : if (rmInfo & kBaseGpIdx) {
4398 : // ==========|> [BASE + INDEX + DISP16].
4399 : uint32_t mod;
4400 :
4401 0 : rbReg &= 0x7;
4402 0 : rxReg &= 0x7;
4403 :
4404 0 : if ((rmInfo & kBaseGpIdx) == kBaseGpIdx) {
4405 : uint32_t shf = rmRel->as<Mem>().shift();
4406 0 : if (ASMJIT_UNLIKELY(shf != 0))
4407 0 : goto InvalidAddress;
4408 0 : mod = x86Mod16BaseIndexTable[(rbReg << 3) + rxReg];
4409 : }
4410 : else {
4411 0 : if (rmInfo & kX86MemInfo_Index)
4412 : rbReg = rxReg;
4413 0 : mod = x86Mod16BaseTable[rbReg];
4414 : }
4415 :
4416 0 : if (ASMJIT_UNLIKELY(mod == 0xFF))
4417 0 : goto InvalidAddress;
4418 :
4419 0 : mod += opReg << 3;
4420 0 : if (relOffset == 0 && mod != 0x06) {
4421 : writer.emit8(mod);
4422 : }
4423 : else if (Support::isInt8(relOffset)) {
4424 0 : writer.emit8(mod + 0x40);
4425 : writer.emit8(uint32_t(relOffset));
4426 : }
4427 : else {
4428 0 : writer.emit8(mod + 0x80);
4429 : writer.emit16uLE(uint32_t(relOffset));
4430 : }
4431 : }
4432 : else {
4433 : // Not supported in 16-bit addresses.
4434 0 : if (rmInfo & (kX86MemInfo_BaseRip | kX86MemInfo_BaseLabel))
4435 0 : goto InvalidAddress;
4436 :
4437 : // ==========|> [DISP16].
4438 0 : writer.emit8(opReg | 0x06);
4439 : writer.emit16uLE(uint32_t(relOffset));
4440 : }
4441 : }
4442 :
4443 142105 : writer.emitImmediate(uint64_t(immValue), immSize);
4444 142105 : goto EmitDone;
4445 :
4446 : // Emit - FPU
4447 : // ----------
4448 :
4449 0 : EmitFpuOp:
4450 : // Mandatory instruction prefix.
4451 : writer.emitPP(opcode.v);
4452 :
4453 : // FPU instructions consist of two opcodes.
4454 0 : writer.emit8(opcode.v >> Opcode::kFPU_2B_Shift);
4455 : writer.emit8(opcode.v);
4456 0 : goto EmitDone;
4457 :
4458 : // Emit - VEX Opcode
4459 : // -----------------
4460 :
4461 : EmitVexOp:
4462 : {
4463 : // These don't use immediate.
4464 : ASMJIT_ASSERT(immSize == 0);
4465 :
4466 : // Only 'vzeroall' and 'vzeroupper' instructions use this encoding, they don't define 'W' to be '1' so we can
4467 : // just check the 'mmmmm' field. Both functions can encode by using VEX2 prefix so VEX3 is basically only used
4468 : // when specified as instruction option.
4469 : ASMJIT_ASSERT((opcode & Opcode::kW) == 0);
4470 :
4471 0 : uint32_t x = (uint32_t(opcode & Opcode::kMM_Mask ) >> (Opcode::kMM_Shift )) |
4472 0 : (uint32_t(opcode & Opcode::kLL_Mask ) >> (Opcode::kLL_Shift - 10)) |
4473 0 : (uint32_t(opcode & Opcode::kPP_VEXMask ) >> (Opcode::kPP_Shift - 8)) ;
4474 :
4475 0 : if (Support::test(options, InstOptions::kX86_Vex3)) {
4476 0 : x = (x & 0xFFFF) << 8; // [00000000|00000Lpp|000mmmmm|00000000].
4477 0 : x ^= (kX86ByteVex3) | // [........|00000Lpp|000mmmmm|__VEX3__].
4478 : (0x07u << 13) | // [........|00000Lpp|111mmmmm|__VEX3__].
4479 0 : (0x0Fu << 19) | // [........|01111Lpp|111mmmmm|__VEX3__].
4480 : (opcode << 24) ; // [_OPCODE_|01111Lpp|111mmmmm|__VEX3__].
4481 :
4482 : writer.emit32uLE(x);
4483 0 : goto EmitDone;
4484 : }
4485 : else {
4486 0 : x = ((x >> 8) ^ x) ^ 0xF9;
4487 : writer.emit8(kX86ByteVex2);
4488 : writer.emit8(x);
4489 : writer.emit8(opcode.v);
4490 0 : goto EmitDone;
4491 : }
4492 : }
4493 :
4494 : // Emit - VEX|EVEX - /r - Register
4495 : // -------------------------------
4496 :
4497 114557 : EmitVexEvexR:
4498 : {
4499 : // Construct `x` - a complete EVEX|VEX prefix.
4500 114557 : uint32_t x = ((opReg << 4) & 0xF980u) | // [........|........|Vvvvv..R|R.......].
4501 114557 : ((rbReg << 2) & 0x0060u) | // [........|........|........|.BB.....].
4502 : (opcode.extractLLMMMMM(options)) | // [........|.LL.....|Vvvvv..R|RBBmmmmm].
4503 114557 : (_extraReg.id() << 16); // [........|.LL..aaa|Vvvvv..R|RBBmmmmm].
4504 114557 : opReg &= 0x7;
4505 :
4506 : // Handle AVX512 options by a single branch.
4507 : const InstOptions kAvx512Options = InstOptions::kX86_ZMask | InstOptions::kX86_ER | InstOptions::kX86_SAE;
4508 114557 : if (Support::test(options, kAvx512Options)) {
4509 : static constexpr uint32_t kBcstMask = 0x1 << 20;
4510 : static constexpr uint32_t kLLMask10 = 0x2 << 21;
4511 : static constexpr uint32_t kLLMask11 = 0x3 << 21;
4512 :
4513 : // Designed to be easily encodable so the position must be exact. The {rz-sae} is encoded as {11},
4514 : // so it should match the mask.
4515 : static_assert(uint32_t(InstOptions::kX86_RZ_SAE) == kLLMask11,
4516 : "This code requires InstOptions::X86_RZ_SAE to match kLLMask11 to work properly");
4517 :
4518 0 : x |= uint32_t(options & InstOptions::kX86_ZMask); // [........|zLLb.aaa|Vvvvv..R|RBBmmmmm].
4519 :
4520 : // Support embedded-rounding {er} and suppress-all-exceptions {sae}.
4521 0 : if (Support::test(options, InstOptions::kX86_ER | InstOptions::kX86_SAE)) {
4522 : // Embedded rounding is only encodable if the instruction is either scalar or it's a 512-bit
4523 : // operation as the {er} rounding predicate collides with LL part of the instruction.
4524 0 : if ((x & kLLMask11) != kLLMask10) {
4525 : // Ok, so LL is not 10, thus the instruction must be scalar. Scalar instructions don't
4526 : // support broadcast so if this instruction supports it {er} nor {sae} would be encodable.
4527 0 : if (ASMJIT_UNLIKELY(commonInfo->hasAvx512B()))
4528 0 : goto InvalidEROrSAE;
4529 : }
4530 :
4531 0 : if (Support::test(options, InstOptions::kX86_ER)) {
4532 0 : if (ASMJIT_UNLIKELY(!commonInfo->hasAvx512ER()))
4533 0 : goto InvalidEROrSAE;
4534 :
4535 0 : x &=~kLLMask11; // [........|.00..aaa|Vvvvv..R|RBBmmmmm].
4536 0 : x |= kBcstMask | (uint32_t(options) & kLLMask11); // [........|.LLb.aaa|Vvvvv..R|RBBmmmmm].
4537 : }
4538 : else {
4539 0 : if (ASMJIT_UNLIKELY(!commonInfo->hasAvx512SAE()))
4540 0 : goto InvalidEROrSAE;
4541 :
4542 0 : x &=~kLLMask11; // [........|.00..aaa|Vvvvv..R|RBBmmmmm].
4543 0 : x |= kBcstMask; // [........|.00b.aaa|Vvvvv..R|RBBmmmmm].
4544 : }
4545 : }
4546 : }
4547 :
4548 : // These bits would force EVEX prefix.
4549 : constexpr uint32_t kEvexForce = 0x00000010u; // [........|........|........|...x....].
4550 : constexpr uint32_t kEvexBits = 0x00D78150u; // [........|xx.x.xxx|x......x|.x.x....].
4551 :
4552 : // Force EVEX prefix even in case the instruction has VEX encoding, because EVEX encoding is preferred. At the
4553 : // moment this is only required by AVX_VNNI instructions, which were added after AVX512_VNNI instructions. If
4554 : // such instruction doesn't specify prefix, EVEX (AVX512_VNNI) is selected by default.
4555 114557 : if (commonInfo->preferEvex()) {
4556 0 : if ((x & kEvexBits) == 0 && !Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3)) {
4557 0 : x |= kEvexForce;
4558 : }
4559 : }
4560 :
4561 : // Check if EVEX is required by checking bits in `x` : [........|xx.x.xxx|x......x|.x.x....].
4562 114557 : if (x & kEvexBits) {
4563 0 : uint32_t y = ((x << 4) & 0x00080000u) | // [........|...bV...|........|........].
4564 0 : ((x >> 4) & 0x00000010u) ; // [........|...bV...|........|...R....].
4565 0 : x = (x & 0x00FF78EFu) | y; // [........|zLLbVaaa|0vvvv000|RBBRmmmm].
4566 0 : x = x << 8; // [zLLbVaaa|0vvvv000|RBBRmmmm|00000000].
4567 0 : x |= (opcode >> kVSHR_W ) & 0x00800000u; // [zLLbVaaa|Wvvvv000|RBBRmmmm|00000000].
4568 0 : x |= (opcode >> kVSHR_PP_EW) & 0x00830000u; // [zLLbVaaa|Wvvvv0pp|RBBRmmmm|00000000] (added PP and EVEX.W).
4569 : // _ ____ ____
4570 0 : x ^= 0x087CF000u | kX86ByteEvex; // [zLLbVaaa|Wvvvv1pp|RBBRmmmm|01100010].
4571 :
4572 : writer.emit32uLE(x);
4573 : writer.emit8(opcode.v);
4574 :
4575 0 : rbReg &= 0x7;
4576 : writer.emit8(x86EncodeMod(3, opReg, rbReg));
4577 0 : writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
4578 0 : goto EmitDone;
4579 : }
4580 :
4581 : // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|R0Bmmmmm].
4582 114557 : x |= ((opcode >> (kVSHR_W + 8)) & 0x8000u) | // [00000000|00L00000|Wvvvv000|R0Bmmmmm].
4583 114557 : ((opcode >> (kVSHR_PP + 8)) & 0x0300u) | // [00000000|00L00000|0vvvv0pp|R0Bmmmmm].
4584 114557 : ((x >> 11 ) & 0x0400u) ; // [00000000|00L00000|WvvvvLpp|R0Bmmmmm].
4585 114557 : x |= x86GetForceEvex3MaskInLastBit(options); // [x0000000|00L00000|WvvvvLpp|R0Bmmmmm].
4586 :
4587 : // Check if VEX3 is required / forced: [x.......|........|x.......|..xxxxx.].
4588 114557 : if (x & 0x8000803Eu) {
4589 2610 : uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opcode << 24);
4590 :
4591 : // Clear all high bits.
4592 2610 : x = (x & 0xFFFF) << 8; // [00000000|WvvvvLpp|R0Bmmmmm|00000000].
4593 : // ____ _ _
4594 2610 : x ^= xorMsk; // [_OPCODE_|WvvvvLpp|R1Bmmmmm|VEX3|XOP].
4595 : writer.emit32uLE(x);
4596 :
4597 2610 : rbReg &= 0x7;
4598 : writer.emit8(x86EncodeMod(3, opReg, rbReg));
4599 2610 : writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
4600 2610 : goto EmitDone;
4601 : }
4602 : else {
4603 : // 'mmmmm' must be '00001'.
4604 : ASMJIT_ASSERT((x & 0x1F) == 0x01);
4605 :
4606 111947 : x = ((x >> 8) ^ x) ^ 0xF9;
4607 : writer.emit8(kX86ByteVex2);
4608 : writer.emit8(x);
4609 : writer.emit8(opcode.v);
4610 :
4611 111947 : rbReg &= 0x7;
4612 : writer.emit8(x86EncodeMod(3, opReg, rbReg));
4613 111947 : writer.emitImmByteOrDWord(uint64_t(immValue), immSize);
4614 111947 : goto EmitDone;
4615 : }
4616 : }
4617 :
4618 : // Emit - VEX|EVEX - /r - Memory
4619 : // -----------------------------
4620 :
4621 142085 : EmitVexEvexM:
4622 : ASMJIT_ASSERT(rmRel != nullptr);
4623 : ASMJIT_ASSERT(rmRel->opType() == OperandType::kMem);
4624 :
4625 142085 : rmInfo = x86MemInfo[rmRel->as<Mem>().baseAndIndexTypes()];
4626 : writer.emitSegmentOverride(rmRel->as<Mem>().segmentId());
4627 :
4628 : memOpAOMark = writer.cursor();
4629 142085 : writer.emitAddressOverride((rmInfo & _addressOverrideMask()) != 0);
4630 :
4631 142085 : rbReg = rmRel->as<Mem>().hasBaseReg() ? rmRel->as<Mem>().baseId() : uint32_t(0);
4632 142085 : rxReg = rmRel->as<Mem>().hasIndexReg() ? rmRel->as<Mem>().indexId() : uint32_t(0);
4633 :
4634 : {
4635 142085 : uint32_t broadcastBit = uint32_t(rmRel->as<Mem>().hasBroadcast());
4636 :
4637 : // Construct `x` - a complete EVEX|VEX prefix.
4638 142085 : uint32_t x = ((opReg << 4) & 0x0000F980u) | // [........|........|Vvvvv..R|R.......].
4639 142085 : ((rxReg << 3) & 0x00000040u) | // [........|........|........|.X......].
4640 142085 : ((rxReg << 15) & 0x00080000u) | // [........|....X...|........|........].
4641 142085 : ((rbReg << 2) & 0x00000020u) | // [........|........|........|..B.....].
4642 142085 : opcode.extractLLMMMMM(options) | // [........|.LL.X...|Vvvvv..R|RXBmmmmm].
4643 142085 : (_extraReg.id() << 16) | // [........|.LL.Xaaa|Vvvvv..R|RXBmmmmm].
4644 142085 : (broadcastBit << 20) ; // [........|.LLbXaaa|Vvvvv..R|RXBmmmmm].
4645 142085 : opReg &= 0x07u;
4646 :
4647 : // Mark invalid VEX (force EVEX) case: // [@.......|.LLbXaaa|Vvvvv..R|RXBmmmmm].
4648 142085 : x |= uint32_t(~commonInfo->flags() & InstDB::InstFlags::kVex) << (31 - Support::ConstCTZ<uint32_t(InstDB::InstFlags::kVex)>::value);
4649 :
4650 : // Handle AVX512 options by a single branch.
4651 : const InstOptions kAvx512Options = InstOptions::kX86_ZMask |
4652 : InstOptions::kX86_ER |
4653 : InstOptions::kX86_SAE ;
4654 142085 : if (Support::test(options, kAvx512Options)) {
4655 : // {er} and {sae} are both invalid if memory operand is used.
4656 0 : if (ASMJIT_UNLIKELY(Support::test(options, InstOptions::kX86_ER | InstOptions::kX86_SAE)))
4657 0 : goto InvalidEROrSAE;
4658 :
4659 0 : x |= uint32_t(options & InstOptions::kX86_ZMask); // [@.......|zLLbXaaa|Vvvvv..R|RXBmmmmm].
4660 : }
4661 :
4662 : // If these bits are used then EVEX prefix is required.
4663 : constexpr uint32_t kEvexForce = 0x00000010u; // [........|........|........|...x....].
4664 : constexpr uint32_t kEvexBits = 0x80DF8110u; // [@.......|xx.xxxxx|x......x|...x....].
4665 :
4666 : // Force EVEX prefix even in case the instruction has VEX encoding, because EVEX encoding is preferred. At the
4667 : // moment this is only required for AVX_VNNI instructions, which were added after AVX512_VNNI instructions. If
4668 : // such instruction doesn't specify prefix, EVEX (AVX512_VNNI) would be used by default,
4669 142085 : if (commonInfo->preferEvex()) {
4670 0 : if ((x & kEvexBits) == 0 && !Support::test(options, InstOptions::kX86_Vex | InstOptions::kX86_Vex3)) {
4671 0 : x |= kEvexForce;
4672 : }
4673 : }
4674 :
4675 : // Check if EVEX is required by checking bits in `x` : [@.......|xx.xxxxx|x......x|...x....].
4676 142085 : if (x & kEvexBits) {
4677 0 : uint32_t y = ((x << 4) & 0x00080000u) | // [@.......|....V...|........|........].
4678 0 : ((x >> 4) & 0x00000010u) ; // [@.......|....V...|........|...R....].
4679 0 : x = (x & 0x00FF78EFu) | y; // [........|zLLbVaaa|0vvvv000|RXBRmmmm].
4680 0 : x = x << 8; // [zLLbVaaa|0vvvv000|RBBRmmmm|00000000].
4681 0 : x |= (opcode >> kVSHR_W ) & 0x00800000u; // [zLLbVaaa|Wvvvv000|RBBRmmmm|00000000].
4682 0 : x |= (opcode >> kVSHR_PP_EW) & 0x00830000u; // [zLLbVaaa|Wvvvv0pp|RBBRmmmm|00000000] (added PP and EVEX.W).
4683 : // _ ____ ____
4684 0 : x ^= 0x087CF000u | kX86ByteEvex; // [zLLbVaaa|Wvvvv1pp|RBBRmmmm|01100010].
4685 :
4686 0 : if (x & 0x10000000u) {
4687 : // Broadcast support.
4688 : //
4689 : // 1. Verify our LL field is correct as broadcast changes the "size" of the source operand. For example if
4690 : // a broadcasted operand is qword_ptr[X] {1to8} the source size becomes 64 and not 8 as the memory operand
4691 : // would report.
4692 : //
4693 : // 2. Change the compressed displacement scale to either x2 (SHL1), x4 (SHL 2), or x8 (SHL 3) depending on
4694 : // the broadcast unit/element size.
4695 : uint32_t broadcastUnitSize = commonInfo->broadcastSize();
4696 0 : uint32_t broadcastVectorSize = broadcastUnitSize << uint32_t(rmRel->as<Mem>().getBroadcast());
4697 :
4698 0 : if (ASMJIT_UNLIKELY(broadcastUnitSize == 0))
4699 0 : goto InvalidBroadcast;
4700 :
4701 : // LL was already shifted 8 bits right.
4702 : constexpr uint32_t kLLShift = 21 + 8;
4703 :
4704 0 : uint32_t currentLL = x & (0x3u << kLLShift);
4705 0 : uint32_t broadcastLL = (Support::max<uint32_t>(Support::ctz(broadcastVectorSize), 4) - 4) << kLLShift;
4706 :
4707 0 : if (broadcastLL > (2u << kLLShift))
4708 0 : goto InvalidBroadcast;
4709 :
4710 : uint32_t newLL = Support::max(currentLL, broadcastLL);
4711 0 : x = (x & ~(uint32_t(0x3) << kLLShift)) | newLL;
4712 :
4713 : opcode &=~uint32_t(Opcode::kCDSHL_Mask);
4714 0 : opcode |= Support::ctz(broadcastUnitSize) << Opcode::kCDSHL_Shift;
4715 : }
4716 : else {
4717 : // Add the compressed displacement 'SHF' to the opcode based on 'TTWLL'.
4718 : // The index to `x86CDisp8SHL` is composed as `CDTT[4:3] | W[2] | LL[1:0]`.
4719 0 : uint32_t TTWLL = ((opcode >> (Opcode::kCDTT_Shift - 3)) & 0x18) +
4720 0 : ((opcode >> (Opcode::kW_Shift - 2)) & 0x04) +
4721 0 : ((x >> 29) & 0x3);
4722 0 : opcode += x86CDisp8SHL[TTWLL];
4723 : }
4724 :
4725 : writer.emit32uLE(x);
4726 : writer.emit8(opcode.v);
4727 : }
4728 : else {
4729 : // Not EVEX, prepare `x` for VEX2 or VEX3: x = [........|00L00000|0vvvv000|RXBmmmmm].
4730 142085 : x |= ((opcode >> (kVSHR_W + 8)) & 0x8000u) | // [00000000|00L00000|Wvvvv000|RXBmmmmm].
4731 142085 : ((opcode >> (kVSHR_PP + 8)) & 0x0300u) | // [00000000|00L00000|Wvvvv0pp|RXBmmmmm].
4732 142085 : ((x >> 11 ) & 0x0400u) ; // [00000000|00L00000|WvvvvLpp|RXBmmmmm].
4733 142085 : x |= x86GetForceEvex3MaskInLastBit(options); // [x0000000|00L00000|WvvvvLpp|RXBmmmmm].
4734 :
4735 : // Clear a possible CDisp specified by EVEX.
4736 : opcode &= ~Opcode::kCDSHL_Mask;
4737 :
4738 : // Check if VEX3 is required / forced: [x.......|........|x.......|.xxxxxx.].
4739 142085 : if (x & 0x8000807Eu) {
4740 0 : uint32_t xorMsk = x86VEXPrefix[x & 0xF] | (opcode << 24);
4741 :
4742 : // Clear all high bits.
4743 0 : x = (x & 0xFFFF) << 8; // [00000000|WvvvvLpp|RXBmmmmm|00000000].
4744 : // ____ ___
4745 0 : x ^= xorMsk; // [_OPCODE_|WvvvvLpp|RXBmmmmm|VEX3_XOP].
4746 : writer.emit32uLE(x);
4747 : }
4748 : else {
4749 : // 'mmmmm' must be '00001'.
4750 : ASMJIT_ASSERT((x & 0x1F) == 0x01);
4751 :
4752 142085 : x = ((x >> 8) ^ x) ^ 0xF9;
4753 : writer.emit8(kX86ByteVex2);
4754 : writer.emit8(x);
4755 : writer.emit8(opcode.v);
4756 : }
4757 : }
4758 : }
4759 :
4760 : // MOD|SIB address.
4761 142085 : if (!commonInfo->hasFlag(InstDB::InstFlags::kVsib))
4762 142085 : goto EmitModSib;
4763 :
4764 : // MOD|VSIB address without INDEX is invalid.
4765 0 : if (rmInfo & kX86MemInfo_Index)
4766 0 : goto EmitModVSib;
4767 0 : goto InvalidInstruction;
4768 :
4769 : // Emit - Jmp/Jcc/Call
4770 : // -------------------
4771 :
4772 0 : EmitJmpCall:
4773 : {
4774 : // Emit REX prefix if asked for (64-bit only).
4775 : uint32_t rex = opcode.extractRex(options);
4776 0 : if (ASMJIT_UNLIKELY(x86IsRexInvalid(rex)))
4777 0 : goto InvalidRexPrefix;
4778 0 : rex &= ~kX86ByteInvalidRex & 0xFF;
4779 0 : writer.emit8If(rex | kX86ByteRex, rex != 0);
4780 :
4781 0 : uint64_t ip = uint64_t(writer.offsetFrom(_bufferData));
4782 : uint32_t rel32 = 0;
4783 : uint32_t opCode8 = x86AltOpcodeOf(instInfo);
4784 :
4785 : uint32_t inst8Size = 1 + 1; // OPCODE + REL8 .
4786 : uint32_t inst32Size = 1 + 4; // [PREFIX] OPCODE + REL32.
4787 :
4788 : // Jcc instructions with 32-bit displacement use 0x0F prefix,
4789 : // other instructions don't. No other prefixes are used by X86.
4790 : ASMJIT_ASSERT((opCode8 & Opcode::kMM_Mask) == 0);
4791 : ASMJIT_ASSERT((opcode & Opcode::kMM_Mask) == 0 ||
4792 : (opcode & Opcode::kMM_Mask) == Opcode::kMM_0F);
4793 :
4794 : // Only one of these should be used at the same time.
4795 0 : inst32Size += uint32_t(opReg != 0);
4796 0 : inst32Size += uint32_t((opcode & Opcode::kMM_Mask) == Opcode::kMM_0F);
4797 :
4798 0 : if (rmRel->isLabel()) {
4799 0 : label = _code->labelEntry(rmRel->as<Label>());
4800 0 : if (ASMJIT_UNLIKELY(!label))
4801 0 : goto InvalidLabel;
4802 :
4803 0 : if (label->isBoundTo(_section)) {
4804 : // Label bound to the current section.
4805 0 : rel32 = uint32_t((label->offset() - ip - inst32Size) & 0xFFFFFFFFu);
4806 0 : goto EmitJmpCallRel;
4807 : }
4808 : else {
4809 : // Non-bound label or label bound to a different section.
4810 0 : if (opCode8 && (!opcode.v || Support::test(options, InstOptions::kShortForm))) {
4811 : writer.emit8(opCode8);
4812 :
4813 : // Record DISP8 (non-bound label).
4814 : relOffset = -1;
4815 : relSize = 1;
4816 0 : goto EmitRel;
4817 : }
4818 : else {
4819 : // Refuse also 'short' prefix, if specified.
4820 0 : if (ASMJIT_UNLIKELY(!opcode.v || Support::test(options, InstOptions::kShortForm)))
4821 0 : goto InvalidDisplacement;
4822 :
4823 0 : writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0);// Emit 0F prefix.
4824 : writer.emit8(opcode.v); // Emit opcode.
4825 : writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0); // Emit MOD.
4826 :
4827 : // Record DISP32 (non-bound label).
4828 : relOffset = -4;
4829 : relSize = 4;
4830 0 : goto EmitRel;
4831 : }
4832 : }
4833 : }
4834 :
4835 0 : if (rmRel->isImm()) {
4836 : uint64_t baseAddress = code()->baseAddress();
4837 : uint64_t jumpAddress = rmRel->as<Imm>().valueAs<uint64_t>();
4838 :
4839 : // If the base-address is known calculate a relative displacement and check if it fits in 32 bits (which is
4840 : // always true in 32-bit mode). Emit relative displacement as it was a bound label if all checks are ok.
4841 0 : if (baseAddress != Globals::kNoBaseAddress) {
4842 0 : uint64_t rel64 = jumpAddress - (ip + baseAddress) - inst32Size;
4843 0 : if (Environment::is32Bit(arch()) || Support::isInt32(int64_t(rel64))) {
4844 0 : rel32 = uint32_t(rel64 & 0xFFFFFFFFu);
4845 0 : goto EmitJmpCallRel;
4846 : }
4847 : else {
4848 : // Relative displacement exceeds 32-bits - relocator can only insert trampoline for jmp/call, but not
4849 : // for jcc/jecxz.
4850 0 : if (ASMJIT_UNLIKELY(!x86IsJmpOrCall(instId)))
4851 0 : goto InvalidDisplacement;
4852 : }
4853 : }
4854 :
4855 0 : err = _code->newRelocEntry(&re, RelocType::kAbsToRel);
4856 0 : if (ASMJIT_UNLIKELY(err))
4857 0 : goto Failed;
4858 :
4859 0 : re->_sourceOffset = offset();
4860 0 : re->_sourceSectionId = _section->id();
4861 0 : re->_payload = jumpAddress;
4862 :
4863 0 : if (ASMJIT_LIKELY(opcode.v)) {
4864 : // 64-bit: Emit REX prefix so the instruction can be patched later. REX prefix does nothing if not patched,
4865 : // but allows to patch the instruction to use MOD/M and to point to a memory where the final 64-bit address
4866 : // is stored.
4867 0 : if (Environment::is64Bit(arch()) && x86IsJmpOrCall(instId)) {
4868 0 : if (!rex)
4869 : writer.emit8(kX86ByteRex);
4870 :
4871 0 : err = _code->addAddressToAddressTable(jumpAddress);
4872 0 : if (ASMJIT_UNLIKELY(err))
4873 0 : goto Failed;
4874 :
4875 0 : re->_relocType = RelocType::kX64AddressEntry;
4876 : }
4877 :
4878 0 : writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0); // Emit 0F prefix.
4879 : writer.emit8(opcode.v); // Emit opcode.
4880 : writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0); // Emit MOD.
4881 0 : re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 4);
4882 0 : re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
4883 : writer.emit32uLE(0); // Emit DISP32.
4884 : }
4885 : else {
4886 : writer.emit8(opCode8); // Emit opcode.
4887 0 : re->_format.resetToSimpleValue(OffsetType::kSignedOffset, 1);
4888 0 : re->_format.setLeadingAndTrailingSize(writer.offsetFrom(_bufferPtr), immSize);
4889 : writer.emit8(0); // Emit DISP8 (zero).
4890 : }
4891 0 : goto EmitDone;
4892 : }
4893 :
4894 : // Not Label|Imm -> Invalid.
4895 0 : goto InvalidInstruction;
4896 :
4897 : // Emit jmp/call with relative displacement known at assembly-time. Decide between 8-bit and 32-bit displacement
4898 : // encoding. Some instructions only allow either 8-bit or 32-bit encoding, others allow both encodings.
4899 0 : EmitJmpCallRel:
4900 0 : if (Support::isInt8(int32_t(rel32 + inst32Size - inst8Size)) && opCode8 && !Support::test(options, InstOptions::kLongForm)) {
4901 : options |= InstOptions::kShortForm;
4902 : writer.emit8(opCode8); // Emit opcode
4903 : writer.emit8(rel32 + inst32Size - inst8Size); // Emit DISP8.
4904 0 : goto EmitDone;
4905 : }
4906 : else {
4907 0 : if (ASMJIT_UNLIKELY(!opcode.v || Support::test(options, InstOptions::kShortForm)))
4908 0 : goto InvalidDisplacement;
4909 :
4910 : options &= ~InstOptions::kShortForm;
4911 0 : writer.emit8If(0x0F, (opcode & Opcode::kMM_Mask) != 0); // Emit 0x0F prefix.
4912 : writer.emit8(opcode.v); // Emit Opcode.
4913 : writer.emit8If(x86EncodeMod(3, opReg, 0), opReg != 0); // Emit MOD.
4914 : writer.emit32uLE(rel32); // Emit DISP32.
4915 0 : goto EmitDone;
4916 : }
4917 : }
4918 :
4919 : // Emit - Relative
4920 : // ---------------
4921 :
4922 0 : EmitRel:
4923 : {
4924 : ASMJIT_ASSERT(relSize == 1 || relSize == 4);
4925 :
4926 : // Chain with label.
4927 0 : size_t offset = size_t(writer.offsetFrom(_bufferData));
4928 : OffsetFormat of;
4929 : of.resetToSimpleValue(OffsetType::kSignedOffset, relSize);
4930 :
4931 0 : LabelLink* link = _code->newLabelLink(label, _section->id(), offset, relOffset, of);
4932 0 : if (ASMJIT_UNLIKELY(!link))
4933 0 : goto OutOfMemory;
4934 :
4935 0 : if (re)
4936 0 : link->relocId = re->id();
4937 :
4938 : // Emit dummy zeros, must be patched later when the reference becomes known.
4939 0 : writer.emitZeros(relSize);
4940 : }
4941 0 : writer.emitImmediate(uint64_t(immValue), immSize);
4942 :
4943 : // Emit - Done
4944 : // -----------
4945 :
4946 392009 : EmitDone:
4947 392009 : if (Support::test(options, InstOptions::kReserved)) {
4948 : #ifndef ASMJIT_NO_LOGGING
4949 27492 : if (_logger)
4950 0 : EmitterUtils::logInstructionEmitted(this, instId, options, o0, o1, o2, opExt, relSize, immSize, writer.cursor());
4951 : #endif
4952 : }
4953 :
4954 : resetExtraReg();
4955 : resetInstOptions();
4956 : resetInlineComment();
4957 :
4958 : writer.done(this);
4959 392009 : return kErrorOk;
4960 :
4961 : // Error Handler
4962 : // -------------
4963 :
4964 : #define ERROR_HANDLER(ERR) ERR: err = DebugUtils::errored(kError##ERR); goto Failed;
4965 0 : ERROR_HANDLER(OutOfMemory)
4966 0 : ERROR_HANDLER(InvalidLabel)
4967 0 : ERROR_HANDLER(InvalidInstruction)
4968 0 : ERROR_HANDLER(InvalidLockPrefix)
4969 0 : ERROR_HANDLER(InvalidXAcquirePrefix)
4970 0 : ERROR_HANDLER(InvalidXReleasePrefix)
4971 0 : ERROR_HANDLER(InvalidRepPrefix)
4972 0 : ERROR_HANDLER(InvalidRexPrefix)
4973 0 : ERROR_HANDLER(InvalidEROrSAE)
4974 0 : ERROR_HANDLER(InvalidAddress)
4975 0 : ERROR_HANDLER(InvalidAddressIndex)
4976 0 : ERROR_HANDLER(InvalidAddress64Bit)
4977 0 : ERROR_HANDLER(InvalidDisplacement)
4978 0 : ERROR_HANDLER(InvalidPhysId)
4979 0 : ERROR_HANDLER(InvalidSegment)
4980 0 : ERROR_HANDLER(InvalidImmediate)
4981 0 : ERROR_HANDLER(InvalidBroadcast)
4982 0 : ERROR_HANDLER(OperandSizeMismatch)
4983 0 : ERROR_HANDLER(AmbiguousOperandSize)
4984 0 : ERROR_HANDLER(NotConsecutiveRegs)
4985 : #undef ERROR_HANDLER
4986 :
4987 0 : Failed:
4988 : #ifndef ASMJIT_NO_LOGGING
4989 0 : return EmitterUtils::logInstructionFailed(this, err, instId, options, o0, o1, o2, opExt);
4990 : #else
4991 : resetExtraReg();
4992 : resetInstOptions();
4993 : resetInlineComment();
4994 : return reportError(err);
4995 : #endif
4996 : }
4997 :
4998 : //x86::Assembler - Align
4999 : // =====================
5000 :
5001 0 : Error Assembler::align(AlignMode alignMode, uint32_t alignment) {
5002 0 : if (ASMJIT_UNLIKELY(!_code))
5003 0 : return reportError(DebugUtils::errored(kErrorNotInitialized));
5004 :
5005 0 : if (ASMJIT_UNLIKELY(uint32_t(alignMode) > uint32_t(AlignMode::kMaxValue)))
5006 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
5007 :
5008 0 : if (alignment <= 1)
5009 : return kErrorOk;
5010 :
5011 0 : if (ASMJIT_UNLIKELY(!Support::isPowerOf2(alignment) || alignment > Globals::kMaxAlignment))
5012 0 : return reportError(DebugUtils::errored(kErrorInvalidArgument));
5013 :
5014 0 : uint32_t i = uint32_t(Support::alignUpDiff<size_t>(offset(), alignment));
5015 0 : if (i > 0) {
5016 : CodeWriter writer(this);
5017 0 : ASMJIT_PROPAGATE(writer.ensureSpace(this, i));
5018 :
5019 : uint8_t pattern = 0x00;
5020 0 : switch (alignMode) {
5021 0 : case AlignMode::kCode: {
5022 0 : if (hasEncodingOption(EncodingOptions::kOptimizedAlign)) {
5023 : // Intel 64 and IA-32 Architectures Software Developer's Manual - Volume 2B (NOP).
5024 : enum { kMaxNopSize = 9 };
5025 :
5026 : static const uint8_t nopData[kMaxNopSize][kMaxNopSize] = {
5027 : { 0x90 },
5028 : { 0x66, 0x90 },
5029 : { 0x0F, 0x1F, 0x00 },
5030 : { 0x0F, 0x1F, 0x40, 0x00 },
5031 : { 0x0F, 0x1F, 0x44, 0x00, 0x00 },
5032 : { 0x66, 0x0F, 0x1F, 0x44, 0x00, 0x00 },
5033 : { 0x0F, 0x1F, 0x80, 0x00, 0x00, 0x00, 0x00 },
5034 : { 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 },
5035 : { 0x66, 0x0F, 0x1F, 0x84, 0x00, 0x00, 0x00, 0x00, 0x00 }
5036 : };
5037 :
5038 : do {
5039 : uint32_t n = Support::min<uint32_t>(i, kMaxNopSize);
5040 0 : const uint8_t* src = nopData[n - 1];
5041 :
5042 0 : i -= n;
5043 : do {
5044 0 : writer.emit8(*src++);
5045 0 : } while (--n);
5046 0 : } while (i);
5047 : }
5048 :
5049 : pattern = 0x90;
5050 : break;
5051 : }
5052 :
5053 0 : case AlignMode::kData:
5054 : pattern = 0xCC;
5055 0 : break;
5056 :
5057 : case AlignMode::kZero:
5058 : // Pattern already set to zero.
5059 : break;
5060 : }
5061 :
5062 0 : while (i) {
5063 : writer.emit8(pattern);
5064 0 : i--;
5065 : }
5066 :
5067 : writer.done(this);
5068 : }
5069 :
5070 : #ifndef ASMJIT_NO_LOGGING
5071 0 : if (_logger) {
5072 : StringTmp<128> sb;
5073 0 : sb.appendChars(' ', _logger->indentation(FormatIndentationGroup::kCode));
5074 : sb.appendFormat("align %u\n", alignment);
5075 0 : _logger->log(sb);
5076 : }
5077 : #endif
5078 :
5079 : return kErrorOk;
5080 : }
5081 :
5082 : // x86::Assembler - Events
5083 : // =======================
5084 :
5085 27492 : Error Assembler::onAttach(CodeHolder* code) noexcept {
5086 : Arch arch = code->arch();
5087 27492 : ASMJIT_PROPAGATE(Base::onAttach(code));
5088 :
5089 27492 : if (Environment::is32Bit(arch)) {
5090 : // 32 bit architecture - X86.
5091 : _forcedInstOptions |= InstOptions::kX86_InvalidRex;
5092 : _setAddressOverrideMask(kX86MemInfo_67H_X86);
5093 : }
5094 : else {
5095 : // 64 bit architecture - X64.
5096 : _forcedInstOptions &= ~InstOptions::kX86_InvalidRex;
5097 : _setAddressOverrideMask(kX86MemInfo_67H_X64);
5098 : }
5099 :
5100 : return kErrorOk;
5101 : }
5102 :
5103 0 : Error Assembler::onDetach(CodeHolder* code) noexcept {
5104 : _forcedInstOptions &= ~InstOptions::kX86_InvalidRex;
5105 : _setAddressOverrideMask(0);
5106 0 : return Base::onDetach(code);
5107 : }
5108 :
5109 : ASMJIT_END_SUB_NAMESPACE
5110 :
5111 : #endif // !ASMJIT_NO_X86
5112 :
5113 : #endif // __PLUMED_HAS_ASMJIT
|