/// <summary> /// Creates the ISR methods. /// </summary> /// <param name="compiler">The compiler.</param> private void CreateISRMethods(AssemblyCompiler compiler) { // Create Interrupt Service Routines (ISR) RuntimeMethod InterruptMethod = compiler.Assembly.EntryPoint; // TODO: replace with another entry point SigType I1 = new SigType(CilElementType.I1); SigType I4 = new SigType(CilElementType.I4); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); for (int i = 0; i <= 256; i++) { InstructionSet set = new InstructionSet(100); Context ctx = new Context(set, -1); ctx.SetInstruction(CPUx86.Instruction.CliInstruction); if ((i != 8) && (i < 10 || i > 14)) // For IRQ 8, 10, 11, 12, 13, 14 the cpu automatically pushed the error code ctx.AppendInstruction(CPUx86.Instruction.PushInstruction, null, new ConstantOperand(I4, 0x0)); ctx.AppendInstruction(CPUx86.Instruction.PushadInstruction); ctx.AppendInstruction(CPUx86.Instruction.PushInstruction, null, new ConstantOperand(I4, i)); // TODO: Set method parameters ctx.AppendInstruction(CPUx86.Instruction.CallInstruction, InterruptMethod); ctx.AppendInstruction(CPUx86.Instruction.PopInstruction, eax); ctx.AppendInstruction(CPUx86.Instruction.PopadInstruction); ctx.AppendInstruction(CPUx86.Instruction.PopInstruction, eax); ctx.AppendInstruction(CPUx86.Instruction.StiInstruction); //ctx.AppendInstruction(CPUx86.Instruction.IRetdInstruction); CompilerGeneratedMethod method = LinkTimeCodeGenerator.Compile(compiler, @"InterruptISR" + i.ToString(), set); } }
/// <summary> /// Creates the ISR methods. /// </summary> /// <param name="compiler">The compiler.</param> private void CreateISRMethods(AssemblyCompiler compiler) { // Get RuntimeMethod for the Mosa.Kernel.X86.IDT.InterruptHandler RuntimeType rt = RuntimeBase.Instance.TypeLoader.GetType(@"Mosa.Kernel.X86.IDT"); RuntimeMethod InterruptMethod = FindMethod(rt, "InterruptHandler"); SigType I1 = new SigType(CilElementType.I1); SigType I2 = new SigType(CilElementType.I4); RegisterOperand ecx1 = new RegisterOperand(I1, GeneralPurposeRegister.ECX); RegisterOperand ecx2 = new RegisterOperand(I2, GeneralPurposeRegister.ECX); for (int i = 0; i <= 256; i++) { InstructionSet set = new InstructionSet(100); Context ctx = new Context(set, -1); ctx.AppendInstruction(CPUx86.Instruction.CliInstruction); ctx.AppendInstruction(CPUx86.Instruction.PushadInstruction); if ((i != 8) && (i < 10 || i > 14)) // For IRQ 8, 10, 11, 12, 13, 14 the cpu automatically pushed the error code ctx.AppendInstruction(CPUx86.Instruction.PushInstruction, null, new ConstantOperand(I1, 0x0)); ctx.AppendInstruction(CPUx86.Instruction.PushInstruction, null, new ConstantOperand(I2, i)); ctx.AppendInstruction(CPUx86.Instruction.CallInstruction, InterruptMethod); // TODO: Replace next two instructions with add esp, 5 ;Stack clearing ctx.AppendInstruction(CPUx86.Instruction.PopInstruction, ecx2); ctx.AppendInstruction(CPUx86.Instruction.PopInstruction, ecx1); ctx.AppendInstruction(CPUx86.Instruction.PopadInstruction); ctx.AppendInstruction(CPUx86.Instruction.StiInstruction); ctx.AppendInstruction(CPUx86.Instruction.IRetdInstruction); CompilerGeneratedMethod method = LinkTimeCodeGenerator.Compile(compiler, @"InterruptISR" + i.ToString(), set); } }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; RegisterOperand imm = new RegisterOperand(new SigType(CilElementType.U4), GeneralPurposeRegister.EAX); context.SetInstruction(IR.Instruction.MoveInstruction, imm, new RegisterOperand(new SigType(CilElementType.U4), _control)); context.AppendInstruction(IR.Instruction.MoveInstruction, result, imm); }
/// <summary> /// Visitation function for <see cref="IR.IIRVisitor.AddressOfInstruction"/> instruction. /// </summary> /// <param name="ctx">The context.</param> void IR.IIRVisitor.AddressOfInstruction(Context ctx) { Operand opRes = ctx.Result; RegisterOperand eax = new RegisterOperand (opRes.Type, GeneralPurposeRegister.EAX); ctx.Result = eax; ctx.ReplaceInstructionOnly (CPUx86.Instruction.LeaInstruction); // ctx.Ignore = true; ctx.AppendInstruction (CPUx86.Instruction.MovInstruction, opRes, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { Operand operand1 = context.Operand1; RegisterOperand imm = new RegisterOperand(new SigType(CilElementType.U4), GeneralPurposeRegister.EAX); context.SetInstruction(IR.Instruction.MoveInstruction, imm, operand1); context.AppendInstruction(IR.Instruction.MoveInstruction, new RegisterOperand(new SigType(CilElementType.U4), _control), imm); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; RegisterOperand tmp = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EDX); MemoryOperand operand = new MemoryOperand(context.Operand1.Type, GeneralPurposeRegister.EDX, new System.IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, tmp, context.Operand1); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, operand); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { SigType I4 = new SigType(CilElementType.I4); RegisterOperand esp = new RegisterOperand(I4, GeneralPurposeRegister.ESP); context.SetInstruction(CPUx86.Instruction.MovInstruction, esp, context.Operand1); context.AppendInstruction(CPUx86.Instruction.PopadInstruction); context.AppendInstruction(CPUx86.Instruction.AddInstruction, esp, new ConstantOperand(I4, 0x08)); context.AppendInstruction(CPUx86.Instruction.StiInstruction); context.AppendInstruction(CPUx86.Instruction.IRetdInstruction); }
/// <summary> /// Converts the given instruction from three address format to a two address format. /// </summary> /// <param name="ctx">The conversion context.</param> private static void ThreeTwoAddressConversion(Context ctx) { Operand result = ctx.Result; Operand op1 = ctx.Operand1; Operand op2 = ctx.Operand2; if (ctx.Instruction is IR.FloatingPointCompareInstruction) return; if (ctx.Instruction is CIL.MulInstruction /*|| ctx.Instruction is CIL.DivInstruction*/) if (!(op1 is ConstantOperand) && (op2 is ConstantOperand)) { Operand temp = op1; op1 = op2; op2 = temp; } // Create registers for different data types RegisterOperand eax = new RegisterOperand(op1.Type, op1.StackType == StackTypeCode.F ? (Register)SSE2Register.XMM0 : GeneralPurposeRegister.EAX); RegisterOperand storeOperand = new RegisterOperand(result.Type, result.StackType == StackTypeCode.F ? (Register)SSE2Register.XMM0 : GeneralPurposeRegister.EAX); // RegisterOperand eaxL = new RegisterOperand(op1.Type, GeneralPurposeRegister.EAX); ctx.Result = storeOperand; ctx.Operand1 = op2; ctx.Operand2 = null; ctx.OperandCount = 1; if (op1.StackType != StackTypeCode.F) { if (IsSigned(op1) && !(op1 is ConstantOperand)) ctx.InsertBefore().SetInstruction(IR.Instruction.SignExtendedMoveInstruction, eax, op1); else if (IsUnsigned(op1) && !(op1 is ConstantOperand)) ctx.InsertBefore().SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, eax, op1); else ctx.InsertBefore().SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); } else { if (op1.Type.Type == CilElementType.R4) { if (op1 is ConstantOperand) { Context before = ctx.InsertBefore(); before.SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); before.AppendInstruction(CPUx86.Instruction.Cvtss2sdInstruction, eax, eax); } else ctx.InsertBefore().SetInstruction(CPUx86.Instruction.Cvtss2sdInstruction, eax, op1); } else ctx.InsertBefore().SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); } ctx.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { Operand operand1 = context.Operand1; Operand operand2 = context.Operand2; RegisterOperand edx = new RegisterOperand (operand1.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand (operand2.Type, GeneralPurposeRegister.EAX); context.SetInstruction (CPUx86.Instruction.MovInstruction, edx, operand1); context.AppendInstruction (CPUx86.Instruction.MovInstruction, eax, operand2); context.AppendInstruction (CPUx86.Instruction.OutInstruction, null, edx, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { Operand result = context.Result; Operand operand = context.Operand1; RegisterOperand eax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.EAX); RegisterOperand ecx = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.ECX); RegisterOperand reg = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), GeneralPurposeRegister.EBX); context.SetInstruction(CPUx86.Instruction.MovInstruction, eax, operand); context.AppendInstruction(CPUx86.Instruction.XorInstruction, ecx, ecx); context.AppendInstruction(CPUx86.Instruction.CpuIdEbxInstruction); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, reg); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; Operand operand1 = context.Operand1; RegisterOperand edx = new RegisterOperand(operand1.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand(result.Type, GeneralPurposeRegister.EAX); context.SetInstruction(CPUx86.Instruction.MovInstruction, edx, operand1); context.AppendInstruction(CPUx86.Instruction.InInstruction, eax, edx); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand result = context.Result; SigType u4 = new SigType(CilElementType.U4); RegisterOperand eax = new RegisterOperand(u4, GeneralPurposeRegister.EAX); context.SetInstruction(CPUx86.Instruction.PopInstruction, eax); context.AppendInstruction(CPUx86.Instruction.AddInstruction, eax, new RegisterOperand(u4, GeneralPurposeRegister.ESP)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(0))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, result, eax); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { Operand dest = context.Operand1; Operand value = context.Operand2; RegisterOperand edx = new RegisterOperand(dest.Type, GeneralPurposeRegister.EDX); RegisterOperand eax = new RegisterOperand(value.Type, GeneralPurposeRegister.EAX); MemoryOperand memory = new MemoryOperand(new SigType(context.InvokeTarget.Signature.Parameters[1].Type), GeneralPurposeRegister.EDX, new IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, edx, dest); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, value); context.AppendInstruction(CPUx86.Instruction.MovInstruction, memory, eax); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { SigType u4 = new SigType(Runtime.Metadata.CilElementType.U4); RegisterOperand ebp = new RegisterOperand(u4, GeneralPurposeRegister.EBP); RegisterOperand esp = new RegisterOperand(u4, GeneralPurposeRegister.ESP); RegisterOperand eax = new RegisterOperand(u4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(u4, GeneralPurposeRegister.EBX); RegisterOperand ecx = new RegisterOperand(u4, GeneralPurposeRegister.ECX); RegisterOperand edx = new RegisterOperand(u4, GeneralPurposeRegister.EDX); RegisterOperand esi = new RegisterOperand(u4, GeneralPurposeRegister.ESI); RegisterOperand edi = new RegisterOperand(u4, GeneralPurposeRegister.EDI); context.SetInstruction(CPUx86.Instruction.PushInstruction, null, ebp); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebp, esp); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, esi); context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, edi); // Load register context context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(28))); // Load exception handler context.AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(32))); // Save EBP context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebp); // Restore register values context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebp, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(24))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(4))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, esi, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(16))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, edi, new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(20))); // Align ESP context.AppendInstruction(CPUx86.Instruction.MovInstruction, edx, esp); context.AppendInstruction(CPUx86.Instruction.AndInstruction, esp, new ConstantOperand(u4, 0xFFFFFFF0u)); context.AppendInstruction(CPUx86.Instruction.SubInstruction, esp, new ConstantOperand(u4, 0x8u)); // Save original ESP context.AppendInstruction(CPUx86.Instruction.PushInstruction, null, edx); // Call catch handler context.AppendInstruction(CPUx86.Instruction.CallInstruction, ecx); // Restore registers context.AppendInstruction(CPUx86.Instruction.PopInstruction, esp); context.AppendInstruction(CPUx86.Instruction.PopInstruction, ebp); context.AppendInstruction(CPUx86.Instruction.PopInstruction, esi); context.AppendInstruction(CPUx86.Instruction.PopInstruction, edi); context.AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); context.AppendInstruction(CPUx86.Instruction.LeaveInstruction); context.AppendInstruction(CPUx86.Instruction.RetInstruction); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> public void ReplaceIntrinsicCall(Context context) { if (!(context.Operand1 is ConstantOperand)) throw new InvalidOperationException(); Operand result = context.Result; ControlRegister control; switch ((int)(context.Operand1 as ConstantOperand).Value) { case 0: control = ControlRegister.CR0; break; case 2: control = ControlRegister.CR2; break; case 3: control = ControlRegister.CR3; break; case 4: control = ControlRegister.CR4; break; default: throw new InvalidOperationException(); } RegisterOperand imm = new RegisterOperand(new SigType(CilElementType.U4), GeneralPurposeRegister.EAX); context.SetInstruction(IR.Instruction.MoveInstruction, imm, new RegisterOperand(new SigType(CilElementType.U4), control)); context.AppendInstruction(IR.Instruction.MoveInstruction, result, imm); }
/// <summary> /// Replaces the instrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem) { MemoryOperand operand = new MemoryOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX, new System.IntPtr(0)); context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.Ptr), GeneralPurposeRegister.EAX), context.Operand1); context.AppendInstruction(CPUx86.Instruction.LgdtInstruction, null, operand); RegisterOperand ax = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), GeneralPurposeRegister.EAX); RegisterOperand ds = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.DS); RegisterOperand es = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.ES); RegisterOperand fs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.FS); RegisterOperand gs = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.GS); RegisterOperand ss = new RegisterOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I2), SegmentRegister.SS); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ax, new ConstantOperand(new Mosa.Runtime.Metadata.Signatures.SigType(Mosa.Runtime.Metadata.CilElementType.I4), (int)0x00000010)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ds, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, es, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, fs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, gs, ax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, ss, ax); context.AppendInstruction(CPUx86.Instruction.FarJmpInstruction); context.AppendInstruction(CPUx86.Instruction.NopInstruction); context.Previous.SetBranch(context.Offset); }
private void HandleMemoryToMemoryOperation(Context ctx, Operand register, bool useStack) { Operand destination = ctx.Result; Operand source = ctx.Operand1; Debug.Assert(destination is MemoryOperand && source is MemoryOperand); if (register == null) register = new RegisterOperand(destination.Type, GeneralPurposeRegister.EDX); ctx.Operand1 = register; Context before = ctx.InsertBefore(); if (useStack) { before.SetInstruction(CPUx86.Instruction.PushInstruction, null, register); before.AppendInstruction(CPUx86.Instruction.MovInstruction, register, source); } else before.SetInstruction(CPUx86.Instruction.MovInstruction, register, source); if (useStack) ctx.AppendInstruction(CPUx86.Instruction.PopInstruction, register); }
/// <summary> /// Spills the given register to its source operand. /// </summary> /// <param name="ctx">The context.</param> /// <param name="op">The operand to spill to.</param> /// <param name="rop">The register operand to spill.</param> private void SpillRegister(Context ctx, Operand op, RegisterOperand rop) { // Set the operand in the active operands list int regIdx = rop.Register.Index; Debug.Assert(_activeOperands[regIdx].Equals(op), @"Register assigned to another operand?"); InsertMove(ctx, op, rop); _activeOperands[regIdx] = null; _activeOpLastUse[regIdx] = null; }
/// <summary> /// Spills a register from the given register set. /// </summary> /// <param name="ctx">The context.</param> /// <param name="type">The signature type of the resulting operand.</param> /// <param name="regs">The instruction compatible subset of the register set.</param> /// <returns>A register From the given set.</returns> private RegisterOperand SpillRegister(Context ctx, SigType type, Register[] regs) { // FIXME: Find the oldest reg from the set. Always use the oldest one. KeyValuePair<Register, Context>[] lastUses = new KeyValuePair<Register, Context>[regs.Length]; int i = 0; foreach (Register reg in regs) lastUses[i++] = new KeyValuePair<Register, Context>(reg, _activeOpLastUse[reg.Index]); // Sort the last uses from oldest -> newest Array.Sort<KeyValuePair<Register, Context>>(lastUses, delegate(KeyValuePair<Register, Context> a, KeyValuePair<Register, Context> b) { return b.Value.Offset - a.Value.Offset; }); // Spill the oldest entry (first index) KeyValuePair<Register, Context> lastUse = lastUses[0]; Operand dest = _activeOperands[lastUse.Key.Index]; RegisterOperand src = new RegisterOperand(dest.Type, lastUse.Key); SpillRegister(lastUse.Value, dest, src); return new RegisterOperand(type, lastUse.Key); }
/// <summary> /// Assigns the operand to the register. /// </summary> /// <param name="rop">The register operand containing the register to assign.</param> /// <param name="op">The operand assigned to the register.</param> /// <param name="ctx">The context.</param> private void AssignRegister(RegisterOperand rop, Operand op, Context ctx) { // Set the operand in the active operands list int regIdx = rop.Register.Index; Debug.Assert(_activeOperands[regIdx] == null, @"Register not free."); _activeOperands[regIdx] = op; _activeOpLastUse[regIdx] = ctx; }
/// <summary> /// Expands the urem instruction. /// </summary> /// <param name="context">The context.</param> private void ExpandURem(Context context) { SigType U4 = new SigType(CilElementType.U4); SigType U1 = new SigType(CilElementType.U1); Operand op0H, op1H, op2H, op0L, op1L, op2L; SplitLongOperand(context.Result, out op0L, out op0H); SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(context.Operand2, out op2L, out op2H); RegisterOperand eax = new RegisterOperand(U4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(U4, GeneralPurposeRegister.EBX); RegisterOperand edx = new RegisterOperand(U4, GeneralPurposeRegister.EDX); RegisterOperand ecx = new RegisterOperand(U4, GeneralPurposeRegister.ECX); RegisterOperand edi = new RegisterOperand(U4, GeneralPurposeRegister.EDI); RegisterOperand esi = new RegisterOperand(U4, GeneralPurposeRegister.ESI); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 11); Context nextBlock = SplitContext(context, false); // Determine sign of the result (edi = 0 if result is positive, non-zero // otherwise) and make operands positive. // xor edi,edi ; result sign assumed positive //mov eax,HIWORD(DVND) ; hi word of a //or eax,eax ; test to see if signed //jge short L1 ; skip rest if a is already positive //inc edi ; complement result sign flag bit //mov edx,LOWORD(DVND) ; lo word of a //neg eax ; make a positive //neg edx //sbb eax,0 //mov HIWORD(DVND),eax ; save positive value //mov LOWORD(DVND),edx context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, edi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, esi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op2H); newBlocks[0].AppendInstruction(CPUx86.Instruction.OrInstruction, eax, eax); newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[2].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[2], newBlocks[1]); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2L); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); newBlocks[1].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[1].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[10].BasicBlock); LinkBlocks(newBlocks[1], newBlocks[10]); // L1: newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, op2L); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1H); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[2], newBlocks[3]); // L3: newBlocks[3].AppendInstruction(CPUx86.Instruction.ShrInstruction, ecx, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.RcrInstruction, ebx, new ConstantOperand(U1, 1)); // RCR newBlocks[3].AppendInstruction(CPUx86.Instruction.ShrInstruction, edx, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.RcrInstruction, eax, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.OrInstruction, ecx, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[3].BasicBlock); newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[4].BasicBlock); LinkBlocks(newBlocks[3], newBlocks[3], newBlocks[4]); newBlocks[4].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ebx); newBlocks[4].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax); newBlocks[4].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2H); newBlocks[4].AppendInstruction(CPUx86.Instruction.XchgInstruction, ecx, eax); newBlocks[4].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2L); newBlocks[4].AppendInstruction(CPUx86.Instruction.AddInstruction, edx, ecx); newBlocks[4].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[8].BasicBlock); newBlocks[4].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[4], newBlocks[8], newBlocks[5]); newBlocks[5].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, edx, op1H); newBlocks[5].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedGreaterThan, newBlocks[8].BasicBlock); newBlocks[5].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[6].BasicBlock); LinkBlocks(newBlocks[5], newBlocks[8], newBlocks[6]); newBlocks[6].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[9].BasicBlock); newBlocks[6].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[7].BasicBlock); LinkBlocks(newBlocks[6], newBlocks[6], newBlocks[7]); newBlocks[7].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, eax, op1L); newBlocks[7].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessOrEqual, newBlocks[9].BasicBlock); newBlocks[7].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[7], newBlocks[9], newBlocks[3]); // L4: newBlocks[8].AppendInstruction(CPUx86.Instruction.SubInstruction, eax, op2L); newBlocks[8].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, op2H); newBlocks[8].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[9].BasicBlock); LinkBlocks(newBlocks[8], newBlocks[9]); // L5: newBlocks[9].AppendInstruction(CPUx86.Instruction.SubInstruction, eax, op1L); newBlocks[9].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, op1H); newBlocks[9].AppendInstruction(CPUx86.Instruction.NegInstruction, edx); newBlocks[9].AppendInstruction(CPUx86.Instruction.NegInstruction, eax); newBlocks[9].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, new ConstantOperand(U4, (int)0)); newBlocks[9].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[10].BasicBlock); LinkBlocks(newBlocks[9], newBlocks[10]); newBlocks[10].SetInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); newBlocks[10].AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, esi); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, edi); newBlocks[10].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock); LinkBlocks(newBlocks[10], nextBlock); }
/// <summary> /// Expands the unsigned move instruction for 64-bits. /// </summary> /// <param name="context">The context.</param> private void ExpandUnsignedMove(Context context) { MemoryOperand op0 = context.Result as MemoryOperand; Operand op1 = context.Operand1; Debug.Assert(op0 != null, @"I8 not in a memory operand!"); SigType U4 = new SigType(CilElementType.U4); Operand op0L, op0H, op1L, op1H; SplitLongOperand(op0, out op0L, out op0H); SplitLongOperand(op1, out op1L, out op1H); RegisterOperand eax = new RegisterOperand(U4, GeneralPurposeRegister.EAX); RegisterOperand edx = new RegisterOperand(U4, GeneralPurposeRegister.EDX); switch (op1.Type.Type) { case CilElementType.Boolean: context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, op0L, op1L); context.AppendInstruction(IR.Instruction.LogicalXorInstruction, op0H, op0H, op0H); break; case CilElementType.U1: context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, eax, op1L); context.AppendInstruction(CPUx86.Instruction.CdqInstruction); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); context.AppendInstruction(IR.Instruction.LogicalXorInstruction, op0H, op0H, op0H); break; case CilElementType.U2: goto case CilElementType.U1; case CilElementType.I4: context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, eax, op1L); context.AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); break; case CilElementType.U4: context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, eax, op1L); context.AppendInstruction(CPUx86.Instruction.CdqInstruction); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); break; case CilElementType.U8: context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, op0L, op1L); context.SetInstruction(IR.Instruction.ZeroExtendedMoveInstruction, op0H, op1H); break; case CilElementType.R4: throw new NotSupportedException(); case CilElementType.R8: throw new NotSupportedException(); default: throw new NotSupportedException(); } }
/// <summary> /// Expands the udiv instruction. /// </summary> /// <param name="context">The context.</param> private void ExpandUDiv(Context context) { SigType U4 = new SigType(CilElementType.U4); SigType U1 = new SigType(CilElementType.U1); Operand op0H, op1H, op2H, op0L, op1L, op2L; SplitLongOperand(context.Result, out op0L, out op0H); SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(context.Operand2, out op2L, out op2H); RegisterOperand eax = new RegisterOperand(U4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(U4, GeneralPurposeRegister.EBX); RegisterOperand edx = new RegisterOperand(U4, GeneralPurposeRegister.EDX); RegisterOperand ecx = new RegisterOperand(U4, GeneralPurposeRegister.ECX); RegisterOperand edi = new RegisterOperand(U4, GeneralPurposeRegister.EDI); RegisterOperand esi = new RegisterOperand(U4, GeneralPurposeRegister.ESI); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 12); Context nextBlock = SplitContext(context, false); context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, edi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, esi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op2H); newBlocks[0].AppendInstruction(CPUx86.Instruction.OrInstruction, eax, eax); newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[2].BasicBlock); // JNZ newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[2], newBlocks[1]); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2L); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); newBlocks[1].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, eax); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[1].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, ebx); newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[10].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[10]); // L1 newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, op2L); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1H); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[2], newBlocks[3]); // L3 newBlocks[3].AppendInstruction(CPUx86.Instruction.ShrInstruction, ecx, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.RcrInstruction, ebx, new ConstantOperand(U1, 1)); // RCR newBlocks[3].AppendInstruction(CPUx86.Instruction.ShrInstruction, edx, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.RcrInstruction, eax, new ConstantOperand(U1, 1)); newBlocks[3].AppendInstruction(CPUx86.Instruction.OrInstruction, ecx, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[3].BasicBlock); // JNZ newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[4].BasicBlock); LinkBlocks(newBlocks[3], newBlocks[3], newBlocks[4]); newBlocks[4].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ebx); newBlocks[4].AppendInstruction(CPUx86.Instruction.MovInstruction, esi, eax); newBlocks[4].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2H); newBlocks[4].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax); newBlocks[4].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op2L); newBlocks[4].AppendInstruction(CPUx86.Instruction.MulInstruction, null, esi); newBlocks[4].AppendInstruction(CPUx86.Instruction.AddInstruction, edx, ecx); newBlocks[4].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[8].BasicBlock); newBlocks[4].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[4], newBlocks[8], newBlocks[5]); newBlocks[5].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, edx, op1H); newBlocks[5].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedGreaterThan, newBlocks[8].BasicBlock); newBlocks[5].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[6].BasicBlock); LinkBlocks(newBlocks[5], newBlocks[8], newBlocks[6]); newBlocks[6].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[9].BasicBlock); newBlocks[6].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[7].BasicBlock); LinkBlocks(newBlocks[6], newBlocks[9], newBlocks[7]); newBlocks[7].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, eax, op1L); newBlocks[7].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessOrEqual, newBlocks[9].BasicBlock); newBlocks[7].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[8].BasicBlock); LinkBlocks(newBlocks[7], newBlocks[9], newBlocks[8]); // L4: newBlocks[8].AppendInstruction(CPUx86.Instruction.DecInstruction, esi); newBlocks[8].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[9].BasicBlock); LinkBlocks(newBlocks[8], newBlocks[9]); // L5 newBlocks[9].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[9].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, esi); newBlocks[9].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[10].BasicBlock); LinkBlocks(newBlocks[9], newBlocks[10]); // L2 newBlocks[10].SetInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); newBlocks[10].AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, esi); newBlocks[10].AppendInstruction(CPUx86.Instruction.PopInstruction, edi); newBlocks[10].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock); LinkBlocks(newBlocks[10], nextBlock); }
/// <summary> /// Expands the store instruction for 64-bits. /// </summary> /// <param name="context">The context.</param> private void ExpandStore(Context context) { MemoryOperand op0 = context.Result as MemoryOperand; Operand offsetOperand = context.Operand1; MemoryOperand op2 = context.Operand2 as MemoryOperand; Debug.Assert(op0 != null && op2 != null, @"Operands to I8 LoadInstruction are not MemoryOperand."); SigType I4 = new SigType(CilElementType.I4); SigType U4 = new SigType(CilElementType.U4); Operand op1L, op1H; SplitLongOperand(op2, out op1L, out op1H); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); context.SetInstruction(CPUx86.Instruction.MovInstruction, edx, op0); // Fortunately in 32-bit mode, we can't have 64-bit offsets, so this plain add should suffice. context.AppendInstruction(CPUx86.Instruction.AddInstruction, edx, offsetOperand); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); context.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(U4, GeneralPurposeRegister.EDX, IntPtr.Zero), eax); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); context.AppendInstruction(CPUx86.Instruction.MovInstruction, new MemoryOperand(I4, GeneralPurposeRegister.EDX, new IntPtr(4)), eax); }
/// <summary> /// Expands the shift right instruction for 64-bits. /// </summary> /// <param name="context">The context.</param> private void ExpandShiftRight(Context context) { SigType I4 = new SigType(CilElementType.I4); SigType I1 = new SigType(CilElementType.I1); SigType U1 = new SigType(CilElementType.U1); Operand count = context.Operand2; Operand op0H, op1H, op0L, op1L; SplitLongOperand(context.Operand1, out op0L, out op0H); SplitLongOperand(context.Operand2, out op1L, out op1H); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); RegisterOperand ecx = new RegisterOperand(U1, GeneralPurposeRegister.ECX); //UNUSED: //RegisterOperand cl = new RegisterOperand(new SigType(CilElementType.U1), GeneralPurposeRegister.ECX); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 6); Context nextBlock = SplitContext(context, true); // Handle shifts of 64 bits or more (if shifting 64 bits or more, the result // depends only on the high order bit of edx). context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ecx); newBlocks[0].AppendInstruction(IR.Instruction.LogicalAndInstruction, count, count, new ConstantOperand(I4, 0x3F)); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, count); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1H); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[0].AppendInstruction(CPUx86.Instruction.CmpInstruction, ecx, new ConstantOperand(I4, 64)); newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedGreaterOrEqual, newBlocks[4].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[4], newBlocks[1]); newBlocks[1].AppendInstruction(CPUx86.Instruction.CmpInstruction, ecx, new ConstantOperand(I4, 32)); newBlocks[1].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedGreaterOrEqual, newBlocks[3].BasicBlock); newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[2].BasicBlock); LinkBlocks(newBlocks[3], newBlocks[2], newBlocks[1]); newBlocks[2].AppendInstruction(CPUx86.Instruction.ShrdInstruction, eax, edx, ecx); newBlocks[2].AppendInstruction(CPUx86.Instruction.SarInstruction, edx, ecx); newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[2], newBlocks[5]); // Handle shifts of between 32 and 63 bits // MORE32: newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, edx); newBlocks[3].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, new ConstantOperand(I1, (sbyte)0x1F)); newBlocks[3].AppendInstruction(CPUx86.Instruction.SarInstruction, edx, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.PopInstruction, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.AndInstruction, ecx, new ConstantOperand(I4, 0x1F)); newBlocks[3].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, new ConstantOperand(I1, (sbyte)0x1F)); newBlocks[3].AppendInstruction(CPUx86.Instruction.SarInstruction, eax, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.PopInstruction, ecx); newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[3], newBlocks[5]); // Return double precision 0 or -1, depending on the sign of edx // RETSIGN: newBlocks[4].AppendInstruction(CPUx86.Instruction.SarInstruction, edx, new ConstantOperand(I1, (sbyte)0x1F)); newBlocks[4].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, edx); newBlocks[4].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[4], newBlocks[5]); // done: // ; remaining code from current basic block newBlocks[5].SetInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); newBlocks[5].AppendInstruction(CPUx86.Instruction.PopInstruction, ecx); newBlocks[5].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock); LinkBlocks(newBlocks[5], nextBlock); }
/// <summary> /// Expands the rem. /// </summary> /// <param name="context">The context.</param> private void ExpandRem(Context context) { SigType I4 = new SigType(CilElementType.I4); SigType U1 = new SigType(CilElementType.U1); Operand op0H, op1H, op2H, op0L, op1L, op2L; SplitLongOperand(context.Result, out op0L, out op0H); SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(context.Operand2, out op2L, out op2H); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(I4, GeneralPurposeRegister.EBX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); RegisterOperand ecx = new RegisterOperand(I4, GeneralPurposeRegister.ECX); RegisterOperand edi = new RegisterOperand(I4, GeneralPurposeRegister.EDI); RegisterOperand esi = new RegisterOperand(I4, GeneralPurposeRegister.ESI); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 16); Context nextBlock = SplitContext(context, false); // Determine sign of the result (edi = 0 if result is positive, non-zero // otherwise) and make operands positive. // xor edi,edi ; result sign assumed positive //mov eax,HIWORD(DVND) ; hi word of a //or eax,eax ; test to see if signed //jge short L1 ; skip rest if a is already positive //inc edi ; complement result sign flag bit //mov edx,LOWORD(DVND) ; lo word of a //neg eax ; make a positive //neg edx //sbb eax,0 //mov HIWORD(DVND),eax ; save positive value //mov LOWORD(DVND),edx context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, edi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, esi); newBlocks[0].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); newBlocks[0].AppendInstruction(CPUx86.Instruction.XorInstruction, edi, edi); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); newBlocks[0].AppendInstruction(CPUx86.Instruction.OrInstruction, eax, eax); newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.GreaterOrEqual, newBlocks[2].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[2], newBlocks[1]); newBlocks[1].AppendInstruction(CPUx86.Instruction.IncInstruction, edi); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1L); newBlocks[1].AppendInstruction(CPUx86.Instruction.NegInstruction, eax); newBlocks[1].AppendInstruction(CPUx86.Instruction.NegInstruction, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.SbbInstruction, eax, new ConstantOperand(I4, 0)); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, op1H, eax); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, op1L, edx); newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[2].BasicBlock); LinkBlocks(newBlocks[1], newBlocks[2]); // L1: // // mov eax,HIWORD(DVSR) ; hi word of b // or eax,eax ; test to see if signed // jge short L2 ; skip rest if b is already positive // mov edx,LOWORD(DVSR) ; lo word of b // neg eax ; make b positive // neg edx // sbb eax,0 // mov HIWORD(DVSR),eax ; save positive value // mov LOWORD(DVSR),edx newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op2H); newBlocks[2].AppendInstruction(CPUx86.Instruction.OrInstruction, eax, eax); newBlocks[2].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.GreaterOrEqual, newBlocks[4].BasicBlock); newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[2], newBlocks[4], newBlocks[3]); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op2L); newBlocks[3].AppendInstruction(CPUx86.Instruction.NegInstruction, eax); newBlocks[3].AppendInstruction(CPUx86.Instruction.NegInstruction, edx); newBlocks[3].AppendInstruction(CPUx86.Instruction.SbbInstruction, eax, new ConstantOperand(I4, 0)); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, op2H, eax); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, op2L, edx); newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[4].BasicBlock); LinkBlocks(newBlocks[3], newBlocks[4]); // L2: // // // Now do the divide. First look to see if the divisor is less than 4194304K. // If so, then we can use a simple algorithm with word divides, otherwise // things get a little more complex. // // NOTE - eax currently contains the high order word of DVSR // // // or eax,eax ; check to see if divisor < 4194304K // jnz short L3 ; nope, gotta do this the hard way // mov ecx,LOWORD(DVSR) ; load divisor // mov eax,HIWORD(DVND) ; load high word of dividend // xor edx,edx // div ecx ; eax <- high order bits of quotient // mov eax,LOWORD(DVND) ; edx:eax <- remainder:lo word of dividend // div ecx ; eax <- low order bits of quotient // mov edx,ebx ; edx:eax <- quotient // jmp short L4 ; set sign, restore stack and return newBlocks[4].AppendInstruction(CPUx86.Instruction.OrInstruction, eax, eax); newBlocks[4].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[6].BasicBlock); newBlocks[4].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[5].BasicBlock); LinkBlocks(newBlocks[4], newBlocks[6], newBlocks[5]); newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2L); newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); newBlocks[5].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[5].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[5].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[5].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, edx); newBlocks[5].AppendInstruction(CPUx86.Instruction.XorInstruction, edx, edx); newBlocks[5].AppendInstruction(CPUx86.Instruction.DecInstruction, edi); newBlocks[5].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotSigned, newBlocks[14].BasicBlock); newBlocks[5].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[15].BasicBlock); LinkBlocks(newBlocks[5], newBlocks[14], newBlocks[15]); // Here we do it the hard way. Remember, eax contains the high word of DVSR // // L3: // mov ebx,eax ; ebx:ecx <- divisor // mov ecx,LOWORD(DVSR) // mov edx,HIWORD(DVND) ; edx:eax <- dividend // mov eax,LOWORD(DVND) newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, eax); newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2L); newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, edx, op1H); newBlocks[6].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[6].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[7].BasicBlock); LinkBlocks(newBlocks[6], newBlocks[7]); // L5: // // shr ebx,1 ; shift divisor right one bit // rcr ecx,1 // shr edx,1 ; shift dividend right one bit // rcr eax,1 // or ebx,ebx // jnz short L5 ; loop until divisor < 4194304K // div ecx ; now divide, ignore remainder // // We may be off by one, so to check, we will multiply the quotient // by the divisor and check the result against the orignal dividend // Note that we must also check for overflow, which can occur if the // dividend is close to 2**64 and the quotient is off by 1. // // mov ecx,eax ; save a copy of quotient in ECX // mul dword ptr HIWORD(DVSR) // xchg ecx,eax ; save product, get quotient in EAX // mul dword ptr LOWORD(DVSR) // add edx,ecx ; EDX:EAX = QUOT * DVSR // jc short L6 ; carry means Quotient is off by 1 // // do long compare here between original dividend and the result of the // multiply in edx:eax. If original is larger or equal, we are ok, otherwise // subtract the original divisor from the result. // // cmp edx,HIWORD(DVND) ; compare hi words of result and original // ja short L6 ; if result > original, do subtract // jb short L7 ; if result < original, we are ok // cmp eax,LOWORD(DVND) ; hi words are equal, compare lo words // jbe short L7 ; if less or equal we are ok, else subtract newBlocks[7].AppendInstruction(CPUx86.Instruction.ShrInstruction, ebx, new ConstantOperand(U1, 1)); newBlocks[7].AppendInstruction(CPUx86.Instruction.RcrInstruction, ecx, new ConstantOperand(U1, 1)); // RCR newBlocks[7].AppendInstruction(CPUx86.Instruction.ShrInstruction, edx, new ConstantOperand(U1, 1)); newBlocks[7].AppendInstruction(CPUx86.Instruction.RcrInstruction, eax, new ConstantOperand(U1, 1)); newBlocks[7].AppendInstruction(CPUx86.Instruction.OrInstruction, ebx, ebx); newBlocks[7].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[7].BasicBlock); newBlocks[7].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[8].BasicBlock); LinkBlocks(newBlocks[7], newBlocks[7], newBlocks[8]); newBlocks[8].AppendInstruction(CPUx86.Instruction.DirectDivisionInstruction, eax, ecx); newBlocks[8].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, eax); newBlocks[8].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2H); newBlocks[8].AppendInstruction(CPUx86.Instruction.XchgInstruction, ecx, eax); newBlocks[8].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2L); newBlocks[8].AppendInstruction(CPUx86.Instruction.AddInstruction, edx, ecx); newBlocks[8].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[12].BasicBlock); newBlocks[8].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[9].BasicBlock); LinkBlocks(newBlocks[8], newBlocks[12], newBlocks[9]); newBlocks[9].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, edx, op1H); newBlocks[9].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedGreaterThan, newBlocks[12].BasicBlock); newBlocks[9].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[10].BasicBlock); LinkBlocks(newBlocks[9], newBlocks[12], newBlocks[10]); newBlocks[10].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessThan, newBlocks[13].BasicBlock); newBlocks[10].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[11].BasicBlock); LinkBlocks(newBlocks[10], newBlocks[13], newBlocks[11]); newBlocks[11].AppendInstruction(CPUx86.Instruction.DirectCompareInstruction, eax, op1L); newBlocks[11].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.UnsignedLessOrEqual, newBlocks[13].BasicBlock); newBlocks[11].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[12].BasicBlock); LinkBlocks(newBlocks[11], newBlocks[13], newBlocks[12]); // L6: newBlocks[12].AppendInstruction(CPUx86.Instruction.SubInstruction, eax, op2L); newBlocks[12].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, op2H); newBlocks[12].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[13].BasicBlock); LinkBlocks(newBlocks[13], newBlocks[13]); // L7: // // Calculate remainder by subtracting the result from the original dividend. // Since the result is already in a register, we will do the subtract in the // opposite direction and negate the result if necessary. // newBlocks[13].AppendInstruction(CPUx86.Instruction.SubInstruction, eax, op1L); newBlocks[13].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, op1H); newBlocks[13].AppendInstruction(CPUx86.Instruction.DecInstruction, edi); newBlocks[13].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotSigned, newBlocks[15].BasicBlock); newBlocks[13].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[14].BasicBlock); LinkBlocks(newBlocks[13], newBlocks[14], newBlocks[15]); // L4: // neg edx ; otherwise, negate the result // neg eax // sbb edx,0 newBlocks[14].AppendInstruction(CPUx86.Instruction.NegInstruction, edx); newBlocks[14].AppendInstruction(CPUx86.Instruction.NegInstruction, eax); newBlocks[14].AppendInstruction(CPUx86.Instruction.SbbInstruction, edx, new ConstantOperand(I4, 0)); newBlocks[14].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[15].BasicBlock); LinkBlocks(newBlocks[14], newBlocks[15]); newBlocks[15].SetInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); newBlocks[15].AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); newBlocks[15].AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); newBlocks[15].AppendInstruction(CPUx86.Instruction.PopInstruction, esi); newBlocks[15].AppendInstruction(CPUx86.Instruction.PopInstruction, edi); newBlocks[15].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock); LinkBlocks(newBlocks[15], nextBlock); }
/// <summary> /// Expands the mul instruction for 64-bit operands. /// </summary> /// <param name="context">The context.</param> private void ExpandMul(Context context) { Operand op0 = context.Result; Operand op1 = context.Operand1; Operand op2 = context.Operand2; Debug.Assert(op0 != null && op1 != null && op2 != null, @"Operands to 64 bit multiplication are not MemoryOperands."); SigType I4 = new SigType(CilElementType.I4); Operand op0H, op1H, op2H, op0L, op1L, op2L; SplitLongOperand(context.Result, out op0L, out op0H); SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(context.Operand2, out op2L, out op2H); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); RegisterOperand ebx = new RegisterOperand(I4, GeneralPurposeRegister.EBX); RegisterOperand ecx = new RegisterOperand(I4, GeneralPurposeRegister.ECX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); Context nextBlock = SplitContext(context, false); Context[] newBlocks = CreateEmptyBlockContexts(context.Label, 4); context.SetInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[0].BasicBlock); LinkBlocks(context, newBlocks[0]); newBlocks[0].SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1H); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2H); newBlocks[0].AppendInstruction(CPUx86.Instruction.OrInstruction, ecx, eax); newBlocks[0].AppendInstruction(CPUx86.Instruction.MovInstruction, ecx, op2L); newBlocks[0].AppendInstruction(CPUx86.Instruction.BranchInstruction, IR.ConditionCode.NotEqual, newBlocks[2].BasicBlock); newBlocks[0].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[1].BasicBlock); LinkBlocks(newBlocks[0], newBlocks[1], newBlocks[2]); newBlocks[1].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[1].AppendInstruction(CPUx86.Instruction.MulInstruction, null, ecx); newBlocks[1].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[1], newBlocks[3]); newBlocks[2].AppendInstruction(CPUx86.Instruction.PushInstruction, null, ebx); newBlocks[2].AppendInstruction(CPUx86.Instruction.MulInstruction, null, ecx); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, ebx, eax); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[2].AppendInstruction(CPUx86.Instruction.MulInstruction, null, op2H); newBlocks[2].AppendInstruction(CPUx86.Instruction.AddInstruction, ebx, eax); newBlocks[2].AppendInstruction(CPUx86.Instruction.MovInstruction, eax, op1L); newBlocks[2].AppendInstruction(CPUx86.Instruction.MulInstruction, null, ecx); newBlocks[2].AppendInstruction(CPUx86.Instruction.AddInstruction, edx, ebx); newBlocks[2].AppendInstruction(CPUx86.Instruction.PopInstruction, ebx); newBlocks[2].AppendInstruction(CPUx86.Instruction.JmpInstruction, newBlocks[3].BasicBlock); LinkBlocks(newBlocks[2], newBlocks[3]); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, eax); newBlocks[3].AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); newBlocks[3].AppendInstruction(CPUx86.Instruction.JmpInstruction, nextBlock.BasicBlock); LinkBlocks(newBlocks[2], nextBlock); }
/// <summary> /// Compares with the given operand for equality. /// </summary> /// <param name="other">The other operand to compare with.</param> /// <returns>The return value is true if the operands are equal; false if not.</returns> public override bool Equals(Operand other) { RegisterOperand rop = other as RegisterOperand; return(null != rop && ReferenceEquals(rop.Register, Register)); }
/// <summary> /// Spills the given register operand, if its register is in use. /// </summary> /// <param name="ctx">The context.</param> /// <param name="rop">The register operand to spill.</param> private void SpillRegisterIfInUse(Context ctx, RegisterOperand rop) { int regIdx = rop.Register.Index; Operand op = _activeOperands[regIdx]; if (op != null) { InsertMove(ctx, op, rop); _activeOperands[regIdx] = null; _activeOpLastUse[regIdx] = null; } }
/// <summary> /// Expands the load instruction for 64-bits. /// </summary> /// <param name="context">The context.</param> private void ExpandLoad(Context context) { Operand op0 = context.Result; Operand op1 = context.Operand1; Operand offsetOperand = context.Operand2; Debug.Assert(op0 != null && op1 != null, @"Operands to I8 LoadInstruction are not MemoryOperand."); SigType I4 = new SigType(CilElementType.I4); Operand op0L, op0H; SplitLongOperand(op0, out op0L, out op0H); RegisterOperand eax = new RegisterOperand(I4, GeneralPurposeRegister.EAX); RegisterOperand edx = new RegisterOperand(I4, GeneralPurposeRegister.EDX); context.SetInstruction(CPUx86.Instruction.MovInstruction, eax, op1); context.AppendInstruction(CPUx86.Instruction.AddInstruction, eax, offsetOperand); context.AppendInstruction(CPUx86.Instruction.MovInstruction, edx, new MemoryOperand(op0L.Type, GeneralPurposeRegister.EAX, IntPtr.Zero)); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0L, edx); context.AppendInstruction(CPUx86.Instruction.MovInstruction, edx, new MemoryOperand(op0H.Type, GeneralPurposeRegister.EAX, new IntPtr(4))); context.AppendInstruction(CPUx86.Instruction.MovInstruction, op0H, edx); }
/// <summary> /// Expands the sub instruction for 64-bit operands. /// </summary> /// <param name="context">The context.</param> private void ExpandSub(Context context) { /* This function transforms the SUB into the following sequence of x86 instructions: * * mov eax, [op1] ; Move lower 32-bits of the first operand into eax * sub eax, [op2] ; Sub lower 32-bits of second operand to eax * mov [result], eax ; Save the result into the lower 32-bits of the result operand * mov eax, [op1+4] ; Move upper 32-bits of the first operand into eax * sbb eax, [op2+4] ; Sub with borrow upper 32-bits of the second operand to eax * mov [result+4], eax ; Save the result into the upper 32-bits of the result operand * */ // This only works for memory operands (can't store I8/U8 in a register.) // This fails for constant operands right now, which need to be extracted into memory // with a literal/literal operand first - TODO RegisterOperand eaxH = new RegisterOperand(new SigType(CilElementType.I4), GeneralPurposeRegister.EAX); RegisterOperand eaxL = new RegisterOperand(new SigType(CilElementType.U4), GeneralPurposeRegister.EAX); Operand op1L, op1H, op2L, op2H, resL, resH; SplitLongOperand(context.Operand1, out op1L, out op1H); SplitLongOperand(context.Operand2, out op2L, out op2H); SplitLongOperand(context.Result, out resL, out resH); context.SetInstruction(CPUx86.Instruction.MovInstruction, eaxL, op1L); context.AppendInstruction(CPUx86.Instruction.SubInstruction, eaxL, op2L); context.AppendInstruction(CPUx86.Instruction.MovInstruction, resL, eaxL); context.AppendInstruction(CPUx86.Instruction.MovInstruction, eaxH, op1H); context.AppendInstruction(CPUx86.Instruction.SbbInstruction, eaxH, op2H); context.AppendInstruction(CPUx86.Instruction.MovInstruction, resH, eaxH); }