diff options
Diffstat (limited to 'libpixelflinger/codeflinger/x86/libenc/enc_tabl.cpp')
-rw-r--r-- | libpixelflinger/codeflinger/x86/libenc/enc_tabl.cpp | 2164 |
1 files changed, 2164 insertions, 0 deletions
diff --git a/libpixelflinger/codeflinger/x86/libenc/enc_tabl.cpp b/libpixelflinger/codeflinger/x86/libenc/enc_tabl.cpp new file mode 100644 index 0000000..b60d6b7 --- /dev/null +++ b/libpixelflinger/codeflinger/x86/libenc/enc_tabl.cpp @@ -0,0 +1,2164 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +/** + * @author Alexander V. Astapchuk + */ + + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> //qsort +#include <string.h> +#include <memory.h> +#include <errno.h> +#include <stdlib.h> + + +// need to use EM64T-specifics - new registers, defines from enc_prvt, etc... +#if !defined(_EM64T_) + #define UNDEF_EM64T + #define _EM64T_ +#endif + +#define USE_ENCODER_DEFINES +#include "enc_prvt.h" +#include "enc_defs.h" + +#ifdef UNDEF_EM64T + #undef _EM64T_ +#endif + +//Android x86 +#if 0 //!defined(_HAVE_MMX_) + #define Mnemonic_PADDQ Mnemonic_Null + #define Mnemonic_PAND Mnemonic_Null + #define Mnemonic_POR Mnemonic_Null + #define Mnemonic_PSUBQ Mnemonic_Null +#endif + +ENCODER_NAMESPACE_START + + +EncoderBase::MnemonicDesc EncoderBase::mnemonics[Mnemonic_Count]; +EncoderBase::OpcodeDesc EncoderBase::opcodes[Mnemonic_Count][MAX_OPCODES]; +unsigned char EncoderBase::opcodesHashMap[Mnemonic_Count][HASH_MAX]; + + +/** + * @file + * @brief 'Master' copy of encoding data. + */ + +/* +This file contains a 'master copy' of encoding table - this is the info used +by both generator of native instructions (EncoderBase class) and by +disassembling routines. The first one uses an info how to encode the +instruction, and the second does an opposite - several separate tables are +built at runtime from this main table. + +============================================================================= + +The table was designed for easy support and maintenance. Thus, it was made as +much close as possible to the Intel's IA32 Architecture Manual descriptions. +The info is based on the latest (at the moment of writing) revision which is +June 2005, order number 253666-016. + +Normally, almost all of opcodes in the 'master' table represented exactly as +they are shown in the Intel's Architecture manual (well, with slashes +replaced with underscore). There are several exclusions especially marked. + +Normally, to add an opcode/instruction, one only need to copy the whole +string from the manual, and simply replace '/' with '_'. + +I.e., TheManual reads for DEC: + (1) FE /1 DEC r/m8 Valid Valid Decrement r/m8 by 1. + (2) REX + FE /1 DEC r/m8* Valid N.E. Decrement r/m8 by 1. + (3) REX.W + FF /1 DEC r/m64 Valid N.E. Decrement r/m64 by 1. + +1. Note, that there is no need to explicitly specify REX-based opcodes for + instruction to handle additional registers on EM64T: + + (1) FE /1 DEC r/m8 Valid Valid Decrement r/m8 by 1. + (3) REX.W + FF /1 DEC r/m64 Valid N.E. Decrement r/m64 by 1. + +2. Copy the string, strip off the text comments, replace '/'=>'_'. Note, that + the second line is for EM64T only + + (1) FE /1 DEC r/m8 + (3) REX.W + FF /1 DEC r/m64 + +3. Fill out the mnemonic, opcode parameters parts + + BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU }, + {OpcodeInfo::em64t, {REX_W, 0xFF, _1}, {r_m64}, DU }, + + DU here - one argument, it's used and defined + +4. That's it, that simple ! + +The operand roles (DU here) are used by Jitrino's optimizing engine to +perform data flow analysis. It also used to store/obtain number of operands. + +Special cases are (see the table for details): +LEA +Some FPU operations (i.e. FSTP) +packed things (XORPD, XORPS, CVTDQ2PD, CVTTPD2DQ) + +Also, the Jitrino's needs require to specify all operands - including +implicit ones (see IMUL). + +The master table iself does not need to be ordered - it's get sorted before +processing. It's recommended (though it's not a law) to group similar +instructions together - i.e. FPU instructions, MMX, etc. + +============================================================================= + +The encoding engine builds several tables basing on the 'master' one (here +'mnemonic' is a kind of synonim for 'instruction'): + +- list of mnemonics which holds general info about instructions + (EncoderBase::mnemonics) +- an array of opcodes descriptions (EncodeBase::opcodes) +- a mapping between a hash value and an opcode description record for a given + mnemonic (EncoderBase::opcodesHashMap) + +The EncoderBase::mnemonics holds general info about instructions. +The EncoderBase::opcodesHashMap is used for fast opcode selection basing on +a hash value. +The EncodeBase::opcodes is used for the encoding itself. + +============================================================================= +The hash value is calculated and used as follows: + +JIT-ted code uses the following operand sizes: 8-, 16-, 32- and 64-bits and +size for an operand can be encoded in just 2 bits. + +The following operand locations are available: one of registers - GP, FP, +MMX, XMM (not taking segment registers), a memory and an immediate, which +gives us 6 variants and can be enumerated in 3 bits. + +As a grand total, the the whole operand's info needed for opcode selection +can be packed in 5 bits. Taking into account the IMUL mnemonic with its 3 +operands (including implicit ones), we're getting 15 bits per instruction and +the complete table is about 32768 items per single instruction. + +Seems too many, but luckily, the 15 bit limit will never be reached: the +worst case is IMUL with its 3 operands: +(IMUL r64, r/m64, imm32)/(IMUL r32, r/m32, imm32). +So, assigning lowest value to GP register, the max value of hash can be +reduced. + +The hash values to use are: +sizes: + 8 -> 11 + 16 -> 10 + 32 -> 01 + 64 -> 00 +locations: + gp reg -> 000 + memory -> 001 + fp reg -> 010 + mmx reg -> 011 + xmm reg -> 100 + immediate -> 101 +and the grand total for the worst case would be +[ GP 32] [GP 32] [Imm 32] +[000-01] [000-01] [101 01] = 1077 + +However, the implicit operands adds additional value, and the worstest case +is 'SHLD r_m32, r32, CL=r8'. This gives us the maximum number of: + +[mem 32] [GP 32] [GP 8b] +[001-01] [000-01] [000-11] = 5155. + +The max number is pretty big and the hash functions is quite rare, thus it +is not resonable to use a direct addressing i.e. +OpcodeDesc[mnemonic][hash_code] - there would be a huge waste of space. + +Instead, we use a kind of mapping: the opcodes info is stored in packed +(here: non rare) array. The max number of opcodes will not exceed 255 for +each instruction. And we have an index array in which we store a mapping +between a hash code value and opcode position for each given instruction. + +Sounds a bit sophisticated, but in real is simple, the opcode gets selected +in 2 simple steps: + +1. Select [hash,mnemonic] => 'n'. + +The array is pretty rare - many cells contain 0xFF which +means 'invalid hash - no opcode with given characteristics' + +char EnbcoderBase::opcodesHashMap[Mnemonic_Count][HASH_MAX] = + ++----+----+----+----+----+----+ +| 00 | 05 | FF | FF | 03 | 12 | ... +|---------+-------------------+ +| 12 | FF | FF | n | 04 | 25 | ... <- Mnemonic +|-----------------------------+ +| FF | 11 | FF | 10 | 13 | .. | ... ++-----------------------------+ + ... ^ + | + hash + +2. Select [n,mnemonic] => 'opcode_desc11' + +OpcodeDesc EncoderBase::opcodes[Mnemonic_Count][MAX_OPCODES] = + ++---------------+---------------+---------------+---------------+ +| opcode_desc00 | opcode_desc01 | opcode_desc02 | last_opcode | ... ++---------------+---------------+---------------+---------------+ +| opcode_desc10 | opcode_desc11 | last_opcode | xxx | <- Mnemonic ++---------------+---------------+---------------+---------------+ +| opcode_desc20 | opcode_desc21 | opcode_desc22 | opcode_desc23 | ... ++---------------+---------------+---------------+---------------+ + ... + ^ + | + n + +Now, use 'opcode_desc11'. + +============================================================================= +The array of opcodes descriptions (EncodeBase::opcodes) is specially prepared +to maximize performance - the EncoderBase::encode() is quite hot on client +applications for the Jitrino/Jitrino.JET. +The preparation is that opcode descriptions from the 'master' encoding table +are preprocessed and a special set of OpcodeDesc prepared: +First, the 'raw' opcode bytes are extracted. Here, 'raw' means the bytes that +do not depened on any operands values, do not require any analysis and can be +simply copied into the output buffer during encoding. Also, number of these +'raw' bytes is counted. The fields are OpcodeDesc::opcode and +OpcodeDesc::opcode_len. + +Then the fisrt non-implicit operand found and its index is stored in +OpcodeDesc::first_opnd. + +The bytes that require processing and analysis ('/r', '+i', etc) are +extracted and stored in OpcodeDesc::aux0 and OpcodeDesc::aux1 fields. + +Here, a special trick is performed: + Some opcodes have register/memory operand, but this is not reflected in + opcode column - for example, (MOVQ xmm64, xmm_m64). In this case, a fake + '_r' added to OpcodeDesc::aux field. + Some other opcodes have immediate operands, but this is again not + reflected in opcode column - for example, CALL cd or PUSH imm32. + In this case, a fake '/cd' or fake '/id' added to appropriate + OpcodeDesc::aux field. + +The OpcodeDesc::last is non-zero for the final OpcodeDesc record (which does +not have valid data itself). +*/ + +// TODO: To extend flexibility, replace bool fields in MnemonicDesc & +// MnemonicInfo with a set of flags packed into integer field. + +unsigned short EncoderBase::getHash(const OpcodeInfo* odesc) +{ + /* + NOTE: any changes in the hash computation must be stricty balanced with + EncoderBase::Operand::hash_it and EncoderBase::Operands() + */ + unsigned short hash = 0; + // The hash computation, uses fast way - table selection instead of if-s. + if (odesc->roles.count > 0) { + OpndKind kind = odesc->opnds[0].kind; + OpndSize size = odesc->opnds[0].size; + assert(kind<COUNTOF(kind_hash)); + assert(size<COUNTOF(size_hash)); + hash = get_kind_hash(kind) | get_size_hash(size); + } + + if (odesc->roles.count > 1) { + OpndKind kind = odesc->opnds[1].kind; + OpndSize size = odesc->opnds[1].size; + assert(kind<COUNTOF(kind_hash)); + assert(size<COUNTOF(size_hash)); + hash = (hash<<HASH_BITS_PER_OPERAND) | + (get_kind_hash(kind) | get_size_hash(size)); + } + + if (odesc->roles.count > 2) { + OpndKind kind = odesc->opnds[2].kind; + OpndSize size = odesc->opnds[2].size; + assert(kind<COUNTOF(kind_hash)); + assert(size<COUNTOF(size_hash)); + hash = (hash<<HASH_BITS_PER_OPERAND) | + (get_kind_hash(kind) | get_size_hash(size)); + } + assert(hash <= HASH_MAX); + return hash; +} + + +#define BEGIN_MNEMONIC(mn, flags, roles) \ + { Mnemonic_##mn, flags, roles, #mn, +#define END_MNEMONIC() }, +#define BEGIN_OPCODES() { +#define END_OPCODES() { OpcodeInfo::all, {OpcodeByteKind_LAST}, {}, {0, 0, 0, 0}}} + + +static MnemonicInfo masterEncodingTable[] = { +// +// Null +// +BEGIN_MNEMONIC(Null, MF_NONE, N) +BEGIN_OPCODES() +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(LAHF, MF_USES_FLAGS, D) +BEGIN_OPCODES() +// TheManual says it's not always supported in em64t mode, thus excluding it + {OpcodeInfo::ia32, {0x9F}, {EAX}, D }, +END_OPCODES() +END_MNEMONIC() +// +// ALU mnemonics - add, adc, or, xor, and, cmp, sub, sbb +// as they differ only in the opcode extention (/digit) number and +// in which number the opcode start from, the opcode definitions +// for those instructions are packed together +// +// The 'opcode_starts_from' and 'opcode_ext' in DEFINE_ALU_OPCODES() +// are enough to define OpcodeInfo::all opcodes and the 'first_opcode' +// parameter is only due to ADD instruction, which requires an zero opcode +// byte which, in turn, is coded especially in the current coding scheme. +// + +#define DEFINE_ALU_OPCODES( opc_ext, opcode_starts_from, first_opcode, def_use ) \ +\ + {OpcodeInfo::decoder, {opcode_starts_from + 4, ib}, {AL, imm8}, DU_U },\ + {OpcodeInfo::decoder, {Size16, opcode_starts_from + 5, iw}, {AX, imm16}, DU_U },\ + {OpcodeInfo::decoder, {opcode_starts_from + 5, id}, {EAX, imm32}, DU_U },\ + {OpcodeInfo::decoder64, {REX_W, opcode_starts_from+5, id}, {RAX, imm32s},DU_U },\ +\ + {OpcodeInfo::all, {0x80, opc_ext, ib}, {r_m8, imm8}, def_use },\ + {OpcodeInfo::all, {Size16, 0x81, opc_ext, iw}, {r_m16, imm16}, def_use },\ + {OpcodeInfo::all, {0x81, opc_ext, id}, {r_m32, imm32}, def_use },\ + {OpcodeInfo::em64t, {REX_W, 0x81, opc_ext, id}, {r_m64, imm32s}, def_use },\ +\ + {OpcodeInfo::all, {Size16, 0x83, opc_ext, ib}, {r_m16, imm8s}, def_use },\ + {OpcodeInfo::all, {0x83, opc_ext, ib}, {r_m32, imm8s}, def_use },\ + {OpcodeInfo::em64t, {REX_W, 0x83, opc_ext, ib}, {r_m64, imm8s}, def_use },\ +\ + {OpcodeInfo::all, {first_opcode, _r}, {r_m8, r8}, def_use },\ +\ + {OpcodeInfo::all, {Size16, opcode_starts_from+1, _r}, {r_m16, r16}, def_use },\ + {OpcodeInfo::all, {opcode_starts_from+1, _r}, {r_m32, r32}, def_use },\ + {OpcodeInfo::em64t, {REX_W, opcode_starts_from+1, _r}, {r_m64, r64}, def_use },\ +\ + {OpcodeInfo::all, {opcode_starts_from+2, _r}, {r8, r_m8}, def_use },\ +\ + {OpcodeInfo::all, {Size16, opcode_starts_from+3, _r}, {r16, r_m16}, def_use },\ + {OpcodeInfo::all, {opcode_starts_from+3, _r}, {r32, r_m32}, def_use },\ + {OpcodeInfo::em64t, {REX_W, opcode_starts_from+3, _r}, {r64, r_m64}, def_use }, + +BEGIN_MNEMONIC(ADD, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_0, 0x00, OxOO, DU_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(OR, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_1, 0x08, 0x08, DU_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(ADC, MF_AFFECTS_FLAGS|MF_USES_FLAGS|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_2, 0x10, 0x10, DU_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(SBB, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_3, 0x18, 0x18, DU_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(AND, MF_AFFECTS_FLAGS|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_4, 0x20, 0x20, DU_U ) +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(SUB, MF_AFFECTS_FLAGS|MF_SAME_ARG_NO_USE, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES(_5, 0x28, 0x28, DU_U ) +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(XOR, MF_AFFECTS_FLAGS|MF_SYMMETRIC|MF_SAME_ARG_NO_USE, DU_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES( _6, 0x30, 0x30, DU_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMP, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + DEFINE_ALU_OPCODES( _7, 0x38, 0x38, U_U ) +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPXCHG, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xB0, _r}, {r_m8, r8, AL}, DU_DU_DU }, + {OpcodeInfo::all, {Size16, 0x0F, 0xB1, _r}, {r_m16, r16, AX}, DU_DU_DU }, + {OpcodeInfo::all, {0x0F, 0xB1, _r}, {r_m32, r32, EAX}, DU_DU_DU}, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB1, _r}, {r_m64, r64, RAX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPXCHG8B, MF_AFFECTS_FLAGS, D) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xC7, _1}, {m64}, DU }, +END_OPCODES() +END_MNEMONIC() + +#undef DEFINE_ALU_OPCODES +// +// +// +BEGIN_MNEMONIC(ADDSD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x58, _r}, {xmm64, xmm_m64}, DU_U}, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(ADDSS, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x58, _r}, {xmm32, xmm_m32}, DU_U}, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(BSF, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xBC}, {r32, r_m32}, D_U}, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(BSR, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xBD}, {r32, r_m32}, D_U}, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(CALL, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xE8, cd}, {rel32}, U }, + {OpcodeInfo::ia32, {Size16, 0xE8, cw}, {rel16}, U }, + {OpcodeInfo::ia32, {0xFF, _2}, {r_m32}, U }, + {OpcodeInfo::em64t, {0xFF, _2}, {r_m64}, U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMC, MF_USES_FLAGS|MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::decoder, {0xF5}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +//TODO: Workaround. Actually, it's D_DU, but Jitrino's CG thinks it's D_U +BEGIN_MNEMONIC(CDQ, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x99}, {DX, AX}, D_U }, + {OpcodeInfo::all, {0x99}, {EDX, EAX}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x99}, {RDX, RAX}, D_U }, +END_OPCODES() +END_MNEMONIC() + +#define DEFINE_CMOVcc_MNEMONIC( cc ) \ + BEGIN_MNEMONIC(CMOV##cc, MF_USES_FLAGS|MF_CONDITIONAL, DU_U ) \ +BEGIN_OPCODES() \ + {OpcodeInfo::all, {Size16, 0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r16, r_m16}, DU_U }, \ + {OpcodeInfo::all, {0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r32, r_m32}, DU_U }, \ + {OpcodeInfo::em64t, {REX_W, 0x0F, 0x40 + ConditionMnemonic_##cc, _r}, {r64, r_m64}, DU_U }, \ +END_OPCODES() \ +END_MNEMONIC() + +DEFINE_CMOVcc_MNEMONIC(O) +DEFINE_CMOVcc_MNEMONIC(NO) +DEFINE_CMOVcc_MNEMONIC(B) +DEFINE_CMOVcc_MNEMONIC(NB) +DEFINE_CMOVcc_MNEMONIC(Z) +DEFINE_CMOVcc_MNEMONIC(NZ) +DEFINE_CMOVcc_MNEMONIC(BE) +DEFINE_CMOVcc_MNEMONIC(NBE) +DEFINE_CMOVcc_MNEMONIC(S) +DEFINE_CMOVcc_MNEMONIC(NS) +DEFINE_CMOVcc_MNEMONIC(P) +DEFINE_CMOVcc_MNEMONIC(NP) +DEFINE_CMOVcc_MNEMONIC(L) +DEFINE_CMOVcc_MNEMONIC(NL) +DEFINE_CMOVcc_MNEMONIC(LE) +DEFINE_CMOVcc_MNEMONIC(NLE) + +#undef DEFINE_CMOVcc_MNEMONIC + +/***************************************************************************** + ***** SSE conversion routines ***** +*****************************************************************************/ +// +// double -> float +BEGIN_MNEMONIC(CVTSD2SS, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x5A, _r}, {xmm32, xmm_m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// double -> I_32 +BEGIN_MNEMONIC(CVTSD2SI, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x2D, _r}, {r32, xmm_m64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2D, _r}, {r64, xmm_m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// double [truncated] -> I_32 +BEGIN_MNEMONIC(CVTTSD2SI, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x2C, _r}, {r32, xmm_m64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2C, _r}, {r64, xmm_m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// float -> double +BEGIN_MNEMONIC(CVTSS2SD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x5A, _r}, {xmm64, xmm_m32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// float -> I_32 +BEGIN_MNEMONIC(CVTSS2SI, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x2D, _r}, {r32, xmm_m32}, D_U}, + {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2D, _r}, {r64, xmm_m32}, D_U}, +END_OPCODES() +END_MNEMONIC() + +// float [truncated] -> I_32 +BEGIN_MNEMONIC(CVTTSS2SI, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x2C, _r}, {r32, xmm_m32}, D_U}, + {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2C, _r}, {r64, xmm_m32}, D_U}, +END_OPCODES() +END_MNEMONIC() + +// I_32 -> double +BEGIN_MNEMONIC(CVTSI2SD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m32}, D_U}, + {OpcodeInfo::em64t, {REX_W, 0xF2, 0x0F, 0x2A, _r}, {xmm64, r_m64}, D_U}, +END_OPCODES() +END_MNEMONIC() + +// I_32 -> float +BEGIN_MNEMONIC(CVTSI2SS, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m32}, D_U}, + {OpcodeInfo::em64t, {REX_W, 0xF3, 0x0F, 0x2A, _r}, {xmm32, r_m64}, D_U}, +END_OPCODES() +END_MNEMONIC() + +// +// ~ SSE conversions +// + +BEGIN_MNEMONIC(DEC, MF_AFFECTS_FLAGS, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xFE, _1}, {r_m8}, DU }, + + {OpcodeInfo::all, {Size16, 0xFF, _1}, {r_m16}, DU }, + {OpcodeInfo::all, {0xFF, _1}, {r_m32}, DU }, + {OpcodeInfo::em64t, {REX_W, 0xFF, _1}, {r_m64}, DU }, + + {OpcodeInfo::ia32, {Size16, 0x48|rw}, {r16}, DU }, + {OpcodeInfo::ia32, {0x48|rd}, {r32}, DU }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(DIVSD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x5E, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(DIVSS, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x5E, _r}, {xmm32, xmm_m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +/**************************************************************************** + ***** FPU operations ***** +****************************************************************************/ + +BEGIN_MNEMONIC(FADDP, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDE, 0xC1}, {FP0D}, DU }, + {OpcodeInfo::all, {0xDE, 0xC1}, {FP0S}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLDZ, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xEE}, {FP0D}, D }, + {OpcodeInfo::all, {0xD9, 0xEE}, {FP0S}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FADD, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDC, _0}, {FP0D, m64}, DU_U }, + {OpcodeInfo::all, {0xD8, _0}, {FP0S, m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSUBP, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDE, 0xE9}, {FP0D}, DU }, + {OpcodeInfo::all, {0xDE, 0xE9}, {FP0S}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSUB, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDC, _4}, {FP0D, m64}, DU_U }, + {OpcodeInfo::all, {0xD8, _4}, {FP0S, m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FISUB, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDA, _4}, {FP0S, m32}, DU_U }, +// {OpcodeInfo::all, {0xDE, _4}, {FP0S, m16}, DU_U }, +END_OPCODES() +END_MNEMONIC() + + + +BEGIN_MNEMONIC(FMUL, MF_NONE, DU_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD8, _1}, {FP0S, m32}, DU_U }, + {OpcodeInfo::all, {0xDC, _1}, {FP0D, m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FMULP, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDE, 0xC9}, {FP0D}, DU }, + {OpcodeInfo::all, {0xDE, 0xC9}, {FP0S}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FDIVP, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDE, 0xF9}, {FP0D}, DU }, + {OpcodeInfo::all, {0xDE, 0xF9}, {FP0S}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FDIV, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDC, _6}, {FP0D, m64}, DU_U }, + {OpcodeInfo::all, {0xD8, _6}, {FP0S, m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(FUCOM, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDD, 0xE1}, {FP0D, FP1D}, DU_U }, + {OpcodeInfo::all, {0xDD, 0xE1}, {FP0S, FP1S}, DU_U }, + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDD, 0xE0|_i}, {fp32}, DU }, + {OpcodeInfo::all, {0xDD, 0xE0|_i}, {fp64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FUCOMI, MF_NONE, D_U ) +BEGIN_OPCODES() + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDB, 0xE8|_i}, {fp32}, DU }, + {OpcodeInfo::all, {0xDB, 0xE8|_i}, {fp64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FUCOMP, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDD, 0xE9}, {FP0D, FP1D}, DU_U }, + {OpcodeInfo::all, {0xDD, 0xE9}, {FP0S, FP1S}, DU_U }, + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDD, 0xE8|_i}, {fp32}, DU }, + {OpcodeInfo::all, {0xDD, 0xE8|_i}, {fp64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FUCOMIP, MF_NONE, D_U ) +BEGIN_OPCODES() + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDF, 0xE8|_i}, {fp32}, DU }, + {OpcodeInfo::all, {0xDF, 0xE8|_i}, {fp64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FUCOMPP, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDA, 0xE9}, {FP0D, FP1D}, DU_U }, + {OpcodeInfo::all, {0xDA, 0xE9}, {FP0S, FP1S}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLDCW, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, _5}, {m16}, U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FNSTCW, MF_NONE, D) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, _7}, {m16}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSTSW, MF_NONE, D) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x9B, 0xDF, 0xE0}, {EAX}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FNSTSW, MF_NONE, D) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDF, 0xE0}, {EAX}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FCHS, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xE0}, {FP0D}, DU }, + {OpcodeInfo::all, {0xD9, 0xE0}, {FP0S}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FCLEX, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x9B, 0xDB, 0xE2}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FNCLEX, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDB, 0xE2}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +//BEGIN_MNEMONIC(FDECSTP, MF_NONE, N) +// BEGIN_OPCODES() +// {OpcodeInfo::all, {0xD9, 0xF6}, {}, N }, +// END_OPCODES() +//END_MNEMONIC() + +BEGIN_MNEMONIC(FILD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDB, _0}, {FP0S, m32}, D_U }, + {OpcodeInfo::all, {0xDF, _5}, {FP0D, m64}, D_U }, + {OpcodeInfo::all, {0xDB, _0}, {FP0S, m32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +//BEGIN_MNEMONIC(FINCSTP, MF_NONE, N) +// BEGIN_OPCODES() +// {OpcodeInfo::all, {0xD9, 0xF7}, {}, N }, +// END_OPCODES() +//END_MNEMONIC() + +BEGIN_MNEMONIC(FIST, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDB, _2}, {m32, FP0S}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FISTP, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDB, _3}, {m32, FP0S}, D_U }, + {OpcodeInfo::all, {0xDF, _7}, {m64, FP0D}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FISTTP, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xDD, _1}, {m64, FP0D}, D_U }, + {OpcodeInfo::all, {0xDB, _1}, {m32, FP0S}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FRNDINT, MF_NONE, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xFC}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xFC}, {FP0D}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, _0}, {FP0S, m32}, D_U }, + {OpcodeInfo::all, {0xDD, _0}, {FP0D, m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLDLG2, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xEC}, {FP0S}, D }, + {OpcodeInfo::all, {0xD9, 0xEC}, {FP0D}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLDLN2, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xED}, {FP0S}, D }, + {OpcodeInfo::all, {0xD9, 0xED}, {FP0D}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FLD1, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xE8}, {FP0S}, D }, + {OpcodeInfo::all, {0xD9, 0xE8}, {FP0D}, D }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(FPREM, MF_NONE, N) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF8}, {}, N }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FPREM1, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF5}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FST, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, _2}, {m32, FP0S}, D_U }, + {OpcodeInfo::all, {0xDD, _2}, {m64, FP0D}, D_U }, + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDD, 0xD0|_i}, {fp32}, D }, + {OpcodeInfo::all, {0xDD, 0xD0|_i}, {fp64}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSTP, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, _3}, {m32, FP0S}, D_U }, + {OpcodeInfo::all, {0xDD, _3}, {m64, FP0D}, D_U }, + // A little trick: actually, these 2 opcodes take only index of the + // needed register. To make the things similar to other instructions + // we encode here as if they took FPREG. + {OpcodeInfo::all, {0xDD, 0xD8|_i}, {fp32}, D }, + {OpcodeInfo::all, {0xDD, 0xD8|_i}, {fp64}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSQRT, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xFA}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xFA}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(FYL2X, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF1}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xF1}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(FYL2XP1, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF9}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xF9}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(F2XM1, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF0}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xF0}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FPATAN, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF3}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xF3}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FXCH, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xC9}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xC9}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSCALE, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xFD}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xFD}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FABS, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xE1}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xE1}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FSIN, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xFE}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xFE}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FCOS, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xFF}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xFF}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(FPTAN, MF_NONE, DU) + BEGIN_OPCODES() + {OpcodeInfo::all, {0xD9, 0xF2}, {FP0S}, DU }, + {OpcodeInfo::all, {0xD9, 0xF2}, {FP0D}, DU }, + END_OPCODES() +END_MNEMONIC() + +// +// ~ FPU +// + +BEGIN_MNEMONIC(DIV, MF_AFFECTS_FLAGS, DU_DU_U) +BEGIN_OPCODES() +#if !defined(_EM64T_) + {OpcodeInfo::all, {0xF6, _6}, {AH, AL, r_m8}, DU_DU_U }, + {OpcodeInfo::all, {Size16, 0xF7, _6}, {DX, AX, r_m16}, DU_DU_U }, +#endif + {OpcodeInfo::all, {0xF7, _6}, {EDX, EAX, r_m32}, DU_DU_U }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _6}, {RDX, RAX, r_m64}, DU_DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(IDIV, MF_AFFECTS_FLAGS, DU_DU_U) +BEGIN_OPCODES() +#if !defined(_EM64T_) + {OpcodeInfo::all, {0xF6, _7}, {AH, AL, r_m8}, DU_DU_U }, + {OpcodeInfo::all, {Size16, 0xF7, _7}, {DX, AX, r_m16}, DU_DU_U }, +#endif + {OpcodeInfo::all, {0xF7, _7}, {EDX, EAX, r_m32}, DU_DU_U }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _7}, {RDX, RAX, r_m64}, DU_DU_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(IMUL, MF_AFFECTS_FLAGS, D_DU_U) +BEGIN_OPCODES() + /*{OpcodeInfo::all, {0xF6, _5}, {AH, AL, r_m8}, D_DU_U }, + {OpcodeInfo::all, {Size16, 0xF7, _5}, {DX, AX, r_m16}, D_DU_U }, + */ + // + {OpcodeInfo::all, {0xF7, _5}, {EDX, EAX, r_m32}, D_DU_U }, + //todo: this opcode's hash conflicts with IMUL r64,r_m64 - they're both 0. + // this particular is not currently used, so we may safely drop it, but need to + // revisit the hash implementation + // {OpcodeInfo::em64t, {REX_W, 0xF7, _5}, {RDX, RAX, r_m64}, D_DU_U }, + // + {OpcodeInfo::all, {Size16, 0x0F, 0xAF, _r}, {r16,r_m16}, DU_U }, + {OpcodeInfo::all, {0x0F, 0xAF, _r}, {r32,r_m32}, DU_U }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xAF, _r}, {r64,r_m64}, DU_U }, + {OpcodeInfo::all, {Size16, 0x6B, _r, ib}, {r16,r_m16,imm8s}, D_DU_U }, + {OpcodeInfo::all, {0x6B, _r, ib}, {r32,r_m32,imm8s}, D_DU_U }, + {OpcodeInfo::em64t, {REX_W, 0x6B, _r, ib}, {r64,r_m64,imm8s}, D_DU_U }, + {OpcodeInfo::all, {Size16, 0x6B, _r, ib}, {r16,imm8s}, DU_U }, + {OpcodeInfo::all, {0x6B, _r, ib}, {r32,imm8s}, DU_U }, + {OpcodeInfo::em64t, {REX_W, 0x6B, _r, ib}, {r64,imm8s}, DU_U }, + {OpcodeInfo::all, {Size16, 0x69, _r, iw}, {r16,r_m16,imm16}, D_U_U }, + {OpcodeInfo::all, {0x69, _r, id}, {r32,r_m32,imm32}, D_U_U }, + {OpcodeInfo::em64t, {REX_W, 0x69, _r, id}, {r64,r_m64,imm32s}, D_U_U }, + {OpcodeInfo::all, {Size16, 0x69, _r, iw}, {r16,imm16}, DU_U }, + {OpcodeInfo::all, {0x69, _r, id}, {r32,imm32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MUL, MF_AFFECTS_FLAGS, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF6, _4}, {AX, AL, r_m8}, D_DU_U }, + {OpcodeInfo::all, {Size16, 0xF7, _4}, {DX, AX, r_m16}, D_DU_U }, + {OpcodeInfo::all, {0xF7, _4}, {EDX, EAX, r_m32}, D_DU_U }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _4}, {RDX, RAX, r_m64}, D_DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(INC, MF_AFFECTS_FLAGS, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xFE, _0}, {r_m8}, DU }, + {OpcodeInfo::all, {Size16, 0xFF, _0}, {r_m16}, DU }, + {OpcodeInfo::all, {0xFF, _0}, {r_m32}, DU }, + {OpcodeInfo::em64t, {REX_W, 0xFF, _0}, {r_m64}, DU }, + {OpcodeInfo::ia32, {Size16, 0x40|rw}, {r16}, DU }, + {OpcodeInfo::ia32, {0x40|rd}, {r32}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(INT3, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xCC}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +#define DEFINE_Jcc_MNEMONIC( cc ) \ + BEGIN_MNEMONIC(J##cc, MF_USES_FLAGS|MF_CONDITIONAL, U ) \ +BEGIN_OPCODES() \ + {OpcodeInfo::all, {0x70 + ConditionMnemonic_##cc, cb }, { rel8 }, U }, \ + {OpcodeInfo::ia32, {Size16, 0x0F, 0x80 + ConditionMnemonic_##cc, cw}, { rel16 }, U }, \ + {OpcodeInfo::all, {0x0F, 0x80 + ConditionMnemonic_##cc, cd}, { rel32 }, U }, \ +END_OPCODES() \ +END_MNEMONIC() + + +DEFINE_Jcc_MNEMONIC(O) +DEFINE_Jcc_MNEMONIC(NO) +DEFINE_Jcc_MNEMONIC(B) +DEFINE_Jcc_MNEMONIC(NB) +DEFINE_Jcc_MNEMONIC(Z) +DEFINE_Jcc_MNEMONIC(NZ) +DEFINE_Jcc_MNEMONIC(BE) +DEFINE_Jcc_MNEMONIC(NBE) + +DEFINE_Jcc_MNEMONIC(S) +DEFINE_Jcc_MNEMONIC(NS) +DEFINE_Jcc_MNEMONIC(P) +DEFINE_Jcc_MNEMONIC(NP) +DEFINE_Jcc_MNEMONIC(L) +DEFINE_Jcc_MNEMONIC(NL) +DEFINE_Jcc_MNEMONIC(LE) +DEFINE_Jcc_MNEMONIC(NLE) + +#undef DEFINE_Jcc_MNEMONIC + +BEGIN_MNEMONIC(JMP, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xEB, cb}, {rel8}, U }, + {OpcodeInfo::ia32, {Size16, 0xE9, cw}, {rel16}, U }, + {OpcodeInfo::all, {0xE9, cd}, {rel32}, U }, + {OpcodeInfo::ia32, {Size16, 0xFF, _4}, {r_m16}, U }, + {OpcodeInfo::ia32, {0xFF, _4}, {r_m32}, U }, + {OpcodeInfo::em64t, {0xFF, _4}, {r_m64}, U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(LEA, MF_NONE, D_U ) +BEGIN_OPCODES() + /* + A special case: the LEA instruction itself does not care about size of + second operand. This is obviuos why it is, and thus in The Manual, a + simple 'm' without size is used. + However, in the Jitrino's instrucitons we'll have an operand with a size. + Also, the hashing scheme is not supposed to handle OpndSize_Null, and + making it to do so will lead to unnecessary complication of hashing + scheme. Thus, instead of handling it as a special case, we simply make + copies of the opcodes with sizes set. + {OpcodeInfo::all, {0x8D, _r}, {r32, m}, D_U }, + {OpcodeInfo::em64t, {0x8D, _r}, {r64, m}, D_U }, + */ + //Android x86: keep r32, m32 only, otherwise, will have decoding error + //{OpcodeInfo::all, {0x8D, _r}, {r32, m8}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m8}, D_U }, + //{OpcodeInfo::all, {0x8D, _r}, {r32, m16}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m16}, D_U }, + {OpcodeInfo::all, {0x8D, _r}, {r32, m32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m32}, D_U }, + {OpcodeInfo::all, {0x8D, _r}, {r32, m64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8D, _r}, {r64, m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(LOOP, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xE2, cb}, {ECX, rel8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(LOOPE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xE1, cb}, {ECX, rel8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(LOOPNE, MF_AFFECTS_FLAGS|MF_USES_FLAGS, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xE0, cb}, {ECX, rel8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOV, MF_NONE, D_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x88, _r}, {r_m8,r8}, D_U }, + + {OpcodeInfo::all, {Size16, 0x89, _r}, {r_m16,r16}, D_U }, + {OpcodeInfo::all, {0x89, _r}, {r_m32,r32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x89, _r}, {r_m64,r64}, D_U }, + {OpcodeInfo::all, {0x8A, _r}, {r8,r_m8}, D_U }, + + {OpcodeInfo::all, {Size16, 0x8B, _r}, {r16,r_m16}, D_U }, + {OpcodeInfo::all, {0x8B, _r}, {r32,r_m32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x8B, _r}, {r64,r_m64}, D_U }, + + {OpcodeInfo::all, {0xB0|rb}, {r8,imm8}, D_U }, + + {OpcodeInfo::all, {Size16, 0xB8|rw}, {r16,imm16}, D_U }, + {OpcodeInfo::all, {0xB8|rd}, {r32,imm32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0xB8|rd}, {r64,imm64}, D_U }, + {OpcodeInfo::all, {0xC6, _0}, {r_m8,imm8}, D_U }, + + {OpcodeInfo::all, {Size16, 0xC7, _0}, {r_m16,imm16}, D_U }, + {OpcodeInfo::all, {0xC7, _0}, {r_m32,imm32}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0xC7, _0}, {r_m64,imm32s}, D_U }, + + {OpcodeInfo::decoder, {0xA0}, {AL, moff8}, D_U }, + {OpcodeInfo::decoder, {Size16, 0xA1}, {AX, moff16}, D_U }, + {OpcodeInfo::decoder, {0xA1}, {EAX, moff32}, D_U }, + //{OpcodeInfo::decoder64, {REX_W, 0xA1}, {RAX, moff64}, D_U }, + + {OpcodeInfo::decoder, {0xA2}, {moff8, AL}, D_U }, + {OpcodeInfo::decoder, {Size16, 0xA3}, {moff16, AX}, D_U }, + {OpcodeInfo::decoder, {0xA3}, {moff32, EAX}, D_U }, + //{OpcodeInfo::decoder64, {REX_W, 0xA3}, {moff64, RAX}, D_U }, +END_OPCODES() +END_MNEMONIC() + + + +BEGIN_MNEMONIC(XCHG, MF_NONE, DU_DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x87, _r}, {r_m32,r32}, DU_DU }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(MOVQ, MF_NONE, D_U ) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0x6F, _r}, {mm64, mm_m64}, D_U }, + {OpcodeInfo::all, {0x0F, 0x7F, _r}, {mm_m64, mm64}, D_U }, +#endif + {OpcodeInfo::all, {0xF3, 0x0F, 0x7E }, {xmm64, xmm_m64}, D_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0xD6 }, {xmm_m64, xmm64}, D_U }, +// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r_m64}, D_U }, +// {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r_m64, xmm64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x6E, _r}, {xmm64, r64}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x66, 0x0F, 0x7E, _r}, {r64, xmm64}, D_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(MOVD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x6E, _r}, {xmm32, r_m32}, D_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x7E, _r}, {r_m32, xmm32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// +// A bunch of MMX instructions +// +#ifdef _HAVE_MMX_ + +BEGIN_MNEMONIC(EMMS, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0x77}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +#endif + +BEGIN_MNEMONIC(PADDQ, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xD4, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xD4, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PAND, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xDB, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xDB, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(POR, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xEB, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xEB, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSUBQ, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xFB, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xFB, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PANDN, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xDF, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xDF, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() +BEGIN_MNEMONIC(PSLLQ, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xF3, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xF3, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x73, _6, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() +BEGIN_MNEMONIC(PSRLQ, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xD3, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xD3, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x73, _2, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PXOR, MF_NONE, DU_U) +BEGIN_OPCODES() +#ifdef _HAVE_MMX_ + {OpcodeInfo::all, {0x0F, 0xEF, _r}, {mm64, mm_m64}, DU_U }, +#endif + {OpcodeInfo::all, {0x66, 0x0F, 0xEF, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(MOVAPD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x28, _r}, {xmm64, xmm_m64}, D_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x29, _r}, {xmm_m64, xmm64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVAPS, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0x28, _r}, {xmm64, xmm_m64}, D_U }, + {OpcodeInfo::all, {0x0F, 0x29, _r}, {xmm_m64, xmm64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(SHUFPS, MF_NONE, D_U_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xC6, _r, ib}, {xmm64, xmm_m64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(MOVSD, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x10, _r}, {xmm64, xmm_m64}, D_U }, + {OpcodeInfo::all, {0xF2, 0x0F, 0x11, _r}, {xmm_m64, xmm64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVSS, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x10, _r}, {xmm32, xmm_m32}, D_U }, + {OpcodeInfo::all, {0xF3, 0x0F, 0x11, _r}, {xmm_m32, xmm32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVSX, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {Size16, 0x0F, 0xBE, _r}, {r16, r_m8s}, D_U }, + {OpcodeInfo::all, {0x0F, 0xBE, _r}, {r32, r_m8s}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xBE, _r}, {r64, r_m8s}, D_U }, + + {OpcodeInfo::all, {0x0F, 0xBF, _r}, {r32, r_m16s}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xBF, _r}, {r64, r_m16s}, D_U }, + + {OpcodeInfo::em64t, {REX_W, 0x63, _r}, {r64, r_m32s}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVZX, MF_NONE, D_U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {Size16, 0x0F, 0xB6, _r}, {r16, r_m8u}, D_U }, + {OpcodeInfo::all, {0x0F, 0xB6, _r}, {r32, r_m8u}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB6, _r}, {r64, r_m8u}, D_U }, + + {OpcodeInfo::all, {0x0F, 0xB7, _r}, {r32, r_m16u}, D_U }, + {OpcodeInfo::em64t, {REX_W, 0x0F, 0xB7, _r}, {r64, r_m16u}, D_U }, + //workaround to get r/rm32->r64 ZX mov functionality: + //simple 32bit reg copying zeros high bits in 64bit reg + {OpcodeInfo::em64t, {0x8B, _r}, {r64, r_m32u}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MULSD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x59, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MULSS, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x59, _r}, {xmm32, xmm_m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(NEG, MF_AFFECTS_FLAGS, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF6, _3}, {r_m8}, DU }, + + {OpcodeInfo::all, {Size16, 0xF7, _3}, {r_m16}, DU }, + {OpcodeInfo::all, {0xF7, _3}, {r_m32}, DU }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _3}, {r_m64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(NOP, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x90}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(NOT, MF_AFFECTS_FLAGS, DU ) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF6, _2}, {r_m8}, DU }, + {OpcodeInfo::all, {Size16, 0xF7, _2}, {r_m16}, DU }, + {OpcodeInfo::all, {0xF7, _2}, {r_m32}, DU }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _2}, {r_m64}, DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(POP, MF_NONE, D) +BEGIN_OPCODES() + {OpcodeInfo::all, {Size16, 0x8F, _0}, {r_m16}, D }, + {OpcodeInfo::ia32, {0x8F, _0}, {r_m32}, D }, + {OpcodeInfo::em64t, {0x8F, _0}, {r_m64}, D }, + + {OpcodeInfo::all, {Size16, 0x58|rw }, {r16}, D }, + {OpcodeInfo::ia32, {0x58|rd }, {r32}, D }, + {OpcodeInfo::em64t, {0x58|rd }, {r64}, D }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(POPFD, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x9D}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PREFETCH, MF_NONE, U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0x18, _0}, {m8}, U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PUSH, MF_NONE, U ) +BEGIN_OPCODES() + {OpcodeInfo::all, {Size16, 0xFF, _6}, {r_m16}, U }, + {OpcodeInfo::ia32, {0xFF, _6}, {r_m32}, U }, + {OpcodeInfo::em64t, {0xFF, _6}, {r_m64}, U }, + + {OpcodeInfo::all, {Size16, 0x50|rw }, {r16}, U }, + {OpcodeInfo::ia32, {0x50|rd }, {r32}, U }, + {OpcodeInfo::em64t, {0x50|rd }, {r64}, U }, + + {OpcodeInfo::all, {0x6A}, {imm8}, U }, + {OpcodeInfo::all, {Size16, 0x68}, {imm16}, U }, + {OpcodeInfo::ia32, {0x68}, {imm32}, U }, +// {OpcodeInfo::em64t, {0x68}, {imm64}, U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PUSHFD, MF_USES_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x9C}, {}, N }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(RET, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xC3}, {}, N }, + {OpcodeInfo::all, {0xC2, iw}, {imm16}, U }, +END_OPCODES() +END_MNEMONIC() + +#define DEFINE_SETcc_MNEMONIC( cc ) \ + BEGIN_MNEMONIC(SET##cc, MF_USES_FLAGS|MF_CONDITIONAL, DU) \ +BEGIN_OPCODES() \ + {OpcodeInfo::all, {0x0F, 0x90 + ConditionMnemonic_##cc}, {r_m8}, DU }, \ +END_OPCODES() \ +END_MNEMONIC() + +DEFINE_SETcc_MNEMONIC(O) +DEFINE_SETcc_MNEMONIC(NO) +DEFINE_SETcc_MNEMONIC(B) +DEFINE_SETcc_MNEMONIC(NB) +DEFINE_SETcc_MNEMONIC(Z) +DEFINE_SETcc_MNEMONIC(NZ) +DEFINE_SETcc_MNEMONIC(BE) +DEFINE_SETcc_MNEMONIC(NBE) + +DEFINE_SETcc_MNEMONIC(S) +DEFINE_SETcc_MNEMONIC(NS) +DEFINE_SETcc_MNEMONIC(P) +DEFINE_SETcc_MNEMONIC(NP) +DEFINE_SETcc_MNEMONIC(L) +DEFINE_SETcc_MNEMONIC(NL) +DEFINE_SETcc_MNEMONIC(LE) +DEFINE_SETcc_MNEMONIC(NLE) + +#undef DEFINE_SETcc_MNEMONIC + +#define DEFINE_SHIFT_MNEMONIC(nam, slash_num, flags) \ +BEGIN_MNEMONIC(nam, flags, DU_U) \ +BEGIN_OPCODES()\ + /* D0 & D1 opcodes are added w/o 2nd operand (1) because */\ + /* they are used for decoding only so only instruction length is needed */\ + {OpcodeInfo::decoder, {0xD0, slash_num}, {r_m8/*,const_1*/}, DU },\ + {OpcodeInfo::all, {0xD2, slash_num}, {r_m8, CL}, DU_U },\ + {OpcodeInfo::all, {0xC0, slash_num, ib}, {r_m8, imm8}, DU_U },\ +\ + {OpcodeInfo::decoder, {Size16, 0xD1, slash_num}, {r_m16/*,const_1*/}, DU },\ + {OpcodeInfo::all, {Size16, 0xD3, slash_num}, {r_m16, CL}, DU_U },\ + {OpcodeInfo::all, {Size16, 0xC1, slash_num, ib}, {r_m16, imm8 }, DU_U },\ +\ + {OpcodeInfo::decoder, {0xD1, slash_num}, {r_m32/*,const_1*/}, DU },\ + {OpcodeInfo::decoder64, {REX_W, 0xD1, slash_num}, {r_m64/*,const_1*/}, DU },\ +\ + {OpcodeInfo::all, {0xD3, slash_num}, {r_m32, CL}, DU_U },\ + {OpcodeInfo::em64t, {REX_W, 0xD3, slash_num}, {r_m64, CL}, DU_U },\ +\ + {OpcodeInfo::all, {0xC1, slash_num, ib}, {r_m32, imm8}, DU_U },\ + {OpcodeInfo::em64t, {REX_W, 0xC1, slash_num, ib}, {r_m64, imm8}, DU_U },\ +END_OPCODES()\ +END_MNEMONIC() + + +DEFINE_SHIFT_MNEMONIC(ROL, _0, MF_AFFECTS_FLAGS) +DEFINE_SHIFT_MNEMONIC(ROR, _1, MF_AFFECTS_FLAGS) +DEFINE_SHIFT_MNEMONIC(RCL, _2, MF_AFFECTS_FLAGS|MF_USES_FLAGS) +DEFINE_SHIFT_MNEMONIC(RCR, _3, MF_AFFECTS_FLAGS|MF_USES_FLAGS) + +DEFINE_SHIFT_MNEMONIC(SAL, _4, MF_AFFECTS_FLAGS) +DEFINE_SHIFT_MNEMONIC(SHR, _5, MF_AFFECTS_FLAGS) +DEFINE_SHIFT_MNEMONIC(SAR, _7, MF_AFFECTS_FLAGS) + +#undef DEFINE_SHIFT_MNEMONIC + +BEGIN_MNEMONIC(SHLD, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xA5}, {r_m32, r32, CL}, DU_DU_U }, + {OpcodeInfo::all, {0x0F, 0xA4}, {r_m32, r32, imm8}, DU_DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(SHRD, MF_AFFECTS_FLAGS, N) +// TODO: the def/use info is wrong +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0xAD}, {r_m32, r32, CL}, DU_DU_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(SUBSD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x5C, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(SUBSS, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x5C, _r}, {xmm32, xmm_m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(TEST, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + + {OpcodeInfo::decoder, {0xA8, ib}, { AL, imm8}, U_U }, + {OpcodeInfo::decoder, {0xA9, iw}, { AX, imm16}, U_U }, + {OpcodeInfo::decoder, {0xA9, id}, { EAX, imm32}, U_U }, + {OpcodeInfo::decoder64, {REX_W, 0xA9, id}, { RAX, imm32s}, U_U }, + + {OpcodeInfo::all, {0xF6, _0, ib}, {r_m8,imm8}, U_U }, + + {OpcodeInfo::all, {Size16, 0xF7, _0, iw}, {r_m16,imm16}, U_U }, + {OpcodeInfo::all, {0xF7, _0, id}, {r_m32,imm32}, U_U }, + {OpcodeInfo::em64t, {REX_W, 0xF7, _0, id}, {r_m64,imm32s}, U_U }, + + {OpcodeInfo::all, {0x84, _r}, {r_m8,r8}, U_U }, + + {OpcodeInfo::all, {Size16, 0x85, _r}, {r_m16,r16}, U_U }, + {OpcodeInfo::all, {0x85, _r}, {r_m32,r32}, U_U }, + {OpcodeInfo::em64t, {REX_W, 0x85, _r}, {r_m64,r64}, U_U }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(UCOMISD, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x2E, _r}, {xmm64, xmm_m64}, U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(UCOMISS, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0x2E, _r}, {xmm32, xmm_m32}, U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(COMISD, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x2F, _r}, {xmm64, xmm_m64}, U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(COMISS, MF_AFFECTS_FLAGS, U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x0F, 0x2F, _r}, {xmm32, xmm_m32}, U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(XORPD, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0x66, 0x0F, 0x57, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(XORPS, MF_SAME_ARG_NO_USE|MF_SYMMETRIC, DU_U) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0x0F, 0x57, _r}, {xmm32, xmm_m32}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CVTDQ2PD, MF_NONE, D_U ) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0xF3, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CVTDQ2PS, MF_NONE, D_U ) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CVTTPD2DQ, MF_NONE, D_U ) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0x66, 0x0F, 0xE6}, {xmm64, xmm_m64}, D_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CVTTPS2DQ, MF_NONE, D_U ) +BEGIN_OPCODES() + //Note: they're actually 128 bits + {OpcodeInfo::all, {0xF3, 0x0F, 0x5B, _r}, {xmm32, xmm_m32}, D_U }, +END_OPCODES() +END_MNEMONIC() + +// +// String operations +// +BEGIN_MNEMONIC(STD, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xFD}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CLD, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xFC}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(SCAS, MF_AFFECTS_FLAGS, N) +// to be symmetric, this mnemonic must have either m32 or RegName_EAX +// but as long, as Jitrino's CG does not use the mnemonic, leaving it +// in its natural form +BEGIN_OPCODES() + {OpcodeInfo::all, {0xAF}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(STOS, MF_AFFECTS_FLAGS, DU_DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xAB}, {EDI, ECX, EAX}, DU_DU_U }, + {OpcodeInfo::all, {0xAA}, {EDI, ECX, AL}, DU_DU_U }, + {OpcodeInfo::em64t, {REX_W, 0xAB}, {RDI, RCX, RAX}, DU_DU_U }, +END_OPCODES() +END_MNEMONIC() + +/* +MOVS and CMPS are the special cases. +Most the code in both CG and Encoder do not expect 2 memory operands. +Also, they are not supposed to setup constrains on which register the +memory reference must reside - m8,m8 or m32,m32 is not the choice. +We can't use r8,r8 either - will have problem with 8bit EDI, ESI. +So, as the workaround we do r32,r32 and specify size of the operand through +the specific mnemonic - the same is in the codegen. +*/ +BEGIN_MNEMONIC(MOVS8, MF_NONE, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA4}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA4}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVS16, MF_NONE, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {Size16, 0xA5}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {Size16, 0xA5}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVS32, MF_NONE, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA5}, {r32,r32,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA5}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVS64, MF_NONE, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::em64t, {REX_W,0xA5}, {r64,r64,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPSB, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA6}, {ESI,EDI,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA6}, {RSI,RDI,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPSW, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {Size16, 0xA7}, {ESI,EDI,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {Size16, 0xA7}, {RSI,RDI,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(CMPSD, MF_AFFECTS_FLAGS, DU_DU_DU) +BEGIN_OPCODES() + {OpcodeInfo::ia32, {0xA7}, {ESI,EDI,ECX}, DU_DU_DU }, + {OpcodeInfo::em64t, {0xA7}, {RSI,RDI,RCX}, DU_DU_DU }, +END_OPCODES() +END_MNEMONIC() + + +BEGIN_MNEMONIC(WAIT, MF_AFFECTS_FLAGS, N) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x9B}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +// +// ~String operations +// + +// +//Note: the instructions below added for the sake of disassembling routine. +// They need to have flags, params and params usage to be defined more precisely. +// +BEGIN_MNEMONIC(LEAVE, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::decoder, {0xC9}, {}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(ENTER, MF_NONE, N) +BEGIN_OPCODES() + {OpcodeInfo::decoder, {0xC8, iw, ib}, {imm16, imm8}, N }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PADDB, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xFC, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PADDW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xFD, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PADDD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xFE, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSUBB, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xF8, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSUBW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xF9, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSUBD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xFA, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PMULLW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xD5, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PMULLD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x40, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSLLW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xF1, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x71, _6, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSLLD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xF2, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x72, _6, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSRAW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xE1, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x71, _4, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSRAD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xE2, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x72, _4, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSRLW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xD1, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x71, _2, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSRLD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xD2, _r}, {xmm64, xmm_m64}, DU_U }, + {OpcodeInfo::all, {0x66, 0x0F, 0x72, _2, ib}, {xmm64, imm8}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PMOVSXBW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x20, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSHUFB, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x00, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSHUFD, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x70, _r, ib}, {xmm64, xmm_m64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSHUFLW, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF2, 0x0F, 0x70, _r, ib}, {xmm64, xmm_m64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PSHUFHW, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0xF3, 0x0F, 0x70, _r, ib}, {xmm64, xmm_m64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHADDSW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x03, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHADDW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x01, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHADDD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x02, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHSUBSW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x07, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHSUBW, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x05, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PHSUBD, MF_NONE, DU_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x38, 0x06, _r}, {xmm64, xmm_m64}, DU_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PEXTRB, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x3A, 0x14, _r, ib}, {r32, xmm64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PEXTRW, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0xC5, _r, ib}, {r32, xmm64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(PEXTRD, MF_NONE, D_U_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x3A, 0x16, _r, ib}, {r_m32, xmm64, imm8}, D_U_U }, +END_OPCODES() +END_MNEMONIC() + +BEGIN_MNEMONIC(MOVDQA, MF_NONE|MF_SYMMETRIC, D_U) +BEGIN_OPCODES() + {OpcodeInfo::all, {0x66, 0x0F, 0x6F, _r}, {xmm64, xmm_m64}, D_U }, + //The encoder cannot properly look up when operands are symmetric but opcode is not: + //{OpcodeInfo::all, {0x66, 0x0F, 0x7F, _r}, {xmm_m128, xmm128}, D_U }, +END_OPCODES() +END_MNEMONIC() + +}; // ~masterEncodingTable[] + +ENCODER_NAMESPACE_END + +ENCODER_NAMESPACE_START + +static int compareMnemonicInfo(const void* info1, const void* info2) +{ + Mnemonic id1, id2; + + id1 = ((const MnemonicInfo*) info1)->mn; + id2 = ((const MnemonicInfo*) info2)->mn; + if (id1 < id2) + return -1; + if (id1 > id2) + return 1; + return 0; +} + +int EncoderBase::buildTable(void) +{ + // A check: all mnemonics must be covered + assert(COUNTOF(masterEncodingTable) == Mnemonic_Count); + + // sort out the mnemonics so the list become ordered + qsort(masterEncodingTable, Mnemonic_Count, sizeof(MnemonicInfo), compareMnemonicInfo); + + // + // clear the things + // + memset(opcodesHashMap, NOHASH, sizeof(opcodesHashMap)); + memset(opcodes, 0, sizeof(opcodes)); + // + // and, finally, build it + for (unsigned i=0; i<Mnemonic_Count; i++) { + assert((Mnemonic)i == (masterEncodingTable + i)->mn); + buildMnemonicDesc(masterEncodingTable+i); + } + return 0; +} + +void EncoderBase::buildMnemonicDesc(const MnemonicInfo * minfo) +{ + MnemonicDesc& mdesc = mnemonics[minfo->mn]; + mdesc.mn = minfo->mn; + mdesc.flags = minfo->flags; + mdesc.roles = minfo->roles; + mdesc.name = minfo->name; + + // + // fill the used opcodes + // + for (unsigned i=0, oindex=0; i<COUNTOF(minfo->opcodes); i++) { + + const OpcodeInfo& oinfo = minfo->opcodes[i]; + OpcodeDesc& odesc = opcodes[minfo->mn][oindex]; + // last opcode ? + if (oinfo.opcode[0] == OpcodeByteKind_LAST) { + // mark the opcode 'last', exit + odesc.opcode_len = 0; + odesc.last = 1; + break; + } + odesc.last = 0; +#ifdef _EM64T_ + if (oinfo.platf == OpcodeInfo::ia32) { continue; } + if (oinfo.platf == OpcodeInfo::decoder32) { continue; } +#else + if (oinfo.platf == OpcodeInfo::em64t) { continue; } + if (oinfo.platf == OpcodeInfo::decoder64) { continue; } +#endif + if (oinfo.platf == OpcodeInfo::decoder64 || + oinfo.platf == OpcodeInfo::decoder32) { + odesc.platf = OpcodeInfo::decoder; + } + else { + odesc.platf = (char)oinfo.platf; + } + // + // fill out opcodes + // + unsigned j = 0; + odesc.opcode_len = 0; + for(; oinfo.opcode[j]; j++) { + unsigned opcod = oinfo.opcode[j]; + unsigned kind = opcod&OpcodeByteKind_KindMask; + if (kind == OpcodeByteKind_REX_W) { + odesc.opcode[odesc.opcode_len++] = (unsigned char)0x48; + continue; + } + else if(kind != 0 && kind != OpcodeByteKind_ZeroOpcodeByte) { + break; + } + unsigned lowByte = (opcod & OpcodeByteKind_OpcodeMask); + odesc.opcode[odesc.opcode_len++] = (unsigned char)lowByte; + } + assert(odesc.opcode_len<5); + odesc.aux0 = odesc.aux1 = 0; + if (oinfo.opcode[j] != 0) { + odesc.aux0 = oinfo.opcode[j]; + assert((odesc.aux0 & OpcodeByteKind_KindMask) != 0); + ++j; + if(oinfo.opcode[j] != 0) { + odesc.aux1 = oinfo.opcode[j]; + assert((odesc.aux1 & OpcodeByteKind_KindMask) != 0); + } + } + else if (oinfo.roles.count>=2) { + if (((oinfo.opnds[0].kind&OpndKind_Mem) && + (isRegKind(oinfo.opnds[1].kind))) || + ((oinfo.opnds[1].kind&OpndKind_Mem) && + (isRegKind(oinfo.opnds[0].kind)))) { + // Example: MOVQ xmm1, xmm/m64 has only opcodes + // same with SHRD + // Adding fake /r + odesc.aux0 = _r; + } + } + else if (oinfo.roles.count==1) { + if (oinfo.opnds[0].kind&OpndKind_Mem) { + // Example: SETcc r/m8, adding fake /0 + odesc.aux0 = _0; + } + } + // check imm + if (oinfo.roles.count > 0 && + (oinfo.opnds[0].kind == OpndKind_Imm || + oinfo.opnds[oinfo.roles.count-1].kind == OpndKind_Imm)) { + // Example: CALL cd, PUSH imm32 - they fit both opnds[0] and + // opnds[oinfo.roles.count-1]. + // The A3 opcode fits only opnds[0] - it's currently have + // MOV imm32, EAX. Looks ridiculous, but this is how the + // moffset is currently implemented. Will need to fix together + // with other usages of moff. + // adding fake /cd or fake /id + unsigned imm_opnd_index = + oinfo.opnds[0].kind == OpndKind_Imm ? 0 : oinfo.roles.count-1; + OpndSize sz = oinfo.opnds[imm_opnd_index].size; + unsigned imm_encode, coff_encode; + if (sz==OpndSize_8) {imm_encode = ib; coff_encode=cb; } + else if (sz==OpndSize_16) {imm_encode = iw; coff_encode=cw;} + else if (sz==OpndSize_32) {imm_encode = id; coff_encode=cd; } + else if (sz==OpndSize_64) {imm_encode = io; coff_encode=0xCC; } + else { assert(false); imm_encode=0xCC; coff_encode=0xCC; } + if (odesc.aux1 == 0) { + if (odesc.aux0==0) { + odesc.aux0 = imm_encode; + } + else { + if (odesc.aux0 != imm_encode && odesc.aux0 != coff_encode) { + odesc.aux1 = imm_encode; + } + } + } + else { + assert(odesc.aux1==imm_encode); + } + + } + + assert(sizeof(odesc.opnds) == sizeof(oinfo.opnds)); + memcpy(odesc.opnds, oinfo.opnds, + sizeof(EncoderBase::OpndDesc) + * EncoderBase::MAX_NUM_OPCODE_OPERANDS); + odesc.roles = oinfo.roles; + odesc.first_opnd = 0; + if (odesc.opnds[0].reg != RegName_Null) { + ++odesc.first_opnd; + if (odesc.opnds[1].reg != RegName_Null) { + ++odesc.first_opnd; + } + } + + if (odesc.platf == OpcodeInfo::decoder) { + // if the opcode is only for decoding info, then do not hash it. + ++oindex; + continue; + } + + // + // check whether the operand info is a mask (i.e. r_m*). + // in this case, split the info to have separate entries for 'r' + // and for 'm'. + // the good news is that there can be only one such operand. + // + int opnd2split = -1; + for (unsigned k=0; k<oinfo.roles.count; k++) { + if ((oinfo.opnds[k].kind & OpndKind_Mem) && + (OpndKind_Mem != oinfo.opnds[k].kind)) { + opnd2split = k; + break; + } + }; + + if (opnd2split == -1) { + // not a mask, hash it, store it, continue. + unsigned short hash = getHash(&oinfo); + opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex; + ++oindex; + continue; + }; + + OpcodeInfo storeItem = oinfo; + unsigned short hash; + + // remove the memory part of the mask, and store only 'r' part + storeItem.opnds[opnd2split].kind = (OpndKind)(storeItem.opnds[opnd2split].kind & ~OpndKind_Mem); + hash = getHash(&storeItem); + if (opcodesHashMap[minfo->mn][hash] == NOHASH) { + opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex; + } + // else { + // do not overwrite if there is something there, just check that operands match + // the reason is that for some instructions there are several possibilities: + // say 'DEC r' may be encode as either '48+r' or 'FF /1', and I believe + // the first one is better for 'dec r'. + // as we're currently processing an opcode with memory part in operand, + // leave already filled items intact, so if there is 'OP reg' there, this + // better choice will be left in the table instead of 'OP r_m' + // } + + // compute hash of memory-based operand, 'm' part in 'r_m' + storeItem.opnds[opnd2split].kind = OpndKind_Mem; + hash = getHash(&storeItem); + // should not happen: for the r_m opcodes, there is a possibility + // that hash value of 'r' part intersects with 'OP r' value, but it's + // impossible for 'm' part. + assert(opcodesHashMap[minfo->mn][hash] == NOHASH); + opcodesHashMap[minfo->mn][hash] = (unsigned char)oindex; + + ++oindex; + } +} + +ENCODER_NAMESPACE_END |