From 4f0a8187ceb1ed93c9a7745b8fcc38599cb60575 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 9 Mar 2020 22:59:07 -0700 Subject: [PATCH 1/2] Implements support for STOS without REP flag It doesn't support REPNE so update that assert as well --- .../Interface/Core/OpcodeDispatcher.cpp | 119 +++++++++++------- 1 file changed, 73 insertions(+), 46 deletions(-) diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index c8f3c030e..3fcdfecb4 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -1748,71 +1748,98 @@ void OpDispatchBuilder::DECOp(OpcodeArgs) { } void OpDispatchBuilder::STOSOp(OpcodeArgs) { - LogMan::Throw::A(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX, "Can't handle REP not existing on STOS\n"); + LogMan::Throw::A(!(Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REPNE_PREFIX), "Invalid REPNE on STOS"); auto Size = GetSrcSize(Op); - // Create all our blocks - auto LoopHead = CreateNewCodeBlock(); - auto LoopTail = CreateNewCodeBlock(); - auto LoopEnd = CreateNewCodeBlock(); - // At the time this was written, our RA can't handle accessing nodes across blocks. - // So we need to re-load and re-calculate essential values each iteration of the loop. + bool Repeat = Op->Flags & FEXCore::X86Tables::DecodeFlags::FLAG_REP_PREFIX; - // First thing we need to do is finish this block and jump to the start of the loop. - _Jump(LoopHead); + if (!Repeat) { + OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); - SetCurrentCodeBlock(LoopHead); - { - OrderedNode *Counter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass); - auto ZeroConst = _Constant(0); + // Store to memory where RDI points + _StoreMem(GPRClass, Size, Dest, Src, Size); - // Can we end the block? - auto CanLeaveCond = _Select(FEXCore::IR::COND_EQ, - Counter, ZeroConst, - _Constant(1), ZeroConst); + auto SizeConst = _Constant(Size); + auto NegSizeConst = _Constant(-Size); - _CondJump(CanLeaveCond, LoopEnd, LoopTail); - } + // Calculate direction. + auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC); + auto PtrDir = _Select(FEXCore::IR::COND_EQ, + DF, _Constant(0), + SizeConst, NegSizeConst); - SetCurrentCodeBlock(LoopTail); - { - OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); - OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); + // Offset the pointer + OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); + TailDest = _Add(TailDest, PtrDir); + _StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest); - // Store to memory where RDI points - _StoreMem(GPRClass, Size, Dest, Src, Size); + } + else { + // Create all our blocks + auto LoopHead = CreateNewCodeBlock(); + auto LoopTail = CreateNewCodeBlock(); + auto LoopEnd = CreateNewCodeBlock(); - OrderedNode *TailCounter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass); - OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); + // At the time this was written, our RA can't handle accessing nodes across blocks. + // So we need to re-load and re-calculate essential values each iteration of the loop. - // Decrement counter - TailCounter = _Sub(TailCounter, _Constant(1)); + // First thing we need to do is finish this block and jump to the start of the loop. + _Jump(LoopHead); - // Store the counter so we don't have to deal with PHI here - _StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), TailCounter); + SetCurrentCodeBlock(LoopHead); + { + OrderedNode *Counter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass); + auto ZeroConst = _Constant(0); - auto SizeConst = _Constant(Size); - auto NegSizeConst = _Constant(-Size); + // Can we end the block? + auto CanLeaveCond = _Select(FEXCore::IR::COND_EQ, + Counter, ZeroConst, + _Constant(1), ZeroConst); - // Calculate direction. - auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC); - auto PtrDir = _Select(FEXCore::IR::COND_EQ, - DF, _Constant(0), - SizeConst, NegSizeConst); + _CondJump(CanLeaveCond, LoopEnd, LoopTail); + } - // Offset the pointer - TailDest = _Add(TailDest, PtrDir); - _StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest); + SetCurrentCodeBlock(LoopTail); + { + OrderedNode *Src = LoadSource(GPRClass, Op, Op->Src[0], Op->Flags, -1); + OrderedNode *Dest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); - // Jump back to the start, we have more work to do - _Jump(LoopHead); - } + // Store to memory where RDI points + _StoreMem(GPRClass, Size, Dest, Src, Size); - // Make sure to start a new block after ending this one + OrderedNode *TailCounter = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), GPRClass); + OrderedNode *TailDest = _LoadContext(8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), GPRClass); - SetCurrentCodeBlock(LoopEnd); + // Decrement counter + TailCounter = _Sub(TailCounter, _Constant(1)); + + // Store the counter so we don't have to deal with PHI here + _StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RCX]), TailCounter); + + auto SizeConst = _Constant(Size); + auto NegSizeConst = _Constant(-Size); + + // Calculate direction. + auto DF = GetRFLAG(FEXCore::X86State::RFLAG_DF_LOC); + auto PtrDir = _Select(FEXCore::IR::COND_EQ, + DF, _Constant(0), + SizeConst, NegSizeConst); + + // Offset the pointer + TailDest = _Add(TailDest, PtrDir); + _StoreContext(GPRClass, 8, offsetof(FEXCore::Core::CPUState, gregs[FEXCore::X86State::REG_RDI]), TailDest); + + // Jump back to the start, we have more work to do + _Jump(LoopHead); + } + + // Make sure to start a new block after ending this one + + SetCurrentCodeBlock(LoopEnd); + } } void OpDispatchBuilder::MOVSOp(OpcodeArgs) { From c51341294b4f5320e17a9ca8925a7315160556d5 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Mon, 9 Mar 2020 22:59:59 -0700 Subject: [PATCH 2/2] Adds STOS unit tests Tests all sizes that STOS supports, with the DF going up AND down. --- unittests/ASM/Primary/Primary_AA.asm | 40 +++++++++++++++++++ unittests/ASM/Primary/Primary_AA_REP.asm | 33 +++++++++++++++ unittests/ASM/Primary/Primary_AA_REP_down.asm | 33 +++++++++++++++ unittests/ASM/Primary/Primary_AB_dword.asm | 33 +++++++++++++++ .../ASM/Primary/Primary_AB_dword_REP.asm | 33 +++++++++++++++ .../ASM/Primary/Primary_AB_dword_REP_down.asm | 33 +++++++++++++++ unittests/ASM/Primary/Primary_AB_qword.asm | 32 +++++++++++++++ .../ASM/Primary/Primary_AB_qword_REP.asm | 36 +++++++++++++++++ .../ASM/Primary/Primary_AB_qword_REP_down.asm | 36 +++++++++++++++++ unittests/ASM/Primary/Primary_AB_word.asm | 35 ++++++++++++++++ unittests/ASM/Primary/Primary_AB_word_REP.asm | 33 +++++++++++++++ .../ASM/Primary/Primary_AB_word_REP_down.asm | 33 +++++++++++++++ 12 files changed, 410 insertions(+) create mode 100644 unittests/ASM/Primary/Primary_AA.asm create mode 100644 unittests/ASM/Primary/Primary_AA_REP.asm create mode 100644 unittests/ASM/Primary/Primary_AA_REP_down.asm create mode 100644 unittests/ASM/Primary/Primary_AB_dword.asm create mode 100644 unittests/ASM/Primary/Primary_AB_dword_REP.asm create mode 100644 unittests/ASM/Primary/Primary_AB_dword_REP_down.asm create mode 100644 unittests/ASM/Primary/Primary_AB_qword.asm create mode 100644 unittests/ASM/Primary/Primary_AB_qword_REP.asm create mode 100644 unittests/ASM/Primary/Primary_AB_qword_REP_down.asm create mode 100644 unittests/ASM/Primary/Primary_AB_word.asm create mode 100644 unittests/ASM/Primary/Primary_AB_word_REP.asm create mode 100644 unittests/ASM/Primary/Primary_AB_word_REP_down.asm diff --git a/unittests/ASM/Primary/Primary_AA.asm b/unittests/ASM/Primary/Primary_AA.asm new file mode 100644 index 000000000..40e7e8999 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AA.asm @@ -0,0 +1,40 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF2F2F2F2F2F2F2F2", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF2 +stosb ; rdi <- al +stosb +stosb +stosb + +stosb +stosb +stosb +stosb + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AA_REP.asm b/unittests/ASM/Primary/Primary_AA_REP.asm new file mode 100644 index 000000000..677cc959d --- /dev/null +++ b/unittests/ASM/Primary/Primary_AA_REP.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF2F2F2F2F2F2F2F2", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rcx, 8 +mov rax, 0xF2 +rep stosb ; rdi <- rsi + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AA_REP_down.asm b/unittests/ASM/Primary/Primary_AA_REP_down.asm new file mode 100644 index 000000000..408dc01f0 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AA_REP_down.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF2F2F2F2F2F2F2F2", + "RDX": "0x0", + "RDI": "0xE000000F" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2 + 7] + +std +mov rcx, 8 +mov rax, 0xF2 +rep stosb ; rdi <- rsi + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_dword.asm b/unittests/ASM/Primary/Primary_AB_dword.asm new file mode 100644 index 000000000..48d954f43 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_dword.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F1F2F3F4", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF1F2F3F4 +stosd ; rdi <- eax +stosd + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_dword_REP.asm b/unittests/ASM/Primary/Primary_AB_dword_REP.asm new file mode 100644 index 000000000..561a86aeb --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_dword_REP.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F1F2F3F4", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF1F2F3F4 +mov rcx, 2 +rep stosd ; rdi <- eax + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_dword_REP_down.asm b/unittests/ASM/Primary/Primary_AB_dword_REP_down.asm new file mode 100644 index 000000000..27872f230 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_dword_REP_down.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F1F2F3F4", + "RDX": "0x0", + "RDI": "0xE000000C" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2 + 4] + +std +mov rax, 0xF1F2F3F4 +mov rcx, 2 +rep stosd ; rdi <- eax + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_qword.asm b/unittests/ASM/Primary/Primary_AB_qword.asm new file mode 100644 index 000000000..ac6666be2 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_qword.asm @@ -0,0 +1,32 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F5F6F7F8", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF1F2F3F4F5F6F7F8 +stosq ; rdi <- rax + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_qword_REP.asm b/unittests/ASM/Primary/Primary_AB_qword_REP.asm new file mode 100644 index 000000000..52805e43b --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_qword_REP.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F5F6F7F8", + "RDX": "0xF1F2F3F4F5F6F7F8", + "RSI": "0x0", + "RDI": "0xE0000020" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax +mov [rdx + 8 * 4], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF1F2F3F4F5F6F7F8 +mov rcx, 2 +rep stosq ; rdi <- rax + +mov rax, [rdx + 8 * 2] +mov rsi, [rdx + 8 * 4] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_qword_REP_down.asm b/unittests/ASM/Primary/Primary_AB_qword_REP_down.asm new file mode 100644 index 000000000..abec1a0c1 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_qword_REP_down.asm @@ -0,0 +1,36 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F3F4F5F6F7F8", + "RDX": "0xF1F2F3F4F5F6F7F8", + "RSI": "0x0", + "RDI": "0xE0000008" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax +mov [rdx + 8 * 4], rax + +lea rdi, [rdx + 8 * 3] + +std +mov rax, 0xF1F2F3F4F5F6F7F8 +mov rcx, 2 +rep stosq ; rdi <- rax + +mov rax, [rdx + 8 * 2] +mov rsi, [rdx + 8 * 4] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_word.asm b/unittests/ASM/Primary/Primary_AB_word.asm new file mode 100644 index 000000000..dcb148cfc --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_word.asm @@ -0,0 +1,35 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F1F2F1F2F1F2", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rax, 0xF1F2 +stosw ; rdi <- ax +stosw +stosw +stosw + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_word_REP.asm b/unittests/ASM/Primary/Primary_AB_word_REP.asm new file mode 100644 index 000000000..8f0f3107f --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_word_REP.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F1F2F1F2F1F2", + "RDX": "0x0", + "RDI": "0xE0000018" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2] + +cld +mov rcx, 0x4 +mov rax, 0xF1F2 +rep stosw ; rdi <- ax + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt diff --git a/unittests/ASM/Primary/Primary_AB_word_REP_down.asm b/unittests/ASM/Primary/Primary_AB_word_REP_down.asm new file mode 100644 index 000000000..2268ca3e2 --- /dev/null +++ b/unittests/ASM/Primary/Primary_AB_word_REP_down.asm @@ -0,0 +1,33 @@ +%ifdef CONFIG +{ + "RegData": { + "RAX": "0xF1F2F1F2F1F2F1F2", + "RDX": "0x0", + "RDI": "0xE000000E" + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x4142434445464748 +mov [rdx + 8 * 0], rax +mov rax, 0x5152535455565758 +mov [rdx + 8 * 1], rax +mov rax, 0x0 +mov [rdx + 8 * 2], rax +mov [rdx + 8 * 3], rax + +lea rdi, [rdx + 8 * 2 + 6] + +std +mov rcx, 0x4 +mov rax, 0xF1F2 +rep stosw ; rdi <- ax + +mov rax, [rdx + 8 * 2] +mov rdx, [rdx + 8 * 3] +hlt