mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-12 21:00:39 +02:00
These would have been forced to 64bit when they would have wanted to be operating in 16bit mode. Fixes that.
412 lines
12 KiB
C++
412 lines
12 KiB
C++
#pragma once
|
|
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <type_traits>
|
|
|
|
namespace FEXCore::IR {
|
|
///< Forward declaration of OpDispatchBuilder
|
|
class OpDispatchBuilder;
|
|
}
|
|
|
|
namespace FEXCore::X86Tables {
|
|
|
|
///< Forward declaration of X86InstInfo
|
|
struct X86InstInfo;
|
|
|
|
namespace DecodeFlags {
|
|
constexpr uint32_t FLAG_OPERAND_SIZE = (1 << 0);
|
|
constexpr uint32_t FLAG_ADDRESS_SIZE = (1 << 1);
|
|
constexpr uint32_t FLAG_LOCK = (1 << 2);
|
|
constexpr uint32_t FLAG_LEGACY_PREFIX = (1 << 3);
|
|
constexpr uint32_t FLAG_REX_PREFIX = (1 << 4);
|
|
constexpr uint32_t FLAG_MODRM_PRESENT = (1 << 5);
|
|
constexpr uint32_t FLAG_SIB_PRESENT = (1 << 6);
|
|
constexpr uint32_t FLAG_REX_WIDENING = (1 << 7);
|
|
constexpr uint32_t FLAG_REX_XGPR_B = (1 << 8);
|
|
constexpr uint32_t FLAG_REX_XGPR_X = (1 << 9);
|
|
constexpr uint32_t FLAG_REX_XGPR_R = (1 << 10);
|
|
constexpr uint32_t FLAG_FS_PREFIX = (1 << 11);
|
|
constexpr uint32_t FLAG_GS_PREFIX = (1 << 12);
|
|
constexpr uint32_t FLAG_REP_PREFIX = (1 << 13);
|
|
constexpr uint32_t FLAG_REPNE_PREFIX = (1 << 14);
|
|
// Size flags
|
|
constexpr uint32_t FLAG_SIZE_DST_OFF = 15;
|
|
constexpr uint32_t FLAG_SIZE_SRC_OFF = FLAG_SIZE_DST_OFF + 3;
|
|
constexpr uint32_t SIZE_MASK = 0b111;
|
|
constexpr uint32_t SIZE_DEF = 0b000; // This should be invalid past decoding
|
|
constexpr uint32_t SIZE_8BIT = 0b001;
|
|
constexpr uint32_t SIZE_16BIT = 0b010;
|
|
constexpr uint32_t SIZE_32BIT = 0b011;
|
|
constexpr uint32_t SIZE_64BIT = 0b100;
|
|
constexpr uint32_t SIZE_128BIT = 0b101;
|
|
constexpr uint32_t SIZE_256BIT = 0b110;
|
|
|
|
inline uint32_t GetSizeDstFlags(uint32_t Flags) { return (Flags >> FLAG_SIZE_DST_OFF) & SIZE_MASK; }
|
|
inline uint32_t GetSizeSrcFlags(uint32_t Flags) { return (Flags >> FLAG_SIZE_SRC_OFF) & SIZE_MASK; }
|
|
|
|
inline uint32_t GenSizeDstSize(uint32_t Size) { return Size << FLAG_SIZE_DST_OFF; }
|
|
inline uint32_t GenSizeSrcSize(uint32_t Size) { return Size << FLAG_SIZE_SRC_OFF; }
|
|
}
|
|
|
|
union DecodedOperand {
|
|
enum {
|
|
TYPE_NONE,
|
|
TYPE_GPR,
|
|
TYPE_GPR_DIRECT,
|
|
TYPE_GPR_INDIRECT,
|
|
TYPE_RIP_RELATIVE,
|
|
TYPE_LITERAL,
|
|
TYPE_SIB,
|
|
};
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
} TypeNone;
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
bool HighBits;
|
|
uint8_t GPR;
|
|
} TypeGPR;
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
uint8_t GPR;
|
|
int32_t Displacement;
|
|
} TypeGPRIndirect;
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
int32_t Literal;
|
|
} TypeRIPLiteral;
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
uint8_t Size;
|
|
uint64_t Literal;
|
|
} TypeLiteral;
|
|
|
|
struct {
|
|
uint8_t Type;
|
|
uint8_t Index; // ~0 invalid
|
|
uint8_t Base; // ~0 invalid
|
|
uint32_t Scale : 8;
|
|
int32_t Offset;
|
|
} TypeSIB;
|
|
};
|
|
|
|
struct DecodedInst {
|
|
uint64_t PC;
|
|
|
|
uint16_t OP;
|
|
uint32_t Flags;
|
|
|
|
uint8_t ModRM;
|
|
uint8_t SIB;
|
|
uint8_t InstSize;
|
|
uint8_t LastEscapePrefix;
|
|
bool DecodedModRM;
|
|
bool DecodedSIB;
|
|
|
|
DecodedOperand Dest;
|
|
DecodedOperand Src1;
|
|
DecodedOperand Src2;
|
|
|
|
// Constains the dispatcher handler pointer
|
|
X86InstInfo const* TableInfo;
|
|
};
|
|
|
|
union ModRMDecoded {
|
|
uint8_t Hex{};
|
|
struct {
|
|
uint8_t rm : 3;
|
|
uint8_t reg : 3;
|
|
uint8_t mod : 2;
|
|
};
|
|
};
|
|
|
|
union SIBDecoded {
|
|
uint8_t Hex{};
|
|
struct {
|
|
uint8_t base : 3;
|
|
uint8_t index : 3;
|
|
uint8_t scale : 2;
|
|
};
|
|
};
|
|
|
|
enum InstType {
|
|
TYPE_UNKNOWN,
|
|
TYPE_LEGACY_PREFIX,
|
|
TYPE_PREFIX,
|
|
TYPE_REX_PREFIX,
|
|
TYPE_SECONDARY_TABLE_PREFIX,
|
|
TYPE_X87_TABLE_PREFIX,
|
|
TYPE_VEX_TABLE_PREFIX,
|
|
TYPE_XOP_TABLE_PREFIX,
|
|
TYPE_INST,
|
|
TYPE_X87 = TYPE_INST,
|
|
TYPE_INVALID,
|
|
TYPE_COPY_OTHER,
|
|
|
|
// Must be in order
|
|
// Groups 1, 1a, 2, 3, 4, 5, 11 are for the primary op table
|
|
// Groups 6, 7, 8, 9, 10, 12, 13, 14, 15, 16, 17, p are for the secondary op table
|
|
TYPE_GROUP_1,
|
|
TYPE_GROUP_1A,
|
|
TYPE_GROUP_2,
|
|
TYPE_GROUP_3,
|
|
TYPE_GROUP_4,
|
|
TYPE_GROUP_5,
|
|
TYPE_GROUP_11,
|
|
|
|
// Must be in order
|
|
// Groups 6-p Are for the secondary op table
|
|
TYPE_GROUP_6,
|
|
TYPE_GROUP_7,
|
|
TYPE_GROUP_8,
|
|
TYPE_GROUP_9,
|
|
TYPE_GROUP_10,
|
|
TYPE_GROUP_12,
|
|
TYPE_GROUP_13,
|
|
TYPE_GROUP_14,
|
|
TYPE_GROUP_15,
|
|
TYPE_GROUP_16,
|
|
TYPE_GROUP_17,
|
|
TYPE_GROUP_P,
|
|
|
|
// The secondary op extension table allows further extensions
|
|
// Group 7 allows additional extensions to this table
|
|
TYPE_SECOND_GROUP_MODRM,
|
|
|
|
TYPE_VEX_GROUP_12,
|
|
TYPE_VEX_GROUP_13,
|
|
TYPE_VEX_GROUP_14,
|
|
TYPE_VEX_GROUP_15,
|
|
TYPE_VEX_GROUP_17,
|
|
|
|
TYPE_GROUP_EVEX,
|
|
|
|
// Just to make grepping easier
|
|
TYPE_3DNOW_TABLE = TYPE_INVALID,
|
|
TYPE_3DNOW_INST = TYPE_INVALID,
|
|
|
|
// Exists in the table but isn't decoded correctly
|
|
TYPE_UNDEC = TYPE_INVALID,
|
|
TYPE_MMX = TYPE_INVALID,
|
|
TYPE_PRIV = TYPE_INVALID,
|
|
TYPE_0F38_TABLE = TYPE_INVALID,
|
|
TYPE_0F3A_TABLE = TYPE_INVALID,
|
|
};
|
|
|
|
namespace InstFlags {
|
|
constexpr uint32_t FLAGS_NONE = 0;
|
|
constexpr uint32_t FLAGS_DEBUG = (1 << 1);
|
|
constexpr uint32_t FLAGS_DEBUG_MEM_ACCESS = (1 << 2);
|
|
constexpr uint32_t FLAGS_SUPPORTS_REP = (1 << 3);
|
|
constexpr uint32_t FLAGS_BLOCK_END = (1 << 4);
|
|
constexpr uint32_t FLAGS_SETS_RIP = (1 << 5);
|
|
|
|
constexpr uint32_t FLAGS_DISPLACE_SIZE_MUL_2 = (1 << 6);
|
|
constexpr uint32_t FLAGS_DISPLACE_SIZE_DIV_2 = (1 << 7);
|
|
constexpr uint32_t FLAGS_SRC_SEXT = (1 << 8);
|
|
constexpr uint32_t FLAGS_MEM_OFFSET = (1 << 9);
|
|
|
|
// Enables XMM based subflags
|
|
// Current reserved range for this SF is [10, 15]
|
|
constexpr uint32_t FLAGS_XMM_FLAGS = (1 << 10);
|
|
|
|
// Non-XMM subflags
|
|
constexpr uint32_t FLAGS_SF_DST_RAX = (1 << 11);
|
|
constexpr uint32_t FLAGS_SF_DST_RDX = (1 << 12);
|
|
constexpr uint32_t FLAGS_SF_SRC_RAX = (1 << 13);
|
|
constexpr uint32_t FLAGS_SF_SRC_RCX = (1 << 14);
|
|
constexpr uint32_t FLAGS_SF_REX_IN_BYTE = (1 << 15);
|
|
|
|
// XMM subflags
|
|
constexpr uint32_t FLAGS_SF_HIGH_XMM_REG = (1 << 11);
|
|
constexpr uint32_t FLAGS_SF_DST_GPR = (1 << 12);
|
|
constexpr uint32_t FLAGS_SF_SRC_GPR = (1 << 13);
|
|
|
|
// Enables MODRM specific subflags
|
|
// Current reserved range for this SF is [14, 17]
|
|
constexpr uint32_t FLAGS_MODRM = (1 << 16);
|
|
|
|
// With ModRM SF flag enabled
|
|
// Direction of ModRM. Dst ^ Src
|
|
// Set means destination is rm bits
|
|
// Unset means src is rm bits
|
|
constexpr uint32_t FLAGS_SF_MOD_DST = (1 << 17);
|
|
|
|
// If the instruction is restricted to mem or reg only
|
|
// 0b00 = Regular ModRM support
|
|
// 0b01 = Memory accesses only
|
|
// 0b10 = Register accesses only
|
|
// 0b11 = <Reserved>
|
|
constexpr uint32_t FLAGS_SF_MOD_MEM_ONLY = (1 << 18);
|
|
constexpr uint32_t FLAGS_SF_MOD_REG_ONLY = (1 << 19);
|
|
|
|
constexpr uint32_t FLAGS_SIZE_DST_OFF = 20;
|
|
constexpr uint32_t FLAGS_SIZE_SRC_OFF = FLAGS_SIZE_DST_OFF + 3;
|
|
|
|
constexpr uint32_t SIZE_MASK = 0b111;
|
|
constexpr uint32_t SIZE_DEF = 0b000;
|
|
constexpr uint32_t SIZE_8BIT = 0b001;
|
|
constexpr uint32_t SIZE_16BIT = 0b010;
|
|
constexpr uint32_t SIZE_32BIT = 0b011;
|
|
constexpr uint32_t SIZE_64BIT = 0b100;
|
|
constexpr uint32_t SIZE_128BIT = 0b101;
|
|
constexpr uint32_t SIZE_256BIT = 0b110;
|
|
constexpr uint32_t SIZE_64BITDEF = 0b111; // Default mode is 64bit instead of typical 32bit
|
|
|
|
inline uint32_t GetSizeDstFlags(uint32_t Flags) { return (Flags >> FLAGS_SIZE_DST_OFF) & SIZE_MASK; }
|
|
inline uint32_t GetSizeSrcFlags(uint32_t Flags) { return (Flags >> FLAGS_SIZE_SRC_OFF) & SIZE_MASK; }
|
|
|
|
inline uint32_t GenFlagsDstSize(uint32_t Size) { return Size << FLAGS_SIZE_DST_OFF; }
|
|
inline uint32_t GenFlagsSrcSize(uint32_t Size) { return Size << FLAGS_SIZE_SRC_OFF; }
|
|
inline uint32_t GenFlagsSameSize(uint32_t Size) {return (Size << FLAGS_SIZE_DST_OFF) | (Size << FLAGS_SIZE_SRC_OFF); }
|
|
inline uint32_t GenFlagsSizes(uint32_t Dest, uint32_t Src) {return (Dest << FLAGS_SIZE_DST_OFF) | (Src << FLAGS_SIZE_SRC_OFF); }
|
|
|
|
|
|
// If it has an xmm subflag
|
|
#define HAS_XMM_SUBFLAG(x, flag) (((x) & (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag))) == (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag)))
|
|
|
|
// If it has non-xmm subflag
|
|
#define HAS_NON_XMM_SUBFLAG(x, flag) (((x) & (FEXCore::X86Tables::InstFlags::FLAGS_XMM_FLAGS | (flag))) == (flag))
|
|
}
|
|
|
|
auto OpToIndex = [](uint8_t Op) constexpr -> uint8_t {
|
|
switch (Op) {
|
|
// Group 1
|
|
case 0x80: return 0;
|
|
case 0x81: return 1;
|
|
case 0x82: return 2;
|
|
case 0x83: return 3;
|
|
// Group 2
|
|
case 0xC0: return 0;
|
|
case 0xC1: return 1;
|
|
case 0xD0: return 2;
|
|
case 0xD1: return 3;
|
|
case 0xD2: return 4;
|
|
case 0xD3: return 5;
|
|
// Group 3
|
|
case 0xF6: return 0;
|
|
case 0xF7: return 1;
|
|
// Group 4
|
|
case 0xFE: return 0;
|
|
// Group 5
|
|
case 0xFF: return 0;
|
|
// Group 11
|
|
case 0xC6: return 0;
|
|
case 0xC7: return 1;
|
|
}
|
|
return 0;
|
|
};
|
|
|
|
using DecodedOp = DecodedInst const*;
|
|
using OpDispatchPtr = void (IR::OpDispatchBuilder::*)(DecodedOp);
|
|
|
|
#ifndef NDEBUG
|
|
namespace X86InstDebugInfo {
|
|
constexpr uint64_t FLAGS_MEM_ALIGN_4 = (1 << 0);
|
|
constexpr uint64_t FLAGS_MEM_ALIGN_8 = (1 << 1);
|
|
constexpr uint64_t FLAGS_MEM_ALIGN_16 = (1 << 2);
|
|
constexpr uint64_t FLAGS_MEM_ALIGN_SIZE = (1 << 3); // If instruction size changes depending on prefixes
|
|
constexpr uint64_t FLAGS_MEM_ACCESS = (1 << 4);
|
|
constexpr uint64_t FLAGS_DEBUG = (1 << 5);
|
|
constexpr uint64_t FLAGS_DIVIDE = (1 << 6);
|
|
|
|
|
|
struct Flags {
|
|
uint64_t DebugFlags;
|
|
};
|
|
void InstallDebugInfo();
|
|
}
|
|
|
|
#endif
|
|
|
|
struct X86InstInfo {
|
|
char const *Name;
|
|
InstType Type;
|
|
uint32_t Flags; ///< Must be larger than InstFlags enum
|
|
uint8_t MoreBytes;
|
|
OpDispatchPtr OpcodeDispatcher;
|
|
#ifndef NDEBUG
|
|
X86InstDebugInfo::Flags DebugInfo;
|
|
uint32_t NumUnitTestsGenerated;
|
|
#endif
|
|
|
|
bool operator==(const X86InstInfo &b) const {
|
|
if (strcmp(Name, b.Name) != 0 ||
|
|
Type != b.Type ||
|
|
Flags != b.Flags ||
|
|
MoreBytes != b.MoreBytes)
|
|
return false;
|
|
|
|
// We don't care if the opcode dispatcher differs
|
|
return true;
|
|
}
|
|
};
|
|
|
|
static_assert(std::is_pod<X86InstInfo>::value, "Pod?");
|
|
|
|
constexpr size_t MAX_PRIMARY_TABLE_SIZE = 256;
|
|
constexpr size_t MAX_SECOND_TABLE_SIZE = 256;
|
|
constexpr size_t MAX_REP_MOD_TABLE_SIZE = 256;
|
|
constexpr size_t MAX_REPNE_MOD_TABLE_SIZE = 256;
|
|
constexpr size_t MAX_OPSIZE_MOD_TABLE_SIZE = 256;
|
|
// 6 (groups) | 6 (max indexes) | 8 ops = 0b111'111'111 = 9 bits
|
|
constexpr size_t MAX_INST_GROUP_TABLE_SIZE = 512;
|
|
// 12 (groups) | 3(max indexes) | 8 ops = 0b1111'11'111 = 9 bits
|
|
constexpr size_t MAX_INST_SECOND_GROUP_TABLE_SIZE = 512;
|
|
constexpr size_t MAX_X87_TABLE_SIZE = 1 << 11;
|
|
constexpr size_t MAX_SECOND_MODRM_TABLE_SIZE = 32;
|
|
// 3 prefixes | 8 bit opcode
|
|
constexpr size_t MAX_0F_38_TABLE_SIZE = (1 << 11);
|
|
// 1 REX | 1 prefixes | 8 bit opcode
|
|
constexpr size_t MAX_0F_3A_TABLE_SIZE = (1 << 11);
|
|
constexpr size_t MAX_3DNOW_TABLE_SIZE = 256;
|
|
// VEX
|
|
// map_select(2 bits for now) | vex.pp (2 bits) | opcode (8bit)
|
|
constexpr size_t MAX_VEX_TABLE_SIZE = (1 << 13);
|
|
// VEX group ops
|
|
// group select (3 bits for now) | ModRM opcode (3 bits)
|
|
constexpr size_t MAX_VEX_GROUP_TABLE_SIZE = (1 << 7);
|
|
|
|
// XOP
|
|
// group (2 bits for now) | vex.pp (2 bits) | opcode (8bit)
|
|
constexpr size_t MAX_XOP_TABLE_SIZE = (1 << 13);
|
|
|
|
// XOP group ops
|
|
// group select (2 bits for now) | modrm opcode (3 bits)
|
|
constexpr size_t MAX_XOP_GROUP_TABLE_SIZE = (1 << 6);
|
|
|
|
constexpr size_t MAX_EVEX_TABLE_SIZE = 256;
|
|
|
|
extern X86InstInfo BaseOps[MAX_PRIMARY_TABLE_SIZE];
|
|
extern X86InstInfo SecondBaseOps[MAX_SECOND_TABLE_SIZE];
|
|
extern X86InstInfo RepModOps[MAX_REP_MOD_TABLE_SIZE];
|
|
extern X86InstInfo RepNEModOps[MAX_REPNE_MOD_TABLE_SIZE];
|
|
extern X86InstInfo OpSizeModOps[MAX_OPSIZE_MOD_TABLE_SIZE];
|
|
extern X86InstInfo PrimaryInstGroupOps[MAX_INST_GROUP_TABLE_SIZE];
|
|
extern X86InstInfo SecondInstGroupOps[MAX_INST_SECOND_GROUP_TABLE_SIZE];
|
|
extern X86InstInfo SecondModRMTableOps[MAX_SECOND_MODRM_TABLE_SIZE];
|
|
extern X86InstInfo X87Ops[MAX_X87_TABLE_SIZE];
|
|
extern X86InstInfo DDDNowOps[MAX_3DNOW_TABLE_SIZE];
|
|
extern X86InstInfo H0F38TableOps[MAX_0F_38_TABLE_SIZE];
|
|
extern X86InstInfo H0F3ATableOps[MAX_0F_3A_TABLE_SIZE];
|
|
|
|
// VEX
|
|
extern X86InstInfo VEXTableOps[MAX_VEX_TABLE_SIZE];
|
|
extern X86InstInfo VEXTableGroupOps[MAX_VEX_GROUP_TABLE_SIZE];
|
|
|
|
// XOP
|
|
extern X86InstInfo XOPTableOps[MAX_XOP_TABLE_SIZE];
|
|
extern X86InstInfo XOPTableGroupOps[MAX_XOP_GROUP_TABLE_SIZE];
|
|
|
|
// EVEX
|
|
extern X86InstInfo EVEXTableOps[MAX_EVEX_TABLE_SIZE];
|
|
|
|
void InitializeInfoTables();
|
|
}
|