| /* |
| * x86 identifier recognition and instruction handling |
| * |
| * Copyright (C) 2002-2007 Peter Johnson |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS'' |
| * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
| * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE |
| * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS |
| * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN |
| * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) |
| * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
| * POSSIBILITY OF SUCH DAMAGE. |
| */ |
| #include <ctype.h> |
| #include <util.h> |
| RCSID("$Id$"); |
| |
| #define YASM_LIB_INTERNAL |
| #define YASM_BC_INTERNAL |
| #define YASM_EXPR_INTERNAL |
| #include <libyasm.h> |
| #include <libyasm/phash.h> |
| |
| #include "modules/arch/x86/x86arch.h" |
| |
| |
| static const char *cpu_find_reverse(unsigned long cpu); |
| |
| /* Opcode modifiers. The opcode bytes are in "reverse" order because the |
| * parameters are read from the arch-specific data in LSB->MSB order. |
| * (only for asthetic reasons in the lexer code below, no practical reason). |
| */ |
| #define MOD_Gap0 (1UL<<0) /* Eats a parameter */ |
| #define MOD_Op2Add (1UL<<1) /* Parameter adds to opcode byte 2 */ |
| #define MOD_Gap1 (1UL<<2) /* Eats a parameter */ |
| #define MOD_Op1Add (1UL<<3) /* Parameter adds to opcode byte 1 */ |
| #define MOD_Gap2 (1UL<<4) /* Eats a parameter */ |
| #define MOD_Op0Add (1UL<<5) /* Parameter adds to opcode byte 0 */ |
| #define MOD_PreAdd (1UL<<6) /* Parameter adds to "special" prefix */ |
| #define MOD_SpAdd (1UL<<7) /* Parameter adds to "spare" value */ |
| #define MOD_OpSizeR (1UL<<8) /* Parameter replaces opersize */ |
| #define MOD_Imm8 (1UL<<9) /* Parameter is included as immediate byte */ |
| #define MOD_AdSizeR (1UL<<10) /* Parameter replaces addrsize (jmp only) */ |
| #define MOD_DOpS64R (1UL<<11) /* Parameter replaces default 64-bit opersize */ |
| #define MOD_Op1AddSp (1UL<<12) /* Parameter is added as "spare" to opcode byte 2 */ |
| |
| /* Modifiers that aren't: these are used with the GAS parser to indicate |
| * special cases. |
| */ |
| #define MOD_GasOnly (1UL<<13) /* Only available in GAS mode */ |
| #define MOD_GasIllegal (1UL<<14) /* Illegal in GAS mode */ |
| #define MOD_GasNoRev (1UL<<15) /* Don't reverse operands */ |
| #define MOD_GasSufB (1UL<<16) /* GAS B suffix ok */ |
| #define MOD_GasSufW (1UL<<17) /* GAS W suffix ok */ |
| #define MOD_GasSufL (1UL<<18) /* GAS L suffix ok */ |
| #define MOD_GasSufQ (1UL<<19) /* GAS Q suffix ok */ |
| #define MOD_GasSufS (1UL<<20) /* GAS S suffix ok */ |
| #define MOD_GasSuf_SHIFT 16 |
| #define MOD_GasSuf_MASK (0x1FUL<<16) |
| |
| /* Operand types. These are more detailed than the "general" types for all |
| * architectures, as they include the size, for instance. |
| * Bit Breakdown (from LSB to MSB): |
| * - 5 bits = general type (must be exact match, except for =3): |
| * 0 = immediate |
| * 1 = any general purpose or FPU register |
| * 2 = memory |
| * 3 = any general purpose or FPU register OR memory |
| * 4 = any MMX or XMM register |
| * 5 = any MMX or XMM register OR memory |
| * 6 = any segment register |
| * 7 = any CR register |
| * 8 = any DR register |
| * 9 = any TR register |
| * A = ST0 |
| * B = AL/AX/EAX/RAX (depending on size) |
| * C = CL/CX/ECX/RCX (depending on size) |
| * D = DL/DX/EDX/RDX (depending on size) |
| * E = CS |
| * F = DS |
| * 10 = ES |
| * 11 = FS |
| * 12 = GS |
| * 13 = SS |
| * 14 = CR4 |
| * 15 = memory offset (an EA, but with no registers allowed) |
| * [special case for MOV opcode] |
| * 16 = immediate, value=1 (for special-case shift) |
| * 17 = immediate, does not contain SEG:OFF (for jmp/call), |
| * 18 = XMM0 |
| * 19 = AX/EAX/RAX memory operand only (EA) |
| * [special case for SVM opcodes] |
| * 20 = EAX memory operand only (EA) |
| * [special case for SVM skinit opcode] |
| * - 3 bits = size (user-specified, or from register size): |
| * 0 = any size acceptable/no size spec acceptable (dep. on strict) |
| * 1/2/3/4 = 8/16/32/64 bits (from user or reg size) |
| * 5/6 = 80/128 bits (from user) |
| * 7 = current BITS setting; when this is used the size matched |
| * gets stored into the opersize as well. |
| * - 1 bit = size implicit or explicit ("strictness" of size matching on |
| * non-registers -- registers are always strictly matched): |
| * 0 = user size must exactly match size above. |
| * 1 = user size either unspecified or exactly match size above. |
| * - 3 bits = target modification. |
| * 0 = no target mod acceptable |
| * 1 = NEAR |
| * 2 = SHORT |
| * 3 = FAR (or SEG:OFF immediate) |
| * 4 = TO |
| * - 1 bit = effective address size |
| * 0 = any address size allowed except for 64-bit |
| * 1 = only 64-bit address size allowed |
| * |
| * MSBs than the above are actions: what to do with the operand if the |
| * instruction matches. Essentially describes what part of the output bytecode |
| * gets the operand. This may require conversion (e.g. a register going into |
| * an ea field). Naturally, only one of each of these may be contained in the |
| * operands of a single insn_info structure. |
| * - 4 bits = action: |
| * 0 = does nothing (operand data is discarded) |
| * 1 = operand data goes into ea field |
| * 2 = operand data goes into imm field |
| * 3 = operand data goes into sign-extended imm field |
| * 4 = operand data goes into "spare" field |
| * 5 = operand data is added to opcode byte 0 |
| * 6 = operand data is added to opcode byte 1 |
| * 7 = operand data goes into BOTH ea and spare |
| * [special case for imul opcode] |
| * 8 = relative jump (outputs a jmp instead of normal insn) |
| * 9 = operand size goes into address size (jmp only) |
| * A = far jump (outputs a farjmp instead of normal insn) |
| * B = ea operand only sets address size (no actual ea field) |
| * The below describes postponed actions: actions which can't be completed at |
| * parse-time due to possibly dependent expressions. For these, some |
| * additional data (stored in the second byte of the opcode with a one-byte |
| * opcode) is passed to later stages of the assembler with flags set to |
| * indicate postponed actions. |
| * - 3 bits = postponed action: |
| * 0 = none |
| * 1 = sign-extended imm8 that could expand to a large imm16/32 |
| * 2 = could become a short opcode mov with bits=64 and a32 prefix |
| * 3 = forced 16-bit address size (override ignored, no prefix) |
| * 4 = large imm64 that can become a sign-extended imm32. |
| */ |
| #define OPT_Imm 0x0 |
| #define OPT_Reg 0x1 |
| #define OPT_Mem 0x2 |
| #define OPT_RM 0x3 |
| #define OPT_SIMDReg 0x4 |
| #define OPT_SIMDRM 0x5 |
| #define OPT_SegReg 0x6 |
| #define OPT_CRReg 0x7 |
| #define OPT_DRReg 0x8 |
| #define OPT_TRReg 0x9 |
| #define OPT_ST0 0xA |
| #define OPT_Areg 0xB |
| #define OPT_Creg 0xC |
| #define OPT_Dreg 0xD |
| #define OPT_CS 0xE |
| #define OPT_DS 0xF |
| #define OPT_ES 0x10 |
| #define OPT_FS 0x11 |
| #define OPT_GS 0x12 |
| #define OPT_SS 0x13 |
| #define OPT_CR4 0x14 |
| #define OPT_MemOffs 0x15 |
| #define OPT_Imm1 0x16 |
| #define OPT_ImmNotSegOff 0x17 |
| #define OPT_XMM0 0x18 |
| #define OPT_MemrAX 0x19 |
| #define OPT_MemEAX 0x1A |
| #define OPT_MASK 0x1F |
| |
| #define OPS_Any (0UL<<5) |
| #define OPS_8 (1UL<<5) |
| #define OPS_16 (2UL<<5) |
| #define OPS_32 (3UL<<5) |
| #define OPS_64 (4UL<<5) |
| #define OPS_80 (5UL<<5) |
| #define OPS_128 (6UL<<5) |
| #define OPS_BITS (7UL<<5) |
| #define OPS_MASK (7UL<<5) |
| #define OPS_SHIFT 5 |
| |
| #define OPS_Relaxed (1UL<<8) |
| #define OPS_RMASK (1UL<<8) |
| |
| #define OPEAS_Not64 (0UL<<9) |
| #define OPEAS_64 (1UL<<9) |
| #define OPEAS_MASK (1UL<<9) |
| |
| #define OPTM_None (0UL<<10) |
| #define OPTM_Near (1UL<<10) |
| #define OPTM_Short (2UL<<10) |
| #define OPTM_Far (3UL<<10) |
| #define OPTM_To (4UL<<10) |
| #define OPTM_MASK (7UL<<10) |
| |
| #define OPA_None (0UL<<13) |
| #define OPA_EA (1UL<<13) |
| #define OPA_Imm (2UL<<13) |
| #define OPA_SImm (3UL<<13) |
| #define OPA_Spare (4UL<<13) |
| #define OPA_Op0Add (5UL<<13) |
| #define OPA_Op1Add (6UL<<13) |
| #define OPA_SpareEA (7UL<<13) |
| #define OPA_JmpRel (8UL<<13) |
| #define OPA_AdSizeR (9UL<<13) |
| #define OPA_JmpFar (0xAUL<<13) |
| #define OPA_AdSizeEA (0xBUL<<13) |
| #define OPA_MASK (0xFUL<<13) |
| |
| #define OPAP_None (0UL<<17) |
| #define OPAP_SImm8 (1UL<<17) |
| #define OPAP_ShortMov (2UL<<17) |
| #define OPAP_A16 (3UL<<17) |
| #define OPAP_SImm32Avail (4UL<<17) |
| #define OPAP_MASK (7UL<<17) |
| |
| typedef struct x86_insn_info { |
| /* The CPU feature flags needed to execute this instruction. This is OR'ed |
| * with arch-specific data[2]. This combined value is compared with |
| * cpu_enabled to see if all bits set here are set in cpu_enabled--if so, |
| * the instruction is available on this CPU. |
| */ |
| unsigned long cpu; |
| |
| /* Opcode modifiers for variations of instruction. As each modifier reads |
| * its parameter in LSB->MSB order from the arch-specific data[1] from the |
| * lexer data, and the LSB of the arch-specific data[1] is reserved for the |
| * count of insn_info structures in the instruction grouping, there can |
| * only be a maximum of 3 modifiers. |
| */ |
| unsigned long modifiers; |
| |
| /* Operand Size */ |
| unsigned char opersize; |
| |
| /* Default operand size in 64-bit mode (0 = 32-bit for readability). */ |
| unsigned char def_opersize_64; |
| |
| /* A special instruction prefix, used for some of the Intel SSE and SSE2 |
| * instructions. Intel calls these 3-byte opcodes, but in AMD64's 64-bit |
| * mode, they're treated like normal prefixes (e.g. the REX prefix needs |
| * to be *after* the F2/F3/66 "prefix"). |
| * (0=no special prefix) |
| */ |
| unsigned char special_prefix; |
| |
| /* The length of the basic opcode */ |
| unsigned char opcode_len; |
| |
| /* The basic 1-3 byte opcode (not including the special instruction |
| * prefix). |
| */ |
| unsigned char opcode[3]; |
| |
| /* The 3-bit "spare" value (extended opcode) for the R/M byte field */ |
| unsigned char spare; |
| |
| /* The number of operands this form of the instruction takes */ |
| unsigned char num_operands; |
| |
| /* The types of each operand, see above */ |
| unsigned long operands[3]; |
| } x86_insn_info; |
| |
| /* |
| * General instruction groupings |
| */ |
| |
| /* Empty instruction */ |
| static const x86_insn_info empty_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, {0, 0, 0} } |
| }; |
| |
| /* Placeholder for instructions invalid in 64-bit mode */ |
| static const x86_insn_info not64_insn[] = { |
| { CPU_Not64, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 0, {0, 0, 0} } |
| }; |
| |
| /* One byte opcode instructions with no operands */ |
| static const x86_insn_info onebyte_insn[] = { |
| { CPU_Any, MOD_Op0Add|MOD_OpSizeR|MOD_DOpS64R, 0, 0, 0, 1, {0, 0, 0}, 0, 0, |
| {0, 0, 0} } |
| }; |
| |
| /* One byte opcode instructions with "special" prefix with no operands */ |
| static const x86_insn_info onebyte_prefix_insn[] = { |
| { CPU_Any, MOD_Op0Add|MOD_PreAdd, 0, 0, 0x00, 1, {0x00, 0, 0}, 0, 0, |
| {0, 0, 0} } |
| }; |
| |
| /* Two byte opcode instructions with no operands */ |
| static const x86_insn_info twobyte_insn[] = { |
| { CPU_Any, MOD_Op1Add|MOD_Op0Add|MOD_GasSufL|MOD_GasSufQ, 0, 0, 0, 2, |
| {0, 0, 0}, 0, 0, {0, 0, 0} } |
| }; |
| |
| /* Three byte opcode instructions with no operands */ |
| static const x86_insn_info threebyte_insn[] = { |
| { CPU_Any, MOD_Op2Add|MOD_Op1Add|MOD_Op0Add, 0, 0, 0, 3, {0, 0, 0}, 0, 0, |
| {0, 0, 0} } |
| }; |
| |
| /* One byte opcode instructions with general memory operand */ |
| static const x86_insn_info onebytemem_insn[] = { |
| { CPU_Any, MOD_Op0Add|MOD_SpAdd|MOD_GasSufL|MOD_GasSufQ|MOD_GasSufS, |
| 0, 0, 0, 1, {0, 0, 0}, 0, 1, {OPT_Mem|OPS_Any|OPA_EA, 0, 0} } |
| }; |
| |
| /* Two byte opcode instructions with general memory operand */ |
| static const x86_insn_info twobytemem_insn[] = { |
| { CPU_Any, |
| MOD_Op1Add|MOD_Op0Add|MOD_SpAdd|MOD_GasSufL|MOD_GasSufQ|MOD_GasSufS, |
| 0, 0, 0, 2, {0, 0, 0}, 0, 1, {OPT_Mem|OPS_Any|OPA_EA, 0, 0} } |
| }; |
| |
| /* P4 VMX Instructions */ |
| static const x86_insn_info vmxmemrd_insn[] = { |
| { CPU_Not64, MOD_Op1Add|MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 2, {0, 0, 0}, 0, |
| 2, {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_64, MOD_Op1Add|MOD_Op0Add|MOD_GasSufQ, 64, 64, 0, 2, {0, 0, 0}, 0, |
| 2, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info vmxmemwr_insn[] = { |
| { CPU_Not64, MOD_Op1Add|MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 2, {0, 0, 0}, 0, |
| 2, {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_64, MOD_Op1Add|MOD_Op0Add|MOD_GasSufQ, 64, 64, 0, 2, {0, 0, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info vmxtwobytemem_insn[] = { |
| { CPU_Any, MOD_SpAdd|MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info vmxthreebytemem_insn[] = { |
| { CPU_Any, MOD_SpAdd|MOD_PreAdd|MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| |
| /* Move instructions */ |
| static const x86_insn_info mov_insn[] = { |
| /* Absolute forms for non-64-bit mode */ |
| { CPU_Not64, MOD_GasSufB, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_MemOffs|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_MemOffs|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_MemOffs|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| |
| { CPU_Not64, MOD_GasSufB, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_8|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_8|OPA_None, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_16|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_32|OPS_Relaxed|OPA_EA, OPT_Areg|OPS_32|OPA_None, 0} }, |
| |
| /* 64-bit absolute forms for 64-bit mode. Disabled for GAS, see movabs */ |
| { CPU_Hammer|CPU_64, 0, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, |
| OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, 0, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, |
| OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, 0, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, |
| OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_None, |
| OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| |
| { CPU_Hammer|CPU_64, 0, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_8|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, 0, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, 0, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_32|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_64|OPA_None, 0} }, |
| |
| /* General 32-bit forms using Areg / short absolute option */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x88, 0xA2, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA|OPAP_ShortMov, OPT_Areg|OPS_8|OPA_Spare, |
| 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA|OPAP_ShortMov, |
| OPT_Areg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA|OPAP_ShortMov, |
| OPT_Areg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x89, 0xA3, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA|OPAP_ShortMov, |
| OPT_Areg|OPS_64|OPA_Spare, 0} }, |
| |
| /* General 32-bit forms */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x88, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x89, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x89, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x89, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} }, |
| |
| /* General 32-bit forms using Areg / short absolute option */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x8A, 0xA0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA|OPAP_ShortMov, |
| 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_Spare, |
| OPT_RM|OPS_16|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_Spare, |
| OPT_RM|OPS_32|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x8B, 0xA1, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_Spare, |
| OPT_RM|OPS_64|OPS_Relaxed|OPA_EA|OPAP_ShortMov, 0} }, |
| |
| /* General 32-bit forms */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x8A, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x8B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x8B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x8B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| |
| /* Segment register forms */ |
| { CPU_Any, MOD_GasSufW, 0, 0, 0, 1, {0x8C, 0, 0}, 0, 2, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x8C, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_EA, OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x8C, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_EA, OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x8C, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_EA, OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} }, |
| |
| { CPU_Any, MOD_GasSufW, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, |
| {OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, |
| OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, |
| {OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 0, 0, 1, {0x8E, 0, 0}, 0, 2, |
| {OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, 0} }, |
| |
| /* Immediate forms */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xB0, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Op0Add, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xB8, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Op0Add, OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xB8, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Op0Add, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| /* 64-bit forced size form */ |
| { CPU_Hammer|CPU_64, MOD_GasIllegal, 64, 0, 0, 1, {0xB8, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Op0Add, OPT_Imm|OPS_64|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xB8, 0xC7, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Op0Add, |
| OPT_Imm|OPS_64|OPS_Relaxed|OPA_Imm|OPAP_SImm32Avail, 0} }, |
| /* Need two sets here, one for strictness on left side, one for right. */ |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xC6, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_16|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_32|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_32|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xC6, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xC7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| |
| /* CR/DR forms */ |
| { CPU_586|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, |
| 2, {OPT_CR4|OPS_32|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, 0} }, |
| { CPU_386|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, |
| 2, {OPT_CRReg|OPS_32|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_Priv|CPU_64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x22, 0}, 0, |
| 2, {OPT_CRReg|OPS_32|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, 0} }, |
| { CPU_586|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, |
| 2, {OPT_Reg|OPS_32|OPA_EA, OPT_CR4|OPS_32|OPA_Spare, 0} }, |
| { CPU_386|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, |
| 2, {OPT_Reg|OPS_32|OPA_EA, OPT_CRReg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_Priv|CPU_64, MOD_GasSufQ, 0, 0, 0, 2, {0x0F, 0x20, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_EA, OPT_CRReg|OPS_32|OPA_Spare, 0} }, |
| |
| { CPU_386|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x23, 0}, 0, |
| 2, {OPT_DRReg|OPS_32|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_Priv|CPU_64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x23, 0}, 0, |
| 2, {OPT_DRReg|OPS_32|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, 0} }, |
| { CPU_386|CPU_Priv|CPU_Not64, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x21, 0}, 0, |
| 2, {OPT_Reg|OPS_32|OPA_EA, OPT_DRReg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_Priv|CPU_64, MOD_GasSufQ, 0, 0, 0, 2, {0x0F, 0x21, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_EA, OPT_DRReg|OPS_32|OPA_Spare, 0} }, |
| |
| /* MMX/SSE2 forms for GAS parser (copied from movq_insn) */ |
| { CPU_MMX, MOD_GasOnly|MOD_GasSufQ, 0, 0, 0, 2, {0x0F, 0x6F, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_MMX|CPU_Hammer|CPU_64, MOD_GasOnly|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_MMX, MOD_GasOnly|MOD_GasSufQ, 0, 0, 0, 2, {0x0F, 0x7F, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} |
| }, |
| { CPU_MMX|CPU_Hammer|CPU_64, MOD_GasOnly|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} }, |
| { CPU_SSE2, MOD_GasOnly|MOD_GasSufQ, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_SSE2, MOD_GasOnly|MOD_GasSufQ, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, MOD_GasOnly|MOD_GasSufQ, 64, 0, 0x66, 2, |
| {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2, MOD_GasOnly|MOD_GasSufQ, 0, 0, 0x66, 2, {0x0F, 0xD6, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} |
| }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, MOD_GasOnly|MOD_GasSufQ, 64, 0, 0x66, 2, |
| {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| |
| /* 64-bit absolute move (for GAS). |
| * These are disabled for GAS for normal mov above. |
| */ |
| static const x86_insn_info movabs_insn[] = { |
| { CPU_Hammer|CPU_64, MOD_GasSufB, 0, 0, 0, 1, {0xA0, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, |
| OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufW, 16, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, |
| OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufL, 32, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, |
| OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xA1, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_None, |
| OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA, 0} }, |
| |
| { CPU_Hammer|CPU_64, MOD_GasSufB, 0, 0, 0, 1, {0xA2, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_8|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_8|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufW, 16, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_16|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufL, 32, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_32|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_32|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xA3, 0, 0}, 0, 2, |
| {OPT_MemOffs|OPS_64|OPS_Relaxed|OPEAS_64|OPA_EA, |
| OPT_Areg|OPS_64|OPA_None, 0} }, |
| |
| /* 64-bit immediate form */ |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xB8, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Op0Add, OPT_Imm|OPS_64|OPS_Relaxed|OPA_Imm, 0} }, |
| }; |
| |
| /* Move with sign/zero extend */ |
| static const x86_insn_info movszx_insn[] = { |
| { CPU_386, MOD_Op1Add|MOD_GasSufB, 16, 0, 0, 2, {0x0F, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufB, 32, 0, 0, 2, {0x0F, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_8|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufB, 64, 0, 0, 2, {0x0F, 0, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_8|OPA_EA, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufW, 32, 0, 0, 2, {0x0F, 1, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_16|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufW, 64, 0, 0, 2, {0x0F, 1, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_16|OPA_EA, 0} } |
| }; |
| |
| /* Move with sign-extend doubleword (64-bit mode only) */ |
| static const x86_insn_info movsxd_insn[] = { |
| { CPU_Hammer|CPU_64, MOD_GasSufL, 64, 0, 0, 1, {0x63, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_32|OPA_EA, 0} } |
| }; |
| |
| /* Push instructions */ |
| static const x86_insn_info push_insn[] = { |
| { CPU_Any, MOD_GasSufW, 16, 64, 0, 1, {0x50, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_16|OPA_Op0Add, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x50, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_32|OPA_Op0Add, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 64, 0, 1, {0x50, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_64|OPA_Op0Add, 0, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 64, 0, 1, {0xFF, 0, 0}, 6, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0xFF, 0, 0}, 6, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 64, 0, 1, {0xFF, 0, 0}, 6, 1, |
| {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_186, MOD_GasIllegal, 0, 64, 0, 1, {0x6A, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPA_SImm, 0, 0} }, |
| { CPU_186, MOD_GasOnly|MOD_GasSufB, 0, 64, 0, 1, {0x6A, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_SImm, 0, 0} }, |
| { CPU_186, MOD_GasOnly|MOD_GasSufW, 16, 64, 0, 1, {0x6A, 0x68, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, |
| {0x6A, 0x68, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 64, 0, 1, |
| {0x6A, 0x68, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8, 0, 0} }, |
| { CPU_186|CPU_Not64, MOD_GasIllegal, 0, 0, 0, 1, |
| {0x6A, 0x68, 0}, 0, 1, |
| {OPT_Imm|OPS_BITS|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0, 0} }, |
| /* Need these when we don't match the BITS size, but they need to be |
| * below the above line so the optimizer can kick in by default. |
| */ |
| { CPU_186, MOD_GasIllegal, 16, 64, 0, 1, {0x68, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPA_Imm, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasIllegal, 32, 0, 0, 1, {0x68, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPA_Imm, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasIllegal, 64, 64, 0, 1, {0x68, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPA_SImm, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x0E, 0, 0}, 0, 1, |
| {OPT_CS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0x0E, 0, 0}, 0, 1, |
| {OPT_CS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x0E, 0, 0}, 0, 1, |
| {OPT_CS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x16, 0, 0}, 0, 1, |
| {OPT_SS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0x16, 0, 0}, 0, 1, |
| {OPT_SS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x16, 0, 0}, 0, 1, |
| {OPT_SS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x1E, 0, 0}, 0, 1, |
| {OPT_DS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0x1E, 0, 0}, 0, 1, |
| {OPT_DS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x1E, 0, 0}, 0, 1, |
| {OPT_DS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x06, 0, 0}, 0, 1, |
| {OPT_ES|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufW, 16, 0, 0, 1, {0x06, 0, 0}, 0, 1, |
| {OPT_ES|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x06, 0, 0}, 0, 1, |
| {OPT_ES|OPS_32|OPA_None, 0, 0} }, |
| { CPU_386, 0, 0, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, |
| {OPT_FS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, |
| {OPT_FS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0xA0, 0}, 0, 1, |
| {OPT_FS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_386, 0, 0, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, |
| {OPT_GS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, |
| {OPT_GS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0xA8, 0}, 0, 1, |
| {OPT_GS|OPS_32|OPA_None, 0, 0} } |
| }; |
| |
| /* Pop instructions */ |
| static const x86_insn_info pop_insn[] = { |
| { CPU_Any, MOD_GasSufW, 16, 64, 0, 1, {0x58, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_16|OPA_Op0Add, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x58, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_32|OPA_Op0Add, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 64, 0, 1, {0x58, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_64|OPA_Op0Add, 0, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 64, 0, 1, {0x8F, 0, 0}, 0, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_GasSufL, 32, 0, 0, 1, {0x8F, 0, 0}, 0, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 64, 0, 1, {0x8F, 0, 0}, 0, 1, |
| {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| /* POP CS is debateably valid on the 8086, if obsolete and undocumented. |
| * We don't include it because it's VERY unlikely it will ever be used |
| * anywhere. If someone really wants it they can db 0x0F it. |
| */ |
| /*{ CPU_Any|CPU_Undoc|CPU_Obs, 0, 0, 1, {0x0F, 0, 0}, 0, 1, |
| {OPT_CS|OPS_Any|OPA_None, 0, 0} },*/ |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x17, 0, 0}, 0, 1, |
| {OPT_SS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 16, 0, 0, 1, {0x17, 0, 0}, 0, 1, |
| {OPT_SS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 32, 0, 0, 1, {0x17, 0, 0}, 0, 1, |
| {OPT_SS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x1F, 0, 0}, 0, 1, |
| {OPT_DS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 16, 0, 0, 1, {0x1F, 0, 0}, 0, 1, |
| {OPT_DS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 32, 0, 0, 1, {0x1F, 0, 0}, 0, 1, |
| {OPT_DS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x07, 0, 0}, 0, 1, |
| {OPT_ES|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 16, 0, 0, 1, {0x07, 0, 0}, 0, 1, |
| {OPT_ES|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Not64, 0, 32, 0, 0, 1, {0x07, 0, 0}, 0, 1, |
| {OPT_ES|OPS_32|OPA_None, 0, 0} }, |
| { CPU_386, 0, 0, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, |
| {OPT_FS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_386, 0, 16, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, |
| {OPT_FS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, 0, 32, 0, 0, 2, {0x0F, 0xA1, 0}, 0, 1, |
| {OPT_FS|OPS_32|OPA_None, 0, 0} }, |
| { CPU_386, 0, 0, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, |
| {OPT_GS|OPS_Any|OPA_None, 0, 0} }, |
| { CPU_386, 0, 16, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, |
| {OPT_GS|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, 0, 32, 0, 0, 2, {0x0F, 0xA9, 0}, 0, 1, |
| {OPT_GS|OPS_32|OPA_None, 0, 0} } |
| }; |
| |
| /* Exchange instructions */ |
| static const x86_insn_info xchg_insn[] = { |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x86, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x86, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| /* We could be extra-efficient in the 64-bit mode case here. |
| * XCHG AX, AX in 64-bit mode is a NOP, as it doesn't clear the |
| * high 48 bits of RAX. Thus we don't need the operand-size prefix. |
| * But this feels too clever, and probably not what the user really |
| * expects in the generated code, so we don't do it. |
| * |
| * { CPU_Any|CPU_64, MOD_GasSufW, 0, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| * {OPT_Areg|OPS_16|OPA_None, OPT_Areg|OPS_16|OPA_Op0Add, 0} }, |
| */ |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_Reg|OPS_16|OPA_Op0Add, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Op0Add, OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| /* Be careful with XCHG EAX, EAX in 64-bit mode. This needs to use |
| * the long form rather than the NOP form, as the long form clears |
| * the high 32 bits of RAX. This makes all 32-bit forms in 64-bit |
| * mode have consistent operation. |
| */ |
| { CPU_386|CPU_64, MOD_GasSufL, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_EA, OPT_Areg|OPS_32|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_Reg|OPS_32|OPA_Op0Add, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Op0Add, OPT_Areg|OPS_32|OPA_None, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| /* Be efficient with XCHG RAX, RAX. |
| * This is a NOP and thus doesn't need the REX prefix. |
| */ |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 0, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_None, OPT_Areg|OPS_64|OPA_Op0Add, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_None, OPT_Reg|OPS_64|OPA_Op0Add, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x90, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Op0Add, OPT_Areg|OPS_64|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x87, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* In/out from ports */ |
| static const x86_insn_info in_insn[] = { |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xE4, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xE5, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xE5, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xEC, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_Dreg|OPS_16|OPA_None, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xED, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_Dreg|OPS_16|OPA_None, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xED, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_Dreg|OPS_16|OPA_None, 0} }, |
| /* GAS-only variants (implict accumulator register) */ |
| { CPU_Any, MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xE4, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 1, {0xE5, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_386, MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, {0xE5, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xEC, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 1, {0xED, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, {0xED, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} } |
| }; |
| static const x86_insn_info out_insn[] = { |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xE6, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, OPT_Areg|OPS_8|OPA_None, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xE7, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xE7, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, OPT_Areg|OPS_32|OPA_None, 0} }, |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xEE, 0, 0}, 0, 2, |
| {OPT_Dreg|OPS_16|OPA_None, OPT_Areg|OPS_8|OPA_None, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xEF, 0, 0}, 0, 2, |
| {OPT_Dreg|OPS_16|OPA_None, OPT_Areg|OPS_16|OPA_None, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xEF, 0, 0}, 0, 2, |
| {OPT_Dreg|OPS_16|OPA_None, OPT_Areg|OPS_32|OPA_None, 0} }, |
| /* GAS-only variants (implict accumulator register) */ |
| { CPU_Any, MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xE6, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 1, {0xE7, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_386, MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, {0xE7, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xEE, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} }, |
| { CPU_Any, MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 1, {0xEF, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} }, |
| { CPU_386, MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, {0xEF, 0, 0}, 0, 1, |
| {OPT_Dreg|OPS_16|OPA_None, 0, 0} } |
| }; |
| |
| /* Load effective address */ |
| static const x86_insn_info lea_insn[] = { |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x8D, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x8D, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x8D, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Load segment registers from memory */ |
| static const x86_insn_info ldes_insn[] = { |
| { CPU_Not64, MOD_Op0Add|MOD_GasSufW, 16, 0, 0, 1, {0, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_Mem|OPS_Any|OPA_EA, 0} }, |
| { CPU_386|CPU_Not64, MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 1, {0, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_Any|OPA_EA, 0} } |
| }; |
| static const x86_insn_info lfgss_insn[] = { |
| { CPU_386, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_Mem|OPS_Any|OPA_EA, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_Any|OPA_EA, 0} } |
| }; |
| |
| /* Arithmetic - general */ |
| static const x86_insn_info arith_insn[] = { |
| { CPU_Any, MOD_Op0Add|MOD_GasSufB, 0, 0, 0, 1, {0x04, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_Op2Add|MOD_Op1AddSp|MOD_GasSufW, 16, 0, 0, 2, |
| {0x83, 0xC0, 0x05}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, |
| OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| { CPU_386, MOD_Op2Add|MOD_Op1AddSp|MOD_GasSufL, 32, 0, 0, 2, |
| {0x83, 0xC0, 0x05}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op2Add|MOD_Op1AddSp|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x83, 0xC0, 0x05}, 0, |
| 2, {OPT_Areg|OPS_64|OPA_None, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0x80, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0x80, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPA_Imm, 0} }, |
| |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0x83, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasIllegal, 16, 0, 0, 1, {0x83, 0x81, 0}, |
| 0, 2, {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_16|OPA_Imm|OPAP_SImm8, 0} }, |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0x83, 0x81, 0}, 0, |
| 2, {OPT_RM|OPS_16|OPA_EA, |
| OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| |
| { CPU_386, MOD_Gap0|MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0x83, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| /* Not64 because we can't tell if add [], dword in 64-bit mode is supposed |
| * to be a qword destination or a dword destination. |
| */ |
| { CPU_386|CPU_Not64, MOD_Gap0|MOD_SpAdd|MOD_GasIllegal, 32, 0, 0, 1, |
| {0x83, 0x81, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_32|OPA_Imm|OPAP_SImm8, 0} }, |
| { CPU_386, MOD_Gap0|MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0x83, 0x81, 0}, 0, |
| 2, {OPT_RM|OPS_32|OPA_EA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| |
| /* No relaxed-RM mode for 64-bit destinations; see above Not64 comment. */ |
| { CPU_Hammer|CPU_64, MOD_Gap0|MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, |
| {0x83, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Gap0|MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, |
| {0x83, 0x81, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPA_EA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm|OPAP_SImm8, 0} }, |
| |
| { CPU_Any, MOD_Op0Add|MOD_GasSufB, 0, 0, 0, 1, {0x00, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_Any, MOD_Op0Add|MOD_GasSufW, 16, 0, 0, 1, {0x01, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 1, {0x01, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op0Add|MOD_GasSufQ, 64, 0, 0, 1, {0x01, 0, 0}, 0, |
| 2, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} }, |
| { CPU_Any, MOD_Op0Add|MOD_GasSufB, 0, 0, 0, 1, {0x02, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Any, MOD_Op0Add|MOD_GasSufW, 16, 0, 0, 1, {0x03, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 1, {0x03, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op0Add|MOD_GasSufQ, 64, 0, 0, 1, {0x03, 0, 0}, 0, |
| 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Arithmetic - inc/dec */ |
| static const x86_insn_info incdec_insn[] = { |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xFE, 0, 0}, 0, 1, |
| {OPT_RM|OPS_8|OPA_EA, 0, 0} }, |
| { CPU_Not64, MOD_Op0Add|MOD_GasSufW, 16, 0, 0, 1, {0, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_16|OPA_Op0Add, 0, 0} }, |
| { CPU_Any, MOD_Gap0|MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xFF, 0, 0}, 0, |
| 1, {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_Op0Add|MOD_GasSufL, 32, 0, 0, 1, {0, 0, 0}, 0, 1, |
| {OPT_Reg|OPS_32|OPA_Op0Add, 0, 0} }, |
| { CPU_386, MOD_Gap0|MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xFF, 0, 0}, 0, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Gap0|MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, |
| {0xFF, 0, 0}, 0, 1, {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| }; |
| |
| /* Arithmetic - mul/neg/not F6 opcodes */ |
| static const x86_insn_info f6_insn[] = { |
| { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 1, |
| {OPT_RM|OPS_8|OPA_EA, 0, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 0, |
| 1, {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| }; |
| |
| /* Arithmetic - div/idiv F6 opcodes |
| * These allow explicit accumulator in GAS mode. |
| */ |
| static const x86_insn_info div_insn[] = { |
| { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 1, |
| {OPT_RM|OPS_8|OPA_EA, 0, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 0, |
| 1, {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| /* Versions with explicit accumulator */ |
| { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_RM|OPS_8|OPA_EA, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_RM|OPS_16|OPA_EA, 0} }, |
| { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_RM|OPS_32|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 0, |
| 2, {OPT_Areg|OPS_64|OPA_None, OPT_RM|OPS_64|OPA_EA, 0} }, |
| }; |
| |
| /* Arithmetic - test instruction */ |
| static const x86_insn_info test_insn[] = { |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xA8, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_8|OPA_None, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xA9, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_16|OPA_None, OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xA9, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_32|OPA_None, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xA9, 0, 0}, 0, 2, |
| {OPT_Areg|OPS_64|OPA_None, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_16|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_32|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_32|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_32|OPA_Imm, 0} }, |
| |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x84, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} }, |
| |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0x84, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x85, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Arithmetic - aad/aam */ |
| static const x86_insn_info aadm_insn[] = { |
| { CPU_Any, MOD_Op0Add, 0, 0, 0, 2, {0xD4, 0x0A, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_Any, MOD_Op0Add, 0, 0, 0, 1, {0xD4, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} } |
| }; |
| |
| /* Arithmetic - imul */ |
| static const x86_insn_info imul_insn[] = { |
| { CPU_Any, MOD_GasSufB, 0, 0, 0, 1, {0xF6, 0, 0}, 5, 1, |
| {OPT_RM|OPS_8|OPA_EA, 0, 0} }, |
| { CPU_Any, MOD_GasSufW, 16, 0, 0, 1, {0xF7, 0, 0}, 5, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0xF7, 0, 0}, 5, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0xF7, 0, 0}, 5, 1, |
| {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| |
| { CPU_386, MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xAF, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| |
| { CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0, 0}, 0, 3, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPA_SImm} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0, 0}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPA_SImm} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0, 0}, 0, 3, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPA_SImm} }, |
| |
| { CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_SpareEA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_SpareEA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_SpareEA, OPT_Imm|OPS_8|OPA_SImm, 0} }, |
| |
| { CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_16|OPS_Relaxed|OPA_SImm|OPAP_SImm8} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 3, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8} }, |
| |
| { CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_SpareEA, |
| OPT_Imm|OPS_16|OPS_Relaxed|OPA_SImm|OPAP_SImm8, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_SpareEA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 1, {0x6B, 0x69, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_SpareEA, |
| OPT_Imm|OPS_32|OPS_Relaxed|OPA_SImm|OPAP_SImm8, 0} } |
| }; |
| |
| /* Shifts - standard */ |
| static const x86_insn_info shift_insn[] = { |
| { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD2, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, |
| { CPU_186, MOD_SpAdd|MOD_GasSufB, 0, 0, 0, 1, {0xC0, 0, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD3, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, |
| { CPU_186, MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 1, {0xC1, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD3, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, |
| { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, |
| { CPU_386, MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 1, {0xC1, 0, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD3, 0, 0}, 0, |
| 2, {OPT_RM|OPS_64|OPA_EA, OPT_Creg|OPS_8|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xD1, 0, 0}, |
| 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm1|OPS_8|OPS_Relaxed|OPA_None, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 1, {0xC1, 0, 0}, |
| 0, 2, {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| /* In GAS mode, single operands are equivalent to shifting by 1 forms */ |
| { CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufB, 0, 0, 0, 1, {0xD0, 0, 0}, |
| 0, 1, {OPT_RM|OPS_8|OPA_EA, 0, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 1, {0xD1, 0, 0}, |
| 0, 1, {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_Any, MOD_SpAdd|MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 1, {0xD1, 0, 0}, |
| 0, 1, {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_SpAdd|MOD_GasOnly|MOD_GasSufQ, 64, 0, 0, 1, |
| {0xD1, 0, 0}, 0, 1, {OPT_RM|OPS_64|OPA_EA, 0, 0} } |
| }; |
| |
| /* Shifts - doubleword */ |
| static const x86_insn_info shlrd_insn[] = { |
| { CPU_386, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x01, 0}, 0, 3, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, |
| OPT_Creg|OPS_8|OPA_None} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 3, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, |
| OPT_Creg|OPS_8|OPA_None} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 3, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x01, 0}, |
| 0, 3, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, |
| OPT_Creg|OPS_8|OPA_None} }, |
| /* GAS parser supports two-operand form for shift with CL count */ |
| { CPU_386, MOD_Op1Add|MOD_GasOnly|MOD_GasSufW, 16, 0, 0, 2, |
| {0x0F, 0x01, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasOnly|MOD_GasSufL, 32, 0, 0, 2, |
| {0x0F, 0x01, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasOnly|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x0F, 0x01, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} } |
| }; |
| |
| /* Control transfer instructions (unconditional) */ |
| static const x86_insn_info call_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} }, |
| |
| { CPU_Any, 0, 16, 64, 0, 1, {0xE8, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xE8, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xE8, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xE8, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| |
| { CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_Mem|OPS_Any|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 16, 64, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_16|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_32|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_RM|OPS_64|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 2, 1, |
| {OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} }, |
| |
| /* Far indirect (through memory). Needs explicit FAR override. */ |
| { CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_32|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }, |
| |
| /* With explicit FAR override */ |
| { CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| |
| /* Since not caught by first ImmNotSegOff group, implicitly FAR. */ |
| { CPU_Not64, 0, 16, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0x9A, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} } |
| }; |
| static const x86_insn_info jmp_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_Any|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_16|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 0, 0, 1, {0, 0, 0}, 0, 1, |
| {OPT_ImmNotSegOff|OPS_32|OPA_JmpRel, 0, 0} }, |
| |
| { CPU_Any, 0, 0, 64, 0, 1, {0xEB, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 16, 64, 0, 1, {0xE9, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xE9, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xE9, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xE9, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| |
| { CPU_Any, 0, 16, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_Mem|OPS_Any|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 16, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_16|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_32|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_RM|OPS_64|OPTM_Near|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 64, 0, 1, {0xFF, 0, 0}, 4, 1, |
| {OPT_Mem|OPS_Any|OPTM_Near|OPA_EA, 0, 0} }, |
| |
| /* Far indirect (through memory). Needs explicit FAR override. */ |
| { CPU_Any, 0, 16, 0, 0, 1, {0xFF, 0, 0}, 5, 1, |
| {OPT_Mem|OPS_16|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_386, 0, 32, 0, 0, 1, {0xFF, 0, 0}, 5, 1, |
| {OPT_Mem|OPS_32|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_EM64T|CPU_64, 0, 64, 0, 0, 1, {0xFF, 0, 0}, 5, 1, |
| {OPT_Mem|OPS_64|OPTM_Far|OPA_EA, 0, 0} }, |
| { CPU_Any, 0, 0, 0, 0, 1, {0xFF, 0, 0}, 5, 1, |
| {OPT_Mem|OPS_Any|OPTM_Far|OPA_EA, 0, 0} }, |
| |
| /* With explicit FAR override */ |
| { CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_16|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_32|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_Any|OPTM_Far|OPA_JmpFar, 0, 0} }, |
| |
| /* Since not caught by first ImmNotSegOff group, implicitly FAR. */ |
| { CPU_Not64, 0, 16, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_16|OPA_JmpFar, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_32|OPA_JmpFar, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 1, {0xEA, 0, 0}, 3, 1, |
| {OPT_Imm|OPS_Any|OPA_JmpFar, 0, 0} } |
| }; |
| static const x86_insn_info retnf_insn[] = { |
| { CPU_Not64, MOD_Op0Add, 0, 0, 0, 1, |
| {0x01, 0, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_Not64, MOD_Op0Add, 0, 0, 0, 1, |
| {0x00, 0, 0}, 0, 1, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| { CPU_64, MOD_Op0Add|MOD_OpSizeR, 0, 0, 0, 1, |
| {0x01, 0, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_64, MOD_Op0Add|MOD_OpSizeR, 0, 0, 0, 1, |
| {0x00, 0, 0}, 0, 1, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0, 0} }, |
| /* GAS suffix versions */ |
| { CPU_Any, MOD_Op0Add|MOD_OpSizeR|MOD_GasSufW|MOD_GasSufL|MOD_GasSufQ, 0, |
| 0, 0, 1, {0x01, 0, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_Any, MOD_Op0Add|MOD_OpSizeR|MOD_GasSufW|MOD_GasSufL|MOD_GasSufQ, 0, |
| 0, 0, 1, {0x00, 0, 0}, 0, 1, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_Imm, 0, 0} } |
| }; |
| static const x86_insn_info enter_insn[] = { |
| { CPU_186|CPU_Not64, MOD_GasNoRev|MOD_GasSufL, 0, 0, 0, 1, {0xC8, 0, 0}, 0, |
| 2, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_EA|OPAP_A16, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasNoRev|MOD_GasSufQ, 64, 64, 0, 1, {0xC8, 0, 0}, |
| 0, 2, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_EA|OPAP_A16, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| /* GAS suffix version */ |
| { CPU_186, MOD_GasOnly|MOD_GasNoRev|MOD_GasSufW, 16, 0, 0, 1, |
| {0xC8, 0, 0}, 0, 2, {OPT_Imm|OPS_16|OPS_Relaxed|OPA_EA|OPAP_A16, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| }; |
| |
| /* Conditional jumps */ |
| static const x86_insn_info jcc_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, 0, 16, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, 0, 32, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, 0, 64, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPA_JmpRel, 0, 0} }, |
| |
| { CPU_Any, MOD_Op0Add, 0, 64, 0, 1, {0x70, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} }, |
| { CPU_386, MOD_Op1Add, 16, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, |
| {OPT_Imm|OPS_16|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_386|CPU_Not64, MOD_Op1Add, 32, 0, 0, 2, {0x0F, 0x80, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add, 64, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, |
| {OPT_Imm|OPS_32|OPTM_Near|OPA_JmpRel, 0, 0} }, |
| { CPU_386, MOD_Op1Add, 0, 64, 0, 2, {0x0F, 0x80, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Near|OPA_JmpRel, 0, 0} } |
| }; |
| static const x86_insn_info jcxz_insn[] = { |
| { CPU_Any, MOD_AdSizeR, 0, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, MOD_AdSizeR, 0, 64, 0, 1, {0xE3, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} } |
| }; |
| |
| /* Loop instructions */ |
| static const x86_insn_info loop_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, 0, 0} }, |
| { CPU_Not64, 0, 0, 0, 0, 0, {0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, OPT_Creg|OPS_16|OPA_AdSizeR, 0} }, |
| { CPU_386, 0, 0, 64, 0, 0, {0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, OPT_Creg|OPS_32|OPA_AdSizeR, 0} }, |
| { CPU_Hammer|CPU_64, 0, 0, 64, 0, 0, {0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPA_JmpRel, OPT_Creg|OPS_64|OPA_AdSizeR, 0} }, |
| |
| { CPU_Not64, MOD_Op0Add, 0, 0, 0, 1, {0xE0, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, 0, 0} }, |
| { CPU_Any, MOD_Op0Add, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, OPT_Creg|OPS_16|OPA_AdSizeR, 0} |
| }, |
| { CPU_386, MOD_Op0Add, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, OPT_Creg|OPS_32|OPA_AdSizeR, 0} |
| }, |
| { CPU_Hammer|CPU_64, MOD_Op0Add, 0, 64, 0, 1, {0xE0, 0, 0}, 0, 2, |
| {OPT_Imm|OPS_Any|OPTM_Short|OPA_JmpRel, OPT_Creg|OPS_64|OPA_AdSizeR, 0} } |
| }; |
| |
| /* Set byte on flag instructions */ |
| static const x86_insn_info setcc_insn[] = { |
| { CPU_386, MOD_Op1Add|MOD_GasSufB, 0, 0, 0, 2, {0x0F, 0x90, 0}, 2, 1, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| |
| /* Bit manipulation - bit tests */ |
| static const x86_insn_info bittest_insn[] = { |
| { CPU_386, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 2, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} }, |
| { CPU_386, MOD_Gap0|MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0xBA, 0}, |
| 0, 2, {OPT_RM|OPS_16|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_386, MOD_Gap0|MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0xBA, 0}, |
| 0, 2, {OPT_RM|OPS_32|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Gap0|MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x0F, 0xBA, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} } |
| }; |
| |
| /* Bit manipulation - bit scans - also used for lar/lsl */ |
| static const x86_insn_info bsfr_insn[] = { |
| { CPU_286, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Interrupts and operating system instructions */ |
| static const x86_insn_info int_insn[] = { |
| { CPU_Any, 0, 0, 0, 0, 1, {0xCD, 0, 0}, 0, 1, |
| {OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0, 0} } |
| }; |
| static const x86_insn_info bound_insn[] = { |
| { CPU_186, MOD_GasSufW, 16, 0, 0, 1, {0x62, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386, MOD_GasSufL, 32, 0, 0, 1, {0x62, 0, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Protection control */ |
| static const x86_insn_info arpl_insn[] = { |
| { CPU_286|CPU_Prot, MOD_GasSufW, 0, 0, 0, 1, {0x63, 0, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info str_insn[] = { |
| { CPU_286|CPU_Prot, MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, |
| {OPT_Reg|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386|CPU_Prot, MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, 1, 1, |
| {OPT_Reg|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64|CPU_Prot, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x00, 0}, 1, |
| 1, {OPT_Reg|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_286|CPU_Prot, MOD_GasSufW|MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x00, 0}, |
| 1, 1, {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info prot286_insn[] = { |
| { CPU_286, MOD_Op1Add|MOD_SpAdd|MOD_GasSufW, 0, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 1, {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info sldtmsw_insn[] = { |
| { CPU_286, MOD_Op1Add|MOD_SpAdd|MOD_GasSufW, 0, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 1, {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_SpAdd|MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 1, {OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_SpAdd|MOD_GasSufQ, 0, 0, 0, 2, |
| {0x0F, 0x00, 0}, 0, 1, {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0, 0} }, |
| { CPU_286, MOD_Op1Add|MOD_SpAdd|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 1, {OPT_Reg|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_386, MOD_Op1Add|MOD_SpAdd|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x00, 0}, |
| 0, 1, {OPT_Reg|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_SpAdd|MOD_GasSufQ, 64, 0, 0, 2, |
| {0x0F, 0x00, 0}, 0, 1, {OPT_Reg|OPS_64|OPA_EA, 0, 0} } |
| }; |
| |
| /* Floating point instructions - load/store with pop (integer and normal) */ |
| static const x86_insn_info fld_insn[] = { |
| { CPU_FPU, MOD_GasSufS, 0, 0, 0, 1, {0xD9, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_GasSufL, 0, 0, 0, 1, {0xDD, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 1, {0xDB, 0, 0}, 5, 1, |
| {OPT_Mem|OPS_80|OPA_EA, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xD9, 0xC0, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} } |
| }; |
| static const x86_insn_info fstp_insn[] = { |
| { CPU_FPU, MOD_GasSufS, 0, 0, 0, 1, {0xD9, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_GasSufL, 0, 0, 0, 1, {0xDD, 0, 0}, 3, 1, |
| {OPT_Mem|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 1, {0xDB, 0, 0}, 7, 1, |
| {OPT_Mem|OPS_80|OPA_EA, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xDD, 0xD8, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} } |
| }; |
| /* Long memory version of floating point load/store for GAS */ |
| static const x86_insn_info fldstpt_insn[] = { |
| { CPU_FPU, MOD_SpAdd, 0, 0, 0, 1, {0xDB, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_80|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info fildstp_insn[] = { |
| { CPU_FPU, MOD_SpAdd|MOD_GasSufS, 0, 0, 0, 1, {0xDF, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_SpAdd|MOD_GasSufL, 0, 0, 0, 1, {0xDB, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_Op0Add|MOD_SpAdd|MOD_GasSufQ, 0, 0, 0, 1, |
| {0xDD, 0, 0}, 0, 1, {OPT_Mem|OPS_64|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info fbldstp_insn[] = { |
| { CPU_FPU, MOD_SpAdd, 0, 0, 0, 1, {0xDF, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_80|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| /* Floating point instructions - store (normal) */ |
| static const x86_insn_info fst_insn[] = { |
| { CPU_FPU, MOD_GasSufS, 0, 0, 0, 1, {0xD9, 0, 0}, 2, 1, |
| {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_GasSufL, 0, 0, 0, 1, {0xDD, 0, 0}, 2, 1, |
| {OPT_Mem|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xDD, 0xD0, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} } |
| }; |
| /* Floating point instructions - exchange (with ST0) */ |
| static const x86_insn_info fxch_insn[] = { |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 2, |
| {OPT_ST0|OPS_80|OPA_None, OPT_Reg|OPS_80|OPA_Op1Add, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xD9, 0xC8, 0}, 0, 2, |
| {OPT_Reg|OPS_80|OPA_Op1Add, OPT_ST0|OPS_80|OPA_None, 0} }, |
| { CPU_FPU, 0, 0, 0, 0, 2, {0xD9, 0xC9, 0}, 0, 0, {0, 0, 0} } |
| }; |
| /* Floating point instructions - comparisons */ |
| static const x86_insn_info fcom_insn[] = { |
| { CPU_FPU, MOD_Gap0|MOD_SpAdd|MOD_GasSufS, 0, 0, 0, 1, {0xD8, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_SpAdd|MOD_GasSufL, 0, 0, 0, 1, {0xDC, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Op1Add, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} }, |
| /* Alias for fcom %st(1) for GAS compat */ |
| { CPU_FPU, MOD_Op1Add|MOD_GasOnly, 0, 0, 0, 2, {0xD8, 0x01, 0}, 0, 0, |
| {0, 0, 0} }, |
| { CPU_FPU, MOD_Op1Add|MOD_GasIllegal, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 2, |
| {OPT_ST0|OPS_80|OPA_None, OPT_Reg|OPS_80|OPA_Op1Add, 0} } |
| }; |
| /* Floating point instructions - extended comparisons */ |
| static const x86_insn_info fcom2_insn[] = { |
| { CPU_286|CPU_FPU, MOD_Op0Add|MOD_Op1Add, 0, 0, 0, 2, {0x00, 0x00, 0}, |
| 0, 1, {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} }, |
| { CPU_286|CPU_FPU, MOD_Op0Add|MOD_Op1Add, 0, 0, 0, 2, {0x00, 0x00, 0}, |
| 0, 2, {OPT_ST0|OPS_80|OPA_None, OPT_Reg|OPS_80|OPA_Op1Add, 0} } |
| }; |
| /* Floating point instructions - arithmetic */ |
| static const x86_insn_info farith_insn[] = { |
| { CPU_FPU, MOD_Gap0|MOD_Gap1|MOD_SpAdd|MOD_GasSufS, 0, 0, 0, 1, |
| {0xD8, 0, 0}, 0, 1, {OPT_Mem|OPS_32|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_Gap1|MOD_SpAdd|MOD_GasSufL, 0, 0, 0, 1, |
| {0xDC, 0, 0}, 0, 1, {OPT_Mem|OPS_64|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_Op1Add, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_Op1Add, 0, 0, 0, 2, {0xD8, 0x00, 0}, 0, 2, |
| {OPT_ST0|OPS_80|OPA_None, OPT_Reg|OPS_80|OPA_Op1Add, 0} }, |
| { CPU_FPU, MOD_Op1Add, 0, 0, 0, 2, {0xDC, 0x00, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPTM_To|OPA_Op1Add, 0, 0} }, |
| { CPU_FPU, MOD_Op1Add|MOD_GasIllegal, 0, 0, 0, 2, {0xDC, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_80|OPA_Op1Add, OPT_ST0|OPS_80|OPA_None, 0} }, |
| { CPU_FPU, MOD_Gap0|MOD_Op1Add|MOD_GasOnly, 0, 0, 0, 2, {0xDC, 0x00, 0}, |
| 0, 2, {OPT_Reg|OPS_80|OPA_Op1Add, OPT_ST0|OPS_80|OPA_None, 0} } |
| }; |
| static const x86_insn_info farithp_insn[] = { |
| { CPU_FPU, MOD_Op1Add, 0, 0, 0, 2, {0xDE, 0x01, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_FPU, MOD_Op1Add, 0, 0, 0, 2, {0xDE, 0x00, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} }, |
| { CPU_FPU, MOD_Op1Add, 0, 0, 0, 2, {0xDE, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_80|OPA_Op1Add, OPT_ST0|OPS_80|OPA_None, 0} } |
| }; |
| /* Floating point instructions - integer arith/store wo pop/compare */ |
| static const x86_insn_info fiarith_insn[] = { |
| { CPU_FPU, MOD_Op0Add|MOD_SpAdd|MOD_GasSufS, 0, 0, 0, 1, {0x04, 0, 0}, 0, |
| 1, {OPT_Mem|OPS_16|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_Op0Add|MOD_SpAdd|MOD_GasSufL, 0, 0, 0, 1, {0x00, 0, 0}, 0, |
| 1, {OPT_Mem|OPS_32|OPA_EA, 0, 0} } |
| }; |
| /* Floating point instructions - processor control */ |
| static const x86_insn_info fldnstcw_insn[] = { |
| { CPU_FPU, MOD_SpAdd|MOD_GasSufW, 0, 0, 0, 1, {0xD9, 0, 0}, 0, 1, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info fstcw_insn[] = { |
| { CPU_FPU, MOD_GasSufW, 0, 0, 0, 2, {0x9B, 0xD9, 0}, 7, 1, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info fnstsw_insn[] = { |
| { CPU_FPU, MOD_GasSufW, 0, 0, 0, 1, {0xDD, 0, 0}, 7, 1, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_GasSufW, 0, 0, 0, 2, {0xDF, 0xE0, 0}, 0, 1, |
| {OPT_Areg|OPS_16|OPA_None, 0, 0} } |
| }; |
| static const x86_insn_info fstsw_insn[] = { |
| { CPU_FPU, MOD_GasSufW, 0, 0, 0, 2, {0x9B, 0xDD, 0}, 7, 1, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0, 0} }, |
| { CPU_FPU, MOD_GasSufW, 0, 0, 0, 3, {0x9B, 0xDF, 0xE0}, 0, 1, |
| {OPT_Areg|OPS_16|OPA_None, 0, 0} } |
| }; |
| static const x86_insn_info ffree_insn[] = { |
| { CPU_FPU, MOD_Op0Add, 0, 0, 0, 2, {0x00, 0xC0, 0}, 0, 1, |
| {OPT_Reg|OPS_80|OPA_Op1Add, 0, 0} } |
| }; |
| |
| /* 486 extensions */ |
| static const x86_insn_info bswap_insn[] = { |
| { CPU_486, MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0xC8, 0}, 0, 1, |
| {OPT_Reg|OPS_32|OPA_Op1Add, 0, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xC8, 0}, 0, 1, |
| {OPT_Reg|OPS_64|OPA_Op1Add, 0, 0} } |
| }; |
| static const x86_insn_info cmpxchgxadd_insn[] = { |
| { CPU_486, MOD_Op1Add|MOD_GasSufB, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_486, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_486, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x01, 0}, |
| 0, 2, {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} } |
| }; |
| |
| /* Pentium extensions */ |
| static const x86_insn_info cmpxchg8b_insn[] = { |
| { CPU_586, MOD_GasSufQ, 0, 0, 0, 2, {0x0F, 0xC7, 0}, 1, 1, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| |
| /* Pentium II/Pentium Pro extensions */ |
| static const x86_insn_info cmovcc_insn[] = { |
| { CPU_686, MOD_Op1Add|MOD_GasSufW, 16, 0, 0, 2, {0x0F, 0x40, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_686, MOD_Op1Add|MOD_GasSufL, 32, 0, 0, 2, {0x0F, 0x40, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_Op1Add|MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x40, 0}, |
| 0, 2, {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info fcmovcc_insn[] = { |
| { CPU_686|CPU_FPU, MOD_Op0Add|MOD_Op1Add, 0, 0, 0, 2, {0x00, 0x00, 0}, |
| 0, 2, {OPT_ST0|OPS_80|OPA_None, OPT_Reg|OPS_80|OPA_Op1Add, 0} } |
| }; |
| |
| /* Pentium4 extensions */ |
| static const x86_insn_info movnti_insn[] = { |
| { CPU_P4, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0xC3, 0}, 0, 2, |
| {OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xC3, 0}, 0, 2, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_64|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info clflush_insn[] = { |
| { CPU_P3, 0, 0, 0, 0, 2, {0x0F, 0xAE, 0}, 7, 1, |
| {OPT_Mem|OPS_8|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| |
| /* MMX/SSE2 instructions */ |
| static const x86_insn_info movd_insn[] = { |
| { CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_MMX|CPU_Hammer|CPU_64, 0, 64, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} }, |
| { CPU_MMX|CPU_Hammer|CPU_64, 0, 64, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, 0, 64, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, 0, 64, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movq_insn[] = { |
| { CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x6F, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_MMX|CPU_Hammer|CPU_64, 0, 64, 0, 0, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x7F, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} |
| }, |
| { CPU_MMX|CPU_Hammer|CPU_64, 0, 64, 0, 0, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF3, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, 0, 64, 0, 0x66, 2, {0x0F, 0x6E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0x66, 2, {0x0F, 0xD6, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} |
| }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, 0, 64, 0, 0x66, 2, {0x0F, 0x7E, 0}, 0, 2, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info mmxsse2_insn[] = { |
| { CPU_MMX, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info pshift_insn[] = { |
| { CPU_MMX, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_MMX, MOD_Gap0|MOD_Op1Add|MOD_SpAdd, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, |
| 2, {OPT_SIMDReg|OPS_64|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} }, |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2, MOD_Gap0|MOD_Op1Add|MOD_SpAdd, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, |
| 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} } |
| }; |
| |
| /* PIII (Katmai) new instructions / SIMD instructiosn */ |
| static const x86_insn_info sseps_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_xmm64_ss_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_xmm64_ps_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_xmm32_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_rx_xmm64_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add|MOD_GasSufL, 0, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add|MOD_GasSufL, 0, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| /* REX */ |
| { CPU_SSE|CPU_Hammer|CPU_64, MOD_PreAdd|MOD_Op1Add|MOD_GasSufQ, 64, 0, |
| 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE|CPU_Hammer|CPU_64, MOD_PreAdd|MOD_Op1Add|MOD_GasSufQ, 64, 0, |
| 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_rx_xmm32_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add|MOD_GasSufL, 0, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add|MOD_GasSufL, 0, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} |
| }, |
| /* REX */ |
| { CPU_SSE|CPU_Hammer|CPU_64, MOD_PreAdd|MOD_Op1Add|MOD_GasSufQ, 64, 0, |
| 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE|CPU_Hammer|CPU_64, MOD_PreAdd|MOD_Op1Add|MOD_GasSufQ, 64, 0, |
| 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_mm_xmm64_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_mm_xmm_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_mm_ss_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_mm_ps_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info cvt_xmm_rmx_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add|MOD_GasSufL, 0, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} |
| }, |
| /* REX */ |
| { CPU_Hammer|CPU_64, MOD_PreAdd|MOD_Op1Add|MOD_GasSufQ, 64, 0, 0x00, 2, |
| {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info ssess_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info ssecmpps_insn[] = { |
| { CPU_SSE, MOD_Imm8, 0, 0, 0, 2, {0x0F, 0xC2, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info ssecmpss_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Imm8, 0, 0, 0x00, 2, {0x0F, 0xC2, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| static const x86_insn_info ssepsimm_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| static const x86_insn_info ssessimm_insn[] = { |
| { CPU_SSE, MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| static const x86_insn_info ldstmxcsr_insn[] = { |
| { CPU_SSE, MOD_SpAdd, 0, 0, 0, 2, {0x0F, 0xAE, 0}, 0, 1, |
| {OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info maskmovq_insn[] = { |
| { CPU_P3|CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0xF7, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movaups_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} |
| } |
| }; |
| static const x86_insn_info movhllhps_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movhlps_insn[] = { |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movmskps_insn[] = { |
| { CPU_SSE, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0x50, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0x50, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movntps_insn[] = { |
| { CPU_SSE, 0, 0, 0, 0, 2, {0x0F, 0x2B, 0}, 0, 2, |
| {OPT_Mem|OPS_128|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movntq_insn[] = { |
| { CPU_SSE, 0, 0, 0, 0, 2, {0x0F, 0xE7, 0}, 0, 2, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_64|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movss_insn[] = { |
| { CPU_SSE, 0, 0, 0, 0xF3, 2, {0x0F, 0x10, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_SSE, 0, 0, 0, 0xF3, 2, {0x0F, 0x10, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE, 0, 0, 0, 0xF3, 2, {0x0F, 0x11, 0}, 0, 2, |
| {OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info pextrw_insn[] = { |
| { CPU_P3|CPU_MMX, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0xC5, 0}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE2, MOD_GasSufL, 0, 0, 0x66, 2, {0x0F, 0xC5, 0}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xC5, 0}, |
| 0, 3, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE2|CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0x66, 2, {0x0F, 0xC5, 0}, |
| 0, 3, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| /* SSE4.1 instructions */ |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, |
| {OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41|CPU_64, 0, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x15}, 0, 3, |
| {OPT_Reg|OPS_64|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| static const x86_insn_info pinsrw_insn[] = { |
| { CPU_P3|CPU_MMX, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_P3|CPU_MMX, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE2, MOD_GasSufL, 0, 0, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Reg|OPS_64|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE2, MOD_GasSufL, 0, 0, 0x66, 2, {0x0F, 0xC4, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| static const x86_insn_info pmovmskb_insn[] = { |
| { CPU_P3|CPU_MMX, MOD_GasSufL, 0, 0, 0, 2, {0x0F, 0xD7, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, 0} }, |
| { CPU_SSE2, MOD_GasSufL, 0, 0, 0x66, 2, {0x0F, 0xD7, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0, 2, {0x0F, 0xD7, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, 0} }, |
| { CPU_Hammer|CPU_64, MOD_GasSufQ, 64, 0, 0x66, 2, {0x0F, 0xD7, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info pshufw_insn[] = { |
| { CPU_P3|CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x70, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| /* SSE2 instructions */ |
| static const x86_insn_info cmpsd_insn[] = { |
| { CPU_Any, MOD_GasIllegal, 32, 0, 0, 1, {0xA7, 0, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF2, 2, {0x0F, 0xC2, 0}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| static const x86_insn_info movaupd_insn[] = { |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} |
| } |
| }; |
| static const x86_insn_info movhlpd_insn[] = { |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x01, 0}, 0, 2, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movmskpd_insn[] = { |
| { CPU_SSE2, MOD_GasSufL, 0, 0, 0x66, 2, {0x0F, 0x50, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movntpddq_insn[] = { |
| { CPU_SSE2, MOD_Op1Add, 0, 0, 0x66, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_Mem|OPS_128|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info movsd_insn[] = { |
| { CPU_Any, MOD_GasIllegal, 32, 0, 0, 1, {0xA5, 0, 0}, 0, 0, {0, 0, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF2, 2, {0x0F, 0x10, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF2, 2, {0x0F, 0x10, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE2, 0, 0, 0, 0xF2, 2, {0x0F, 0x11, 0}, 0, 2, |
| {OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info maskmovdqu_insn[] = { |
| { CPU_SSE2, 0, 0, 0, 0x66, 2, {0x0F, 0xF7, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movdqau_insn[] = { |
| { CPU_SSE2, MOD_PreAdd, 0, 0, 0x00, 2, {0x0F, 0x6F, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE2, MOD_PreAdd, 0, 0, 0x00, 2, {0x0F, 0x7F, 0}, 0, 2, |
| {OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, 0} |
| } |
| }; |
| static const x86_insn_info movdq2q_insn[] = { |
| { CPU_SSE2, 0, 0, 0, 0xF2, 2, {0x0F, 0xD6, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| static const x86_insn_info movq2dq_insn[] = { |
| { CPU_SSE2, 0, 0, 0, 0xF3, 2, {0x0F, 0xD6, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_64|OPA_EA, 0} } |
| }; |
| static const x86_insn_info pslrldq_insn[] = { |
| { CPU_SSE2, MOD_SpAdd, 0, 0, 0x66, 2, {0x0F, 0x73, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm, 0} } |
| }; |
| |
| /* SSE3 instructions */ |
| static const x86_insn_info lddqu_insn[] = { |
| { CPU_SSE3, 0, 0, 0, 0xF2, 2, {0x0F, 0xF0, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_Any|OPA_EA, 0} } |
| }; |
| |
| /* SSSE3 instructions */ |
| static const x86_insn_info ssse3_insn[] = { |
| { CPU_SSSE3, MOD_Op2Add, 0, 0, 0, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSSE3, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| |
| static const x86_insn_info ssse3imm_insn[] = { |
| { CPU_SSSE3, MOD_Op2Add, 0, 0, 0, 3, {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} |
| }, |
| { CPU_SSSE3, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} |
| } |
| }; |
| |
| /* SSE4 instructions */ |
| |
| static const x86_insn_info sse4_insn[] = { |
| { CPU_Any, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| } |
| }; |
| |
| static const x86_insn_info sse4imm_insn[] = { |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info sse4xmm0_insn[] = { |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, 0} |
| }, |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_XMM0|OPS_128|OPA_None} |
| } |
| }; |
| |
| static const x86_insn_info crc32_insn[] = { |
| { CPU_SSE42, MOD_GasSufB, 0, 0, 0xF2, 3, {0x0F, 0x38, 0xF0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_8|OPA_EA, 0} }, |
| { CPU_SSE42, MOD_GasSufW, 16, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_16|OPA_EA, 0} }, |
| { CPU_SSE42, MOD_GasSufL, 32, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE42|CPU_64, MOD_GasSufB, 64, 0, 0xF2, 3, {0x0F, 0x38, 0xF0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_8|OPA_EA, 0} }, |
| { CPU_SSE42|CPU_64, MOD_GasSufQ, 64, 0, 0xF2, 3, {0x0F, 0x38, 0xF1}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| static const x86_insn_info extractps_insn[] = { |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x17}, 0, 3, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41|CPU_64, 0, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x17}, 0, 3, |
| {OPT_Reg|OPS_64|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info insertps_insn[] = { |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x21}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x21}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info movntdqa_insn[] = { |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x38, 0x2A}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_128|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| static const x86_insn_info sse4pcmpstr_insn[] = { |
| { CPU_SSE42, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE42, MOD_Op2Add|MOD_GasOnly|MOD_GasSufW, 16, 0, 0x66, 3, |
| {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} |
| }, |
| { CPU_SSE42, MOD_Op2Add|MOD_GasOnly|MOD_GasSufL, 32, 0, 0x66, 3, |
| {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} |
| }, |
| { CPU_SSE42, MOD_Op2Add|MOD_GasOnly|MOD_GasSufQ, 64, 0, 0x66, 3, |
| {0x0F, 0x3A, 0x00}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDRM|OPS_128|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} |
| } |
| }; |
| |
| static const x86_insn_info pextrb_insn[] = { |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, |
| {OPT_Mem|OPS_8|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, |
| {OPT_Reg|OPS_32|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41|CPU_64, 0, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x14}, 0, 3, |
| {OPT_Reg|OPS_64|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info pextrd_insn[] = { |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x16}, 0, 3, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info pextrq_insn[] = { |
| { CPU_SSE41|CPU_64, 0, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x16}, 0, 3, |
| {OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, OPT_SIMDReg|OPS_128|OPA_Spare, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info pinsrb_insn[] = { |
| { CPU_SSE41, 0, 0, 0, 0x66, 3, {0x0F, 0x3A, 0x20}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_8|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} }, |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x20}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Reg|OPS_32|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info pinsrd_insn[] = { |
| { CPU_SSE41, 0, 32, 0, 0x66, 3, {0x0F, 0x3A, 0x22}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info pinsrq_insn[] = { |
| { CPU_SSE41|CPU_64, 0, 64, 0, 0x66, 3, {0x0F, 0x3A, 0x22}, 0, 3, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, |
| OPT_Imm|OPS_8|OPS_Relaxed|OPA_Imm} } |
| }; |
| |
| static const x86_insn_info sse4m64_insn[] = { |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| |
| static const x86_insn_info sse4m32_insn[] = { |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| |
| static const x86_insn_info sse4m16_insn[] = { |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE41, MOD_Op2Add, 0, 0, 0x66, 3, {0x0F, 0x38, 0x00}, 0, 2, |
| {OPT_SIMDReg|OPS_128|OPA_Spare, OPT_SIMDReg|OPS_128|OPA_EA, 0} } |
| }; |
| |
| static const x86_insn_info popcnt_insn[] = { |
| { CPU_SSE42, MOD_GasSufW, 16, 0, 0xF3, 2, {0x0F, 0xB8, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE42, MOD_GasSufL, 32, 0, 0xF3, 2, {0x0F, 0xB8, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_SSE42|CPU_64, MOD_GasSufQ, 64, 0, 0xF3, 2, {0x0F, 0xB8, 0}, 0, 2, |
| {OPT_Reg|OPS_64|OPA_Spare, OPT_RM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* AMD 3DNow! instructions */ |
| static const x86_insn_info now3d_insn[] = { |
| { CPU_3DNow, MOD_Imm8, 0, 0, 0, 2, {0x0F, 0x0F, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* AMD x86-64 extensions */ |
| static const x86_insn_info cmpxchg16b_insn[] = { |
| { CPU_64|CPU_Hammer, 0, 64, 0, 0, 2, {0x0F, 0xC7, 0}, 1, 1, |
| {OPT_Mem|OPS_128|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| |
| /* AMD Pacifica (SVM) instructions */ |
| static const x86_insn_info invlpga_insn[] = { |
| { CPU_SVM, 0, 0, 0, 0, 3, {0x0F, 0x01, 0xDF}, 0, 0, {0, 0, 0} }, |
| { CPU_SVM, 0, 0, 0, 0, 3, {0x0F, 0x01, 0xDF}, 0, 2, |
| {OPT_MemrAX|OPS_Any|OPA_AdSizeEA, OPT_Creg|OPS_32|OPA_None, 0} } |
| }; |
| static const x86_insn_info skinit_insn[] = { |
| { CPU_SVM, 0, 0, 0, 0, 3, {0x0F, 0x01, 0xDE}, 0, 0, {0, 0, 0} }, |
| { CPU_SVM, 0, 0, 0, 0, 3, {0x0F, 0x01, 0xDE}, 0, 1, |
| {OPT_MemEAX|OPS_Any|OPA_None, 0, 0} } |
| }; |
| static const x86_insn_info svm_rax_insn[] = { |
| { CPU_SVM, MOD_Op2Add, 0, 0, 0, 3, {0x0F, 0x01, 0x00}, 0, 0, {0, 0, 0} }, |
| { CPU_SVM, MOD_Op2Add, 0, 0, 0, 3, {0x0F, 0x01, 0x00}, 0, 1, |
| {OPT_MemrAX|OPS_Any|OPA_AdSizeEA, 0, 0} } |
| }; |
| /* VIA PadLock instructions */ |
| static const x86_insn_info padlock_insn[] = { |
| { CPU_Any, MOD_Imm8|MOD_PreAdd|MOD_Op1Add, 0, 0, 0x00, 2, {0x0F, 0x00, 0}, |
| 0, 0, {0, 0, 0} } |
| }; |
| |
| /* Cyrix MMX instructions */ |
| static const x86_insn_info cyrixmmx_insn[] = { |
| { CPU_Cyrix|CPU_MMX, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_SIMDRM|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info pmachriw_insn[] = { |
| { CPU_Cyrix|CPU_MMX, 0, 0, 0, 0, 2, {0x0F, 0x5E, 0}, 0, 2, |
| {OPT_SIMDReg|OPS_64|OPA_Spare, OPT_Mem|OPS_64|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| /* Cyrix extensions */ |
| static const x86_insn_info rdwrshr_insn[] = { |
| { CPU_486|CPU_Cyrix|CPU_SMM, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x36, 0}, 0, 1, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info rsdc_insn[] = { |
| { CPU_486|CPU_Cyrix|CPU_SMM, 0, 0, 0, 0, 2, {0x0F, 0x79, 0}, 0, 2, |
| {OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, |
| OPT_Mem|OPS_80|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info cyrixsmm_insn[] = { |
| { CPU_486|CPU_Cyrix|CPU_SMM, MOD_Op1Add, 0, 0, 0, 2, {0x0F, 0x00, 0}, 0, 1, |
| {OPT_Mem|OPS_80|OPS_Relaxed|OPA_EA, 0, 0} } |
| }; |
| static const x86_insn_info svdc_insn[] = { |
| { CPU_486|CPU_Cyrix|CPU_SMM, 0, 0, 0, 0, 2, {0x0F, 0x78, 0}, 0, 2, |
| {OPT_Mem|OPS_80|OPS_Relaxed|OPA_EA, |
| OPT_SegReg|OPS_16|OPS_Relaxed|OPA_Spare, 0} } |
| }; |
| |
| /* Obsolete/undocumented instructions */ |
| static const x86_insn_info ibts_insn[] = { |
| { CPU_386|CPU_Undoc|CPU_Obs, 0, 16, 0, 0, 2, {0x0F, 0xA7, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386|CPU_Undoc|CPU_Obs, 0, 32, 0, 0, 2, {0x0F, 0xA7, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} } |
| }; |
| static const x86_insn_info umov_insn[] = { |
| { CPU_386|CPU_Undoc, 0, 0, 0, 0, 2, {0x0F, 0x10, 0}, 0, 2, |
| {OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_8|OPA_Spare, 0} }, |
| { CPU_386|CPU_Undoc, 0, 16, 0, 0, 2, {0x0F, 0x11, 0}, 0, 2, |
| {OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_16|OPA_Spare, 0} }, |
| { CPU_386|CPU_Undoc, 0, 32, 0, 0, 2, {0x0F, 0x11, 0}, 0, 2, |
| {OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, OPT_Reg|OPS_32|OPA_Spare, 0} }, |
| { CPU_386|CPU_Undoc, 0, 0, 0, 0, 2, {0x0F, 0x12, 0}, 0, 2, |
| {OPT_Reg|OPS_8|OPA_Spare, OPT_RM|OPS_8|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386|CPU_Undoc, 0, 16, 0, 0, 2, {0x0F, 0x13, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_RM|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386|CPU_Undoc, 0, 32, 0, 0, 2, {0x0F, 0x13, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_RM|OPS_32|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| static const x86_insn_info xbts_insn[] = { |
| { CPU_386|CPU_Undoc|CPU_Obs, 0, 16, 0, 0, 2, {0x0F, 0xA6, 0}, 0, 2, |
| {OPT_Reg|OPS_16|OPA_Spare, OPT_Mem|OPS_16|OPS_Relaxed|OPA_EA, 0} }, |
| { CPU_386|CPU_Undoc|CPU_Obs, 0, 32, 0, 0, 2, {0x0F, 0xA6, 0}, 0, 2, |
| {OPT_Reg|OPS_32|OPA_Spare, OPT_Mem|OPS_32|OPS_Relaxed|OPA_EA, 0} } |
| }; |
| |
| |
| static void |
| x86_finalize_common(x86_common *common, const x86_insn_info *info, |
| uintptr_t mode_bits) |
| { |
| common->addrsize = 0; |
| common->opersize = info->opersize; |
| common->lockrep_pre = 0; |
| common->mode_bits = (unsigned char)mode_bits; |
| } |
| |
| static void |
| x86_finalize_opcode(x86_opcode *opcode, const x86_insn_info *info) |
| { |
| opcode->len = info->opcode_len; |
| opcode->opcode[0] = info->opcode[0]; |
| opcode->opcode[1] = info->opcode[1]; |
| opcode->opcode[2] = info->opcode[2]; |
| } |
| |
| static void |
| x86_finalize_jmpfar(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc, |
| const uintptr_t data[4], int num_operands, |
| yasm_insn_operands *operands, int num_prefixes, |
| uintptr_t **prefixes, const x86_insn_info *info) |
| { |
| x86_jmpfar *jmpfar; |
| yasm_insn_operand *op; |
| /*@only@*/ yasm_expr *segment; |
| |
| jmpfar = yasm_xmalloc(sizeof(x86_jmpfar)); |
| x86_finalize_common(&jmpfar->common, info, data[3]); |
| x86_finalize_opcode(&jmpfar->opcode, info); |
| |
| op = yasm_ops_first(operands); |
| |
| if (op->type == YASM_INSN__OPERAND_IMM && |
| yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF)) { |
| /* SEG:OFF expression; split it. */ |
| segment = yasm_expr_extract_segoff(&op->data.val); |
| if (!segment) |
| yasm_internal_error(N_("didn't get SEG:OFF expression in jmpfar")); |
| if (yasm_value_finalize_expr(&jmpfar->segment, segment, prev_bc, 16)) |
| yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
| N_("jump target segment too complex")); |
| if (yasm_value_finalize_expr(&jmpfar->offset, op->data.val, prev_bc, |
| 0)) |
| yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
| N_("jump target offset too complex")); |
| } else if (op->targetmod == X86_FAR) { |
| /* "FAR imm" target needs to become "seg imm:imm". */ |
| if (yasm_value_finalize_expr(&jmpfar->offset, |
| yasm_expr_copy(op->data.val), prev_bc, 0) |
| || yasm_value_finalize_expr(&jmpfar->segment, op->data.val, |
| prev_bc, 16)) |
| yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
| N_("jump target expression too complex")); |
| jmpfar->segment.seg_of = 1; |
| } else |
| yasm_internal_error(N_("didn't get FAR expression in jmpfar")); |
| |
| yasm_x86__bc_apply_prefixes((x86_common *)jmpfar, NULL, |
| info->def_opersize_64, num_prefixes, |
| prefixes); |
| |
| /* Transform the bytecode */ |
| yasm_x86__bc_transform_jmpfar(bc, jmpfar); |
| } |
| |
| static void |
| x86_finalize_jmp(yasm_arch *arch, yasm_bytecode *bc, yasm_bytecode *prev_bc, |
| const uintptr_t data[4], int num_operands, |
| yasm_insn_operands *operands, int num_prefixes, |
| uintptr_t **prefixes, const x86_insn_info *jinfo) |
| { |
| x86_jmp *jmp; |
| int num_info = (int)(data[1]&0xFF); |
| x86_insn_info *info = (x86_insn_info *)data[0]; |
| unsigned long mod_data = (unsigned long)(data[1] >> 8); |
| unsigned int mode_bits = (unsigned int)(data[3] & 0xFF); |
| /*unsigned char suffix = (unsigned char)((data[3]>>8) & 0xFF);*/ |
| yasm_insn_operand *op; |
| static const unsigned char size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0}; |
| |
| /* We know the target is in operand 0, but sanity check for Imm. */ |
| op = yasm_ops_first(operands); |
| if (op->type != YASM_INSN__OPERAND_IMM) |
| yasm_internal_error(N_("invalid operand conversion")); |
| |
| jmp = yasm_xmalloc(sizeof(x86_jmp)); |
| x86_finalize_common(&jmp->common, jinfo, mode_bits); |
| if (yasm_value_finalize_expr(&jmp->target, op->data.val, prev_bc, 0)) |
| yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
| N_("jump target expression too complex")); |
| if (jmp->target.seg_of || jmp->target.rshift || jmp->target.curpos_rel) |
| yasm_error_set(YASM_ERROR_VALUE, N_("invalid jump target")); |
| yasm_value_set_curpos_rel(&jmp->target, bc, 0); |
| jmp->target.jump_target = 1; |
| |
| /* See if the user explicitly specified short/near/far. */ |
| switch ((int)(jinfo->operands[0] & OPTM_MASK)) { |
| case OPTM_Short: |
| jmp->op_sel = JMP_SHORT_FORCED; |
| break; |
| case OPTM_Near: |
| jmp->op_sel = JMP_NEAR_FORCED; |
| break; |
| default: |
| jmp->op_sel = JMP_NONE; |
| } |
| |
| /* Check for address size setting in second operand, if present */ |
| if (jinfo->num_operands > 1 && |
| (jinfo->operands[1] & OPA_MASK) == OPA_AdSizeR) |
| jmp->common.addrsize = (unsigned char) |
| size_lookup[(jinfo->operands[1] & OPS_MASK)>>OPS_SHIFT]; |
| |
| /* Check for address size override */ |
| if (jinfo->modifiers & MOD_AdSizeR) |
| jmp->common.addrsize = (unsigned char)(mod_data & 0xFF); |
| |
| /* Scan through other infos for this insn looking for short/near versions. |
| * Needs to match opersize and number of operands, also be within CPU. |
| */ |
| jmp->shortop.len = 0; |
| jmp->nearop.len = 0; |
| for (; num_info>0 && (jmp->shortop.len == 0 || jmp->nearop.len == 0); |
| num_info--, info++) { |
| unsigned long cpu = info->cpu; |
| |
| if ((cpu & CPU_64) && mode_bits != 64) |
| continue; |
| if ((cpu & CPU_Not64) && mode_bits == 64) |
| continue; |
| cpu &= ~(CPU_64 | CPU_Not64); |
| |
| if ((data[2] & cpu) != cpu) |
| continue; |
| |
| if (info->num_operands == 0) |
| continue; |
| |
| if ((info->operands[0] & OPA_MASK) != OPA_JmpRel) |
| continue; |
| |
| if (info->opersize != jmp->common.opersize) |
| continue; |
| |
| switch ((int)(info->operands[0] & OPTM_MASK)) { |
| case OPTM_Short: |
| x86_finalize_opcode(&jmp->shortop, info); |
| if (info->modifiers & MOD_Op0Add) |
| jmp->shortop.opcode[0] += (unsigned char)(mod_data & 0xFF); |
| break; |
| case OPTM_Near: |
| x86_finalize_opcode(&jmp->nearop, info); |
| if (info->modifiers & MOD_Op1Add) |
| jmp->nearop.opcode[1] += (unsigned char)(mod_data & 0xFF); |
| break; |
| } |
| } |
| |
| if ((jmp->op_sel == JMP_SHORT_FORCED) && (jmp->nearop.len == 0)) |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("no SHORT form of that jump instruction exists")); |
| if ((jmp->op_sel == JMP_NEAR_FORCED) && (jmp->shortop.len == 0)) |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("no NEAR form of that jump instruction exists")); |
| |
| if (jmp->op_sel == JMP_NONE) { |
| if (jmp->nearop.len == 0) |
| jmp->op_sel = JMP_SHORT_FORCED; |
| if (jmp->shortop.len == 0) |
| jmp->op_sel = JMP_NEAR_FORCED; |
| } |
| |
| yasm_x86__bc_apply_prefixes((x86_common *)jmp, NULL, info->def_opersize_64, |
| num_prefixes, prefixes); |
| |
| /* Transform the bytecode */ |
| yasm_x86__bc_transform_jmp(bc, jmp); |
| } |
| |
| static const x86_insn_info * |
| x86_find_match(yasm_arch *arch, int num_info, const x86_insn_info *info, |
| uintptr_t cpu, unsigned int mode_bits, unsigned int suffix, |
| int num_operands, yasm_insn_operand **ops, |
| yasm_insn_operand **rev_ops, const unsigned int *size_lookup, |
| int bypass) |
| { |
| yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; |
| int found = 0; |
| |
| /* Just do a simple linear search through the info array for a match. |
| * First match wins. |
| */ |
| for (; num_info>0 && !found; num_info--, info++) { |
| yasm_insn_operand *op, **use_ops; |
| unsigned long icpu; |
| unsigned int size; |
| int mismatch = 0; |
| int i; |
| |
| /* Match CPU */ |
| icpu = info->cpu; |
| |
| if ((icpu & CPU_64) && mode_bits != 64) |
| continue; |
| if ((icpu & CPU_Not64) && mode_bits == 64) |
| continue; |
| icpu &= ~(CPU_64 | CPU_Not64); |
| |
| if (bypass != 7 && (cpu & icpu) != icpu) |
| continue; |
| |
| /* Match # of operands */ |
| if (num_operands != info->num_operands) |
| continue; |
| |
| /* Match parser mode */ |
| if ((info->modifiers & MOD_GasOnly) |
| && arch_x86->parser != X86_PARSER_GAS) |
| continue; |
| if ((info->modifiers & MOD_GasIllegal) |
| && arch_x86->parser == X86_PARSER_GAS) |
| continue; |
| |
| /* Match suffix (if required) */ |
| if (suffix != 0 && suffix != 0x80 |
| && ((suffix<<MOD_GasSuf_SHIFT) & info->modifiers) == 0) |
| continue; |
| |
| /* Use reversed operands in GAS mode if not otherwise specified */ |
| use_ops = ops; |
| if (arch_x86->parser == X86_PARSER_GAS |
| && !(info->modifiers & MOD_GasNoRev)) |
| use_ops = rev_ops; |
| |
| if (num_operands == 0) { |
| found = 1; /* no operands -> must have a match here. */ |
| break; |
| } |
| |
| /* Match each operand type and size */ |
| for (i = 0, op = use_ops[0]; op && i<info->num_operands && !mismatch; |
| op = use_ops[++i]) { |
| /* Check operand type */ |
| switch ((int)(info->operands[i] & OPT_MASK)) { |
| case OPT_Imm: |
| if (op->type != YASM_INSN__OPERAND_IMM) |
| mismatch = 1; |
| break; |
| case OPT_RM: |
| if (op->type == YASM_INSN__OPERAND_MEMORY) |
| break; |
| /*@fallthrough@*/ |
| case OPT_Reg: |
| if (op->type != YASM_INSN__OPERAND_REG) |
| mismatch = 1; |
| else { |
| switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { |
| case X86_REG8: |
| case X86_REG8X: |
| case X86_REG16: |
| case X86_REG32: |
| case X86_REG64: |
| case X86_FPUREG: |
| break; |
| default: |
| mismatch = 1; |
| break; |
| } |
| } |
| break; |
| case OPT_Mem: |
| if (op->type != YASM_INSN__OPERAND_MEMORY) |
| mismatch = 1; |
| break; |
| case OPT_SIMDRM: |
| if (op->type == YASM_INSN__OPERAND_MEMORY) |
| break; |
| /*@fallthrough@*/ |
| case OPT_SIMDReg: |
| if (op->type != YASM_INSN__OPERAND_REG) |
| mismatch = 1; |
| else { |
| switch ((x86_expritem_reg_size)(op->data.reg&~0xFUL)) { |
| case X86_MMXREG: |
| case X86_XMMREG: |
| break; |
| default: |
| mismatch = 1; |
| break; |
| } |
| } |
| break; |
| case OPT_SegReg: |
| if (op->type != YASM_INSN__OPERAND_SEGREG) |
| mismatch = 1; |
| break; |
| case OPT_CRReg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| (op->data.reg & ~0xFUL) != X86_CRREG) |
| mismatch = 1; |
| break; |
| case OPT_DRReg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| (op->data.reg & ~0xFUL) != X86_DRREG) |
| mismatch = 1; |
| break; |
| case OPT_TRReg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| (op->data.reg & ~0xFUL) != X86_TRREG) |
| mismatch = 1; |
| break; |
| case OPT_ST0: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| op->data.reg != X86_FPUREG) |
| mismatch = 1; |
| break; |
| case OPT_Areg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| ((info->operands[i] & OPS_MASK) == OPS_8 && |
| op->data.reg != (X86_REG8 | 0) && |
| op->data.reg != (X86_REG8X | 0)) || |
| ((info->operands[i] & OPS_MASK) == OPS_16 && |
| op->data.reg != (X86_REG16 | 0)) || |
| ((info->operands[i] & OPS_MASK) == OPS_32 && |
| op->data.reg != (X86_REG32 | 0)) || |
| ((info->operands[i] & OPS_MASK) == OPS_64 && |
| op->data.reg != (X86_REG64 | 0))) |
| mismatch = 1; |
| break; |
| case OPT_Creg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| ((info->operands[i] & OPS_MASK) == OPS_8 && |
| op->data.reg != (X86_REG8 | 1) && |
| op->data.reg != (X86_REG8X | 1)) || |
| ((info->operands[i] & OPS_MASK) == OPS_16 && |
| op->data.reg != (X86_REG16 | 1)) || |
| ((info->operands[i] & OPS_MASK) == OPS_32 && |
| op->data.reg != (X86_REG32 | 1)) || |
| ((info->operands[i] & OPS_MASK) == OPS_64 && |
| op->data.reg != (X86_REG64 | 1))) |
| mismatch = 1; |
| break; |
| case OPT_Dreg: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| ((info->operands[i] & OPS_MASK) == OPS_8 && |
| op->data.reg != (X86_REG8 | 2) && |
| op->data.reg != (X86_REG8X | 2)) || |
| ((info->operands[i] & OPS_MASK) == OPS_16 && |
| op->data.reg != (X86_REG16 | 2)) || |
| ((info->operands[i] & OPS_MASK) == OPS_32 && |
| op->data.reg != (X86_REG32 | 2)) || |
| ((info->operands[i] & OPS_MASK) == OPS_64 && |
| op->data.reg != (X86_REG64 | 2))) |
| mismatch = 1; |
| break; |
| case OPT_CS: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 1) |
| mismatch = 1; |
| break; |
| case OPT_DS: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 3) |
| mismatch = 1; |
| break; |
| case OPT_ES: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 0) |
| mismatch = 1; |
| break; |
| case OPT_FS: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 4) |
| mismatch = 1; |
| break; |
| case OPT_GS: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 5) |
| mismatch = 1; |
| break; |
| case OPT_SS: |
| if (op->type != YASM_INSN__OPERAND_SEGREG || |
| (op->data.reg & 0xF) != 2) |
| mismatch = 1; |
| break; |
| case OPT_CR4: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| op->data.reg != (X86_CRREG | 4)) |
| mismatch = 1; |
| break; |
| case OPT_MemOffs: |
| if (op->type != YASM_INSN__OPERAND_MEMORY || |
| yasm_expr__contains(yasm_ea_get_disp(op->data.ea), |
| YASM_EXPR_REG)) |
| mismatch = 1; |
| break; |
| case OPT_Imm1: |
| if (op->type == YASM_INSN__OPERAND_IMM) { |
| const yasm_intnum *num; |
| num = yasm_expr_get_intnum(&op->data.val, 0); |
| if (!num || !yasm_intnum_is_pos1(num)) |
| mismatch = 1; |
| } else |
| mismatch = 1; |
| break; |
| case OPT_ImmNotSegOff: |
| if (op->type != YASM_INSN__OPERAND_IMM || |
| op->targetmod != 0 || |
| yasm_expr_is_op(op->data.val, YASM_EXPR_SEGOFF)) |
| mismatch = 1; |
| break; |
| case OPT_XMM0: |
| if (op->type != YASM_INSN__OPERAND_REG || |
| op->data.reg != X86_XMMREG) |
| mismatch = 1; |
| break; |
| case OPT_MemrAX: { |
| const uintptr_t *regp; |
| if (op->type != YASM_INSN__OPERAND_MEMORY || |
| !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || |
| (*regp != (X86_REG16 | 0) && |
| *regp != (X86_REG32 | 0) && |
| *regp != (X86_REG64 | 0))) |
| mismatch = 1; |
| break; |
| } |
| case OPT_MemEAX: { |
| const uintptr_t *regp; |
| if (op->type != YASM_INSN__OPERAND_MEMORY || |
| !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0)) || |
| *regp != (X86_REG32 | 0)) |
| mismatch = 1; |
| break; |
| } |
| default: |
| yasm_internal_error(N_("invalid operand type")); |
| } |
| |
| if (mismatch) |
| break; |
| |
| /* Check operand size */ |
| size = size_lookup[(info->operands[i] & OPS_MASK)>>OPS_SHIFT]; |
| if (suffix != 0) { |
| /* Require relaxed operands for GAS mode (don't allow |
| * per-operand sizing). |
| */ |
| if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { |
| /* Register size must exactly match */ |
| if (yasm_x86__get_reg_size(arch, op->data.reg) != size) |
| mismatch = 1; |
| } else if (((info->operands[i] & OPT_MASK) == OPT_Imm |
| || (info->operands[i] & OPT_MASK) == OPT_ImmNotSegOff |
| || (info->operands[i] & OPT_MASK) == OPT_Imm1) |
| && (info->operands[i] & OPS_RMASK) != OPS_Relaxed |
| && (info->operands[i] & OPA_MASK) != OPA_JmpRel) |
| mismatch = 1; |
| } else { |
| if (op->type == YASM_INSN__OPERAND_REG && op->size == 0) { |
| /* Register size must exactly match */ |
| if ((bypass == 4 && i == 0) || (bypass == 5 && i == 1) |
| || (bypass == 6 && i == 3)) |
| ; |
| else if (yasm_x86__get_reg_size(arch, |
| op->data.reg) != size) |
| mismatch = 1; |
| } else { |
| if ((bypass == 1 && i == 0) || (bypass == 2 && i == 1) |
| || (bypass == 3 && i == 3)) |
| ; |
| else if ((info->operands[i] & OPS_RMASK) == OPS_Relaxed) { |
| /* Relaxed checking */ |
| if (size != 0 && op->size != size && op->size != 0) |
| mismatch = 1; |
| } else { |
| /* Strict checking */ |
| if (op->size != size) |
| mismatch = 1; |
| } |
| } |
| } |
| |
| if (mismatch) |
| break; |
| |
| /* Check for 64-bit effective address size in NASM mode */ |
| if (suffix == 0 && op->type == YASM_INSN__OPERAND_MEMORY) { |
| if ((info->operands[i] & OPEAS_MASK) == OPEAS_64) { |
| if (op->data.ea->disp.size != 64) |
| mismatch = 1; |
| } else if (op->data.ea->disp.size == 64) |
| mismatch = 1; |
| } |
| |
| if (mismatch) |
| break; |
| |
| /* Check target modifier */ |
| switch ((int)(info->operands[i] & OPTM_MASK)) { |
| case OPTM_None: |
| if (op->targetmod != 0) |
| mismatch = 1; |
| break; |
| case OPTM_Near: |
| if (op->targetmod != X86_NEAR) |
| mismatch = 1; |
| break; |
| case OPTM_Short: |
| if (op->targetmod != X86_SHORT) |
| mismatch = 1; |
| break; |
| case OPTM_Far: |
| if (op->targetmod != X86_FAR) |
| mismatch = 1; |
| break; |
| case OPTM_To: |
| if (op->targetmod != X86_TO) |
| mismatch = 1; |
| break; |
| default: |
| yasm_internal_error(N_("invalid target modifier type")); |
| } |
| } |
| |
| if (!mismatch) { |
| found = 1; |
| break; |
| } |
| } |
| |
| if (!found) |
| return NULL; |
| return info; |
| } |
| |
| static void |
| x86_match_error(yasm_arch *arch, int num_info, const x86_insn_info *info, |
| uintptr_t cpu, unsigned int mode_bits, unsigned int suffix, |
| int num_operands, yasm_insn_operand **ops, |
| yasm_insn_operand **rev_ops, const unsigned int *size_lookup) |
| { |
| const x86_insn_info *i; |
| int ni; |
| int found; |
| int bypass; |
| |
| /* Check for matching # of operands */ |
| found = 0; |
| for (ni=num_info, i=info; ni>0; ni--, i++) { |
| if (num_operands == i->num_operands) { |
| found = 1; |
| break; |
| } |
| } |
| if (!found) { |
| yasm_error_set(YASM_ERROR_TYPE, N_("invalid number of operands")); |
| return; |
| } |
| |
| for (bypass=1; bypass<8; bypass++) { |
| i = x86_find_match(arch, num_info, info, cpu, mode_bits, suffix, |
| num_operands, ops, rev_ops, size_lookup, bypass); |
| if (i) |
| break; |
| } |
| |
| switch (bypass) { |
| case 1: |
| case 4: |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("invalid size for operand %d"), 1); |
| break; |
| case 2: |
| case 5: |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("invalid size for operand %d"), 2); |
| break; |
| case 3: |
| case 6: |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("invalid size for operand %d"), 3); |
| break; |
| case 7: |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("requires CPU%s"), |
| cpu_find_reverse(i->cpu & ~(CPU_64 | CPU_Not64))); |
| break; |
| default: |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("invalid combination of opcode and operands")); |
| } |
| } |
| |
| void |
| yasm_x86__finalize_insn(yasm_arch *arch, yasm_bytecode *bc, |
| yasm_bytecode *prev_bc, const uintptr_t data[4], |
| int num_operands, |
| /*@null@*/ yasm_insn_operands *operands, |
| int num_prefixes, uintptr_t **prefixes, |
| int num_segregs, const uintptr_t *segregs) |
| { |
| yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; |
| x86_insn *insn; |
| int num_info = (int)(data[1]&0xFF); |
| const x86_insn_info *info = (const x86_insn_info *)data[0]; |
| unsigned long mod_data = (unsigned long)(data[1] >> 8); |
| unsigned int mode_bits = (unsigned int)(data[3] & 0xFF); |
| unsigned int suffix = (unsigned int)((data[3]>>8) & 0xFF); |
| yasm_insn_operand *op, *ops[4], *rev_ops[4]; |
| /*@null@*/ yasm_expr *imm; |
| unsigned char im_len; |
| unsigned char im_sign; |
| unsigned char spare; |
| int i; |
| unsigned int size_lookup[] = {0, 8, 16, 32, 64, 80, 128, 0}; |
| unsigned long do_postop = 0; |
| |
| size_lookup[7] = mode_bits; |
| |
| if (!info) { |
| num_info = 1; |
| info = empty_insn; |
| } |
| |
| /* Build local array of operands from list, since we know we have a max |
| * of 3 operands. |
| */ |
| if (num_operands > 3) { |
| yasm_error_set(YASM_ERROR_TYPE, N_("too many operands")); |
| return; |
| } |
| ops[0] = ops[1] = ops[2] = ops[3] = NULL; |
| for (i = 0, op = yasm_ops_first(operands); op && i < num_operands; |
| op = yasm_operand_next(op), i++) |
| ops[i] = op; |
| |
| /* If we're running in GAS mode, build a reverse array of the operands |
| * as most GAS instructions have reversed operands from Intel style. |
| */ |
| if (arch_x86->parser == X86_PARSER_GAS) { |
| rev_ops[0] = rev_ops[1] = rev_ops[2] = rev_ops[3] = NULL; |
| for (i = num_operands-1, op = yasm_ops_first(operands); op && i >= 0; |
| op = yasm_operand_next(op), i--) |
| rev_ops[i] = op; |
| } |
| |
| /* If we're running in GAS mode, look at the first insn_info to see |
| * if this is a relative jump (OPA_JmpRel). If so, run through the |
| * operands and adjust for dereferences / lack thereof. |
| */ |
| if (arch_x86->parser == X86_PARSER_GAS |
| && (info->operands[0] & OPA_MASK) == OPA_JmpRel) { |
| for (i = 0, op = ops[0]; op; op = ops[++i]) { |
| if (!op->deref && (op->type == YASM_INSN__OPERAND_REG |
| || (op->type == YASM_INSN__OPERAND_MEMORY |
| && op->data.ea->strong))) |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("indirect call without `*'")); |
| if (!op->deref && op->type == YASM_INSN__OPERAND_MEMORY |
| && !op->data.ea->strong) { |
| /* Memory that is not dereferenced, and not strong, is |
| * actually an immediate for the purposes of relative jumps. |
| */ |
| if (op->data.ea->segreg != 0) |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("skipping prefixes on this instruction")); |
| imm = op->data.ea->disp.abs; |
| op->data.ea->disp.abs = NULL; |
| yasm_ea_destroy(op->data.ea); |
| op->type = YASM_INSN__OPERAND_IMM; |
| op->data.val = imm; |
| } |
| } |
| } |
| |
| info = x86_find_match(arch, num_info, info, data[2], mode_bits, suffix, |
| num_operands, ops, rev_ops, size_lookup, 0); |
| |
| if (!info) { |
| /* Didn't find a match */ |
| info = (const x86_insn_info *)data[0]; |
| if (!info) |
| info = empty_insn; |
| x86_match_error(arch, num_info, info, data[2], mode_bits, suffix, |
| num_operands, ops, rev_ops, size_lookup); |
| return; |
| } |
| |
| if (operands) { |
| switch (info->operands[0] & OPA_MASK) { |
| case OPA_JmpRel: |
| /* Shortcut to JmpRel */ |
| x86_finalize_jmp(arch, bc, prev_bc, data, num_operands, |
| operands, num_prefixes, prefixes, info); |
| return; |
| case OPA_JmpFar: |
| /* Shortcut to JmpFar */ |
| x86_finalize_jmpfar(arch, bc, prev_bc, data, num_operands, |
| operands, num_prefixes, prefixes, info); |
| return; |
| } |
| } |
| |
| /* Copy what we can from info */ |
| insn = yasm_xmalloc(sizeof(x86_insn)); |
| x86_finalize_common(&insn->common, info, mode_bits); |
| x86_finalize_opcode(&insn->opcode, info); |
| insn->x86_ea = NULL; |
| imm = NULL; |
| insn->def_opersize_64 = info->def_opersize_64; |
| insn->special_prefix = info->special_prefix; |
| spare = info->spare; |
| im_len = 0; |
| im_sign = 0; |
| insn->postop = X86_POSTOP_NONE; |
| insn->rex = 0; |
| |
| /* Apply modifiers */ |
| if (info->modifiers & MOD_Gap0) |
| mod_data >>= 8; |
| if (info->modifiers & MOD_Op2Add) { |
| insn->opcode.opcode[2] += (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_Gap1) |
| mod_data >>= 8; |
| if (info->modifiers & MOD_Op1Add) { |
| insn->opcode.opcode[1] += (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_Gap2) |
| mod_data >>= 8; |
| if (info->modifiers & MOD_Op0Add) { |
| insn->opcode.opcode[0] += (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_PreAdd) { |
| insn->special_prefix += (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_SpAdd) { |
| spare += (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_OpSizeR) { |
| insn->common.opersize = (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_Imm8) { |
| imm = yasm_expr_create_ident(yasm_expr_int( |
| yasm_intnum_create_uint(mod_data & 0xFF)), bc->line); |
| im_len = 8; |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_DOpS64R) { |
| insn->def_opersize_64 = (unsigned char)(mod_data & 0xFF); |
| mod_data >>= 8; |
| } |
| if (info->modifiers & MOD_Op1AddSp) { |
| insn->opcode.opcode[1] += (unsigned char)(mod_data & 0xFF)<<3; |
| /*mod_data >>= 8;*/ |
| } |
| |
| /* In 64-bit mode, if opersize is 64 and default is not 64, force REX byte */ |
| if (mode_bits == 64 && insn->common.opersize == 64 && |
| insn->def_opersize_64 != 64) |
| insn->rex = 0x48; |
| |
| /* Go through operands and assign */ |
| if (operands) { |
| yasm_insn_operand **use_ops = ops; |
| |
| /* Use reversed operands in GAS mode if not otherwise specified */ |
| if (arch_x86->parser == X86_PARSER_GAS |
| && !(info->modifiers & MOD_GasNoRev)) |
| use_ops = rev_ops; |
| |
| for (i = 0, op = use_ops[0]; op && i<info->num_operands; |
| op = use_ops[++i]) { |
| switch ((int)(info->operands[i] & OPA_MASK)) { |
| case OPA_None: |
| /* Throw away the operand contents */ |
| switch (op->type) { |
| case YASM_INSN__OPERAND_REG: |
| case YASM_INSN__OPERAND_SEGREG: |
| break; |
| case YASM_INSN__OPERAND_MEMORY: |
| yasm_ea_destroy(op->data.ea); |
| break; |
| case YASM_INSN__OPERAND_IMM: |
| yasm_expr_destroy(op->data.val); |
| break; |
| } |
| break; |
| case OPA_EA: |
| switch (op->type) { |
| case YASM_INSN__OPERAND_REG: |
| insn->x86_ea = yasm_x86__ea_create_reg( |
| (unsigned long)op->data.reg, &insn->rex, |
| mode_bits); |
| break; |
| case YASM_INSN__OPERAND_SEGREG: |
| yasm_internal_error( |
| N_("invalid operand conversion")); |
| case YASM_INSN__OPERAND_MEMORY: |
| insn->x86_ea = (x86_effaddr *)op->data.ea; |
| if ((info->operands[i] & OPT_MASK) == OPT_MemOffs) |
| /* Special-case for MOV MemOffs instruction */ |
| yasm_x86__ea_set_disponly(insn->x86_ea); |
| break; |
| case YASM_INSN__OPERAND_IMM: |
| insn->x86_ea = |
| yasm_x86__ea_create_imm(op->data.val, |
| size_lookup[(info->operands[i] & |
| OPS_MASK)>>OPS_SHIFT]); |
| break; |
| } |
| break; |
| case OPA_Imm: |
| if (op->type == YASM_INSN__OPERAND_IMM) { |
| imm = op->data.val; |
| im_len = size_lookup[(info->operands[i] & |
| OPS_MASK)>>OPS_SHIFT]; |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_SImm: |
| if (op->type == YASM_INSN__OPERAND_IMM) { |
| imm = op->data.val; |
| im_len = size_lookup[(info->operands[i] & |
| OPS_MASK)>>OPS_SHIFT]; |
| im_sign = 1; |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_Spare: |
| if (op->type == YASM_INSN__OPERAND_SEGREG) |
| spare = (unsigned char)(op->data.reg&7); |
| else if (op->type == YASM_INSN__OPERAND_REG) { |
| if (yasm_x86__set_rex_from_reg(&insn->rex, &spare, |
| op->data.reg, mode_bits, X86_REX_R)) |
| return; |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_Op0Add: |
| if (op->type == YASM_INSN__OPERAND_REG) { |
| unsigned char opadd; |
| if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, |
| op->data.reg, mode_bits, X86_REX_B)) |
| return; |
| insn->opcode.opcode[0] += opadd; |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_Op1Add: |
| if (op->type == YASM_INSN__OPERAND_REG) { |
| unsigned char opadd; |
| if (yasm_x86__set_rex_from_reg(&insn->rex, &opadd, |
| op->data.reg, mode_bits, X86_REX_B)) |
| return; |
| insn->opcode.opcode[1] += opadd; |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_SpareEA: |
| if (op->type == YASM_INSN__OPERAND_REG) { |
| insn->x86_ea = |
| yasm_x86__ea_create_reg((unsigned long)op->data.reg, |
| &insn->rex, mode_bits); |
| if (!insn->x86_ea || |
| yasm_x86__set_rex_from_reg(&insn->rex, &spare, |
| op->data.reg, mode_bits, X86_REX_R)) { |
| if (insn->x86_ea) |
| yasm_xfree(insn->x86_ea); |
| yasm_xfree(insn); |
| return; |
| } |
| } else |
| yasm_internal_error(N_("invalid operand conversion")); |
| break; |
| case OPA_AdSizeEA: { |
| const uintptr_t *regp = NULL; |
| /* Only implement this for OPT_MemrAX and OPT_MemEAX |
| * for now. |
| */ |
| if (op->type != YASM_INSN__OPERAND_MEMORY || |
| !(regp = yasm_expr_get_reg(&op->data.ea->disp.abs, 0))) |
| yasm_internal_error(N_("invalid operand conversion")); |
| /* 64-bit mode does not allow 16-bit addresses */ |
| if (mode_bits == 64 && *regp == (X86_REG16 | 0)) |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("16-bit addresses not supported in 64-bit mode")); |
| else if (*regp == (X86_REG16 | 0)) |
| insn->common.addrsize = 16; |
| else if (*regp == (X86_REG32 | 0)) |
| insn->common.addrsize = 32; |
| else if (mode_bits == 64 && *regp == (X86_REG64 | 0)) |
| insn->common.addrsize = 64; |
| else |
| yasm_error_set(YASM_ERROR_TYPE, |
| N_("unsupported address size")); |
| yasm_ea_destroy(op->data.ea); |
| break; |
| } |
| default: |
| yasm_internal_error(N_("unknown operand action")); |
| } |
| |
| if ((info->operands[i] & OPS_MASK) == OPS_BITS) |
| insn->common.opersize = (unsigned char)mode_bits; |
| |
| switch ((int)(info->operands[i] & OPAP_MASK)) { |
| case OPAP_None: |
| break; |
| case OPAP_SImm8: |
| /* Check operand strictness; if strict and non-8-bit, |
| * pre-emptively expand to full size. |
| * For unspecified size case, still optimize. |
| */ |
| if (!(arch_x86->force_strict || op->strict) |
| || op->size == 0) |
| insn->postop = X86_POSTOP_SIGNEXT_IMM8; |
| else if (op->size != 8) { |
| insn->opcode.opcode[0] = |
| insn->opcode.opcode[insn->opcode.len]; |
| insn->opcode.len = 1; |
| } |
| break; |
| case OPAP_ShortMov: |
| do_postop = OPAP_ShortMov; |
| break; |
| case OPAP_A16: |
| insn->postop = X86_POSTOP_ADDRESS16; |
| break; |
| case OPAP_SImm32Avail: |
| do_postop = OPAP_SImm32Avail; |
| break; |
| default: |
| yasm_internal_error( |
| N_("unknown operand postponed action")); |
| } |
| } |
| } |
| |
| if (insn->x86_ea) { |
| yasm_x86__ea_init(insn->x86_ea, spare, prev_bc); |
| for (i=0; i<num_segregs; i++) |
| yasm_ea_set_segreg(&insn->x86_ea->ea, segregs[i]); |
| } else if (num_segregs > 0 && insn->special_prefix == 0) { |
| if (num_segregs > 1) |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("multiple segment overrides, using leftmost")); |
| insn->special_prefix = (unsigned char)(segregs[num_segregs-1]>>8); |
| } else if (num_segregs > 0) |
| yasm_internal_error(N_("unhandled segment prefix")); |
| |
| if (imm) { |
| insn->imm = yasm_xmalloc(sizeof(yasm_value)); |
| if (yasm_value_finalize_expr(insn->imm, imm, prev_bc, 0)) |
| yasm_error_set(YASM_ERROR_TOO_COMPLEX, |
| N_("immediate expression too complex")); |
| insn->imm->size = im_len; |
| insn->imm->sign = im_sign; |
| } else |
| insn->imm = NULL; |
| |
| yasm_x86__bc_apply_prefixes((x86_common *)insn, &insn->rex, |
| insn->def_opersize_64, num_prefixes, prefixes); |
| |
| if (insn->postop == X86_POSTOP_ADDRESS16 && insn->common.addrsize) { |
| yasm_warn_set(YASM_WARN_GENERAL, N_("address size override ignored")); |
| insn->common.addrsize = 0; |
| } |
| |
| /* Handle non-span-dependent post-ops here */ |
| switch (do_postop) { |
| case OPAP_ShortMov: |
| /* Long (modrm+sib) mov instructions in amd64 can be optimized into |
| * short mov instructions if a 32-bit address override is applied in |
| * 64-bit mode to an EA of just an offset (no registers) and the |
| * target register is al/ax/eax/rax. |
| */ |
| if (insn->common.mode_bits == 64 && insn->common.addrsize == 32 && |
| (!insn->x86_ea->ea.disp.abs || |
| !yasm_expr__contains(insn->x86_ea->ea.disp.abs, |
| YASM_EXPR_REG))) { |
| yasm_x86__ea_set_disponly(insn->x86_ea); |
| /* Make the short form permanent. */ |
| insn->opcode.opcode[0] = insn->opcode.opcode[1]; |
| } |
| insn->opcode.opcode[1] = 0; /* avoid possible confusion */ |
| break; |
| case OPAP_SImm32Avail: |
| /* Used for 64-bit mov immediate, which can take a sign-extended |
| * imm32 as well as imm64 values. The imm32 form is put in the |
| * second byte of the opcode and its ModRM byte is put in the third |
| * byte of the opcode. |
| */ |
| if (!insn->imm->abs || |
| (yasm_expr_get_intnum(&insn->imm->abs, 0) && |
| yasm_intnum_check_size( |
| yasm_expr_get_intnum(&insn->imm->abs, 0), 32, 0, 1))) { |
| /* Throwaway REX byte */ |
| unsigned char rex_temp = 0; |
| |
| /* Build ModRM EA - CAUTION: this depends on |
| * opcode 0 being a mov instruction! |
| */ |
| insn->x86_ea = yasm_x86__ea_create_reg( |
| (unsigned long)insn->opcode.opcode[0]-0xB8, &rex_temp, 64); |
| |
| /* Make the imm32s form permanent. */ |
| insn->opcode.opcode[0] = insn->opcode.opcode[1]; |
| insn->imm->size = 32; |
| } |
| insn->opcode.opcode[1] = 0; /* avoid possible confusion */ |
| break; |
| default: |
| break; |
| } |
| |
| /* Transform the bytecode */ |
| yasm_x86__bc_transform_insn(bc, insn); |
| } |
| |
| /* Static parse data structure for instructions */ |
| typedef struct insnprefix_parse_data { |
| const char *name; |
| |
| /* instruction parse group - NULL if prefix */ |
| /*@null@*/ const x86_insn_info *group; |
| |
| /* For instruction, modifier in upper 24 bits, number of elements in group |
| * in lower 8 bits. |
| * For prefix, prefix type. |
| */ |
| unsigned long data1; |
| |
| /* For instruction, cpu flags. |
| * For prefix, prefix value. |
| */ |
| unsigned long data2; |
| |
| /* suffix flags for instructions */ |
| enum { |
| NONE = 0, |
| SUF_B = (MOD_GasSufB >> MOD_GasSuf_SHIFT), |
| SUF_W = (MOD_GasSufW >> MOD_GasSuf_SHIFT), |
| SUF_L = (MOD_GasSufL >> MOD_GasSuf_SHIFT), |
| SUF_Q = (MOD_GasSufQ >> MOD_GasSuf_SHIFT), |
| SUF_S = (MOD_GasSufS >> MOD_GasSuf_SHIFT), |
| WEAK = 0x80 /* Relaxed operand mode for GAS */ |
| } flags; |
| } insnprefix_parse_data; |
| #define INSN(name, flags, group, mod, cpu) \ |
| { name, group##_insn, (mod##UL<<8)|NELEMS(group##_insn), cpu, flags } |
| #define PREFIX(name, type, value) \ |
| { name, NULL, type, value, NONE } |
| |
| /* Static parse data structure for CPU feature flags */ |
| typedef struct cpu_parse_data { |
| const char *name; |
| |
| unsigned long cpu; |
| enum { |
| CPU_MODE_VERBATIM, |
| CPU_MODE_SET, |
| CPU_MODE_CLEAR |
| } mode; |
| } cpu_parse_data; |
| |
| typedef struct regtmod_parse_data { |
| const char *name; |
| |
| unsigned long regtmod; |
| } regtmod_parse_data; |
| #define REG(name, type, index, bits) \ |
| { name, (((unsigned long)YASM_ARCH_REG) << 24) | \ |
| (((unsigned long)bits) << 16) | (type | index) } |
| #define REGGROUP(name, group) \ |
| { name, (((unsigned long)YASM_ARCH_REGGROUP) << 24) | (group) } |
| #define SEGREG(name, prefix, num, bits) \ |
| { name, (((unsigned long)YASM_ARCH_SEGREG) << 24) | \ |
| (((unsigned long)bits) << 16) | (prefix << 8) | (num) } |
| #define TARGETMOD(name, mod) \ |
| { name, (((unsigned long)YASM_ARCH_TARGETMOD) << 24) | (mod) } |
| |
| /* Pull in all parse data */ |
| #include "x86parse.c" |
| |
| static const char * |
| cpu_find_reverse(unsigned long cpu) |
| { |
| static char cpuname[200]; |
| |
| cpuname[0] = '\0'; |
| |
| if (cpu & CPU_Prot) |
| strcat(cpuname, " Protected"); |
| if (cpu & CPU_Undoc) |
| strcat(cpuname, " Undocumented"); |
| if (cpu & CPU_Obs) |
| strcat(cpuname, " Obsolete"); |
| if (cpu & CPU_Priv) |
| strcat(cpuname, " Privileged"); |
| |
| if (cpu & CPU_FPU) |
| strcat(cpuname, " FPU"); |
| if (cpu & CPU_MMX) |
| strcat(cpuname, " MMX"); |
| if (cpu & CPU_SSE) |
| strcat(cpuname, " SSE"); |
| if (cpu & CPU_SSE2) |
| strcat(cpuname, " SSE2"); |
| if (cpu & CPU_SSE3) |
| strcat(cpuname, " SSE3"); |
| if (cpu & CPU_3DNow) |
| strcat(cpuname, " 3DNow"); |
| if (cpu & CPU_Cyrix) |
| strcat(cpuname, " Cyrix"); |
| if (cpu & CPU_AMD) |
| strcat(cpuname, " AMD"); |
| if (cpu & CPU_SMM) |
| strcat(cpuname, " SMM"); |
| if (cpu & CPU_SVM) |
| strcat(cpuname, " SVM"); |
| if (cpu & CPU_PadLock) |
| strcat(cpuname, " PadLock"); |
| if (cpu & CPU_EM64T) |
| strcat(cpuname, " EM64T"); |
| if (cpu & CPU_SSSE3) |
| strcat(cpuname, " SSSE3"); |
| if (cpu & CPU_SSE41) |
| strcat(cpuname, " SSE4.1"); |
| if (cpu & CPU_SSE42) |
| strcat(cpuname, " SSE4.2"); |
| |
| if (cpu & CPU_186) |
| strcat(cpuname, " 186"); |
| if (cpu & CPU_286) |
| strcat(cpuname, " 286"); |
| if (cpu & CPU_386) |
| strcat(cpuname, " 386"); |
| if (cpu & CPU_486) |
| strcat(cpuname, " 486"); |
| if (cpu & CPU_586) |
| strcat(cpuname, " 586"); |
| if (cpu & CPU_686) |
| strcat(cpuname, " 686"); |
| if (cpu & CPU_P3) |
| strcat(cpuname, " P3"); |
| if (cpu & CPU_P4) |
| strcat(cpuname, " P4"); |
| if (cpu & CPU_IA64) |
| strcat(cpuname, " IA64"); |
| if (cpu & CPU_K6) |
| strcat(cpuname, " K6"); |
| if (cpu & CPU_Athlon) |
| strcat(cpuname, " Athlon"); |
| if (cpu & CPU_Hammer) |
| strcat(cpuname, " Hammer"); |
| return cpuname; |
| } |
| |
| yasm_arch_insnprefix |
| yasm_x86__parse_check_insnprefix(yasm_arch *arch, uintptr_t data[4], |
| const char *id, size_t id_len) |
| { |
| yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; |
| /*@null@*/ const insnprefix_parse_data *pdata; |
| size_t i; |
| static char lcaseid[16]; |
| |
| if (id_len > 15) |
| return YASM_ARCH_NOTINSNPREFIX; |
| for (i=0; i<id_len; i++) |
| lcaseid[i] = tolower(id[i]); |
| lcaseid[id_len] = '\0'; |
| |
| switch (arch_x86->parser) { |
| case X86_PARSER_NASM: |
| pdata = insnprefix_nasm_find(lcaseid, id_len); |
| break; |
| case X86_PARSER_GAS: |
| pdata = insnprefix_gas_find(lcaseid, id_len); |
| break; |
| default: |
| pdata = NULL; |
| } |
| if (!pdata) |
| return YASM_ARCH_NOTINSNPREFIX; |
| |
| if (pdata->group) { |
| unsigned long cpu = pdata->data2; |
| |
| if ((cpu & CPU_64) && arch_x86->mode_bits != 64) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("`%s' is an instruction in 64-bit mode"), id); |
| return YASM_ARCH_NOTINSNPREFIX; |
| } |
| if ((cpu & CPU_Not64) && arch_x86->mode_bits == 64) { |
| yasm_error_set(YASM_ERROR_GENERAL, |
| N_("`%s' invalid in 64-bit mode"), id); |
| data[0] = (uintptr_t)not64_insn; |
| data[1] = NELEMS(not64_insn); |
| data[2] = CPU_Not64; |
| data[3] = arch_x86->mode_bits; |
| return YASM_ARCH_INSN; |
| } |
| |
| cpu &= ~(CPU_64 | CPU_Not64); |
| if ((arch_x86->cpu_enabled & cpu) != cpu) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("`%s' is an instruction in CPU%s"), id, |
| cpu_find_reverse(cpu)); |
| return YASM_ARCH_NOTINSNPREFIX; |
| } |
| |
| data[0] = (uintptr_t)pdata->group; |
| data[1] = pdata->data1; |
| data[2] = arch_x86->cpu_enabled; |
| data[3] = (((unsigned long)pdata->flags)<<8) | arch_x86->mode_bits; |
| return YASM_ARCH_INSN; |
| } else { |
| unsigned long type = pdata->data1; |
| unsigned long value = pdata->data2; |
| |
| if (arch_x86->mode_bits == 64 && type == X86_OPERSIZE && value == 32) { |
| yasm_error_set(YASM_ERROR_GENERAL, |
| N_("Cannot override data size to 32 bits in 64-bit mode")); |
| return YASM_ARCH_NOTINSNPREFIX; |
| } |
| |
| if (arch_x86->mode_bits == 64 && type == X86_ADDRSIZE && value == 16) { |
| yasm_error_set(YASM_ERROR_GENERAL, |
| N_("Cannot override address size to 16 bits in 64-bit mode")); |
| return YASM_ARCH_NOTINSNPREFIX; |
| } |
| |
| if ((type == X86_REX || |
| (value == 64 && (type == X86_OPERSIZE || type == X86_ADDRSIZE))) |
| && arch_x86->mode_bits != 64) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("`%s' is a prefix in 64-bit mode"), id); |
| return YASM_ARCH_NOTINSNPREFIX; |
| } |
| data[0] = type; |
| data[1] = value; |
| return YASM_ARCH_PREFIX; |
| } |
| } |
| |
| void |
| yasm_x86__parse_cpu(yasm_arch_x86 *arch_x86, const char *cpuid, |
| size_t cpuid_len) |
| { |
| /*@null@*/ const cpu_parse_data *pdata; |
| size_t i; |
| static char lcaseid[16]; |
| |
| if (cpuid_len > 15) |
| return; |
| for (i=0; i<cpuid_len; i++) |
| lcaseid[i] = tolower(cpuid[i]); |
| lcaseid[cpuid_len] = '\0'; |
| |
| pdata = cpu_find(lcaseid, cpuid_len); |
| if (!pdata) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("unrecognized CPU identifier `%s'"), cpuid); |
| return; |
| } |
| |
| switch (pdata->mode) { |
| case CPU_MODE_VERBATIM: |
| arch_x86->cpu_enabled = pdata->cpu; |
| break; |
| case CPU_MODE_SET: |
| arch_x86->cpu_enabled |= pdata->cpu; |
| break; |
| case CPU_MODE_CLEAR: |
| arch_x86->cpu_enabled &= ~pdata->cpu; |
| break; |
| } |
| } |
| |
| yasm_arch_regtmod |
| yasm_x86__parse_check_regtmod(yasm_arch *arch, uintptr_t *data, |
| const char *id, size_t id_len) |
| { |
| yasm_arch_x86 *arch_x86 = (yasm_arch_x86 *)arch; |
| /*@null@*/ const regtmod_parse_data *pdata; |
| size_t i; |
| static char lcaseid[8]; |
| unsigned int bits; |
| yasm_arch_regtmod type; |
| |
| if (id_len > 7) |
| return YASM_ARCH_NOTREGTMOD; |
| for (i=0; i<id_len; i++) |
| lcaseid[i] = tolower(id[i]); |
| lcaseid[id_len] = '\0'; |
| |
| pdata = regtmod_find(lcaseid, id_len); |
| if (!pdata) |
| return YASM_ARCH_NOTREGTMOD; |
| |
| type = (yasm_arch_regtmod)(pdata->regtmod >> 24); |
| bits = (pdata->regtmod >> 16) & 0xFF; |
| |
| if (type == YASM_ARCH_REG && bits != 0 && arch_x86->mode_bits != bits) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("`%s' is a register in %u-bit mode"), id, bits); |
| return YASM_ARCH_NOTREGTMOD; |
| } |
| |
| if (type == YASM_ARCH_SEGREG && bits != 0 && arch_x86->mode_bits == bits) { |
| yasm_warn_set(YASM_WARN_GENERAL, |
| N_("`%s' segment register ignored in %u-bit mode"), id, |
| bits); |
| } |
| |
| *data = pdata->regtmod & 0x0000FFFFUL; |
| return type; |
| } |
| |