diff --git a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp index ce120f60b..4b0f3c289 100644 --- a/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp +++ b/External/FEXCore/Source/Interface/Core/Interpreter/InterpreterCore.cpp @@ -2539,6 +2539,23 @@ void InterpreterCore::ExecuteCode(FEXCore::Core::InternalThreadState *Thread) { memcpy(GDP, Tmp, Op->Header.ElementSize); break; } + case IR::OP_VURAVG: { + auto Op = IROp->C(); + void *Src1 = GetSrc(Op->Header.Args[0]); + void *Src2 = GetSrc(Op->Header.Args[1]); + uint8_t Tmp[16]; + + uint8_t Elements = OpSize / Op->Header.ElementSize; + + auto Func = [](auto a, auto b) { return (a + b + 1) >> 1; }; + switch (Op->Header.ElementSize) { + DO_VECTOR_OP(1, uint8_t, Func) + DO_VECTOR_OP(2, uint16_t, Func) + default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break; + } + memcpy(GDP, Tmp, OpSize); + break; + } case IR::OP_VABS: { auto Op = IROp->C(); void *Src = GetSrc(Op->Header.Args[0]); diff --git a/External/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp b/External/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp index a1780ed0d..7f4817724 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/Arm64/VectorOps.cpp @@ -276,6 +276,21 @@ DEF_OP(VAddV) { } } +DEF_OP(VURAvg) { + auto Op = IROp->C(); + switch (Op->Header.ElementSize) { + case 1: { + urhadd(GetDst(Node).V16B(), GetSrc(Op->Header.Args[0].ID()).V16B(), GetSrc(Op->Header.Args[1].ID()).V16B()); + break; + } + case 2: { + urhadd(GetDst(Node).V8H(), GetSrc(Op->Header.Args[0].ID()).V8H(), GetSrc(Op->Header.Args[1].ID()).V8H()); + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break; + } +} + DEF_OP(VAbs) { auto Op = IROp->C(); uint8_t OpSize = IROp->Size; 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 ec4835eb0..3420c8e46 100644 --- a/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp +++ b/External/FEXCore/Source/Interface/Core/JIT/x86_64/JIT.cpp @@ -2404,6 +2404,21 @@ void *JITCore::CompileCode([[maybe_unused]] FEXCore::IR::IRListView const movaps(Dest, xmm15); break; } + case IR::OP_VURAVG: { + auto Op = IROp->C(); + switch (Op->Header.ElementSize) { + case 1: { + vpavgb(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID())); + break; + } + case 2: { + vpavgw(GetDst(Node), GetSrc(Op->Header.Args[0].ID()), GetSrc(Op->Header.Args[1].ID())); + break; + } + default: LogMan::Msg::A("Unknown Element Size: %d", Op->Header.ElementSize); break; + } + break; + } case IR::OP_VABS: { auto Op = IROp->C(); switch (Op->Header.ElementSize) { diff --git a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp index 755280a20..f3bce3c62 100644 --- a/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp +++ b/External/FEXCore/Source/Interface/Core/LLVMJIT/LLVMCore.cpp @@ -626,6 +626,41 @@ private: return Result; } + llvm::Value *VURAVG(llvm::Value *Arg1, llvm::Value *Arg2, uint8_t RegisterSize, uint8_t ElementSize) { + + uint8_t NumElements = RegisterSize / ElementSize; + std::vector Values1; + std::vector Values2; + std::vector Results; + + // XXX: these need to be widening to ElementSize * 2 for overflows + for (size_t i = 0; i < NumElements; ++i) { + Values1.emplace_back(JITState.IRBuilder->CreateExtractElement(Arg1, i));; + Values2.emplace_back(JITState.IRBuilder->CreateExtractElement(Arg2, i));; + } + + for (size_t i = 0; i < NumElements; ++i) { + + // XXX: These need to operate on ElementSize * 2 for overflows + auto sum = JITState.IRBuilder->CreateAdd(Values1[i], Values2[i]); + sum = JITState.IRBuilder->CreateAdd(sum, JITState.IRBuilder->getIntN(ElementSize, 1)); + + // XXX: This needs to be narrowing to ElementSize + auto Result = JITState.IRBuilder->CreateLShr(sum, JITState.IRBuilder->getIntN(ElementSize, 1)); + + Results.emplace_back(Result); + } + + // Cast to the type we want + llvm::Value *Result = llvm::UndefValue::get(Arg1->getType()); + + for (size_t i = 0; i < NumElements; ++i) { + Result = JITState.IRBuilder->CreateInsertElement(Result, Results[i], i); + } + + return Result; + } + llvm::Value *VADDV(llvm::Value *Arg, uint8_t RegisterSize, uint8_t ElementSize) { uint8_t NumElements = RegisterSize / ElementSize; std::vector Values; @@ -2693,6 +2728,20 @@ void LLVMJITCore::HandleIR(FEXCore::IR::IRListView const *IR, IR::NodeWrap SetDest(*WrapperOp, Result); break; } + case IR::OP_VURAVG: { + 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, OpSize, Op->Header.ElementSize); + Src2 = CastVectorToType(Src2, true, OpSize, Op->Header.ElementSize); + + auto Result = VURAVG(Src1, Src2, OpSize, Op->Header.ElementSize); + + SetDest(*WrapperOp, Result); + break; + } case IR::OP_VABS: { auto Op = IROp->C(); auto Src = GetSrc(Op->Header.Args[0]); diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp index 119c372c2..6285e9b40 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.cpp @@ -5133,6 +5133,16 @@ void OpDispatchBuilder::PSRAIOp(OpcodeArgs) { StoreResult(FPRClass, Op, Result, -1); } +template +void OpDispatchBuilder::PAVGOp(OpcodeArgs) { + auto Size = GetSrcSize(Op); + OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); + OrderedNode *Dest = LoadSource(FPRClass, Op, Op->Dest, Op->Flags, -1); + + auto Result = _VURAvg(Size, ElementSize, Dest, Src); + StoreResult(FPRClass, Op, Result, -1); +} + void OpDispatchBuilder::MOVDDUPOp(OpcodeArgs) { OrderedNode *Src = LoadSource(FPRClass, Op, Op->Src[0], Op->Flags, -1); OrderedNode *Res = _SplatVector2(Src); @@ -7171,8 +7181,10 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xDD, 1, &OpDispatchBuilder::PADDSOp<2, false>}, {0xDE, 1, &OpDispatchBuilder::PMAXUOp<1>}, {0xDF, 1, &OpDispatchBuilder::ANDNOp}, + {0xE0, 1, &OpDispatchBuilder::PAVGOp<1>}, {0xE1, 1, &OpDispatchBuilder::PSRAOp<2, true, 0>}, {0xE2, 1, &OpDispatchBuilder::PSRAOp<4, true, 0>}, + {0xE3, 1, &OpDispatchBuilder::PAVGOp<2>}, {0xE4, 1, &OpDispatchBuilder::PMULHW}, {0xE5, 1, &OpDispatchBuilder::PMULHW}, {0xE7, 1, &OpDispatchBuilder::MOVUPSOp}, @@ -7437,8 +7449,10 @@ void InstallOpcodeHandlers(Context::OperatingMode Mode) { {0xDD, 1, &OpDispatchBuilder::VectorALUOp}, {0xDE, 1, &OpDispatchBuilder::PMAXUOp<1>}, {0xDF, 1, &OpDispatchBuilder::ANDNOp}, + {0xE0, 1, &OpDispatchBuilder::PAVGOp<1>}, {0xE1, 1, &OpDispatchBuilder::PSRAOp<2, true, 0>}, {0xE2, 1, &OpDispatchBuilder::PSRAOp<4, true, 0>}, + {0xE3, 1, &OpDispatchBuilder::PAVGOp<2>}, {0xE4, 1, &OpDispatchBuilder::PMULHW}, {0xE5, 1, &OpDispatchBuilder::PMULHW}, {0xE6, 1, &OpDispatchBuilder::Vector_CVT_Float_To_Int<8, true, true>}, diff --git a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h index e9b656c5f..6f6c91979 100644 --- a/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h +++ b/External/FEXCore/Source/Interface/Core/OpcodeDispatcher.h @@ -258,6 +258,8 @@ public: void PSLLDQ(OpcodeArgs); template void PSRAIOp(OpcodeArgs); + template + void PAVGOp(OpcodeArgs); void MOVDDUPOp(OpcodeArgs); template void CVTGPR_To_FPR(OpcodeArgs); diff --git a/External/FEXCore/Source/Interface/Core/X86Tables/SecondaryTables.cpp b/External/FEXCore/Source/Interface/Core/X86Tables/SecondaryTables.cpp index 5fcae8cb8..0dcef4737 100644 --- a/External/FEXCore/Source/Interface/Core/X86Tables/SecondaryTables.cpp +++ b/External/FEXCore/Source/Interface/Core/X86Tables/SecondaryTables.cpp @@ -215,10 +215,10 @@ void InitializeSecondaryTables() { {0xDE, 1, X86InstInfo{"PMAXUB", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xDF, 1, X86InstInfo{"PANDN", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, - {0xE0, 1, X86InstInfo{"PAVGB", TYPE_MMX, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, + {0xE0, 1, X86InstInfo{"PAVGB", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xE1, 1, X86InstInfo{"PSRAW", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xE2, 1, X86InstInfo{"PSRAD", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, - {0xE3, 1, X86InstInfo{"PAVGW", TYPE_MMX, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, + {0xE3, 1, X86InstInfo{"PAVGW", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xE4, 1, X86InstInfo{"PMULHUW", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xE5, 1, X86InstInfo{"PMULHW", TYPE_INST, GenFlagsSameSize(SIZE_64BIT) | FLAGS_MODRM | FLAGS_XMM_FLAGS | FLAGS_SF_MMX, 0, nullptr}}, {0xE6, 1, X86InstInfo{"", TYPE_INVALID, FLAGS_NONE, 0, nullptr}}, diff --git a/External/FEXCore/Source/Interface/IR/IR.json b/External/FEXCore/Source/Interface/IR/IR.json index 608eff91d..895d78a85 100644 --- a/External/FEXCore/Source/Interface/IR/IR.json +++ b/External/FEXCore/Source/Interface/IR/IR.json @@ -1533,6 +1533,24 @@ ] }, + "VURAvg": { + "OpClass": "Vector", + "Desc": ["Does an unsigned rounded average", "dst_elem = (src1_elem + src2_elem + 1) >> 1"], + "HasDest": true, + "DestClass": "FPR", + "DestSize": "RegisterSize", + "NumElements": "RegisterSize / ElementSize", + "SSAArgs": "2", + "SSANames": [ + "Vector1", + "Vector2" + ], + "HelperArgs": [ + "uint8_t", "RegisterSize", + "uint8_t", "ElementSize" + ] + }, + "VAbs": { "OpClass": "Vector", "Desc": ["Does an signed integer absolute" diff --git a/External/FEXCore/include/FEXCore/IR/IREmitter.h b/External/FEXCore/include/FEXCore/IR/IREmitter.h index 66311880b..32cc737df 100644 --- a/External/FEXCore/include/FEXCore/IR/IREmitter.h +++ b/External/FEXCore/include/FEXCore/IR/IREmitter.h @@ -127,6 +127,9 @@ friend class FEXCore::IR::PassManager; IRPair _VAddV(uint8_t RegisterSize, uint8_t ElementSize, OrderedNode *ssa0) { return _VAddV(ssa0, RegisterSize, ElementSize); } + IRPair _VURAvg(uint8_t RegisterSize, uint8_t ElementSize, OrderedNode *ssa0, OrderedNode *ssa1) { + return _VURAvg(ssa0, ssa1, RegisterSize, ElementSize); + } IRPair _VAbs(uint8_t RegisterSize, uint8_t ElementSize, OrderedNode *ssa0) { return _VAbs(ssa0, RegisterSize, ElementSize); } diff --git a/unittests/ASM/OpSize/66_E0.asm b/unittests/ASM/OpSize/66_E0.asm new file mode 100644 index 000000000..e399a9506 --- /dev/null +++ b/unittests/ASM/OpSize/66_E0.asm @@ -0,0 +1,58 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM0": ["0x2179b0697d5378c4", "0x3b8e6eae8c165248"], + "XMM1": ["0x1ed68638699d35ca", "0x5e2e7560ab7b5262"], + "XMM2": ["0x165c42291f28194c", "0x0923643c32130145"], + "XMM3": ["0x2179b0697d5378c4", "0x3b8e6eae8c165248"], + "XMM4": ["0x1ed68638699d35ca", "0x5e2e7560ab7b5262"], + "XMM5": ["0x165c42291f28194c", "0x0923643c32130145"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x2bb883523d4f3197 +mov [rdx + 8 * 0], rax +mov rax, 0x1246c77764260189 +mov [rdx + 8 * 1], rax + +mov rax, 0x163add80bc57bef1 +mov [rdx + 8 * 2], rax +mov rax, 0x64d615e5b405a306 +mov [rdx + 8 * 3], rax + +mov rax, 0x11f4881d94eb39fc +mov [rdx + 8 * 4], rax +mov rax, 0xa9162248f2d0a23a +mov [rdx + 8 * 5], rax + +mov rax, 0x0 +mov [rdx + 8 * 6], rax +mov rax, 0x0 +mov [rdx + 8 * 7], rax + +movapd xmm0, [rdx + 8 * 0] +movapd xmm1, [rdx + 8 * 0] +movapd xmm2, [rdx + 8 * 0] +movapd xmm3, [rdx + 8 * 0] +movapd xmm4, [rdx + 8 * 0] +movapd xmm5, [rdx + 8 * 0] + +movapd xmm6, [rdx + 8 * 2] +movapd xmm7, [rdx + 8 * 4] +movapd xmm8, [rdx + 8 * 6] + +pavgb xmm0, xmm6 +pavgb xmm1, xmm7 +pavgb xmm2, xmm8 + +pavgb xmm3, [rdx + 8 * 2] +pavgb xmm4, [rdx + 8 * 4] +pavgb xmm5, [rdx + 8 * 6] + +hlt diff --git a/unittests/ASM/OpSize/66_E3.asm b/unittests/ASM/OpSize/66_E3.asm new file mode 100644 index 000000000..ea8d409a3 --- /dev/null +++ b/unittests/ASM/OpSize/66_E3.asm @@ -0,0 +1,58 @@ +%ifdef CONFIG +{ + "RegData": { + "XMM0": ["0x20f9b0697cd37844", "0x3b8e6eae8c165248"], + "XMM1": ["0x1ed685b8691d35ca", "0x5dae74e0ab7b51e2"], + "XMM2": ["0x15dc41a91ea818cc", "0x092363bc321300c5"], + "XMM3": ["0x20f9b0697cd37844", "0x3b8e6eae8c165248"], + "XMM4": ["0x1ed685b8691d35ca", "0x5dae74e0ab7b51e2"], + "XMM5": ["0x15dc41a91ea818cc", "0x092363bc321300c5"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x2bb883523d4f3197 +mov [rdx + 8 * 0], rax +mov rax, 0x1246c77764260189 +mov [rdx + 8 * 1], rax + +mov rax, 0x163add80bc57bef1 +mov [rdx + 8 * 2], rax +mov rax, 0x64d615e5b405a306 +mov [rdx + 8 * 3], rax + +mov rax, 0x11f4881d94eb39fc +mov [rdx + 8 * 4], rax +mov rax, 0xa9162248f2d0a23a +mov [rdx + 8 * 5], rax + +mov rax, 0x0 +mov [rdx + 8 * 6], rax +mov rax, 0x0 +mov [rdx + 8 * 7], rax + +movapd xmm0, [rdx + 8 * 0] +movapd xmm1, [rdx + 8 * 0] +movapd xmm2, [rdx + 8 * 0] +movapd xmm3, [rdx + 8 * 0] +movapd xmm4, [rdx + 8 * 0] +movapd xmm5, [rdx + 8 * 0] + +movapd xmm6, [rdx + 8 * 2] +movapd xmm7, [rdx + 8 * 4] +movapd xmm8, [rdx + 8 * 6] + +pavgw xmm0, xmm6 +pavgw xmm1, xmm7 +pavgw xmm2, xmm8 + +pavgw xmm3, [rdx + 8 * 2] +pavgw xmm4, [rdx + 8 * 4] +pavgw xmm5, [rdx + 8 * 6] + +hlt diff --git a/unittests/ASM/TwoByte/0F_E0.asm b/unittests/ASM/TwoByte/0F_E0.asm new file mode 100644 index 000000000..128fa9dc1 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_E0.asm @@ -0,0 +1,58 @@ +%ifdef CONFIG +{ + "RegData": { + "MM0": ["0x2179b0697d5378c4", "0x0"], + "MM1": ["0x1ed68638699d35ca", "0x0"], + "MM2": ["0x165c42291f28194c", "0x0"], + "MM3": ["0x2179b0697d5378c4", "0x0"], + "MM4": ["0x1ed68638699d35ca", "0x0"], + "MM5": ["0x165c42291f28194c", "0x0"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x2bb883523d4f3197 +mov [rdx + 8 * 0], rax +mov rax, 0x1246c77764260189 +mov [rdx + 8 * 1], rax + +mov rax, 0x163add80bc57bef1 +mov [rdx + 8 * 2], rax +mov rax, 0x64d615e5b405a306 +mov [rdx + 8 * 3], rax + +mov rax, 0x11f4881d94eb39fc +mov [rdx + 8 * 4], rax +mov rax, 0xa9162248f2d0a23a +mov [rdx + 8 * 5], rax + +mov rax, 0x0 +mov [rdx + 8 * 6], rax +mov rax, 0x0 +mov [rdx + 8 * 7], rax + +movq mm0, [rdx + 8 * 0] +movq mm1, [rdx + 8 * 0] +movq mm2, [rdx + 8 * 0] +movq mm3, [rdx + 8 * 0] +movq mm4, [rdx + 8 * 0] +movq mm5, [rdx + 8 * 0] +movq mm6, [rdx + 8 * 2] +movq mm7, [rdx + 8 * 4] + +pavgb mm0, mm6 +pavgb mm1, mm7 + +movq mm7, [rdx + 8 * 6] +pavgb mm2, mm7 + +pavgb mm3, [rdx + 8 * 2] +pavgb mm4, [rdx + 8 * 4] +pavgb mm5, [rdx + 8 * 6] + +hlt diff --git a/unittests/ASM/TwoByte/0F_E3.asm b/unittests/ASM/TwoByte/0F_E3.asm new file mode 100644 index 000000000..628e50a42 --- /dev/null +++ b/unittests/ASM/TwoByte/0F_E3.asm @@ -0,0 +1,58 @@ +%ifdef CONFIG +{ + "RegData": { + "MM0": ["0x20f9b0697cd37844", "0x0"], + "MM1": ["0x1ed685b8691d35ca", "0x0"], + "MM2": ["0x15dc41a91ea818cc", "0x0"], + "MM3": ["0x20f9b0697cd37844", "0x0"], + "MM4": ["0x1ed685b8691d35ca", "0x0"], + "MM5": ["0x15dc41a91ea818cc", "0x0"] + }, + "MemoryRegions": { + "0x100000000": "4096" + } +} +%endif + +mov rdx, 0xe0000000 + +mov rax, 0x2bb883523d4f3197 +mov [rdx + 8 * 0], rax +mov rax, 0x1246c77764260189 +mov [rdx + 8 * 1], rax + +mov rax, 0x163add80bc57bef1 +mov [rdx + 8 * 2], rax +mov rax, 0x64d615e5b405a306 +mov [rdx + 8 * 3], rax + +mov rax, 0x11f4881d94eb39fc +mov [rdx + 8 * 4], rax +mov rax, 0xa9162248f2d0a23a +mov [rdx + 8 * 5], rax + +mov rax, 0x0 +mov [rdx + 8 * 6], rax +mov rax, 0x0 +mov [rdx + 8 * 7], rax + +movq mm0, [rdx + 8 * 0] +movq mm1, [rdx + 8 * 0] +movq mm2, [rdx + 8 * 0] +movq mm3, [rdx + 8 * 0] +movq mm4, [rdx + 8 * 0] +movq mm5, [rdx + 8 * 0] +movq mm6, [rdx + 8 * 2] +movq mm7, [rdx + 8 * 4] + +pavgw mm0, mm6 +pavgw mm1, mm7 + +movq mm7, [rdx + 8 * 6] +pavgw mm2, mm7 + +pavgw mm3, [rdx + 8 * 2] +pavgw mm4, [rdx + 8 * 4] +pavgw mm5, [rdx + 8 * 6] + +hlt