Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OpcodeDispatcher: Fixes 32-bit mode LOOP RCX register usage #3504

Merged
merged 2 commits into from
Mar 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1058,13 +1058,19 @@ void OpDispatchBuilder::LoopOp(OpcodeArgs) {

BlockSetRIP = true;
uint32_t SrcSize = (Op->Flags & X86Tables::DecodeFlags::FLAG_ADDRESS_SIZE) ? 4 : 8;
auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;

if (!CTX->Config.Is64BitMode) {
// RCX size is 32-bit or 16-bit when executing in 32-bit mode.
SrcSize >>= 1;
OpSize = OpSize::i32Bit;
}

LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here");

uint64_t Target = Op->PC + Op->InstSize + Op->Src[1].Data.Literal.Value;

auto OpSize = SrcSize == 8 ? OpSize::i64Bit : OpSize::i32Bit;
OrderedNode *CondReg = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags);
OrderedNode *CondReg = LoadSource_WithOpSize(GPRClass, Op, Op->Src[0], SrcSize, Op->Flags);
CondReg = _Sub(OpSize, CondReg, _Constant(SrcSize * 8, 1));
StoreResult(GPRClass, Op, Op->Src[0], CondReg, -1);

Expand Down
27 changes: 27 additions & 0 deletions unittests/32Bit_ASM/FEX_bugs/LoopAddressSizeCheck.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0x0000000000000001",
"RBX": "0x0000000000010001"
},
"Mode": "32BIT"
}
%endif

; FEX-Emu had a bug where a16 loop instructions weren't treating the input RCX register as 16-bit.
; Effectively always treating it as 32-bit.
; Little test that operates at 16-bit and 32-bit sizes to ensure it is correctly handled.
mov eax, 0
mov ebx, 0
mov ecx, 0x0001_0001

.test:
inc eax
a16 loop .test

mov ecx, 0x0001_0001
.test2:
inc ebx
a32 loop .test2

hlt
25 changes: 25 additions & 0 deletions unittests/ASM/FEX_bugs/LoopAddressSizeCheck.asm
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
%ifdef CONFIG
{
"RegData": {
"RAX": "0x0000000000010001",
"RBX": "0x0000000000000001"
}
}
%endif

; FEX-Emu had a bug in the 32-bit implementation of LOOP where it didn't handle 16-bit RCX correctly.
; For test coverage on the 64-bit side, ensure that both 64-bit and 32-bit operation works correctly.
mov rax, 0
mov rbx, 0
mov rcx, 0x0001_0001

.test:
inc rax
a64 loop .test

mov rcx, 0x1_0000_0001
.test2:
inc rbx
a32 loop .test2

hlt
Loading