diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index fcf917d04..e9e134ffc 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -4307,6 +4307,50 @@ void OpDispatchBuilder::PINSROp(OpcodeArgs) { StoreResult(FPRClass, Op, ALUOp, -1); } +void OpDispatchBuilder::InsertPSOp(OpcodeArgs) { + LOGMAN_THROW_A(Op->Src[1].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_LITERAL, "Src1 needs to be literal here"); + uint8_t Imm = Op->Src[1].TypeLiteral.Literal; + uint8_t CountS = (Imm >> 6); + uint8_t CountD = (Imm >> 4) & 0b11; + uint8_t ZMask = Imm & 0xF; + + OrderedNode *Dest{}; + if (ZMask != 0xF) { + // Only need to load destination if it isn't a full zero + Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, GetDstSize(Op), Op->Flags, -1); + } + + if (!(ZMask & (1 << CountD))) { + // In the case that ZMask overwrites the destination element, then don't even insert + OrderedNode *Src{}; + if (Op->Src[0].TypeNone.Type == FEXCore::X86Tables::DecodedOperand::TYPE_GPR) { + Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + } + else { + // If loading from memory then CountS is forced to zero + CountS = 0; + Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], 4, Op->Flags, -1); + } + + Dest = _VInsElement(GetDstSize(Op), 4, CountD, CountS, Dest, Src); + } + + // ZMask happens after insert + if (ZMask == 0xF) { + Dest = _VectorImm(0, 16, 4); + } + else if (ZMask) { + auto Zero = _VectorImm(0, 16, 4); + for (size_t i = 0; i < 4; ++i) { + if (ZMask & (1 << i)) { + Dest = _VInsElement(GetDstSize(Op), 4, i, 0, Dest, Zero); + } + } + } + + StoreResult(FPRClass, Op, Dest, -1); +} + template void OpDispatchBuilder::PExtrOp(OpcodeArgs) { auto Size = GetSrcSize(Op); @@ -9357,6 +9401,7 @@ constexpr uint16_t PF_F2 = 3; {OPD(1, PF_3A_66, 0x16), 1, &OpDispatchBuilder::PExtrOp<8>}, {OPD(0, PF_3A_66, 0x20), 1, &OpDispatchBuilder::PINSROp<1>}, + {OPD(0, PF_3A_66, 0x21), 1, &OpDispatchBuilder::InsertPSOp}, {OPD(0, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<4>}, {OPD(1, PF_3A_66, 0x22), 1, &OpDispatchBuilder::PINSROp<8>}, diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 5a0efb76e..eaa4a1527 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -325,6 +325,7 @@ public: void ANDNOp(OpcodeArgs); template void PINSROp(OpcodeArgs); + void InsertPSOp(OpcodeArgs); template void PExtrOp(OpcodeArgs); template diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp index 1ed82003d..4db6d59a7 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/H0F3ATables.cpp @@ -31,7 +31,7 @@ void InitializeH0F3ATables(Context::OperatingMode Mode) { {OPD(0, PF_3A_66, 0x17), 1, X86InstInfo{"EXTRACTPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(0, PF_3A_66, 0x20), 1, X86InstInfo{"PINSRB", TYPE_INST, GenFlagsSizes(SIZE_128BIT, SIZE_8BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_SRC_GPR, 1, nullptr}}, - {OPD(0, PF_3A_66, 0x21), 1, X86InstInfo{"INSERTPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, + {OPD(0, PF_3A_66, 0x21), 1, X86InstInfo{"INSERTPS", TYPE_INST, GenFlagsSameSize(SIZE_128BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS, 1, nullptr}}, {OPD(0, PF_3A_66, 0x22), 1, X86InstInfo{"PINSRD", TYPE_INST, GenFlagsSizes(SIZE_128BIT, SIZE_32BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_SRC_GPR, 1, nullptr}}, {OPD(0, PF_3A_66, 0x40), 1, X86InstInfo{"DPPS", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, {OPD(0, PF_3A_66, 0x41), 1, X86InstInfo{"DPPD", TYPE_UNDEC, FLAGS_NONE, 0, nullptr}}, diff --git a/unittests/ASM/H0F3A/0_66_21.asm b/unittests/ASM/H0F3A/0_66_21.asm new file mode 100644 index 000000000..650e7fb91 --- /dev/null +++ b/unittests/ASM/H0F3A/0_66_21.asm @@ -0,0 +1,63 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM0": ["0x4142434465666768", "0x5152535455565758"], + "XMM1": ["0x4142434461626364", "0x5152535455565758"], + "XMM2": ["0x7576777845464748", "0x5152535455565758"], + "XMM3": ["0x4142434445464748", "0x5152535471727374"], + "XMM4": ["0x4142434445464748", "0x7576777855565758"], + "XMM5": ["0x4142434445464748", "0x5152535475767778"], + "XMM6": ["0x7576777845464748", "0x5152535455565758"], + "XMM7": ["0x4142434475767778", "0x5152535455565758"], + "XMM8": ["0x0000000065666768", "0x5152535455565758"], + "XMM9": ["0x0000000061626364", "0x5152535455565758"], + "XMM10": ["0x0000000000000000", "0x0000000000000000"] + } +} +%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 + +movapd xmm0, [rdx] +movapd xmm1, [rdx] +movapd xmm2, [rdx] +movapd xmm3, [rdx] +movapd xmm4, [rdx] +movapd xmm5, [rdx] +movapd xmm6, [rdx] +movapd xmm7, [rdx] +movapd xmm8, [rdx] +movapd xmm9, [rdx] +movapd xmm10, [rdx] +movapd xmm15, [rdx + 8 * 2] + +; Simple move Reg<-Reg +insertps xmm0, xmm15, ((0b00 << 6) | (0b00 << 4) | (0b0000)) +insertps xmm1, xmm15, ((0b01 << 6) | (0b00 << 4) | (0b0000)) +insertps xmm2, xmm15, ((0b10 << 6) | (0b01 << 4) | (0b0000)) +insertps xmm3, xmm15, ((0b11 << 6) | (0b10 << 4) | (0b0000)) + +; Simple move Reg<-Mem +insertps xmm4, [rdx + 8 * 3], ((0b00 << 6) | (0b11 << 4) | (0b0000)) +insertps xmm5, [rdx + 8 * 3], ((0b01 << 6) | (0b10 << 4) | (0b0000)) +insertps xmm6, [rdx + 8 * 3], ((0b10 << 6) | (0b01 << 4) | (0b0000)) +insertps xmm7, [rdx + 8 * 3], ((0b11 << 6) | (0b00 << 4) | (0b0000)) + +; Simple move Reg<-Reg with mask +insertps xmm8, xmm15, ((0b00 << 6) | (0b00 << 4) | (0b0010)) +insertps xmm9, xmm15, ((0b01 << 6) | (0b00 << 4) | (0b0010)) + +; Full ZMask +insertps xmm10, xmm15, ((0b00 << 6) | (0b00 << 4) | (0b1111)) + +hlt