/* * * public static unsafe void Fill16Blocks( * byte *dest, [ebp + 8] * int value, [ebp + 12] * int BlocksNum) [ebp + 16] */ public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { /* First we copy dest, value and DestSize from EBP (stack) to 3 different registers */ XS.Comment("Destination (int pointer)"); XS.Set(EAX, EBP, sourceDisplacement: DestDisplacement); XS.Comment("Value"); XS.Set(EBX, EBP, sourceDisplacement: ValueDisplacement); XS.Comment("BlocksNum"); XS.Set(ECX, EBP, sourceDisplacement: BlocksNumDisplacement); /* * Now we need to copy 'value' (EBX) to an SSE register but we should not simply do a copy (!) * but all the register with 'value' repeating! * That is in the 16 byte SSE register should go this repeating pattern: * |value|value|value|value * luckily we don't need to do a loop for this there is the SSE3 instruction for this shufps */ XS.SSE2.MoveD(XMM0, EBX); XS.SSE.Shufps(XMM0, XMM0, 0x0000); // This broadcast the first element of XMM0 on the other 3 /* Do the 'loop' */ XS.Xor(EDI, EDI); // EDI is 0 XS.Label(".loop"); //XS.SSE.MoveUPS(EAX, XMM0, destinationIsIndirect: true, destinationDisplacement: EDI); XS.LiteralCode("movups[EAX + EDI], XMM0"); XS.Add(EDI, 16); XS.Sub(ECX, 1); //XS.LiteralCode("jnz .loop"); XS.Jump(ConditionalTestEnum.NotZero, ".loop"); //XS.Return(); }
public override void AssembleNew(Assembler aAssembler, object aMethodInfo) { // load element size into eax // load length into ebx // calculate entire size into eax and move to exc // load start into edi // clear ecx bytes starting at edi // load element size into eax XS.Set(EAX, EBP, sourceDisplacement: SourceArrayDisplacement); XS.Add(EAX, 8); XS.Set(EAX, EAX, sourceIsIndirect: true); // load length into ebx XS.Set(EBX, EBP, sourceDisplacement: SourceArrayDisplacement); XS.Add(EBX, 12); XS.Set(EBX, EBX, sourceIsIndirect: true); // calculate size in bytes and move to ecx XS.Multiply(EBX); XS.Set(ECX, EAX); // load start into esi XS.Set(EDI, EBP, sourceDisplacement: SourceArrayDisplacement); XS.Add(EDI, 16); // clear eax bytes starting at esi XS.Set(EAX, 0); XS.LiteralCode("rep stosb"); }
public override void Execute(_MethodInfo aMethod, ILOpCode aOpCode) { var xValue = aOpCode.StackPopTypes[0]; var xValueIsFloat = TypeIsFloat(xValue); var xValueSize = SizeOfType(xValue); if (xValueSize > 8) { //EmitNotImplementedException( Assembler, aServiceProvider, "Size '" + xSize.Size + "' not supported (add)", aCurrentLabel, aCurrentMethodInfo, aCurrentOffset, aNextLabel ); throw new NotImplementedException(); } //TODO if on stack a float it is first truncated, http://msdn.microsoft.com/en-us/library/system.reflection.emit.opcodes.conv_r_un.aspx if (!xValueIsFloat) { switch (xValueSize) { case 1: case 2: case 4: /* * Code generated by C# / Visual Studio 2015 * mov eax,dword ptr [anInt] * mov dword ptr [ebp-0E0h],eax * cvtsi2sd xmm0,dword ptr [ebp-0E0h] * mov ecx,dword ptr [ebp-0E0h] * shr ecx,1Fh * addsd xmm0,mmword ptr __xmm@41f00000000000000000000000000000 (01176B40h)[ecx*8] * movsd mmword ptr [aDouble],xmm0 # This for now means to copy our converted double to ESP */ string BaseLabel = GetLabel(aMethod, aOpCode) + "."; string LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset"; XS.Set(EAX, ESP, sourceIsIndirect: true); XS.Set(EBP, EAX, destinationDisplacement: -0xE0, destinationIsIndirect: true); XS.SSE2.ConvertSI2SD(XMM0, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true); XS.Set(ECX, EBP, sourceDisplacement: -0xE0, sourceIsIndirect: true); // OK now we put in ECX the last bit of our unsigned value, we call it "SIGN_BIT" but is a little improper... XS.ShiftRight(ECX, 31); /* * if the 'SIGN_BIT' is 0 it means that our uint could have been placed in a normal int so ConvertSI2SD did already * the right thing: we have finished * if the value is 1 we need to do that addition with that weird constant to obtain the real value as double */ XS.Compare(ECX, 0x00); XS.Jump(ConditionalTestEnum.Equal, LabelSign_Bit_Unset); XS.LiteralCode(@"addsd xmm0, [__uint2double_const]"); XS.Label(LabelSign_Bit_Unset); // We have converted our value to double put it on ESP // expand stack, that moved data is valid stack XS.Sub(ESP, 4); XS.SSE2.MoveSD(ESP, XMM0, destinationIsIndirect: true); break; case 8: BaseLabel = GetLabel(aMethod, aOpCode) + "."; LabelSign_Bit_Unset = BaseLabel + "LabelSign_Bit_Unset"; /* * mov EAX, ESP + 4 * fild qword ptr [esp] * shr EAX, 31 * cmp ESP, 0 * jpe LabelSign_Bit_Unset * LabelSign_Bit_Unset: * fadd dword ptr __ulong2double_const2 * fstp ESP */ // Save the high part of the ulong in EAX (we cannot move all of ESP as it has 64 bit size) XS.Set(EAX, ESP, sourceIsIndirect: true, sourceDisplacement: 4); XS.FPU.IntLoad(ESP, isIndirect: true, size: RegisterSize.Long64); XS.Test(EAX, EAX); XS.Jump(ConditionalTestEnum.NotSign, LabelSign_Bit_Unset); // If the sign is set we remove it using the constant __ulong2double_const4 XS.LiteralCode(@"fadd dword [__ulong2double_const]"); XS.Label(LabelSign_Bit_Unset); // Convert the value to double and move it into the stack XS.FPU.FloatStoreAndPop(ESP, isIndirect: true, size: RegisterSize.Long64); break; default: //EmitNotImplementedException( Assembler, GetServiceProvider(), "Conv_I: SourceSize " + xSource + " not supported!", mCurLabel, mMethodInformation, mCurOffset, mNextLabel ); throw new NotImplementedException("Conv_R_Un with type " + xValue + " not supported!"); } } else { throw new NotImplementedException("Conv_R_Un with type " + xValue + " not supported!"); } }