diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index d78356ba9..48a9b9cf0 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -6986,6 +6986,9 @@ constexpr uint16_t PF_F2 = 3; #define OPD(map_select, pp, opcode) (((map_select - 1) << 10) | (pp << 8) | (opcode)) constexpr std::tuple VEXTable[] = { + {OPD(1, 0b00, 0x28), 1, &OpDispatchBuilder::VMOVAPSOp}, + {OPD(1, 0b00, 0x29), 1, &OpDispatchBuilder::VMOVAPSOp}, + {OPD(1, 0b01, 0x6E), 2, &OpDispatchBuilder::UnimplementedOp}, {OPD(1, 0b10, 0x6F), 1, &OpDispatchBuilder::UnimplementedOp}, diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index a17625a4e..e1ff506f2 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -404,6 +404,9 @@ public: // ADX Ops void ADXOp(OpcodeArgs); + // AVX Ops + void VMOVAPSOp(OpcodeArgs); + // X87 Ops template void FLD(OpcodeArgs); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 4a31548b1..4b55db504 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -38,6 +38,18 @@ void OpDispatchBuilder::MOVAPSOp(OpcodeArgs) { StoreResult(FPRClass, Op, Src, -1); } +void OpDispatchBuilder::VMOVAPSOp(OpcodeArgs) { + OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + const auto Is128BitDest = GetDstSize(Op) == Core::CPUState::XMM_SSE_REG_SIZE; + + if (Op->Dest.IsGPR() && Is128BitDest) { + // Perform 32 byte store to clear the upper lane. + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Src, 32, -1); + } else { + StoreResult(FPRClass, Op, Src, -1); + } +} + void OpDispatchBuilder::MOVUPSOp(OpcodeArgs) { OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, 1); StoreResult(FPRClass, Op, Src, 1); diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp index ffa355893..3c3b20070 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/VEXTables.cpp @@ -112,10 +112,10 @@ void InitializeVEXTables() { // This table doesn't state which VEX.pp is for which instruction // XXX: Confirm all the above encoding opcodes - {OPD(1, 0b00, 0x28), 1, X86InstInfo{"VMOVAPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, + {OPD(1, 0b00, 0x28), 1, X86InstInfo{"VMOVAPS", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 0, nullptr}}, {OPD(1, 0b01, 0x28), 1, X86InstInfo{"VMOVAPD", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, - {OPD(1, 0b00, 0x29), 1, X86InstInfo{"VMOVAPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, + {OPD(1, 0b00, 0x29), 1, X86InstInfo{"VMOVAPS", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_SF_MOD_DST | FLAGS_XMM_FLAGS, 0, nullptr}}, {OPD(1, 0b01, 0x29), 1, X86InstInfo{"VMOVAPD", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(1, 0b10, 0x2A), 1, X86InstInfo{"VCVTSI2SS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, diff --git a/unittests/ASM/VEX/vmovaps.asm b/unittests/ASM/VEX/vmovaps.asm new file mode 100644 index 000000000..b76159c08 --- /dev/null +++ b/unittests/ASM/VEX/vmovaps.asm @@ -0,0 +1,26 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "XMM1": ["0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF"], + "XMM2": ["0xFFFFFFFFFFFFFFFF", "0xFFFFFFFFFFFFFFFF", "0x0000000000000000", "0x0000000000000000"], + "XMM3": ["0xCCCCCCCCCCCCCCCC", "0xCCCCCCCCCCCCCCCC", "0xCCCCCCCCCCCCCCCC", "0xCCCCCCCCCCCCCCCC"] + } +} +%endif + +lea rdx, [rel .data] + +; Load inputs +vmovaps ymm1, [rdx] +vmovaps xmm2, [rdx] +vmovaps ymm3, [rdx + 32] + +hlt + +align 32 +.data: +db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +db 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF +db 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC +db 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC diff --git a/unittests/ASM/VEX/vmovaps_mem.asm b/unittests/ASM/VEX/vmovaps_mem.asm new file mode 100644 index 000000000..ac0442a78 --- /dev/null +++ b/unittests/ASM/VEX/vmovaps_mem.asm @@ -0,0 +1,49 @@ +%ifdef CONFIG +{ + "HostFeatures": ["AVX"], + "RegData": { + "RAX": "0x6162636465666768", + "RBX": "0x7172737475767778", + "XMM0": ["0x4142434445464748", "0x5152535455565758", "0x6162636465666768", "0x7172737475767778"], + "XMM1": ["0x4142434445464748", "0x5152535455565758", "0x6162636465666768", "0x7172737475767778"], + "XMM2": ["0xCCCCCCCCCCCCCCCC", "0xDDDDDDDDDDDDDDDD", "0x0000000000000000", "0x0000000000000000"] + }, + "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, 0x6162636465666768 +mov [rdx + 8 * 2], rax +mov rax, 0x7172737475767778 +mov [rdx + 8 * 3], rax + +mov rax, 0xCCCCCCCCCCCCCCCC +mov [rdx + 8 * 4], rax +mov rax, 0xDDDDDDDDDDDDDDDD +mov [rdx + 8 * 5], rax +mov rax, 0xEEEEEEEEEEEEEEEE +mov [rdx + 8 * 6], rax +mov rax, 0xFFFFFFFFFFFFFFFF +mov [rdx + 8 * 7], rax + +; Test truncation +vmovaps ymm2, [rdx + 8 * 4] +vmovaps xmm2, [rdx + 8 * 4] + +; Test memory overwrite +vmovaps ymm0, [rdx] +vmovaps [rdx + 8 * 4], ymm0 +vmovaps ymm1, ymm0 + +mov rax, [rdx + 8 * 6] +mov rbx, [rdx + 8 * 7] + +hlt