diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index 3db3cffdd..cefd95128 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -304,7 +304,33 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { } break; } + case IR::OP_VEXTRACTELEMENT: { + auto Op = IROp->C(); + LogMan::Throw::A(Op->RegisterSize <= 16, "OpSize is too large for VExtractToGPR: %d", OpSize); + if (Op->RegisterSize == 16) { + __uint128_t SourceMask = (1ULL << (Op->ElementSize * 8)) - 1; + uint64_t Shift = Op->ElementSize * Op->Index * 8; + if (Op->ElementSize == 8) + SourceMask = ~0ULL; + __uint128_t Src = *GetSrc<__uint128_t*>(Op->Header.Args[0]); + Src >>= Shift; + Src &= SourceMask; + memcpy(GDP, &Src, Op->ElementSize); + } + else { + uint64_t SourceMask = (1ULL << (Op->ElementSize * 8)) - 1; + uint64_t Shift = Op->ElementSize * Op->Index * 8; + if (Op->ElementSize == 8) + SourceMask = ~0ULL; + + uint64_t Src = *GetSrc(Op->Header.Args[0]); + Src >>= Shift; + Src &= SourceMask; + GD = Src; + } + break; + } case IR::OP_CONSTANT: { auto Op = IROp->C(); GD = Op->Constant; @@ -2813,6 +2839,44 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->RegisterSize); break; } + case IR::OP_VINSSCALARELEMENT: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t Tmp[16]; + + // Copy src1 in to dest + memcpy(Tmp, Src1, Op->RegisterSize); + switch (Op->ElementSize) { + case 1: { + auto *Dst_d = reinterpret_cast(Tmp); + auto Src2_d = *reinterpret_cast(Src2); + Dst_d[Op->DestIdx] = Src2_d; + break; + } + case 2: { + auto *Dst_d = reinterpret_cast(Tmp); + auto Src2_d = *reinterpret_cast(Src2); + Dst_d[Op->DestIdx] = Src2_d; + break; + } + case 4: { + auto *Dst_d = reinterpret_cast(Tmp); + auto Src2_d = *reinterpret_cast(Src2); + Dst_d[Op->DestIdx] = Src2_d; + break; + } + case 8: { + auto *Dst_d = reinterpret_cast(Tmp); + auto Src2_d = *reinterpret_cast(Src2); + Dst_d[Op->DestIdx] = Src2_d; + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + }; + memcpy(GDP, Tmp, Op->RegisterSize); + break; + } case IR::OP_VCMPEQ: { auto Op = IROp->C(); void *Src1 = GetSrc(Op->Header.Args[0]); diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp index 4b95ba458..466abc847 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/JIT.cpp @@ -530,6 +530,25 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const } break; } + case IR::OP_VEXTRACTELEMENT: { + auto Op = IROp->C(); + switch (OpSize) { + case 1: + mov(GetDst(Node).B(), GetSrc(Op->Header.Args[0].ID()).V16B(), Op->Index); + break; + case 2: + mov(GetDst(Node).H(), GetSrc(Op->Header.Args[0].ID()).V8H(), Op->Index); + break; + case 4: + mov(GetDst(Node).S(), GetSrc(Op->Header.Args[0].ID()).V4S(), Op->Index); + break; + case 8: + mov(GetDst(Node).D(), GetSrc(Op->Header.Args[0].ID()).V2D(), Op->Index); + break; + default: LogMan::Msg::A("Unhandled ExtractElementSize: %d", OpSize); + } + break; + } case IR::OP_JUMP: { auto Op = IROp->C(); @@ -2042,6 +2061,31 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const mov(GetDst(Node), VTMP1); break; } + case IR::OP_VINSSCALARELEMENT: { + auto Op = IROp->C(); + mov(VTMP1, GetSrc(Op->Header.Args[0].ID())); + switch (Op->ElementSize) { + case 1: { + mov(VTMP1.V16B(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V16B(), 0); + break; + } + case 2: { + mov(VTMP1.V8H(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V8H(), 0); + break; + } + case 4: { + mov(VTMP1.V4S(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V4S(), 0); + break; + } + case 8: { + mov(VTMP1.V2D(), Op->DestIdx, GetSrc(Op->Header.Args[1].ID()).V2D(), 0); + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + mov(GetDst(Node), VTMP1); + break; + } case IR::OP_VNOT: { auto Op = IROp->C(); mvn(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B()); diff --git a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp index 7e39345e8..4d2a4b5d6 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -2000,6 +2000,70 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const movapd(GetDst(Node), xmm15); break; } + case IR::OP_VINSSCALARELEMENT: { + auto Op = IROp->C(); + movapd(xmm15, GetSrc(Op->Header.Args[0].ID())); + + // Dst_d[Op->DestIdx] = Src2_d[Op->SrcIdx]; + + // pextrq reg64/mem64, xmm, imm + // pinsrq xmm, reg64/mem64, imm8 + switch (Op->ElementSize) { + case 1: { + pextrb(eax, GetSrc(Op->Header.Args[1].ID()), 0); + pinsrb(xmm15, eax, Op->DestIdx); + break; + } + case 2: { + pextrw(eax, GetSrc(Op->Header.Args[1].ID()), 0); + pinsrw(xmm15, eax, Op->DestIdx); + break; + } + case 4: { + pextrd(eax, GetSrc(Op->Header.Args[1].ID()), 0); + pinsrd(xmm15, eax, Op->DestIdx); + break; + } + case 8: { + pextrq(rax, GetSrc(Op->Header.Args[1].ID()), 0); + pinsrq(xmm15, rax, Op->DestIdx); + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + + movapd(GetDst(Node), xmm15); + break; + } + case IR::OP_VEXTRACTELEMENT: { + auto Op = IROp->C(); + + switch (Op->ElementSize) { + case 1: { + pextrb(eax, GetSrc(Op->Header.Args[1].ID()), Op->Index); + pinsrb(GetDst(Node), eax, 0); + break; + } + case 2: { + pextrw(eax, GetSrc(Op->Header.Args[1].ID()), Op->Index); + pinsrw(GetDst(Node), eax, 0); + break; + } + case 4: { + pextrd(eax, GetSrc(Op->Header.Args[1].ID()), Op->Index); + pinsrd(GetDst(Node), eax, 0); + break; + } + case 8: { + pextrq(rax, GetSrc(Op->Header.Args[1].ID()), Op->Index); + pinsrq(GetDst(Node), rax, 0); + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->ElementSize); break; + } + + break; + } case IR::OP_VADD: { auto Op = IROp->C(); switch (Op->ElementSize) { diff --git a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp index 26dcb4be4..6f7258a85 100644 --- a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp +++ b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp @@ -1818,6 +1818,17 @@ void LLVMJITCore::HandleIR(FEXCore::IR::IRListView const *IR, IR::NodeWrap SetDest(*WrapperOp, Result); break; } + case IR::OP_VEXTRACTELEMENT: { + auto Op = IROp->C(); + auto Src = GetSrc(Op->Header.Args[0]); + + // Cast to the type we want + Src = CastVectorToType(Src, true, Op->RegisterSize, Op->ElementSize); + + auto Result = JITState.IRBuilder->CreateExtractElement(Src, JITState.IRBuilder->getInt32(Op->Index)); + SetDest(*WrapperOp, Result); + break; + } case IR::OP_VINSGPR: { auto Op = IROp->C(); auto Src1 = GetSrc(Op->Header.Args[0]); @@ -2511,6 +2522,20 @@ void LLVMJITCore::HandleIR(FEXCore::IR::IRListView const *IR, IR::NodeWrap SetDest(*WrapperOp, Result); break; } + case IR::OP_VINSSCALARELEMENT: { + auto Op = IROp->C(); + auto Src1 = GetSrc(Op->Header.Args[0]); + auto Src2 = GetSrc(Op->Header.Args[1]); + + // Cast to the type we want + Src1 = CastVectorToType(Src1, true, Op->RegisterSize, Op->ElementSize); + Src2 = CastScalarToType(Src2, true, Op->RegisterSize, Op->ElementSize); + + // Extract our source index + auto Result = JITState.IRBuilder->CreateInsertElement(Src1, Src2, JITState.IRBuilder->getInt32(Op->DestIdx)); + SetDest(*WrapperOp, Result); + break; + } case IR::OP_VECTOR_UTOF: { auto Op = IROp->C(); auto Src = GetSrc(Op->Header.Args[0]);