mirror of
https://github.com/FEX-Emu/FEX.git
synced 2025-01-10 07:41:41 +00:00
OpcodeDispatcher: Handle BMI BEXTR
This commit is contained in:
parent
26d493a66e
commit
79d6bf2840
@ -2141,6 +2141,70 @@ void OpDispatchBuilder::ANDNBMIOp(OpcodeArgs) {
|
||||
GenerateFlags_Logical(Op, Dest, Src1, Src2);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::BEXTRBMIOp(OpcodeArgs) {
|
||||
// Essentially (Src1 >> Start) & ((1 << Length) - 1)
|
||||
// along with some edge-case handling and flag setting.
|
||||
|
||||
auto* Src1 = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1);
|
||||
auto* Src2 = LoadSource(GPRClass, Op, Op->Src[1], Op->Flags, -1);
|
||||
|
||||
const auto SrcSize = GetSrcSize(Op) * 8;
|
||||
const auto MaxSrcBit = SrcSize - 1;
|
||||
auto MaxSrcBitOp = _Constant(SrcSize, MaxSrcBit);
|
||||
|
||||
// Shift the operand down to the starting bit
|
||||
auto Start = _Bfe(8, 0, Src2);
|
||||
auto Shifted = _Lshr(Src1, Start);
|
||||
|
||||
// Shifts larger than operand size need to be set to zero.
|
||||
auto SanitizedShifted = _Select(IR::COND_ULE,
|
||||
Start, MaxSrcBitOp,
|
||||
Shifted, _Constant(SrcSize, 0));
|
||||
|
||||
// Now handle the length specifier.
|
||||
auto Length = _Bfe(8, 8, Src2);
|
||||
auto SanitizedLength = _Select(IR::COND_ULE,
|
||||
Length, MaxSrcBitOp,
|
||||
Length, MaxSrcBitOp);
|
||||
|
||||
// Now build up the mask
|
||||
// (1 << SanitizedLength) - 1
|
||||
auto One = _Constant(SrcSize, 1);
|
||||
auto Mask = _Sub(_Lshl(One, SanitizedLength), One);
|
||||
|
||||
// Now put it all together and make the result.
|
||||
auto Dest = _And(SanitizedShifted, Mask);
|
||||
|
||||
// Finally store the result.
|
||||
StoreResult(GPRClass, Op, Dest, -1);
|
||||
|
||||
// Handle flag setting.
|
||||
//
|
||||
// All that matters primarily for this instruction is
|
||||
// that we only set the ZF flag properly.
|
||||
//
|
||||
// Every other flag is considered undefined after a
|
||||
// BEXTR instruction, but we opt to reliably clear them.
|
||||
//
|
||||
SetRFLAG<X86State::RFLAG_AF_LOC>(_Constant(0));
|
||||
SetRFLAG<X86State::RFLAG_SF_LOC>(_Constant(0));
|
||||
SetRFLAG<X86State::RFLAG_CF_LOC>(_Constant(0));
|
||||
SetRFLAG<X86State::RFLAG_OF_LOC>(_Constant(0));
|
||||
|
||||
// PF
|
||||
if (CTX->Config.ABINoPF) {
|
||||
_InvalidateFlags(1UL << X86State::RFLAG_PF_LOC);
|
||||
} else {
|
||||
SetRFLAG<X86State::RFLAG_PF_LOC>(_Constant(0));
|
||||
}
|
||||
|
||||
// ZF
|
||||
auto ZeroOp = _Select(IR::COND_EQ,
|
||||
Dest, _Constant(0),
|
||||
_Constant(1), _Constant(0));
|
||||
SetRFLAG<X86State::RFLAG_ZF_LOC>(ZeroOp);
|
||||
}
|
||||
|
||||
void OpDispatchBuilder::RCROp1Bit(OpcodeArgs) {
|
||||
OrderedNode *Dest = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1);
|
||||
auto Size = GetSrcSize(Op) * 8;
|
||||
@ -5810,6 +5874,7 @@ constexpr uint16_t PF_F2 = 3;
|
||||
{OPD(2, 0b01, 0x79), 1, &OpDispatchBuilder::UnimplementedOp},
|
||||
|
||||
{OPD(2, 0b00, 0xF2), 1, &OpDispatchBuilder::ANDNBMIOp},
|
||||
{OPD(2, 0b00, 0xF7), 1, &OpDispatchBuilder::BEXTRBMIOp},
|
||||
};
|
||||
#undef OPD
|
||||
|
||||
|
@ -326,6 +326,7 @@ public:
|
||||
|
||||
// BMI Ops
|
||||
void ANDNBMIOp(OpcodeArgs);
|
||||
void BEXTRBMIOp(OpcodeArgs);
|
||||
|
||||
// X87 Ops
|
||||
template<size_t width>
|
||||
|
@ -399,7 +399,7 @@ void InitializeVEXTables() {
|
||||
|
||||
{OPD(2, 0b11, 0xF6), 1, X86InstInfo{"MULX", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}},
|
||||
|
||||
{OPD(2, 0b00, 0xF7), 1, X86InstInfo{"BEXTR", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}},
|
||||
{OPD(2, 0b00, 0xF7), 1, X86InstInfo{"BEXTR", TYPE_INST, FLAGS_MODRM | FLAGS_VEX_2ND_SRC, 0, nullptr}},
|
||||
{OPD(2, 0b01, 0xF7), 1, X86InstInfo{"SHLX", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}},
|
||||
{OPD(2, 0b10, 0xF7), 1, X86InstInfo{"SARX", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}},
|
||||
{OPD(2, 0b11, 0xF7), 1, X86InstInfo{"SHRX", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}},
|
||||
|
34
unittests/ASM/VEX/bextr.asm
Normal file
34
unittests/ASM/VEX/bextr.asm
Normal file
@ -0,0 +1,34 @@
|
||||
%ifdef CONFIG
|
||||
{
|
||||
"RegData": {
|
||||
"RAX": "0x7F",
|
||||
"RBX": "0",
|
||||
"RDX": "0xFF",
|
||||
"RSI": "0"
|
||||
}
|
||||
}
|
||||
%endif
|
||||
|
||||
; General extraction
|
||||
mov rax, 0x7FFFFFFFFFFFFFFF
|
||||
mov rbx, 0x838 ; Start at bit 56 and extract 8 bits
|
||||
bextr rax, rax, rbx ; This results in 0x7F being placed into RAX
|
||||
|
||||
; Extraction with 0 bits should clear the destination
|
||||
mov rbx, -1
|
||||
mov rcx, 0
|
||||
bextr rbx, rbx, rcx
|
||||
|
||||
; Same tests as above but with 32-bit registers
|
||||
|
||||
; General extraction
|
||||
mov rdx, 0x7FFFFFFFFFFFFFFF
|
||||
mov rsi, 0x818 ; Start at bit 24 and extract 8 bits
|
||||
bextr edx, edx, esi ; This results in 0xFF being placed into EDX
|
||||
|
||||
; Extraction with 0 bits should clear RSI to 0
|
||||
mov rsi, -1
|
||||
mov rdi, 0
|
||||
bextr esi, esi, edi
|
||||
|
||||
hlt
|
Loading…
Reference in New Issue
Block a user