#include #include "CodeGen.h" #include "CodeGen_StackPatterns.h" using namespace std; using namespace std::tr1::placeholders; bool CCodeGen::Register128HasNextUse(XMMREGISTER registerId) { unsigned int nCount = m_Shadow.GetCount(); for(unsigned int i = 0; i < nCount; i += 2) { if(m_Shadow.GetAt(i) == REGISTER128) { if(m_Shadow.GetAt(i + 1) == registerId) return true; } } return false; } void CCodeGen::CopyRegister128(XMMREGISTER destination, XMMREGISTER source) { m_Assembler.MovapsVo(CX86Assembler::MakeXmmRegisterAddress(destination), source); } void CCodeGen::LoadRelative128InRegister(XMMREGISTER registerId, uint32 offset) { m_Assembler.MovapsVo(registerId, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, offset)); } void CCodeGen::MD_PushRel(size_t offset) { m_Shadow.Push(static_cast(offset)); m_Shadow.Push(RELATIVE128); } void CCodeGen::MD_PushRelExpand(size_t offset) { //Need to convert to a register XMMREGISTER valueRegister = AllocateXmmRegister(); m_Assembler.MovssEd(valueRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(offset))); m_Assembler.ShufpsVo(valueRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister), 0x00); MD_PushReg(valueRegister); } void CCodeGen::MD_PushCstExpand(float constant) { XMMREGISTER valueRegister = AllocateXmmRegister(); unsigned int tempRegister = AllocateRegister(); m_Assembler.MovId(m_nRegisterLookupEx[tempRegister], *reinterpret_cast(&constant)); m_Assembler.MovdVo(valueRegister, CX86Assembler::MakeRegisterAddress(m_nRegisterLookupEx[tempRegister])); m_Assembler.ShufpsVo(valueRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister), 0x00); MD_PushReg(valueRegister); FreeRegister(tempRegister); } void CCodeGen::MD_PullRel(size_t offset) { if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); m_Assembler.MovdquVo(CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(offset)), valueRegister); FreeXmmRegister(valueRegister); } else { throw exception(); } } void CCodeGen::MD_PullRel(size_t offset0, size_t offset1, size_t offset2, size_t offset3) { if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); if( offset0 != SIZE_MAX && offset1 != SIZE_MAX && offset2 != SIZE_MAX && offset3 != SIZE_MAX ) { //All elements are non-null if((offset1 == offset0 + 4) && (offset2 == offset1 + 4) && (offset3 == offset2 + 4)) { m_Assembler.MovapsVo(CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(offset0)), valueRegister); } else { throw exception(); } } else { size_t offset[4]; uint8 shuffle[4] = { 0x00, 0xE5, 0xEA, 0xFF }; offset[0] = offset0; offset[1] = offset1; offset[2] = offset2; offset[3] = offset3; for(unsigned int i = 0; i < 4; i++) { if(offset[i] != SIZE_MAX) { if(i != 0) { m_Assembler.ShufpsVo(valueRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister), shuffle[i]); } m_Assembler.MovssEd(CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(offset[i])), valueRegister); } } } FreeXmmRegister(valueRegister); } else { throw exception(); } } void CCodeGen::MD_PullRel(size_t registerId, bool has0, bool has1, bool has2, bool has3) { throw exception(); uint8 partCount = (has0 ? 1 : 0) + (has1 ? 1 : 0) + (has2 ? 1 : 0) + (has3 ? 1 : 0); uint8 lonelySrcPart = (has0 ? 1 : 0) + (has1 ? 2 : 0) + (has2 ? 3 : 0) + (has3 ? 4 : 0) - 1; uint8 lonelyDstPart = (has0 ? 0 : 1) + (has1 ? 0 : 2) + (has2 ? 0 : 3) + (has3 ? 0 : 4) - 1; /* if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); assert(!Register128HasNextUse(valueRegister)); if(partCount == 4) { m_Assembler.MovapsVo(CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(registerId)), valueRegister); } else { XMMREGISTER tempRegister = AllocateXmmRegister(); m_Assembler.MovapsVo(tempRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(registerId))); //Check if we need to copy either 0 or 1 if(has0 || has1) { uint8 mask = (has0 ? 0x00) } m_Assembler.ShufpsVo(tempRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister), shuffle[i]); m_Assembler.MovapsVo(CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(registerId)), tempRegister); } FreeXmmRegister(tempRegister); } else { XMMREGISTER tempRegister = AllocateXmmRegister(); if(has3 || has2) { } m_Assembler.MovapsVo(tempRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, static_cast(registerId))); m_Assembler.ShufpsVo(tempRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister), shuffle[i]); FreeXmmRegister(tempRegister); //has0 has1 has2 has3 // 0 0 0 0 -> Shouldn't happen // 1 0 0 0 -> res[src0, dst1, dst2, dst3] // 0 1 0 0 -> res[dst0, src1, dst2, dst3] // 0 1 1 0 -> res[dst0, src1, src2, dst3] // 1 1 0 1 -> res[src0, src1, dst2, src3] } FreeXmmRegister(valueRegister); } else { throw exception(); } */ } void CCodeGen::MD_PushReg(XMMREGISTER registerId) { m_Shadow.Push(registerId); m_Shadow.Push(REGISTER128); } void CCodeGen::MD_GenericPackedShift(const PackedShiftFunction& instruction, uint8 amount) { if(FitsPattern()) { SingleRelative128::PatternValue op(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, op); instruction(resultRegister, amount); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_GenericOneOperand(const MdTwoOperandFunction& instruction) { if(FitsPattern()) { SingleRelative128::PatternValue op = GetPattern(); XMMREGISTER resultRegister = AllocateXmmRegister(); instruction(resultRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, op)); MD_PushReg(resultRegister); } else if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); assert(!Register128HasNextUse(valueRegister)); instruction(valueRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister)); MD_PushReg(valueRegister); } else { throw exception(); } } void CCodeGen::MD_GenericTwoOperand(const MdTwoOperandFunction& instruction) { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, ops.first); instruction(resultRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.second)); MD_PushReg(resultRegister); } else if(FitsPattern()) { RegisterRegister128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister; XMMREGISTER dstRegister = static_cast(ops.first); XMMREGISTER srcRegister = static_cast(ops.second); if(!Register128HasNextUse(dstRegister)) { resultRegister = dstRegister; } else { resultRegister = AllocateXmmRegister(); } instruction(resultRegister, CX86Assembler::MakeXmmRegisterAddress(srcRegister)); if(!Register128HasNextUse(srcRegister)) { FreeXmmRegister(srcRegister); } MD_PushReg(resultRegister); } else if(FitsPattern()) { RelativeRegister128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); { XMMREGISTER valueRegister = static_cast(ops.second); LoadRelative128InRegister(resultRegister, ops.first); instruction(resultRegister, CX86Assembler::MakeXmmRegisterAddress(valueRegister)); if(!Register128HasNextUse(valueRegister)) { FreeXmmRegister(valueRegister); } } MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_GenericTwoOperandReversed(const MdTwoOperandFunction& instruction) { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, ops.second); instruction(resultRegister, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.first)); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_AbsS() { if(FitsPattern()) { SingleRelative128::PatternValue op(GetPattern()); XMMREGISTER maskRegister = AllocateXmmRegister(); XMMREGISTER resultRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, op); m_Assembler.PcmpeqdVo(maskRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); m_Assembler.PsrldVo(maskRegister, 1); m_Assembler.PandVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); FreeXmmRegister(maskRegister); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_AddH() { MD_GenericTwoOperand(bind(&CX86Assembler::PaddwVo, m_Assembler, _1, _2)); } void CCodeGen::MD_AddWSS() { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); { unsigned int tempRegister = AllocateRegister(); unsigned int positiveValueRegister = AllocateRegister(); unsigned int negativeValueRegister = AllocateRegister(); //Prepare registers m_Assembler.MovId(m_nRegisterLookupEx[positiveValueRegister], 0x7FFFFFFF); m_Assembler.MovId(m_nRegisterLookupEx[negativeValueRegister], 0x80000000); for(int i = 3; i >= 0; i--) { CX86Assembler::LABEL doneLabel = m_Assembler.CreateLabel(); m_Assembler.MovEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.first + (i * 4))); m_Assembler.AddEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.second + (i * 4))); m_Assembler.JnoJb(doneLabel); m_Assembler.CmovsEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeRegisterAddress(m_nRegisterLookupEx[negativeValueRegister])); m_Assembler.CmovnsEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeRegisterAddress(m_nRegisterLookupEx[positiveValueRegister])); m_Assembler.MarkLabel(doneLabel); m_Assembler.Push(m_nRegisterLookupEx[tempRegister]); } FreeRegister(tempRegister); FreeRegister(positiveValueRegister); FreeRegister(negativeValueRegister); } m_Assembler.ResolveLabelReferences(); m_Assembler.MovdquVo(resultRegister, CX86Assembler::MakeIndRegAddress(CX86Assembler::rSP)); m_Assembler.AddId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 0x10); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_AddWUS() { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); unsigned int tempRegister = AllocateRegister(); XMMREGISTER resultRegister = AllocateXmmRegister(); for(int i = 3; i >= 0; i--) { CX86Assembler::LABEL overflowLabel = m_Assembler.CreateLabel(); CX86Assembler::LABEL doneLabel = m_Assembler.CreateLabel(); m_Assembler.MovEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.first + (i * 4))); m_Assembler.AddEd(m_nRegisterLookupEx[tempRegister], CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, ops.second + (i * 4))); m_Assembler.JcJb(overflowLabel); m_Assembler.PushEd(CX86Assembler::MakeRegisterAddress(m_nRegisterLookupEx[tempRegister])); m_Assembler.JmpJb(doneLabel); m_Assembler.MarkLabel(overflowLabel); m_Assembler.PushId(0xFFFFFFFF); m_Assembler.MarkLabel(doneLabel); } FreeRegister(tempRegister); m_Assembler.ResolveLabelReferences(); m_Assembler.MovdquVo(resultRegister, CX86Assembler::MakeIndRegAddress(CX86Assembler::rSP)); m_Assembler.AddId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 0x10); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_AddS() { MD_GenericTwoOperand(bind(&CX86Assembler::AddpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_And() { MD_GenericTwoOperand(bind(&CX86Assembler::PandVo, m_Assembler, _1, _2)); } void CCodeGen::MD_CmpEqW() { MD_GenericTwoOperand(bind(&CX86Assembler::PcmpeqdVo, m_Assembler, _1, _2)); } void CCodeGen::MD_CmpGtH() { MD_GenericTwoOperand(bind(&CX86Assembler::PcmpgtwVo, m_Assembler, _1, _2)); } void CCodeGen::MD_DivS() { MD_GenericTwoOperand(bind(&CX86Assembler::DivpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_IsNegative() { if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); XMMREGISTER resultRegister; if(Register128HasNextUse(valueRegister)) { resultRegister = AllocateXmmRegister(); CopyRegister128(resultRegister, valueRegister); } else { resultRegister = valueRegister; } XMMREGISTER maskRegister = AllocateXmmRegister(); m_Assembler.PcmpeqdVo(maskRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); m_Assembler.PslldVo(maskRegister, 31); m_Assembler.PandVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); FreeXmmRegister(maskRegister); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_IsZero() { if(FitsPattern()) { XMMREGISTER valueRegister = static_cast(GetPattern()); XMMREGISTER resultRegister; if(Register128HasNextUse(valueRegister)) { resultRegister = AllocateXmmRegister(); CopyRegister128(resultRegister, valueRegister); } else { resultRegister = valueRegister; } XMMREGISTER zeroRegister = AllocateXmmRegister(); m_Assembler.PandnVo(zeroRegister, CX86Assembler::MakeXmmRegisterAddress(zeroRegister)); m_Assembler.PcmpeqdVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(zeroRegister)); FreeXmmRegister(zeroRegister); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_MaxH() { MD_GenericTwoOperand(bind(&CX86Assembler::PmaxswVo, m_Assembler, _1, _2)); } void CCodeGen::MD_MaxS() { MD_GenericTwoOperand(bind(&CX86Assembler::MaxpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_MinH() { MD_GenericTwoOperand(bind(&CX86Assembler::PminswVo, m_Assembler, _1, _2)); } void CCodeGen::MD_MinS() { MD_GenericTwoOperand(bind(&CX86Assembler::MinpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_MulS() { MD_GenericTwoOperand(bind(&CX86Assembler::MulpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_Not() { if(FitsPattern()) { XMMREGISTER resultRegister(static_cast(GetPattern())); assert(!Register128HasNextUse(resultRegister)); XMMREGISTER tempRegister = AllocateXmmRegister(); m_Assembler.PcmpeqdVo(tempRegister, CX86Assembler::MakeXmmRegisterAddress(tempRegister)); m_Assembler.PxorVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(tempRegister)); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_Or() { MD_GenericTwoOperand(bind(&CX86Assembler::PorVo, m_Assembler, _1, _2)); } void CCodeGen::MD_PackHB() { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); XMMREGISTER tempRegister = AllocateXmmRegister(); XMMREGISTER maskRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, ops.second); LoadRelative128InRegister(tempRegister, ops.first); //Generate mask (0x00FF x8) m_Assembler.PcmpeqdVo(maskRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); m_Assembler.PsrlwVo(maskRegister, 0x08); //Mask both operands m_Assembler.PandVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); m_Assembler.PandVo(tempRegister, CX86Assembler::MakeXmmRegisterAddress(maskRegister)); //Pack m_Assembler.PackuswbVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(tempRegister)); FreeXmmRegister(maskRegister); FreeXmmRegister(tempRegister); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_PackWH() { if(FitsPattern()) { RelativeRelative128::PatternValue ops(GetPattern()); XMMREGISTER resultRegister = AllocateXmmRegister(); XMMREGISTER tempRegister = AllocateXmmRegister(); LoadRelative128InRegister(resultRegister, ops.second); LoadRelative128InRegister(tempRegister, ops.first); //Sign extend the lower half word of our registers m_Assembler.PslldVo(resultRegister, 0x10); m_Assembler.PsradVo(resultRegister, 0x10); m_Assembler.PslldVo(tempRegister, 0x10); m_Assembler.PsradVo(tempRegister, 0x10); //Pack m_Assembler.PackssdwVo(resultRegister, CX86Assembler::MakeXmmRegisterAddress(tempRegister)); FreeXmmRegister(tempRegister); MD_PushReg(resultRegister); } else { throw exception(); } } void CCodeGen::MD_SllH(uint8 amount) { MD_GenericPackedShift(bind(&CX86Assembler::PsllwVo, &m_Assembler, _1, _2), amount); } void CCodeGen::MD_SraH(uint8 amount) { MD_GenericPackedShift(bind(&CX86Assembler::PsrawVo, &m_Assembler, _1, _2), amount); } void CCodeGen::MD_SraW(uint8 amount) { MD_GenericPackedShift(bind(&CX86Assembler::PsradVo, &m_Assembler, _1, _2), amount); } void CCodeGen::MD_SrlH(uint8 amount) { MD_GenericPackedShift(bind(&CX86Assembler::PsrlwVo, &m_Assembler, _1, _2), amount); } void CCodeGen::MD_Srl256() { if(m_Shadow.Pull() != RELATIVE) assert(0); uint32 shiftAmount = m_Shadow.Pull(); if(m_Shadow.Pull() != RELATIVE128) assert(0); uint32 operand2 = m_Shadow.Pull(); if(m_Shadow.Pull() != RELATIVE128) assert(0); uint32 operand1 = m_Shadow.Pull(); assert(m_nRegisterAllocated[1] == false); //eCX assert(m_nRegisterAllocated[4] == false); //eSI assert(m_nRegisterAllocated[5] == false); //eDI XMMREGISTER resultRegister = AllocateXmmRegister(); //Copy both registers on the stack //----------------------------- m_Assembler.SubId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 0x30); m_Assembler.MovGd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rDI), CX86Assembler::rSP); m_Assembler.LeaGd(CX86Assembler::rSI, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, operand2)); m_Assembler.MovId(CX86Assembler::rCX, 0x10); m_Assembler.RepMovsb(); m_Assembler.LeaGd(CX86Assembler::rSI, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, operand1)); m_Assembler.MovId(CX86Assembler::rCX, 0x10); m_Assembler.RepMovsb(); //Setup SA //----------------------------- m_Assembler.MovEd(CX86Assembler::rAX, CX86Assembler::MakeIndRegOffAddress(g_nBaseRegister, shiftAmount)); m_Assembler.AndId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX), 0x7F); m_Assembler.ShrEd(CX86Assembler::MakeRegisterAddress(CX86Assembler::rAX), 0x03); //Setup ESI //----------------------------- m_Assembler.LeaGd(CX86Assembler::rSI, CX86Assembler::MakeBaseIndexScaleAddress(CX86Assembler::rSP, CX86Assembler::rAX, 1)); //Setup ECX //----------------------------- m_Assembler.MovId(CX86Assembler::rCX, 0x10); //Generate result //----------------------------- m_Assembler.RepMovsb(); //Load result and free Stack //----------------------------- m_Assembler.MovdquVo(resultRegister, CX86Assembler::MakeIndRegOffAddress(CX86Assembler::rSP, 0x20)); m_Assembler.AddId(CX86Assembler::MakeRegisterAddress(CX86Assembler::rSP), 0x30); MD_PushReg(resultRegister); } void CCodeGen::MD_SubB() { MD_GenericTwoOperand(bind(&CX86Assembler::PsubbVo, m_Assembler, _1, _2)); } void CCodeGen::MD_SubW() { MD_GenericTwoOperand(bind(&CX86Assembler::PsubdVo, m_Assembler, _1, _2)); } void CCodeGen::MD_SubS() { MD_GenericTwoOperand(bind(&CX86Assembler::SubpsVo, m_Assembler, _1, _2)); } void CCodeGen::MD_ToSingle() { MD_GenericOneOperand(bind(&CX86Assembler::Cvtdq2psVo, m_Assembler, _1, _2)); } void CCodeGen::MD_ToWordTruncate() { MD_GenericOneOperand(bind(&CX86Assembler::Cvttps2dqVo, m_Assembler, _1, _2)); } void CCodeGen::MD_UnpackLowerBH() { MD_GenericTwoOperandReversed(bind(&CX86Assembler::PunpcklbwVo, m_Assembler, _1, _2)); } void CCodeGen::MD_UnpackLowerHW() { MD_GenericTwoOperandReversed(bind(&CX86Assembler::PunpcklwdVo, m_Assembler, _1, _2)); } void CCodeGen::MD_UnpackLowerWD() { MD_GenericTwoOperandReversed(bind(&CX86Assembler::PunpckldqVo, m_Assembler, _1, _2)); } void CCodeGen::MD_UnpackUpperBH() { MD_GenericTwoOperandReversed(bind(&CX86Assembler::PunpckhbwVo, m_Assembler, _1, _2)); } void CCodeGen::MD_UnpackUpperWD() { MD_GenericTwoOperandReversed(bind(&CX86Assembler::PunpckhdqVo, m_Assembler, _1, _2)); } void CCodeGen::MD_Xor() { MD_GenericTwoOperand(bind(&CX86Assembler::PxorVo, m_Assembler, _1, _2)); }