/*
 *  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
 */
#ifndef _ENCODER_DEFS_H_
#define _ENCODER_DEFS_H_


// Used to isolate experimental or being tuned encoder into a separate
// namespace so it can coexist with a stable one in the same bundle.
#ifdef ENCODER_ISOLATE
    #define ENCODER_NAMESPACE_START namespace enc_ia32 {
    #define ENCODER_NAMESPACE_END };
#else
    #define ENCODER_NAMESPACE_START
    #define ENCODER_NAMESPACE_END
#endif

#include <assert.h>
#include "enc_defs_ext.h"

#ifndef COUNTOF
    /**
     * Number of items in an array.
     */
    #define COUNTOF(a)      (sizeof(a)/sizeof(a[0]))
#endif

#ifdef _EM64T_
    /**
     * A stack pointer of default platform's size.
     */
    #define REG_STACK       RegName_RSP
    /**
     * A max GP register (with a highest index number)
     */
    #define REG_MAX         RegName_R15
    /**
     * Total number of GP registers including stack pointer.
     */
    #define MAX_REGS        15
#else
    #define REG_STACK       RegName_ESP
    #define REG_MAX         RegName_EDI
    #define MAX_REGS        8
#endif

ENCODER_NAMESPACE_START

/**
 * A number of bytes 'eaten' by an ordinary PUSH/POP.
 */
#define STACK_SLOT_SIZE (sizeof(void*))


/**
 * A recommended by Intel Arch Manual aligment for instructions that
 * are targets for jmps.
 */
#define JMP_TARGET_ALIGMENT     (16)
/**
 * A maximum possible size of native instruction.
 */
#define MAX_NATIVE_INST_SIZE (15)
/**
 * The enum OpndKind describes an operand's location - memory, immediate or a register.
 * It can be used as a bit mask.
 */
typedef enum OpndKind {
    /**
     * A change must be balanced with at least the following places:
     *              Ia32::Constraint-s use the OpndKind as a mask
     *              encoder.cpp & encoder_master_info.cpp uses OpndKind as an index for hashing
     *              - perhaps there are much more places
     *
     * NOTE: an MMXReg kind is incompatible with the current constraints framework,
     *              as it's not encoded as a mask.
     */
    OpndKind_Null=0,
    OpndKind_GPReg          = 0x01, OpndKind_MinRegKind = OpndKind_GPReg,
    OpndKind_SReg           = 0x02,
#ifdef _HAVE_MMX_
    OpndKind_MMXReg         = 0x03,
#endif
    OpndKind_FPReg          = 0x04,
    OpndKind_XMMReg         = 0x08,
    OpndKind_OtherReg       = 0x10,
    OpndKind_StatusReg      = OpndKind_OtherReg,
    OpndKind_MaxRegKind     = OpndKind_StatusReg,   // a max existing kind of register
    OpndKind_MaxReg,                                // -'- + 1 to be used in array defs
    //
    OpndKind_Immediate      = 0x20, OpndKind_Imm=OpndKind_Immediate,
    OpndKind_Memory         = 0x40, OpndKind_Mem=OpndKind_Memory,
    //
    OpndKind_Reg            = 0x1F,
    OpndKind_Any            = 0x7F,
    // syntetic constants. Normally not used anywhere, but are used for
    // human-readable showing under the debugger
    OpndKind_GPReg_Mem      = OpndKind_GPReg|OpndKind_Mem,
#ifdef _HAVE_MMX_
    OpndKind_MMXReg_Mem     = OpndKind_MMXReg|OpndKind_Mem,
#endif
    OpndKind_XMMReg_Mem     = OpndKind_XMMReg|OpndKind_Mem,
} OpndKind;

/**
 * Defines type of extention allowed for particular operand.
 * For example imul r32,r_m32,imm8 sign extend imm8 before performing multiplication.
 * To satisfy instruction constraints immediate operand should be either OpndExt_Signed
 * or OpndExt_Any.
 */
typedef enum OpndExt {
    OpndExt_None    = 0x0,
    OpndExt_Signed  = 0x1,
    OpndExt_Zero    = 0x2,
    OpndExt_Any     = 0x3,
}OpndExt;

/**
 * enum OpndRole defines the role of an operand in an instruction
 * Can be used as mask to combine def and use. The complete def+use
 * info can be combined in 2 bits which is used, say in Encoder::OpndRole.
 */
//TODO: this duplicates an Role used in the Ia32::Inst. That duplicate enum should be removed.
typedef enum OpndRole {
    OpndRole_Null=0,
    OpndRole_Use=0x1,
    OpndRole_Def=0x2,
    OpndRole_UseDef=OpndRole_Use|OpndRole_Def,
    OpndRole_All=0xffff,
} OpndRole;


#define REGNAME(k,s,i) ( ((k & OpndKind_Any)<<24) | ((s & OpndSize_Any)<<16) | (i&0xFF) )

// Gregory -
// It is critical that all register indexes (3rd number) inside of the
// following table go in ascending order. That is R8 goes after
// RDI. It is necessary for decoder when extending registers from RAX-RDI
// to R8-R15 by simply adding 8 to the index on EM64T architecture
typedef enum RegName {

    RegName_Null = 0,

#ifdef _EM64T_
    /*
    An index part of the RegName-s for RAX-RDI, EAX-ESI, AX-SI and AL-BH is
    the same as the index used during instructions encoding. The same rule
    applies for XMM regsters for IA32.
    For new EM64T registers (both GP and XMM) the index need to be corrected to
    obtain the index used in processor's instructions.
    */
    RegName_RAX = REGNAME(OpndKind_GPReg,OpndSize_64,0),
    RegName_RCX = REGNAME(OpndKind_GPReg,OpndSize_64,1),
    RegName_RDX = REGNAME(OpndKind_GPReg,OpndSize_64,2),
    RegName_RBX = REGNAME(OpndKind_GPReg,OpndSize_64,3),
    RegName_RSP = REGNAME(OpndKind_GPReg,OpndSize_64,4),
    RegName_RBP = REGNAME(OpndKind_GPReg,OpndSize_64,5),
    RegName_RSI = REGNAME(OpndKind_GPReg,OpndSize_64,6),
    RegName_RDI = REGNAME(OpndKind_GPReg,OpndSize_64,7),

    RegName_R8  = REGNAME(OpndKind_GPReg,OpndSize_64,8),
    RegName_R9  = REGNAME(OpndKind_GPReg,OpndSize_64,9),
    RegName_R10 = REGNAME(OpndKind_GPReg,OpndSize_64,10),
    RegName_R11 = REGNAME(OpndKind_GPReg,OpndSize_64,11),
    RegName_R12 = REGNAME(OpndKind_GPReg,OpndSize_64,12),
    RegName_R13 = REGNAME(OpndKind_GPReg,OpndSize_64,13),
    RegName_R14 = REGNAME(OpndKind_GPReg,OpndSize_64,14),
    RegName_R15 = REGNAME(OpndKind_GPReg,OpndSize_64,15),
#endif //~_EM64T_

    RegName_EAX=REGNAME(OpndKind_GPReg,OpndSize_32,0),
    RegName_ECX=REGNAME(OpndKind_GPReg,OpndSize_32,1),
    RegName_EDX=REGNAME(OpndKind_GPReg,OpndSize_32,2),
    RegName_EBX=REGNAME(OpndKind_GPReg,OpndSize_32,3),
    RegName_ESP=REGNAME(OpndKind_GPReg,OpndSize_32,4),
    RegName_EBP=REGNAME(OpndKind_GPReg,OpndSize_32,5),
    RegName_ESI=REGNAME(OpndKind_GPReg,OpndSize_32,6),
    RegName_EDI=REGNAME(OpndKind_GPReg,OpndSize_32,7),

#ifdef _EM64T_
    RegName_R8D  = REGNAME(OpndKind_GPReg,OpndSize_32,8),
    RegName_R9D  = REGNAME(OpndKind_GPReg,OpndSize_32,9),
    RegName_R10D = REGNAME(OpndKind_GPReg,OpndSize_32,10),
    RegName_R11D = REGNAME(OpndKind_GPReg,OpndSize_32,11),
    RegName_R12D = REGNAME(OpndKind_GPReg,OpndSize_32,12),
    RegName_R13D = REGNAME(OpndKind_GPReg,OpndSize_32,13),
    RegName_R14D = REGNAME(OpndKind_GPReg,OpndSize_32,14),
    RegName_R15D = REGNAME(OpndKind_GPReg,OpndSize_32,15),
#endif //~_EM64T_

    RegName_AX=REGNAME(OpndKind_GPReg,OpndSize_16,0),
    RegName_CX=REGNAME(OpndKind_GPReg,OpndSize_16,1),
    RegName_DX=REGNAME(OpndKind_GPReg,OpndSize_16,2),
    RegName_BX=REGNAME(OpndKind_GPReg,OpndSize_16,3),
    RegName_SP=REGNAME(OpndKind_GPReg,OpndSize_16,4),
    RegName_BP=REGNAME(OpndKind_GPReg,OpndSize_16,5),
    RegName_SI=REGNAME(OpndKind_GPReg,OpndSize_16,6),
    RegName_DI=REGNAME(OpndKind_GPReg,OpndSize_16,7),

#ifdef _EM64T_
    RegName_R8S  = REGNAME(OpndKind_GPReg,OpndSize_16,8),
    RegName_R9S  = REGNAME(OpndKind_GPReg,OpndSize_16,9),
    RegName_R10S = REGNAME(OpndKind_GPReg,OpndSize_16,10),
    RegName_R11S = REGNAME(OpndKind_GPReg,OpndSize_16,11),
    RegName_R12S = REGNAME(OpndKind_GPReg,OpndSize_16,12),
    RegName_R13S = REGNAME(OpndKind_GPReg,OpndSize_16,13),
    RegName_R14S = REGNAME(OpndKind_GPReg,OpndSize_16,14),
    RegName_R15S = REGNAME(OpndKind_GPReg,OpndSize_16,15),
#endif //~_EM64T_

    RegName_AL=REGNAME(OpndKind_GPReg,OpndSize_8,0),
    RegName_CL=REGNAME(OpndKind_GPReg,OpndSize_8,1),
    RegName_DL=REGNAME(OpndKind_GPReg,OpndSize_8,2),
    RegName_BL=REGNAME(OpndKind_GPReg,OpndSize_8,3),
    // FIXME: Used in enc_tabl.cpp
    // AH is not accessible on EM64T, instead encoded register is SPL, so decoded
    // register will return incorrect enum
    RegName_AH=REGNAME(OpndKind_GPReg,OpndSize_8,4),
#if !defined(_EM64T_)
    RegName_CH=REGNAME(OpndKind_GPReg,OpndSize_8,5),
    RegName_DH=REGNAME(OpndKind_GPReg,OpndSize_8,6),
    RegName_BH=REGNAME(OpndKind_GPReg,OpndSize_8,7),
#else
    RegName_SPL=REGNAME(OpndKind_GPReg,OpndSize_8,4),
    RegName_BPL=REGNAME(OpndKind_GPReg,OpndSize_8,5),
    RegName_SIL=REGNAME(OpndKind_GPReg,OpndSize_8,6),
    RegName_DIL=REGNAME(OpndKind_GPReg,OpndSize_8,7),
    RegName_R8L=REGNAME(OpndKind_GPReg,OpndSize_8,8),
    RegName_R9L=REGNAME(OpndKind_GPReg,OpndSize_8,9),
    RegName_R10L=REGNAME(OpndKind_GPReg,OpndSize_8,10),
    RegName_R11L=REGNAME(OpndKind_GPReg,OpndSize_8,11),
    RegName_R12L=REGNAME(OpndKind_GPReg,OpndSize_8,12),
    RegName_R13L=REGNAME(OpndKind_GPReg,OpndSize_8,13),
    RegName_R14L=REGNAME(OpndKind_GPReg,OpndSize_8,14),
    RegName_R15L=REGNAME(OpndKind_GPReg,OpndSize_8,15),
#endif

    RegName_ES=REGNAME(OpndKind_SReg,OpndSize_16,0),
    RegName_CS=REGNAME(OpndKind_SReg,OpndSize_16,1),
    RegName_SS=REGNAME(OpndKind_SReg,OpndSize_16,2),
    RegName_DS=REGNAME(OpndKind_SReg,OpndSize_16,3),
    RegName_FS=REGNAME(OpndKind_SReg,OpndSize_16,4),
    RegName_GS=REGNAME(OpndKind_SReg,OpndSize_16,5),

    RegName_EFLAGS=REGNAME(OpndKind_StatusReg,OpndSize_32,0),

#if !defined(TESTING_ENCODER)
    RegName_FP0=REGNAME(OpndKind_FPReg,OpndSize_80,0),
    RegName_FP1=REGNAME(OpndKind_FPReg,OpndSize_80,1),
    RegName_FP2=REGNAME(OpndKind_FPReg,OpndSize_80,2),
    RegName_FP3=REGNAME(OpndKind_FPReg,OpndSize_80,3),
    RegName_FP4=REGNAME(OpndKind_FPReg,OpndSize_80,4),
    RegName_FP5=REGNAME(OpndKind_FPReg,OpndSize_80,5),
    RegName_FP6=REGNAME(OpndKind_FPReg,OpndSize_80,6),
    RegName_FP7=REGNAME(OpndKind_FPReg,OpndSize_80,7),
#endif
    RegName_FP0S=REGNAME(OpndKind_FPReg,OpndSize_32,0),
    RegName_FP1S=REGNAME(OpndKind_FPReg,OpndSize_32,1),
    RegName_FP2S=REGNAME(OpndKind_FPReg,OpndSize_32,2),
    RegName_FP3S=REGNAME(OpndKind_FPReg,OpndSize_32,3),
    RegName_FP4S=REGNAME(OpndKind_FPReg,OpndSize_32,4),
    RegName_FP5S=REGNAME(OpndKind_FPReg,OpndSize_32,5),
    RegName_FP6S=REGNAME(OpndKind_FPReg,OpndSize_32,6),
    RegName_FP7S=REGNAME(OpndKind_FPReg,OpndSize_32,7),

    RegName_FP0D=REGNAME(OpndKind_FPReg,OpndSize_64,0),
    RegName_FP1D=REGNAME(OpndKind_FPReg,OpndSize_64,1),
    RegName_FP2D=REGNAME(OpndKind_FPReg,OpndSize_64,2),
    RegName_FP3D=REGNAME(OpndKind_FPReg,OpndSize_64,3),
    RegName_FP4D=REGNAME(OpndKind_FPReg,OpndSize_64,4),
    RegName_FP5D=REGNAME(OpndKind_FPReg,OpndSize_64,5),
    RegName_FP6D=REGNAME(OpndKind_FPReg,OpndSize_64,6),
    RegName_FP7D=REGNAME(OpndKind_FPReg,OpndSize_64,7),

#if !defined(TESTING_ENCODER)
    RegName_XMM0=REGNAME(OpndKind_XMMReg,OpndSize_128,0),
    RegName_XMM1=REGNAME(OpndKind_XMMReg,OpndSize_128,1),
    RegName_XMM2=REGNAME(OpndKind_XMMReg,OpndSize_128,2),
    RegName_XMM3=REGNAME(OpndKind_XMMReg,OpndSize_128,3),
    RegName_XMM4=REGNAME(OpndKind_XMMReg,OpndSize_128,4),
    RegName_XMM5=REGNAME(OpndKind_XMMReg,OpndSize_128,5),
    RegName_XMM6=REGNAME(OpndKind_XMMReg,OpndSize_128,6),
    RegName_XMM7=REGNAME(OpndKind_XMMReg,OpndSize_128,7),

#ifdef _EM64T_
    RegName_XMM8  = REGNAME(OpndKind_XMMReg,OpndSize_128,0),
    RegName_XMM9  = REGNAME(OpndKind_XMMReg,OpndSize_128,1),
    RegName_XMM10 = REGNAME(OpndKind_XMMReg,OpndSize_128,2),
    RegName_XMM11 = REGNAME(OpndKind_XMMReg,OpndSize_128,3),
    RegName_XMM12 = REGNAME(OpndKind_XMMReg,OpndSize_128,4),
    RegName_XMM13 = REGNAME(OpndKind_XMMReg,OpndSize_128,5),
    RegName_XMM14 = REGNAME(OpndKind_XMMReg,OpndSize_128,6),
    RegName_XMM15 = REGNAME(OpndKind_XMMReg,OpndSize_128,7),
#endif //~_EM64T_

#endif  // ~TESTING_ENCODER

    RegName_XMM0S=REGNAME(OpndKind_XMMReg,OpndSize_32,0),
    RegName_XMM1S=REGNAME(OpndKind_XMMReg,OpndSize_32,1),
    RegName_XMM2S=REGNAME(OpndKind_XMMReg,OpndSize_32,2),
    RegName_XMM3S=REGNAME(OpndKind_XMMReg,OpndSize_32,3),
    RegName_XMM4S=REGNAME(OpndKind_XMMReg,OpndSize_32,4),
    RegName_XMM5S=REGNAME(OpndKind_XMMReg,OpndSize_32,5),
    RegName_XMM6S=REGNAME(OpndKind_XMMReg,OpndSize_32,6),
    RegName_XMM7S=REGNAME(OpndKind_XMMReg,OpndSize_32,7),
#ifdef _EM64T_
    RegName_XMM8S=REGNAME(OpndKind_XMMReg,OpndSize_32,8),
    RegName_XMM9S=REGNAME(OpndKind_XMMReg,OpndSize_32,9),
    RegName_XMM10S=REGNAME(OpndKind_XMMReg,OpndSize_32,10),
    RegName_XMM11S=REGNAME(OpndKind_XMMReg,OpndSize_32,11),
    RegName_XMM12S=REGNAME(OpndKind_XMMReg,OpndSize_32,12),
    RegName_XMM13S=REGNAME(OpndKind_XMMReg,OpndSize_32,13),
    RegName_XMM14S=REGNAME(OpndKind_XMMReg,OpndSize_32,14),
    RegName_XMM15S=REGNAME(OpndKind_XMMReg,OpndSize_32,15),
#endif // ifdef _EM64T_
    RegName_XMM0D=REGNAME(OpndKind_XMMReg,OpndSize_64,0),
    RegName_XMM1D=REGNAME(OpndKind_XMMReg,OpndSize_64,1),
    RegName_XMM2D=REGNAME(OpndKind_XMMReg,OpndSize_64,2),
    RegName_XMM3D=REGNAME(OpndKind_XMMReg,OpndSize_64,3),
    RegName_XMM4D=REGNAME(OpndKind_XMMReg,OpndSize_64,4),
    RegName_XMM5D=REGNAME(OpndKind_XMMReg,OpndSize_64,5),
    RegName_XMM6D=REGNAME(OpndKind_XMMReg,OpndSize_64,6),
    RegName_XMM7D=REGNAME(OpndKind_XMMReg,OpndSize_64,7),
#ifdef _EM64T_
    RegName_XMM8D=REGNAME(OpndKind_XMMReg,OpndSize_64,8),
    RegName_XMM9D=REGNAME(OpndKind_XMMReg,OpndSize_64,9),
    RegName_XMM10D=REGNAME(OpndKind_XMMReg,OpndSize_64,10),
    RegName_XMM11D=REGNAME(OpndKind_XMMReg,OpndSize_64,11),
    RegName_XMM12D=REGNAME(OpndKind_XMMReg,OpndSize_64,12),
    RegName_XMM13D=REGNAME(OpndKind_XMMReg,OpndSize_64,13),
    RegName_XMM14D=REGNAME(OpndKind_XMMReg,OpndSize_64,14),
    RegName_XMM15D=REGNAME(OpndKind_XMMReg,OpndSize_64,15),
#endif // ifdef _EM64T_
#ifdef _HAVE_MMX_
    RegName_MMX0=REGNAME(OpndKind_MMXReg,OpndSize_64,0),
    RegName_MMX1=REGNAME(OpndKind_MMXReg,OpndSize_64,1),
    RegName_MMX2=REGNAME(OpndKind_MMXReg,OpndSize_64,2),
    RegName_MMX3=REGNAME(OpndKind_MMXReg,OpndSize_64,3),
    RegName_MMX4=REGNAME(OpndKind_MMXReg,OpndSize_64,4),
    RegName_MMX5=REGNAME(OpndKind_MMXReg,OpndSize_64,5),
    RegName_MMX6=REGNAME(OpndKind_MMXReg,OpndSize_64,6),
    RegName_MMX7=REGNAME(OpndKind_MMXReg,OpndSize_64,7),
#endif  // _HAVE_MMX_
} RegName;

#if 0   // Android x86: use mnemonics defined in enc_defs_ext.h
/**
 * Conditional mnemonics.
 * The values match the 'real' (==processor's) values of the appropriate
 * condition values used in the opcodes.
 */
enum ConditionMnemonic {

    ConditionMnemonic_O=0,
    ConditionMnemonic_NO=1,
    ConditionMnemonic_B=2, ConditionMnemonic_NAE=ConditionMnemonic_B, ConditionMnemonic_C=ConditionMnemonic_B,
    ConditionMnemonic_NB=3, ConditionMnemonic_AE=ConditionMnemonic_NB, ConditionMnemonic_NC=ConditionMnemonic_NB,
    ConditionMnemonic_Z=4, ConditionMnemonic_E=ConditionMnemonic_Z,
    ConditionMnemonic_NZ=5, ConditionMnemonic_NE=ConditionMnemonic_NZ,
    ConditionMnemonic_BE=6, ConditionMnemonic_NA=ConditionMnemonic_BE,
    ConditionMnemonic_NBE=7, ConditionMnemonic_A=ConditionMnemonic_NBE,

    ConditionMnemonic_S=8,
    ConditionMnemonic_NS=9,
    ConditionMnemonic_P=10, ConditionMnemonic_PE=ConditionMnemonic_P,
    ConditionMnemonic_NP=11, ConditionMnemonic_PO=ConditionMnemonic_NP,
    ConditionMnemonic_L=12, ConditionMnemonic_NGE=ConditionMnemonic_L,
    ConditionMnemonic_NL=13, ConditionMnemonic_GE=ConditionMnemonic_NL,
    ConditionMnemonic_LE=14, ConditionMnemonic_NG=ConditionMnemonic_LE,
    ConditionMnemonic_NLE=15, ConditionMnemonic_G=ConditionMnemonic_NLE,
    ConditionMnemonic_Count=16
};


#define CCM(prefix,cond) Mnemonic_##prefix##cond=Mnemonic_##prefix##cc+ConditionMnemonic_##cond

//=========================================================================================================
enum Mnemonic {

Mnemonic_NULL=0, Mnemonic_Null=Mnemonic_NULL,
Mnemonic_ADC,                           // Add with Carry
Mnemonic_ADD,                           // Add
Mnemonic_ADDSD,                         // Add Scalar Double-Precision Floating-Point Values
Mnemonic_ADDSS,                         // Add Scalar Single-Precision Floating-Point Values
Mnemonic_AND,                           // Logical AND

Mnemonic_BSF,                           // Bit scan forward
Mnemonic_BSR,                           // Bit scan reverse

Mnemonic_CALL,                          // Call Procedure
Mnemonic_CMC,                           // Complement Carry Flag
Mnemonic_CWD, Mnemonic_CDQ=Mnemonic_CWD,// Convert Word to Doubleword/Convert Doubleword to Qua T dword
Mnemonic_CMOVcc,                        // Conditional Move
    CCM(CMOV,O),
    CCM(CMOV,NO),
    CCM(CMOV,B), CCM(CMOV,NAE), CCM(CMOV,C),
    CCM(CMOV,NB), CCM(CMOV,AE), CCM(CMOV,NC),
    CCM(CMOV,Z), CCM(CMOV,E),
    CCM(CMOV,NZ), CCM(CMOV,NE),
    CCM(CMOV,BE), CCM(CMOV,NA),
    CCM(CMOV,NBE), CCM(CMOV,A),

    CCM(CMOV,S),
    CCM(CMOV,NS),
    CCM(CMOV,P), CCM(CMOV,PE),
    CCM(CMOV,NP), CCM(CMOV,PO),
    CCM(CMOV,L), CCM(CMOV,NGE),
    CCM(CMOV,NL), CCM(CMOV,GE),
    CCM(CMOV,LE), CCM(CMOV,NG),
    CCM(CMOV,NLE), CCM(CMOV,G),

Mnemonic_CMP,                           // Compare Two Operands
Mnemonic_CMPXCHG,                       // Compare and exchange
Mnemonic_CMPXCHG8B,                     // Compare and Exchange 8 Bytes
Mnemonic_CMPSB,                         // Compare Two Bytes at DS:ESI and ES:EDI
Mnemonic_CMPSW,                         // Compare Two Words at DS:ESI and ES:EDI
Mnemonic_CMPSD,                        // Compare Two Doublewords at DS:ESI and ES:EDI
//
// double -> float
Mnemonic_CVTSD2SS,                      // Convert Scalar Double-Precision Floating-Point Value to Scalar Single-Precision Floating-Point Value
// double -> I_32
Mnemonic_CVTSD2SI,                      // Convert Scalar Double-Precision Floating-Point Value to Doubleword Integer
// double [truncated] -> I_32
Mnemonic_CVTTSD2SI,                     // Convert with Truncation Scalar Double-Precision Floating-Point Value to Signed Doubleword Integer
//
// float -> double
Mnemonic_CVTSS2SD,                      // Convert Scalar Single-Precision Floating-Point Value to Scalar Double-Precision Floating-Point Value
// float -> I_32
Mnemonic_CVTSS2SI,                      // Convert Scalar Single-Precision Floating-Point Value to Doubleword Integer
// float [truncated] -> I_32
Mnemonic_CVTTSS2SI,                     // Convert with Truncation Scalar Single-Precision Floating-Point Value to Doubleword Integer
//
// I_32 -> double
Mnemonic_CVTSI2SD,                      // Convert Doubleword Integer to Scalar Double-Precision Floating-Point Value
// I_32 -> float
Mnemonic_CVTSI2SS,                      // Convert Doubleword Integer to Scalar Single-Precision Floating-Point Value

Mnemonic_COMISD,                        // Compare Scalar Ordered Double-Precision Floating-Point Values and Set EFLAGS
Mnemonic_COMISS,                        // Compare Scalar Ordered Single-Precision Floating-Point Values and Set EFLAGS
Mnemonic_DEC,                           // Decrement by 1
//Mnemonic_DIV,                         // Unsigned Divide
Mnemonic_DIVSD,                         // Divide Scalar Double-Precision Floating-Point Values
Mnemonic_DIVSS,                         // Divide Scalar Single-Precision Floating-Point Values

#ifdef _HAVE_MMX_
Mnemonic_EMMS,                          // Empty MMX Technology State
#endif

Mnemonic_ENTER,                         // ENTER-Make Stack Frame for Procedure Parameters
Mnemonic_FLDCW,                         // Load FPU control word
Mnemonic_FADDP,
Mnemonic_FLDZ,
Mnemonic_FADD,
Mnemonic_FSUBP,
Mnemonic_FSUB,
Mnemonic_FISUB,
Mnemonic_FMUL,
Mnemonic_FMULP,
Mnemonic_FDIVP,
Mnemonic_FDIV,
Mnemonic_FUCOMPP,
Mnemonic_FRNDINT,
Mnemonic_FNSTCW,                        // Store FPU control word
Mnemonic_FSTSW,                         // Store FPU status word
Mnemonic_FNSTSW,                         // Store FPU status word
//Mnemonic_FDECSTP,                     // Decrement Stack-Top Pointer
Mnemonic_FILD,                          // Load Integer
Mnemonic_FLD,                           // Load Floating Point Value
Mnemonic_FLDLG2,
Mnemonic_FLDLN2,
Mnemonic_FLD1,

Mnemonic_FCLEX,                         // Clear Exceptions
Mnemonic_FCHS,                          // Change sign of ST0
Mnemonic_FNCLEX,                        // Clear Exceptions

//Mnemonic_FINCSTP,                     // Increment Stack-Top Pointer
Mnemonic_FIST,                          // Store Integer
Mnemonic_FISTP,                         // Store Integer, pop FPU stack
Mnemonic_FISTTP,                        // Store Integer with Truncation
Mnemonic_FPREM,                         // Partial Remainder
Mnemonic_FPREM1,                        // Partial Remainder
Mnemonic_FST,                           // Store Floating Point Value
Mnemonic_FSTP,                          // Store Floating Point Value and pop the FP stack
Mnemonic_FSQRT,                         //Computes the square root of the source value in the stack and pop the FP stack
Mnemonic_FABS,                          //Computes the absolute value of the source value in the stack and pop the FP stack
Mnemonic_FSIN,                          //Computes the sine of the source value in the stack and pop the FP stack
Mnemonic_FCOS,                          //Computes the cosine of the source value in the stack and pop the FP stack
Mnemonic_FPTAN,                         //Computes the tangent of the source value in the stack and pop the FP stack
Mnemonic_FYL2X,
Mnemonic_FYL2XP1,
Mnemonic_F2XM1,
Mnemonic_FPATAN,
Mnemonic_FXCH,
Mnemonic_FSCALE,

Mnemonic_XCHG,
Mnemonic_DIV,                           // Unsigned Divide
Mnemonic_IDIV,                          // Signed Divide
Mnemonic_MUL,                           // Unsigned Multiply
Mnemonic_IMUL,                          // Signed Multiply
Mnemonic_INC,                           // Increment by 1
Mnemonic_INT3,                          // Call break point
Mnemonic_Jcc,                           // Jump if Condition Is Met
    CCM(J,O),
    CCM(J,NO),
    CCM(J,B), CCM(J,NAE), CCM(J,C),
    CCM(J,NB), CCM(J,AE), CCM(J,NC),
    CCM(J,Z), CCM(J,E),
    CCM(J,NZ), CCM(J,NE),
    CCM(J,BE), CCM(J,NA),
    CCM(J,NBE), CCM(J,A),
    CCM(J,S),
    CCM(J,NS),
    CCM(J,P), CCM(J,PE),
    CCM(J,NP), CCM(J,PO),
    CCM(J,L), CCM(J,NGE),
    CCM(J,NL), CCM(J,GE),
    CCM(J,LE), CCM(J,NG),
    CCM(J,NLE), CCM(J,G),
Mnemonic_JMP,                           // Jump
Mnemonic_LEA,                           // Load Effective Address
Mnemonic_LEAVE,                         // High Level Procedure Exit
Mnemonic_LOOP,                          // Loop according to ECX counter
Mnemonic_LOOPE,                          // Loop according to ECX counter
Mnemonic_LOOPNE, Mnemonic_LOOPNZ = Mnemonic_LOOPNE, // Loop according to ECX
Mnemonic_LAHF,                          // Load Flags into AH
Mnemonic_MOV,                           // Move
Mnemonic_MOVD,                          // Move Double word
Mnemonic_MOVQ,                          // Move Quadword
/*Mnemonic_MOVS,                        // Move Data from String to String*/
// MOVS is a special case: see encoding table for more details,
Mnemonic_MOVS8, Mnemonic_MOVS16, Mnemonic_MOVS32, Mnemonic_MOVS64,
//
Mnemonic_MOVAPD,                         // Move Scalar Double-Precision Floating-Point Value
Mnemonic_MOVSD,                         // Move Scalar Double-Precision Floating-Point Value
Mnemonic_MOVSS,                         // Move Scalar Single-Precision Floating-Point Values
Mnemonic_MOVSX,                         // Move with Sign-Extension
Mnemonic_MOVZX,                         // Move with Zero-Extend
//Mnemonic_MUL,                         // Unsigned Multiply
Mnemonic_MULSD,                         // Multiply Scalar Double-Precision Floating-Point Values
Mnemonic_MULSS,                         // Multiply Scalar Single-Precision Floating-Point Values
Mnemonic_NEG,                           // Two's Complement Negation
Mnemonic_NOP,                           // No Operation
Mnemonic_NOT,                           // One's Complement Negation
Mnemonic_OR,                            // Logical Inclusive OR
Mnemonic_PREFETCH,                      // prefetch

#ifdef _HAVE_MMX_
    Mnemonic_PADDQ,                     // Add Packed Quadword Integers
    Mnemonic_PAND,                      // Logical AND
    Mnemonic_POR,                       // Bitwise Logical OR
    Mnemonic_PSUBQ,                     // Subtract Packed Quadword Integers
#endif

Mnemonic_PXOR,                          // Logical Exclusive OR
Mnemonic_POP,                           // Pop a Value from the Stack
Mnemonic_POPFD,                         // Pop a Value of EFLAGS register from the Stack
Mnemonic_PUSH,                          // Push Word or Doubleword Onto the Stack
Mnemonic_PUSHFD,                        // Push EFLAGS Doubleword Onto the Stack
Mnemonic_RET,                           // Return from Procedure

Mnemonic_SETcc,                         // Set Byte on Condition
    CCM(SET,O),
    CCM(SET,NO),
    CCM(SET,B), CCM(SET,NAE), CCM(SET,C),
    CCM(SET,NB), CCM(SET,AE), CCM(SET,NC),
    CCM(SET,Z), CCM(SET,E),
    CCM(SET,NZ), CCM(SET,NE),
    CCM(SET,BE), CCM(SET,NA),
    CCM(SET,NBE), CCM(SET,A),
    CCM(SET,S),
    CCM(SET,NS),
    CCM(SET,P), CCM(SET,PE),
    CCM(SET,NP), CCM(SET,PO),
    CCM(SET,L), CCM(SET,NGE),
    CCM(SET,NL), CCM(SET,GE),
    CCM(SET,LE), CCM(SET,NG),
    CCM(SET,NLE), CCM(SET,G),

Mnemonic_SAL, Mnemonic_SHL=Mnemonic_SAL,// Shift left
Mnemonic_SAR,                           // Shift right
Mnemonic_ROR,                           // Rotate right
Mnemonic_RCR,                           // Rotate right through CARRY flag
Mnemonic_ROL,                           // Rotate left
Mnemonic_RCL,                           // Rotate left through CARRY flag
Mnemonic_SHR,                           // Unsigned shift right
Mnemonic_SHRD,                          // Double Precision Shift Right
Mnemonic_SHLD,                          // Double Precision Shift Left

Mnemonic_SBB,                           // Integer Subtraction with Borrow
Mnemonic_SUB,                           // Subtract
Mnemonic_SUBSD,                         // Subtract Scalar Double-Precision Floating-Point Values
Mnemonic_SUBSS,                         // Subtract Scalar Single-Precision Floating-Point Values

Mnemonic_TEST,                          // Logical Compare

Mnemonic_UCOMISD,                       // Unordered Compare Scalar Double-Precision Floating-Point Values and Set EFLAGS
Mnemonic_UCOMISS,                       // Unordered Compare Scalar Single-Precision Floating-Point Values and Set EFLAGS

Mnemonic_XOR,                           // Logical Exclusive OR
//
// packed things,
//
Mnemonic_XORPD,                         // Bitwise Logical XOR for Double-Precision Floating-Point Values
Mnemonic_XORPS,                         // Bitwise Logical XOR for Single-Precision Floating-Point Values

Mnemonic_CVTDQ2PD,                      // Convert Packed Doubleword Integers to Packed Double-Precision Floating-Point Values
Mnemonic_CVTTPD2DQ,                     // Convert with Truncation Packed Double-Precision Floating-Point Values to Packed Doubleword Integers

Mnemonic_CVTDQ2PS,                      // Convert Packed Doubleword Integers to Packed Single-Precision Floating-Point Values
Mnemonic_CVTTPS2DQ,                     // Convert with Truncation Packed Single-Precision Floating-Point Values to Packed Doubleword Integers
//
// String operations
//
Mnemonic_STD,                           // Set direction flag
Mnemonic_CLD,                           // Clear direction flag
Mnemonic_SCAS,                          // Scan string
Mnemonic_STOS,                          // Store string

//
Mnemonic_WAIT,                          // Check pending pending unmasked floating-point exception
//
Mnemonic_Count
};

#undef CCM
#endif

/**
 * @brief Instruction prefixes, according to arch manual.
 */
typedef enum InstPrefix {
    InstPrefix_Null = 0,
    // Group 1
    InstPrefix_LOCK = 0xF0,
    InstPrefix_REPNE = 0xF2,
    InstPrefix_REPNZ = InstPrefix_REPNE,
    InstPrefix_REP = 0xF3, InstPrefix_REPZ = InstPrefix_REP,
    // Group 2
    InstPrefix_CS = 0x2E,
    InstPrefix_SS = 0x36,
    InstPrefix_DS = 0x3E,
    InstPrefix_ES = 0x26,
    InstPrefix_FS = 0x64,
    InstPrefix_GS = 0x65,
    //
    InstPrefix_HintTaken = 0x3E,
    InstPrefix_HintNotTaken = 0x2E,
    // Group 3
    InstPrefix_OpndSize = 0x66,
    // Group 4
    InstPrefix_AddrSize = 0x67
} InstPrefix;

inline unsigned getSizeBytes(OpndSize sz)
{
    if (sz==OpndSize_64) { return 8; }
    if (sz==OpndSize_32) { return 4; }
    if (sz==OpndSize_16) { return 2; }
    if (sz==OpndSize_8)  { return 1; }
    assert(false);
    return 0;
}

inline bool isRegKind(OpndKind kind)
{
    return OpndKind_GPReg<= kind && kind<=OpndKind_MaxRegKind;
}

/**
 * @brief Returns RegName for a given name.
 *
 * Name is case-insensitive.
 * @param regname - string name of a register
 * @return RegName for the given name, or RegName_Null if name is invalid
 */
RegName         getRegName(const char * regname);
/**
 * Constructs RegName from the given OpndKind, size and index.
 */
inline RegName  getRegName(OpndKind k, OpndSize s, int idx)
{
    return (RegName)REGNAME(k,s,idx);
}
/**
 * Extracts a bit mask with a bit set at the position of the register's index.
 */
inline unsigned getRegMask(RegName reg)
{
    return 1<<(reg&0xff);
}
/**
 * @brief Extracts OpndKind from the RegName.
 */
inline OpndKind getRegKind(RegName reg)
{
    return (OpndKind)(reg>>24);
}
/**
 * @brief Extracts OpndSize from RegName.
 */
inline OpndSize getRegSize(RegName reg)
{
    return (OpndSize)((reg>>16)&0xFF);
}
/**
 * Extracts an index from the given RegName.
 */
inline unsigned char getRegIndex(RegName reg)
{
    return (unsigned char)(reg&0xFF);
}
/**
 * Returns a string name of the given RegName. The name returned is in upper-case.
 * Returns NULL if invalid RegName specified.
 */
const char *    getRegNameString(RegName reg);
/**
 * Returns string name of a given OpndSize.
 * Returns NULL if invalid OpndSize passed.
 */
const char *    getOpndSizeString(OpndSize size);
/**
 * Returns OpndSize passed by its string representation (case insensitive).
 * Returns OpndSize_Null if invalid string specified.
 * The 'sizeString' can not be NULL.
 */
OpndSize        getOpndSize(const char * sizeString);
/**
 * Returns string name of a given OpndKind.
 * Returns NULL if the passed kind is invalid.
 */
const char *    getOpndKindString(OpndKind kind);
/**
 * Returns OpndKind found by its string representation (case insensitive).
 * Returns OpndKind_Null if the name is invalid.
 * The 'kindString' can not be NULL.
 */
OpndKind        getOpndKind(const char * kindString);
/**
 *
 */
const char *    getConditionString(ConditionMnemonic cm);

/**
 * Constructs an RegName with the same index and kind, but with a different size from
 * the given RegName (i.e. getRegAlias(EAX, OpndSize_16) => AX; getRegAlias(BL, OpndSize_32) => EBX).
 * The constructed RegName is not checked in any way and thus may be invalid.
 * Note, that the aliasing does not work for at least AH,BH,CH,DH, ESI, EDI, ESP and EBP regs.
 */
inline RegName getAliasReg(RegName reg, OpndSize sz)
{
    return (RegName)REGNAME(getRegKind(reg), sz, getRegIndex(reg));
}

/**
 * brief Tests two RegName-s of the same kind for equality.
 *
 * @note Does work for 8 bit general purpose registers (AH, AL, BH, BL, etc).
 */
inline bool equals(RegName r0, RegName r1)
{
    return getRegKind(r0) == getRegKind(r1) &&
           getRegIndex(r0) == getRegIndex(r1);
}

ENCODER_NAMESPACE_END

#endif  // ifndef _ENCODER_DEFS_H_
