diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 7e4c19e3a..4b5992474 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -5030,7 +5030,7 @@ OrderedNode *OpDispatchBuilder::LoadSource_WithOpSize(FEXCore::IR::RegisterClass // Now extract the subregister if it was a partial load /smaller/ than SSE size // TODO: Instead of doing the VMov implicitly on load, hunt down all use cases that require partial loads and do it after load. // We don't have information here to know if the operation needs zero upper bits or can contain data. - if (OpSize < Core::CPUState::XMM_SSE_REG_SIZE) { + if (!AllowUpperGarbage && OpSize < Core::CPUState::XMM_SSE_REG_SIZE) { Src = _VMov(OpSize, Src); } } @@ -5908,8 +5908,8 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(1, 0b00, 0x29), 1, &OpDispatchBuilder::MOVAPS_MOVAPDOp}, {OPD(1, 0b01, 0x29), 1, &OpDispatchBuilder::MOVAPS_MOVAPDOp}, - {OPD(1, 0b10, 0x2A), 1, &OpDispatchBuilder::AVXCVTGPR_To_FPR<4>}, - {OPD(1, 0b11, 0x2A), 1, &OpDispatchBuilder::AVXCVTGPR_To_FPR<8>}, + {OPD(1, 0b10, 0x2A), 1, &OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<4>}, + {OPD(1, 0b11, 0x2A), 1, &OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<8>}, {OPD(1, 0b00, 0x2B), 1, &OpDispatchBuilder::MOVVectorNTOp}, {OPD(1, 0b01, 0x2B), 1, &OpDispatchBuilder::MOVVectorNTOp}, @@ -5928,16 +5928,16 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(1, 0b00, 0x50), 1, &OpDispatchBuilder::MOVMSKOp<4>}, {OPD(1, 0b01, 0x50), 1, &OpDispatchBuilder::MOVMSKOp<8>}, - {OPD(1, 0b00, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(1, 0b01, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(1, 0b10, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(1, 0b11, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b00, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b01, 0x51), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b10, 0x51), 1, &OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp}, + {OPD(1, 0b11, 0x51), 1, &OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp}, - {OPD(1, 0b00, 0x52), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(1, 0b10, 0x52), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b00, 0x52), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b10, 0x52), 1, &OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp}, - {OPD(1, 0b00, 0x53), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(1, 0b10, 0x53), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b00, 0x53), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(1, 0b10, 0x53), 1, &OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp}, {OPD(1, 0b00, 0x54), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x54), 1, &OpDispatchBuilder::AVXVectorALUOp}, @@ -5953,18 +5953,18 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(1, 0b00, 0x58), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x58), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x58), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x58), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x58), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x58), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b00, 0x59), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x59), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x59), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x59), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x59), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x59), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b00, 0x5A), 1, &OpDispatchBuilder::Vector_CVT_Float_To_Float<8, 4>}, {OPD(1, 0b01, 0x5A), 1, &OpDispatchBuilder::Vector_CVT_Float_To_Float<4, 8>}, - {OPD(1, 0b10, 0x5A), 1, &OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<8, 4>}, - {OPD(1, 0b11, 0x5A), 1, &OpDispatchBuilder::AVXScalar_CVT_Float_To_Float<4, 8>}, + {OPD(1, 0b10, 0x5A), 1, &OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<8, 4>}, + {OPD(1, 0b11, 0x5A), 1, &OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<4, 8>}, {OPD(1, 0b00, 0x5B), 1, &OpDispatchBuilder::AVXVector_CVT_Int_To_Float<4, false>}, {OPD(1, 0b01, 0x5B), 1, &OpDispatchBuilder::AVXVector_CVT_Float_To_Int<4, false, true>}, @@ -5972,23 +5972,23 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(1, 0b00, 0x5C), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x5C), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x5C), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x5C), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x5C), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x5C), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b00, 0x5D), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x5D), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x5D), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x5D), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x5D), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x5D), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b00, 0x5E), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x5E), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x5E), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x5E), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x5E), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x5E), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b00, 0x5F), 1, &OpDispatchBuilder::AVXVectorALUOp}, {OPD(1, 0b01, 0x5F), 1, &OpDispatchBuilder::AVXVectorALUOp}, - {OPD(1, 0b10, 0x5F), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, - {OPD(1, 0b11, 0x5F), 1, &OpDispatchBuilder::AVXVectorScalarALUOp}, + {OPD(1, 0b10, 0x5F), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, + {OPD(1, 0b11, 0x5F), 1, &OpDispatchBuilder::AVXVectorScalarInsertALUOp}, {OPD(1, 0b01, 0x60), 1, &OpDispatchBuilder::VPUNPCKLOp<1>}, {OPD(1, 0b01, 0x61), 1, &OpDispatchBuilder::VPUNPCKLOp<2>}, @@ -6030,10 +6030,10 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(1, 0b01, 0x7F), 1, &OpDispatchBuilder::MOVAPS_MOVAPDOp}, {OPD(1, 0b10, 0x7F), 1, &OpDispatchBuilder::MOVUPS_MOVUPDOp}, - {OPD(1, 0b00, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<4, false>}, - {OPD(1, 0b01, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<8, false>}, - {OPD(1, 0b10, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<4, true>}, - {OPD(1, 0b11, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<8, true>}, + {OPD(1, 0b00, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<4>}, + {OPD(1, 0b01, 0xC2), 1, &OpDispatchBuilder::AVXVFCMPOp<8>}, + {OPD(1, 0b10, 0xC2), 1, &OpDispatchBuilder::AVXInsertScalarFCMPOp<4>}, + {OPD(1, 0b11, 0xC2), 1, &OpDispatchBuilder::AVXInsertScalarFCMPOp<8>}, {OPD(1, 0b01, 0xC4), 1, &OpDispatchBuilder::VPINSRWOp}, {OPD(1, 0b01, 0xC5), 1, &OpDispatchBuilder::PExtrOp<2>}, @@ -6124,9 +6124,9 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(2, 0b01, 0x18), 1, &OpDispatchBuilder::VBROADCASTOp<4>}, {OPD(2, 0b01, 0x19), 1, &OpDispatchBuilder::VBROADCASTOp<8>}, {OPD(2, 0b01, 0x1A), 1, &OpDispatchBuilder::VBROADCASTOp<16>}, - {OPD(2, 0b01, 0x1C), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(2, 0b01, 0x1D), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, - {OPD(2, 0b01, 0x1E), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(2, 0b01, 0x1C), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(2, 0b01, 0x1D), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, + {OPD(2, 0b01, 0x1E), 1, &OpDispatchBuilder::AVXVectorUnaryOp}, {OPD(2, 0b01, 0x20), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, true>}, {OPD(2, 0b01, 0x21), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, true>}, @@ -6190,10 +6190,10 @@ void OpDispatchBuilder::InstallHostSpecificOpcodeHandlers() { {OPD(3, 0b01, 0x04), 1, &OpDispatchBuilder::VPERMILImmOp<4>}, {OPD(3, 0b01, 0x05), 1, &OpDispatchBuilder::VPERMILImmOp<8>}, {OPD(3, 0b01, 0x06), 1, &OpDispatchBuilder::VPERM2Op}, - {OPD(3, 0b01, 0x08), 1, &OpDispatchBuilder::AVXVectorRound<4, false>}, - {OPD(3, 0b01, 0x09), 1, &OpDispatchBuilder::AVXVectorRound<8, false>}, - {OPD(3, 0b01, 0x0A), 1, &OpDispatchBuilder::AVXVectorRound<4, true>}, - {OPD(3, 0b01, 0x0B), 1, &OpDispatchBuilder::AVXVectorRound<8, true>}, + {OPD(3, 0b01, 0x08), 1, &OpDispatchBuilder::AVXVectorRound<4>}, + {OPD(3, 0b01, 0x09), 1, &OpDispatchBuilder::AVXVectorRound<8>}, + {OPD(3, 0b01, 0x0A), 1, &OpDispatchBuilder::AVXInsertScalarRound<4>}, + {OPD(3, 0b01, 0x0B), 1, &OpDispatchBuilder::AVXInsertScalarRound<8>}, {OPD(3, 0b01, 0x0C), 1, &OpDispatchBuilder::VPBLENDDOp}, {OPD(3, 0b01, 0x0D), 1, &OpDispatchBuilder::VBLENDPDOp}, {OPD(3, 0b01, 0x0E), 1, &OpDispatchBuilder::VPBLENDWOp}, @@ -6441,15 +6441,15 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x15, 1, &OpDispatchBuilder::PUNPCKHOp<4>}, {0x16, 2, &OpDispatchBuilder::MOVHPDOp}, {0x28, 2, &OpDispatchBuilder::MOVAPS_MOVAPDOp}, - {0x2A, 1, &OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float<4, false>}, + {0x2A, 1, &OpDispatchBuilder::InsertMMX_To_XMM_Vector_CVT_Int_To_Float}, {0x2B, 1, &OpDispatchBuilder::MOVVectorNTOp}, {0x2C, 1, &OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, false>}, {0x2D, 1, &OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<4, false, true>}, {0x2E, 2, &OpDispatchBuilder::UCOMISxOp<4>}, {0x50, 1, &OpDispatchBuilder::MOVMSKOp<4>}, - {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x52, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x53, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x52, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x53, 1, &OpDispatchBuilder::VectorUnaryOp}, {0x54, 1, &OpDispatchBuilder::VectorALUOp}, {0x55, 1, &OpDispatchBuilder::VectorALUROp}, {0x56, 1, &OpDispatchBuilder::VectorALUOp}, @@ -6481,7 +6481,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x76, 1, &OpDispatchBuilder::VectorALUOp}, {0x77, 1, &OpDispatchBuilder::X87EMMS}, - {0xC2, 1, &OpDispatchBuilder::VFCMPOp<4, false>}, + {0xC2, 1, &OpDispatchBuilder::VFCMPOp<4>}, {0xC6, 1, &OpDispatchBuilder::SHUFOp<4>}, {0xD1, 1, &OpDispatchBuilder::PSRLDOp<2>}, @@ -6668,21 +6668,21 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x12, 1, &OpDispatchBuilder::VMOVSLDUPOp}, {0x16, 1, &OpDispatchBuilder::VMOVSHDUPOp}, {0x19, 7, &OpDispatchBuilder::NOPOp}, - {0x2A, 1, &OpDispatchBuilder::CVTGPR_To_FPR<4>}, + {0x2A, 1, &OpDispatchBuilder::InsertCVTGPR_To_FPR<4>}, {0x2B, 1, &OpDispatchBuilder::MOVVectorNTOp}, {0x2C, 1, &OpDispatchBuilder::CVTFPR_To_GPR<4, false>}, {0x2D, 1, &OpDispatchBuilder::CVTFPR_To_GPR<4, true>}, - {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x52, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x53, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x58, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x59, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5A, 1, &OpDispatchBuilder::Scalar_CVT_Float_To_Float<8, 4>}, + {0x51, 1, &OpDispatchBuilder::VectorScalarUnaryInsertALUOp}, + {0x52, 1, &OpDispatchBuilder::VectorScalarUnaryInsertALUOp}, + {0x53, 1, &OpDispatchBuilder::VectorScalarUnaryInsertALUOp}, + {0x58, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x59, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5A, 1, &OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<8, 4>}, {0x5B, 1, &OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, false>}, - {0x5C, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5D, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5E, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5F, 1, &OpDispatchBuilder::VectorScalarALUOp}, + {0x5C, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5D, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5E, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5F, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, {0x6F, 1, &OpDispatchBuilder::MOVUPS_MOVUPDOp}, {0x70, 1, &OpDispatchBuilder::PSHUFWOp}, {0x7E, 1, &OpDispatchBuilder::MOVQOp}, @@ -6690,7 +6690,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xB8, 1, &OpDispatchBuilder::PopcountOp}, {0xBC, 1, &OpDispatchBuilder::TZCNT}, {0xBD, 1, &OpDispatchBuilder::LZCNT}, - {0xC2, 1, &OpDispatchBuilder::VFCMPOp<4, true>}, + {0xC2, 1, &OpDispatchBuilder::InsertScalarFCMPOp<4>}, {0xD6, 1, &OpDispatchBuilder::MOVQ2DQ}, {0xE6, 1, &OpDispatchBuilder::Vector_CVT_Int_To_Float<4, true>}, }; @@ -6699,25 +6699,25 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x10, 2, &OpDispatchBuilder::MOVSDOp}, {0x12, 1, &OpDispatchBuilder::MOVDDUPOp}, {0x19, 7, &OpDispatchBuilder::NOPOp}, - {0x2A, 1, &OpDispatchBuilder::CVTGPR_To_FPR<8>}, + {0x2A, 1, &OpDispatchBuilder::InsertCVTGPR_To_FPR<8>}, {0x2B, 1, &OpDispatchBuilder::MOVVectorOp}, {0x2C, 1, &OpDispatchBuilder::CVTFPR_To_GPR<8, false>}, {0x2D, 1, &OpDispatchBuilder::CVTFPR_To_GPR<8, true>}, - {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x51, 1, &OpDispatchBuilder::VectorScalarUnaryInsertALUOp}, //x52 = Invalid - {0x58, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x59, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5A, 1, &OpDispatchBuilder::Scalar_CVT_Float_To_Float<4, 8>}, - {0x5C, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5D, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5E, 1, &OpDispatchBuilder::VectorScalarALUOp}, - {0x5F, 1, &OpDispatchBuilder::VectorScalarALUOp}, + {0x58, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x59, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5A, 1, &OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<4, 8>}, + {0x5C, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5D, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5E, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, + {0x5F, 1, &OpDispatchBuilder::VectorScalarInsertALUOp}, {0x70, 1, &OpDispatchBuilder::PSHUFWOp}, {0x7C, 1, &OpDispatchBuilder::VectorALUOp}, {0x7D, 1, &OpDispatchBuilder::HSUBP<4>}, {0xD0, 1, &OpDispatchBuilder::ADDSUBPOp<4>}, {0xD6, 1, &OpDispatchBuilder::MOVQ2DQ}, - {0xC2, 1, &OpDispatchBuilder::VFCMPOp<8, true>}, + {0xC2, 1, &OpDispatchBuilder::InsertScalarFCMPOp<8>}, {0xE6, 1, &OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, true>}, {0xF0, 1, &OpDispatchBuilder::MOVVectorOp}, }; @@ -6730,7 +6730,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x16, 2, &OpDispatchBuilder::MOVHPDOp}, {0x19, 7, &OpDispatchBuilder::NOPOp}, {0x28, 2, &OpDispatchBuilder::MOVAPS_MOVAPDOp}, - {0x2A, 1, &OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float<4, true>}, + {0x2A, 1, &OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float}, {0x2B, 1, &OpDispatchBuilder::MOVVectorNTOp}, {0x2C, 1, &OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, false>}, {0x2D, 1, &OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int<8, true, true>}, @@ -6738,7 +6738,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x40, 16, &OpDispatchBuilder::CMOVOp}, {0x50, 1, &OpDispatchBuilder::MOVMSKOp<8>}, - {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x51, 1, &OpDispatchBuilder::VectorUnaryOp}, {0x54, 1, &OpDispatchBuilder::VectorALUOp}, {0x55, 1, &OpDispatchBuilder::VectorALUROp}, {0x56, 1, &OpDispatchBuilder::VectorALUOp}, @@ -6777,7 +6777,7 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0x7D, 1, &OpDispatchBuilder::HSUBP<8>}, {0x7E, 1, &OpDispatchBuilder::MOVBetweenGPR_FPR}, {0x7F, 1, &OpDispatchBuilder::MOVUPS_MOVUPDOp}, - {0xC2, 1, &OpDispatchBuilder::VFCMPOp<8, false>}, + {0xC2, 1, &OpDispatchBuilder::VFCMPOp<8>}, {0xC4, 1, &OpDispatchBuilder::PINSROp<2>}, {0xC5, 1, &OpDispatchBuilder::PExtrOp<2>}, {0xC6, 1, &OpDispatchBuilder::SHUFOp<8>}, @@ -7444,12 +7444,12 @@ constexpr uint16_t PF_F2 = 3; {OPD(PF_38_66, 0x14), 1, &OpDispatchBuilder::VectorVariableBlend<4>}, {OPD(PF_38_66, 0x15), 1, &OpDispatchBuilder::VectorVariableBlend<8>}, {OPD(PF_38_66, 0x17), 1, &OpDispatchBuilder::PTestOp}, - {OPD(PF_38_NONE, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_NONE, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_NONE, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, - {OPD(PF_38_66, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_NONE, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x1C), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_NONE, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x1D), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_NONE, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, + {OPD(PF_38_66, 0x1E), 1, &OpDispatchBuilder::VectorUnaryOp}, {OPD(PF_38_66, 0x20), 1, &OpDispatchBuilder::ExtendVectorElements<1, 2, true>}, {OPD(PF_38_66, 0x21), 1, &OpDispatchBuilder::ExtendVectorElements<1, 4, true>}, {OPD(PF_38_66, 0x22), 1, &OpDispatchBuilder::ExtendVectorElements<1, 8, true>}, @@ -7491,10 +7491,10 @@ constexpr uint16_t PF_F2 = 3; #define PF_3A_NONE 0 #define PF_3A_66 1 constexpr std::tuple H0F3ATable[] = { - {OPD(0, PF_3A_66, 0x08), 1, &OpDispatchBuilder::VectorRound<4, false>}, - {OPD(0, PF_3A_66, 0x09), 1, &OpDispatchBuilder::VectorRound<8, false>}, - {OPD(0, PF_3A_66, 0x0A), 1, &OpDispatchBuilder::VectorRound<4, true>}, - {OPD(0, PF_3A_66, 0x0B), 1, &OpDispatchBuilder::VectorRound<8, true>}, + {OPD(0, PF_3A_66, 0x08), 1, &OpDispatchBuilder::VectorRound<4>}, + {OPD(0, PF_3A_66, 0x09), 1, &OpDispatchBuilder::VectorRound<8>}, + {OPD(0, PF_3A_66, 0x0A), 1, &OpDispatchBuilder::InsertScalarRound<4>}, + {OPD(0, PF_3A_66, 0x0B), 1, &OpDispatchBuilder::InsertScalarRound<8>}, {OPD(0, PF_3A_66, 0x0C), 1, &OpDispatchBuilder::VectorBlend<4>}, {OPD(0, PF_3A_66, 0x0D), 1, &OpDispatchBuilder::VectorBlend<8>}, {OPD(0, PF_3A_66, 0x0E), 1, &OpDispatchBuilder::VectorBlend<2>}, @@ -7535,8 +7535,8 @@ constexpr uint16_t PF_F2 = 3; {0x1C, 1, &OpDispatchBuilder::PF2IWOp}, {0x1D, 1, &OpDispatchBuilder::Vector_CVT_Float_To_Int<4, false, false>}, - {0x86, 1, &OpDispatchBuilder::VectorUnaryOp}, - {0x87, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x86, 1, &OpDispatchBuilder::VectorUnaryOp}, + {0x87, 1, &OpDispatchBuilder::VectorUnaryOp}, {0x8A, 1, &OpDispatchBuilder::PFNACCOp}, {0x8E, 1, &OpDispatchBuilder::PFPNACCOp}, diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index 4bda4e9cf..843db8028 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -333,8 +333,6 @@ public: template void VectorALUROp(OpcodeArgs); template - void VectorScalarALUOp(OpcodeArgs); - template void VectorUnaryOp(OpcodeArgs); template void VectorUnaryDuplicateOp(OpcodeArgs); @@ -379,7 +377,6 @@ public: void Vector_CVT_Float_To_Float(OpcodeArgs); template void Vector_CVT_Float_To_Int(OpcodeArgs); - template void MMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs); template void XMM_To_MMX_Vector_CVT_Float_To_Int(OpcodeArgs); @@ -387,7 +384,7 @@ public: void MOVBetweenGPR_FPR(OpcodeArgs); void TZCNT(OpcodeArgs); void LZCNT(OpcodeArgs); - template + template void VFCMPOp(OpcodeArgs); template void SHUFOp(OpcodeArgs); @@ -424,11 +421,9 @@ public: template void AVXVectorALUOp(OpcodeArgs); template - void AVXVectorScalarALUOp(OpcodeArgs); - template void AVXVectorUnaryOp(OpcodeArgs); - template + template void AVXVectorRound(OpcodeArgs); template @@ -440,10 +435,41 @@ public: template void AVXVector_CVT_Int_To_Float(OpcodeArgs); + template + void VectorScalarInsertALUOp(OpcodeArgs); + template + void AVXVectorScalarInsertALUOp(OpcodeArgs); + + template + void VectorScalarUnaryInsertALUOp(OpcodeArgs); + template + void AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); + + void InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs); + template + void InsertCVTGPR_To_FPR(OpcodeArgs); + template + void AVXInsertCVTGPR_To_FPR(OpcodeArgs); + + template + void InsertScalar_CVT_Float_To_Float(OpcodeArgs); + template + void AVXInsertScalar_CVT_Float_To_Float(OpcodeArgs); + + template + void InsertScalarRound(OpcodeArgs); + template + void AVXInsertScalarRound(OpcodeArgs); + + template + void InsertScalarFCMPOp(OpcodeArgs); + template + void AVXInsertScalarFCMPOp(OpcodeArgs); + template void AVXCVTGPR_To_FPR(OpcodeArgs); - template + template void AVXVFCMPOp(OpcodeArgs); template @@ -787,7 +813,7 @@ public: template void ExtendVectorElements(OpcodeArgs); - template + template void VectorRound(OpcodeArgs); template @@ -889,8 +915,7 @@ private: OrderedNode *Src1, OrderedNode *Src2); void AVXVectorALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); - void AVXVectorScalarALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); - void AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize, bool Scalar); + void AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); template void AVXVectorVariableBlend(OpcodeArgs); @@ -997,19 +1022,63 @@ private: void MOVScalarOpImpl(OpcodeArgs, size_t ElementSize); void VMOVScalarOpImpl(OpcodeArgs, size_t ElementSize); - OrderedNode* VFCMPOpImpl(OpcodeArgs, size_t ElementSize, bool Scalar, + OrderedNode* VFCMPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode *Src1, OrderedNode *Src2, uint8_t CompType); void VTESTOpImpl(OpcodeArgs, size_t ElementSize); void VectorALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); void VectorALUROpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); - void VectorScalarALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); - void VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize, bool Scalar); + void VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); void VectorUnaryDuplicateOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize); + // x86 ALU scalar operations operate in three different ways + // - AVX512: Writemask shenanigans that we don't care about. + // - AVX/VEX: Two source + // - Example 32bit VADDSS Dest, Src1, Src2 + // - Dest[31:0] = Src1[31:0] + Src2[31:0] + // - Dest[127:32] = Src1[127:32] + // - SSE: Scalar operation inserts in to the low bits, upper bits completely unaffected. + // - Example 32bit ADDSS Dest, Src + // - Dest[31:0] = Dest[31:0] + Src[31:0] + // - Dest[{256,128}:32] = (Unmodified) + OrderedNode* VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits); + + OrderedNode* VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits); + + OrderedNode* InsertCVTGPR_To_FPRImpl(OpcodeArgs, + size_t DstSize, size_t DstElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits); + + OrderedNode* InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, + size_t DstSize, size_t DstElementSize, size_t SrcElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits); + OrderedNode* InsertScalarRoundImpl(OpcodeArgs, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + uint64_t Mode, bool ZeroUpperBits); + + OrderedNode* InsertScalarFCMPOpImpl(OpcodeArgs, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + uint8_t CompType, bool ZeroUpperBits); + OrderedNode* VectorRoundImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Mode, bool IsScalar); + OrderedNode *Src, uint64_t Mode); OrderedNode* Scalar_CVT_Float_To_FloatImpl(OpcodeArgs, size_t DstElementSize, size_t SrcElementSize, const X86Tables::DecodedOperand& Src1Op, @@ -1067,6 +1136,10 @@ private: void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, FEXCore::X86Tables::DecodedOperand const& Operand, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::ACCESS_DEFAULT); void StoreResult(FEXCore::IR::RegisterClassType Class, FEXCore::X86Tables::DecodedOp Op, OrderedNode *const Src, int8_t Align, MemoryAccessType AccessType = MemoryAccessType::ACCESS_DEFAULT); + constexpr OpSize GetGuestVectorLength() const { + return CTX->HostFeatures.SupportsAVX ? OpSize::i256Bit : OpSize::i128Bit; + } + [[nodiscard]] static uint32_t GPROffset(X86State::X86Reg reg) { LOGMAN_THROW_AA_FMT(reg <= X86State::X86Reg::REG_R15, "Invalid reg used"); return static_cast(offsetof(Core::CPUState, gregs[static_cast(reg)])); diff --git a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp index 2e270c110..cd3f7d1c5 100644 --- a/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp +++ b/FEXCore/Source/Interface/Core/OpcodeDispatcher/Vector.cpp @@ -500,236 +500,487 @@ void OpDispatchBuilder::VectorALUROp(OpcodeArgs); template void OpDispatchBuilder::VectorALUROp(OpcodeArgs); -void OpDispatchBuilder::VectorScalarALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { +OrderedNode* OpDispatchBuilder::VectorScalarInsertALUOpImpl(OpcodeArgs, IROps IROp, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. - const auto SrcSize = Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); + + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, -1, true, false, MemoryAccessType::ACCESS_DEFAULT, true); + + // If OpSize == ElementSize then it only does the lower scalar op + auto ALUOp = _VFAddScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, ZeroUpperBits); + // Overwrite our IR's op type + ALUOp.first->Header.Op = IROp; + + return ALUOp; +} + +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Dest, Op->Src[0], false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Src[0], Op->Src[1], true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarInsertALUOp(OpcodeArgs); + +OrderedNode* OpDispatchBuilder::VectorScalarUnaryInsertALUOpImpl(OpcodeArgs, IROps IROp, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits) { + // We load the full vector width when dealing with a source vector, + // so that we don't do any unnecessary zero extension to the scalar + // element that we're going to operate on. + const auto SrcSize = GetSrcSize(Op); + + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, -1, true, false, MemoryAccessType::ACCESS_DEFAULT, true); + + // If OpSize == ElementSize then it only does the lower scalar op + auto ALUOp = _VFSqrtScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, ZeroUpperBits); + // Overwrite our IR's op type + ALUOp.first->Header.Op = IROp; + + return ALUOp; +} + +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Dest, Op->Src[0], false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorScalarUnaryInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + auto Result = VectorScalarInsertALUOpImpl(Op, IROp, DstSize, ElementSize, Op->Src[0], Op->Src[1], true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); + +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); +template +void OpDispatchBuilder::AVXVectorScalarUnaryInsertALUOp(OpcodeArgs); + +void OpDispatchBuilder::InsertMMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { + // We load the full vector width when dealing with a source vector, + // so that we don't do any unnecessary zero extension to the scalar + // element that we're going to operate on. + const auto DstSize = GetGuestVectorLength(); + const auto SrcSize = Op->Src[0].IsGPR() ? 8 : GetSrcSize(Op); OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags, -1); OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); - // If OpSize == ElementSize then it only does the lower scalar op - auto ALUOp = _VAdd(ElementSize, ElementSize, Dest, Src); - // Overwrite our IR's op type - ALUOp.first->Header.Op = IROp; + // Always 32-bit. + const size_t ElementSize = 4; + // Always signed + Dest = _VSToFVectorInsert(IR::SizeToOpSize(DstSize), ElementSize, ElementSize, Dest, Src, true, false); - OrderedNode* Result = ALUOp; - - if (DstSize != ElementSize) { - // Insert the lower bits - Result = _VInsElement(DstSize, ElementSize, 0, 0, Dest, ALUOp); - } - - StoreResult(FPRClass, Op, Result, -1); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Dest, DstSize, -1); } -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs) { - VectorScalarALUOpImpl(Op, IROp, ElementSize); -} - -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorScalarALUOp(OpcodeArgs); - -void OpDispatchBuilder::AVXVectorScalarALUOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { +OrderedNode* OpDispatchBuilder::InsertCVTGPR_To_FPRImpl(OpcodeArgs, + size_t DstSize, size_t DstElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits) { // We load the full vector width when dealing with a source vector, // so that we don't do any unnecessary zero extension to the scalar // element that we're going to operate on. - const auto SrcSize = Op->Src[1].IsGPR() ? 16U : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags, -1); - OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], SrcSize, Op->Flags, -1); + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); - // If OpSize == ElementSize then it only does the lower scalar op - auto ALUOp = _VAdd(ElementSize, ElementSize, Src1, Src2); - // Overwrite our IR's op type - ALUOp.first->Header.Op = IROp; - - OrderedNode* Result = ALUOp; - - if (DstSize != ElementSize) { - // Insert the lower bits - Result = _VInsElement(DstSize, ElementSize, 0, 0, Src1, ALUOp); + if (Src2Op.IsGPR()) { + // If the source is a GPR then convert directly from the GPR. + auto Src2 = LoadSource_WithOpSize(GPRClass, Op, Src2Op, CTX->GetGPRSize(), Op->Flags, -1); + return _VSToFGPRInsert(IR::SizeToOpSize(DstSize), DstElementSize, SrcSize, Src1, Src2, ZeroUpperBits); + } + else if (SrcSize != DstElementSize) { + // If the source is from memory but the Source size and destination size aren't the same, + // then it is more optimal to load in to a GPR and convert between GPR->FPR. + // ARM GPR->FPR conversion supports different size source and destinations while FPR->FPR doesn't. + auto Src2 = LoadSource(GPRClass, Op, Src2Op, Op->Flags, -1); + return _VSToFGPRInsert(IR::SizeToOpSize(DstSize), DstElementSize, SrcSize, Src1, Src2, ZeroUpperBits); } - StoreResult(FPRClass, Op, Result, -1); + // In the case of cvtsi2s{s,d} where the source and destination are the same size, + // then it is more optimal to load in to the FPR register directly and convert there. + auto Src2 = LoadSource(FPRClass, Op, Src2Op, Op->Flags, -1); + // Always signed + return _VSToFVectorInsert(IR::SizeToOpSize(DstSize), DstElementSize, DstElementSize, Src1, Src2, false, ZeroUpperBits); } -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs) { - AVXVectorScalarALUOpImpl(Op, IROp, ElementSize); +template +void OpDispatchBuilder::InsertCVTGPR_To_FPR(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + auto Result = InsertCVTGPR_To_FPRImpl(Op, DstSize, DstElementSize, Op->Dest, Op->Src[0], false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); } template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); +void OpDispatchBuilder::InsertCVTGPR_To_FPR<4>(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorScalarALUOp(OpcodeArgs); +void OpDispatchBuilder::InsertCVTGPR_To_FPR<8>(OpcodeArgs); -void OpDispatchBuilder::VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize, bool Scalar) { +template +void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertCVTGPR_To_FPRImpl(Op, DstSize, DstElementSize, Op->Src[0], Op->Src[1], true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} +template +void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<4>(OpcodeArgs); +template +void OpDispatchBuilder::AVXInsertCVTGPR_To_FPR<8>(OpcodeArgs); + +OrderedNode* OpDispatchBuilder::InsertScalar_CVT_Float_To_FloatImpl(OpcodeArgs, + size_t DstSize, size_t DstElementSize, size_t SrcElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + bool ZeroUpperBits) { + + // We load the full vector width when dealing with a source vector, + // so that we don't do any unnecessary zero extension to the scalar + // element that we're going to operate on. + const auto SrcSize = GetSrcSize(Op); + + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, -1, true, false, MemoryAccessType::ACCESS_DEFAULT, true); + + return _VFToFScalarInsert(IR::SizeToOpSize(DstSize), DstElementSize, SrcElementSize, Src1, Src2, ZeroUpperBits); +} + +template +void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Dest, Op->Src[0], false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template +void OpDispatchBuilder::InsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); + +template +void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float(OpcodeArgs) { + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalar_CVT_Float_To_FloatImpl(Op, DstSize, DstElementSize, SrcElementSize, Op->Src[0], Op->Src[1], true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<4, 8>(OpcodeArgs); +template +void OpDispatchBuilder::AVXInsertScalar_CVT_Float_To_Float<8, 4>(OpcodeArgs); + +OrderedNode* OpDispatchBuilder::InsertScalarRoundImpl(OpcodeArgs, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + uint64_t Mode, bool ZeroUpperBits) { + // We load the full vector width when dealing with a source vector, + // so that we don't do any unnecessary zero extension to the scalar + // element that we're going to operate on. + const auto SrcSize = GetSrcSize(Op); + + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, -1, true, false, MemoryAccessType::ACCESS_DEFAULT, true); + + const uint64_t RoundControlSource = (Mode >> 2) & 1; + uint64_t RoundControl = Mode & 0b11; + + static constexpr std::array SourceModes = { + FEXCore::IR::Round_Nearest, + FEXCore::IR::Round_Negative_Infinity, + FEXCore::IR::Round_Positive_Infinity, + FEXCore::IR::Round_Towards_Zero, + }; + + const auto SourceMode = RoundControlSource ? Round_Host : SourceModes[RoundControl]; + + auto ALUOp = _VFToIScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, SourceMode, ZeroUpperBits); + + return ALUOp; +} + +template +void OpDispatchBuilder::InsertScalarRound(OpcodeArgs) { + LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); + const uint64_t Mode = Op->Src[1].Data.Literal.Value; + + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::InsertScalarRound<4>(OpcodeArgs); +template +void OpDispatchBuilder::InsertScalarRound<8>(OpcodeArgs); + +template +void OpDispatchBuilder::AVXInsertScalarRound(OpcodeArgs) { + LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src1 needs to be literal here"); + const uint64_t Mode = Op->Src[2].Data.Literal.Value; + + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalarRoundImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], Mode, true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::AVXInsertScalarRound<4>(OpcodeArgs); +template +void OpDispatchBuilder::AVXInsertScalarRound<8>(OpcodeArgs); + + +OrderedNode* OpDispatchBuilder::InsertScalarFCMPOpImpl(OpcodeArgs, + size_t DstSize, size_t ElementSize, + const X86Tables::DecodedOperand& Src1Op, + const X86Tables::DecodedOperand& Src2Op, + uint8_t CompType, bool ZeroUpperBits) { + // We load the full vector width when dealing with a source vector, + // so that we don't do any unnecessary zero extension to the scalar + // element that we're going to operate on. + const auto SrcSize = GetSrcSize(Op); + + OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Src1Op, DstSize, Op->Flags, -1); + OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Src2Op, SrcSize, Op->Flags, -1, true, false, MemoryAccessType::ACCESS_DEFAULT, true); + + switch (CompType) { + case 0x00: case 0x08: case 0x10: case 0x18: // EQ + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::EQ, ZeroUpperBits); + case 0x01: case 0x09: case 0x11: case 0x19: // LT, GT(Swapped operand) + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LT, ZeroUpperBits); + case 0x02: case 0x0A: case 0x12: case 0x1A: // LE, GE(Swapped operand) + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::LE, ZeroUpperBits); + case 0x03: case 0x0B: case 0x13: case 0x1B: // Unordered + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::UNO, ZeroUpperBits); + case 0x04: case 0x0C: case 0x14: case 0x1C: // NEQ + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::NEQ, ZeroUpperBits); + case 0x05: case 0x0D: case 0x15: case 0x1D: { // NLT, NGT(Swapped operand) + OrderedNode *Result = _VFCMPLT(ElementSize, ElementSize, Src1, Src2); + Result = _VNot(ElementSize, ElementSize, Result); + // Insert the lower bits + return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); + } + case 0x06: case 0x0E: case 0x16: case 0x1E: { // NLE, NGE(Swapped operand) + OrderedNode *Result = _VFCMPLE(ElementSize, ElementSize, Src1, Src2); + Result = _VNot(ElementSize, ElementSize, Result); + // Insert the lower bits + return _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); + } + case 0x07: case 0x0F: case 0x17: case 0x1F: // Ordered + return _VFCMPScalarInsert(IR::SizeToOpSize(DstSize), ElementSize, Src1, Src2, FloatCompareOp::ORD, ZeroUpperBits); + default: + LOGMAN_MSG_A_FMT("Unknown Comparison type: {}", CompType); + break; + } + FEX_UNREACHABLE; +} + +template +void OpDispatchBuilder::InsertScalarFCMPOp(OpcodeArgs) { + LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src[2] needs to be literal"); + const uint8_t CompType = Op->Src[1].Data.Literal.Value; + + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Dest, Op->Src[0], CompType, false); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::InsertScalarFCMPOp<4>(OpcodeArgs); +template +void OpDispatchBuilder::InsertScalarFCMPOp<8>(OpcodeArgs); + +template +void OpDispatchBuilder::AVXInsertScalarFCMPOp(OpcodeArgs) { + LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal"); + const uint8_t CompType = Op->Src[2].Data.Literal.Value; + + const auto DstSize = GetGuestVectorLength(); + OrderedNode *Result = InsertScalarFCMPOpImpl(Op, DstSize, ElementSize, Op->Src[0], Op->Src[1], CompType, true); + StoreResult_WithOpSize(FPRClass, Op, Op->Dest, Result, DstSize, -1); +} + +template +void OpDispatchBuilder::AVXInsertScalarFCMPOp<4>(OpcodeArgs); +template +void OpDispatchBuilder::AVXInsertScalarFCMPOp<8>(OpcodeArgs); + +void OpDispatchBuilder::VectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { // In the event of a scalar operation and a vector source, then // we can specify the entire vector length in order to avoid // unnecessary sign extension on the element to be operated on. // In the event of a memory operand, we load the exact element size. - const auto SrcSize = Scalar && Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - const auto OpSize = Scalar ? ElementSize : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); + const auto OpSize = GetSrcSize(Op); OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags, -1); auto ALUOp = _VFSqrt(OpSize, ElementSize, Src); // Overwrite our IR's op type ALUOp.first->Header.Op = IROp; - if (Scalar) { - // Insert the lower bits - auto Result = _VInsElement(DstSize, ElementSize, 0, 0, Dest, ALUOp); - StoreResult(FPRClass, Op, Result, -1); - } else { - StoreResult(FPRClass, Op, ALUOp, -1); - } + StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs) { - VectorUnaryOpImpl(Op, IROp, ElementSize, Scalar); + VectorUnaryOpImpl(Op, IROp, ElementSize); } template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); +template +void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::VectorUnaryOp(OpcodeArgs); - -void OpDispatchBuilder::AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize, bool Scalar) { +void OpDispatchBuilder::AVXVectorUnaryOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { // In the event of a scalar operation and a vector source, then // we can specify the entire vector length in order to avoid // unnecessary sign extension on the element to be operated on. // In the event of a memory operand, we load the exact element size. - const auto SrcSize = Scalar && Op->Src[1].IsGPR() ? 16U : GetSrcSize(Op); - const auto OpSize = Scalar ? ElementSize : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); + const auto OpSize = GetSrcSize(Op); - OrderedNode *Src = [&] { - const auto SrcIndex = Scalar ? 1 : 0; - return LoadSource_WithOpSize(FPRClass, Op, Op->Src[SrcIndex], SrcSize, Op->Flags, -1); - }(); - OrderedNode *Dest = [&] { - const auto& Operand = Scalar ? Op->Src[0] : Op->Dest; - return LoadSource_WithOpSize(FPRClass, Op, Operand, DstSize, Op->Flags, -1); - }(); + OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); auto ALUOp = _VFSqrt(OpSize, ElementSize, Src); // Overwrite our IR's op type ALUOp.first->Header.Op = IROp; - OrderedNode* Result = ALUOp; - if (Scalar) { - // Insert the lower bits - Result = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Result); - } - // NOTE: We don't need to clear the upper lanes here, since the // IR ops make use of 128-bit AdvSimd for 128-bit cases, // which, on hardware with SVE, zero-extends as part of // storing into the destination. - StoreResult(FPRClass, Op, Result, -1); + StoreResult(FPRClass, Op, ALUOp, -1); } -template +template void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs) { - AVXVectorUnaryOpImpl(Op, IROp, ElementSize, Scalar); + AVXVectorUnaryOpImpl(Op, IROp, ElementSize); } template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); +void OpDispatchBuilder::AVXVectorUnaryOp(OpcodeArgs); void OpDispatchBuilder::VectorUnaryDuplicateOpImpl(OpcodeArgs, IROps IROp, size_t ElementSize) { const auto Size = GetSrcSize(Op); @@ -2411,38 +2662,22 @@ void OpDispatchBuilder::Vector_CVT_Float_To_Float<4, 8>(OpcodeArgs); template void OpDispatchBuilder::Vector_CVT_Float_To_Float<8, 4>(OpcodeArgs); -template void OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float(OpcodeArgs) { OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); - size_t ElementSize = SrcElementSize; + // Always 32-bit. + size_t ElementSize = 4; size_t DstSize = GetDstSize(Op); - if constexpr (Widen) { - Src = _VSXTL(DstSize, ElementSize, Src); - ElementSize <<= 1; - } + + Src = _VSXTL(DstSize, ElementSize, Src); + ElementSize <<= 1; // Always signed Src = _Vector_SToF(DstSize, ElementSize, Src); - OrderedNode *Dest{}; - if constexpr (Widen) { - Dest = Src; - } - else { - Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags, -1); - // Insert the lower bits - Dest = _VInsElement(GetDstSize(Op), 8, 0, 0, Dest, Src); - } - - StoreResult(FPRClass, Op, Dest, -1); + StoreResult(FPRClass, Op, Src, -1); } -template -void OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float<4, false>(OpcodeArgs); -template -void OpDispatchBuilder::MMX_To_XMM_Vector_CVT_Int_To_Float<4, true>(OpcodeArgs); - template void OpDispatchBuilder::XMM_To_MMX_Vector_CVT_Float_To_Int(OpcodeArgs) { // If loading a vector, use the full size, so we don't @@ -2578,7 +2813,7 @@ void OpDispatchBuilder::MOVBetweenGPR_FPR(OpcodeArgs) { } } -OrderedNode* OpDispatchBuilder::VFCMPOpImpl(OpcodeArgs, size_t ElementSize, bool Scalar, +OrderedNode* OpDispatchBuilder::VFCMPOpImpl(OpcodeArgs, size_t ElementSize, OrderedNode *Src1, OrderedNode *Src2, uint8_t CompType) { const auto Size = GetSrcSize(Op); @@ -2615,44 +2850,35 @@ OrderedNode* OpDispatchBuilder::VFCMPOpImpl(OpcodeArgs, size_t ElementSize, bool break; } - if (Scalar) { - // Insert the lower bits - Result = _VInsElement(GetDstSize(Op), ElementSize, 0, 0, Src1, Result); - } - return Result; } -template +template void OpDispatchBuilder::VFCMPOp(OpcodeArgs) { // No need for zero-extending in the scalar case, since // all we need is an insert at the end of the operation. - const auto SrcSize = Scalar && Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); + const auto SrcSize = GetSrcSize(Op); const auto DstSize = GetDstSize(Op); OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags, -1); const uint8_t CompType = Op->Src[1].Data.Literal.Value; - OrderedNode* Result = VFCMPOpImpl(Op, ElementSize, Scalar, Dest, Src, CompType); + OrderedNode* Result = VFCMPOpImpl(Op, ElementSize, Dest, Src, CompType); StoreResult(FPRClass, Op, Result, -1); } template -void OpDispatchBuilder::VFCMPOp<4, false>(OpcodeArgs); +void OpDispatchBuilder::VFCMPOp<4>(OpcodeArgs); template -void OpDispatchBuilder::VFCMPOp<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::VFCMPOp<8, false>(OpcodeArgs); -template -void OpDispatchBuilder::VFCMPOp<8, true>(OpcodeArgs); +void OpDispatchBuilder::VFCMPOp<8>(OpcodeArgs); -template +template void OpDispatchBuilder::AVXVFCMPOp(OpcodeArgs) { // No need for zero-extending in the scalar case, since // all we need is an insert at the end of the operation. - const auto SrcSize = Scalar && Op->Src[1].IsGPR() ? 16U : GetSrcSize(Op); + const auto SrcSize = GetSrcSize(Op); const auto DstSize = GetDstSize(Op); LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src[2] needs to be literal"); @@ -2660,19 +2886,15 @@ void OpDispatchBuilder::AVXVFCMPOp(OpcodeArgs) { OrderedNode *Src1 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags, -1); OrderedNode *Src2 = LoadSource_WithOpSize(FPRClass, Op, Op->Src[1], SrcSize, Op->Flags, -1); - OrderedNode *Result = VFCMPOpImpl(Op, ElementSize, Scalar, Src1, Src2, CompType); + OrderedNode *Result = VFCMPOpImpl(Op, ElementSize, Src1, Src2, CompType); StoreResult(FPRClass, Op, Result, -1); } template -void OpDispatchBuilder::AVXVFCMPOp<4, false>(OpcodeArgs); +void OpDispatchBuilder::AVXVFCMPOp<4>(OpcodeArgs); template -void OpDispatchBuilder::AVXVFCMPOp<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVFCMPOp<8, false>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVFCMPOp<8, true>(OpcodeArgs); +void OpDispatchBuilder::AVXVFCMPOp<8>(OpcodeArgs); void OpDispatchBuilder::FXSaveOp(OpcodeArgs) { OrderedNode *Mem = LoadSource(GPRClass, Op, Op->Dest, Op->Flags, -1, false); @@ -3928,8 +4150,7 @@ template void OpDispatchBuilder::ExtendVectorElements<4, 8, true>(OpcodeArgs); OrderedNode* OpDispatchBuilder::VectorRoundImpl(OpcodeArgs, size_t ElementSize, - OrderedNode *Src, uint64_t Mode, - bool IsScalar) { + OrderedNode *Src, uint64_t Mode) { const auto Size = GetDstSize(Op); const uint64_t RoundControlSource = (Mode >> 2) & 1; uint64_t RoundControl = Mode & 0b11; @@ -3947,82 +4168,48 @@ OrderedNode* OpDispatchBuilder::VectorRoundImpl(OpcodeArgs, size_t ElementSize, }; const auto SourceMode = SourceModes[(RoundControlSource << 2) | RoundControl]; - const auto OpSize = IsScalar ? ElementSize : Size; - return _Vector_FToI(OpSize, ElementSize, Src, SourceMode); + return _Vector_FToI(Size, ElementSize, Src, SourceMode); } -template +template void OpDispatchBuilder::VectorRound(OpcodeArgs) { // No need to zero extend the vector in the event we have a // scalar source, especially since it's only inserted into another vector. - const auto SrcSize = Scalar && Op->Src[0].IsGPR() ? 16U : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); const uint64_t Mode = Op->Src[1].Data.Literal.Value; - Src = VectorRoundImpl(Op, ElementSize, Src, Mode, Scalar); + Src = VectorRoundImpl(Op, ElementSize, Src, Mode); - if constexpr (Scalar) { - // Insert the lower bits - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Dest, DstSize, Op->Flags, -1); - auto Result = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Src); - StoreResult(FPRClass, Op, Result, -1); - } else { - StoreResult(FPRClass, Op, Src, -1); - } + StoreResult(FPRClass, Op, Src, -1); } template -void OpDispatchBuilder::VectorRound<4, false>(OpcodeArgs); +void OpDispatchBuilder::VectorRound<4>(OpcodeArgs); template -void OpDispatchBuilder::VectorRound<8, false>(OpcodeArgs); +void OpDispatchBuilder::VectorRound<8>(OpcodeArgs); -template -void OpDispatchBuilder::VectorRound<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::VectorRound<8, true>(OpcodeArgs); - -template +template void OpDispatchBuilder::AVXVectorRound(OpcodeArgs) { - const auto GetMode = [&] { - if constexpr (Scalar) { - LOGMAN_THROW_A_FMT(Op->Src[2].IsLiteral(), "Src2 needs to be literal here"); - return Op->Src[2].Data.Literal.Value; - } else { - LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); - return Op->Src[1].Data.Literal.Value; - } - }; + LOGMAN_THROW_A_FMT(Op->Src[1].IsLiteral(), "Src1 needs to be literal here"); + const auto Mode = Op->Src[1].Data.Literal.Value; // No need to zero extend the vector in the event we have a // scalar source, especially since it's only inserted into another vector. - const auto SrcIdx = Scalar ? 1 : 0; - const auto SrcSize = Scalar && Op->Src[SrcIdx].IsGPR() ? 16U : GetSrcSize(Op); - const auto DstSize = GetDstSize(Op); + const auto SrcSize = GetSrcSize(Op); - OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[SrcIdx], SrcSize, Op->Flags, -1); - OrderedNode *Result = VectorRoundImpl(Op, ElementSize, Src, GetMode(), Scalar); - - if constexpr (Scalar) { - // Insert the lower bits - OrderedNode *Dest = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], DstSize, Op->Flags, -1); - Result = _VInsElement(DstSize, ElementSize, 0, 0, Dest, Result); - } + OrderedNode *Src = LoadSource_WithOpSize(FPRClass, Op, Op->Src[0], SrcSize, Op->Flags, -1); + OrderedNode *Result = VectorRoundImpl(Op, ElementSize, Src, Mode); StoreResult(FPRClass, Op, Result, -1); } template -void OpDispatchBuilder::AVXVectorRound<4, false>(OpcodeArgs); +void OpDispatchBuilder::AVXVectorRound<4>(OpcodeArgs); template -void OpDispatchBuilder::AVXVectorRound<8, false>(OpcodeArgs); - -template -void OpDispatchBuilder::AVXVectorRound<4, true>(OpcodeArgs); -template -void OpDispatchBuilder::AVXVectorRound<8, true>(OpcodeArgs); +void OpDispatchBuilder::AVXVectorRound<8>(OpcodeArgs); template void OpDispatchBuilder::VectorBlend(OpcodeArgs) {