mirror of
https://github.com/FEX-Emu/FEX.git
synced 2026-10-29 04:01:27 +01:00
Merge pull request #1344 from lioncash/bmi
OpcodeDispatcher: Implement handling for BLSI
This commit is contained in:
6 files changed
+164
-54
No files matched your search
+8
-2
@@ -450,8 +450,8 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op,
|
||||
// New instruction size decoding
|
||||
{
|
||||
// Decode destinations first
|
||||
uint32_t DstSizeFlag = FEXCore::X86Tables::InstFlags::GetSizeDstFlags(Info->Flags);
|
||||
uint32_t SrcSizeFlag = FEXCore::X86Tables::InstFlags::GetSizeSrcFlags(Info->Flags);
|
||||
const auto DstSizeFlag = FEXCore::X86Tables::InstFlags::GetSizeDstFlags(Info->Flags);
|
||||
const auto SrcSizeFlag = FEXCore::X86Tables::InstFlags::GetSizeSrcFlags(Info->Flags);
|
||||
|
||||
if (DstSizeFlag == FEXCore::X86Tables::InstFlags::SIZE_8BIT) {
|
||||
DecodeInst->Flags |= DecodeFlags::GenSizeDstSize(DecodeFlags::SIZE_8BIT);
|
||||
@@ -634,6 +634,12 @@ bool Decoder::NormalOp(FEXCore::X86Tables::X86InstInfo const *Info, uint16_t Op,
|
||||
++CurrentSrc;
|
||||
}
|
||||
|
||||
if ((Info->Flags & FEXCore::X86Tables::InstFlags::FLAGS_VEX_DST) != 0) {
|
||||
CurrentDest->Type = DecodedOperand::OpType::GPR;
|
||||
CurrentDest->Data.GPR.HighBits = false;
|
||||
CurrentDest->Data.GPR.GPR = MapVEXToReg(Options.vvvv, HasXMMDst);
|
||||
}
|
||||
|
||||
if (Bytes != 0) {
|
||||
LOGMAN_THROW_A(Bytes <= 8, "Number of bytes should be <= 8 for literal src");
|
||||
|
||||
|
||||
@@ -2204,6 +2204,63 @@ void OpDispatchBuilder::BEXTRBMIOp(OpcodeArgs) {
|
||||
SetRFLAG<X86State::RFLAG_ZF_LOC>(ZeroOp);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BLSIBMIOp(OpcodeArgs) {
|
||||
// Equivalent to performing: SRC & -SRC
|
||||
|
||||
auto* Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
auto NegatedSrc = _Neg(Src);
|
||||
auto Result = _And(Src, NegatedSrc);
|
||||
|
||||
// ...and we're done. Painless!
|
||||
StoreResult(GPRClass, Op, Result, -1);
|
||||
|
||||
// Now for the flags:
|
||||
//
|
||||
// Only CF, SF, ZF and OF are defined as being updated
|
||||
// CF is cleared if Src is zero, otherwise it's set.
|
||||
// SF is set to the value of the most significant operand bit of Result.
|
||||
// OF is always cleared
|
||||
// ZF is set, as usual, if Result is zero or not.
|
||||
//
|
||||
// AF and PF are documented as being in an undefined state after
|
||||
// a BLSI operation, however, we choose to reliably clear them.
|
||||
|
||||
auto Zero = _Constant(0);
|
||||
auto One = _Constant(1);
|
||||
|
||||
SetRFLAG<X86State::RFLAG_OF_LOC>(Zero);
|
||||
SetRFLAG<X86State::RFLAG_AF_LOC>(Zero);
|
||||
if (CTX->Config.ABINoPF) {
|
||||
_InvalidateFlags(1UL << X86State::RFLAG_PF_LOC);
|
||||
} else {
|
||||
SetRFLAG<X86State::RFLAG_PF_LOC>(Zero);
|
||||
}
|
||||
|
||||
// ZF
|
||||
{
|
||||
auto ZFOp = _Select(IR::COND_EQ,
|
||||
Result, Zero,
|
||||
One, Zero);
|
||||
SetRFLAG<X86State::RFLAG_ZF_LOC>(ZFOp);
|
||||
}
|
||||
|
||||
// CF
|
||||
{
|
||||
auto CFOp = _Select(IR::COND_EQ,
|
||||
Src, Zero,
|
||||
Zero, One);
|
||||
SetRFLAG<X86State::RFLAG_CF_LOC>(CFOp);
|
||||
}
|
||||
|
||||
// SF
|
||||
{
|
||||
auto SignBit = _Constant((GetSrcSize(Op) * 8) - 1);
|
||||
auto SFOp = _Lshr(Result, SignBit);
|
||||
|
||||
SetRFLAG<X86State::RFLAG_SF_LOC>(SFOp);
|
||||
}
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RCROp1Bit(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@@ -5876,6 +5933,12 @@ constexpr uint16_t PF_F2 = 3;
|
||||
};
|
||||
#undef OPD
|
||||
|
||||
#define OPD(group, pp, opcode) (((group - X86Tables::InstType::TYPE_VEX_GROUP_12) << 4) | (pp << 3) | (opcode))
|
||||
const std::vector<std::tuple<uint8_t, uint8_t, X86Tables::OpDispatchPtr>> VEXGroupTable = {
|
||||
{OPD(X86Tables::InstType::TYPE_VEX_GROUP_17, 0, 0b011), 1, &OpDispatchBuilder::BLSIBMIOp},
|
||||
};
|
||||
#undef OPD
|
||||
|
||||
const std::vector<std::tuple<uint8_t, uint8_t, FEXCore::X86Tables::OpDispatchPtr>> EVEXTable = {
|
||||
{0x10, 2, &OpDispatchBuilder::UnimplementedOp},
|
||||
{0x59, 1, &OpDispatchBuilder::UnimplementedOp},
|
||||
@@ -5936,6 +5999,7 @@ constexpr uint16_t PF_F2 = 3;
|
||||
InstallToTable(FEXCore::X86Tables::H0F38TableOps, H0F38Table);
|
||||
InstallToTable(FEXCore::X86Tables::H0F3ATableOps, H0F3ATable);
|
||||
InstallToTable(FEXCore::X86Tables::VEXTableOps, VEXTable);
|
||||
InstallToTable(FEXCore::X86Tables::VEXTableGroupOps, VEXGroupTable);
|
||||
InstallToTable(FEXCore::X86Tables::EVEXTableOps, EVEXTable);
|
||||
}
|
||||
|
||||
|
||||
@@ -327,6 +327,7 @@ public:
|
||||
// BMI Ops
|
||||
void ANDNBMIOp(OpcodeArgs);
|
||||
void BEXTRBMIOp(OpcodeArgs);
|
||||
void BLSIBMIOp(OpcodeArgs);
|
||||
|
||||
// X87 Ops
|
||||
template<size_t width>
|
||||
|
||||
@@ -505,7 +505,7 @@ void InitializeVEXTables() {
|
||||
|
||||
{OPD(TYPE_VEX_GROUP_17, 0, 0b001), 1, X86InstInfo{"BLSR", TYPE_UNDEC, FLAGS_MODRM, 0, nullptr}},
|
||||
{OPD(TYPE_VEX_GROUP_17, 0, 0b010), 1, X86InstInfo{"BLSMSK", TYPE_UNDEC, FLAGS_MODRM, 0, nullptr}},
|
||||
{OPD(TYPE_VEX_GROUP_17, 0, 0b011), 1, X86InstInfo{"BLSI", TYPE_UNDEC, FLAGS_MODRM, 0, nullptr}},
|
||||
{OPD(TYPE_VEX_GROUP_17, 0, 0b011), 1, X86InstInfo{"BLSI", TYPE_INST, FLAGS_MODRM | FLAGS_VEX_DST, 0, nullptr}},
|
||||
};
|
||||
#undef OPD
|
||||
|
||||
|
||||
+56
-51
@@ -272,97 +272,102 @@ enum InstType {
|
||||
};
|
||||
|
||||
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);
|
||||
using InstFlagType = uint64_t;
|
||||
|
||||
constexpr InstFlagType FLAGS_NONE = 0;
|
||||
constexpr InstFlagType FLAGS_DEBUG = (1ULL << 1);
|
||||
constexpr InstFlagType FLAGS_DEBUG_MEM_ACCESS = (1ULL << 2);
|
||||
constexpr InstFlagType FLAGS_SUPPORTS_REP = (1ULL << 3);
|
||||
constexpr InstFlagType FLAGS_BLOCK_END = (1ULL << 4);
|
||||
constexpr InstFlagType FLAGS_SETS_RIP = (1ULL << 5);
|
||||
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_MUL_2 = (1ULL << 6);
|
||||
constexpr InstFlagType FLAGS_DISPLACE_SIZE_DIV_2 = (1ULL << 7);
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT = (1ULL << 8);
|
||||
constexpr InstFlagType FLAGS_MEM_OFFSET = (1ULL << 9);
|
||||
|
||||
// Enables XMM based subflags
|
||||
// Current reserved range for this SF is [10, 15]
|
||||
constexpr uint32_t FLAGS_XMM_FLAGS = (1 << 10);
|
||||
constexpr InstFlagType FLAGS_XMM_FLAGS = (1ULL << 10);
|
||||
|
||||
// X87 flags aliased to XMM flags selection
|
||||
// Allows X87 instruction table that is abusing the flag for 64BIT selection to work
|
||||
constexpr uint32_t FLAGS_X87_FLAGS = (1 << 10);
|
||||
constexpr InstFlagType FLAGS_X87_FLAGS = (1ULL << 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);
|
||||
constexpr InstFlagType FLAGS_SF_DST_RAX = (1ULL << 11);
|
||||
constexpr InstFlagType FLAGS_SF_DST_RDX = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RAX = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_RCX = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_REX_IN_BYTE = (1ULL << 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);
|
||||
constexpr uint32_t FLAGS_SF_MMX = (3 << 14); // MMX_DST | MMX_SRC
|
||||
constexpr uint32_t FLAGS_SF_MMX_DST = (1 << 14);
|
||||
constexpr uint32_t FLAGS_SF_MMX_SRC = (1 << 15);
|
||||
constexpr InstFlagType FLAGS_SF_HIGH_XMM_REG = (1ULL << 11);
|
||||
constexpr InstFlagType FLAGS_SF_DST_GPR = (1ULL << 12);
|
||||
constexpr InstFlagType FLAGS_SF_SRC_GPR = (1ULL << 13);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_DST = (1ULL << 14);
|
||||
constexpr InstFlagType FLAGS_SF_MMX_SRC = (1ULL << 15);
|
||||
constexpr InstFlagType FLAGS_SF_MMX = FLAGS_SF_MMX_DST | FLAGS_SF_MMX_SRC;
|
||||
|
||||
// Enables MODRM specific subflags
|
||||
// Current reserved range for this SF is [14, 17]
|
||||
constexpr uint32_t FLAGS_MODRM = (1 << 16);
|
||||
constexpr InstFlagType FLAGS_MODRM = (1ULL << 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);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_DST = (1ULL << 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 InstFlagType FLAGS_SF_MOD_MEM_ONLY = (1ULL << 18);
|
||||
constexpr InstFlagType FLAGS_SF_MOD_REG_ONLY = (1ULL << 19);
|
||||
|
||||
// The secondary Opcode Map uses prefix bytes to overlay more instruction
|
||||
// But some instructions need to ignore this overlay and consume these prefixes.
|
||||
constexpr uint32_t FLAGS_NO_OVERLAY = (1 << 20);
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY = (1ULL << 20);
|
||||
// Some instructions partially ignore overlay
|
||||
// Ignore OpSize (0x66) in this case
|
||||
constexpr uint32_t FLAGS_NO_OVERLAY66 = (1 << 21);
|
||||
constexpr InstFlagType FLAGS_NO_OVERLAY66 = (1ULL << 21);
|
||||
|
||||
// x87
|
||||
constexpr uint32_t FLAGS_POP = (1 << 22);
|
||||
constexpr InstFlagType FLAGS_POP = (1ULL << 22);
|
||||
|
||||
// Only SEXT if the instruction is operating in 64bit operand size
|
||||
constexpr uint32_t FLAGS_SRC_SEXT64BIT = (1 << 23);
|
||||
constexpr InstFlagType FLAGS_SRC_SEXT64BIT = (1ULL << 23);
|
||||
|
||||
// Whether or not the instruction has a VEX prefix for the first source operand
|
||||
constexpr uint32_t FLAGS_VEX_1ST_SRC = (1 << 24);
|
||||
constexpr InstFlagType FLAGS_VEX_1ST_SRC = (1ULL << 24);
|
||||
// Whether or not the instruction has a VEX prefix for the second source operand
|
||||
constexpr uint32_t FLAGS_VEX_2ND_SRC = (1 << 25);
|
||||
constexpr InstFlagType FLAGS_VEX_2ND_SRC = (1ULL << 25);
|
||||
// Whether or not the instruction has a VEX prefix for the destination
|
||||
constexpr InstFlagType FLAGS_VEX_DST = (1ULL << 26);
|
||||
|
||||
constexpr uint32_t FLAGS_SIZE_DST_OFF = 26;
|
||||
constexpr uint32_t FLAGS_SIZE_SRC_OFF = FLAGS_SIZE_DST_OFF + 3;
|
||||
constexpr InstFlagType FLAGS_SIZE_DST_OFF = 58;
|
||||
constexpr InstFlagType 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
|
||||
constexpr InstFlagType SIZE_MASK = 0b111;
|
||||
constexpr InstFlagType SIZE_DEF = 0b000;
|
||||
constexpr InstFlagType SIZE_8BIT = 0b001;
|
||||
constexpr InstFlagType SIZE_16BIT = 0b010;
|
||||
constexpr InstFlagType SIZE_32BIT = 0b011;
|
||||
constexpr InstFlagType SIZE_64BIT = 0b100;
|
||||
constexpr InstFlagType SIZE_128BIT = 0b101;
|
||||
constexpr InstFlagType SIZE_256BIT = 0b110;
|
||||
constexpr InstFlagType SIZE_64BITDEF = 0b111; // Default mode is 64bit instead of typical 32bit
|
||||
|
||||
constexpr uint32_t GetSizeDstFlags(uint32_t Flags) { return (Flags >> FLAGS_SIZE_DST_OFF) & SIZE_MASK; }
|
||||
constexpr uint32_t GetSizeSrcFlags(uint32_t Flags) { return (Flags >> FLAGS_SIZE_SRC_OFF) & SIZE_MASK; }
|
||||
constexpr InstFlagType GetSizeDstFlags(InstFlagType Flags) { return (Flags >> FLAGS_SIZE_DST_OFF) & SIZE_MASK; }
|
||||
constexpr InstFlagType GetSizeSrcFlags(InstFlagType Flags) { return (Flags >> FLAGS_SIZE_SRC_OFF) & SIZE_MASK; }
|
||||
|
||||
constexpr uint32_t GenFlagsDstSize(uint32_t Size) { return Size << FLAGS_SIZE_DST_OFF; }
|
||||
constexpr uint32_t GenFlagsSrcSize(uint32_t Size) { return Size << FLAGS_SIZE_SRC_OFF; }
|
||||
constexpr uint32_t GenFlagsSameSize(uint32_t Size) { return (Size << FLAGS_SIZE_DST_OFF) | (Size << FLAGS_SIZE_SRC_OFF); }
|
||||
constexpr uint32_t GenFlagsSizes(uint32_t Dest, uint32_t Src) { return (Dest << FLAGS_SIZE_DST_OFF) | (Src << FLAGS_SIZE_SRC_OFF); }
|
||||
constexpr InstFlagType GenFlagsDstSize(InstFlagType Size) { return Size << FLAGS_SIZE_DST_OFF; }
|
||||
constexpr InstFlagType GenFlagsSrcSize(InstFlagType Size) { return Size << FLAGS_SIZE_SRC_OFF; }
|
||||
constexpr InstFlagType GenFlagsSameSize(InstFlagType Size) { return (Size << FLAGS_SIZE_DST_OFF) | (Size << FLAGS_SIZE_SRC_OFF); }
|
||||
constexpr InstFlagType GenFlagsSizes(InstFlagType Dest, InstFlagType 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)))
|
||||
@@ -424,7 +429,7 @@ void InstallDebugInfo();
|
||||
struct X86InstInfo {
|
||||
char const *Name;
|
||||
InstType Type;
|
||||
uint32_t Flags; ///< Must be larger than InstFlags enum
|
||||
InstFlags::InstFlagType Flags; ///< Must be larger than InstFlags enum
|
||||
uint8_t MoreBytes;
|
||||
OpDispatchPtr OpcodeDispatcher;
|
||||
#ifndef NDEBUG
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "1",
|
||||
"RBX": "0xFF00000000000000",
|
||||
"RCX": "0x0100000000000000",
|
||||
"RDX": "1",
|
||||
"RSI": "0xFF000000",
|
||||
"RDI": "0x01000000"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; Trivial test, this should result in 1.
|
||||
mov rax, 11
|
||||
blsi rax, rax
|
||||
|
||||
; Results in the lowest set bit (bit 56) being extracted
|
||||
mov rbx, 0xFF00000000000000
|
||||
mov rcx, 0
|
||||
blsi rcx, rbx
|
||||
|
||||
; Same tests but with 32-bit registers
|
||||
|
||||
; Trivial test, this should result in 1.
|
||||
mov edx, 11
|
||||
blsi edx, edx
|
||||
|
||||
; Results in the lowest set bit (bit 24) being extracted
|
||||
mov rsi, 0xFF000000
|
||||
mov rdi, 0
|
||||
blsi edi, esi
|
||||
|
||||
hlt
|
||||
Reference in new issue
Block a user